Modularize Lift Applications

174 views
Skip to first unread message

Torsten Uhlmann

unread,
Dec 10, 2012, 12:08:03 PM12/10/12
to lif...@googlegroups.com
Hi,

I'm developing some Lift base functionality (snippets, css, js, html templates) that I would like to use in a number of client projects.

What is the best way to externalize some of the functionality into a module?

Right now I'm trying to build it a Lift Module and move the css/js/html stuff into resources/toserve

In the module's init I allow access:

ResourceServer.allow {
    case _ => true
}

Still embed does not find the templates:

> [ERROR] net.liftweb.builtin.snippet.Embed - 'embed' snippet failed with message: FIXME trying to embed a template named '/templates-hidden/parts/footer', but the template not found. 

Is there a better way to externalize stuff and keep web artefacts under "webapp"?

Thanks,
Torsten.

David Pollak

unread,
Dec 10, 2012, 12:53:16 PM12/10/12
to lif...@googlegroups.com
Torsten,

I'd suggest explicitly registering the snippets in the external module in LiftRules.

This is orthogonal to the ResourceServer.

Thanks,

David

--
--
Lift, the simply functional web framework: http://liftweb.net
Code: http://github.com/lift
Discussion: http://groups.google.com/group/liftweb
Stuck? Help us help you: https://www.assembla.com/wiki/show/liftweb/Posting_example_code
 
 
 



--
Telegram, Simply Beautiful CMS https://telegr.am
Lift, the simply functional web framework http://liftweb.net


AGYNAMIX Torsten Uhlmann

unread,
Dec 10, 2012, 2:18:19 PM12/10/12
to lif...@googlegroups.com
Thanks, David, for your response!

I don't quiet understand the correlation, though. The problem was serving a template html file from the external module through the internal Embed snippet.

Would that problem still be solved?

When you talk about registering the snippets, do you mean publishing the class path (LiftRules.addToPackages("…")- I've done this) or individually registering each external snippet?

Thanks,
Torsten.

Austen Holmes

unread,
Dec 10, 2012, 4:08:21 PM12/10/12
to lif...@googlegroups.com
Where are your template files located?

If you do some digging in the code starting with the embed snippet, you'll see that eventually templates are loaded by LiftRules.findTemplate, which eventually gets down to LiftRules.getResource(...), which by default uses the container's resource loader to find an item.  Therefore, if you are able to access the file via the container, lift should be able to find it.  You may want to set a breakpoint in LiftRules.doWithResource (or a few other similar places if you follow the call chain) to see how the app finds it (pretty quickly from there you'll be getting into jetty/tomcat/etc calls, though.)

I've been working on getting certain items out of the container altogether lately (putting them in a configurable folder, for example a user's home directory) and had to do a bit of digging to see what needs to be overridden.  From what I can tell, all the parts to override are there, it's just finding the right ones and writing the correct methods to load the files.  Most things eventually go through LiftRules.getResource (a var...at times I've wished this was a factory - it would save some headache from having to override things in different ways for different types of content) in the end, though (also see, ResourceServer.findResourceInClasspath.)

I'm fairly new to lift, though, so there's still a lot of trial and error I go through.  I do like how most everything can be overridden in one way or another.  LiftRules.externalTemplateResolver being a factory has come in handy a few times.  I can swap it in and out based on the current execution context.  Sometimes I set it to empty to grab things explicitly from the web-inf directory.  Other times, I allow templates to be overridden and retrieved elsewhere.  Same with LiftRules.resourceForCurrentLoc.  To the core app, it's transparent, you just say Templates("path") and behind the scenes the application has some smarts to figure out where things should be located.  The cool thing is all of the embedded lift snippets work without any further hacks/tricks, since they seem to load things in a consistent manner.

-Austen

AGYNAMIX Torsten Uhlmann

unread,
Dec 10, 2012, 4:24:48 PM12/10/12
to lif...@googlegroups.com
Austen,

Thanks for your in depth reply.
I'll look through it tomorrow!

Torsten.

Von meinem iPhone gesendet

Torsten Uhlmann

unread,
Dec 17, 2012, 4:09:42 AM12/17/12
to lif...@googlegroups.com
I did choose a slightly different approach that allows me to edit the base module with the same ease as the specialized module.

For each module, I have a separate GIT repository, which is important for me as I use the base module several times for different applications.
I then create a GIT bundle module and import the base and the specialized module as GIT submodules.

The bundle module repository contains a "project/Build.scala" definition that defines a SBT multi project build with the bundle module as root, and the specialized module depending on the base module.

This setup allows me to edit the base module the same way I do with the specialized one and have changes picked up automatically. 
Also, a package-war merges the web app parts of both projects together into one.

I tried this setup first with Eclipse 3.8 and the multi project stuff seems to slow the Scala-Ide down considerable. After switching back to a fresh Eclipse 3.7 and the latest Scala-Ide all works fine.

Here's a nice tidbit of SBT knowledge I picked up along the way. I put a ".sbtrc" file in the root folder of my bundle project with the following line:

alias boot = ;reload ;project special_module ;iflast shell

This will make the specialized module the selected one after I start sbt.

Torsten.

Austen Holmes

unread,
Dec 17, 2012, 11:07:18 AM12/17/12
to lif...@googlegroups.com
Interesting.  I like how you have multiple git repositories and leverage the base-sub dependency using git modules.  I have something similar, but it doesn't look to be as flexible as your setup.

Another thing I've done is created traits for different things my applications may do.  By doing this, my code in Boot is pretty minimal, with most of the initialization pushed into the traits.  This lets me define patterns for how to configure things and allows apps to only include functionality from the base module they require.  Each trait has a few fields that define the configuration.

For example, here are some traits I have:
Application (base trait - sets up common patterns I use in my apps with regards to resource location, user account stuff, etc)
MySqlApplication
MailApplication (sets up the app to be able to send mail)
ImageUploadApplication - (provides an image upload server with pluggable processing)

This way, in my Boot, I can simply say
    object application extends Application with MySqlApplication with MailApplication {
      def connection = Props.get("db.url").openOrThrowException("No database connection URL defined.  Set property db.url")

      def username = Props.get("db.username").openOrThrowException("No database username defined.  Set property db.username")

      def password = Props.get("db.password").openOrThrowException("No database password defined.  Set property db.password")

      def packages = "com.myorganization.package" :: Nil

      def resourcePaths = "path/resource" :: Nil

      override def entries = List(
        ...
     
)

    }

   
application.init()


-Austen

Diego Medina

unread,
Dec 17, 2012, 11:28:34 AM12/17/12
to Lift
It's nice to see how you all use different patterns on your daily use of Lift!

Thanks fior sharing

Diego
Diego Medina
Lift/Scala Developer
di...@fmpwizard.com
http://www.fmpwizard.com
Reply all
Reply to author
Forward
0 new messages