Switch branches/tags
Nothing to show
Find file History
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
..
Failed to load latest commit information.
coordinator
greeter
uploader
CHANGELOG.md
README.adoc

README.adoc

standard environment examples

The GAE standard environment supports two kinds of web application:

  • Standard, Java Servlet applications. This kind of application consists of a single WAR directory.

  • Services-based applications. This kind of application is composed of one or more WAR directories, each of which acts as an independent service. See Configuration Files for an explanation of the structure of such applications.

boot-gae is designed to support both application styles from one code base. Services may be developed as standard, stand-alone servlet applications, and then integrated (as microservices) into a service-based application. Quasi-REPL responsiveness is supported in both cases.

With boot-gae, the programmer configures applications by writing a build.boot file and some edn files. The boot-gae system then generates the required WAR directories (and their contents) automatically.

The sample code is designed to demonstrate both cases. Two of the examples (greeter and uploader) can be developed as standard servlet apps. The microservices-app example assembles those two apps (as services) together with the coordinator service to create a service-based app.

  • greeter - a "hello world" app that can be used as either as a standard servlet app or a microservice in a service-based app

  • uploader - an app that can be used as either as a standard servlet app or a microservice in a service-based app. Demonstrates basic file upload functionality.

  • coordinator - an app designed to be used as the default service of a services-based app.

getting started

Important
you do not need a GAE account to experiment! The GAE SDK contains everything you need to run webapps on the local devserver; you only need a GAE account if you want to deploy to the production servers.
Note
Use of App Engine services such as the Datastore is beyond the scope of these examples. Their sole purpose is to demonstrate the use of boot-gae to get Clojure webapps up and running on GAE with a repl-like development environment.

Start by building and running greeter as a standard servlet app.

Once you’re comfortable working with it as a standard servlet app, build it as a service. As explained in the README, this involves a minor change in the build.boot file. You will not directly gae/run the service! Instead, you will build all the services required by your service-based app, and then assemble and run the app (see microservices-app for details).

how it works

The greeter README file contains a detailed explanation of how boot-gae works for building servlet apps and services; the README for microservices-app explains how boot-gae assembles a service-based app from independently developed services.

Note
See Configuration Files for the official explanation of the structure of services-based application.

Very briefly, the most obvious difference between a servlet app and a services app is in the root directory. For a servlet, the root directory (default: target/) will contain WEB-INF and any public resources (like index.html). This directory will be created and populated automatically by boot-gae. There are some other differences involving configuration files; for example, a service will have a <module> element in its appengine-web.xml file, and a servlet app will not. But boot-gae handles all the housekeeping transparently, so the programmer will typically not need to even know about this, so long as the build.boot and edn files are properly configured.

For example, if you build greeter as a servlet app, the target directory will have this structure:

target/
    WEB-INF/
    favicon.ico
    index.html
    scripts/
    styles/

By contrast, building a service will have the same structure, but with the insertion of an intermediate sub-directory with the service name. In the case of greeter as a service:

target/
    greetings/
        WEB-INF/
        favicon.ico
        index.html
        scripts/
        styles/

The reason for this is that in the assembled service application, each service must be included in a top-level directory of the application’s target directory. For example, with the microservices-app example we have (truncated):

target/
    META-INF/
        ...
    default/
        ...
    greetings/
        WEB-INF/
        favicon.ico
        index.html
        scripts/
        styles/
    uploader/
        ...

Here default is actually the coordinator service, automatically renamed to make it the default service.

Warning
If you build as a servlet app, and then you want to build as a service, you need to delete the target directory first. gae/target will by default remove the target directory, but that is different in the two cases: for servlets it is target/; for a service named foo, it will be target/foo/. So building the service will delete target/foo/ but not target/, which leaves detritus from the servlet build in target/.

quasi-REPL

We don’t have a genuine REPL, but we do have reload-on-refresh, which is almost as good. You edit your Clojure code in the source tree, and your changes will be picked up when you refresh the web page.

for servlet apps

Just run the gae/monitor task in a separate terminal session. This is a convenience task that composes boot’s watch task and some other tasks, such that changes to the source tree are propagated to the appropriate place in the output dir. This is required by the security constraints of GAE, which prevent it from accessing anything outside of the web app root directory.

Behind the scenes, gae/build by default inserts a reloader filter in the generated app; this filter monitors the web app directories and reloads any changed namespaces.

Warning
When you are ready to deploy to production, you want to omit the reloader filter; use the -p flag on gae/build to do this. For details, see the boot-gae task documentation.

for services

If you have services that interact - for example, you might have a data-service that is called by a presentation-service - you might need to interactively develop them simultaneously. You can do this by running the service-based app and then running gae/monitor from the project root director of each service (not from the service app’s root directory).

From the service root dir, you will run gae/monitor as for servlet apps, but you will add a target task to the pipeline, using the -d flag to pass the directory path of the service-based app (here, microservices-app). For example, to interactively work with the greeter service from the microservices-app start by running the app:

microservices-app/ $ boot gae/run

Then, from the greeter project:

greeter/ $ boot gae/monitor -s

This uses the :app-dir entry of the :module map in the :gae map in build.boot to determine where to copy changed files.

troubleshooting

  • Note that services must by installed before they can be assembled into a micro-services app.

obsolete

To see the transient web.xml.edn and *.clj files used to configure the app, use the -k switch with build:

$ ./boot.sh gae/build -k gae/target gae/run

Note the use of gae/target rather than the built-in target task.

Note
Use of boot.sh is optional; you can also just run $ boot gae/build, etc. boot.sh uses the JVM options in ./.boot-jvm-options. See JVM Options.

To get a repl-like dev environment, open a second terminal and start a monitor:

$ boot gae/monitor

The gae/monitor task is a convenience wrapper that uses boot’s watch task to detect changes to the source tree, then propagates changes to the correct target dirctory.

Now you can edit the source, and your changes will be included when you reload the webpage. For example, go to http://localhost:8080/hello/bob. Then edit the greeting message in src/clj/greetings/hello.clj. Save your edit, then reload the page.

If you need to change the configuration, for example to add another servlet, you’ll have to restart the server. Rerun boot gae/build target to reconfigure the webapp, then run boot gae/run again.

Remember that with boot it is not enough to run gae/build; you than have to run the target task to put the results of the build on disk where appengine expects them.

troubleshooting

java.lang.NoClassDefFoundError: clojure/lang/Var

Check <build-root>/WEB-INF/lib to make sure your jars are there. You probably did not run gae/libs.

the code

See the README for https://github.com/migae/boot-gae for more info.