How to instantiate a BSP controller manually - abap

I tried initially
DATA: cl_rest_bo_list TYPE REF TO zcl_rm_rest_bulk_orders.
CREATE OBJECT cl_rest_bo_list.
cl_rest_bo_list->request->if_http_request~set_method( 'GET' ).
cl_rest_bo_list->do_request( ).
This resulted into an abend, accessing request which was not initialized.
Then I tried to instantiate the request and the response
DATA: cl_rest_bo_list TYPE REF TO zcl_rm_rest_bulk_orders.
DATA: cl_request TYPE REF TO cl_http_request.
DATA: cl_response TYPE REF TO cl_http_response.
CREATE OBJECT cl_rest_bo_list.
CREATE OBJECT cl_request.
CREATE OBJECT cl_response.
request->if_http_request~set_method( 'GET' ).
cl_rest_bo_list->request = cl_request.
cl_rest_bo_list->response = cl_response.
cl_rest_bo_list->do_request( ).
This, at least, does not abend, but the set_method return error code here and does not actually set the method.
system-call ict
did
ihttp_scid_set_request_method
parameters
m_c_msg " > c handle
method " > method
m_last_error. " < return code
Since Google does not know about ihttp_scid_set_request_method, I am pretty sure that I am doing this wrong. Maybe there is no provision to instantiate BSP controllers, though I am not sure what this means for ABAP Unit testing BSP controllers.
As a solution for now I have lifted all business logic into a separate method which gets called/tested without trouble. Still, if anybody knows how to instantiate CL_BSP_CONTROLLER2 classes, that would be great.

As far as I know, the BSP controller can only be instantiated from within the ICF processing because it retrieves information about the call from the kernel. I'm not sure why you would want to install unit tests for the UI in the first place, unless you didn't separate the UI and the business logic as your comment about "lifting" suggests....

Related

Dynamic model attribute with SAILSJS

