Main  /  Edit version 8  /  Edit version 9  /   /  Users Area

Difference "Applications Hierarchy" ver. 8 versus ver. 9

Content:

<!--toc-->
## General
The basic approach of mapping an URL to a member function of our class works well for small applications, but can become problematic for complex systems.
CppCMS allows you to create a hierarchy of applications that work as a single unit. You connect them by using the `url_mapper` and `url_dispatcher` classes.
Before you read this tutorial, please read [URL Dispatching and Mapping](/wikipp/en/page/cppcms_1x_tut_url_mapping) tutorial.
## Example
### Hierarchy
We will create a very simple example of an "educational" application, that consists of two sub-applications:
- myapp - main application
- numbers - display different numbers:
- all
- odd
- even
- prime
- letters - display different letters:
- all
- capital
- small
We will create 3 classes where `myapp` would be the topmost class in the hierarchy, and `numbers` and `letters` would be child applications.
### Sub-Applications
Let's define our sub-applications:
class numbers : public cppcms::application {
public:
The constructor:
numbers(cppcms::service &srv) : cppcms::application(srv)
{
dispatcher().assign("",&numbers::all,this);
mapper().assign("");
dispatcher().assign("/odd",&numbers::odd,this);
mapper().assign("odd","/odd");
dispatcher().assign("/even",&numbers::even,this);
mapper().assign("even","/even");
dispatcher().assign("/prime",&numbers::prime,this);
mapper().assign("prime","/prime");
}
Create default application URL - all, and connect 4 member functions `odd`, `even`, `prime` and `all` to it, such that:
void prime()
{
response().out() << "2,3,5,7,...";
}
void odd()
{
response().out() << "1,3,5,7,9,...";
}
void even()
{
response().out() << "2,4,6,8,10,...";
}
Now let's create our `all` member function that would
include links to different modules:
void all()
{
response().out()
<< "<a href='" << url("/") << "'>Top</a><br>"
<< "<a href='" << url("/letters")<< "'>Letters</a><br>"
<< "<a href='" << url(".") << "'>All Numbers</a><br>"
<< "<a href='" << url("odd") << "'>Odd Numbers</a><br>"
<< "<a href='" << url("even") << "'>Even Numbers</a><br>"
<< "<a href='" << url("prime") << "'>Prime Numbers</a><br>"
<< "1,2,3,4,5,6,7,8,9,10,...";
}
Note:
- `url("/")` - points to the default location of the topmost application. The `numbers` application does not need to know what that is.
- `url("/letters")` - points to the default location of the sub-application letters starting from the root.
- `url(".")` - points to the default handling for the current application.
- `url("odd")`, `url("even")`, `url("prime")` - point
to current application's different parts.
Now we create a similar class for `letters`
class letters : public cppcms::application {
public:
Constructor:
letters(cppcms::service &srv) : cppcms::application(srv)
{
dispatcher().assign("",&letters::all,this);
mapper().assign("");
dispatcher().assign("/capital",&letters::capital,this);
mapper().assign("capital","/capital");
dispatcher().assign("/small",&letters::small,this);
mapper().assign("small","/small");
}
Member functions:
void all()
{
response().out()
<< "<a href='" << url("/") << "'>Top</a><br>"
<< "<a href='" << url("/numbers")<< "'>Numbers</a><br>"
<< "<a href='" << url(".") << "'>All Letters</a><br>"
<< "<a href='" << url("capital") << "'>Capital Letters</a><br>"
<< "<a href='" << url("small") << "'>Small Letters</a><br>"
<< "Aa, Bb, Cc, Dd,...";
}
void capital()
{
response().out() << "A,B,C,D,...";
}
void small()
{
response().out() << "a,b,c,d,...";
}
### Main Application
Now lets create our topmost application:
class myapp: public cppcms::application {
public:
Constructor:
myapp(cppcms::service &srv) :
cppcms::application(srv)
{
attach( new numbers(srv),
"numbers", "/numbers{1}", // mapping
"/numbers(/(.*))?", 1); // dispatching
attach( new letters(srv),
"letters", "/letters{1}", // mapping
"/letters(/(.*))?", 1); // dispatching
dispatcher().assign("",&myapp::describe,this);
mapper().assign(""); // default URL
mapper().root("/myapp");
}
Note: we call `attach` member function with following parameters:
new numbers(srv)
New sub-application - we pass the ownership to the parent so we don't need to handle its lifetime on our own.
"numbers", "/numbers{1}"
Mapping - application named "numbers" is mapper according
the the patter "/numbers{1}" - such that each sub application's URL would replace the `{1}` placeholder.
Mapping - application named "numbers" is mapped according
the the pattern "/numbers{1}" - such that each sub application's URL would replace the `{1}` placeholder.
"/numbers(/(.*))?", 1)
The regular expression pattern for matching the sub-application. Note, unlike with member functions, exactly one sub-expression is expected - this captured subexpression is passed to child's main function for further dispatching.
The regular expression pattern for matching the sub-application. Note, unlike with member functions, exactly one sub-expression is expected - this captured subexpression is passed to the child's main function for further dispatching.
The same done for the `letters` and `myapp` own member functions.
The same is done for the `letters` and `myapp` member functions.
Now lets analyze how an HTTP request `GET /myapp/numbers/prime` is parsed.
1. Web server splits `/myapp/numbers/prime` to `/myapp` as `SCRIPT_NAME` and `/numbers/prime` as `PATH_INFO`
2. `myapp` matches `/numbers/prime` against `/numbers(/(.*))?` expression and extracts `/prime` as
subexpression that is passed to `numbers`'s main function.
3. `/prime` is matched against `/prime` expression and `numbers::prime` function is called.
Now lets show the final touch - the `describe` function of `myapp`:
void describe()
{
response().out()
<< "<a href='" << url("/numbers")<< "'>Numbers</a><br>"
<< "<a href='" << url("/letters")<< "'>Letters</a><br>"
<< "<a href='" << url("/numbers/odd")<< "'>Odd Numbers</a><br>";
}
The URL "/numbers" - relates to the default URL of "numbers" sub-application, same for `letters`. The "/numbers/odd` refer to "odd" mapping of "numbers" sub-application. Let's see how mapping is done in details.
1. A path `/numbers/odd` is split into "numbers" and "odd" tokens.
2. We search for "numbers" sub-application and find it.
3. In `numbers`'s sub-application mapper we search for "odd" mapping and find it.
4. We construct all backward:
- "odd" -> "/odd"
- "/numbers{1}" + "/odd" -> "/numbers/odd"
- Root "/myapp" + "/numbers/odd" -> "/myapp/numbers/odd"
So we fully connect our main applications and sub-applications using some generic names.
## Running
Finally let's add main function
int main(int argc,char ** argv)
{
try {
cppcms::service app(argc,argv);
app.applications_pool().mount(cppcms::applications_factory<myapp>());
app.run();
}
catch(std::exception const &e) {
std::cerr<<e.what()<<std::endl;
}
}
Create configuration file:
{
"service" : {
"api" : "http",
"port" : 8080
},
"http" : {
"script" : "/myapp"
}
}
Build and run as:
./myapp -c config.js
And hit the URL: <http://localhost:8080/myapp>

About

CppCMS is a web development framework for performance demanding applications.

Support This Project

SourceForge.net Logo

Поддержать проект

CppCMS needs You


Navigation

Main Page


Valid CSS | Valid XHTML 1.0