///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
//
// See accompanying file COPYING.TXT file for licensing details.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef CPPCMS_APPLICATION_H
#define CPPCMS_APPLICATION_H
#include <cppcms/defs.h>
#include <booster/noncopyable.h>
#include <booster/hold_ptr.h>
#include <booster/atomic_counter.h>
#include <booster/intrusive_ptr.h>
#include <booster/shared_ptr.h>
#include <string>
namespace cppcms {
class application;
}
namespace booster {
void CPPCMS_API intrusive_ptr_add_ref(cppcms::application *p);
void CPPCMS_API intrusive_ptr_release(cppcms::application *p);
}
namespace cppcms {
class service;
class url_dispatcher;
class url_mapper;
class applications_pool;
class application_specific_pool;
class application;
class base_content;
class cache_interface;
class session_interface;
namespace http {
class request;
class response;
class context;
}
namespace json {
class value;
}
namespace filters {
class streamable;
}
///
/// \brief application class is the base class for all user created applications.
///
/// This class is the base for all user actions required for web page generation.
/// User application classes are created upon web page request and then cached in \a application_pool.
///
/// Applications can be bundled to hierarchies. You may add a sub application to hierarchy,
/// and they will always be connected with topmost application and their lifetime would be binded to them.
///
/// application class is reference counted and may be used with \a intrusive_ptr. But reference count
/// semantics is very different form an ordinary semantics for other classes derived from \a cppcms::refcounted.
///
/// 1. All hierarchy share the counter of the topmost application. Thus, when all bundle is counted
/// as a single unit allowing passing intrusive_ptr to itself to the central service safely.
/// When the topmost application is destroyed, it destroys all its children application classes.
/// 2. When reference count goes to 0, the application is not destroyed but rather recycled to the
/// application pool for future use.
/// 3. The above hold only for synchronous applications, asynchronous one are destroyed when all
/// reference count goes to 0.
///
/// There two ways to add sub-applications to hierarchy:
///
/// 1. Using member function family \a add, usually used with direct members of the parent class.
/// Such child are not destroyed explicitly.
/// 2. Using member function family \a attach. The ownership on the application is moved to the
/// parent class and it destroys an attached class with delete.
///
class CPPCMS_API application : public booster::noncopyable {
public:
///
/// Create a new application running on service \a srv, with a parent \a parent
///
application(cppcms::service &srv);
///
/// Destroys an application and all assigned application children.
///
virtual ~application();
///
/// Get the main service
///
cppcms::service &service();
///
/// Get global service settings
///
json::value const &settings();
///
/// Get a context of the single HTTP request/response.
///
http::context &context();
///
/// Get a HTTP request information class, same as context().request();
///
http::request &request();
///
/// Get a HTTP response information class, same as context().response();
///
http::response &response();
///
/// Get a dispatched class -- class that responsible on mapping between URLs and a member
/// functions of application class.
///
/// This member function is application specific and not
/// Connection specific.
///
url_dispatcher &dispatcher();
///
/// Get a url_mapper class -- class that responsible on mapping between real objects and
/// urls displayer on the page.
///
/// This member function is application specific and not
/// Connection specific.
///
url_mapper &mapper();
///
/// Get a cache_interface instance. Same as context().cache();
///
cache_interface &cache();
///
/// Get current session_interface instance. Same as context().session();
///
session_interface &session();
///
/// Render a template \a template_name of default skin using content \a content.
///
/// Side effect requires: output stream for response class, causes all updated session
/// data be saved and all headers be written. You can't change headers after calling this function.
///
void render(std::string template_name,base_content &content);
///
/// Render a template \a template_name of \a skin skin using content \a content.
///
/// Side effect requires: output stream for response class, causes all updated session
/// data be saved and all headers be written. You can't change headers after calling this function.
///
void render(std::string skin,std::string template_name,base_content &content);
///
/// Render a template \a template_name of default skin using content \a content to an output
/// stream \a out. Note: You are responsible to imbue suitable locale to the stream.
///
/// You should use context().locale() or service().generator() to create such locales.
///
void render(std::string template_name,std::ostream &out,base_content &content);
///
/// Render a template \a template_name of a skin \a skin using content \a content to an output
/// stream \a out. Note: You are responsible to imbue suitable locale to the stream.
///
/// You should use context().locale() or service().generator() to create such locales.
///
void render(std::string skin,std::string template_name,std::ostream &out,base_content &content);
///
/// Register an application \a app as child. Ownership of app is not transfered to parent, however
/// it would shared it's parent reference count.
///
void add(application &app);
///
/// Register an application \a app as child and mount it into url dispatched calling
/// dispatcher().mount(regex,app,part);
///
/// Ownership of app is not transfered to parent, however
/// it would shared it's parent reference count.
///
///
void add(application &app,std::string const ®ex,int part);
///
/// Register an application \a app as child and mount it into:
///
/// - url_dispatcher calling dispatcher().mount(regex,app,part);
/// - url_mapper calling mapper().mount(name,url,app);
///
/// Ownership of app is not transfered to parent, however
/// it would shared it's parent reference count.
///
///
void add(application &app,std::string const &name,std::string const &url,std::string const ®ex,int part);
///
/// Register an application \a app as child and mount it into
/// url_mapper calling mapper().mount(name,url,app);
///
/// Ownership of app is not transfered to parent, however
/// it would shared it's parent reference count.
///
///
void add(application &app,std::string const &name,std::string const &url);
///
/// Register an application \a app as child. Ownership of app is transfered to parent
///
void attach(application *app);
///
/// Register an application \a app as child and mount it into
/// url_dispatcher calling dispatcher().mount(regex,*app,part);
///
/// Ownership of app is transfered to parent.
///
void attach(application *app,std::string const ®ex,int part);
///
/// Register an application \a app as child and mount it into
/// url_mapper calling mapper().mount(name,url,*app);
///
/// Ownership of app is transfered to parent.
///
void attach(application *app,std::string const &name,std::string const &url);
///
/// Register an application \a app as child and mount it into:
///
/// - url_dispatcher calling dispatcher().mount(regex,*app,part);
/// - url_mapper calling mapper().mount(name,url,*app);
///
/// Ownership of app is transfered to parent.
///
void attach(application *app,std::string const &name,std::string const &url,std::string const ®ex,int part);
///
/// Get the parent of the application, if the application is the topmost class in hierarchy,
/// it would return \a this, So, if you want to check if the application has any parent test
/// app->parent()!=app;
///
application *parent();
///
/// Get the root application of the hierarchy. Note, if the application is the topmost one,
/// \a this pointer would be returned
///
application *root();
///
/// Request from an application give-up on ownership of the http::context class and give it
/// to the user control. Usually it is required for processing asynchronous requests.
///
/// Note: because application hierarchy shared same context, it affects all classes in it.
///
booster::shared_ptr<http::context> release_context();
///
/// Get reference counted pointer to the http::context
///
booster::shared_ptr<http::context> get_context();
///
/// Set context to the application. The application gets shared ownership on the context.
///
/// Note: because application hierarchy shared same context, it affects all classes in it.
///
void assign_context(booster::shared_ptr<http::context> conn);
///
/// Add context to applications such that context ownership isn't transferred
/// to the application
///
/// \ver{v1_2}
void add_context(http::context &conn);
///
/// Remove context added with add_context
///
/// \ver{v1_2}
void remove_context();
///
/// Returns true if current application was created as asynchronous application.
///
bool is_asynchronous();
///
/// Returns true if there is a context added or assigned to application
///
/// \ver{v1_2}
bool has_context();
///
/// Returns true if the application owns a context (that can be released for example)
///
/// \ver{v1_2}
bool owns_context();
///
/// This is main function of the application that is called when it is matched
/// according to the regular expression in the applications_pool class.
///
/// By default, main calls dispatcher().dispatch(url). And if the last fails, it
/// creates 404 Error page. This allows developers to create its own hooks for
/// reaction on incoming URL as, initialization and cleanup of general resources,
/// Custom 404 and error handlers etc.
///
virtual void main(std::string url);
///
/// This member function called when URL is dispatched to this application, it is
/// useful when member functions of applications are called, by default does nothing
///
virtual void init();
///
/// This function is used for cleanup unused stuff, it should not throw
///
virtual void clear();
///
/// Translate a message in current locale for given \a message in \a context
///
std::string translate(char const *context,char const *message);
///
/// Translate a message in current locale for given \a message
///
std::string translate(char const *message);
///
/// Translate a message in current locale for given \a single and \a plural form for number \a n in \a context.
///
std::string translate(char const *context,char const *single,char const *plural,int n);
///
/// Translate a message in current locale for given \a single and \a plural form for number \a n
///
std::string translate(char const *single,char const *plural,int n);
///
/// Map url-key \a key to actual URL, without parameters
///
/// Effectively it calls mapper().map(...)
///
std::string url(std::string const &key);
///
/// Map url-key \a key to actual URL, with parameter p1
///
/// Effectively it calls mapper().map(...)
///
std::string url(std::string const &key,
filters::streamable const &p1);
///
/// Map url-key \a key to actual URL, with parameters p1, p2
///
/// Effectively it calls mapper().map(...)
///
std::string url(std::string const &key,
filters::streamable const &p1,
filters::streamable const &p2);
///
/// Map url-key \a key to actual URL, with parameters p1, p2, p3
///
/// Effectively it calls mapper().map(...)
///
std::string url(std::string const &key,
filters::streamable const &p1,
filters::streamable const &p2,
filters::streamable const &p3);
///
/// Map url-key \a key to actual URL, with parameters p1, p2, p3, p4
///
/// Effectively it calls mapper().map(...)
///
std::string url(std::string const &key,
filters::streamable const &p1,
filters::streamable const &p2,
filters::streamable const &p3,
filters::streamable const &p4);
///
/// Map url-key \a key to actual URL, with parameters p1, p2, p3, p4, p5
///
/// Effectively it calls mapper().map(...)
///
std::string url(std::string const &key,
filters::streamable const &p1,
filters::streamable const &p2,
filters::streamable const &p3,
filters::streamable const &p4,
filters::streamable const &p5);
///
/// Map url-key \a key to actual URL, with parameters p1, p2, p3, p4, p5, p6
///
/// Effectively it calls mapper().map(...)
///
std::string url(std::string const &key,
filters::streamable const &p1,
filters::streamable const &p2,
filters::streamable const &p3,
filters::streamable const &p4,
filters::streamable const &p5,
filters::streamable const &p6);
private:
void recycle();
void parent(application *parent);
booster::weak_ptr<application_specific_pool> get_pool();
void set_pool(booster::weak_ptr<application_specific_pool> pool);
struct _data; // future use
booster::hold_ptr<_data> d;
application *parent_;
application *root_;
booster::atomic_counter refs_;
friend class applications_pool;
friend class application_specific_pool;
friend void booster::intrusive_ptr_add_ref(application *p);
friend void booster::intrusive_ptr_release(application *p);
};
} // cppcms
#endif