[Lift] Expiring pages via HTTP headers

2008-12-09 Thread Charles F. Munat

I want to (attempt to) prevent the browser from caching certain pages as 
there is a problem if the user backs up to them. I can do this with HTTP 
headers, of course.

Question: Is this functionality built-in to Lift? I could find nothing 
on the wiki. If not, how does one set the HTTP headers on a page (and 
from where)?

Thanks.

Chas.

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Lift" group.
To post to this group, send email to liftweb@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en
-~--~~~~--~~--~--~---



[Lift] Re: Loc, trailing slashes, and index files

2008-12-09 Thread Derek Chen-Becker
Awesome!

Derek

PS - I just got two of the same email from you at 4:25 and 4:38. Did you hit
send twice or is something going on with the list?

On Tue, Dec 9, 2008 at 4:38 PM, David Pollak
<[EMAIL PROTECTED]>wrote:

> I looks like a defect to me.  I'll work on fixing it Thursday.
>
> On Tue, Dec 9, 2008 at 2:04 PM, Derek Chen-Becker <[EMAIL PROTECTED]>wrote:
>
>> This is both a comment and a question. I'd like to be able to have a Menu
>> with a Loc pointing at "/help/". By using the strPairToLink method on the
>> Loc object, I can use it as both an entry into the help system. This allows
>> me to effectively bring up "/help/index" due to Lift converting trailing
>> slashes to "/index", and I can use the boolean parameter to allow access to
>> all files under the help subdirectory. In order to make this work, though, I
>> need to define the menu like:
>>
>> val helpMenu = Menu(Loc("HelpHome", ("help" :: "" :: Nil) -> true,
>> "Help"))
>>
>> Note the empty string as part of the path definition. If I omit this, then
>> files under the help subdirectory are accessible, but the link generated by
>> Menu.builder is "/help". Because it omits the trailing slash it seems that
>> Lift tries to open the directory as a template XML file and I get an
>> internal server error (500, stack trace at the end of the email). My
>> question is whether this is the intended way of doing what I want, or if
>> I've missed some other way to define this in a single Menu entry (yes, I
>> could do two, with one hidden). With a server like apache, if I request a
>> directory without the trailing slash it will respond with a 301 redirect to
>> the same URL, but with a trailing slash. Should Lift be modified to follow
>> this behavior?
>>
>> One more related issue is that even if I define my Menu as I've shown
>> above, if I try to use "/help" in the URL without the trailing slash, I get
>> a directory listing instead of the index.html, which I would expect.
>>
>> I'm not sure if this is all under Lift's purview or if some of it should
>> be handled by chaining in the filter.
>>
>> Derek
>>
>> PS - Here's the stack trace if I omit the fake "slash":
>>
>> ERROR - Exception being returned to browser when processing Req(List(),
>> Map(), ParsePath(List(help),,true,false), , GetRequest, null)
>> java.lang.IllegalArgumentException: line 1 does not exist
>> at scala.io.Source.getLine(Source.scala:280)
>> at scala.io.Source.report(Source.scala:368)
>> at scala.io.Source.reportError(Source.scala:355)
>> at scala.io.Source.reportError(Source.scala:344)
>> at
>> scala.xml.parsing.MarkupParser$class.reportSyntaxError(MarkupParser.scala:1113)
>>
>>
>>
>>
>
>
> --
> Lift, the simply functional web framework http://liftweb.net
> Collaborative Task Management http://much4.us
> Follow me: http://twitter.com/dpp
> Git some: http://github.com/dpp
>
> >
>

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Lift" group.
To post to this group, send email to liftweb@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en
-~--~~~~--~~--~--~---



[Lift] Re: Why JPA?

