You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@jspwiki.apache.org by Janne Jalkanen <Ja...@ecyrd.com> on 2008/08/24 20:49:20 UTC

WikiContext & JCR Sessions

All (but especially Andrew),

JCR requires an object called a Session.  This is very similar to  
Hibernate's Session, in the sense that it represents actual read/ 
write access to the repository.  The session gathers all the changes,  
and those changes are then flushed all by calling Session.save().   
The chief limitation is that Sessions are *not* thread-safe (and not  
synchronized, for speed).  However, Sessions are fairly fast to open  
(JackRabbit is around 1.5 ms, Priha is faster).

My initial feeling would be to make the JCR Session a part of the  
WikiContext (or, to be precise, a JCRWikiContext, which would be a  
concrete class which would implement a WikiContext interface).  When  
the WikiContext is created, the Session is created too, and when the  
WikiContext expires, the Session is logged out.  We could also add a  
WikiContext.save() method to flush all changes. This would provide  
fairly logical lifecycle management.

The bad thing is that means that we need to carry WikiContext into  
quite a few places after that.  Unless we turn WikiContext into the  
main repository interface as well, providing things like a Search  
interface as well.  That means that it would inherit pretty much all  
of the functionality of the WikiEngine, which might make it a bit too  
unwieldy.

My current idea is to turn WikiPages into essentially representatives  
of Nodes.  Calling WikiPage.getContent() will return the content of  
the page and WikiPage.setContent() will set it. This provides a  
really neat way of managing the data, since e.g. WikiPage.get/ 
setAttribute() could be automatically persisted.  The bad thing,  
obviously, would be that since Nodes contain a reference to the  
Session where they came from, you *cannot* cache a WikiPage across  
new invocations (e.g. threads).

Retaining the old WikiEngine API is problematic because the passed  
arguments only contain Strings.  Since there is no session management  
in that API, we would need to do Repository.login() every time e.g.  
pageExists() is called, and *that* would become a bit too rough.  So  
my preference would be, frankly, to dump existing WikiEngine API and  
make something nicer.  We can have a lookalike API, but that's going  
to be slow.

An obvious option would be to use a ThreadLocal for a Session, but  
that would pretty much make it a global, and the other problem is  
that then lifecycle management becomes a bit hazy - if there are  
unsaved changes, the session would grow uncontrollably.  So there  
would need to be a separate flushing action at some point...  But  
that would allow us to keep the existing API.

Any thoughts?  Gotchas?  Obvious ideas I've ignored?  It would be a  
good idea if others read up on the JCR documentation as well - the  
spec is fairly well written, but it's quite long.

/Janne

Re: WikiContext & JCR Sessions

Posted by Janne Jalkanen <Ja...@ecyrd.com>.
>> Reading this declaration hurts my head. :)
>
> This last declaration suggests that WikiContext ought to be a type  
> of ActionBeanContext. I recall discussing that WikiContext was  
> meant to be a superclass (or a marker interface) for page-oriented  
> ActionBeans, rather than the ActionBeanContext. I.e., the  
> relationship diagram  would look like this:

My preference is strongly towards WikiContext being an interface.  We  
know already pretty well what is needed in it.

The idea really is that if someone wants to use JSPWiki as a basic  
rendering engine, they can provide their own implementations of the  
basic interfaces, without having to bring in the entire JSPWiki  
WikiEngine and backend and stuff.

>
> However, it is not crazy to suggest that WikiContext could be a  
> support class (like WikiActionBeanContext) rather than an  
> ActionBean class itself. WikiContext shares several characteristics  
> with WikiActionBeanContext: both need to set references to  
> WikiEngine and WikiSession, and generally need to get at the  
> request/response objects.  That said, get/setWikiPage are better  
> left in the ActionBean classes. WikiPage is really a property of  
> the request, and in the HTTP scenario at least, would be bound by  
> the magical Stripes request binder.

I think that WikiContext.getPage() *is* required, since it is used  
practically everywhere, in all our plugins for example.  If that  
goes, we can pretty much kiss bye-bye to any attempt at making our  
3rd party plugins somewhat easily compatible with 3.0...

Also, I would like to keep the name WikiContext.

The backend does not care whether it is a property of the request or  
not - but it needs it in order to resolve relative paths and other  
things.  So I think that really does need to live on the WikiContext...

