📜 ⬆️ ⬇️

QHessian: Qt & Hessian

image
The article covers the implementation of the Hessian binary web protocol on the Qt library stack. Target platform C ++.



Hessian is a binary web protocol designed to create useful web services (to put it simply, this thing will let you know what the weather is like outside the window from any of your applications). Hessian was developed by Caucho Technology, Inc. The company also developed protocol implementations for Java, Python, and ActionScript. Third-party companies have developed implementations for almost all programming languages ​​(C ++, C #, Perl, PHP, Ruby, Objective-C, D, Erlang).
')
Imagine that we have a basket of apples on the server. And we want, at the request of the client, to give him an apple. This is where hessian will help us.

On the server, we create a service interface (server in Java):
public interface FruitService {
Apple getNextApple();
}


* This source code was highlighted with Source Code Highlighter .
We create a similar class on the client (C ++):
class FruitService {
public :
Apple getNextApple();
}


* This source code was highlighted with Source Code Highlighter .
When the getNextApple () method is called on the client, the hessian implementation makes a request to the server (to a similar server method) and returns the result to the client. Hessian undertakes to deliver apples to us through the net. In fact, it serializes the data on the server and deserializes it on the client. Turning an apple into an array of bytes, transferring it over the network and restoring an apple from an array is the hessian task. The rest is your task.

Qt
Qt as a framework is widely known and hardly needs any introduction. I will only note that it will be a question of implementing the Hessian protocol for Qt C ++.

In general, there are several implementations (I managed to find 2) of the protocol under C ++:Hessian cpp and hessianorb are great projects and they are quite functional. Initially, for my development I used hessianorb - it supports code generation, i.e. allows you to create a C ++ proxy for all your services with one team (after two hours of preparation).

Unfortunately, both implementations force you to create code that looks foreign in the Qt environment. They require an additional library stack: hessian cpp - SSLPP, hessianorb - CURL. This fact, of course, complicates cross-platform development. Obviously, these libraries are needed for network data transfer, but Qt has its own layer for working with the network and I wanted to use it. In addition, both implementations block the thread of execution when interacting with the server, while the Qt network layer is asynchronous.

Thus , my goal was to create a protocol implementation based on the use of QNetworkAccessManager and its asynchronous nature.

QHessian

QHessian (hereinafter referred to as qh) is an implementation of the hessian protocol that does not use third-party libraries. In other words, a stack of Qt libraries is sufficient for working with this implementation.

As I mentioned earlier, the hessian task is to serialize, network, and deserialize data. The QNetworkAccessManager takes over the full network transmission. Serialization and deserialization of data is carried out according to the Hessian 2.0 Serialization Protocol document. The document states that the implementation of the protocol should be able to:To implement this requirement, qh uses its own type hierarchy:The mechanisms for working with qh copy mechanisms for working with standard input / output streams. Those. reading is carried out using the operator “ >> ”, and writing, respectively, using the operator “ << ”. Reading is from a special object QHessianReturnParser (server response parser). And the record is in the QHessianMethodCall object (preparing the data for sending to the server).

For example, to call the sample method of the server (Integer, String, Date) you need to run the code:
{
using namespace QHessian:: in ;
QHessian::QHessianMethodCall call( "sample" );
call << Long(55) << String (“”) << DateTime (QDateTime::currentDateTime ());
call.invoke(networkManager,
QUrl(“http: //serviceUrl”), //
myQObject, // QObject,
SLOT(reply()), //
SLOT(error( int , const QString&))); //
}


* This source code was highlighted with Source Code Highlighter .
This code will call the sample method with parameters 55, Vasily, current time. The server response will be processed in the reply () slot of the myQObject object, or, if an error occurs, in the error slot of the myQObject object. Let me remind you that the call is not blocking, i.e. no need to steam with multithreading.

Imagine that our service simply returns the data passed to it in the com.googlecode.AnswerObject object. Then the reply response in the reply slot will be:
void MyQObject::reply() {
using namespace QHessian:: out ;

qint32 long ;
QString string ;
QDateTime dateTime;

QHessian::QHessianReturnParser& parser =
*(QHessian::QHessianReturnParser*) QObject::sender();

parser >> BeginObject(“com.googlecode.AnswerObject”)
>> Long( long )
>> String ( String )
>> DateTime (dateTime)
>> EndObject();

parser.deleteLater();
}


* This source code was highlighted with Source Code Highlighter .
After execution, long will take the value 55, string - Vasily, dateTime - transmitted time.

QHessian supports collections (arrays, lists, associative arrays, etc.).
This could be the reading of the Polygon class from the server response:
{
using namespace QHessian:: out ;

QHessian::QHessianReturnParser& parser =
*(QHessian::QHessianReturnParser*) QObject::sender();

qint32 pointCount;

parser >> BeginObject( "Polygon" );
parser >> BeginCollection(“points”, pointCount);

for ( int i=0; i<pointCount; ++i) {
qint32 x, y;
parser >> Integer(x) >> Integer(y);
}

parser >> EndCollection();
parser >> EndObject();
parser.deleteLater();
}


* This source code was highlighted with Source Code Highlighter .
In this code:It is also possible that we do not know the type of the object, for example, the server returns an untyped List <? extends geometry>. In this case, you need to use a special peek () method, which determines whether it is possible to perform the desired read operation from the stream (an example is on the project website).

findings
I think that it turned out to be a completely suitable implementation of the protocol, which can be used in real applications.

The advantages include:By cons:References:
Hessian: http://hessian.caucho.com
QHessian: http://code.google.com/p/qhessian
QHessian FAQ: http://code.google.com/p/qhessian/wiki/FAQ
QHessian QA: http://code.google.com/p/qhessian/wiki/QHessian_QA

Thank.

==
Thanks to Sergey Bizin for his help in developing the project and writing the article.

UPD: Blog

Source: https://habr.com/ru/post/109393/


All Articles