Scaling API-first ā The story of a global engineering organization
Ā
POCO C++ Libraries Intro and Overview
1. POCO C++ Libraries
Intro & Overview
GĆ¼nter Obiltschnig
Founder, POCO C++ Libraries Project
Applied Informatics Software Engineering GmbH
guenter@pocoproject.org
2. "Without a good library, most
interesting tasks are hard to do in C++;
but given a good library, almost any
task can be made easy."
Bjarne Stroustrup
(designer and original implementor of C++)
3.
4. The POCO C++ Libraries are...
> a collection of C++ class libraries, similar in concept to the Java
Class Library, the .NET Framework or Apple's Cocoa;
> focused on "internet-age" network-centric applications;
> written in eļ¬cient, modern ANSI/ISO Standard C++ and based
on the C++ Standard Library/STL;
> highly portable and available on many diļ¬erent platforms;
> Open Source, licensed under the Boost Software License,
> and thus completely free for both commercial and non-
commercial use.
5. Zip NetSSL Tools & Utilities
Util Net Data
MySQL
SQLite
ODBC
XML Crypto
Foundation
Application
C++ and C Standard Libraries
POSIX, WIN32, other (RT)OS API
6. POCO Objectives and Mission
> POCO is a powerful, yet easy to use platform to build your
applications upon
> POCO allows you to build highly portable applications
(write once ā compile and run anywhere)
> POCO is modular and scalable from embedded to enterprise
applications (you only pay for what you use)
> POCO provides consistent, comprehensive and comprehensible
programming interfaces
> POCO is written in fast, eļ¬cient C++
7. Objectives and Mission (cont'd)
> POCO favors simplicity over complexity
("as simple as possible, but not simpler")
> POCO aims for consistency in design, coding style and
documentation
> POCO emphasizes source code quality, in terms of readability,
comprehensiveness, consistency, style and testability
> POCO aims to make C++ programming fun again
8. Guiding Principles
> Strong focus on code quality, style, consistency and code
readability āall code must satisfy our coding styleguide
(and it works ā we frequently get compliments on our code quality)
> Strong focus on tests (automated unit tests with high coverage)
> Favor pragmatic and elegant design over "solving all the worlds
problems" (if we can satisfy 95 % of all use cases with an elegant
solution, and the remaining 5 % would require an overly complex
design, we focus on the 95 %)
> Build on top of solid foundations ā use existing proven C libraries
(e.g., expat, zlib, PCRE, SQLite) where it makes sense
9. History & Milestones
06.2006
boost license, new website
08.2004 05.2006
project started > 1000 downloads/month
02.2005 01.2006 11.2006
first release on sourceforge release 1.0 first major commercial
user (> 100 devs)
03.2005 03.2006
first contributor release 1.1
applied informatics founded
10. History & Milestones 05.2012
joined wg21
> 5500 downloads/month
01.2007 12.2010 08.2012
> 2000 downloads/month release 1.4 work on 1.5/1.6
05.2007 01.2011
relese 1.3 > 5000 downloads/month
12.2008
bjarne mentions poco in interview
11. Windows Windows
XP/Vista/7/Server Embedded/Compact (CE)
OS X iOS
Linux Embedded Linux
Server/Desktop Mobile/Embedded
12. POCO ā Scalability Embedded
> POCO is well-suited for embedded systems running under
Embedded Linux, Windows Embedded CE or QNX.
> POCO-based applications (using the built-in web server) run on
75 MHz ARM9-based Linux systems (uClibc) with 8 MB RAM and
4 MB Flash (e.g. Digi Connect ME 9210).
> A typical POCO-based application using the
web server from the Net library has a statically
linked size of 2 MB and uses about 2 ā 3 MB of RAM.
> Typical mid-ranged embedded platforms (32 ā 64 MB RAM, 16 ā
64 MB Flash, 180 MHz ARM9) provide plenty of resources even for
more complex applications (using OSP and Remoting).
14. POCO and Applied Informatics
> Applied Informatics provides project infrastructure and leads the
open source project.
> Professional, commercial support and training.
> Additional C++ libraries and tools.
15. Device Management
Remoting OSP Universal
Plug and Play
Binary SOAP Standard Services
Devices & Services
Code Generator Bundle Creator SOAP, GENA
HTTPMU, SSDP
Fast Infoset Zeroconf
UPnP Core
POCO C++ Libraries
Application
(Foundation, XML, Crypto, Net, NetSSL, Data, Util, Zip)
C++ and C Standard Libraries
POSIX, WIN32, other (RT)OS API
Commercial Open Source Third party/customer-speciļ¬c
16. Roadmap
08.2012 11.2012 06.2013
release 1.4.4 release 1.6 release 2.0
production release production release c++11 alignment
bugfixes, minor new features based on 1.5 dev branch
09.2012 01.2013
release 1.5 release 1.4.5
development release bugfixes
new data library
major new features
18. http://pocoproject.org/download
> Source packages for Windows have CR-LF line endings and are in
Zip format.
> Source packages for other platforms have LF line endings and are
in .tar.gz format.
19. External Dependencies
> Basic Edition (only Foundation, XML, Util, Net) has no external
dependencies.
> Complete Edition needs third-party libraries:
> OpenSSL
(for Crypto and NetSSL)
> ODBC
(for Data/ODBC)
> MySQL Client
(for Data/MySQL)
20. External Dependencies: OpenSSL
> needed by Crypto and NetSSL libraries
> integrated in Mac OS X and most Linux distributions
> alternatively, build from source (http://openssl.org)
> Windows
> use installer from Shining Light Productions
http://www.slproweb.com/products/Win32OpenSSL.html
> or build from source
21. External Dependencies: ODBC
> needed by Data/ODBC
> part of the Windows SDK
> Mac OS X: includes iodbc
> Linux/other Unix platforms:
get unixodbc or iodbc.
22. External Dependencies: MySQL
> needed by Data/MySQL
> get from http://dev.mysql.com/downloads/
> or use Linux package
sudo apt-get install libmysqlclient-dev
23. Building on Windows
> Source code distribution includes Visual Studio solutions and
project ļ¬les for:
> Visual Studio .NET 2003
> Visual Studio 2005
> Visual Studio 2008 (32 and 64-bit, Windows CE)
> Visual Studio 2010/2012 (32 and 64-bit)
> Build Script buildwin.cmd for command-line batch builds
24. Building on Windows: Configurations
Build Results
debug release
static_md PocoFoundationmdd.lib PocoFoundationmd.lib
static_mt PocoFoundationmtd.lib PocoFoundationmt.lib
shared PocoFoundationd.dll PocoFoundation.dll
26. Building on Windows: Build Script
> buildwin.cmd builds all libraries, testsuites and (optionally)
samples
> arguments specify Visual Studio version, build conļ¬guration and
platform
> External Dependencies (OpenSSL, etc.):
> either add search paths to INCLUDE and LIB environment vars
> or edit buildwin.cmd and add search paths
27. Building on Windows: Build Script Examples
> build everything (Visual Studio 2008)
buildwin 90 build all both Win32 samples
> build 64-bit static libs, no samples (Visual Studio 2008)
buildwin 90 build static_mt both x64 nosamples
Important: run from Visual Studio 2008 x64 Cross Tools Command
Prompt
> show all options ā launch buildwin with no arguments
28. Building on Windows: Build Output
> Dynamic Link Libraries will be placed in:
%POCO_BASE%bin (32-bit)
%POCO_BASE%bin64 (64-bit)
%POCO_BASE%bin%PLATFORM_NAME% (Windows CE)
> Static and import libraries will be placed in:
%POCO_BASE%lib (32-bit)
%POCO_BASE%lib64 (64-bit)
%POCO_BASE%lib%PLATFORM_NAME% (Windows CE)
> Binaries go into:
bin
binstatic_md (statically linked, multithreaded DLL, new in 1.4)
binstatic_mt (statically linked, multithreaded, new in 1.4)
29. Building on Unix/Linux
> Unix/Linux platforms use a build system based on GNU Make
> can be used on Linux, Mac OS X, FreeBSD, QNX, Solaris, HP-UX,
etc. (also Cygwin)
> supports cross-builds for Embedded Linux
> supports automatic computation of dependencies
> can be used for custom projects
> requires GNU Make 3.80 or newer
> conļ¬gure script to simplify setup
31. Building on Unix/Linux: Customizing
> Don't build samples and testsuites:
./conļ¬gure --no-samples --no-tests
> Don't build a speciļ¬c library (Data/MySQL):
./conļ¬gure --omit=Data/MySQL
> Use a speciļ¬c build conļ¬guration (cross build):
./conļ¬gure --conļ¬g=iPhone
> Typical Embedded Linux build:
./conļ¬gure --conļ¬g=DigiEL --poquito --static --no-samples --no-tests
> Show all options:
./conļ¬gure --help
32. Building on Unix/Linux: Build Output
> Shared and static libraries will be placed in:
${POCO_BASE}/lib/${OSNAME}/${OSARCH}
> Examples:
${POCO_BASE}/Linux/i686
${POCO_BASE}/Linux/armv5tejl
${POCO_BASE}/Darwin/x86_64
> Binaries go into:
bin/${OSNAME}/${OSARCH}
bin/${OSNAME}/${OSARCH}/static (statically linked, new in 1.4)
> Code for diļ¬erent architectures can be built within same source tree
33. Building on Unix/Linux: Environment
> Set environment variable POCO_BASE:
export POCO_BASE=/ws/poco-1.4
cd $POCO_BASE/XML
make -s -j4
> Use a speciļ¬c build conļ¬guration:
export POCO_CONFIG=DigiEL
> Clean rebuild:
make clean
make -s -j4
38. XML Programming Interfaces
> POCO supports two standard interfaces for working with
(reading and writing) XML data:
> The Simple API for XML, Version 2
> The Document Object Model
> There's also Poco::Util::XMLConļ¬guration
for the lazy ones ;-)
39. The Simple API for XML (SAX)
> SAX was originally a Java-only API for reading XML data.
> The API has been developed by a group of volunteers, not by an
"oļ¬cial" standardization group.
> The current version of the API is 2.0.2 (since April 2004)
> POCO supports a C++ variant of the original Java API.
> For more information: http://www.saxproject.org
40. Event-driven Parsing
> SAX is an event-driven interface.
> The XML document is not loaded into memory as a whole for
parsing.
> Instead, the parser scans the XML document, and for every XML
construct (element, text, processing instruction, etc.) it ļ¬nds, calls
a certain member function of a handler object.
> SAX basically deļ¬nes the interfaces of these handler objects, as
well as the interface you use to start and conļ¬gure the parser.
45. SAX Parser Configuration
> XMLReader deļ¬nes the interface of the parser.
> Methods for registering handlers
(setContentHandler(), etc.)
> Methods for parser conļ¬guration:
> setFeature(), getFeature()
e.g. for enabling/disabling namespaces support
> setProperty(), getProperty()
e.g. for registering LexicalHandler, DeclHandler
47. The Document Object Model
> The Document Object Model is an API speciļ¬ed by the World
Wide Web Consortium (W3C)
> DOM uses a tree representation of the XML document
> The entire document has to be loaded into memory
> You can modify the XML document directly
48. <xml version="1.0">
<root>
<elem1>
some text
</elem1>
<elem2 attr1="val2"
attr2="val3"/>
</root>
Document
Element
Attr
Element Element
Attr
Text
49. EventTarget
Node
Document Element CharacterData ProcessingInstruction
Text Comment
CDATASection
50. Navigating the DOM
> Node has
> parentNode()
> ļ¬rstChild(), lastChild()
> nextSibling(), previousSibling()
> NodeIterator for document-order traversal:
nextNode(), previousNode()
> TreeWalker for arbitraty navigation:
parentNode(), ļ¬rstChild(), lastChild(), etc.
> NodeIterator and TreeWalker support node ļ¬ltering
51. Memory Management in the DOM
> DOM Nodes are reference counted.
> If you create a new node and add it to a document, the
document increments its reference count. So use an AutoPtr.
> You only get ownership of non-tree objects implementing the
NamedNodeMap and NodeList interface.
You have to release them (or use an AutoPtr).
> The document keeps ownership of nodes you remove from the
tree. These nodes end up in the document's AutoReleasePool.
53. Creating XML Documents
> You can create an XML document by:
> building a DOM document from scratch, or
> by using the XMLWriter class,
> or by generating the XML yourself.
> XMLWriter supports a SAX interface for generating XML data.
56. DOM and XPath
> The DOM parser oļ¬ers minimal XPath support for ļ¬nding
elements and attributes in DOM trees.
> Node* getNodeByPath(const XMLString& path) const
searches a node (element or attribute) based on a simpliļ¬ed
XPath expression:
> elem1/elem2/elem3 <root>
<elem1>
<elem2 attr1="value1">
> /elem1/elem2[1] <elem3>
</elem3>
>
</elem2>
/elem1/elem2[@attr1] <elem2 attr1="value2">
</elem2>
> //elem1/elem2[@attr1='value2']
</elem1>
</root>
59. The Socket Class
> Poco::Net::Socket is the root class of the sockets inheritance tree.
> It supports methods that can be used with some or all kinds of
sockets, like:
> select() and poll()
> setting and getting various socket options (timeouts, buļ¬er
sizes, reuse address ļ¬ag, etc.)
> getting the socket's local address and the peer's address
60. The StreamSocket Class
> Poco::Net::StreamSocket is used for creating a TCP connection to
a server.
> Use sendBytes() and receiveBytes() to send and receive data, or
use the Poco::Net::SocketStream class, which provides an I/O
streams interface to a StreamSocket.
62. The ServerSocket Class
> Poco::Net::ServerSocket is used to create a TCP server socket.
> It is pretty low level.
> For an actual server, consider using the TCPServer or the Reactor
framework.
64. The TCPServer Framework
> Poco::Net::TCPServer implements a multithreaded TCP server.
> The server uses a ServerSocket to accept incoming connections.
You must put the ServerSocket into listening mode before
passing it to the TCPServer.
> The server maintains a queue for incoming connections.
> A variable number of worker threads fetches connections from
the queue to process them. The number of worker threads is
adjusted automatically, depending on the number of
connections waiting in the queue.
65. The TCPServer Framework (cont'd)
> The number of connections in the queue can be limited to
prevent the server from being ļ¬ooded with requests. Incoming
connections that no longer ļ¬t into the queue are closed
immediately.
> TCPServer creates its own thread that accepts connections and
places them in the queue.
> TCPServer uses TCPServerConnection objects to handle a
connection. You must create your own subclass of
TCPServerConnection, as well as a factory for it. The factory
object is passed to the constructor of TCPServer.
66. The TCPServer Framework (cont'd)
> Your subclass of TCPServerConnection must override the run()
method. In the run() method, you handle the connection.
> When run() returns, the TCPServerConnection object will be
deleted, and the connection closed.
> A new TCPServerConnection will be created for every accepted
connection.
67. The HTTPServer Framework
> POCO contains a ready-to-use HTTP Server framework
> multithreaded
> HTTP 1.0/1.1
> authentication support
> cookie support
> HTTPS by using the NetSSL library
68. HTTPServer
> conļ¬gurable multi-threading
> maximum number of threads
> uses thread pool
> queue size for pending connections
> similar to TCPServer
> expects a HTTPRequestHandlerFactory which creates
HTTPRequestHandler based on the URI
69. HTTPRequestHandlerFactory
> manages all known HTTPRequestHandlers
> sole purpose is to decide which request handler will answer a
request
> can be used to check cookies, authentication info but this is
mostly done by the request handlers
70. Poco::UInt16 port = 9999;
HTTPServerParams::Ptr pParams = new HTTPServerParams;
pParams->setMaxQueued(100);
pParams->setMaxThreads(16);
ServerSocket svs(port);
HTTPServer srv(new MyRequestHandlerFactory, svs, pParams);
// start the HTTPServer
srv.start();
waitForTerminationRequest();
// Stop the HTTPServer
srv.stop();
71. #include "Poco/Net/HTTPRequestHandlerFactory.h"
#include "Poco/Net/HTTPServerRequest.h"
#include "RootHandler.h"
#include "DataHandler.h"
class MyRequestHandlerFactory: public Poco::Net::HTTPRequestHandlerFactory
{
public:
MyRequestHandlerFactory()
{
}
Poco::Net::HTTPRequestHandler* createRequestHandler(
const Poco::Net::HTTPServerRequest& request)
{
if (request.getURI() == "/")
return new RootHandler;
else
return new DataHandler;
}
};
72. HTTPServerRequest
> created by the server
> passed as parameter to the HTTPRequestHandler/-Factory
> contains URI
> cookies
> authentiļ¬cation information
> HTML form data
73. HTTPServerResponse
> created by the server but initialized by the request handler
> sets:
> cookies
> content type of the answer
response.setContentType("text/html");
> either (a) the length of the content or (b) chunked transfer
encoding
response.setContentLength(1024);
response.setChunkedTransferEncoding(true);
74. HTTPServerResponse (cont)
> set response type
response.setStatus[AndReason](
HTTPResponse::HTTP_OK); // default
response.setStatus[AndReason](
HTTPResponse::HTTP_UNAUTHORIZED)
> after response is fully conļ¬gured, send the header
std::ostream& out = response.send();
> if required, write data content to the returned stream
> send() must be invoked exactly once!
75. class RootHandler: public Poco::Net::HTTPRequestHandler
{
public:
void handleRequest(Poco::Net::HTTPServerRequest& request,
Poco::Net::HTTPServerResponse& response)
{
Application& app = Application::instance();
app.logger().information("Request from "
+ request.clientAddress().toString());
response.setChunkedTransferEncoding(true);
response.setContentType("text/html");
std::ostream& ostr = response.send();
ostr << "<html><head>"
"<title>HTTP Server powered by POCO C++ Libraries</title>"
"</head>";
ostr << "<body>";
...
ostr << "</body></html>";
};
76. Handling Cookies
> Support for handling cookies is provided by the
Poco::Net::HTTPCookie class, as well as by the
Poco::Net::HTTPRequest and Poco::Net::HTTPResponse classes.
// set cookie in response
Poco::Net::HTTPCookie cookie(ānameā, āPeterā);
cookie.setPath(ā/ā);
cookie.setMaxAge(3600); // 1 hour
response.addCookie(cookie);
// extract cookie from request
Poco::Net::NameValueCollection cookies;
request.getCookies(cookies);
Poco::Net::NameValueCollection::ConstIterator it = cookies.find(ānameā);
std::string userName;
if (it != cookies.end())
userName = it->second;
78. HTMLForm
> helper class to handle HTML form data
Poco::Net::HTMLForm form(request);
form[āentry1ā] == āsomedataā;
> to handle ļ¬le uploads (POST with attachments) you must
combine it with a Poco::Net::PartHandler
MyPartHandler myHandler;
Poco::Net::HTMLForm form(request, request.stream(), myHandler);
79. #include āPoco/Net/PartHandler.hā
#include āPoco/Net/MessageHeader.hā
class MyPartHandler: public Poco::Net::PartHandler
{
public:
void handlePart(const Poco::Net::MessageHeader& header, std::istream& stream)
{
_disp = header["Content-Disposition"];
_type = header["Content-Type"];
// read from stream and do something with it
}
private:
std::string _disp;
std::string _type;
};
80. HTTP Client
> Poco::Net::HTTPClientSession
> allows you set GET/POST
> authentication information
> proxy support
> Poco::Net::HTTPStreamFactory and Poco::StreamCopier
if you only want to download something
82. PageCompiler
> Allows to write HTML (or other) ļ¬les with embedded C++ code.
(similar to PHP, JSP, ASP, etc.)
> Compiles pages into header and implementation ļ¬le containing
a Poco::Net::HTTPRequestHandler subclass.
> Makes it a lot easier to implement web servers.
84. URIStreamOpener
> Poco::URIStreamOpener is used to create and open input streams
for resources identiļ¬ed by URIs.
> #include "Poco/URIStreamOpener.h"
> For every URI scheme used, a subclass of Poco::URIStreamFactory
must be registered.
> POCO provides stream factories for ļ¬les, HTTP, HTTPS and FTP
resources.
87. Poco::Data Features
> Transactions
> all builtin C++ data types (and more) supported:
bool, short, int, long, Poco::Int64, std::string, Poco::Data::BLOB
> container support: vector, map, multimap, set, multiset, list
> complex type support: map classes to database tables
> supports Oracle, DB2, SQLServer and PostgreSQL (using ODBC),
SQLite and MySQL
> elegant, easy to use interface
89. int main(int argc, char* argv[])
{
init();
Session ses(
SessionFactory::instance().create(
SQLite::Connector::KEY, "dummy.db"
)
);
int count = 0;
ses << "SELECT COUNT(*) FROM PERSON", into(count), now;
std::cout << "People in DB " << count;
shutdown();
return 0;
}
90. Statement stmt(ses << "SELECT COUNT(*) FROM PERSON",into(count));
stmt.execute();
std::string str;
Statement insert(ses << "INSERT INTO Strings VALUES(?)", use(str));
insert.execute(); // inserts the empty string
str = "Hi";
insert.execute(); // inserts "Hi"
std::set<std::string> setStr; // [...] init with 100s of strings
Statement bulk(ses << "INSERT INTO Strings VALUES(?)", use(setStr));
bulk.execute();
91. Keywords
> into
where should we write data to
> use
where should we read data from
> lowerLimit, upperLimit, limit
how many rows should we fetch at least/at most
> range
deļ¬nes a range (lowerLimit, upperLimit)
> now
execute the query immediately
92. Session Pooling
> Creating a Session is a potentially expensive operation.
(involving network activity, user authentication/authorization, etc.)
> A SessionPool stores Session objects for eventual later reuse.
> Unused sessions are closed automatically.
93. Complex Type Mapping
> You can create mappings from your own types to database
tables.
> You do this by specializing the Poco::Data::TypeHandler template
for your type.
94. RecordSet
> A generic way to access data in an SQL table
(e.g., you don't know the exact schema)
> Find out about the columns in a table
(name, type, size, etc.)
> Get the data from columns as DynamicAny
95. Session session("SQLite", "sample.db");
Statement select(session);
select << "SELECT * FROM Person";
select.execute();
RecordSet rs(select);
std::size_t cols = rs.columnCount();
for (std::size_t col = 0; col < cols; ++col)
{
std::cout << rs.columnName(col) << std::endl;
}
bool more = rs.moveFirst();
while (more)
{
for (std::size_t col = 0; col < cols; ++col)
{
std::cout << rs[col].convert<std::string>() << " ";
}
std::cout << std::endl;
more = rs.moveNext();
}