Perhaps there should be a superinterface of WikiContext (but a  
subinterface of ActionBeanContext) which does not have the WikiPage?   
That might have some limited use...

I think your second proposal was pretty good already :-)

/Janne

Re: WikiContext & JCR Sessions

Posted by Andrew Jaquith <an...@me.com>.
> WikiSession - contains user information and any thread-safe things  
> which are expensive to create.

Yes.

>
> WikiActionBeanContext - encapsulates the basic info about the  
> request.  Does not require a WikiPage.

Yes.

>
> WikiContext - provides access to JSPWiki internals; lives exactly as  
> long as an WikiActionBeanContext; requires a WikiPage.

Yes.

>
> RenderingContext - provides access to JSPWiki internals and  
> rendering parameters; requires a WikiPage; thrown away after a chunk  
> of wikimarkup is rendered.
>
> // Only bare minimum to make rendering work
> public interface RenderingContext
> {
>   public WikiPage getPage();
>   public WikiEngine getEngine();
>   ...
> }
>
> // Extra context
> public interface WikiContext extends RenderingContext
> {
>   public HttpServletRequest getRequest(); // This already exists.
>   ...
> }

Makes sense. However, see my comments below.

>
>
> public class WikiActionBeanContext
> {
>    public WikiSession getSession();
>    public WikiEngine  getEngine();
>    public HttpServletRequest getRequest();
>    public HttpServletResponse getResponse();
> }

Yes.


> public class WikiPageActionBeanContext extends WikiActionBeanContext  
> implements WikiContext
> {
> ...
> }
>

Reading this declaration hurts my head. :)

This last declaration suggests that WikiContext ought to be a type of  
ActionBeanContext. I recall discussing that WikiContext was meant to  
be a superclass (or a marker interface) for page-oriented ActionBeans,  
rather than the ActionBeanContext. I.e., the relationship diagram   
would look like this:

1) Support classes -- used by ActionBeans

ActionBeanContext
    --> sets/gets HttpServletRequest
    --> sets/gets HttpServletResponse

WikiActionBeanContext
    --> extends ActionBeanContext
    --> gets/sets WikiEngine
    --> gets/sets WikiSession

2) ActionBean classes

ActionBean
    --> gets/sets ActionBeanContext
    --> gets/sets request parameters submitted by user

WikiActionBean (interface) + AbstractWikiActionBean (abstract class)
    --> extends ActionBean
    --> sets/gets WikiActionBeanContext
    --> contains much of today's WikiContext implementation code:  
e.g., get/set variables

WikiContext (abstract class)
    --> implements WikiActionBean
    --> extends AbstractWikiActionBean
    --> gets/sets WikiPage
    --> gets/sets HttpRequest (which forwards to WikiActionBeanContext)

ViewActionBean (concrete class)
    --> extends WikiContext
    --> gets/sets version
    --> contains "view" handler method


However, it is not crazy to suggest that WikiContext could be a  
support class (like WikiActionBeanContext) rather than an ActionBean  
class itself. WikiContext shares several characteristics with  
WikiActionBeanContext: both need to set references to WikiEngine and  
WikiSession, and generally need to get at the request/response  
objects.  That said, get/setWikiPage are better left in the ActionBean  
classes. WikiPage is really a property of the request, and in the HTTP  
scenario at least, would be bound by the magical Stripes request binder.

The re-worked hierarchy would look like this:

1) Support classes -- used by ActionBeans

ActionBeanContext -- same as before
    --> sets/gets HttpServletRequest
    --> sets/gets HttpServletResponse

WikiActionBeanContext -- changed. (Could also be called WikiContext)
    --> extends ActionBeanContext
    --> gets/sets WikiEngine
    --> gets/sets WikiSession
    --> contains much of today's WikiContext implementation code:  
e.g., get/set variables

2) ActionBean classes

ActionBean -- same as before
    --> gets/sets ActionBeanContext
    --> gets/sets request parameters submitted by user

WikiActionBean -- same as before
    --> extends ActionBean
    --> sets/gets WikiActionBeanContext

ViewActionBean (concrete class) -- changes slightly
    --> extends WikiContext
    --> gets/sets WikiPage
    --> gets/sets version
    --> contains "view" handler method

