Aspect Oriented Programming in Qt - c++

I'm trying to get my head around AOP and some Qt Code would really help.
From wikipedia here is some sample code (easy for a Qt/C++ programmer to read):
void transfer(Account fromAcc, Account toAcc, int amount, User user, Logger logger)
throws Exception {
logger.info("transferring money...");
if (! checkUserPermission(user)){
logger.info("User has no permission.");
throw new UnauthorizedUserException();
}
if (fromAcc.getBalance() < amount) {
logger.info("Insufficient Funds, sorry :( ");
throw new InsufficientFundsException();
}
fromAcc.withdraw(amount);
toAcc.deposit(amount);
//get database connection
//save transactions
logger.info("Successful transaction. :) ");
}
And then "aspectized":
void transfer(Account fromAcc, Account toAcc, int amount) throws Exception {
if (fromAcc.getBalance() < amount) {
throw new InsufficientFundsException();
}
fromAcc.withdraw(amount);
toAcc.deposit(amount);
}
aspect Logger
{
void Bank.transfer(Account fromAcc, Account toAcc, int amount, User user, Logger logger)
{
logger.info("transferring money...");
}
void Bank.getMoneyBack(User user, int transactionId, Logger logger)
{
logger.info("User requested money back");
}
// other crosscutting code...
}
Qt has signals and slots to decouple objects. But I still need to emit signals.
So: Can this be done with Qt or do I need some special framework/preprocessors as referenced in the wikipedia article?
I have a feeling that there must be some trick since Qt uses the Meta Object Compiler and some functionality might be "injected" with dynamic methods.... just spit-balling here ;)
Edit: To give a better context: I really like the dynamic aspects (power) of the Qt meta object with signals and slots and would like to keep a Qt feel to it. Thus, my idea is to make use of slots (or signals) as point cuts. For example:
If I define slot Bank::transfer(...) and then signal Bank::OnBeforeTranfer() and signal Bank::OnAfterTransfer(). If I then connect them to other aspects say Security::transfer() and Logger::transfer() (all QObjects) I can block calls (like fail OnBeforeTransfer).
But, if we then take it to the next evolution to get less and cleaner code I would like to get rid of the OnXXXX signals and connect the Bank::transfer slot to Security::transfer slot and Logger::transfer. Anything dynamic in Qt? : Like order of calling slots and and preventing next call in the "slot chain"?
This whole context can still be considered AOP right? I'm trying to stick to "method level point cuts" or am I totally beside the point here?

In what language are you planning to use Qt? I recently had to build a simple GUI in Qt around a python script and used the AOP python package Aspyct to do some quick before and after stuff. Qt is event-driven programming, I'd say get familiar with the Qt basics, many things are similar to AOP-style operations and then find some AOP libraries for the language you plan to use Qt in.

Another AOP framework you may consider using is AspectC++. I've played with it a bit and it seems to work quite well. They even have a whitepaper on the site that describes how AspectC++ can be used with Qt.

If you want to stay within the Qt framework, you could take a look at the State Machine Framework. (And get rid of the exceptions :)
Then you could just connect the Logger to state change events.

Related

Qt testing when dependent on Network

I'm working on a Qt project, and I need to be able to write unit tests for functions that depend on QNetworkAccessManager.
Google Mock seems like an overkill for my purposes, and I found this answer which suggest using a "linker trick" to mock the class. However, I'm very new to C++ (and C in general), and I'm having somewhat hard time in understanding the exact way I'm supposed to use this "trick". Am I supposed to manually change the header file to run the test, or is there some nicer way to do it (I'm assuming there is).
Any kind of an example on the header/code structure to do this correctly would be an immense help.
You could use linker tricks, but as QNetworkAccessManager can be subclassed, you might find it easier just to do that.
For example, if you want to make a version that doesn't actually connect, you could do something like:
class FailQNetworkAccessManager : public QNetworkAccessManager
{
Q_OBJECT
public:
FailQNetworkAccessManager(QObject *parent = Q_NULLPTR):QNetworkAccessManager(parent){}
protected:
QNetworkReply* createRequest(Operation op, const QNetworkRequest &originalReq, QIODevice *outgoingData = Q_NULLPTR)
{
QNetworkReply* rep = QNetworkAccessManager::createRequest(op, originalReq, outgoingData);
// Queue the abort to occur from main loop
QMetaObject::invokeMethod(req, "abort", Qt::QueuedConnection);
return rep;
}
};
Then your test code can provide your class with the FailQNetworkAccessManager rather than the real one, and all requests should abort as soon as they're created. (This is just example code, I haven't actually tried this code yet - I would also recommend splitting this into header & cpp files).
You should also have a look at the Qt Test system, which is the built in test framework.

