tliron / prudence

An opinionated lightweight web framework built for scale
https://prudence.threecrickets.com
Apache License 2.0
13 stars 5 forks source link

Error attempting to use prudence.util.CacheControlFilter example #26

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
1) NullPointer Exception trying to use the CacheControlFilter example shown on 
Prudence site

Wrapped java.lang.NullPointerException (applications\stickstick\routing.js#31)
 Document: applications\stickstick\routing.js
  Line: 31
  Column: 0
 Document: defaults\instance\default.js
  Line: 44
  Column: 0
 Document: defaults\instance\default.js
  Line: 49
  Column: 0
 Document: defaults\instance\default.js
  Line: 49
  Column: 0
 Document: instance\default.js
  Line: 15
  Column: 0

2) How can someone else reproduce it?
Add code below to router.js.  (Use the stickstick routing.js)  Note this code 
is from 
http://threecrickets.com/prudence/manual/static-web/#cache-control-filter

importClass(
    org.restlet.data.MediaType,
    com.threecrickets.prudence.util.CacheControlFilter)
​
var staticWebCacheControlFilter = new CacheControlFilter(null)
​
// Disable caching for CSS and JavaScript files
staticWebCacheControlFilter.maxAgeForMediaType.put(MediaType.TEXT_CSS, -1)
staticWebCacheControlFilter.maxAgeForMediaType.put(MediaType.APPLICATION_JAVASCR
IPT, -1)
​
router.filterBase(staticWebBaseURL, staticWebCacheControlFilter, staticWeb)

3) What flavor of the Prudence are you using? Which version, and on what
operating system?  Javascript, Windows XP, 

4) Please provide any additional information below:

I was initially trying this in my app.  Could not get it to work, thought then 
to just add to stickstick routing.js and I see the same error there.

The error seems to happen on this line in either my app or stickstick: 
router.filterBase(staticWebBaseURL, staticWebCacheControlFilter, staticWeb)

Thinking to divide my static folder into two parts: /app/ and /lib/.  app is my 
custom static resources which will change during development.  /lib/ is from 
3rd parties (jquery, twitter bootstrap etc.)  I want to get a max-age header 
put on the /libs/ so they are not revalidated from the client.

Original issue reported on code.google.com by tgloc...@gmail.com on 1 Mar 2012 at 4:58

GoogleCodeExporter commented 9 years ago
Ah - I got it to go further..  Since using CssUnifyMinifyFilter and 
JavaScriptUnifyMinifyFilter and how the calls to 

router.filterBase(staticWebBaseURL, cssFilter, staticWeb)
router.filterBase(staticWebBaseURL, javaScriptFilter, cssFilter)

Require the 3rd parameter to change.

So using router.filterBase(staticWebBaseURL, staticWebCacheControlFilter, 
javaScriptFilter)

Will get the filter to run error free.  However, one issue remains - How can I 
get this to run on staticWebBaseURL + 'libs/' ?  If I add that, I again get the 
Wrapped java.lang.NullPointerException.

Any thoughts ?

Original comment by tgloc...@gmail.com on 1 Mar 2012 at 5:36

GoogleCodeExporter commented 9 years ago
Hey, can you tell me what is the error in the example given in the Manual?

The problem is that filterBase is not a very good API. It was supposed be 
convenient "sugar", but instead it ends up confusing things. I am considering 
removing it entirely in Prudence 2.0. Try using a simple attach instead:

var staticWebCacheControlFilter = new CacheControlFilter(null)
staticWebCacheControlFilter.next = staticWeb
router.attach(staticWebBaseURL + 'libs/', staticWebCacheControlFilter)

Original comment by tal.liron on 1 Mar 2012 at 5:46

GoogleCodeExporter commented 9 years ago
The error I had was the wrapped nullpointer exception.

I don’t think there is necessarily an error in the prudence docs, its 
something specific to my code.

I attached my router.js if you find a free moment for review.

What I have been trying to achieve is:

1. A handler that gets invoked for non-static requests ( written as a .js in 
the /handlers/ folder )
2. All static web requests get checked by both CssUnifyMinifyFilter and 
JavaScriptUnifyMinifyFilter
3. Everything under the staticWebBaseURL + 'libs/' that is CSS, JS or IMAGE 
gets a max-age put on it.
4. Everything under the staticWebBaseURL + 'app/' gets Prudence defaults 
(last-modified and expires +10 mins)