> So the basic idea would be that we use the Wiki/RenderingContext as  
> interfaces announcing what kind of functionalities are required, and  
> use the ActionBeanContext classes to implement these.  Or maybe they  
> should be ActionBeans, I am not too sure (and I'm too lazy right now  
> to snap the code out of SVN ;-)
>
> (The rendering code can then check whether it has a full WikiContext  
> or just a RenderingContext, and then function accordingly.)
>
> /Janne


Re: WikiContext & JCR Sessions

Posted by Janne Jalkanen <Ja...@ecyrd.com>.
>
> ActionBeanContext is really just meant to encapsulate HTTP request  
> state. (From the Stripes Javadoc: "Encapsulates information about  
> the current request. Also provides access to the underlying Servlet  
> API should you need to use it for any reason.") The  
> ActionBeanContext is just a property of an ActionBean, and it can  
> be set or get freely.
>
> Rendering might well be one of those concerns that should be  
> cleanly separated from HTTP. In fact, it probably should be.  
> However, don't think we should build rendering functions into  
> WikiContext directly. A property that allows the rendering context  
> to be obtained, similar to how the HTTP context can be obtained via  
> getContext(). Maybe getRenderingContext()? Making accessible via a  
> delegate method is probably a lot cleaner than building it into an  
> abstract superclass.
>
> What kinds of functionality do you foresee RenderingContext needing?

Well, RenderingContext needs to provide page context information  
(i.e. getWikiPage()) for example to determine the real URLs for any  
relative links, as well as page variables.  So it sounds like it  
should be a relative of WikiContext.  It should also have pretty  
broad access (e.g. to determine variable values from the HttpRequest,  
so it might need access to that, too).  Also, if any plugins exist on  
the page, they *will* need access to the full WikiContext.  Also, the  
idea would be that someone who only wants the JSPWiki rendering  
capability can pass their own RenderingContext to it, so it should be  
fairly simple.

Agree on that we don't want to put the rendering stuff into  
WikiContext.  It would only confuse things.  Making it available via  
a factory or a delegate method is probably the best idea (with slight  
preference to the factory, because then it can be made independent of  
other structures).

So, we have...

WikiSession - contains user information and any thread-safe things  
which are expensive to create.
WikiActionBeanContext - encapsulates the basic info about the  
request.  Does not require a WikiPage.
WikiContext - provides access to JSPWiki internals; lives exactly as  
long as an WikiActionBeanContext; requires a WikiPage.
RenderingContext - provides access to JSPWiki internals and rendering  
parameters; requires a WikiPage; thrown away after a chunk of  
wikimarkup is rendered.

// Only bare minimum to make rendering work
public interface RenderingContext
{
    public WikiPage getPage();
    public WikiEngine getEngine();
    ...
}

// Extra context
public interface WikiContext extends RenderingContext
{
    public HttpServletRequest getRequest(); // This already exists.
    ...
}

public class WikiActionBeanContext
{
     public WikiSession getSession();
     public WikiEngine  getEngine();
     public HttpServletRequest getRequest();
     public HttpServletResponse getResponse();
}

public class WikiPageActionBeanContext extends WikiActionBeanContext  
implements WikiContext
{
  ...
}

So the basic idea would be that we use the Wiki/RenderingContext as  
interfaces announcing what kind of functionalities are required, and  
use the ActionBeanContext classes to implement these.  Or maybe they  
should be ActionBeans, I am not too sure (and I'm too lazy right now  
to snap the code out of SVN ;-)

(The rendering code can then check whether it has a full WikiContext  
or just a RenderingContext, and then function accordingly.)

/Janne

Re: WikiContext & JCR Sessions

Posted by Andrew Jaquith <an...@me.com>.
>> required ActionBean method getContext()). The WikiActionBeanContext  
>> itself contains only four references: for WikiEngine, WikiSession,  
>> HttpServletRequest and HttpServletResponse. That's it -- no other  
>> references to Stripes objects, and no long chains of object  
>> references pulling in lots of heavyweight stuff.
>
> Well, that looks good - except for the HttpServletRequest/Response.   
> Those are dependent on this all being a HTTP application (which may  
> not be true if you embed the rendering engine in some app).  But on  
> the other hand, we can of course state that those *can* be null in  
> certain cases, or substitute dummy values (which in turn make these  
> again Stripes-dependent).