2008-12-09 Thread Derek Chen-Becker
OK, I definitely see some problems here. Unfortunately I'm pretty tied up
for the rest of the evening, but if you don't mind waiting I promise to
write up a detailed response tomorrow. Let me just point out some things I
see:


   1. You're calling merge (Model.merge(s)) on an object that you just
   obtained via getReference. While it won't cause problems, it's redundant,
   since the object returned from getReference already has its state managed.
   2. I would probably set a val to the new Row first, instead of using a
   wrapper to get at the last item in the s.rows collection. You also need to
   persist the row object itself unless you've explicitly placed a Cascade on
   s.rows. Otherwise, you're using an object that isn't really an entity which
   might explain double entries.
   3. Since this is AJAX you may not need to add the new Row object to the
   s.rows collection at all at this point. Just setting the owner field on the
   Row (not sure what it's actually called) but not persisting it should do
   what you want in terms of only persisting on first update.
   4. I think you might need an explicit flush in the AjaxText update
   function

I also forgot to ask if you're using JTA or RESOURCE_LOCAL transactions.

Derek

On Tue, Dec 9, 2008 at 4:27 PM, Charles F. Munat <[EMAIL PROTECTED]> wrote:

>
> Derek Chen-Becker wrote:
> > Hmmm. It doesn't seem like this should be causing issues. Probably the
> > most common mistake made with merge is that merge returns an entirely
> > new object, so you discard the original.
>
> Ah! That's good to know. I think that after I used Model.merge(row) I
> expected row to be attached. But then maybe I should have used row =
> Model.merge(row)? So then row needs to be a var not a val?
>
> I am confused...
> > Also, if you want the change to
> > be immediately visible and to check constraints, etc, you need to
> > immediately flush. For instance:
> >
> > updateRow (row : Row) : Row = {
> >   Model.merge(row)
> >   Model.flush()
> > }
>
> Oh, yeah... I've been flushing so much my water bill doubled this month.
> Flush, flush, flush, but then I have twenty copies of each row... sigh.
>
> > It really should be that simple. I'd be happy to look at code if you'd
> > like to see where there might be issues. I've added some comments below:
>
> I can zip it up and send it to you if you're curious.
>
> > I'm assuming that at least this works flawlessly, right?
>
> I think so.
>
> > I'm not 100%, but you may need to actually set the owner field on the
> > row as well as adding it to the Survey.rows collection. If I remember
> > correctly, owner fields in objects belonging to collections aren't
> > automatically updated unless you explicitly set the Cascade property on
> > the collection.
>
> Yeah, this is very confusing. What I am currently doing is this:
>
> def getOneButton(xhtml: NodeSeq) : NodeSeq = {
>   val survey: Survey = Model.createNamedQuery[Survey](...)
> .getSingleResult()
>
>   SHtml.ajaxButton("Add a row",
> () => {
>   AppendHtml("myTable", getRow(survey))
> }, ("class", "removeButton"
>   )
> }
>
> def getRow(survey: Survey): NodeSeq = {
>
>   val s = Model.getReference[Survey](classOf[Survey], survey.id)
>   s.rows.add(new Row())
>   Model.merge(s)
>   Model.flush()
>   val row = JPA.listToWrapper(s.rows).last
>
>   
> {SHtml.ajaxText(row.colOne,
>   (txt: String) => {
> row.colOne = txt
> Model.merge(row)
> Noop
>   },
>   ("id", "colOne" + row.id.toString), ("size", "8"))}
> ...
>   
>
> }
>
> > In your add row method, did you persist the new Row before returning it?
> > If not, it never gets an ID and then when it gets merged it will create
> > a new instance. I'd have to look at the code to see for sure.
>
> See above.
>
> > Actually, I think the case of a multi-page form is a good candidate for
> > an extended session, simply because you would likely want the entire
> > form to be treated atomically.
>
> Yes, although the client wanted every change to the form to be persisted
> immediately (no submit buttons), so I end up making lots of trips to the
> database. But there will only be a few dozen people taking this survey,
> so performance is not an issue. I have other sites with similar forms
> where that is not the case.
>
> > I'm having trouble visualizing what exactly the dirty flag is
> representing.
>
> I want to be able to strip out empty rows afterwards (since blank rows
> are persisted before they are sent to the browser). Rather than check
> every field in the row (there are seven), I have a flag (not really a
> dirty flag) called isNull or something like that. On the first change to
> a field, I set it to false. Then later I can delete all isNull == true
> rows to clean things up.
>
> If I could just create -- but not persist -- rows and persist them after
> the first field is updated, then that would be better. But I was having
> a really difficult time of that.
>
> > I think I mos

[Lift] Re: Loc, trailing slashes, and index files

2008-12-09 Thread David Pollak
I looks like a defect to me.  I'll work on fixing it Thursday.

On Tue, Dec 9, 2008 at 2:04 PM, Derek Chen-Becker <[EMAIL PROTECTED]>wrote:

> This is both a comment and a question. I'd like to be able to have a Menu
> with a Loc pointing at "/help/". By using the strPairToLink method on the
> Loc object, I can use it as both an entry into the help system. This allows
> me to effectively bring up "/help/index" due to Lift converting trailing
> slashes to "/index", and I can use the boolean parameter to allow access to
> all files under the help subdirectory. In order to make this work, though, I
> need to define the menu like:
>
> val helpMenu = Menu(Loc("HelpHome", ("help" :: "" :: Nil) -> true, "Help"))
>
> Note the empty string as part of the path definition. If I omit this, then
> files under the help subdirectory are accessible, but the link generated by
> Menu.builder is "/help". Because it omits the trailing slash it seems that
> Lift tries to open the directory as a template XML file and I get an
> internal server error (500, stack trace at the end of the email). My
> question is whether this is the intended way of doing what I want, or if
> I've missed some other way to define this in a single Menu entry (yes, I
> could do two, with one hidden). With a server like apache, if I request a
> directory without the trailing slash it will respond with a 301 redirect to
> the same URL, but with a trailing slash. Should Lift be modified to follow
> this behavior?
>
> One more related issue is that even if I define my Menu as I've shown
> above, if I try to use "/help" in the URL without the trailing slash, I get
> a directory listing instead of the index.html, which I would expect.
>
> I'm not sure if this is all under Lift's purview or if some of it should be
> handled by chaining in the filter.
>
> Derek
>
> PS - Here's the stack trace if I omit the fake "slash":
>
> ERROR - Exception being returned to browser when processing Req(List(),
> Map(), ParsePath(List(help),,true,false), , GetRequest, null)
> java.lang.IllegalArgumentException: line 1 does not exist
> at scala.io.Source.getLine(Source.scala:280)
> at scala.io.Source.report(Source.scala:368)
> at scala.io.Source.reportError(Source.scala:355)
> at scala.io.Source.reportError(Source.scala:344)
> at
> scala.xml.parsing.MarkupParser$class.reportSyntaxError(MarkupParser.scala:1113)
>
>
> >
>


-- 
Lift, the simply functional web framework http://liftweb.net
Collaborative Task Management http://much4.us
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Lift" group.
To post to this group, send email to liftweb@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en
-~--~~~~--~~--~--~---



[Lift] Re: Why JPA?

2008-12-09 Thread Charles F. Munat

Derek Chen-Becker wrote:
> Hmmm. It doesn't seem like this should be causing issues. Probably the 
> most common mistake made with merge is that merge returns an entirely 
> new object, so you discard the original.

Ah! That's good to know. I think that after I used Model.merge(row) I 
expected row to be attached. But then maybe I should have used row = 
Model.merge(row)? So then row needs to be a var not a val?

I am confused...
> Also, if you want the change to 
> be immediately visible and to check constraints, etc, you need to 
> immediately flush. For instance:
> 
> updateRow (row : Row) : Row = {
>   Model.merge(row)
>   Model.flush()
> }

Oh, yeah... I've been flushing so much my water bill doubled this month. 
Flush, flush, flush, but then I have twenty copies of each row... sigh.

> It really should be that simple. I'd be happy to look at code if you'd 
> like to see where there might be issues. I've added some comments below:

I can zip it up and send it to you if you're curious.

> I'm assuming that at least this works flawlessly, right?

I think so.

> I'm not 100%, but you may need to actually set the owner field on the 
> row as well as adding it to the Survey.rows collection. If I remember 
> correctly, owner fields in objects belonging to collections aren't 
> automatically updated unless you explicitly set the Cascade property on 
> the collection.

Yeah, this is very confusing. What I am currently doing is this:

def getOneButton(xhtml: NodeSeq) : NodeSeq = {
   val survey: Survey = Model.createNamedQuery[Survey](...)
 .getSingleResult()

   SHtml.ajaxButton("Add a row",
 () => {
   AppendHtml("myTable", getRow(survey))
 }, ("class", "removeButton"
   )
}

def getRow(survey: Survey): NodeSeq = {

   val s = Model.getReference[Survey](classOf[Survey], survey.id)
   s.rows.add(new Row())
   Model.merge(s)
   Model.flush()
   val row = JPA.listToWrapper(s.rows).last

   
 {SHtml.ajaxText(row.colOne,
   (txt: String) => {
 row.colOne = txt
 Model.merge(row)
 Noop
   },
   ("id", "colOne" + row.id.toString), ("size", "8"))}
 ...
   

}

> In your add row method, did you persist the new Row before returning it? 
> If not, it never gets an ID and then when it gets merged it will create 
> a new instance. I'd have to look at the code to see for sure.

See above.

> Actually, I think the case of a multi-page form is a good candidate for 
> an extended session, simply because you would likely want the entire 
> form to be treated atomically.

Yes, although the client wanted every change to the form to be persisted 
immediately (no submit buttons), so I end up making lots of trips to the 
database. But there will only be a few dozen people taking this survey, 
so performance is not an issue. I have other sites with similar forms 
where that is not the case.

> I'm having trouble visualizing what exactly the dirty flag is representing.

I want to be able to strip out empty rows afterwards (since blank rows 
are persisted before they are sent to the browser). Rather than check 
every field in the row (there are seven), I have a flag (not really a 
dirty flag) called isNull or something like that. On the first change to 
a field, I set it to false. Then later I can delete all isNull == true 
rows to clean things up.

If I could just create -- but not persist -- rows and persist them after 
the first field is updated, then that would be better. But I was having 
a really difficult time of that.

> I think I mostly understand and it sounds like something is probably 
> wrong. I don't think what you're describing is the intended behavior for 
> JPA.

Thanks. I'll zip up the site and send it to you off list (I'm not going 
to clean it). If you have a chance to look at the snippet, maybe you can 
see quickly what I'm doing wrong. Hopefully, it will also give you some 
ideas for how something like this could be added to the JPA example. 
That would be super.

Chas.

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Lift" group.
To post to this group, send email to liftweb@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en
-~--~~~~--~~--~--~---



[Lift] Re: Loc, trailing slashes, and index files

2008-12-09 Thread David Pollak
I looks like a defect to me.  I'll work on fixing it Thursday.

On Tue, Dec 9, 2008 at 2:04 PM, Derek Chen-Becker <[EMAIL PROTECTED]>wrote:

> This is both a comment and a question. I'd like to be able to have a Menu
> with a Loc pointing at "/help/". By using the strPairToLink method on the
> Loc object, I can use it as both an entry into the help system. This allows
> me to effectively bring up "/help/index" due to Lift converting trailing
> slashes to "/index", and I can use the boolean parameter to allow access to
> all files under the help subdirectory. In order to make this work, though, I
> need to define the menu like:
>
> val helpMenu = Menu(Loc("HelpHome", ("help" :: "" :: Nil) -> true, "Help"))
>
> Note the empty string as part of the path definition. If I omit this, then
> files under the help subdirectory are accessible, but the link generated by
> Menu.builder is "/help". Because it omits the trailing slash it seems that
> Lift tries to open the directory as a template XML file and I get an
> internal server error (500, stack trace at the end of the email). My
> question is whether this is the intended way of doing what I want, or if
> I've missed some other way to define this in a single Menu entry (yes, I
> could do two, with one hidden). With a server like apache, if I request a
> directory without the trailing slash it will respond with a 301 redirect to
> the same URL, but with a trailing slash. Should Lift be modified to follow
> this behavior?
>
> One more related issue is that even if I define my Menu as I've shown
> above, if I try to use "/help" in the URL without the trailing slash, I get
> a directory listing instead of the index.html, which I would expect.
>
> I'm not sure if this is all under Lift's purview or if some of it should be
> handled by chaining in the filter.
>
> Derek
>
> PS - Here's the stack trace if I omit the fake "slash":
>
> ERROR - Exception being returned to browser when processing Req(List(),
> Map(), ParsePath(List(help),,true,false), , GetRequest, null)
> java.lang.IllegalArgumentException: line 1 does not exist
> at scala.io.Source.getLine(Source.scala:280)
> at scala.io.Source.report(Source.scala:368)
> at scala.io.Source.reportError(Source.scala:355)
> at scala.io.Source.reportError(Source.scala:344)
> at
> scala.xml.parsing.MarkupParser$class.reportSyntaxError(MarkupParser.scala:1113)
>
>
> >
>