My use case needs me to use Dynamic Model attributes with my Sails.Js project and all of my methods fail. First I tried to call model1 method from model2 but it doesn't works. I also tried to use global variables but this fails too because, the global is set after the load of the application, and finaly I called model1Controller from the model2 but it still not working.
This is the mothod in my model2Controller
getbyTable:function(req,res){
let field = Field.find({fTable:req.param('tableName')});
field.exec(function(err, response) {
if(err) {
res.status(500);
return res.view('500', {data: err});
}
//res.json(response);
return response;
});
},
And this is my model2
'use strict';
const fieldController = require('../controllers/Model1Controller');
const donnees = fieldController.getbyTable('person');
module.exports={
}
When run it fires as error that req.param is not a function.
Need help!!! Thanks.
This looks like an interesting way to organize - I'd be curious to see how successful a project could be without Model attributes set in stone.
I can see a few specific errors in your code, maybe seeing them will help you move forward.
From your model2 you invoke getbyTable('person') with a string argument - but all controller methods are really intended to have reqest/response arguments (as in the definition getbyTable(req, res). Directly invoking a controller method is a bit unusual - if you ever did it, I'd expect to pass along a request and response from some other controller method.
Inside getbyTable, you try to return the response, but the response is only defined inside the exec callback. The response would be an array of objects fetched from your database - if that's what you need, you can't return them directly since database calls are async.
Your controller should probably do something with res in all logical branches, such as res.json, res.send, etc.
It's a bit hard to see exactly what you're trying to achieve, so maybe if you could explain the goal I could have some more relevant advice. For now, I could say that you might want to consider putting some code inside a service rather than a controller. Create file /api/services/MyService.js and use it to export a method that can be called from your model2 (you can require the service just like the controller). Keep the controller methods strictly for handling requests.
Good luck.

Cumulocity using custom type properties in esper statements

I have a hard time using the properties of my custom types to write statements like contexts. For exemple, this is working:
create context TripContext
context PartionBySource
partition by source from EventCreated,
context ContextBorders
initiated by EventCreated(
type="c8y_SwitchPowerReport") as startEvent
terminated by EventCreated(
type="c8y_SwitchPowerReport") as endEvent;
However it's not enough and I need to check some of my custom properties to better define the context. I'd like to be able to do something like this:
create context TripContext
context PartionBySource
partition by
source,
getString(????, "customProp1"),
getNumber(????, "customProp2"),
...
from EventCreated,
context ContextBorders
initiated by EventCreated(
type="c8y_SwitchPowerReport",
getString(startEvent, "c8y_SwitchPower.newStatus") = "ON") as startEvent
terminated by EventCreated(
type="c8y_SwitchPowerReport",
getString(endEvent, "c8y_SwitchPower.newStatus") = "OFF") as endEvent;
I have no idea what to put instead of the ???? to make reference to the event. It's transparent for the "native" properties like source, time, type, etc. but as soon as there is a custom property, I have no idea how to access it.
As for the initiated/terminated syntax, there is something really weird I dont understand, but maybe it's more an Esper than Cumulocity problem. This is working:
terminated by EventCreated(
type="c8y_SwitchPowerReport",
getString(endEvent, "c8y_SwitchPower.newStatus") = "OFF") as endEvent
But this is not:
initiated by EventCreated(
type="c8y_SwitchPowerReport",
getString(startEvent, "c8y_SwitchPower.newStatus") = "ON") as startEvent
I got an error saying:
Failed to validate single-row function parameter expression 'startEvent': Property named 'startEvent' is not valid in any stream
Any insight would be appreciated.
I also couldn't find a quick way to get it run like you try.
But I would recommend the following approach. If you anyways relating heavily on custom fragments it makes sense to run the event through an additional stream that extracts this values:
create schema MyCustomEvent(
event Event,
myCustomString String,
myCustomNumber BigDecimal
);
insert into MyCustomEvent
select
e.event as Event,
getString(e, "myCustomString") as myCustomString,
getNumber(e, "myCustomNumber") as myCustomNumber
from EventCreated e
where getString(e, "myCustomString") is not null
and getNumber(e, "myCustomNumber") is not null;
Now you can easily create a context on MyCustomEvent instead on EventCreated.

Autofac SingleInstance not working

I am trying to get a Singleton instance working with Autofac. I'm kind of doing a quasi-mvvm type thing with Winforms, just an experiment so don't get to hung up on that. But I am trying you have my model be a single instance with a reference in a command (ICommand here is not the WPF variety):
I have the following setup of a container:
var cb = new ContainerBuilder();
cb.RegisterType<CalculateCommissionCommand>().As<ICommand<TradeEntry>>().SingleInstance();
cb.RegisterType<CalculationsModel>().As<ICalculationsModel>().SingleInstance();
cb.Register(c => new CalculationsView() { Model = c.Resolve<ICalculationsModel>() }).SingleInstance();
cb.Build();
Now the Command takes an ICalculationsModel as a constructor parameter. However, when I set a value in the Model being passed to the Command, that value does not appear within the model that has already been set withing the CalculationsView. It seems that the command and the view are being passed different instances of the CalculationsModel despite the "singleInstance" method being called. Am I missing something? Why is this happening?
We hit a similar problem today and this seems to be the only post where this question is asked, so I thought I'd share our experience in the hopes it helps someone out. In the end it was something right in front of our eyes and of course they're usually the hardest problems to solve :-).
In our scenario, we were:
Registering a specific implementation of a configuration provider
Auto-registering certain types within an assembly.
Something along these lines:
var cb = new ContainerBuilder();
cb.RegisterType<FileBasedConfigurationProvider>()
.As<IConfigurationProvider>()
.SingleInstance();
cb.RegisterAssemblyTypes(typeof(MailProvider).Assembly)
.Where(t => !t.IsAbstract && t.Name.EndsWith("Provider"))
.AsImplementedInterfaces();
Stupidly, we didn't think about/realise that the FileBasedConfigurationProvider was in the same assembly as the MailProvider, so the second registration call basically overwrote the first one; hence, SingleInstance "wasn't working".
Hope that helps someone else out!
It's not clear from your code how you are storing/using the container. It is likely you have created multiple containers.
In my case the problem was that the parameter to the method generating the second instance was defined as the class instead of the interface
i.e.
SomeMethod(ClassName parameter)
instead of
SomeMethod(**I**ClassName parameter)
Obvious mistake, but took a few minutes to see it.
In my case I had two registrations for a class for different interfaces declaring that each was single instance. I assumed there would be a single instance of the class... no there's a single instance for each registration.
e.g
builder.RegisterType<MyClass>().As<IMyFirstInterface>().SingleInstance(); // 1st instance
builder.RegisterType<MyClass>().As<IMySecondInterface>().SingleInstance(); // 2nd instance
The correct way to do this was...
builder
.RegisterType<MyClass>()
.As<IMyFirstInterface>()
.As<IMySecondInterface>()
.SingleInstance();

Ninject: More than one matching bindings are available