To avoid NPEs, I take the position that HttpServletRequest/Response  
references must always be set when a WikiContext/WikiActionBeans are  
created, even if the caller doesn't (or cannot) supply any. In other  
words, we create some dummy objects (Stripes MockHttpServletRequest/ 
Response objects actually). Take a look at  
WikiActionBeanFactory.newInstance() in ARJ_STRIPES_BRANCH....

Is this sort of thing a kluge? Yes. Does it make us dependent on  
Stripes? No, because there aren't any references made or kept to  
Stripes classes other than the ActionBeanContext subclass itself  
(WikiActionBeanContext). It's more, as you point out, a dependency on  
HTTP.

> I'm not worried about HTTP requests, I'm worried about cases  
> *outside* HTTP (still trying to think separation of rendering and  
> the rest).

Got it...

> What is the real relationship between WikiContext and  
> WikiActionBeanContext?   For rendering, I think we need a separate  
> RenderingContext interface, which encapsulates everything that the  
> rendering engine needs into one interface.  But I am currently  
> unsure as to how all these should relate to each other.

ActionBeanContext is really just meant to encapsulate HTTP request  
state. (From the Stripes Javadoc: "Encapsulates information about the  
current request. Also provides access to the underlying Servlet API  
should you need to use it for any reason.") The ActionBeanContext is  
just a property of an ActionBean, and it can be set or get freely.

Rendering might well be one of those concerns that should be cleanly  
separated from HTTP. In fact, it probably should be. However, don't  
think we should build rendering functions into WikiContext directly. A  
property that allows the rendering context to be obtained, similar to  
how the HTTP context can be obtained via getContext(). Maybe  
getRenderingContext()? Making accessible via a delegate method is  
probably a lot cleaner than building it into an abstract superclass.

What kinds of functionality do you foresee RenderingContext needing?

Andrew 

Re: WikiContext & JCR Sessions

Posted by Janne Jalkanen <Ja...@ecyrd.com>.
> Are you sure they are stashed in the HttpSession? The original  
> implementation I wrote took great care to make sure that they  
> weren't. That MIGHT have changed due to a bug fix, but I just took  
> a look at SessionMonitor and WikiSession, and I could not find when  
> WikiSession was actually stashed. A quick reference-skim for  
> HttpSession.setAttribute() didn't turn up anything either.

Well, okay, not really stashed into HttpSession, but SessionManager  
stores them by using the HttpSession as a key.  So they will be  
called from multiple threads, though not at the same time.   
Regardless, it's not an optimal solution.

> required ActionBean method getContext()). The WikiActionBeanContext  
> itself contains only four references: for WikiEngine, WikiSession,  
> HttpServletRequest and HttpServletResponse. That's it -- no other  
> references to Stripes objects, and no long chains of object  
> references pulling in lots of heavyweight stuff.

Well, that looks good - except for the HttpServletRequest/Response.   
Those are dependent on this all being a HTTP application (which may  
not be true if you embed the rendering engine in some app).  But on  
the other hand, we can of course state that those *can* be null in  
certain cases, or substitute dummy values (which in turn make these  
again Stripes-dependent).

> I'm NOT actually trying to argue that WikiActionBeanContext is the  
> right place to put the JCR code (or a reference to a class that  
> contains it) -- just pointing out that it's not as heavyweight as  
> you might think. It will always be available, which makes it a  
> decent place to put stuff. And a new one is created, fresh, for  
> every HTTP request.

I'm not worried about HTTP requests, I'm worried about cases  
*outside* HTTP (still trying to think separation of rendering and the  
rest).

What is the real relationship between WikiContext and  
WikiActionBeanContext?   For rendering, I think we need a separate  
RenderingContext interface, which encapsulates everything that the  
rendering engine needs into one interface.  But I am currently unsure  
as to how all these should relate to each other.

/Janne

Re: WikiContext & JCR Sessions

Posted by Andrew Jaquith <an...@me.com>.
(Janne -- you should interpret my comments, below, as informational  
rather than argumentative. Use, or not, as you see fit.)