-- 
Lift, the simply functional web framework http://liftweb.net
Collaborative Task Management http://much4.us
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Lift" group.
To post to this group, send email to liftweb@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en
-~--~~~~--~~--~--~---



[Lift] Loc, trailing slashes, and index files

2008-12-09 Thread Derek Chen-Becker
This is both a comment and a question. I'd like to be able to have a Menu
with a Loc pointing at "/help/". By using the strPairToLink method on the
Loc object, I can use it as both an entry into the help system. This allows
me to effectively bring up "/help/index" due to Lift converting trailing
slashes to "/index", and I can use the boolean parameter to allow access to
all files under the help subdirectory. In order to make this work, though, I
need to define the menu like:

val helpMenu = Menu(Loc("HelpHome", ("help" :: "" :: Nil) -> true, "Help"))

Note the empty string as part of the path definition. If I omit this, then
files under the help subdirectory are accessible, but the link generated by
Menu.builder is "/help". Because it omits the trailing slash it seems that
Lift tries to open the directory as a template XML file and I get an
internal server error (500, stack trace at the end of the email). My
question is whether this is the intended way of doing what I want, or if
I've missed some other way to define this in a single Menu entry (yes, I
could do two, with one hidden). With a server like apache, if I request a
directory without the trailing slash it will respond with a 301 redirect to
the same URL, but with a trailing slash. Should Lift be modified to follow
this behavior?

One more related issue is that even if I define my Menu as I've shown above,
if I try to use "/help" in the URL without the trailing slash, I get a
directory listing instead of the index.html, which I would expect.

I'm not sure if this is all under Lift's purview or if some of it should be
handled by chaining in the filter.

Derek

PS - Here's the stack trace if I omit the fake "slash":

ERROR - Exception being returned to browser when processing Req(List(),
Map(), ParsePath(List(help),,true,false), , GetRequest, null)
java.lang.IllegalArgumentException: line 1 does not exist
at scala.io.Source.getLine(Source.scala:280)
at scala.io.Source.report(Source.scala:368)
at scala.io.Source.reportError(Source.scala:355)
at scala.io.Source.reportError(Source.scala:344)
at
scala.xml.parsing.MarkupParser$class.reportSyntaxError(MarkupParser.scala:1113)

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Lift" group.
To post to this group, send email to liftweb@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en
-~--~~~~--~~--~--~---



[Lift] Re: LiftRules consolidation

2008-12-09 Thread David Pollak
On Tue, Dec 9, 2008 at 12:12 PM, Jorge Ortiz <[EMAIL PROTECTED]> wrote:

> Hm... I can think of situations where such mutations are useful after
> Boot (app/prependSnippet comes to mind). Maybe they can be made immutable
> (.toList) as necessary?
>

I think these should be session-specific and there is (or at least was) a
mechanism for session-specific snippets.


>
> --j
>
>
> On Tue, Dec 9, 2008 at 2:01 PM, David Pollak <
> [EMAIL PROTECTED]> wrote:
>
>> And we should freeze the lists after Boot is finished.  The permutation
>> methods should throw exceptions post-boot
>>
>> On Dec 9, 2008 11:39 AM, "Jorge Ortiz" <[EMAIL PROTECTED]> wrote:
>>
>> Seems like prime opportunity for an abstraction...
>>
>> Why not make them (*gasp*) mutable data structures with prepend/append
>> methods?
>>
>> --j
>>
>> On Tue, Dec 9, 2008 at 1:35 PM, Marius <[EMAIL PROTECTED]> wrote: >
>> > > Hi. > > Unfortunatel...
>>
>>
>>
>>
>
> >
>


-- 
Lift, the simply functional web framework http://liftweb.net
Collaborative Task Management http://much4.us
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Lift" group.
To post to this group, send email to liftweb@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en
-~--~~~~--~~--~--~---



[Lift] Re: Why JPA?

2008-12-09 Thread Derek Chen-Becker
Hmmm. It doesn't seem like this should be causing issues. Probably the most
common mistake made with merge is that merge returns an entirely new object,
so you discard the original. Also, if you want the change to be immediately
visible and to check constraints, etc, you need to immediately flush. For
instance:

updateRow (row : Row) : Row = {
  Model.merge(row)
  Model.flush()
}

It really should be that simple. I'd be happy to look at code if you'd like
to see where there might be issues. I've added some comments below:

On Tue, Dec 9, 2008 at 3:09 PM, Charles F. Munat <[EMAIL PROTECTED]> wrote:

> I set this up so that the user gets a blank row. They can click an "add
> a row" link to add another row. They can click a "-" link at the end of
> each row to remove that row.


I'm assuming that at least this works flawlessly, right?