I have a dependency with parameters constructor. When I call the action more than 1x, it show this error:
Error activating IValidationPurchaseService
More than one matching bindings are available.
Activation path:
1) Request for IValidationPurchaseService
Suggestions:
1) Ensure that you have defined a binding for IValidationPurchaseService only once.
public ActionResult Detalhes(string regionUrl, string discountUrl, DetalhesModel detalhesModel)
{
var validationPurchaseDTO = new ValidationPurchaseDTO {...}
KernelFactory.Kernel.Bind<IValidationPurchaseService>().To<ValidationPurchaseService>()
.WithConstructorArgument("validationPurchaseDTO", validationPurchaseDTO)
.WithConstructorArgument("confirmPayment", true);
this.ValidationPurchaseService = KernelFactory.Kernel.Get<IValidationPurchaseService>();
...
}
I'm not sure what are you trying to achieve by the code you cited. The error is raised because you bind the same service more than once, so when you are trying to resolve it it can't choose one (identical) binding over another. This is not how DI Container is supposed to be operated. In your example you are not getting advantage of your DI at all. You can replace your code:
KernelFactory.Kernel.Bind<IValidationPurchaseService>().To<ValidationPurchaseService>()
.WithConstructorArgument("validationPurchaseDTO", validationPurchaseDTO)
.WithConstructorArgument("confirmPayment", true);
this.ValidationPurchaseService = KernelFactory.Kernel.Get<IValidationPurchaseService>();
With this:
this.ValidationPurchaseService = new ValidationPurchaseService(validationPurchaseDTO:validationPurchaseDTO, confirmPayment:true)
If you could explain what you are trying to achieve by using ninject in this scenario the community will be able to assist further.
Your KernelFactory probably returns the same kernel (singleton) on each successive call to the controller. Which is why you add a similar binding every time you hit the URL that activates this controller. So it probably works the first time and starts failing after the second time.

How do I utilize a named instance within the ObjectFactory.Initialize call for StructureMap?

I am trying to do the following bootstrapping:
x.For(Of IErrorLogger).Use(Of ErrorLogger.SQLErrorLogger)().
Ctor(Of IErrorLogger)("backupErrorLogger").Is(ObjectFactory.GetNamedInstance(Of IErrorLogger)("Disk"))
x.For(Of IErrorLogger).Add(
Function()
Return New ErrorLogger.DiskErrorLogger(
CreateErrorFileName(ServerMapPath(GetAppSetting("ErrorLogFolder"))))
End Function).Named("Disk")
But it shows this error:
StructureMap Exception Code: 200
Could not find an Instance named "Disk" for PluginType Logging.IErrorLogger
I sort of understand why this is happening.. the question is, how do I utilize a named instance within the registry? Maybe something like lazy initialization for the ctor argument for the SQLErrorLogger? I am not sure how to make it happen.
Thanks in advance for any help you can provide.
I found the correct way to do it in the latest version (2.6.1) of StructureMap:
x.For(Of IErrorLogger).Use(Of ErrorLogger.SQLErrorLogger)().
Ctor(Of IErrorLogger)("backupErrorLogger").Is(
Function(c) c.ConstructedBy(Function() ObjectFactory.GetNamedInstance(Of IErrorLogger)("Disk"))
)
x.For(Of IErrorLogger).Add(Function() _
New ErrorLogger.DiskErrorLogger(
CreateErrorFileName(ServerMapPath(GetAppSetting("ErrorLogFolder"))))
).Named("Disk")
Notice for the Is method of Ctor, we need to provide a func(IContext), and use the IContext.ConstructedBy(Func()) to call ObjectFactory.Get... to successfully register the IErrorLogger in this case.
This is the only way to do it as far as I know. The other Icontext methods such as IsThis and Instance will only work with already registered type.
Your problem is that you are trying to access the Container before it's configured. In order to make structuremap evaluate the object resolution after the configuration you need to provide a lambda to the Is function. The lambda will be evaluated when trying to resolve the type registered.
x.[For](Of ILogger)().Add(Of SqlLogger)().Ctor(Of ILogger)("backupErrorLogger")_
.[Is](Function(context) context.GetInstance(Of ILogger)("Disk"))
x.[For](Of ILogger)().Add(Of DiskLogger)().Ctor(Of String)("errorFileName")_
.[Is](CreateErrorFileName(ServerMapPath(GetAppSetting("ErrorLogFolder"))))_
.Named("Disk")
Disclaimer: I'm not completely up-to-date with the lambda syntax in VB.NET, but I hope I got it right.
Edit:
The working C# version of this I tried myself before posting was this:
ObjectFactory.Initialize(i =>
{
i.For<ILogger>().Add<SqlLogger>()
.Ctor<ILogger>("backup").Is(
c => c.GetInstance<ILogger>("disk"))
.Named("sql");
i.For<ILogger>().Add<DiskLogger>().Named("disk");
});
var logger = ObjectFactory.GetNamedInstance<ILogger>("sql");