Converting an unruly dependency injection model with a service locator - c++

I've been using DI for a game engine project for a while and I just hit a wall; given the below order of creation: The job system does not depend on anything and everything depends on the file logger. It makes sense to create the job system, then the file logger, then pass the created references for each dependency down to its dependents' constructors.
App::App(const std::string& cmdString)
: EngineSubsystem()
, _theJobSystem{std::make_unique<JobSystem>(-1, static_cast<std::size_t>(JobType::Max), new std::condition_variable)}
, _theFileLogger{std::make_unique<FileLogger>(*_theJobSystem.get(), "game")}
, _theConfig{std::make_unique<Config>(KeyValueParser{cmdString})}
, _theRenderer{std::make_unique<Renderer>(*_theJobSystem.get(), *_theFileLogger.get(), *_theConfig.get())}
, _theInputSystem{std::make_unique<InputSystem>(*_theFileLogger.get(), *_theRenderer.get())}
, _theUI{std::make_unique<UISystem>(*_theFileLogger.get(), *_theRenderer.get(), *_theInputSystem.get())}
, _theConsole{std::make_unique<Console>(*_theFileLogger.get(), *_theRenderer.get())}
, _theAudioSystem{std::make_unique<AudioSystem>(*_theFileLogger.get()) }
, _theGame{std::make_unique<Game>()}
{
SetupEngineSystemPointers();
SetupEngineSystemChainOfResponsibility();
LogSystemDescription();
}
void App::SetupEngineSystemPointers() {
g_theJobSystem = _theJobSystem.get();
g_theFileLogger = _theFileLogger.get();
g_theConfig = _theConfig.get();
g_theRenderer = _theRenderer.get();
g_theUISystem = _theUI.get();
g_theConsole = _theConsole.get();
g_theInputSystem = _theInputSystem.get();
g_theAudioSystem = _theAudioSystem.get();
g_theGame = _theGame.get();
g_theApp = this;
}
void App::SetupEngineSystemChainOfResponsibility() {
g_theConsole->SetNextHandler(g_theUISystem);
g_theUISystem->SetNextHandler(g_theInputSystem);
g_theInputSystem->SetNextHandler(g_theApp);
g_theApp->SetNextHandler(nullptr);
g_theSubsystemHead = g_theConsole;
}
As you can see, passing the different subsystems around to the other subsystem constructors is starting to get messy. In particular when dealing with jobs, logging, console commands, UI, configuration, and audio (and physics, not pictured).
(Side note: These are going to eventually be replaced with interfaces created via factories for cross-compatibility, i.e. the Renderer is strictly a DirectX/Windows-only renderer but I want to eventually support OpenGL/Linux; that's why everything is passed around as references and created as pointers instead of a concrete types)
I've run in to situations where pretty much all the subsystems are in some way dependent on every other subsystem.
But, due to construction-order problems, Dependency Injection does not work because one or more of the required-to-exist subsystems hasn't been constructed yet. Same problem with two-phase construction: the subsystem may not have been initialized by the time it's needed further downstream.
I looked in to the service locator pattern and this question deems it a bad idea, but the game industry likes using bad ideas (like global variables to every subsystem for game-specific code to use) if they work.
Would converting to a service locator fix this problem?
What other implementations do you know of that could also fix the issue?

I ultimately went with the ServiceLocator pattern, deriving every subsystem that was a dependency as a Service:
App::App(const std::string& cmdString)
: EngineSubsystem()
, _theConfig{std::make_unique<Config>(KeyValueParser{cmdString})}
{
SetupEngineSystemPointers();
SetupEngineSystemChainOfResponsibility();
LogSystemDescription();
}
void App::SetupEngineSystemPointers() {
ServiceLocator::provide(*static_cast<IConfigService*>(_theConfig.get()));
_theJobSystem = std::make_unique<JobSystem>(-1, static_cast<std::size_t>(JobType::Max), new std::condition_variable);
ServiceLocator::provide(*static_cast<IJobSystemService*>(_theJobSystem.get()));
_theFileLogger = std::make_unique<FileLogger>("game");
ServiceLocator::provide(*static_cast<IFileLoggerService*>(_theFileLogger.get()));
_theRenderer = std::make_unique<Renderer>();
ServiceLocator::provide(*static_cast<IRendererService*>(_theRenderer.get()));
_theInputSystem = std::make_unique<InputSystem>();
ServiceLocator::provide(*static_cast<IInputService*>(_theInputSystem.get()));
_theAudioSystem = std::make_unique<AudioSystem>();
ServiceLocator::provide(*static_cast<IAudioService*>(_theAudioSystem.get()));
_theUI = std::make_unique<UISystem>();
_theConsole = std::make_unique<Console>();
_theGame = std::make_unique<Game>();
g_theJobSystem = _theJobSystem.get();
g_theFileLogger = _theFileLogger.get();
g_theConfig = _theConfig.get();
g_theRenderer = _theRenderer.get();
g_theUISystem = _theUI.get();
g_theConsole = _theConsole.get();
g_theInputSystem = _theInputSystem.get();
g_theAudioSystem = _theAudioSystem.get();
g_theGame = _theGame.get();
g_theApp = this;
}
void App::SetupEngineSystemChainOfResponsibility() {
g_theConsole->SetNextHandler(g_theUISystem);
g_theUISystem->SetNextHandler(g_theInputSystem);
g_theInputSystem->SetNextHandler(g_theRenderer);
g_theRenderer->SetNextHandler(g_theApp);
g_theApp->SetNextHandler(nullptr);
g_theSubsystemHead = g_theConsole;
}

Related

Has anyone used Appium/WinAppDriver for automating desktop applications.

I am looking for automating a windows application,and researching on what tools to be used. I have come across Appium/WinAppDriver, but not sure if it has a good usage anywhere so far....Appreciate suggestions on this.
I'm currently using the WinAppDriver to automate a WPF program. It's very similar to Selenium, if you have any experience with that then I'd advise using the WinAppDriver over something like White. You also get to use the Selenium WebDriverWait which was a massive bonus.
There is also a tool known as 'Inspect' that comes with the Windows SDK that allows you to inspect a windows application similar to the web-browser dev tools.
You simply initiate a driver (similar to Selenium) however you also need to start the WinApp process.
C# example:
protected WindowsDriver<WindowsElement> GetWindowsDriver()
{
var appCapabilities = new DesiredCapabilities();
appCapabilities.SetCapability("app",
PathHelper.GetClientInstallPath() + "APPLICATION.exe");
appCapabilities.SetCapability("deviceName", "WindowsPC");
if (!IsWinAppDriverProcesssRunning())
{
StartWinAppProcessRunning();
}
var driver = new WindowsDriver<WindowsElement>(new Uri("http://127.0.0.1:4723"), appCapabilities);
driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(5);
return driver;
}
private static bool IsWinAppDriverProcesssRunning()
{
const string processName = "WinAppDriver";
var existingProcesses = Process.GetProcessesByName(processName);
return existingProcesses.Any();
}
private static void StartWinAppProcessRunning()
{
const string winAppDirectory = #"C:\Program Files (x86)\Windows Application Driver";
var winAppProcess =
new Process
{
StartInfo =
{
FileName = Path.Combine(winAppDirectory, "WinAppDriver.exe"),
WindowStyle = ProcessWindowStyle.Hidden,
WorkingDirectory = winAppDirectory
}
};
winAppProcess.Start();
}

AutoCAD C++ When AcDbEntity need to open for read?

I’m not sure when open entities for read is necessary, and when it may be omit.
For example I know I don’t need to open entity when I want to use objectId() but there are some methods which require to open entity before.
I don’t know if it’s necessary to open AcDbPolyline before getArcSegAt(). In many cases I can simple try to use method before it’s open I will get what I want or not. But maybe there is some easy rule for that?
Example:
AcDbObjectId id = somethingNotImportant();
AcDbPolyline* _pPoly = NULL;
if (id.isValid())
{
AcDbEntity* pEnt = NULL;
Acad::ErrorStatus es;
es = acdbOpenObject(pEnt, id, AcDb::kForRead);
if( es == Acad::eOk)
{
if(pEnt->isKindOf(AcDbPolyline::desc()))
{
this->_pPoly = AcDbPolyline::cast(pEnt);
}
es = pEnt->close();
}
}
now _pPoly is initiallized , but it is closed because of pEnt->close();
now I want for example use:
AcGePoint3d Px = initializedSomehow();
double distAtPx = 0;
_pPoly->getDistAtPoint(Px , distAtPx);
do I need to :
es = acdbOpenObject(_pPoly, id, AcDb::kForRead);
before:
_pPoly->getDistAtPoint(Px , distAtPx);
I would consider it good practise to use the appropriate read access on your object first. That way you are guaranteed to know if you are only able to read the entity or also write to the entity.
This way you are in control. If you just go ahead and use the entity you have no way of knowing in the underlying library changes it's default behaviour.
Sorry if this does not answer your question.
I've looked in the documentation, and I'm not seeing anything that indicates anything about being able to use methods on a closed object. I expect that the assumption is that to work with any real AutoCAD data requires the object to be open for at least reading.
In that case, there are two ways to improve upon your example.
First option: do the work before closing the object. This keeps the open/close code all together with the work being done in the middle. This is nice that it should be clear when the object is open and can be worked with and that the object is not left open. This also meets the recommendation in the documentation to not keep object open any longer than necessary.
AcGePoint3d Px = initializedSomehow();
double distAtPx = 0;
AcDbObjectId id = somethingNotImportant();
if (id.isValid())
{
AcDbEntity* pEnt = NULL;
Acad::ErrorStatus es;
es = acdbOpenObject(pEnt, id, AcDb::kForRead);
if( es == Acad::eOk)
{
if(pEnt->isKindOf(AcDbPolyline::desc()))
{
AcDbPolyline*_pPoly = AcDbPolyline::cast(pEnt);
//Do work with poly here
_pPoly->getDistAtPoint(Px , distAtPx);
}
es = pEnt->close();
}
}
Second option: close the object only after doing the work, and only if the object is the right type. This allows for non-local usage of the opened object, but you need to make sure you close it later!
AcDbObjectId id = somethingNotImportant();
AcDbPolyline* _pPoly = NULL;
if (id.isValid())
{
AcDbEntity* pEnt = NULL;
Acad::ErrorStatus es;
es = acdbOpenObject(pEnt, id, AcDb::kForRead);
if( es == Acad::eOk)
{
if(pEnt->isKindOf(AcDbPolyline::desc()))
{
_pPoly = AcDbPolyline::cast(pEnt);
}
else
es = pEnt->close(); //not polyline, close now
}
}
AcGePoint3d Px = initializedSomehow();
double distAtPx = 0;
if (_pPoly)
{
//Do work with poly here
_pPoly->getDistAtPoint(Px , distAtPx);
_pPoly->close();
}

C++ Builder - Creating a TCP Server Connection programmatically with TIdTCPServer

I need to implement a TCP Server connection with TIdTCPServer component.
I already did it with GUI (drag & drop) and its working. But I need to Split form and TCP implementations. Example codes I've seen so far always uses TIdTCPServer as the member of TForm class.(result of drag and drop).
How I Call TCPConnection class that I've implemented from the TForm
TCPConnection CConnection = new TCPConnection(Owner, this);
Here is how I try to create a TCP Server Connection.
TCPConnection::TCPConnection(TComponent* Owner, TForm4* TSuperForm){
IdTCPServer1 = new TIdTCPServer(Owner);
IdTCPServer1->Bindings->Clear();
//IdTCPServer1->Bindings->Add()->SetBinding("10.10.2.103", 774);
IdTCPServer1->OnConnect = (TIdServerThreadEvent)(&OnConnect);
IdTCPServer1->OnExecute = (TIdServerThreadEvent)&OnExecute;
IdTCPServer1->OnDisconnect = (TIdServerThreadEvent)&OnConnect;
IdTCPServer1->OnException = (TIdServerThreadExceptionEvent)&OnException;
IdTCPServer1->DefaultPort = 774;
IdTCPServer1->Bindings->Add();
IdTCPServer1->Bindings->Items[0]->IP="10.10.2.103";
IdTCPServer1->Bindings->Items[0]->Port=774;
IdTCPServer1->ListenQueue = 15;
IdTCPServer1->MaxConnections = 15;
IdTCPServer1->TerminateWaitTime = 5000;
IdTCPServer1->Active = true;
this->TSuperForm = TSuperForm;
}
So far that codes work. But when I try to reach the context, connection is lost and throws an exception
void TCPConnection::OnConnect(TIdContext *AContext){
String IP = AContext->Binding()->PeerIP;
}
void TCPConnection::OnException(TIdContext *AContext, Exception *AException)
{
ShowMessage("Error:" + AException->ToString());
}
Error says TIdTaskThreadWork (I'll edit error, might be wrong)
If I don't try to reach AContext, connection stays without problem.
Might be something about thread, locking list, ...
Any Suggestions?
Those function casts look very smelly. Are you sure you've defined the functions as __fastcall, as the function casts should not be required at all.
This should be all you need, if you've defined them correctly.
IdTCPServer1->OnConnect = &OnConnect;
// ... etc...
This is what I do:
TIdTCPServer *TCPServer = new TIdTCPServer( this );
TCPServer->Active = false;
TCPServer->OnExecute = MyExecute;
TCPServer->DefaultPort = XXX;
TCPServer->Active = true;
Then my MyExecute call is defined like this:
void __fastcall MyExecute( TIdContext* AContext );
Other callbacks are handled the same way, don't forget __fastcall and it should work.

Design puzzle about database connectivity architecture

I am designing a database browsing application, which till now had MySQL support, but recently I have started implementing supporting Sqlite too and I face some ugliness while designing the way the connectivity architecture is being implemented. This is only about the "connection" part (ie: where you get the user/db/host, or for sqlite the filename), not the database functionality. That is sorted out already.
I have a base class "Connection" which exposes "normal" methods like name(), or pure virtual methods which are like virtual string fullLocation() = 0 which returns me a string that can be used to identify the database (such as: database#host for MySql, or /etc/mydb.sqlite for Sqlite).
Now, the user of course needs to specify a database he wants to connect to, so in the GUI of the application he simply chooses the type and then fills in the credentials. And here my troubles start. I have created a MySqlConnection and an SqliteConnectionclasses, both derived from Connection but most of the cases I end up with something like:
Connection* c = 0;
if(gui->engine_name() == "MYSQL")
{
string host = gui->getHost();
string user = gui->getUser();
string password = gui->getPassword();
int port = gui->getPort();
string db = gui->getDatabase();
c = new MySqlConnection(host, user, password, db, port);
}
else
{
string dbFile = gui->getSqliteDbFile();
c = new SqliteConnection(dbFile);
}
string meta = application->use_connection(&c);
and I have the fear, that this will continue through the entire application, due to the so different nature of these two database engines.
Do you have some guidance on how to solve this in an elegant way?
You need pattern Factory, that will create Connection for you in abstract way. It is superficial answer.
This Factory would be nice parametrize with Builder pattern. Something like that:
ParamBuilder *b = new ParamBuilder;
if(gui->engine_name() == "MYSQL")
{
b->setHost(gui->getHost())
->setUser(gui->getUser());
->setPassword(gui->getPassword());
...
}
else
{
b->setFile(gui->getSqliteDbFile());
}
Connection *c = globalConnectionFactory->createConnection(b);
A much more elegant way would be designing a factory class and handling GUI inputs in the GenerateConnection() method of that factory:
void ConnectionFactory::GenerateConnection(Connection* c)
{
if(gui->engine_name() == "MYSQL")
{
string host = gui->getHost();
string user = gui->getUser();
string password = gui->getPassword();
int port = gui->getPort();
string db = gui->getDatabase();
c = new MySqlConnection(host, user, password, db, port);
}
else
{
string dbFile = gui->getSqliteDbFile();
c = new SqliteConnection(dbFile);
}
}
If you do not prefer a dependency on the gui, you can just define a struct named Parameters and update its instance according to the gui inputs and give this object into the connection generating method of connection factory.

Windows Phone 7 Consuming Webservice WSDL

Ok I have written some basic generic webservices before but I have never tried to consume a 3rd party one.
The one I am trying to consume is
http://opendap.co-ops.nos.noaa.gov/axis/webservices/predictions/wsdl/Predictions.wsdl
I am not getting any results back from this what so ever and cannot figure out why.
More odd is it is not even reaching PredictionsClient_getPredictionsAndMetadataCompleted when I put a break point in the code it doesn't even reach it.
Any suggestions would be greatly appreciated
public void Bouy(double meters)
{
PredictionService.Parameters PredictionParams = new PredictionService.Parameters();
PredictionService.PredictionsPortTypeClient PredictionsClient = new PredictionService.PredictionsPortTypeClient();
GeoCoordinateWatcher gc = new GeoCoordinateWatcher(GeoPositionAccuracy.Default);
//gc.Position.Location.Latitude, gc.Position.Location.Longitude
GeoCoordinate myLocation = new GeoCoordinate(27.931631,-82.802582);
foreach (var bl in BouyLocation.GetAll())
{
GeoCoordinate otherLocation = new GeoCoordinate(bl.Lat, bl.Lon);
PredictionParams.beginDate = DateTime.Now.ToString("yyyyMMdd");
PredictionParams.endDate = DateTime.Now.AddDays(1.0).ToString("yyyyMMdd");
PredictionParams.stationId = bl.LocationID;
PredictionParams.timeZone = 0;
PredictionParams.unit = 1;
PredictionParams.dataInterval = 6;
PredictionsClient.getPredictionsAndMetadataCompleted += new EventHandler<PredictionService.getPredictionsAndMetadataCompletedEventArgs>(PredictionsClient_getPredictionsAndMetadataCompleted);
PredictionsClient.getPredictionsAndMetadataAsync(PredictionParams);
double mymeters = myLocation.GetDistanceTo(otherLocation);
if (mymeters < meters)
{
TextBlock DynTextBlock = new TextBlock
{
Name = "Appearance" + bl.LocationID,
Text = bl.LocationName + PredictionResult,
TextWrapping = System.Windows.TextWrapping.Wrap,
Margin = new Thickness(12, -6, 12, 0),
Style = (Style)Resources["PhoneTextSubtleStyle"]
};
DynamicAppearance.Children.Add(DynTextBlock);
this.nearByLocations.Add(new BouyLocationModel() { LocationName = bl.LocationName, LocationID = bl.LocationID, Lat = bl.Lat, Lon = bl.Lon });
}
}
var test = nearByLocations;
}
void PredictionsClient_getPredictionsAndMetadataCompleted(object sender, PredictionService.getPredictionsAndMetadataCompletedEventArgs e)
{
string err = e.Error.ToString();
PredictionResult = e.Result.ToString();
}
Loooking at the code you have here I think that you have used the importing of a ServiceReference to auto build the classes for you?
Unfortunately I have found that this is rather temperamental on WP7 and the only way I actually got it to work was when I connected it to a Microsoft WCF service. Connecting to anything else just doesn't work.
If you do google searches there are various pages talking about the fact it doesn't work and ways around it (which I couldn't get to work).
However, there are ways around it but it isn't as simple as the auto-generated stuff. Basically you do things manually.
Although there are other ways to manually create the web service what I did was follow the information in the following which worked well: http://zetitle.wordpress.com/2010/10/14/using-reactive-extensions-with-webrequest/
You will need to parse the response yourself but XML to LINQ works really well for this.
Hope that helps, or maybe someone will have the solution as it is something I am interested in knowing how to get working too