Re: Mixing TOMCAT and mod_perl sessions
Yair Lenga wrote: The website I'm supporting is running both TOMCAT applications ('.war'), and has mod_perl scripts (all of them are registry - CGI scripts). I have the following requirements: * The user identification information must be shared between TOMCAT and mod_perl (so that the user does not need to login twice). * No data sharing between mod_perl and TOMCAT application - but each of them need to store some persistent data. * Session should be persistent across server restarts (which excludes shared memory based solutions). You would probably have to implement the session interface on both sides. It could be fairly easy to implement sessions if you make a few assumptions, like a session will be a single hash with no complex structures or objects in it. A simple serialization scheme would then be possible for both languages (maybe use an existing XML one). You can use a database for persistent storage from both sides. - Perrin
Re: [Newbie Q] Cleanest way to implement one logon per user?
Eric Cholet wrote: Someone recently suggested to me the following solution, based on slightly modified sessions. It involves sending a cookie that contains a new ID with each response. The server stores that ID keyed on the user's login name. The next request from the client is expected to return that cookie. Sounds like an ordinary session to me. If you aren't logged, you must log in. Logging in clears all other sessions tied to this user ID. That should work fine. - Perrin
Re: [RFC] Apache::SessionManager
Enrico Sorcinelli wrote: Apache::SessionManager creates an object session (in Header parsing phase, but not obligatorily) and make it available to all other handlers transparently by putting in pnotes. Others handlers can retrieve session directly from pnotes or by calling the simple function Apache::SessionManager::get_session($r) It would be better if you don't instantiate the session until someone asks for it the first time. That will prevent unnecessary work. Also, when using Apache::Session with any locking module except NullLocker, it's very important to have the session object exist for the shortest possible time because it is locking out all other access to that session while it exists. (For this reason, it's also very important to make sure that requests for images and other static objects don't instantiate Apache::Session objects.) After some search on CPAN I haven't found a mod_perl module that does the same thing (right?). Some of the Apache::Auth* modules like Apache::AuthCookieURL are close, but I don't know of any that do the actual glue with Apache::Session. You might want to look at some of the existing modules and see if a merge of some kind is possible. - Perrin
Re: [RFC] Apache::SessionManager
Enrico Sorcinelli wrote: Some of the Apache::Auth* modules like Apache::AuthCookieURL are close, but I don't know of any that do the actual glue with Apache::Session. You might want to look at some of the existing modules and see if a merge of some kind is possible. This modules haven't glue with Apache::Session Right, that's my point. Your module has overlap with them in terms of managing cookies and specifying locations, but adds the actual calls to Apache::Session. If I were doing something like this, I would probably start with one of the Auth modules, which already do a good job of handling things like cookie verification and even cookie-less sessions, and add the actual Apache::Session glue. It might at least be worth stealing some code from the other modules, like the ticket-based cookies idea, but of course you can do what you like. I think it's good to have a module like this, and if you put yours out there people can contribute to it. Incidentally there is also a session manager module very similar to this in the Extropia modules. I've written Apache::SessionManager to be used _also_ in a mod_perl handlers or in a CGI script over Registry. The Apache::Auth modules also support that. - Perrin
Re: [RFC] Apache::SessionManager
Enrico Sorcinelli wrote: Incidentally there is also a session manager module very similar to this in the Extropia modules. Sincerely, I don't know Extropia modules! You can find some documentation on them here: http://www.extropia.com/support/docs/adt/customization.html#Session_and_Session_Manager_Conf They're not on CPAN, so I'm not surprised you didn't see them. - Perrin
Re: [Newbie Q] Cleanest way to implement one logon per user?
Baljit Sethi wrote: What I want to do is limit client logons to one logon per username ie while a client has a session open, he/she cannot logon to the website from another terminal. The simplest thing to do is create a new session for the user each time he logs in and invalidate any old sessions this user may have. This assumes you are talking about actual logins, not just sessions for anonymous browsers. - Perrin
Re: ANNOUNCE: Mason 1.12
Dave Rolsky wrote: It can, but I'm not sure what to update it to. Frankly, I think CPAN is more at fault here given that _many_ people use CVS for this sort of stuff and this quite normal when using CVS. This is a common complaint about CPAN.pm, but it's kept this way so far because of performance issues with doing fancier version parsing. I would suggest following David Wheeler's advice and setting version manually, so that you can just make 1.69 or something. Incidentally, all hell is going to break loose when Perl 5.10 gets released. Maybe that will force a change in CPAN.pm. - Perrin
Re: [ANNOUNCE] Apache Hello World Benchmarks - Apache C API, HelloDB
Dennis Haney wrote: The bias in the test is even a little slanted towards the JSP benchmarks since the trivial connection pooling I used there is nothing like the Apache::DBI overhead in the mod_perl test, when I could have just used a persistent global $dbh instead. ( maybe I should? ) I believe you should. It is the most common setup using mod_perl, if you are concerned about performance, anyway. I think you got confused by the wording. The most common setup with mod_perl is to use Apache::DBI, which is what he used in the test. To answer the original question, I don't think Apache::DBI is much overhead at all. It amounts to little more than a hash lookup. Certainly less work than the the thread synchronization required for connection pooling. - Perrin
Re: [ANNOUNCE] Apache Hello World Benchmarks - Apache C API, HelloDB
Josh Chamas wrote: My only problem with Apache::DBI for a benchmark is its default ping of the db per connect(). Oh, you're right I wasn't thinking about that. It is important in a benchmark to be testing equivalent functionality as much as possible, although it's very difficult to do. I spent hours ( 12 lines of code :) ) writing an overly simple database connection pooling manager for the JSP benchmarks where a standard one seems to be lacking in JDBC JNDI I thought that JDBC had a pooling capability now. I also thought Resin had something built in. I would use those if possible. Stick with Apache::DBI for mod_perl though. I would never tell anyone to roll their own database persistence for performance instead of using Apache::DBI. Pinging the database connection is good, and all systems should do it if they don't already. - Perrin
Re: Apache-print Timed Out
David Wheeler wrote: Why should Apache-print ever time out? One reason could be a web client that disconnects. There could also be a dropped network connection or one that's too slow. I think you can adjust this behavior with the TimeOut directive in httpd.conf. I didn't even know that timing out was something that a print method could do. This isn't the same thing as CORE::print. It's overriden for mod_perl to send to the network. Even CORE::print can return false in certain conditions, like when writing a file when the disk is full. And why does it only happen for some browser/platform combinations? Probably buggy browsers or TCP stacks. - Perrin
Re: [ANNOUNCE] Petal 0.1
Rob Nagler wrote: Apologies to those who are tired of the *ML vs. Perl debate. I think you're confusing the issue. You're not talking about in-line Perl vs. templating languages, but rather templating vs. a whole different concept. Jean-Michel clearly wants to use HTML-based templates, and wrote his module specifically for that purpose. When most people talk about templates for web pages, this is what they have in mind: HTML (or XML or PDF or whatever) bristled with processing instructions in Perl or a templating language. It's an easy transition for people who already know HTML, and provides what most people want from a templating solution. What Bivio uses could reasonably be called a template, but it's a completely different animal from the sort of fill-in-the-blank templates that most people mean, and maybe deserves a different name. It's more like a declarative program, or a configuration file, or CGI.pm widgets. It is an alternative to traditional templating, but suggesting that this will fix issues with XML parsing is kind of like saying you wouldn't need that winter coat if you lived in Hawaii -- true, but not very helpful to someone who lives in Montreal and likes it. - Perrin
Re: Apache::Registry and Apache::PerlRun
Boex,Matthew W. wrote: can i have both Registry and PerlRun running in the same environment? i have my cgi scripts running under Apache::Registry in one directory, and want to run a legacy cgi script under PerlRun in another directory. is this possible? Yes, no problem at all. - Perrin
Re: Purify, Perl and mod_perl
Carwheel, Dan wrote: although their web page says only works for C, C++, Java and a few others, I've seen this page: http://www.perlpod.com/stable/perlhack.html on getting Perl work with with Purify. That page is about getting Perl's C executable to work with Purify, not using Purify to check your perl code. My question is this...can I run my application using this purified perl under mod_perl to track down potential memory leaks and other problems? You probably don't have any memory leaks. Most things that people refer to as leaks are just normal growth. A leak is when an area of memory gets lost because the program that allocated it forgets to free it. Growth is when your program uses variables in such a way that it needs more memory over time. The latter is pretty common. Doing things like eval'ing code, reading variable length data into strings, and keeping other data structures that are affected by changes in user input or data over time will often lead to this. If you have out-of-control memory growth, you should try finding it the old-fashioned way: take things out until it stops. Then, if you find a little section that causes growth and you can't understand why, post it here and someone may be able to explain it. A number of the most common sources of memory growth are explained in the guide: http://perl.apache.org/docs/1.0/guide/performance.html#Improving_Performance_by_Prevention - Perrin
Re: sql-relay
Richard Clarke wrote: I came across http://www.firstworks.com/sqlrelay.html the other day. Have any of you come across this product before. It's been discussed here before (see the archives) but no one has talked about any real experience with it yet. Try it out and tell us what you find. With the whole problem of providing seemless recovery at the client side from database failure this tool seems quite productive. What problem is that? I don't think there's much you can do beyond re-connecting, which Apache::DBI does. - Perrin
Re: TIPool / multiple database connections
Elizabeth Mattijsen wrote: Hmm... but you won't be able to fetch the $dbh from the thread. It can only live in _that_ thread. You cannot pass objects between threads. But you _can_ send queries to that thread, fetch a jobid for that job and then obtain whatever was returned as a Perl datastructure. (if anyone knows of a way to pass objects between threads, I'd really would like to know) Hmmm... That could really throw a wrench in things. If you have an object based on a hash, and you share that hash, and you re-bless the object in each thread, does that work? What if the hash contains references to other variables. Do they need to be explicity shared as well? Thread::Pool doesn't work that way. You could have 1 database connection in one worker thread and 40 threads submitting jobs: they would be handled in the order they were submitted. This effectively serializes access (which could be an approach for DBI drivers that do not support _any_ threading at all). It could be useful for people who design their applications to use different database logins for each end user. This would allow the server to maintain a single persistent connection to the database for that user, rather than one in each process. Or you could have 10 worker threads with 40 threads submitting jobs. That would work faster if your database is threaded as well ;-) That would work well for the more common case, once the DBI threading issues are worked out. But does this mean we would need to create a whole new interface for sending in queries and getting results back, because the actual $sth objects can't be shared? That would be painful. Maybe some kind of local proxy object could handle this, forwarding all method calls to the worker thread and returning all results. It would be kind of like a transparent RPC mechanism. - Perrin
Re: sql-relay
Richard Clarke wrote: I mean in the case of the database crashing and being able to switch to a replicated backup system. That's trivial to implement if it happens during connect time. You can simply keep a list of databases to try, and if one fails you go on to the next. This approach is compatible with Apache::DBI, which will check database handles before handing them out to you. It will attempt a re-connect, and if it fails it will pass the failure message back to you just as if it were a normal connection attempt. It's harder if you want every query to be able to automatically retry on another database if it fails. For that, you would need to add some extra code to catch the exception, recognize it as a connection failure, make a new connection, and retry the query. I don't see anything on the SQL-Relay pages about this sort of ability. - Perrin
Re: Propogating Errors / E-Toys
Matt Sergeant wrote: On Wed, 10 Jul 2002, Fran Fabrizio wrote: Just to confirm, the end result of Matt's slide presentation was that Error.pm was good, and you should use it, but you should not use the try/catch syntax, or at the bare minimum only catch in your outermost handler. Is that correct? We were debating this just yesterday in our office. Actually my recommendation for this year's talk on exceptions is to just use eval{}; if ($) {}. It's a little more typing, but at the end of the day closures created by subroutine prototypes are a really bad thing (tm). I believe he was asking if Error.pm is a good class to use for exceptions if you don't use the try/catch keywords. I think it is. It provides handy methods for storing attributes of the exception and getting stack traces, and it's easy to subclass. You could also use Dave Rolsky's Exception::Class, which is pretty similar. - Perrin
Re: Growing Server Size modperl-2.0 on Solaris 2.7
Stas Bekman wrote: If you are talking about threaded mpms, we will need to develop new tools to restrict the size of the perl interpreters in the pool. I was thinking about that too. Are there hooks for causing an interpreter to exit? Is it safe to simply call CORE::exit? I'd like to make SizeLimit work for the threaded MPMs if possible. - Perrin
Re: Growing Server Size modperl-2.0 on Solaris 2.7
Stas Bekman wrote: I think the idea was to have a special thread running whose only purpose is monitoring the pool of idle interpreters. That sounds like a better solution. I believe that we can add a Perl space hook that sets a flag that condemns an interpreter to death. The other problem, which might be harder, is to figure out how big a particular interpreter is. The current implementations of Apache::SizeLimit and GTopLimit cheat by asking the OS how big the current process is. That won't work with threads. - Perrin
Re: Propogating Errors / E-Toys
Michael Schout wrote: in other words, if I understand the eToys article correctly, the leaks only happen if I nest a try block inside another try block. I have experimented some, and it appears to me that this is in fact the case ($count doesnt get cleaned up if there is a nested try). But as long as I dont nest try blocks there doesnt appear to be a leak. You are correct, you won't get a leak from the code in Matt's example. What you will get is an unexpected persistence of the value of the $count variable. It will retain its value and not be reset when you enter the handler sub again. There are other problems too, like return not doing what you would expect when used inside a try block (it only returns from the try block). - Perrin
Re: Perl sections
Mike Blazer wrote: MB Or may be there is some way to un-load mod_perl after Perl sections MB processing? If you need Perl sections only to do initial web server configuration and you do not need mod_perl features in runtime then instead of using Perl just write Perl script to generate Apache config file from templates and run it before starting Apache. This way you do not need mod_perl on frontend Apache at all. Yes, sure, that was my backup idea :) But I just wanted to make all 3 configs in one big file, because of tons of the parameters (like log names, leves, auth, ssl etc). To keep it all together and start with -D proxy or -D pages. Well of course you can do exactly that with what Ilya suggested: one template file that your script uses to generate appropriate conf files for each server. It's really your only choice for a proxy server. It's also somewhat safer, since it means your database doesn't have to be up just to start your proxy server. - Perrin
Re: Understanding why this fixes my perlaccess script
Jason Wilkes wrote: So far so good, and all works well. Except for one user id (actually id=333), which causes an internal server error. If I put print debugging lines in - everything works (even for user 333). If I take them out again all other users work fine except 333. Can anybody throw any light on this?? Yes. You are returning the value of the last operation, 333, when $answer is not true. To fix it, you should return DECLINED (or OK if no other access handlers should be allowed to run). Why does it work when you debug? Because you change the value of the last operation. BTW: when the internal server error happens there is no log of it in the error_log - although the HTTP response code in access_log is 333 (which I don't think is a valid response code). There is no server error. Your browser is just interpreting the response of 333 as a sign that something went wrong and putting a pretty face on it. Microsoft browsers are notorious for this, although you can turn the behavior off. - Perrin
Re: Propogating Errors / E-Toys
Richard Clarke wrote: Using Perrin's article on E-Toys is perhaps a good place to start. In the Model object which performs various DB procedures, what actions were taken if for some reason the connection to the database failed or if an SQL error happened? Was the whole execute() block put in an eval procedure and then a generic error page produced; Or were either per procedure evals or Exception objects used to propogate specific errors up to the control object so that it could display errors in the current page/view? Well, naturally the answer is it depends. Most database errors can't be gracefully recovered from, so we would let them propagate up. If it was possible for a database error to be caused by user input (say, a duplicate login name) that would need to be caught and handled. It would also be caught if any special cleanup of non-database resources was needed. Errors that propagate up are caught by an eval wrapping the whole handler method which issues a rollback to the database, logs the error, and prints either a pretty error page or a stack trace depending on the current debug settings. Here's an excerpt from the documentation I wrote for our exception base class. This uses the try/catch syntax from Error.pm. =head1 HANDLING DBI ERRORS Since DBI errors are the most common source of exceptions in our application, I'm giving them special treatment here. Because we are planning to use the RaiseError option of DBI, you can expect DBI to die whenever it hits a problem, as opposed to returning an undef value that you have to check for. This means that most of the time you don't need to do anything special for handling DBI errors. They will propagate up and be caught at the top level. DBI exceptions will be propagated as instances of the Error::Simple class. You can catch your own exceptions without catching the DBI exceptions by catching specific classes other than Error::Simple. try { # lookup password in Oracle my $sth = $dbh-prepare_cached($sql_query); $sth-execute($bind_value); if (!$sth-rows) { # should have matched something throw ESF::Error::User::BogusPassword -text $password; } $ary_ref = $sth-fetchrow_arrayref; # ... etc. ... } catch ESF::Error::User::BogusPassword with { # handle this error }; # -- don't forget! It's okay to use transactions, and to put in your C$dbh-commit statement at the end assuming everything will work. If DBI throws an exception that propagates to the top without being caught, we will automatically issue a C$dbh-rollback command. Sometimes, you may want to catch a specific DBI error. Be careful when doing this, because you need to know the error number or text of the error message in order to trap the right exception. DBI's raise error setting will cause it to fill the text attribute of the Error::Simple objects it throws with the message given by Oracle, so if you want to trap errors of type ORA-172, you can do this: try { my $sth = $dbh-prepare_cached($sql_query); $sth-execute($bind_value); } catch Error::Simple with { my $err = shift; if ($err-text() =~ m/ORA-172/) { # handle the error here } else { # let this error propagate $err-throw(); } }; # -- don't forget! - Perrin
Re: Propogating Errors / E-Toys
F. Xavier Noria wrote: I remember the article has a comment regarding a gotcha of the Error module that causes memory leaks, but you didn't go into details there. We've actually discussed this on the list. It has to do with closures. Matt gave a presentation about exception handling which covers it and shows a workaround. You can see it here: http://axkit.org/docs/presentations/tpc2001/ - Perrin
Re: Need Porting Sanity Check
Jeff wrote: Hey thanks for the reply. I am making progress but I have run into a problem where when I have PerlRun enabled my scripts are not see the field values being passed in the URL. I'm still using cgi-lib.pl not CGI.pm. I've never used cgi-lib.pl and you shouldn't either. That package has been deprecated for many years. By the way, do you know if PerlRun caches CGI.pm because I know otherwise it takes longer to load than the old cgi-lib.pl CGI.pm -- and any other external modules you use -- will be cached when used from PerlRun. The only thing that isn't cached is your script itself. - Perrin
Re: Need Porting Sanity Check
Jeff wrote: So here is my strategy that I would like a sanity check from anyone on. Go through and quickly clean up my existing code by adding use strict and localizing all my variables (with 'my' and 'local' for special variables) and then run is under mod_Perl using the Apache::PerlRun. Write all my new code so that it will run under Apache::Registry and then when I have spare time (ya right) go work on porting the older code. PerlRun works reasonably well, and I have used it to quickly port a large amount of legacy CGI code that made extensive use of globals. However, it is only very slightly different from Apache::Regsitry. The difference is that globals get cleared after each invocation, so you don't have to worry about them retaining values. You will not have problems with subroutines creating closures if you're using global variables. You also won't have problems if you're passing varaibles to subroutines. You will only have trouble if you use lexicals in your subs that are defined outside the scope of the sub. This is bad: my $foo = 7; print_foo(); sub print_foo { print $foo\n; } But this is not: my $foo = 7; print_foo($foo); sub print_foo { my $foo = shift; print $foo\n; } One thing that I had to change when moving to PerlRun was that the existing scripts made extensive use of libraries that were not proper modules, i.e. they did not declare packages, but just used a simple require lib.pl to define a bunch of stuff in the current namespace. That doesn't work with PerlRun or Registry. There are various approaches for dealing with this, the quickest and worst being to change the require file to a do file. The best is to make them actual modules. - Perrin
Re: Any known good configuration for mod_perl DSO?
Wilbur, Charlton wrote: Or am I looking at rolling my own RPMs or installing from source RPMs? My suspicion, confirmed by Mr Turner, is that this is tied directly to shared libraries and toolchains, and so I suspect further that the problem will go away if I build everything from scratch using source RPMs. I highly recommend building your own RPMs. It works great, you get exactly what you want (and nothing you don't want), and you can install them quickly on a cluster of machines because you don't have to recompile on each one. - Perrin
Re: missing .al files with apache/mod_perl
Allen Day wrote: Furthermore, this file doesn't exist in my filesystem. How is it possible that (1) the module works without this apparently required file at the command line but (2) doesn't work with apache/mod_perl ? How is it possible? Two ways: you could be wrong about the existence of the file, or the situtation that requires the file might only arise when you use it with mod_perl. I'd suggest you start debugging it by looking at the things that are different when running it from mod_perl: the user, environment variables, working directory, ways that you call it, etc. One of those things is probably responsible. - Perrin
Re: when to mod_perl?
md wrote: I was just a bit worried about the amount of static content. In the past I've had a lot more hardware to work with and I never had to worry about it much. Static content is easy; just don't serve it from mod_perl. The proxy approach is good, and so is a separate image server (which you can host on the same machine). I've found thttpd to be an amazingly efficient server for images, but a slimmed-down apache does very well too. - Perrin
Re: mod_perl memory leaks on Windows
Andrey Prokopenko wrote: After a fresh restart, I started Apache/mod_perl. Then i issued a little stress test using simple perl script with LWP::Simple. I ran a performance test on /mod_perl/index.pl page for 10 minutes. The source code of that page is given below : - #!/perl/bin/perl use CGI qw(:all); print header; print Hello, World!; - After 10 mintues of execution, the memory consumption of Apahce.exe had jumped from approx 5 MB to 120MB ( virtual memory ). I ve noticed, that Apache child grown by 4-8kb per each request. Have you tried it without using CGI.pm? Have you tried writing a handler instead of using Apache::Registry? I know that mod_perl on Windows is a development version but still this memory leak thing is pretty obvious and should have been taken care off. There's a pretty good chance that it's not mod_perl causing it. It may be just that Win32 perl grows a little when you run that CGI::header call over and over. The upcoming mod_perl 2 will have better support for Windows. You can find information on it here: http://perl.apache.org/release/docs/ - Perrin
Re: mod_perl memory leaks on Windows
Andrey Prokopenko wrote: I tried a plain Perl cgi script, with no module used, and still the same. ;(( Do you mean that this leak cannot be fixed from Apache/mod_perl side ? I can't say for sure since I don't use mod_perl on Win32, but most of the process growth problems reported when using mod_perl are not caused by mod_perl. They are usually caused by the perl code involved, but it looks like a mod_perl problem because when running under CGI you never get the chance to notice this growth (because the processes are not persistent). Sorry, but for now we're stuck with Apache 1.3.x, because we use module, which cannot work with Apache 2.0. So i seek appropriate solution based on Apache 1.3 version. Why can't the module work with Apache 2? You might be able to get some advice here on how to fix it. Otherwise, you could look at alternatives like PerlEx, but they may have the same issues. - Perrin
Re: [ANNOUNCE] Apache::DBI 0.89
Stas Bekman wrote: the threaded mpms will need a new version/mode of Apache::DBI using threads::shared, currently available only for 5.8.0-tobe, unless things will get backported to 5.6.2. Currently it seems that the threaded mpms will be safe to use only with 5.8.0, unless again things will get backported. Otherwise chances are that 5.8.0 will be a requirement. I saw that message, which is why I mentioned 5.8, but I was wondering if anyone has seen discussion of whether or not DBI will be safe to use with 5.8 threads. Does anyone know? - Perrin
Re: XML::Write and XML::Simple incompatibility
Prakash Chatterjee wrote: Thanks people. It turned out to be an Expat problem. As advised, we compiled Apache without EXPAT - and hunky dory - it works. Sorry about that, I steered you wrong: it was a mod_perl/apache problem. I know about the Expat issue, but I didn't think either of those modules would work if you had this problem and it sounded like you were only getting it when trying to use both of them together. - Perrin
Re: Apache::LightBackhand
Ricardo Basto wrote I'd like some feedback on this module I just wrote. It's something like a reverse proxy, but intended as a gateway from the fully-functional apache/mod_perl to another webserver, probably behind a firewall in the corporate network. That sounds just like mod_proxy's reverse mode or several of the mod_perl proxy modules on CPAN. Have you looked at those? Also, the name is confusing because it doesn't seem much like mod_backhand. Don't get me wrong, the code looks fine and it's nice of you to make it public. I wouldn't suggest putting it on CPAN though unless it does something that the others don't do. - Perrin
Re: separating C from V in MVC
Tony Bowden wrote: I'd have to disagree. Maybe Mike had something different in mind when he created Class::DBI, but as the current active developer on it, I'm definitely pushing it in the R-O direction. Like Dave, I always start by thinking of my database schema and then Class::DBI provides a way to translate that, table - class, row - object, column - method. Throw in some simple relationship builders and a sprinking of syntactic sugar, and that's pretty much there is to Class::DBI. Tangram may have loftier goals, but in general that's pretty much all there is to any of them. And I don't think that the angle you approach your data design from -- classes or tables -- has much bearing on which tool you would use, with the possible exception of Tangram. SPOPS is explicit about wanting to support legacy schemas without changes. I think that in this realm there is Tangram, which tries to bring some extra stuff like database modelling of object inheritance and queries written in perl, and everything else. Things like Tangram model the domain objects, i.e. concerts, seats, people. Things like Alzabo model the database objects, i.e. tables, rows, foreign keys. I think on this front they both try to do both. Class::DBI does anyway. My casual perusal of the documentation certainly made it look like Class::DBI hid a lot more of the database stuff than Alzabo. After the configuration is done, the database concepts like foreign keys are never explict. I guess my point here is simply that I think there isn't so much difference between most of these tools and that characterizing them as being anti-database or too heavy is not accurate. As a sort of wrap-up to this round of O/R technology discussion, I want to post a link to this quote from the author of SPOPS where he talks about the practical limitations of SQL abstraction. I thought it was a pretty astute observation: http://perlmonks.org/index.pl?node_id=162259 - Perrin
Re: [RFC] Change our habits in module naming?
Also, a module map might be a good thing to create, i.e. an improved version of this: http://perl.apache.org/src/apache-modlist.html. Well, because the module list has now moved into the Perl Module List entirely, we are removing it with the new site. What I meant was that since you can't expect all of the existing modules to change their names you could make a little directory page that follows the organization you're proposing and have it list the existing modules in each category. Maybe not worth it, but it could be useful for newbies. - Perrin
Re: MVC Topic Joy
In most cases the Handler is set to view, in which case View.pm instantiates other modules objects, (and those instantiations use other url string data to determine what to construct into the object). View then just spits out the default head, body (created with the other objects) and footer. All of the real work is done by the other modules. View.pm could care less what comes back from $html_obj-view_data. It just adds the result to $body. It's the html module's job to fill the return from view_data with the correct information. It sounds like you have a system that works well for you, and that's what really matters. I would probably try to get this default HTML that View.pm puts out into the same place the rest of your HTML is created, especially since it seems like View.pm is responsible for interpreting request data and calling methods on model objects. (View.pm is maybe a somewhat misleading name, since it isn't the part that generates the HTML view.) - Perrin
Re: [OT] WebObjects [Was: Re: separating C from V in MVC]
WO is amazing, no two ways about it. Once you use it, everything else sucks. There are no exceptions. That's kind of a rude statement to make on this list, where all of these people are offering free software and support to you. It's been a few years since I last evaluated WebObjects, but it certainly didn't seem like a panacea. It had a number of interesing ideas behind it, but its insistence on trying to hide all the details of the browser interaction made some simple things very hard, especially since it tried to keep all of the state information server-side. The problems it had with back buttons and multiple browser windows come to mind. It also seems to encourage design where browsers directly request a view, rather than calling a controller which chooses a view depending on the outcome of processing. That could be just a shortcoming of their introductory documentation though. - Perrin
Re: separating C from V in MVC
My general motto is tiers eq tears ... I've never seen a really comfortable OO/SQL bridge. So who's talking about an OO/SQL bridge? Not me. At least not an automatic one. I write the SQL by hand. Group bys, order bys, multi-table selects, locking, SQL query plans and index optimisation all rightfully belong to the database but are an anathema to a simple OO/SQL bridge. I use all of those things in my model objects. The model objects use SQL to implement methods like $product-user_comments() or $address-save(), and sometimes it is complex. The point is that the rest of the application gets to the database through the model objects, rather than through SQL. Encapsulation, reuse, blah blah blah. Generally I try to minimise the layers/tiers/abstraction between the front-end and the database - for me OO/SQL abstraction is something akin to 'GOTO considered harmful'. I think you're overgeneralizing based on some kind of O/R mapping tool you've used that tried to do too much. Wrapping up the knowledge of how to work with the database to accomplish certain tasks inside of objects is no different from any other application of OO programming. - Perrin
Re: separating C from V in MVC
This approach works for some things, but I think it falls down when it comes to doing complex database searches, particularly searches generated ad-hoc on multiple columns in multiple tables. In general, the user interface you provide for a search will be much higher-level than the SQL that implements it. That's what is gained by making this kind of object: it's a place to put the translation of the business concept find people in New Jersey into the four table join that might be needed to find them. This is why Alzabo is much lower-level than what you have above. I needed something where I could easily construct queries that might include 1+ tables, with various types of searches of individual columns in those tables (equal to, between, less than, like, etc.) with dynamic sorting (again, on any of the columns in any of the tables, ascending or descending). I would just write SQL at that point, but I do realize that Alzabo provides more database independence. You could easilly use Alzabo to build the queries that implement the model objects I'm talking about. With what you're proposing, I think you could easily end up with either: A) a ridiculously flexible interface that looks sort of like SQL, except where it is SQL, except where it's only sort of like SQL, etc. B) a ridiculous profusion of classes, methods, or both. I think you're overestimating the number of search variations and model objects that most applications have. For example, Fran's application generates his stale watches report. There's no need to create a fully-parameterized search interface to Watch objects just for that. Instead, you make a Watches-find_stale() method or something and keep the knowledge of what that means to the database hidden behind that API. At eToys we had a very large and complex (highly normalized) database, and this approach worked very well. I think it works best when you have a complex database requiring complex SQL, because if you just have a bunch of simple 1-1 table mappings there isn't really much to abstract. I'm thinking of trying out SPOPS the next time I do this kind of thing, because it will automatically handle the no-brainer cases (1-1 mappings) and allow me to write the SQL for the complex cases by hand, all with a consistent interface and hooks for caching, etc. Trying to jam a thick layer of OO-goodness over relational data is asking for a mess. OO has its place, but if your application is primarily about the database, I don't think that a heavy OO layer on top of that will do you much good. There's nothing thick or heavy about the way I do it. There is no automatic SQL generation, and nothing to prevent me from using any SQL tricks that my database supports. It's just a way of wrapping up chunks of code that implement data-related tasks into an easy task-oriented API for the controller (or other model objects) to act on. - Perrin
Re: separating C from V in MVC
An Object-Relational mapper takes objects and stores them in a relational database, as transparently as possible. I think the most pure example of this I've seen in the Perl world is Tangram (www.tangram-persistence.org). SPOPS is also an O-R mapper (actually, its a generic Object persistence mechanism but it seems to most feature-rich when used with an RDBMS). A Relational-Object takes a relational database, and provides access to it (select, insert, update, delete) via objects. Class::DBI, Alzabo, and DBIx::RecordSet are examples of such a beast. I would actually put Class::DBI in with the first set. To me the difference is not O/R vs R/O, since both of them go both directions. Rather it's a question of what you're modelling in your objects. Things like Tangram model the domain objects, i.e. concerts, seats, people. Things like Alzabo model the database objects, i.e. tables, rows, foreign keys. My approach falls in the first camp, although I don't currently use any OOP tools for assistance. - Perrin
Re: [OT] WebObjects [Was: Re: separating C from V in MVC]
Not quite sure what you mean here. The general WO request-response loop is 1 Process request 2 Perform action 3 Return response Step 3 is entirely dependent on the previous two, just like any mod_perl/CGI/php app. The introductory documentation makes it look each URL is tied to a specific HTML template. It may just be a problem with that documentation though. I think the most perfect web development env would be a WO-style framework build on top of mod_perl You can assemble various parts of it from CPAN. Most of the perl O/R frameworks are not as ambitious as EOF, but Tangram is trying pretty hard. The templating tools available for perl are as good as the ones in WO. Using those with one of the MVC frameworks discussed here gets you quite a bit. The main thing you don't get is GUI tools, which there doesn't seem to be much demand for from the mod_perl community. - Perrin
Re: [OT] what drives Amazon?
Does anybody know which is the technology behind Amazon? If you look at their job listings, you'll see it's a lot of C/C++ and Perl, with a smattering of other things, running on Unix. That's pretty typical of the really big sites. - Perrin
Re: Mapping to location /
md wrote: What I'm really trying to do is more like the PHP I'm replacing. I should be able to go to: www.someserver.com/index.phtml for a dynamic page and www.someserver.com/index.html for a static page. I'm guessing that my best solution would be to use HTML::Mason or Apache::ASP instead of Template-Toolkit. Why? Just because you don't have literal files for those URLs with TT and with Mason or ASP you would? I don't really see the problem. You can map all the URLs that end with a certain extension to one module that does some work and then calls a template. You can map individual URLs or sets of URLs to separate modules that do different processing and call a template. You could even put the actual files there and use Apache::Template to serve them. Apache::Template has a hook to add your processing code before the template gets run, and you can have multiple handlers that do different processing in different locations. I may try using the PerlTransHandler to change the uri to a location...say with www.someserver.com/index.phtml the uri gets changed to /modperl (or www.someserver.com/somedir/index.phtml the uri becomes /modperl/somedir) which is used in a Location /modperl directive. What does that get you? I don't see why you would want to do that. - Perrin
Re: separating C from V in MVC
Fran Fabrizio wrote: Now, how do you represent in the model a complex query that joins across 5 of the nouns? Others have already commented on this, but I want to point out that this is a general OO modelling question, not an MVC one, and there are many resources available to help you learn this stuff. I'd suggest getting to your local computer book store and browsing through some OO programming titles. In your concert example, if I wanted to define a report that showed me all of the seats that were purchased by people from New Jersey with a Mastercard in the last week, how would I represent that? That's a tricky one, because it doesn't make much sense to put all that logic about finding users' home states and payment types into a Concert class. You could manipulate the objects to accomplish this: my wanted_seats; my seats = Model::Concert-findSeatsReservedAfter($date); foreach my $seat (seats) { if ($seat-person()-address()-state() = 'NJ') { push wanted_seats, $seat; } } As you can see it gets messy fast, and I didn't even cover the Mastercard part. It would probably have terruble performance too. This is why people usually just write this kind of report as a big SQL query instead. You can make a model object called ConcertSeatSearch: seats = Model::ConcertSeatSearch-findSeats( reserved_after = $date, payment_type = $card, user_state = $state, ); Just be careful that you don't end up making this into something that mirrors the SQL exactly. There might be 4 tables involved in finding out what kind of credit card the user had, but that gets hidden behind this API. If you find yourself writing classes that take options like where = 'date ' . $date you are reinventing SQL, and you've lost your abstraction. - Perrin
Re: mod_perl/passing session information (MVC related, maybe...)
Rob Nagler wrote: A session is useful for very limited things, like remembering if this user is logged in and linking him to a user_id. We store this information in the cookie. I don't see how it could be otherwise. It's the browser that maintains the login state. My preferred design for this is to set one cookie that lasts forever and serves as a browser ID. If that user logs in, you can associate a user ID with that browser ID, on the server side. You never need to send another cookie after the very first time someone hits your site. If you decide to attach new kinds of state information to the browser, you still don't need to send a new cookie. Many sites need to keep track of state information (like what's in your shopping cart) for anonymous users who haven't logged in. Having this unique browser ID (or session ID, if you prefer to give out a new one each time someone comes to the site) lets you track this for unregistered users. Consider the following scenario: * User logs in. * Site Admin decides to delete the user. * In our stateless servers, the user_id is invalidated immediately. * Next request from User, he's implicitly logged out, because the user_id is verified on every request. In the case of a session-based server, you have to delete the user and invalidate any sessions which the user owns. I don't see that as a big deal. You'd have to delete lots of other data associated with a user too. Actually deleting a user is something I've never seen happen anywhere. Although Oracle can be fast, some data models and application requirements make it hard to do live queries every time and still have decent performance. This is especially true as traffic starts to climb. I've tried to put numbers on some of this. I've never worked on a 1M/day site, so I don't know if this is the point where you need sessions. What sites other than etoys needs this type of session caching? Well, eToys handled more than 2.5 million pages per hour, but caching can be important for much smaller sites in some situations. It's not session caching necessarilly, although we did cache session data in a local write-through cache on each server. We knew that the database would probably be the bottleneck in scaling our application, and it was. We took pains to take as much work as possible off the database, so that it could spend its resources on handling things that can't be cached, like user submitted data and orders. Here's a situation where a small site could need caching: suppose you have a typical hierarchical catalog site, with a tree of categories that contain products. Now suppose that the requirements for the site make it necessary to do a pretty hairy query to get the list of products in a category, because you have some sort of indirect association based on product attributes or something and you have to account for start and end dates on every product and various availability statuses, etc. Categories should only be shown if they have products in them or if their child categories have products in them. Keep piling on business rules. Then the UI design calls for the front page to have a Yahoo-style display showing multiple levels of the category hierarchy, maybe 70 categories or so. Sure, you get your DBAs to tune the SQL and to put all the indexes in place, and it gets the results for a single category pretty fast, in .08 seconds, but you have 70 of them! When you throw multiple users in the mix, all executing these queries every time they hit the homepage, your database server will burn a hole through the floor. Or you can take advantage of your domain knowledge, that the data used in generating this page only changes every 6 hours or so, and just cache the page, or part of the page, or the data, for an hour. Maybe I just have bad luck, but I always seem to end up at companies where they give me requirements like these. And then they say to make it really fast and handle a billion users. They are happy to trade slightly stale data for very good performance, and part of the requirements gathering process involves finding out how often various kinds of data change and how much it matters if they are out of date. (For example, inventory data for products changes often and needs to be much more current than, say, user comments on that product.) - Perrin - Perrin
Re: mod_perl/passing session information (MVC related, maybe...)
Vuillemot, Ward W wrote: There is a Apache::Session which is sufficient to check to see if they are logged in, et cetera. But I want to be able to remember the last query so that I can return results into multple pages along with memory of where in the stack I am at. You can store anything in Apache::Session; it's just a persistent hash table. However, storing query results based on a user's session is not a good idea! What if your users open up two browser windows and tries to do a search in each one? Server-side session data is global to all browser windows, so they'll get bizarre and incorrect results. If you check any of the major sites you'll see that they handle multiple windows correctly. My suggestions would be to have a separate cache just for query results. Turn the sorted query parameters into a key. If someone goes to page 2 of the results, you just pull them out of the cache. There are persistent modules, but I am wondering if there is a better way with Apache and mod_perl There have been a few benchmarks of ways to store a persistent hash. I'll have some new numbers on this soon, but for now I'd suggest looking at Cache::Cache, MLDBM::Sync, or Cache::Mmap. - Perrin
Re: mod_perl/passing session information (MVC related, maybe...)
Jeff AA wrote: Agreed, but he wasn't talking about storing the results, just the query parameters and current offset / number of rows, which is a-ok for putting into a session. No, that's exactly what ISN'T okay for putting into a session. If a user opens two browser windows, does a search in each, and then pages forward in each set of results, he will get completely wrong pages if you do this. The query parameters from the first search will be written over and lost. Don't forget that you can have multiple sessions - store the query params in a session identified by a query_id so that subsequent requests just say something like: A HREF='/searchquery_id=123456789action=next'Next/A You could do that, with a unique ID for each set of parameters, but you might as well just put the parameters right in the link unless they're very long. Don't mix transient query sessions with a User Session that stores info about the user's logged in state etc. It would be normal for one user to have multiple queries in a login session Hold on, I think we actually agree, but you're using the word session for a bunch of different things. What you're saying here sounds like the opposite of what you said above. In common usage, a session is the state of the user's interaction with the application. A cache of query data would be something else. Or even to use a database that has a decent approach to caching. MySQL promises automatic cacheable paged queries in the near future. And if you write your own DB cache, you then need to manage the DB / cache synch issues, cache size, cache expiry etc etc issues. Good cache is very hard to do! better to get it from a real data bank. MySQL is fast, but usually not as fast as simple disk access. Cache::Cache and Cache::Mmap handle the details of the cache stuff for you, making it pretty easy. - Perrin
Re: mod_perl/passing session information (MVC related, maybe...)
John Siracusa wrote: On 6/12/02 12:57 PM, Per Einar Ellefsen wrote: But what if someone opens one of the links in a different window, and continue on the same pages as in the original window, but with different parameters? The session ID would be the same, the context id would be the same, but the params would be different, right? Well, then things break I guess... :) Maybe you could do some magic based on what browsers send as the referrer when users explicitly open a link in a new tab or window? Probably not worth it... Right, which is why you shouldn't try to store server-side state for anything that could be different in multiple browser windows. Only store global browser information on the server-side. Everything else has to go into the links and forms. - Perrin
Re: mod_perl/passing session information (MVC related, maybe...)
Rob Nagler wrote: Stateful instances are also problematic. You have essentially two paths through the code: first time and subsequent time. If you write the code statelessly, there is only one path. Fewer bugs, smaller code, less development. I find you can tie this cache stuff up inside of your data access objects and make it all transparent to the other code. That worked really well for me. There are hooks for this in some of the O/R mapping modules on CPAN. Sessions are caches. One of the things Java programmers often do wrong is cache general data in the session, because the servlet API makes it so easy to do. But most data that people cache (as we're seeing in this discussion about search params) is not user-specific and thus doesn't belong in the session (i.e. everyone who searches for foosball gets the same result). A session is useful for very limited things, like remembering if this user is logged in and linking him to a user_id. Almost everything else belongs either in separate database tables or in the query args passed on each page. Oracle will cache the query compilation and results so it is very fast (basically a round-trip to database server) for the second query. We execute these two queries on every paged list on every request. Although Oracle can be fast, some data models and application requirements make it hard to do live queries every time and still have decent performance. This is especially true as traffic starts to climb. That's when you can add in some caching and take a lot of stress off the database. There are a million ways to implement caching, from denormalized tables to replicated databases to BerkeleyDB to mod_proxy and most web applications have some data that is read-only or close to it. (I know that yours deals with financial data, so in your case it may actually have to be all real-time data.) - Perrin
Re: mod_perl/passing session information (MVC related, maybe...)
Jeff AA wrote: Interestingly MySQL and other DBs are often as fast as simple disk access - contrary to popular wisdom, most DB engines actually cache in memory, with more data access information and hence effective cache memory usage than is available to external cache components. Yes, Network transference can be an issue - but hey! be a masochist, buy a switch! It's a simple rule: if you do less work, you will finish faster. Reading a file will go to the file system code in the kernel, which uses some sort of in-memory cache on any modern OS. That means that for any frequent access data you are reading it from memory using system-level calls. By contrast, MySQL has to deal with network transfers and SQL parsing before it reaches that stage. It's not a huge difference, but it is a difference. I'll have numbers on this stuff soon as part of my article on data sharing with mod_perl, so that people can compare and see if it's worth the effort for them. The more important reason to cache is scalability. Every time you don't hit the database, that means more resources are available to handle the queries that can't be cached. On a site with heavy traffic, that's very important. I parse 'use a cache for db stuff' as 'my XYZ cache component is way smarter than all the guys at 'Oracle|Sybase|MySQL' combined', or 'I know my data better than the database, cos I'm a kewl Koder'. Actually, I really parse 'use a cache for db stuff' as 'I don't really understand databases, 3NF and indexing, and can't be bothered learning to use them well'. I've worked with some good DBAs, but there is a limit to what they can do. Ultimately, a database is designed to always give 100% correct up-to-date results, but in most web applications people would prefer to get slightly out-of-date results if they can get them much faster. Databases don't know how to do that. Why should you go to MySQL every time someone hits the front page of Slashdot just to give them the very latest count on comments? Caching that page for 1 minute takes a ton of load off the database and doesn't really impact the user experience. I fully agree that optimizing the database and SQL is the first step, but correct use of caching can make a huge difference on high-volume sites. - Perrin
Re: separating C from V in MVC
Wow, this is a long one. As usual, everyone has slightly different ideas about how to do MVC, so keep a grain of salt handy. This basic pattern repeated ad infinitum. It's grown way out of control, is a pain to work with, and just feels wrong, very wrong. :-) We've all been there. 1. Is there one Controller or many? Usually there are many. Should I have one for each main area of my site? /myapp/admin/ goes to an Admin Controller, /myapp/reports to another controller, etc... That's how I would do it. The idea is to group the things that are related together, since they tend to change at the same time. 2. Does the first part of my code above even remotely resemble a Controller? Sort of. It does choose a view and it does parse some user input, but a controller is more than just a dispatcher. It would include some of the code that you're currently putting into your doDoctorActivity() sub. The idea is that the model objects represent just the data in your application (the nouns) and the controller understands how to translate user input into a series of method calls on the model objects to carry out the user's request. It's hard to give a good example that is short, but let's say you were building an application to sell concert tickets. The act of buying the ticket might involve model objects representing a concert, a user, a form of payment, etc. The concert object knows how to reserve a specific seat (or call a seat object to do that). The payment object knows how to verify and charge a credit card. The user object has a mailing address. The controller knows how to turn the user's form data into a bunch of method calls on these objects that accomplish reserving the ticket and charging the user. If you find yourself writing a BuyTicket module, that's a controller not a model object. 3. How do you prevent a Controller from just becoming another big if statement, or is this their purpose in life? If you break up your app into multiple controllers, there will probably only be a few different actions that each one handles. That's a pretty small if statement, or you could use a dispatch table. Modules like CGI::Application have already written the dispatch table code for you, so you just provide the configuration that maps actions to subroutines. 4. In the case of a form, what perl structure is used to pass the data into the model? You don't pass a form directly to a model object. You parse the form, then you use the API provided by the model object. Remember, we want to be able to use these same model objects from a cron job. my $hospital = $apr-param('hospital'); $doctor-set_hospital($hospital); 5. Do you create an actual class for each form? Similar to #1, each form might have it's own controller class, or you might group some related forms (that act on the same data) together in a single controller. 6. Do you need to create objects at all? Is OO a prerequisite to MVC? Modelling your data as objects is sort of an underlying assumption in MVC. You could do a clean design without using OO, but it would be a little odd and the model objects might not be very reusable. 6.5. (thought of while proofreading :-) Is the statement there is one set of controllers for each defined view correct? No. In other words, if we someday want to output the reports section of the site as Excel spreadsheets in addition to HTML, would we define a new set of controllers or how would that work? You would make your existing controllers understand the piece of user input or context that means they want Excel format, and have them pass the model data to a different view in that case. 7a. Is it insane to leave my SQL hard-coded in there? You're going to have SQL somewhere, but if you wrap it up into objects that represent your data, it's easier to maintain. It hides all of that specific database knowledge from the rest of the application and avoids repitition. At eToys we had a tremendous amount of data associated with each product. It spanned many tables and was not very easy to work with. However, once I had written an object representing a product, the search code, shopping cart code, product page code, etc. could all use it. When we added new properties, I only had to do it one place. OO modelling is a big subject and lots of good books have been written on it, so I won't say more about it here. 7b. Should I really investigate real object persistence like discussed at the POOP site (I have used Tangram with some success on tiny side projects but nothing remotely this size)? Only if you like what it does for you. I generally prefer to write the SQL myself because of the tuning opportunities it affords, but this is the sort of topic that many people have strong opinions on. Anyway, objects that contain hand-coded SQL are just as real as objects that use a POOP module to generate the SQL for them. Begging the question, should I really be migrating to
Re: separating C from V in MVC
Ward Vuillemot wrote: I know we are straying WOT, but I would love to get a better feel for XML, XSLT and AxKit. Barrie Slaymaker has written a couple of articles on perl.com that serve as a good intro to AxKit. - Perrin
Re: separating C from V in MVC
John Hurst wrote: Still, I don't think that replacing this: Location /search SetHandler perl-script PerlHandler Controller::Search /Location with this: [% Ctrl.Search() %] makes Controller::Search any less a controller. You're right. It just looks kind of odd to me, invoking a template for something that is not a display-related task. It looks like the way people typically do MVC in Mason or Embperl, with a first template that doesn't do anything but invoke a module to take over the processing. Obviously, the stand-alone dynamic pages are not MVC at all. They exist because there are often 'glue' pages that don't warrant the comlexity of MVC (those that don't need M and have very simple VC needs). I agree that there is often a need for some quick and dirty internal-use pages (admin or reporting usually) that don't require the extra baggage. - Perrin
Re: separating C from V in MVC
Gerald Richter wrote: Embperl 2.0 can invoke such a controller (it's called application object there) after it has setup it's request parameters (GET/POST data, session data, etc.) and before any templates are get a chance to run. That sounds like a good addition to Embperl. Can you give a URL for the documentation on how to use this? - Perrin
Re: MVC Topic Joy
Jon Robison wrote: I should never really have to edit #3 (the Viewer), because the HTML construction should be done in #2. If I find myself editing my viewer to accomodate some function I am adding to the overall system, I know I need to re-think what I am doing. In an MVC system, you would definitely need to edit the controller any time you change the input side of the user interface. You may or may not need to change the model and view as well. Which part handles taking the user input, figuring out which methods to call on the model objects, and choosing a view (usually a template) to show? This is all stuff that the controller would do in an MVC system, and you don't seem to have one in your description. If you don't have a controller, you will end up wedging that stuff into the model objects which makes them a lot less reusable. Don't get me wrong: a basic script + a template is still better than a basic script + a bunch of print statements, but there is value in the separation of the controller and the model too. - Perrin
Re: separating C from V in MVC
Ray Zimmerman wrote: So how is everybody else handling URL mapping? In httpd.conf: Location /search SetHandler perl-script PerlHandler Controller::Search /Location Location /cart SetHandler perl-script PerlHandler Controller::ShoppingCart /Location Most applications only have a handful of controllers, so this works fine. You could also look at the way OpenInteract does it, which allows you to gather all the related stuff including this configuration into a single package that you can install in one shot. - Perrin
Re: MVC Topic Joy
Jon Robison wrote: In most cases the Handler is set to view, in which case View.pm instantiates other modules objects, (and those instantiations use other url string data to determine what to construct into the object). View then just spits out the default head, body (created with the other objects) and footer. The confusion here is that your View.pm is not a view, but a controller. It's the html module's job to fill the return from view_data with the correct information. Then it sounds like the html module is your view. It's the part that accepts data and generates HTML. - Perrin
Re: separating C from V in MVC
Valerio_Valdez Paolini wrote: On Mon, 10 Jun 2002, John Hurst wrote: In the filesystem. Directly requested .tt files are all sent to a default template handler: ... I used html pages with augmented tags parsed by a standard handler: Those are both interesting and may be the most appropriate solution for the problems you're working on, but I wouldn't call either of them MVC. You are going straight to a view (template) and letting it drive all the decisions. In an MVC application, you would go to a controller that would do some work and then decide which view to show. - Perrin
Re: FreeBSD Apache/mod_perl/OpenSRS/expat problem + solution
I just ran down a problem that was somewhat hard to find, and I didn't see any mention of anything like it in the archives anywhere. The expat issue has been discussed quite a bit on this list, and is documented here: http://perl.apache.org/guide/troubleshooting.html#Segfaults_when_using_X ML_Parser Sorry to hear you had trouble finding it. That section of the guide is the first place you should look when you're having segfault problems. - Perrin
Re: [OT] MVC soup (was: separating C from V in MVC)
What I didn't like about this is I then had to adjust the so-called controller code that decoded the user input for my request object to include these new features. But really that data was of only interest to the model. So a change in the model forced a change in the controller. No, a change in the user interface forced a change in the controller, which is fine. Your user interface now supports parameters of starting page and page size, so the controller has to know how to handle those parameters and translate them for the model. (Incidentally, it's not such a good idea to make page size a query arg. Better to put it in some config file on the server.) For example, you might have controller code like this: my $query = $apr-param('query'); my $page = $apr-param('page'); my $search = Model::Search-new( query = $query, page = $page, ); The controller is tightly coupled to parsing and handling user input, but knows nothing about what that model object will do with it. It is basically translating HTTP requests into sets of method calls on model objects. So now I just have been passing in an object which has a param() method (which, lately I've been using a CGI object instead of an Apache::Request) so the model can have full access to all the user input. It bugs me a bit because it feels like the model now has intimate access to the user input. I agree, this is not good. The controller is supposed to be parsing that stuff and abstracting it from the model. The model shouldn't care if you decide to start encrypting some parameters, or getting them from the user's session, or using different names for them on different forms. My second, reasonably unrelated question is this: I often need to make links back to a page, such as a link for page next. I like to build links in the view, keeping the HTML out of the model if possible. But for something like a page next link that might contain a bunch of parameters it would seem best to build href in the model that knows about all those parameters. I don't think it makes a huge difference, but I would probably assemble these either in the controller or in the view. The model would just provide the data. If they are simple links (i.e. same params always, no logic) you should be able to use any templating system to build them. Template Toolkit has a URL plugin for convenience: http://www.template-toolkit.org/docs/default/Modules/Template/Plugin/URL .html - Perrin
Re: Building high load mod_perl/Mason servers
We are going to be moving to mod_perl, but I am worried about how to keep from getting into the same kind of trap with mod_perl as with PHP. You may want to read my article about building a large site with mod_perl: http://perl.apache.org/release/docs/tutorials/apps/scale_etoys/etoys.htm l. So I am thinking whatever I do it should fit within an existing framework, something like Mason. But I am confused about what real advatage Mason provides, and how things like source code control would work if we are running lots of servers. Your best bet to avoid spaghetti code with Mason is to use OO perl modules for all of the real functionality in the application and then use Mason's components as templates for displaying the results. Mason is good at handling the plumbing aspects of web development and provides an environment for doing HTML templates with in-line perl. See this article for more on appropriate use of components and modules: http://masonhq.com/user/autarch/Comps_vs_modules There are many frameworks for mod_perl, so if Mason doesn't look like exactly what you want you can check out some others here: http://perl.apache.org/#appservers Do people use rsync to keep up to date? If you have a high-volume commercial site, you would be better off with a slightly more structured process. You can set up a script to make releases which will tag the CVS tree and build a release in some package format like RPM or .tar.gz. Then you can QA that release and later install the same release, all with development continuing in CVS for the next release. This allows you to easilly go back to a prior release if a disastrous bug is found in production. (Well, there are issues like config files and database changes which complicate things, but that's the basic idea.) - Perrin
Re: [OT] MVC soup (was: separating C from V in MVC)
Bill Moseley wrote: My MVC efforts often fall apart in the C an M separation. My M parts end up knowing too much about each other -- typically because of error conditions e.g. data that's passed to an M that does not validate. And I don't want to validate too much data in the C as the C ends up doing M's work. I agree that this is one of the thornier problems. For simple things you can just throw exceptions, as Jesse mentioned. This is all you need to do for system-level problems like failing to connect to the database. The difficult part is when you need to provide feedback to users on their incorrect input. For example, if you have a form for registering as a user which has multiple fields, you want to be able to tell them everything that was wrong with their input (zip code invalid, phone number invalid, etc.), not just the first thing you encountered. Putting that into a model object is awkward, since coding your constructor or setter methods to keep going after they've found the first error feels wrong. You can write a special validate_input() method for it which takes all the input and checks it at once returning a list of errors. You could also just punt and push this out to the controller. (Not very pure but simple to implement.) Either way you can use one of the convenient form validation packages on CPAN. Anyone have links to examples of MVC Perl code (mostly controller code) that does a good job of M and C separation, and good ways to propagate errors back to the C? You could look at the OpenInteract code. It includes some good examples. - Perrin
Re: Separating Aspects (Re: separating C from V in MVC)
Sam Tregar wrote: Now, I don't use HTML::Template::Expr. I think it's generally not such a good idea. But it's there if you want it... For posterity, and possible inclusion in the next rev of the templating tutorial, how would you recommend people handle this sort of situation without using HTML::Template::Expr? Suppose you have a model object for a concert which includes a date. On one page, the designers want to dipslay the date in a verbose way with the month spelled out, but on another they want it abbreviated and fixed length so that dates line up nicely. Would you put that formatting in the controller? What if you had a model object that generates a list of these concerts, and on a certain page the designers want to show it in two columns. Would you split it into two arrays in the controller? - Perrin
Re: tutorials (was: Re: rfc Apache::Dynagzip)
Stas Bekman wrote: The ongoing discission of MVC is a good example of a tutorial candidate Incidentally, I already wrote a fair amount on this subject in the eToys-related tutorial: http://perl.apache.org/release/docs/tutorials/scale_etoys/etoys.html#Code_Structure There's a diagram, code examples, etc. I wasn't planning to write a spearate MVC one because I've already said most of it there. - Perrin
Re: DBI Bug
Udlei Nattis wrote: hi, sorry my english ;) when i add this line in httpd.conf PerlModule DBI or use DBI(); in startup.conf apache dont start, i receive this error: /usr/local/apache-2.0/bin/apachectl: line 192: 12547 Segmentation fault $HTTPD /usr/local/apache-2.0/bin/apachectl start: httpd could not be started i test it in Apache 2.0/Perl 5.8.0RC1/Modperl 1.99.02/03 Apache 2.0/Perl 5.7.3/Modperl 1.99.02/03 Apache 2.0/Perl 5.6.1/Modperl 1.99.02/03 Apache 2.0-cvs/All Perls/All Modperls It definitely works with the Apache 1.x/mod_perl 1.x/perl 5.6.1 combo. Maybe someone else can verify that they've run DBI under mod_perl 2? You might need to use the pre-fork MPM when using DBI, depending on how well your database driver works with threads. You should also make sure you compile all of these with the same compiler, to ensure compatibility between libraries. - Perrin
Re: separating C from V in MVC
Rob Nagler wrote: The way I understand how plugins work is that they are arbitrary classes. But how do you share behavior? I probably wouldn't use a plugin for something that needed to output HTML, because that would prevent the designers from editing it. A macro (basically a mini-template) could be broken down into smaller shared templates, but there is a practical limit to that approach. FILTER does not shared behavior, but is a pipe mechanism. Yes. I think it would be a good way to do the FONT trick you mentioned though. There is no protocol for communicating between these various components except well-known global variables. That's correct. A template can call macros which are parameterized (e.g. a macro for making large text headlines which accepts the text as a parameter), but that's not exactly the same thing. If you find that you really need to have stateful widgets that share data beyond whatever model data was passed to the view, then templating is probably not an appropriate solution. For example, if a Link is not executable by the current user, it won't render as a link (and possibly be completely blank depending on the circumstance and configuration). That's easy to do, but not easy to share between multiple templates with different appearances. Another concern I have about Template Toolkit (and other template languages) is that it has its own syntax and semantics for data and control structures distinct from Perl. Why isn't Perl good enough? The syntax for accessing complex data structures in perl is non-trivial and possibly too confusing for designers. Here's the perl version: foreach my $account ( {$model_data-{'user'}-{'accounts'}} ) { and in TT: [% FOREACH account = user.accounts %] or with localized loop variables, like HTML::Template: [% FOREACH user.accounts %] My experience with little languages is that they take on a life of their own That can happen, and I've seen some people do appalling things with templating tools, but these people tend to be programmers working by themselves with no separate designer. The place where these tools really pay off is when you're working with a separate design group. My experience has been that designers have no trouble grasping the basic ideas of templating, and don't feel the need to try and wedge in stuff that doesn't belong there. The thing that worries me about a widget approach is that I would have the same problem I had with CGI.pm's HTML widgets way back: the designers can't change the HTML easilly. Getting perl developers out of the HTML business is my main reason for using templating. - Perrin
Re: separating C from V in MVC
Rob Nagler wrote: Perrin Harkins writes: You can actually do that pretty comfortably with Template Toolkit. You could use a filter for example, which might look like this: [% FILTER font('my_first_name_font') %] ... some text, possibly with other template directives in it... [% END %] One of the reasons Perl is popular is its idioms. Having to say something in three lines is not as idiomatic as one line. It takes a lot of discipline to use it everywhere. In other words, I don't think the above is more comfortable than: String(['User.first_name'], 'my_first_name_font'); The advantage is that my example can contain other templating code: [% FILTER font('basic_info_font') %] Hello [% User.first_name %]!BR [% IF User.accounts %] You have these accounts:BR [% FOREACH User.accounts %] [% name %]: [% balance %]BR [% END %] [% END %] [% END %] Unless I'm missing something about your example, the FILTER concept seems more powerful. It is perfectly possible to simply add a plugin to TT to make it look like yor example though: [% String(User.first_name, 'my_first_name_font') %] Note also the accessor for User.first_name in Template Toolkit is probably nontrivial. Assuming it's just $User-first_name() and you passed in $User as part of your data to the view, there's no additional work. - Perrin
Re: separating C from V in MVC
Rob Nagler wrote: [Skirting on the edge of YATW. :-] I certainly don't mean to have a templating war. I'm just trying to figure out what the difference is between these approaches and if there's something I've been missing that I should consider adding to future applications. Here's your expanded example in widgets: String(Prose('EOF'), 'basic_info_font'); Hello String(['Model.User', 'first_name']);!br If(['Model.AccountList', '-get_result_set_size'], Join([ You have these accounts:br, Table('Model.AccountList', [ 'name', 'balance', ]), ]), ); EOF If your String widget can accept other widgets recursively like this, then our examples are equivalent. I thought it was limited to a simple value. Unless I missing something, the template example won't align properly in HTML. This is a significant semantic difference between FOREACH and Table. I just didn't put in any fancy HTML in my example. I could have put in table tags right there, or made a macro if that table gets repeated a lot. Looks to me like they work the same. In TT, I would probably use macros or small templates (possibly defined in this same template file at the top) for little repeating chunks, and filters or plugins for things with more brains, like the String widget that decides whether or not it needs to print FONT tags. - Perrin
Re: separating C from V in MVC
It seems problematic to me to require the programmers to do work when a designer wants to change the number of decimals in a page, for example. HTML::Template::Expr may present a solution to this particular desire, although it isn't one I've come across. How often are HTML designers fiddling with numeric formats? Are they really HTML designers if they can deal with, say, a printf-style format string? Yes, they are, and printf isn't so much harder than JavaScript, style sheets, and templating tags. One place where this comes up is date formatting and internationalization. Making the model objects understand locale and act appropriately is not always a good approach, and supplying a date format in the template - which is all about appearance anyway - seems appropriate. This can also be useful when the same date needs to be displayed in multiple ways, like an abbreviated format on one page and a fixed length format in an e-mail template. You could make the controller do this sort of formatting before passing data off to the view, but I think it's an awkward fit and increases the coupling between components unnecessarilly. Obviously there are lots of ways to solve these problems, but what I like about doing it in the template is that it puts these concerns in the hands of the people who control the rest of the look-and-feel issues in the application, and gets them out of the perl programmers' way. - Perrin
Re: separating C from V in MVC
It is interesting to try and fit our approach into the MVC+template pattern Just to clarify, it's not MVC+template; it's just MVC. The templates are one way of implementing views. You could mix and match this where appropriate, so that your Excel view is a perl module with a set of formatting guidelines stored in a sort of style sheet, while your HTML view is simply a template executed by a templating module. I see the Controller as also responsible for deciding what to do with the results of rendering the DOM in Excel or HTML formats - Views don't decide how their results should be distributed. This is typically something you would put into the controller, since the view shouldn't have to worry about details like HTTP headers. - Perrin
Re: separating C from V in MVC
A String widget/template allows you to control the rendering of all fonts dynamically. If the String widget/template sees the incoming request is from IE5+, it doesn't render the font if the font is the same as the default font. The Style widget/template renders the default font in a style if the browser is IE5+. This avoids the stylesheet bugs in all other browsers and gives 90% of your users who are running IE5+ a much lighter weight page. It's cumbersome to do wrap all text in string templates, because the calling mechanism is verbose. Most template languages I've looked at only support named parameters. Widgets can have named parameters, e.g. String({ value = ['User.first_name'], string_font = 'my_first_name_font', }); but it is much more convenient to use positional notation: String(['User.first_name'], 'my_first_name_font'); You can actually do that pretty comfortably with Template Toolkit. You could use a filter for example, which might look like this: [% FILTER font('my_first_name_font') %] ... some text, possibly with other template directives in it... [% END %] The filter is a module which would get to post-process the output of the contained block. I believe the taglibs in AxKit could be used in a similar way. - Perrin
Re: Persistent Net::Telnet Objects
French, Shawn wrote: Recall that I am using: Apache/1.3.20 (Win32) mod_perl/1.25_01-dev mod_ssl/2.8.4 OpenSSL/0.9.6a on Windows 2000 with PHP 4.21 Would this be why my scripts are working? Mystery solved! Yes, that's why. You are running mod_perl in single process mode because you're on Windows, so only one request is handled at a time. That means that every user will always return to the same Apache process, since there is only one of them! Does this mean that as long as I stay with windows I will be alright? For certan definitions of alright, yes. It won't be speedy if you start getting many concurrent requests. - Perrin
Re: Persistant references [was] Persistent Net::Telnet Objects
First, there is no way to effectively pass compiled code between processes at this time. It isn't likely to happen with Perl 5 because attempts at loading compiled bytecode from disk have usually had poor performance and other issues. Second, what you're proposing is probably not a good idea unless this is for a small in-house project. What I mean is, if a request comes in for a certain form I would like to be able to do something like this: my $form = load_form($r); $c{$session_id}-{handler} = $form-{handler}; # -- this being a code ref... $r-send_http_header; print $form; Then when the user completes the form and resubmits: my $handler = $c{$session_id}-{handler}; $r-send_http_header; print $handler-($r); What if the same user has multiple browser windows open and starts on a new form before finishing the existing form? Remember, sessions are global to all browser windows. The right thing to do here is pass the form data the old-hasioned way, in URLs or form fields. Those are distinct for each browser window. I would like to be able to dynamically create anonymous subroutine handlers based on input and have them be active until the form is submitted, at which time they are used to process the form then discarded. But why go to all that trouble, generating subroutines on the fly? It just doesn't seem necessary for processing form input. - Perrin
Re: separating C from V in MVC
Jeff AA wrote: do you use any standards for the data being returned to the Controller? eg do you use a struct [ie hash/array Perl primitive] or do you return an object? eg a table object etc? HTML::Template requires you to pass a perl data structure. Template Toolkit can handle objects as well (i.e. automatically call their accessor methods to fetch properties). Passing perl structs is faster, while passing objects allows for some additional tricks, like lazy-loading data in Class::DBI objects. (Class::DBI is a module for modelling database data as objects.) For more background on templating tools, see my article here: http://perl.apache.org/features/tmpl-cmp.html does the Model returned data contain lots of style hints? Or do you leave this completely to the View layer? Ideally you should have no style information at all in the model. How does the view layer know for example to render an Error cell as RED in HTML but blue in Excel due to Excel palette limitations? You have different views for different targets. Make an HTML view and an Excel view and have the controller know which one to use. Optimally, the View avoids *ALL* application logic. - so the Model has to say RED rather than ERROR? Just the opposite: the model provides the list of errors, and the view knows how to display them. Sounds like Controller only interacts with one Model? The model might be made up of dozens of different classes, but it's still referred to as the model as in the application's data model. What controls the overall layout? The view. e.g. what is the equivalent of the 'Grid Bag' layout manager - is this done in the Controller? and then passed to the View with all the data from a set of Models? Or do you make the Controller minimalist and have a meta-Model that assembles all the sub-Models into a layout. I don't know what a Grid Bag is, but the idea is pretty simple: - Controller looks at input and decides which model objects to call. - Controller calls some methods on model objects. - Controller picks a view and passes data from model objects to it. I wrote about this in my article on the eToys system: http://www.perl.com/pub/a/2001/10/17/etoys.html - Perrin
Re: separating C from V in MVC
Hi Jesse, It's the addition tricks which bug me out. With those two words you establish the mother of all slippery slopes to architecture oblivion. When you have objects passing freely between your Controller and View (which are quoted here, 'cuz I don't think they are separate in this case), how do you decide where to put a particular bit of code? The answer is, it is completely arbitrary. First of all, I don't do it that way. I pass simple Perl data structures to Template Toolkit, because I know what data I want to send and it's faster that way. However, I don't really understand your objection. The view doesn't get to do anything but call accessor methods on the object. They look just like simple structures: NAME: [% person.name %] The template coder doesn't know that person is an object and TT called a method to get that instead of just doing a hash lookup. The reason people usually do this is so they can do lazy-loading. With something like Class::DBI you can set it so that if no one ever uses person.name in a template it will never be loaded from the database. It's a performance optimization. People who like that approach have objected to my approach of passing data because it requires the controller to know exactly what data the template will need, or else pass data that may not be needed and possible waste effort. Personally, I don't mind having the controller know what data is needed, as long as it doesn't make any decisions about how the data is shown. In the architecture you describe it is inevitable that given enough time and different programmers your Controller and View will coalesce into a undifferentiated mash of code and HTML, separated only by the fact that they are in two different files. I don't see where you're getting this from. The objects return data, not HTML, and they have no side effects. They are read-only. The view (template) does all of the formatting. IMHO, any system built on Template Toolkit (unless it is small and always managed by the same programmer) will ultimately devolve in just the same way as a Server Page system. Well, you're not right about that. We built a very large system at eToys using TT and it never had any of these problems you're describing. The separation was clear, and the templates did nothing but display data. HTML::Template isn't just faster than just about everything else out there -- it also is pretty much the only templating system which has an actual clear vision when it comes to how it fits into the larger architecture. I don't agree with that either. Template Toolkit and AxKit (or any other XSLT-based system) can both enforce a clear separation of responsibilities. Template Toolkit allows people to do it other ways if they want to, through the use of plugins or by passing objects that do more than just return data, but the documentation and most of the mailing list discussion centers around the same approach as HTML::Template. The speed differences aren't really significant at this point. All of these tools are blazing fast. They all have C code under the hood now (with the new HTML::Template compiler). The bottleneck on performance of web applications is still what it always was: data access. - Perrin
Re: [Mason] Re: separating C from V in MVC
Dave Rolsky wrote: Alzabo could handle a _lot_ of this for you. Class::DBI could handle some of it (though less). SPOPS is also a good choice for this. All of them are on CPAN, just waiting for you. - Perrin
Re: separating C from V in MVC
Jeff AA wrote: For example to render a date in Excel some jiggery pokey is required, and I would also expect a HTML V to print pretty dates rather than 20020531172534 (or something other than the raw stringification) Yes. That's why you need to use a good templating system. There is a plugin for date formatting in Template Toolkit and HTML::Template can do it by using the HTML::Template::Expr module. Maybe some AxKit expert could explain how to handle it there. We also deal with lots of numerics - some are quantities, and others are values or interest rates - they need zero, 2 or 4dps when being presented. Same deal: TT has a formatting plugin, and HTML::Template::Expr gives you access to sprintf or an arbitrary formatting function of your own. So for example if your savings balance has gone negative, the value should be rendered as an error balance rather than a normal balance. In HTML you might choose to display the cell with a RED background, but this does not work in Excel, where a RED background prints as black, so you can't just tell the view RED - you need to tell it the reason and let Excel choose one of its limited bg colours. A simple approach for this would be to have a data model that includes a boolean flag for whether or not this balance is overdrawn. For example: my $balance = { value = -7, overdrawn = 1 }; Note that the model object is making the decision about whether the balance is overdrawn and no logic about that is going into the template. Then in your template you say something like this: [% IF balance.overdrawn %] bgcolor=red [% END %] Or whatever makes sense for your target output. Ok - so results from a collection of models are assembled and passed to the view. One model, made up of many data objects. - not sure if I like this. I thought the whole point of the View was to contain all the logic about things like HTML tags or Excel binary representation etc, and as little as possible about other things. That's right. Exactly where in the MVC world, would I decide that column 3 which contains a description should expand to fill 70% of the available space and that column 5 which contains a possibly long name should use the remaining available space, whilst column 1 which contains a name should not be wrapped? In the view. I'm not sure where your confusion lies here. I guess I have talked myself round to thinking that the Controller is actually the layout manager, in that it marshals results from a set of models, decides how this collection should interact, and then asks an appropriate View to render the result in a specific interface flavour. That's exactly what I'm saying, except that I don't see what your layout manager is for. You should just pass some data to a template (or maybe to something fancier for certain types of output like Excel) and then the template makes all the decisions about how to show that data. Have I talked myself out of HTML:Template route? Not sure, I guess it depends on whether HTML::Template can be smartened up to understand that I want Dates rendered in a pretty format, quantities should be commified, cash values must have commas and 2dps, interest rates should have 4dps and cells with an error attribute should have a red background. No problem, as I explained above. - Perrin
Re: separating C from V in MVC
Rob Nagler wrote: Layout managers accept a declaration ('this cell is northwest', 'this other one expands across the bottom', etc.). They interpret the decl at run-time. It's like HTML, but more declarative. Some attributes of our Grid manager are: cell_nowrap - don't wrap the text in the cell cell_align - gens valign and align from a single compass direction cell_expand - this cell eats up the rest of the columns in the row row_control - a conditional value to control whether row is displayed cell_width - contains the HTML width= value (may be dynamic) Can't all of that be expressed in an HTML template? It seems like the template should know enough about what kind of data it's displaying to know how to arrange the tables. After all, it's not a template for a generic table; it's a template for a table that displays specific data with a structure that is pre-determined. Usually when I see people doing this kind of thing it's because they haven't expressed all the necessary information in their model. For example, if you have a rule that says people's names don't get wrapped, then you need to know which pieces of data are names. If that isn't obvious from your data structure (i.e. person.name is always a name) then you add some flag to your data structure like is_name, so that the model can tell the view that this is a name. Then the view gets to decide what special treatment to give that data. Maybe there's a certain class of problems where the sort of layout hints you're talking about are needed and I've just never had to deal with it. - Perrin
Re: separating C from V in MVC
Rob Nagler wrote: Let's say, though, that you want the same template to render in a WAP, Opera, Konqueror, IE, NS, etc. The implementation of Grid handles this for you. For example, our code automatically renders style sheets for IE5+, but no other browsers. (This isn't in Grid, but you get what I mean, I hope.) The same template? How does the layout manager help with that? Does it modify the template? It would make more sense to me if this were a sort of abstraction to factor out common layout ideas from multiple templates. However, sometimes you have dense tables where you allow wrapping and other sparse tables where you don't. We have a really wide table for admins which allows them to see all EC info at a glance. It has to wrap all cells or it wouldn't fit on some screens. When the customer sees the payment reason, on their subscription page, it doesn't wrap. Two views of the same data. That doesn't require a layout manager though. Simple templating is fine for that, i.e. two different templates (views). - Perrin
Re: MVC advice..?
Rafiq Ismail (ADMIN) wrote: Now my problem is that I have to assign which Subclass I want to instantiate, based on the script and params. So, you're asking how to map URLs to perl modules? Is there some reason you aren't simply using httpd.conf or Apache::Dispatch? In my last MVC design, we had all of our controllers inherit from one base controller that held all of the common code. Then we could just map from URLs to the specific controllers that handled them: Location /mycontroller SetHandler perl-script PerlHandler My::Controller /Location I my last effort I went for a Shared datastructure holding (script, control module pairs) which then allowed one to be dynamically eval 'use..''ed in the main content handler. I found that clunky. There's no good reason to do an eval 'use'. Use require instead, and import if you need to (but most people don't). I'm building from scratch again and am thinking of just firing up a template and allowing the control to be loaded INTO the view as a template toolkit plugin. What I hate about this is that I'm surrendering my View layer. I agree, that's a bad idea and certainly not MVC. - Perrin
Re: separating C from V in MVC
Ray Zimmerman wrote: If I understand correctly, the Mason component that generates the page the user sees would be considered the View. But where is the Controller? I wrote a little about this in my templating guide, and there has been discussion on the Mason list. A common approach is to use Mason's autohandlers as controllers, but you could really use any component. Just have it do some work in perl, gather some data, and then pass it off to a view component that generates the HTML. This is code I would normally have put in the %init section of the display component (with a possible redirect to another component based on application logic). This sounds like C and V are not separated as they should be. That's a standard way to do it in Mason, but not an MVC way. To make it more MVC, you need to have separate components for C and V, with V just receiving data and displaying it in HTML. - Perrin
Re: MVC advice..?
Dave Rolsky wrote: On Wed, 29 May 2002, Perrin Harkins wrote: There's no good reason to do an eval 'use'. Use require instead, and import if you need to (but most people don't). Actually, there is. This code: my $module = 'Foo::Bar'; require $module; is not the same as this: require Foo::Bar; If require is given a string, it looks for a filename _matching_ that string. If it's given a bareword, it converts '::' to filesystem path separators first. Then do an eval 'require Foo::Bar', but eval 'use Foo::Bar' doesn't make sense. - Perrin
Re: MVC advice..?
Rafiq Ismail (ADMIN) wrote: I'm not so keen on loading all the inheriting classes into memory beforehand You really should do that, because it will save overall memory by increasing the amount of memory that's shared. All modules should be loaded during startup in the parent process. It's a fairly large site and my main concern was to do with how I should store the correspondence from uri to object. The httpd.conf format seems about as simple as you can get to me. It's pretty unusual for a site to have dozens of controllers, and it usually indicates a design problem. Apache::Dispatch is fine too. How does StatINC behave with 'required' packages? Require and use are very similar and both add the loaded module to %INC. Read 'perldoc -f use' for the exact differences. - Perrin
Re: Persistent Net::Telnet Objects
French, Shawn wrote: Although this is working right now, I don't know enough [ anything? :) ] about Apache or mod_perl to be sure that this will work in the future. I can't see how it could be working now, unless it is actually creating a new Telnet object on every request. Your %sessionHash is not shared between processes and you have no control over which process will handle any request. You're probably opening new telnet connections from each apache process. What I am really concerned about is that the telnetObj will only be accessible from scripts run by the same child process as that which created and saved it. That won't work, since you can't control which process will handle requests from the client. Is there a better way to do this? You could write a web server in Perl, which would run a separate persistent process for each client on a different port. Randal wrote a column about that: http://www.stonehenge.com/merlyn/WebTechniques/col23.html You could also use this technique to make a sort of telnet server, and hide that server behind Apache/mod_perl, i.e. clients talk to mod_perl which talks to the telnet server. Of course the simplest approach would be to just let each Apache process open telnet sessions as needed. - Perrin
Re: Apache::DBI connection cache
Ask Bjoern Hansen wrote: Apache::DBI is turning the argument hashref into the cache key with the following code, my ($key, $val); while (($key,$val) = each %{$args[3]}) { $Idx .= $;$key=$val; } can anyone think of a good reason not to change that to something like map { $Idx .= $;$_=$args[3]-{$_} } sort keys %{$args[3]}; Good find. That's a bug. Fix it. - Perrin
Re: Apache::GTopLimit
Stas Bekman wrote: Hmm, when a new process starts it shares *everything* with the parent. Why do you say that it's not? It doesn't share everything with the parent. As soon as it forks there is unshared memory, and after the first request it handles there is usually more. Over time, the average amount of shared memory among child processes seems to gradually decrease. Restarting fixes this. - Perrin
Re: Apache::GTopLimit
Stas Bekman wrote: What you are saying is that when the server is started afresh, the newly started child processes share more memory with the parent, than newly started child processes some time later. Am I correct? Yes, exactly.
Re: Apache::GTopLimit
Stas Bekman wrote: Perrin Harkins wrote: Stas Bekman wrote: What you are saying is that when the server is started afresh, the newly started child processes share more memory with the parent, than newly started child processes some time later. Am I correct? Yes, exactly. Any ideas why? Not really. I thought maybe it was because of something changing in the parent process, but that doesn't seem possible. There was a long thread a little while back about turning swap off and on again to solve this. I've never tried that. I think restarting every 24 hours is a good idea anyway, because I've seen strange things happen now and then when a server is up for a long time. - Perrin
Re: GTop
If you're not able to resolve your difficulties with GTop, try Apache::SizeLimit instead. It fully supports FreeBSD. You just need to install the BSD::Resource module, which is useful to have anyway. - Perrin
Re: Image::Size, TT, and mod_perl Question
my %vars = {TOO_WIDE = 1}; That isn't doing what you think it's doing. Try this: my $vars = { 'TOO_WIDE' = 1 };
Re: Memory Leaks
Gregory Matthews wrote: I too thought of setting a cron job to restart the server once per day in order to keep the memory fresh. In a production environment, are there any downsides to doing this, i.e., server inaccessibility, etc..? There have been some discussion on the list about this in the past. The ideal situation is to have a cluster that you can do a rolling restart on without making the service totally unavailable. - Perrin
Re: Memory Leaks
Per Einar Ellefsen wrote: And if something goes wrong? You'd be having a server offline with noone knowing about it. You can easilly set up mon (http://www.kernel.org/software/mon/) to page you if the server doesn't come back up within a certain amount of time. - Perrin
Re: Memory Leaks
Jason wrote: If you don't want to restart the server then don't do this instead, it should help prevent small leaks from being a problem. http://httpd.apache.org/docs-2.0/mod/mpm_common.html#maxrequestsperchild Apache::SizeLimit or Apache::GTopLimit is a better way to do it, since it results in fewer unnecessary restarts. However, it's still a good idea to restart periodically, because some of the shared memory seems to become unshared over time no matter what you do, and restarting fixes that. - Perrin
Re: Monitoring the processes
Gregory Matthews wrote: For example, is there a command line tool to use that will allow me to see the process growth upon request reload? I know that I should run the server with httpd -X, but I don't know how to actually see the memory being used/increased/decreased when the prog is being executed. As I understand it, this is a good indication that there might be a problem. You can steal some code from Apache::SizeLimit or Apache::GTopLimit to print the current size in the error log. Otherwise, just use top. Keep in mind that sometimes a leaky piece of code will have to be run several times before you see the leak, because of the way that Perl allocates memory in chunks. - Perrin
Re: Apache::GTopLimit
Does using the Apache::GTopLimit module have the same net effect as restarting the server itself by simply killing off the actual processes which are growing beyond the set threshold, and thereby causing new processes to be born? It does kill off processes that are getting too big, and you definitely should use either GtopLimit or SizeLimit to get the most out of your server. However, it's not quite the same thing as a restart. Over time, some of the shared memory from the parent process appears to become unshared, and new processes that are spawned start out with less shared memory because of this. Restarting now and then takes care of this problem. - Perrin
Re: Apache::GTopLimit
So to modify my previous question, other than the loss of some shared memory over time, GTopLimit will have the same effect as restarting the server? Yes. That shared memory is important though. On a side note, how are you tracking/discovering the this minimal loss over time? Apache::SizeLimit prints statistics to the error log when it kills a process. Also, you can just look at top. - Perrin
Re: Memory Leaks
I have a couple of questions regarding leaking memory in mod_perl: 1. What are the main culprits, in order of severity, of memory leaks, i.e.: a. global variables (NOT lexically scoped via my) b. ... c. ... 2. When writing code from scratch (a new application), what is the best way to avoid creating leaks to begin with, i.e., use strict;, PerlWarn On, etc.. ? There are actually not very many ways you can leak memory in Perl (and thus mod_perl). Most people confuse memory growth with memory leakage. If you want to know how to avoid memory growth, look at the performance tuning stuff in the Guide, like passing references, avoiding slurping of large files, controlling the buffering of DBI result sets, etc. Leaks are caused by circular references, the string form of eval (at least it used to leak a little), nested closures (sometimes created accidentally with the Error module), and one or two obscure syntax problems. I think one of them involved code like my $x = 7 if $y;. Matt Sergeant got bitten by this in the early stages of AxKit development, and the details are in the mailing list archive. Global variables by themselves are not a source of leaks or growth. If you slurp a large file into a global, your process will grow, but the same is true for a lexical. - Perrin
Re: Memory Leaks
So am I being overly paranoid concerning the leak potential of mod_perl programming? No, memory management is very important with mod_perl. If I start with strict code to begin with and try my best to stay away from the problems you mentioned, then any potential memory leak/drain issues will be avoided? Using strict is an absolute must for many reasons. It won't prevent you from using up tons of memory though. You have to become tuned in to the things that use up memory so that you can avoid them. Start with the Guide. - Perrin
Re: sending CGI ouput through a handler
My::Handler takes the requested file and adds some markup to it with the Template Toolkit if the MIMEtype of the file is text/html. I want to be able to use the same handler to also add markup to the output of executed CGI. What is the best way to do this? You can't feed the output of mod_cgi to mod_perl, at least not in Apache 1.x. The best thing to do (at least for performance) would be to rewrite the CGI so that you call it as a module from your handler. Another approach would be to use Apache::Filter to grab the output from PerlRun or Regsistry. You could also sublass PerlRun or Registry and add your handler code to it. - Perrin