>
>
> On the server, this creates a new Row() and adds it to the survey
> (Survey.rows.add(new Row())). Then it populates a table row and sends it
> back to the browser.


I'm not 100%, but you may need to actually set the owner field on the row as
well as adding it to the Survey.rows collection. If I remember correctly,
owner fields in objects belonging to collections aren't automatically
updated unless you explicitly set the Cascade property on the collection.


>
>
> I had a TERRIBLE time making this work (and I'm still not convinced it's
> working consistently).
>
> For one thing, the fields in the table update the server on blur using
> AJAX. That was a hassle. Each time I tabbed from one field to the next,
> instead of updating the current Row object, it would create a new one.
> The reason seemed to be because the object was detached. I tried all
> sorts of things: merging, flushing, even trying to pull the row back out
> from the Survey object before merging it. This drove me crazy for two days.


In your add row method, did you persist the new Row before returning it? If
not, it never gets an ID and then when it gets merged it will create a new
instance. I'd have to look at the code to see for sure.


>
>
> Maybe I'm wrong, but the idea of keeping the EntityManager open for the
> duration of the session, manually calling begin and end transaction, and
> only merging and flushing as necessary appeals to me. In this instance,
> I'd push the changes to the database probably on every request to be
> safe, but I'd prefer it if objects didn't detach themselves.


Actually, I think the case of a multi-page form is a good candidate for an
extended session, simply because you would likely want the entire form to be
treated atomically.


>
>
> It would also be nice to be able to create new objects, and then only
> persist them if they need to be persisted. On the above project, I have
> a dirty field on the Row. Each time the page is reloaded, I delete all
> rows that are not dirty, then recreate new rows as necessary. This burns
> up a lot of ids needlessly. It won't make a difference on this survey,
> but it seems a kludgy way to do things.


I'm having trouble visualizing what exactly the dirty flag is representing.


>
> What do you think, Derek? Am I explaining this well enough that you can
> understand what I'm talking about? Is there a simple solution that I'm
> missing? I'm happy to post code if that helps.
>

I think I mostly understand and it sounds like something is probably wrong.
I don't think what you're describing is the intended behavior for JPA.

Derek

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Lift" group.
To post to this group, send email to liftweb@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en
-~--~~~~--~~--~--~---



[Lift] Re: Why JPA?

2008-12-09 Thread Charles F. Munat

I'm not really very clear on how all this works, but I've had a terrible 
time with merging objects.

I built a multi-page survey with forty-some questions on it. One of the 
questions asks users to fill out a table in which each row is an object 
-- call it a Row. I don't know in advance whether there will be two rows 
or twenty.

I set this up so that the user gets a blank row. They can click an "add 
a row" link to add another row. They can click a "-" link at the end of 
each row to remove that row.

On the server, this creates a new Row() and adds it to the survey 
(Survey.rows.add(new Row())). Then it populates a table row and sends it 
back to the browser.

I had a TERRIBLE time making this work (and I'm still not convinced it's 
working consistently).

For one thing, the fields in the table update the server on blur using 
AJAX. That was a hassle. Each time I tabbed from one field to the next, 
instead of updating the current Row object, it would create a new one. 
The reason seemed to be because the object was detached. I tried all 
sorts of things: merging, flushing, even trying to pull the row back out 
from the Survey object before merging it. This drove me crazy for two days.

Maybe I'm wrong, but the idea of keeping the EntityManager open for the 
duration of the session, manually calling begin and end transaction, and 
only merging and flushing as necessary appeals to me. In this instance, 
I'd push the changes to the database probably on every request to be 
safe, but I'd prefer it if objects didn't detach themselves.

It would also be nice to be able to create new objects, and then only 
persist them if they need to be persisted. On the above project, I have 
a dirty field on the Row. Each time the page is reloaded, I delete all 
rows that are not dirty, then recreate new rows as necessary. This burns 
up a lot of ids needlessly. It won't make a difference on this survey, 
but it seems a kludgy way to do things.

Scala is wonderful, Lift is amazing, and JPA/Hibernate mostly rocks. But 
when working with multiple objects associated in a one-to-many 
relationship to a parent object, there simply *has* to be a better way. 
This is one spot where the SQL-centric Rails seems infinitely superior.

So I don't know if the problems I experienced and am experiencing are 
because of some basic misunderstanding on my part, or because of the 
volatile nature of the EntityManager as it is currently managed in 
JPA/Lift, but if it's the latter, then I'm all for the sorts of changes 
that Philip is suggesting.

What do you think, Derek? Am I explaining this well enough that you can 
understand what I'm talking about? Is there a simple solution that I'm 
missing? I'm happy to post code if that helps.

Chas.