> WikiSession does not work, because WikiSessions are shared across  
> threads (they're stashed in the HttpSession), and therefore it is  
> illegal to put Sessions in there.  WikiSessions also live too long.

Are you sure they are stashed in the HttpSession? The original  
implementation I wrote took great care to make sure that they weren't.  
That MIGHT have changed due to a bug fix, but I just took a look at  
SessionMonitor and WikiSession, and I could not find when WikiSession  
was actually stashed. A quick reference-skim for  
HttpSession.setAttribute() didn't turn up anything either.

> I am not sure about that, since that would mean that any and all  
> backend methods suddenly need to become Stripes-aware, and that is  
> simply just leaking too much information across boundaries.  It will  
> also make life of the embedders annoying, when they just want to  
> render content, and they need to carry the entire ActionBean legacy  
> from Stripes into their code - when they really don't even need it.

That's a good point. But, the Stripes stuff that is referenced by  
WikiContexts/WikiActionBeans is pretty minor, though. And because of  
the way I've had to retrofit it into our existing classes, it is done  
in a way that is transparent to the rest of JSPWiki. The contract is,  
basically, that if a WikiContext is created through any of the four  
possible methods (StripesFilter, useActionBean tag,  
WikiEngine.createContext() or WikiActionBeanFactory.newActionBean()),  
it will be guaranteed to have a non-null WikiActionBeanContext made  
available to it (via the required ActionBean method getContext()). The  
WikiActionBeanContext itself contains only four references: for  
WikiEngine, WikiSession, HttpServletRequest and HttpServletResponse.  
That's it -- no other references to Stripes objects, and no long  
chains of object references pulling in lots of heavyweight stuff.

(I've written up the approach in the "doc/README - Stripes Migration"  
file, in ARJ_STRIPES_BRANCH.)

I'm NOT actually trying to argue that WikiActionBeanContext is the  
right place to put the JCR code (or a reference to a class that  
contains it) -- just pointing out that it's not as heavyweight as you  
might think. It will always be available, which makes it a decent  
place to put stuff. And a new one is created, fresh, for every HTTP  
request.

> ONLY when we are talking about a http context.  Embedders, or say,  
> even RSS generation internally, would not have it (and would need  
> the DummyHttpRequest & others).

You can still execute handler methods outside of Stripes. What you  
won't get are the automatic property binding and validation features.  
But event methods should still work fine. And more to the point,  
handler methods can return any type they want or throw Exceptions.  
That makes them useful in non-Stripes contexts.

Also, the WikiActionBeanFactory methods for creating new WikiContexts/ 
ActionBeans, by necessity, create a backing WikiActionBeanContext  
object and mock request/response objects, if not supplied by callers.  
This allows for backwards compatibility with  
WikiEngine.createContext() -- critical for JSP migration. That is  
really all the event handler methods need to function properly.

>> WikiEngine should go on a diet. I'd like to see something really  
>> simple in 3.0. WikiEngine should just contains references to the  
>> major Manager classes, and eliminates convenience methods like  
>> saveText() and pageExists(), chiefly because they don't contain  
>> have method signatures with the right parameters. Certainly, if JCR  
>> needs "session awareness" we'll need to do a different API anyhow,  
>> so ditching the existing WikiEngine methods would be good.
>
> Did you take a look at the current WikiEngine in the API proposal?   
> It's *very* lean.  Too lean, in fact...

I am overdue in looking at this... :)


Re: WikiContext & JCR Sessions