Google Play Services C++ / Run UI on second activity using IntentHandler

I am developing a mobile game using Cocos2D-x engine for android platform and i want to integrate GPGS on it.
I achieved to show leaderboards, but there is a little annoying problem. When leaderboard is visible, if i go background and then come back to app, the gamescene goes to black. I think opengl context being released and doesnt restore again. In my opinion running leaderboard on same activity causes this, the game engine cant understand whats happening there. Whatever, because of this I want to run leaderboard (and also all GPGS things) on a new activity using intent.
Google likes "Providing"
In the reference documents of Google Play Game Services C++ SDK, there is a few unclear/fuzzy explanation about using SetOptionalIntentHandlerForUI method.
"Provide a function that can start a provided UI intent at any point, using startActivityForResult."
What is the mean of "Providing"? What is a provided Intent? How will I use startActivityForResult method? Unfortunately, "using" and "providing methods" are not clear expressions for coding. There is no sample about
using this method in the documents of GPGS for C++. Eventually,
Google's document is so poor and
there is no useful information on the internet. If someone from Google helps me, I will be so happy.
As i understand, I wrote the code like this. But it gives error when starting.
AppActivity.java
public void runGPGSActivity(Intent i) {
startActivityForResult(i,100);
}
AndroidPlatformConfiguration.h (From C++ gpg lib)
typedef std::function<void(jobject)> IntentHandler;
AndroidPlatformConfiguration &SetOptionalIntentHandlerForUI(
IntentHandler intent_handler);
main.cpp (JNI binding, the working code, GPGS runs on same activity )
gpg::AndroidPlatformConfiguration platform_configuration;
platform_configuration.SetActivity(activity);
StateManager::InitServices( ...
main.cpp (JNI binding, GPGS must be run on new activity )
gpg::AndroidPlatformConfiguration platform_configuration;
jclass activityClass = env->FindClass("org/cocos2dx/cpp/AppActivity");
jmethodID jIntentHandlerMethodID = env->GetMethodID(activityClass,"runGPGSActivity","(Landorid/content/Intent;)V");
jobject jIntentHandler = env->NewObject(activityClass, jIntentHandlerMethodID);
gpg::AndroidPlatformConfiguration::IntentHandler mIntentHandler; /*= [](jobject mjIntentHandler){};*/
std::function<void(jobject)> intentHandler = std::bind(mIntentHandler,jIntentHandler);
platform_configuration.SetOptionalIntentHandlerForUI(intentHandler);
platform_configuration.SetActivity(activity);
StateManager::InitServices(
There is no build error, but the application crashes when launching.
03-24 14:12:24.301: A/libc(21352): Fatal signal 6 (SIGABRT) at
0x00005368 (code=-6), thread 21352 (main)
And some links about this issue:
IntentHandler reference
StartActivityForResult reference
/// Thank you in advance. ///
...Yeah I solved the problem, but didn't use IntentHandler method.
I was using this code in my app, to show weekly leaderboard data.
gameServices->Leaderboards().ShowUIBlocking(leaderboardId,gpg::LeaderboardTimeSpan::WEEKLY);
But return value is not void, it is UIStatus (whatever it is)
I've reverted back to this code, app is not going to black screen now. This method returns void, I think I have to catch some callbacks when using ShowUIBlocking method, with that UIStatus thing.
gameServices->Leaderboards().ShowUI(leaderboardId);
But now, I can't benefit from timespan feature of leaderboards.
I am going to research how it can be used. There is no problem for now. But, documentation of SetOptionalIntentHandlerForUI must be written more explicit, for programmers who want to use it.

How to test asynchronuous code

I've written my own access layer to a game engine. There is a GameLoop which gets called every frame which lets me process my own code. I'm able to do specific things and to check if these things happened. In a very basic way it could look like this:
void cycle()
{
//set a specific value
Engine::setText("Hello World");
//read the value
std::string text = Engine::getText();
}
I want to test if my Engine-layer is working by writing automated tests. I have some experience in using the Boost Unittest Framework for simple comparison tests like this.
The problem is, that some things I want the engine to do are just processed after the call to cycle(). So calling Engine::getText() directly after Engine::setText(...) would return an empty string. If I would wait until the next call of cycle() the right value would be returned.
I now am wondering how I should write my tests if it is not possible to process them in the same cycle. Are there any best practices? Is it possible to use the "traditional testing" approach given by Boost Unittest Framework in such an environment? Are there perhaps other frameworks aimed at such a specialised case?
I'm using C++ for everything here, but I could imagine that there are answers unrelated to the programming language.
UPDATE:
It is not possible to access the Engine outside of cycle()
In your example above, std::string text = Engine::getText(); is the code you want to remember from one cycle but execute in the next. You can save it for later execution. For example - using C++11 you could use a lambda to wrap the test into a simple function specified inline.
There are two options with you:
If the library that you have can be used synchronously or using c++11 futures like facility (which can indicate the readyness of the result) then in your test case you can do something as below
void testcycle()
{
//set a specific value
Engine::setText("Hello World");
while (!Engine::isResultReady());
//read the value
assert(Engine::getText() == "WHATEVERVALUEYOUEXPECT");
}
If you dont have the above the best you can do have a timeout (this is not a good option though because you may have spurious failures):
void testcycle()
{
//set a specific value
Engine::setText("Hello World");
while (Engine::getText() != "WHATEVERVALUEYOUEXPECT") {
wait(1 millisec);
if (total_wait_time > 1 sec) // you can put whatever max time
assert(0);
}
}

How to handle state transitions and yet replace "if" statements with polymorphic types?

Recently I was listening to a tech talk on clean coding. The speaker was a test engineer, who emphasized on avoiding the "if" statements in the code and use polymorphism as much as possible. Also he advocated against global states.
I quite agree with him, yet i need a clarification on replacing the global state and "if" statement using polymorphism for the below scenario,
I have 3 states in my document. I want to change the state of the UI components based on the document state. Right now, i use "if" blocks and an enumeration type holding the current state of document to transition the states of UI components.
eg:
enum DOC_STATE
{
DOC_STATE_A = 0,
DOC_STATE_B,
DOC_STATE_C
};
void QMainWindow::handleUi(_docState)
{
switch(_docState)
{
case (DOC_STATE_A):
{
menu.disable();
....
}
case (DOC_STATE_B):
{
menu.enable();
...
}
case (DOC_STATE_C):
{
...
}
}
I think i can have separate child classes for each state and have the handleUI() method in each class. Calling handleUi() method calls the right method call. But say i maintain these objects in my doc, how do i switch from one object to other each time there is a transition in state?
In other words, how to handle UI transition by tracking the change in state of document without using a global state and "if" or Switch statements?
I use Qt. Thanks.
If you are using Qt, take a look at The Qt State Machine Framework and the State Machine Examples. No need to re-invent the wheel when your framework already provides a sports car :)
I don't think I understand the problem because the answer is too trivial: you replace the pointer to your state instance with a new state instance and discard the old one.

Pattern for UI configuration

I have a Win32 C++ program that validates user input and updates the UI with status information and options. Currently it is written like this:
void ShowError() {
SetIcon(kError);
SetMessageString("There was an error");
HideButton(kButton1);
HideButton(kButton2);
ShowButton(kButton3);
}
void ShowSuccess() {
SetIcon(kError);
std::String statusText (GetStatusText());
SetMessageString(statusText);
HideButton(kButton1);
HideButton(kButton2);
ShowButton(kButton3);
}
// plus several more methods to update the UI using similar mechanisms
I do not likes this because it duplicates code and causes me to update several methods if something changes in the UI.
I am wondering if there is a design pattern or best practice to remove the duplication and make the functionality easier to understand and update.
I could consolidate the code inside a config function and pass in flags to enable/disable UI items, but I am not convinced this is the best approach.
Any suggestions and ideas?
I would recommend Observer Pattern and State Pattern, when an validation happens to be successful or unsuccessful, attached buttons can change their state according to information provided in "notify" method. Please refer to GoF's book for further details, or just google them. Hope it helps.