Derek Chen-Becker wrote:
> I think you misunderstand the lifecycle of a stateful snippet. A 
> stateful snippet has specific techniques to keep it resident (using 
> this.link, this.redirect, etc) so you have to be careful about how you 
> use it or you lose the instance. The HTTP session would be the most 
> appropriate place for a JPA EM that crosses request boundaries because 
> it will *always* be available to snippets (I had forgotten about the 
> EXTENDED type, I've never used it).
> 
> Another issue, orthogonal to how you keep the session around, is that 
> when you hold a session open you're also holding a transaction open 
> unless you use RESOURCE_LOCAL transactions (unmanaged JDBC connections, 
> essentially). That has implications on data visibility to other 
> connections, how you handle exceptions, etc.
> 
> Don't get me wrong, I think that there's a place for extended JPA EMs, I 
> just want to make sure you're aware of all of the tradeoffs so that you 
> don't get any nasty surprises. It's my opinion that for most use cases 
> opening a session for each request (and the merge/getReference that 
> doing it this way implies) is the best way to do it. JPA providers are 
> usually pretty intelligent about efficiently using database operations 
> to keep things coherent, so I don't think that "avoiding merge" is 
> necessarily a worthwhile goal in and of itself.
> 
> Cheers,
> 
> Derek
> 
> On Tue, Dec 9, 2008 at 6:39 AM, philip <[EMAIL PROTECTED] 
> > wrote:
> 
> 
> Hi Derek,
> 
> I think I found the solution to the problem I am thinking of.
> Its called JPA Extended Persistence Context. Its suggested that a
> extended persistence context be created which starts at some time and
> ends at some time and is stored in HttpSession. From the bits I read
> they said its no good to store in a Stateful Session Bean because the
> bean may be passivated and the context lost. Well we are not using
> stateful session bean so it doesn't matter, we can put it in the
> session or put it on some object that hands around like a session such
> as a ... in our case I believe a Snippet.
> 
> So in the JPA demo, you would then open as
> 

[Lift] Re: LiftRules consolidation

2008-12-09 Thread Marius

I started to add a few RulesSeq ... looks pretty neat so far not to
mention that LiftRules is reducing its size. And these var can
actually be publicly exposed as val-s.

On Dec 9, 10:30 pm, Marius <[EMAIL PROTECTED]> wrote:
> I agree with append/prepend naming. As far as ListBuffer goes I'm not
> sure ... I mean you are correct about it, but these "rules" will be
> done once in boot and I'm not sure who actually adds more then a few
> items .. in practice.
>
> At the end of the day I don;t mind using ListBuffer or List ...as I
> think in this specific context it has little consequence. If this
> approach is fine with everyone I can start implementing it.
>
> Br's,
> Marius
>
> On Dec 9, 10:25 pm, "Jorge Ortiz" <[EMAIL PROTECTED]> wrote:
>
> > I would use a ListBuffer as the underlying representation. I would call the
> > methods "append" and "prepend" (LiftRules.snippet.append,
> > LiftRules.dispatch.append, etc.). I would also make them immutable
> > as-needed. ListBuffer caches toList so that it's very efficient if you don't
> > append/prepend in between calls to toList.
>
> > On Tue, Dec 9, 2008 at 2:20 PM, Marius <[EMAIL PROTECTED]> wrote:
>
> > > I'm not sure if this is the case ... if we want context dependent
> > > Snippets then probably using loc snippets is the right place
>
> > > How about something like:
>
> > > abstract class RulesSeq[T] {
> > >  var rules : List[T] = Nil
>
> > >  private def safe_?(f : => Any) {
> > >    doneBoot match {
> > >      case false => f
> > >      case _ => throw new IllegalStateException("Can not modify after
> > > boot.");
> > >    }
> > >  }
>
> > >  def prependRule(r: T) {
> > >    safe_? {
> > >      rules = r :: rules
> > >    }
> > >  }
>
> > >  def appendRule(r: T) {
> > >    safe_? {
> > >      rules = rules ::: List(r)
> > >    }
> > >  }
> > > }
>
> > > Br's,
> > > marius
>
> > > On Dec 9, 10:12 pm, "Jorge Ortiz" <[EMAIL PROTECTED]> wrote:
> > > > Hm... I can think of situations where such mutations are useful 
> > > > after
> > > > Boot (app/prependSnippet comes to mind). Maybe they can be made 
> > > > immutable
> > > > (.toList) as necessary?
>
> > > > --j
>
> > > > On Tue, Dec 9, 2008 at 2:01 PM, David Pollak
> > > > <[EMAIL PROTECTED]>wrote:
>
> > > > > And we should freeze the lists after Boot is finished.  The 
> > > > > permutation
> > > > > methods should throw exceptions post-boot
>
> > > > > On Dec 9, 2008 11:39 AM, "Jorge Ortiz" <[EMAIL PROTECTED]> wrote:
>
> > > > > Seems like prime opportunity for an abstraction...
>
> > > > > Why not make them (*gasp*) mutable data structures with prepend/append
> > > > > methods?
>
> > > > > --j
>
> > > > > On Tue, Dec 9, 2008 at 1:35 PM, Marius <[EMAIL PROTECTED]>
> > > wrote: >
> > > > > > > Hi. > > Unfortunatel...
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Lift" group.
To post to this group, send email to liftweb@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en
-~--~~~~--~~--~--~---



[Lift] Re: LiftRules consolidation

2008-12-09 Thread Marius

I agree with append/prepend naming. As far as ListBuffer goes I'm not
sure ... I mean you are correct about it, but these "rules" will be
done once in boot and I'm not sure who actually adds more then a few
items .. in practice.

At the end of the day I don;t mind using ListBuffer or List ...as I
think in this specific context it has little consequence. If this
approach is fine with everyone I can start implementing it.


Br's,
Marius

On Dec 9, 10:25 pm, "Jorge Ortiz" <[EMAIL PROTECTED]> wrote:
> I would use a ListBuffer as the underlying representation. I would call the
> methods "append" and "prepend" (LiftRules.snippet.append,
> LiftRules.dispatch.append, etc.). I would also make them immutable
> as-needed. ListBuffer caches toList so that it's very efficient if you don't
> append/prepend in between calls to toList.
>
> On Tue, Dec 9, 2008 at 2:20 PM, Marius <[EMAIL PROTECTED]> wrote:
>
> > I'm not sure if this is the case ... if we want context dependent
> > Snippets then probably using loc snippets is the right place
>
> > How about something like:
>
> > abstract class RulesSeq[T] {
> >  var rules : List[T] = Nil
>
> >  private def safe_?(f : => Any) {
> >    doneBoot match {
> >      case false => f
> >      case _ => throw new IllegalStateException("Can not modify after
> > boot.");
> >    }
> >  }
>
> >  def prependRule(r: T) {
> >    safe_? {
> >      rules = r :: rules
> >    }
> >  }
>
> >  def appendRule(r: T) {
> >    safe_? {
> >      rules = rules ::: List(r)
> >    }
> >  }
> > }
>
> > Br's,
> > marius
>
> > On Dec 9, 10:12 pm, "Jorge Ortiz" <[EMAIL PROTECTED]> wrote:
> > > Hm... I can think of situations where such mutations are useful after
> > > Boot (app/prependSnippet comes to mind). Maybe they can be made immutable
> > > (.toList) as necessary?
>
> > > --j
>
> > > On Tue, Dec 9, 2008 at 2:01 PM, David Pollak
> > > <[EMAIL PROTECTED]>wrote:
>
> > > > And we should freeze the lists after Boot is finished.  The permutation
> > > > methods should throw exceptions post-boot
>
> > > > On Dec 9, 2008 11:39 AM, "Jorge Ortiz" <[EMAIL PROTECTED]> wrote:
>
> > > > Seems like prime opportunity for an abstraction...
>
> > > > Why not make them (*gasp*) mutable data structures with prepend/append
> > > > methods?
>
> > > > --j
>
> > > > On Tue, Dec 9, 2008 at 1:35 PM, Marius <[EMAIL PROTECTED]>
> > wrote: >
> > > > > > Hi. > > Unfortunatel...
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Lift" group.
To post to this group, send email to liftweb@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en
-~--~~~~--~~--~--~---



[Lift] Re: LiftRules consolidation

2008-12-09 Thread Jorge Ortiz
I would use a ListBuffer as the underlying representation. I would call the
methods "append" and "prepend" (LiftRules.snippet.append,
LiftRules.dispatch.append, etc.). I would also make them immutable
as-needed. ListBuffer caches toList so that it's very efficient if you don't
append/prepend in between calls to toList.

On Tue, Dec 9, 2008 at 2:20 PM, Marius <[EMAIL PROTECTED]> wrote:

>
> I'm not sure if this is the case ... if we want context dependent
> Snippets then probably using loc snippets is the right place
>
> How about something like:
>
> abstract class RulesSeq[T] {
>  var rules : List[T] = Nil
>
>  private def safe_?(f : => Any) {
>doneBoot match {
>  case false => f
>  case _ => throw new IllegalStateException("Can not modify after
> boot.");
>}
>  }
>
>  def prependRule(r: T) {
>safe_? {
>  rules = r :: rules
>}
>  }
>
>  def appendRule(r: T) {
>safe_? {
>  rules = rules ::: List(r)
>}
>  }
> }
>
> Br's,
> marius
>
> On Dec 9, 10:12 pm, "Jorge Ortiz" <[EMAIL PROTECTED]> wrote:
> > Hm... I can think of situations where such mutations are useful after
> > Boot (app/prependSnippet comes to mind). Maybe they can be made immutable
> > (.toList) as necessary?
> >
> > --j
> >
> > On Tue, Dec 9, 2008 at 2:01 PM, David Pollak
> > <[EMAIL PROTECTED]>wrote:
> >
> > > And we should freeze the lists after Boot is finished.  The permutation
> > > methods should throw exceptions post-boot
> >
> > > On Dec 9, 2008 11:39 AM, "Jorge Ortiz" <[EMAIL PROTECTED]> wrote:
> >
> > > Seems like prime opportunity for an abstraction...
> >
> > > Why not make them (*gasp*) mutable data structures with prepend/append
> > > methods?
> >
> > > --j
> >
> > > On Tue, Dec 9, 2008 at 1:35 PM, Marius <[EMAIL PROTECTED]>
> wrote: >
> > > > > Hi. > > Unfortunatel...
> >
>

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Lift" group.
To post to this group, send email to liftweb@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en
-~--~~~~--~~--~--~---



[Lift] Re: Why JPA?

2008-12-09 Thread Derek Chen-Becker
I think you misunderstand the lifecycle of a stateful snippet. A stateful
snippet has specific techniques to keep it resident (using this.link,
this.redirect, etc) so you have to be careful about how you use it or you
lose the instance. The HTTP session would be the most appropriate place for
a JPA EM that crosses request boundaries because it will *always* be
available to snippets (I had forgotten about the EXTENDED type, I've never
used it).

Another issue, orthogonal to how you keep the session around, is that when
you hold a session open you're also holding a transaction open unless you
use RESOURCE_LOCAL transactions (unmanaged JDBC connections, essentially).
That has implications on data visibility to other connections, how you
handle exceptions, etc.

Don't get me wrong, I think that there's a place for extended JPA EMs, I
just want to make sure you're aware of all of the tradeoffs so that you
don't get any nasty surprises. It's my opinion that for most use cases
opening a session for each request (and the merge/getReference that doing it
this way implies) is the best way to do it. JPA providers are usually pretty
intelligent about efficiently using database operations to keep things
coherent, so I don't think that "avoiding merge" is necessarily a worthwhile
goal in and of itself.

Cheers,

Derek

On Tue, Dec 9, 2008 at 6:39 AM, philip <[EMAIL PROTECTED]> wrote:

>
> Hi Derek,
>
> I think I found the solution to the problem I am thinking of.
> Its called JPA Extended Persistence Context. Its suggested that a
> extended persistence context be created which starts at some time and
> ends at some time and is stored in HttpSession. From the bits I read
> they said its no good to store in a Stateful Session Bean because the
> bean may be passivated and the context lost. Well we are not using
> stateful session bean so it doesn't matter, we can put it in the
> session or put it on some object that hands around like a session such
> as a ... in our case I believe a Snippet.
>
> So in the JPA demo, you would then open as
>  override def openEM () = {
>val em = factory.createEntityManager
> (PersistenceContextType.EXTENDED)
>em.getTransaction().begin()
>em
>  }
>
> So then I would suggest the em be stored in the snippet which is a
> stateful thing that hangs around.
> According to the docs, many transactions can happen on the em, until
> em.close() is called and therefore it is then flushed to the database.
> NORMALLY Extended persistence context is managed by the container,
> SEAM or EJB this is called container managed, but in our case we can
> do our own management. In EJB its something insane like this
> @Stateful
> @Remote(ShoppingCart.class)
> public class ShoppingCartBean implements ShoppingCart
> {
>   @PersistenceContext(type=PersistenceContextType.EXTENDED)
> EntityManager em;
> ...
> But we do it ourselves...
> Why do this? The benefit is that you can keep using the same JPA
> object references without doing a merge. So if you have a Employee
> object which is a JPA/Hibernate object, and you changed its data and
> you want to save it to the database, merge is not needed.
> Why is that good? Because merge normally re-loads an entity from the
> database at the merge call, then it overwrites the entity contents and
> you might loose data that was previously written by another user!
> (unless you used a version number). In our case without merge, then
> the entity that was originally used by the EM is still in use. It is
> not a detached entity. Also you can navigate lazy relationships from
> request to request, from an Employee to a Manager which is really good
> as you can just display a list of Employees, then when someone clicks
> on the manager link of the employee it will just be able to navigate
> as a object reference lazy loaded from DB.
> Without the extended persistence context then the entity would be
> called detached because the original persistence context of the entity
> has been closed.
>
> Now - I haven't actually tested this! but I feel reasonably convinced
> I'm right - please tell me I am wrong. I want to at least solve these
> problems before I can start on the larger project. It then makes sense
> for me to use JPA, I'll reverse engineer first from mysql then convert
> from Java to Scala and use the JPA example project as a starting
> point, I can do the project in waterfall steps.
>
> Thanks, Philip
>
> On Dec 8, 2:01 pm, "Derek Chen-Becker" <[EMAIL PROTECTED]> wrote:
> > I use request vars to pass these things around in my own code, so merging
> is
> > pretty trivial. For example:
> >
> > object employee extends RequestVar[Can[Employee]](Empty)
> >
> > def viewEmployee (xhtml : NodeSeq) : NodeSeq =
> > employee.map(Model.merge(_)).map({ empl =>
> >...
> >bind(...)
> >
> > }) openOr Text("Invalid Employee for View")
> >
> > Note the double map call. The first merges, the second actually does the
> > binding. If you preferred to load from the DB each time yo

[Lift] Re: LiftRules consolidation

2008-12-09 Thread Marius

I'm not sure if this is the case ... if we want context dependent
Snippets then probably using loc snippets is the right place

How about something like:

abstract class RulesSeq[T] {
  var rules : List[T] = Nil

  private def safe_?(f : => Any) {
doneBoot match {
  case false => f
  case _ => throw new IllegalStateException("Can not modify after
boot.");
}
  }

  def prependRule(r: T) {
safe_? {
  rules = r :: rules
}
  }

  def appendRule(r: T) {
safe_? {
  rules = rules ::: List(r)
}
  }
}

Br's,
marius

On Dec 9, 10:12 pm, "Jorge Ortiz" <[EMAIL PROTECTED]> wrote:
> Hm... I can think of situations where such mutations are useful after
> Boot (app/prependSnippet comes to mind). Maybe they can be made immutable
> (.toList) as necessary?
>
> --j
>
> On Tue, Dec 9, 2008 at 2:01 PM, David Pollak
> <[EMAIL PROTECTED]>wrote:
>
> > And we should freeze the lists after Boot is finished.  The permutation
> > methods should throw exceptions post-boot
>
> > On Dec 9, 2008 11:39 AM, "Jorge Ortiz" <[EMAIL PROTECTED]> wrote:
>
> > Seems like prime opportunity for an abstraction...
>
> > Why not make them (*gasp*) mutable data structures with prepend/append
> > methods?
>
> > --j
>
> > On Tue, Dec 9, 2008 at 1:35 PM, Marius <[EMAIL PROTECTED]> wrote: >
> > > > Hi. > > Unfortunatel...
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Lift" group.
To post to this group, send email to liftweb@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en
-~--~~~~--~~--~--~---



[Lift] Re: LiftRules consolidation

2008-12-09 Thread Jorge Ortiz
ListBuffer has constant time append and prepend methods, as well as constant
time toList. (Except after using toList, the next append/prepend will take
some work.)

--j

On Tue, Dec 9, 2008 at 2:09 PM, Marius <[EMAIL PROTECTED]> wrote:

>
> Sounds good. I'll look into it
>
>
> On Dec 9, 10:01 pm, "David Pollak" <[EMAIL PROTECTED]>
> wrote:
> > And we should freeze the lists after Boot is finished.  The permutation
> > methods should throw exceptions post-boot
> >
> > On Dec 9, 2008 11:39 AM, "Jorge Ortiz" <[EMAIL PROTECTED]> wrote:
> >
> > Seems like prime opportunity for an abstraction...
> >
> > Why not make them (*gasp*) mutable data structures with prepend/append
> > methods?
> >
> > --j
> >
> > On Tue, Dec 9, 2008 at 1:35 PM, Marius <[EMAIL PROTECTED]> wrote:
> > >
> > > Hi. > > Unfortunatel...
> >
>

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Lift" group.
To post to this group, send email to liftweb@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en
-~--~~~~--~~--~--~---



[Lift] Re: LiftRules consolidation

2008-12-09 Thread Jorge Ortiz
Hm... I can think of situations where such mutations are useful after
Boot (app/prependSnippet comes to mind). Maybe they can be made immutable
(.toList) as necessary?

--j

On Tue, Dec 9, 2008 at 2:01 PM, David Pollak
<[EMAIL PROTECTED]>wrote:

> And we should freeze the lists after Boot is finished.  The permutation
> methods should throw exceptions post-boot
>
> On Dec 9, 2008 11:39 AM, "Jorge Ortiz" <[EMAIL PROTECTED]> wrote:
>
> Seems like prime opportunity for an abstraction...
>
> Why not make them (*gasp*) mutable data structures with prepend/append
> methods?
>
> --j
>
> On Tue, Dec 9, 2008 at 1:35 PM, Marius <[EMAIL PROTECTED]> wrote: >
> > > Hi. > > Unfortunatel...
>
>
> >
>

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Lift" group.
To post to this group, send email to liftweb@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en
-~--~~~~--~~--~--~---



[Lift] Re: LiftRules consolidation

2008-12-09 Thread Marius

Sounds good. I'll look into it


On Dec 9, 10:01 pm, "David Pollak" <[EMAIL PROTECTED]>
wrote:
> And we should freeze the lists after Boot is finished.  The permutation
> methods should throw exceptions post-boot
>
> On Dec 9, 2008 11:39 AM, "Jorge Ortiz" <[EMAIL PROTECTED]> wrote:
>
> Seems like prime opportunity for an abstraction...
>
> Why not make them (*gasp*) mutable data structures with prepend/append
> methods?
>
> --j
>
> On Tue, Dec 9, 2008 at 1:35 PM, Marius <[EMAIL PROTECTED]> wrote: > >
> > Hi. > > Unfortunatel...
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Lift" group.
To post to this group, send email to liftweb@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en
-~--~~~~--~~--~--~---



[Lift] Re: LiftRules consolidation

2008-12-09 Thread David Pollak
And we should freeze the lists after Boot is finished.  The permutation
methods should throw exceptions post-boot

On Dec 9, 2008 11:39 AM, "Jorge Ortiz" <[EMAIL PROTECTED]> wrote:

Seems like prime opportunity for an abstraction...

Why not make them (*gasp*) mutable data structures with prepend/append
methods?

--j

On Tue, Dec 9, 2008 at 1:35 PM, Marius <[EMAIL PROTECTED]> wrote: > >
> Hi. > > Unfortunatel...

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Lift" group.
To post to this group, send email to liftweb@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en
-~--~~~~--~~--~--~---



[Lift] Re: LiftRules consolidation

2008-12-09 Thread Jorge Ortiz
Seems like prime opportunity for an abstraction...

Why not make them (*gasp*) mutable data structures with prepend/append
methods?

--j

On Tue, Dec 9, 2008 at 1:35 PM, Marius <[EMAIL PROTECTED]> wrote:

>
> Hi.
>
> Unfortunatelly only some vars that are essentially Lists of something
> are private and prepend/append functions are exposed.
>
> I proposed to do this for ALL List variables.
>
> Br's,
> Marius
> >
>

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Lift" group.
To post to this group, send email to liftweb@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en
-~--~~~~--~~--~--~---



[Lift] LiftRules consolidation

2008-12-09 Thread Marius

Hi.

Unfortunatelly only some vars that are essentially Lists of something
are private and prepend/append functions are exposed.

I proposed to do this for ALL List variables.

Br's,
Marius
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Lift" group.
To post to this group, send email to liftweb@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en
-~--~~~~--~~--~--~---



[Lift] Re: a simple screencast for making a sample app

2008-12-09 Thread Dano

Matt,

This is great.  I am looking forward to your Netbeans screencast.

Thanks.


Dan

On Dec 8, 1:00 am, "Matt Harrington" <[EMAIL PROTECTED]> wrote:
> I made a little screencast about creating a sample
> "lift-archetype-basic" application.  I hadn't made a screencast
> before, and it was actually trickier than I thought it'd be.  It's
> challenging to read from a script and work at the terminal at the same
> time.
>
> It's mostly about installing Maven, and if you've ever built a sample
> Lift app you won't get anything out of it, but perhaps absolute
> beginners will find it helpful:
>
> http://www.vimeo.com/2461367
>
> I envision 3 parts, and started with part II.  Part I will be a brief
> overview of Lift & Scala, and Part III will be about NetBeans.
>
> ---Matt
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Lift" group.
To post to this group, send email to liftweb@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en
-~--~~~~--~~--~--~---



[Lift] Re: Why JPA?

2008-12-09 Thread philip

Hi Derek,

I think I found the solution to the problem I am thinking of.
Its called JPA Extended Persistence Context. Its suggested that a
extended persistence context be created which starts at some time and
ends at some time and is stored in HttpSession. From the bits I read
they said its no good to store in a Stateful Session Bean because the
bean may be passivated and the context lost. Well we are not using
stateful session bean so it doesn't matter, we can put it in the
session or put it on some object that hands around like a session such
as a ... in our case I believe a Snippet.

So in the JPA demo, you would then open as
  override def openEM () = {
val em = factory.createEntityManager
(PersistenceContextType.EXTENDED)
em.getTransaction().begin()
em
  }

So then I would suggest the em be stored in the snippet which is a
stateful thing that hangs around.
According to the docs, many transactions can happen on the em, until
em.close() is called and therefore it is then flushed to the database.
NORMALLY Extended persistence context is managed by the container,
SEAM or EJB this is called container managed, but in our case we can
do our own management. In EJB its something insane like this
@Stateful
@Remote(ShoppingCart.class)
public class ShoppingCartBean implements ShoppingCart
{
   @PersistenceContext(type=PersistenceContextType.EXTENDED)
EntityManager em;
...
But we do it ourselves...
Why do this? The benefit is that you can keep using the same JPA
object references without doing a merge. So if you have a Employee
object which is a JPA/Hibernate object, and you changed its data and
you want to save it to the database, merge is not needed.
Why is that good? Because merge normally re-loads an entity from the
database at the merge call, then it overwrites the entity contents and
you might loose data that was previously written by another user!
(unless you used a version number). In our case without merge, then
the entity that was originally used by the EM is still in use. It is
not a detached entity. Also you can navigate lazy relationships from
request to request, from an Employee to a Manager which is really good
as you can just display a list of Employees, then when someone clicks
on the manager link of the employee it will just be able to navigate
as a object reference lazy loaded from DB.
Without the extended persistence context then the entity would be
called detached because the original persistence context of the entity
has been closed.

Now - I haven't actually tested this! but I feel reasonably convinced
I'm right - please tell me I am wrong. I want to at least solve these
problems before I can start on the larger project. It then makes sense
for me to use JPA, I'll reverse engineer first from mysql then convert
from Java to Scala and use the JPA example project as a starting
point, I can do the project in waterfall steps.

Thanks, Philip

On Dec 8, 2:01 pm, "Derek Chen-Becker" <[EMAIL PROTECTED]> wrote:
> I use request vars to pass these things around in my own code, so merging is
> pretty trivial. For example:
>
> object employee extends RequestVar[Can[Employee]](Empty)
>
> def viewEmployee (xhtml : NodeSeq) : NodeSeq =
> employee.map(Model.merge(_)).map({ empl =>
>...
>bind(...)
>
> }) openOr Text("Invalid Employee for View")
>
> Note the double map call. The first merges, the second actually does the
> binding. If you preferred to load from the DB each time you could do
>
> def viewEmployee (xhtml : NodeSeq) : NodeSeq =
> employee.map(Model.getReference(classOf[Employee], _.id)).map({ empl =>
>
> instead. In either case this is simple enough that I haven't really bothered
> looking for any cleaner solution. One thing I'd note is that generally in
> Hibernate and JPA, keeping a session open across multiple web requests is
> frowned upon. I don't know enough about the guts of SEAM to know if they're
> really doing that, or using some magic to make it appear that they are. If I
> remember correctly, in SEAM your objects are injected and outjected by SEAM
> itself, so they could easily be intercepting things to make it kosher. In
> any case, using the EM this way is outside my experience so if things start
> going screwy I don't know how much I can help.
>
> Derek
>
> On Sun, Dec 7, 2008 at 8:44 AM, philip <[EMAIL PROTECTED]> wrote:
>
> > Hi Derek,
>
> > The problem I am thinking about is if you loaded for example, a list
> > of "Employees" your going to show in a table.
> > In your table you have a view button to view the employee, since you
> > used JPA to load the list in the first place but now since the EM is
> > finished from the first request and now we are on a second request
> > with a new EM instance. If we try to navigate the lazy loading
> > relationships, it won't work, it will throw a LazyLoadingException.
>
> > So what you do - is your merge the entity back and the load it back
> > from the database and then navigate the relationship.
> > But if the EM was a

[Lift] Re: Why JPA?

2008-12-09 Thread philip

Hi Derek,

I think I found the solution to the problem I am thinking of.
Its called JPA Extended Persistence Context. Its suggested that a
extended persistence context be created which starts at some time and
ends at some time and is stored in HttpSession. From the bits I read
they said its no good to store in a Stateful Session Bean because the
bean may be passivated and the context lost. Well we are not using
stateful session bean so it doesn't matter, we can put it in the
session or put it on some object that hands around like a session such
as a ... in our case I believe a Snippet.

So in the JPA demo, you would then open as
  override def openEM () = {
val em = factory.createEntityManager
(PersistenceContextType.EXTENDED)
em.getTransaction().begin()
em
  }

So then I would suggest the em be stored in the snippet which is a
stateful thing that hangs around.
According to the docs, many transactions can happen on the em, until
em.close() is called and therefore it is then flushed to the database.
NORMALLY Extended persistence context is managed by the container,
SEAM or EJB this is called container managed, but in our case we can
do our own management. In EJB its something insane like this
@Stateful
@Remote(ShoppingCart.class)
public class ShoppingCartBean implements ShoppingCart
{
   @PersistenceContext(type=PersistenceContextType.EXTENDED)
EntityManager em;
...
But we do it ourselves...
Why do this? The benefit is that you can keep using the same JPA
object references without doing a merge. So if you have a Employee
object which is a JPA/Hibernate object, and you changed its data and
you want to save it to the database, merge is not needed.
Why is that good? Because merge normally re-loads an entity from the
database at the merge call, then it overwrites the entity contents and
you might loose data that was previously written by another user!
(unless you used a version number). In our case without merge, then
the entity that was originally used by the EM is still in use. It is
not a detached entity. Also you can navigate lazy relationships from
request to request, from an Employee to a Manager which is really good
as you can just display a list of Employees, then when someone clicks
on the manager link of the employee it will just be able to navigate
as a object reference lazy loaded from DB.
Without the extended persistence context then the entity would be
called detached because the original persistence context of the entity
has been closed.

Now - I haven't actually tested this! but I feel reasonably convinced
I'm right - please tell me I am wrong. I want to at least solve these
problems before I can start on the larger project. It then makes sense
for me to use JPA, I'll reverse engineer first from mysql then convert
from Java to Scala and use the JPA example project as a starting
point, I can do the project in waterfall steps.

Thanks, Philip

On Dec 8, 2:01 pm, "Derek Chen-Becker" <[EMAIL PROTECTED]> wrote:
> I use request vars to pass these things around in my own code, so merging is
> pretty trivial. For example:
>
> object employee extends RequestVar[Can[Employee]](Empty)
>
> def viewEmployee (xhtml : NodeSeq) : NodeSeq =
> employee.map(Model.merge(_)).map({ empl =>
>...
>bind(...)
>
> }) openOr Text("Invalid Employee for View")
>
> Note the double map call. The first merges, the second actually does the
> binding. If you preferred to load from the DB each time you could do
>
> def viewEmployee (xhtml : NodeSeq) : NodeSeq =
> employee.map(Model.getReference(classOf[Employee], _.id)).map({ empl =>
>
> instead. In either case this is simple enough that I haven't really bothered
> looking for any cleaner solution. One thing I'd note is that generally in
> Hibernate and JPA, keeping a session open across multiple web requests is
> frowned upon. I don't know enough about the guts of SEAM to know if they're
> really doing that, or using some magic to make it appear that they are. If I
> remember correctly, in SEAM your objects are injected and outjected by SEAM
> itself, so they could easily be intercepting things to make it kosher. In
> any case, using the EM this way is outside my experience so if things start
> going screwy I don't know how much I can help.
>
> Derek
>
> On Sun, Dec 7, 2008 at 8:44 AM, philip <[EMAIL PROTECTED]> wrote:
>
> > Hi Derek,
>
> > The problem I am thinking about is if you loaded for example, a list
> > of "Employees" your going to show in a table.
> > In your table you have a view button to view the employee, since you
> > used JPA to load the list in the first place but now since the EM is
> > finished from the first request and now we are on a second request
> > with a new EM instance. If we try to navigate the lazy loading
> > relationships, it won't work, it will throw a LazyLoadingException.
>
> > So what you do - is your merge the entity back and the load it back
> > from the database and then navigate the relationship.
> > But if the EM was a