The idea is that folders and subfolders under libs/... would contain 3rd party 
javascript, css and image types (jquery, underscore, chosen, twitterbootstrap, 
etc.)  These are unlikely to change often and I would put some version number 
at the directory level if needed.  I want the max-age to avoid client side 
revalidation for these 3rd party js libraries.

What I see:

I could only get the handler to be invoked with the syntax shown in the 
attached router.js.  This works, except that it is invoked for static requests 
as well as dynamic.

Max-Age is not being set.  There are no errors in the prudence log.  

Thought for sure the lack of Max-Age had to do with attach() and not using 
attachBase().  But attachBase() caused 500 response codes for static resources 
and a warning in the log: "The filter CacheControlFilter was executed without a 
next Restlet attached to it." 

In one incantation I had both Expires and Max-Age headers…  But I cannot seem 
to get back to that state.  Even so, I think different browsers would react in 
an inconsitant manner so both headers are not desireable.

I did notice that image/png is NOT a default mimetype - but it was simple to 
add in settings.js using: 
applicationInstance.metadataService.addExtension('png', MediaType.IMAGE_PNG);

At any rate, I'm going to read 
http://threecrickets.com/prudence/manual/routing/#filtering again and see what 
I can learn.  
If you happen to be writing more docs - the more examples the better.

Original comment by tgloc...@gmail.com on 2 Mar 2012 at 8:29

Attachments:

GoogleCodeExporter commented 9 years ago
Thanks for the details -- I will definitely try to beef up the documentation 
for Prudence 2.0. The whole API for routing.js is changing, so I will have to 
rewrite it anyway.

Did you see my last comment on this bug? I show specifically set the .next for 
the filter, which should address the exception you are seeing. (Though I did 
make a mistake and used attach instead of attachBase.)

So, what I would do is put the CacheControlFilter *after* the rest of the 
filters, with this code:

var staticWebCacheControlFilter = new CacheControlFilter(null)
staticWebCacheControlFilter.next = staticWeb
staticWebCacheControlFilter.maxAgeForMediaType.put(MediaType.TEXT_CSS, 60)
staticWebCacheControlFilter.maxAgeForMediaType.put(MediaType.APPLICATION_JAVASCR
IPT, 60)
staticWebCacheControlFilter.maxAgeForMediaType.put(MediaType.IMAGE_PNG, 60)
router.attachBase(staticWebBaseURL + 'libs/', staticWebCacheControlFilter)

Original comment by tal.liron on 3 Mar 2012 at 8:38

GoogleCodeExporter commented 9 years ago
Thanks Tal -

I missed assigning staticWeb to .next and attachBase was required too.

The examples at http://threecrickets.com/prudence/manual/routing/#filtering do 
show assignment to .next.  I realized I did not understand two important 
concepts: that routes are not hierarchical and .next.

Truthfully .next and filterBase are still a bit of mystery to me.

Take this example:
  document.execute('/defaults/application/routing/')
  router.filterBase(dynamicWebBaseURL, '/page-filter/', dynamicWeb)

I think that puts the /page-filter/ *in front* of dynamicWeb but only because 
the method is named 'filterBase' i.e. make this the baseFilter.  But I dont 
know if dynamicWeb is then reassigned or not.

Another confusing part of my application was recognizing that the files located 
in libs require [staticweb]/libs/libs/... in order to reference them.   Not 
exactly sure why this is.

At any rate, you are redesigning the routing and I have it working - no need to 
dive into this further.

Again thanks for your help.  I will be attempting to migrate my app to 2.0 
whenever you publish it and will want to have 3rd party js with a max-age and 
no client re-validation.  The application's custom js will want to have some 
client side re-validation.  

On a positive note, Prudence fragments make it easy to bump version numbers for 
'static' resources via query string.  I have one fragment that includes any 
required js and I can just tweak it as needed here.

I run into far too many applications in my day job that rely on client side 
re-validation and all those 'If-modified-Since' requests can just kill 
performance.

Please close this as a bug - it was not.

Original comment by tgloc...@gmail.com on 5 Mar 2012 at 5:43

GoogleCodeExporter commented 9 years ago
As I said, the filterBase API is indeed bad. It is an attempt to make things 
easier, but it does work too mysteriously and hides things that you actually 
need. Internally, it does exactly set .next. And you pointed exactly to the 
problem: it does not reassign dynamicWeb, because it in fact can't! That's a 
value external to what the API can access.

What is .next? It is the next restlet (handler) in the route! It means that 
after the filter does its job (or not) the conversation continues to the next 
one. There always needs to a next restlet is the filter is just passing 
through, which is what CacheControlFilter does.

Original comment by tal.liron on 5 Mar 2012 at 8:00