diff --git a/PageCompiler/File2Page/src/File2Page.cpp b/PageCompiler/File2Page/src/File2Page.cpp index b5ffc4e8b..b323f1804 100644 --- a/PageCompiler/File2Page/src/File2Page.cpp +++ b/PageCompiler/File2Page/src/File2Page.cpp @@ -1,7 +1,7 @@ // // File2Page.cpp // -// $Id: //poco/1.4/PageCompiler/File2Page/src/File2Page.cpp#3 $ +// $Id: //poco/1.4/PageCompiler/File2Page/src/File2Page.cpp#4 $ // // An application that creates a Page Compiler source file from an // ordinary file. @@ -88,46 +88,53 @@ protected: Application::defineOptions(options); options.addOption( - Option("help", "h", "display help information on command line arguments") + Option("help", "h", "Display help information on command line arguments.") .required(false) .repeatable(false) .callback(OptionCallback(this, &File2PageApp::handleHelp))); options.addOption( - Option("contentType", "t", "specify a content type") + Option("contentType", "t", "Specify a content type.") .required(false) .repeatable(false) .argument("MIME-Type") .callback(OptionCallback(this, &File2PageApp::handleContentType))); options.addOption( - Option("contentLanguage", "l", "specify a content language") + Option("contentLanguage", "l", "Specify a content language.") .required(false) .repeatable(false) .argument("language") .callback(OptionCallback(this, &File2PageApp::handleContentLang))); options.addOption( - Option("class", "c", "specify the handler class name") + Option("class", "c", "Specify the handler class name.") .required(false) .repeatable(false) .argument("class-name") .callback(OptionCallback(this, &File2PageApp::handleClassName))); options.addOption( - Option("namespace", "n", "specify the handler class namespace name") + Option("namespace", "n", "Specify the handler class namespace name.") .required(false) .repeatable(false) .argument("namespace-name") .callback(OptionCallback(this, &File2PageApp::handleNamespace))); options.addOption( - Option("output", "o", "specify the output file name") + Option("output", "o", "Specify the output file name.") .required(false) .repeatable(false) .argument("path") .callback(OptionCallback(this, &File2PageApp::handleOutput))); -} + + options.addOption( + Option("path", "p", "Specify the server path of the file.") + .required(false) + .repeatable(false) + .argument("path") + .callback(OptionCallback(this, &File2PageApp::handlePath))); + } void handleHelp(const std::string& name, const std::string& value) { @@ -161,12 +168,18 @@ protected: _output = value; } + void handlePath(const std::string& name, const std::string& value) + { + _path = value; + } + void displayHelp() { HelpFormatter helpFormatter(options()); helpFormatter.setCommand(commandName()); helpFormatter.setUsage("OPTIONS"); helpFormatter.setHeader("Create a PageCompiler source file from a binary file."); + helpFormatter.setIndent(8); helpFormatter.format(std::cout); } @@ -200,8 +213,12 @@ protected: } ostr << " form=\"false\"\n" << " namespace=\"" << _namespace << "\"\n" - << " class=\"" << _clazz << "\"\n" - << " precondition=\"checkModified(request)\"%><%@" + << " class=\"" << _clazz << "\"\n"; + if (!_path.empty()) + { + ostr << " path=\"" << _path << "\"\n"; + } + ostr << " precondition=\"checkModified(request)\"%><%@" << " impl include=\"Poco/DateTime.h\"\n" << " include=\"Poco/DateTimeParser.h\"\n" << " include=\"Poco/DateTimeFormatter.h\"\n" @@ -292,6 +309,7 @@ private: std::string _clazz; std::string _namespace; std::string _output; + std::string _path; }; diff --git a/PageCompiler/doc/PageCompilerUserGuide.page b/PageCompiler/doc/PageCompilerUserGuide.page index 0fc35d2e8..12b42a908 100644 --- a/PageCompiler/doc/PageCompilerUserGuide.page +++ b/PageCompiler/doc/PageCompilerUserGuide.page @@ -245,6 +245,28 @@ Allows you to specify whether the response is sent using chunked transfer encodi Defaults to <[true]>. Set the value to <[false]> to disable chunked transfer encoding. +!compressed + +Enables or disables response body compression. If set to <[true]>, and the client supports +the "gzip" content encoding (indicated by the "Accept-Encoding" header), +the response body will be compressed using the "gzip" format and the +"Content-Encoding" header will be set accordingly. +Defaults to <[false]>. Cannot be enabled together with response buffering. + +!compressionLevel + +Specify the compression level, if response body compression is enabled. +Valid values are 1 (fastest) to 9 (best compression). Defaults to 1. + +!buffered + +Enables or disables response buffering. Response buffering is disabled by default. +Set to <[true]> to enable buffering, or to <[false]> to disable it. +If response buffering is enabled, everything written to the response stream +is actually written to a string stream (<[std::ostringstream]>). +Sending of the HTTP response back to the client is deferred to +when the page is complete. + !session (OSP only) For use with the POCO Open Service Platform only. @@ -273,15 +295,6 @@ a new session will be created if the request does not contain a (valid) session If set to <[false]> and there is no existing session that matches the session cookie. the <[session]> variable will be null. -!buffered - -Enables or disables response buffering. Response buffering is disabled by default. -Set to <[true]> to enable buffering, or to <[false]> to disable it. -If response buffering is enabled, everything written to the response stream -is actually written to a string stream (<[std::ostringstream]>). -Sending of the HTTP response back to the client is deferred to -when the page is complete. - !precondition Allows to specify a C++ boolean expression which will be evaluated before processing @@ -295,6 +308,17 @@ Example: <%@ page precondition="checkCredentials(request, response)" %> ---- +!path + +Specify a server path for the page. If specified, the generated handler class +will contain a public static <[const std::string]> member variable named <[PATH]> +containing the specified path. + +Example: + <%@ page path="/index.html" %> +---- + + !!Implicit Objects The following objects are available in the handler code. diff --git a/PageCompiler/src/CodeWriter.cpp b/PageCompiler/src/CodeWriter.cpp index 54e3f32c3..706fe8ab9 100644 --- a/PageCompiler/src/CodeWriter.cpp +++ b/PageCompiler/src/CodeWriter.cpp @@ -1,7 +1,7 @@ // // CodeWriter.cpp // -// $Id: //poco/1.4/PageCompiler/src/CodeWriter.cpp#2 $ +// $Id: //poco/1.4/PageCompiler/src/CodeWriter.cpp#3 $ // // Copyright (c) 2008, Applied Informatics Software Engineering GmbH. // and Contributors. @@ -34,6 +34,7 @@ #include "Page.h" #include "Poco/Path.h" #include "Poco/StringTokenizer.h" +#include "Poco/String.h" using Poco::Path; @@ -76,6 +77,10 @@ void CodeWriter::writeImpl(std::ostream& ostr, const std::string& headerFileName { ostr << "#include \"" << headerFileName << "\"\n"; writeImplIncludes(ostr); + if (_page.getBool("page.compressed", false)) + { + ostr << "#include \"Poco/DeflatingStream.h\"\n"; + } if (_page.getBool("page.buffered", false)) { ostr << "#include \"Poco/StreamCopier.h\"\n"; @@ -90,6 +95,13 @@ void CodeWriter::writeImpl(std::ostream& ostr, const std::string& headerFileName } beginNamespace(ostr); + + std::string path = _page.get("page.path", ""); + if (!path.empty()) + { + ostr << "\tconst std::string " << _class << "::PATH(\"" << path << "\");\n\n\n"; + } + writeConstructor(ostr); writeHandler(ostr); writeFactory(ostr); @@ -132,7 +144,9 @@ void CodeWriter::beginGuard(std::ostream& ostr, const std::string& headerFileNam { Path p(headerFileName); std::string guard(p.getBaseName()); + Poco::translateInPlace(guard, ".-", "__"); guard += "_INCLUDED"; + ostr << "#ifndef " << guard << "\n"; ostr << "#define " << guard << "\n"; ostr << "\n\n"; @@ -143,6 +157,7 @@ void CodeWriter::endGuard(std::ostream& ostr, const std::string& headerFileName) { Path p(headerFileName); std::string guard(p.getBaseName()); + Poco::translateInPlace(guard, ".-", "__"); guard += "_INCLUDED"; ostr << "\n\n"; ostr << "#endif // " << guard << "\n"; @@ -164,6 +179,13 @@ void CodeWriter::handlerClass(std::ostream& ostr, const std::string& base, const } ostr << "\tvoid handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response);\n"; writeHandlerMembers(ostr); + + std::string path = _page.get("page.path", ""); + if (!path.empty()) + { + ostr << "\n\tstatic const std::string PATH;\n"; + } + ostr << "};\n"; } @@ -313,7 +335,10 @@ void CodeWriter::writeResponse(std::ostream& ostr) std::string contentLang(_page.get("page.contentLanguage", "")); bool buffered(_page.getBool("page.buffered", false)); bool chunked(_page.getBool("page.chunked", !buffered)); - + bool compressed(_page.getBool("page.compressed", false)); + if (buffered) compressed = false; + if (compressed) chunked = true; + if (chunked) { ostr << "\tresponse.setChunkedTransferEncoding(true);\n"; @@ -325,6 +350,11 @@ void CodeWriter::writeResponse(std::ostream& ostr) ostr << "\tif (request.has(\"Accept-Language\"))\n" << "\t\tresponse.set(\"Content-Language\", \"" << contentLang << "\");\n"; } + if (compressed) + { + ostr << "\tbool _compressResponse(request.hasToken(\"Accept-Encoding\", \"gzip\"));\n" + << "\tif (_compressResponse) response.set(\"Content-Encoding\", \"gzip\");\n"; + } ostr << "\n"; } @@ -333,6 +363,10 @@ void CodeWriter::writeContent(std::ostream& ostr) { bool buffered(_page.getBool("page.buffered", false)); bool chunked(_page.getBool("page.chunked", !buffered)); + bool compressed(_page.getBool("page.compressed", false)); + int compressionLevel(_page.getInt("page.compressionLevel", 1)); + if (buffered) compressed = false; + if (compressed) chunked = true; if (buffered) { @@ -344,6 +378,14 @@ void CodeWriter::writeContent(std::ostream& ostr) } ostr << "\tPoco::StreamCopier::copyStream(responseStream, response.send());\n"; } + else if (compressed) + { + ostr << "\tstd::ostream& _responseStream = response.send();\n" + << "\tPoco::DeflatingOutputStream _gzipStream(_responseStream, Poco::DeflatingStreamBuf::STREAM_GZIP, " << compressionLevel << ");\n" + << "\tstd::ostream& responseStream = _compressResponse ? _gzipStream : _responseStream;\n"; + ostr << _page.handler().str(); + ostr << "\tif (_compressResponse) _gzipStream.close();\n"; + } else { ostr << "\tstd::ostream& responseStream = response.send();\n"; diff --git a/PageCompiler/src/OSPCodeWriter.cpp b/PageCompiler/src/OSPCodeWriter.cpp index cb4240a60..9fcd77f77 100644 --- a/PageCompiler/src/OSPCodeWriter.cpp +++ b/PageCompiler/src/OSPCodeWriter.cpp @@ -1,7 +1,7 @@ // // OSPCodeWriter.cpp // -// $Id: //poco/1.4/PageCompiler/src/OSPCodeWriter.cpp#2 $ +// $Id: //poco/1.4/PageCompiler/src/OSPCodeWriter.cpp#3 $ // // Copyright (c) 2008, Applied Informatics Software Engineering GmbH. // and Contributors. @@ -64,15 +64,19 @@ void OSPCodeWriter::writeHandlerClass(std::ostream& ostr) void OSPCodeWriter::writeHandlerMembers(std::ostream& ostr) { - ostr << "\n"; - ostr << "protected:\n"; - ostr << "\tPoco::OSP::BundleContext::Ptr context() const\n"; - ostr << "\t{\n"; - ostr << "\t\treturn _pContext;\n"; - ostr << "\t}\n"; - ostr << "\n"; - ostr << "private:\n"; - ostr << "\tPoco::OSP::BundleContext::Ptr _pContext;\n"; + std::string base(page().get("page.baseClass", "")); + if (base.empty()) + { + ostr << "\n"; + ostr << "protected:\n"; + ostr << "\tPoco::OSP::BundleContext::Ptr context() const\n"; + ostr << "\t{\n"; + ostr << "\t\treturn _pContext;\n"; + ostr << "\t}\n"; + ostr << "\n"; + ostr << "private:\n"; + ostr << "\tPoco::OSP::BundleContext::Ptr _pContext;\n"; + } } @@ -97,9 +101,16 @@ void OSPCodeWriter::writeImplIncludes(std::ostream& ostr) void OSPCodeWriter::writeConstructor(std::ostream& ostr) { - std::string base(page().get("page.baseClass", "Poco::Net::HTTPRequestHandler")); + std::string base(page().get("page.baseClass", "")); ostr << clazz() << "::" << clazz() << "(Poco::OSP::BundleContext::Ptr pContext):\n"; - ostr << "\t_pContext(pContext)\n"; + if (base.empty()) + { + ostr << "\t_pContext(pContext)\n"; + } + else + { + ostr << "\t" << base << "(pContext)\n"; + } ostr << "{\n}\n"; ostr << "\n\n"; } diff --git a/PageCompiler/src/Page.cpp b/PageCompiler/src/Page.cpp index 87b66fdca..01d3d82d8 100644 --- a/PageCompiler/src/Page.cpp +++ b/PageCompiler/src/Page.cpp @@ -1,7 +1,7 @@ // // Page.cpp // -// $Id: //poco/1.4/PageCompiler/src/Page.cpp#1 $ +// $Id: //poco/1.4/PageCompiler/src/Page.cpp#2 $ // // Copyright (c) 2008, Applied Informatics Software Engineering GmbH. // and Contributors. @@ -32,6 +32,7 @@ #include "Page.h" #include "Poco/String.h" +#include "Poco/NumberParser.h" Page::Page() @@ -55,3 +56,13 @@ bool Page::getBool(const std::string& property, bool deflt) const } else return deflt; } + + +int Page::getInt(const std::string& property, int deflt) const +{ + if (has(property)) + { + return Poco::NumberParser::parse(get(property)); + } + else return deflt; +} diff --git a/PageCompiler/src/Page.h b/PageCompiler/src/Page.h index ce673f059..1d966cedb 100644 --- a/PageCompiler/src/Page.h +++ b/PageCompiler/src/Page.h @@ -1,7 +1,7 @@ // // Page.h // -// $Id: //poco/1.4/PageCompiler/src/Page.h#1 $ +// $Id: //poco/1.4/PageCompiler/src/Page.h#2 $ // // Copyright (c) 2008, Applied Informatics Software Engineering GmbH. // and Contributors. @@ -84,6 +84,9 @@ public: /// /// Otherwise, the return value will be false. + int getInt(const std::string& property, int deflt = 0) const; + /// Returns the integer value of the given property. + private: Page(const Page&); Page& operator = (const Page&); diff --git a/PageCompiler/src/PageCompiler.cpp b/PageCompiler/src/PageCompiler.cpp index 47a8ff387..d14e108a5 100644 --- a/PageCompiler/src/PageCompiler.cpp +++ b/PageCompiler/src/PageCompiler.cpp @@ -1,7 +1,7 @@ // // PageCompiler.cpp // -// $Id: //poco/1.4/PageCompiler/src/PageCompiler.cpp#3 $ +// $Id: //poco/1.4/PageCompiler/src/PageCompiler.cpp#4 $ // // A compiler that compiler HTML pages containing JSP directives into C++ classes. // @@ -139,6 +139,13 @@ protected: .argument("") .callback(OptionCallback(this, &CompilerApp::handleHeaderPrefix))); + options.addOption( + Option("base-file-name", "b", "Use instead of the class name for the output file name.") + .required(false) + .repeatable(false) + .argument("") + .callback(OptionCallback(this, &CompilerApp::handleBase))); + options.addOption( Option("osp", "O", "Add factory class definition and implementation for use with the Open Service Platform.") .required(false) @@ -191,6 +198,11 @@ protected: _headerPrefix += '/'; } + void handleBase(const std::string& name, const std::string& value) + { + _base = value; + } + void handleOSP(const std::string& name, const std::string& value) { _generateOSPCode = true; @@ -205,7 +217,7 @@ protected: { _emitLineDirectives = false; } - + void displayHelp() { HelpFormatter helpFormatter(options()); @@ -255,19 +267,32 @@ protected: { compile(*it); } - + return Application::EXIT_OK; } - void compile(const std::string& path) + void parse(const std::string& path, Page& page, std::string& clazz) { - Page page; - FileInputStream srcStream(path); PageReader pageReader(page, path); pageReader.emitLineDirectives(_emitLineDirectives); pageReader.parse(srcStream); + Path p(path); + + if (page.has("page.class")) + { + clazz = page.get("page.class"); + } + else + { + clazz = p.getBaseName() + "Handler"; + clazz[0] = Poco::Ascii::toUpper(clazz[0]); + } + } + + void write(const std::string& path, const Page& page, const std::string& clazz) + { Path p(path); config().setString("inputFileName", p.getFileName()); config().setString("inputFilePath", p.toString()); @@ -275,17 +300,10 @@ protected: DateTime now; config().setString("dateTime", DateTimeFormatter::format(now, DateTimeFormat::SORTABLE_FORMAT)); - std::string clazz; if (page.has("page.class")) { - clazz = page.get("page.class"); p.setBaseName(clazz); } - else - { - clazz = p.getBaseName() + "Handler"; - clazz[0] = Poco::Ascii::toUpper(clazz[0]); - } std::auto_ptr pCodeWriter(createCodeWriter(page, clazz)); @@ -293,6 +311,12 @@ protected: { p = Path(_outputDir, p.getBaseName()); } + + if (!_base.empty()) + { + p.setBaseName(_base); + } + p.setExtension("cpp"); std::string implPath = p.toString(); std::string implFileName = p.getFileName(); @@ -319,6 +343,20 @@ protected: writeFileHeader(headerLEC); pCodeWriter->writeHeader(headerLEC, headerFileName); } + + void compile(const std::string& path) + { + Page page; + std::string clazz; + parse(path, page, clazz); + write(path, page, clazz); + + FileInputStream srcStream(path); + PageReader pageReader(page, path); + pageReader.emitLineDirectives(_emitLineDirectives); + pageReader.parse(srcStream); + + } void writeFileHeader(std::ostream& ostr) { @@ -348,6 +386,7 @@ private: std::string _outputDir; std::string _headerOutputDir; std::string _headerPrefix; + std::string _base; };