Posted by Janne Jalkanen <Ja...@ecyrd.com>.
> There are two potentially better places to locate JCR  
> functionality. One place might be in the WikiSession, ideally as a  
> property of the WikiSession (e.g., getRepositoryManager()/ 
> setRepositoryManager()). This is a pretty good place, actually,  
> because WikiSession has privileged access to the JAAS Subject that  
> contains the user's Principal set, and the user's private  
> credentials (which we haven't exploited yet).

WikiSession does not work, because WikiSessions are shared across  
threads (they're stashed in the HttpSession), and therefore it is  
illegal to put Sessions in there.  WikiSessions also live too long.

> The other place would be the ActionBeanContext, which Stripes or  
> WikiActionBeanFactory associates with every WikiActionBean/ 
> WikiContext. Our implementation is tentatively called the  
> WikiActionBeanContext (not suprisingly), and right now it doesn't  
> do much more than the standard ActionBeanContext than contain a  
> reference to the WikiEngine and WikiSession. We could certainly add  
> JCR functions to that, as well.

I am not sure about that, since that would mean that any and all  
backend methods suddenly need to become Stripes-aware, and that is  
simply just leaking too much information across boundaries.  It will  
also make life of the embedders annoying, when they just want to  
render content, and they need to carry the entire ActionBean legacy  
from Stripes into their code - when they really don't even need it.

The JCR Session object is purely and only related to the Model tier,  
so mixing View or Controller stuff to it sounds icky.

> Remember that most of the "events" a user invokes that cause  
> interesting things to happen will be done through event handler  
> methods. Event handler methods are where the JSP scriptlet code  
> will move to, and they will do most of the heavy lifting for  
> business logic.

ONLY when we are talking about a http context.  Embedders, or say,  
even RSS generation internally, would not have it (and would need the  
DummyHttpRequest & others).

> WikiPages == Node sounds good. We'll need to have a bit more  
> discussion on the degree of auto-commit you foresee. I'm thinking  
> in particular of the side-effects this might have if used in  
> combination with the WikiPageTypeConverter (for 3.0), which will  
> wire up and automatically set the correct WikiPage for a  
> WikiActionBean based on the "page" parameter set in the request.

I'm not seeing any autocommit there.  All changes need a separate  
commit() [or in JCR lingo, save()].

> But beyond that, WikiPage.setContent()/getContent() sound like good  
> places for persistence logic. PageManager might be good too. I tend  
> to prefer data objects that are fairly stupid, and Manager classes  
> that are smart.

Me too, usually - it's just that in this case, once the WikiPage  
contains a reference to the Node, we've pretty much lost the game :-)

> WikiEngine should go on a diet. I'd like to see something really  
> simple in 3.0. WikiEngine should just contains references to the  
> major Manager classes, and eliminates convenience methods like  
> saveText() and pageExists(), chiefly because they don't contain  
> have method signatures with the right parameters. Certainly, if JCR  
> needs "session awareness" we'll need to do a different API anyhow,  
> so ditching the existing WikiEngine methods would be good.

Did you take a look at the current WikiEngine in the API proposal?   
It's *very* lean.  Too lean, in fact...

But the point is really that we can create a special, self-contained  
API JAR, which we can say "this is now the public API which won't be  
changed".  This means that even the WikiEngine interface cannot  
expose too much internals. (You can always then get a WikiEngineImpl  
for hacking.)

> PS. One more thought on WikiSession. The WikiSession's Subject  
> would be a good place to stash the JCR credentials (username and  
> password). I'm thinking, in particular, of  
> Subject.setPublicCredentials() and Subject.setPrivateCredentials.

Mmm... Well, JCR credentials != JSPWiki credentials.  We will need to  
put in the credentials in the property file anyway (in order to allow  
the engine itself access to the repository outside a Http request,  
e.g. indexing or whatever).  I don't think that the JCR auth system  
is very good for us anyway, since it's too restrictive.  I wasn't  
planning on using it.

> It might make sense to write a "JCR Monitor" similar to  
> SessionMonitor, but for JCR sessions... perhaps something that  
> "autosaves" or "autoflushes" every few minutes? This might be a  
> good place to use JMX TimerMBean, too. (Actually, I'd kind of like  
> to refactor the WikiBackgroundThread to be TimerMBeans, because the  
> existing implementation doesn't always terminate cleanly... but  
> that is another discussion...)

Well, if we keep a JCR Session open through only a single HTTP  
Request (remember, they're cheap to create, and this seems to be the  
recommended way at least from the Jackrabbit people), there is no need.

/Janne

Re: WikiContext & JCR Sessions

Posted by Andrew Jaquith <an...@me.com>.
> My initial feeling would be to make the JCR Session a part of the  
> WikiContext (or, to be precise, a JCRWikiContext, which would be a  
> concrete class which would implement a WikiContext interface).  When  
> the WikiContext is created, the Session is created too, and when the  
> WikiContext expires, the Session is logged out.  We could also add a  
> WikiContext.save() method to flush all changes. This would provide  
> fairly logical lifecycle management.

Hmm. I don't think this is a good idea. WikiContexts should really  
just be simple receptacles for form properties, plus some handler  
events that do things based on user actions. That is, they should be  
JavaBeans with some additional "verb" methods. (Or in Stripes  
parlance: ActionBean property getters and setters, plus event handler  
methods.) Putting JCR functionality into WikiContexts makes these  
things heavier, in my view, than they should be.

There are two potentially better places to locate JCR functionality.  
One place might be in the WikiSession, ideally as a property of the  
WikiSession (e.g., getRepositoryManager()/setRepositoryManager()).  
This is a pretty good place, actually, because WikiSession has  
privileged access to the JAAS Subject that contains the user's  
Principal set, and the user's private credentials (which we haven't  
exploited yet).

The other place would be the ActionBeanContext, which Stripes or  
WikiActionBeanFactory associates with every WikiActionBean/ 
WikiContext. Our implementation is tentatively called the  
WikiActionBeanContext (not suprisingly), and right now it doesn't do  
much more than the standard ActionBeanContext than contain a reference  
to the WikiEngine and WikiSession. We could certainly add JCR  
functions to that, as well.

So, those are my two suggested places.

> The bad thing is that means that we need to carry WikiContext into  
> quite a few places after that.  Unless we turn WikiContext into the  
> main repository interface as well, providing things like a Search  
> interface as well.  That means that it would inherit pretty much all  
> of the functionality of the WikiEngine, which might make it a bit  
> too unwieldy.

Remember that most of the "events" a user invokes that cause  
interesting things to happen will be done through event handler  
methods. Event handler methods are where the JSP scriptlet code will  
move to, and they will do most of the heavy lifting for business logic.

Also, WikiActionBean will be guaranteed to contain references to the  
WikiSession (as is the case today), or to the WikiActionBeanContext  
(as will be the case in 3.0). It would not be much work to do an extra  
getActionBeanContext().getRepositoryManager() and then invoke the  
functions that are needed.

> My current idea is to turn WikiPages into essentially  
> representatives of Nodes.  Calling WikiPage.getContent() will return  
> the content of the page and WikiPage.setContent() will set it. This  
> provides a really neat way of managing the data, since e.g.  
> WikiPage.get/setAttribute() could be automatically persisted.  The  
> bad thing, obviously, would be that since Nodes contain a reference  
> to the Session where they came from, you *cannot* cache a WikiPage  
> across new invocations (e.g. threads).

WikiPages == Node sounds good. We'll need to have a bit more  
discussion on the degree of auto-commit you foresee. I'm thinking in  
particular of the side-effects this might have if used in combination  
with the WikiPageTypeConverter (for 3.0), which will wire up and  
automatically set the correct WikiPage for a WikiActionBean based on  
the "page" parameter set in the request.

But beyond that, WikiPage.setContent()/getContent() sound like good  
places for persistence logic. PageManager might be good too. I tend to  
prefer data objects that are fairly stupid, and Manager classes that  
are smart.

> Retaining the old WikiEngine API is problematic because the passed  
> arguments only contain Strings.  Since there is no session  
> management in that API, we would need to do Repository.login() every  
> time e.g. pageExists() is called, and *that* would become a bit too  
> rough.  So my preference would be, frankly, to dump existing  
> WikiEngine API and make something nicer.  We can have a lookalike  
> API, but that's going to be slow.

WikiEngine should go on a diet. I'd like to see something really  
simple in 3.0. WikiEngine should just contains references to the major  
Manager classes, and eliminates convenience methods like saveText()  
and pageExists(), chiefly because they don't contain have method  
signatures with the right parameters. Certainly, if JCR needs "session  
awareness" we'll need to do a different API anyhow, so ditching the  
existing WikiEngine methods would be good.

PS. One more thought on WikiSession. The WikiSession's Subject would  
be a good place to stash the JCR credentials (username and password).  
I'm thinking, in particular, of Subject.setPublicCredentials() and  
Subject.setPrivateCredentials.

> An obvious option would be to use a ThreadLocal for a Session, but  
> that would pretty much make it a global, and the other problem is  
> that then lifecycle management becomes a bit hazy - if there are  
> unsaved changes, the session would grow uncontrollably.  So there  
> would need to be a separate flushing action at some point...  But  
> that would allow us to keep the existing API.

Well, we all know how important it is to have separate flushing  
actions. Otherwise, things would get messy indeed. <cough>

It might make sense to write a "JCR Monitor" similar to  
SessionMonitor, but for JCR sessions... perhaps something that  
"autosaves" or "autoflushes" every few minutes? This might be a good  
place to use JMX TimerMBean, too. (Actually, I'd kind of like to  
refactor the WikiBackgroundThread to be TimerMBeans, because the  
existing implementation doesn't always terminate cleanly... but that  
is another discussion...)

> Any thoughts?  Gotchas?  Obvious ideas I've ignored?  It would be a  
> good idea if others read up on the JCR documentation as well - the  
> spec is fairly well written, but it's quite long.

I wish I had the time. :)