Is it possible to programmatically add a new Mule Flow after the context has been initialized? - mule

I would like to programmatically add new RSS Connector flows while Mule is running (after the context has been initialized). When I try to do this, I get a Lifecycle Exception saying that the context is already initialized.
Is there a way to do this without restarting the whole context?

I figured out a solution on my own. It turned out that creating a new Mule context, adding my flow, and then starting the context worked just fine. In fact, this ended up being simpler, faster, and cleaner than the other path I was going down.
Creating a default Mule context worked just fine for me. You might need to add a ConfigurationBuilder to yours if you have special needs.
MuleContext newMuleContext = new DefaultMuleContextFactory().createMuleContext();
MuleRegistry registry = newMuleContext.getRegistry();
Flow flow = createFlow();
registry.registerFlowConstruct(flow);
newMuleContext.start();
Edit. Here's the createFlow method. Your specifics will be different based on the needs of your app.
protected Flow createFlow(MuleContext context, RssBean feed) throws Exception {
MuleRegistry registry = context.getRegistry();
String feedName = feed.getName();
HttpPollingConnector connector = getHttpPollingConnector(context, registry, feedName);
EndpointURIEndpointBuilder endpointBuilder = getEndpointBuilder(context, feed, registry, shortName, connector);
registry.registerEndpointBuilder(feedName + ".in", endpointBuilder);
MessagePropertiesTransformer transformer = getTransformer(context, feedName);
MessageProcessor mp = getOutboundFlowRef(context);
Flow flow = getFlow(context, shortName, endpointBuilder, transformer, mp);
registry.registerFlowConstruct(flow);
return flow;
}

Related

UWP SyncFusion SfDataGrid Serialization Exception

I'm trying to make use of the SfDataGrid component in my UWP app and have everything working just fine in debug mode. When I switched over to release mode to regression test the app before publishing to the Windows store the app throws an exception during grid serialization.
I have an SfDataGrid defined with 4 text columns, 1 numeric column and 1 template column. The template column just includes a delete button so that the user to can remove the row.
I have a method to return the serialization options as follows:
private SerializationOptions GetGridSerializationOptions()
{
return new SerializationOptions
{
SerializeFiltering = false,
SerializeColumns = true,
SerializeGrouping = true,
SerializeSorting = true,
SerializeTableSummaries = true,
SerializeCaptionSummary = true,
SerializeGroupSummaries = true,
SerializeStackedHeaders = true
};
}
Then I have another method to serialize the grid settings as follows:
private void RetrieveDefaultGridSettings()
{
using (MemoryStream ms = new MemoryStream())
{
gridReport.Serialize(ms, GetGridSerializationOptions());
_defaultGridSettings = Convert.ToBase64String(ms.ToArray());
}
}
I've followed the SyncFusion documentation (https://help.syncfusion.com/uwp/datagrid/serialization-and-deserialization) which describes how to serialize template columns. I have everything working perfectly in debug mode, but when I switch to release mode I get an exception on this line:
gridReport.Serialize(ms, GetGridSerializationOptions());
The exception is:
System.Runtime.Serialization.InvalidDataContractException: 'KnownTypeAttribute attribute on type 'Syncfusion.UI.Xaml.Grid.SerializableGridColumn' specifies a method named 'KnownTypes' to provide known types. Static method 'KnownTypes()' was not found on this type. Ensure that the method exists and is marked as static.'
I've had a look at the SerializableGridColumn class and can see a public static method called KnownTypes so I don't really understand why this exception is happening. I'm even more confused about why it's only happening in release mode.
In attempt to fix the problem I have tried referencing the entire SDK, removing the SDK and referencing the specific assemblies (Syncfusion.SfGrid.UWP, Syncfusion.Data.UWP, Syncfusion.SfInput.UWP, Syncfusion.SfShared.UWP, Syncfusion.SfGridConverter.UWP, Syncfusion.XlsIO.UWP and Syncfusion.Pdf.UWP) but neither yields a different result and the exception still occurs, but only in release mode.
Switching off the setting "Compile with .NET Native tool chain" does resolve the problem, but is not a practical solution as this blocks me from publishing the app to the Windows store.
Thanks very much for any assistance anyone can provide.
After exhausting all possible problems with my own code, I logged with an issue with SyncFusion. They're investigating and will hopefully provide a fix soon.

Getting Request Object in Spring Webflux elastic thread

I am facing one issue.
I am calling some API's in parallel using Spring Webflux. If any child thread faces any issue, it needs to log the request. Now the issue is , for logging a normal POJO class in which there is a static method which gets a bean via ApplicationContent and store the data in a Queue.
Now the issue is, I want to access request params like Request URL / Controller etc.
I tried
ServletRequestAttributes sra =
(ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
logger.error("====="+sra);
HttpServletRequest httpRequest = sra.getRequest();
but In this case, sra is null. I tried adding the following code,
#Configuration
public class InheritableRequestContextListener extends RequestContextListener {
private static final String REQUEST_ATTRIBUTES_ATTRIBUTE =
InheritableRequestContextListener.class.getName() + ".REQUEST_ATTRIBUTES";
#Override
public void requestInitialized(ServletRequestEvent requestEvent) {
System.out.println("111111111111111111");
if (!(requestEvent.getServletRequest() instanceof HttpServletRequest)) {
throw new IllegalArgumentException(
"Request is not an HttpServletRequest: " + requestEvent.getServletRequest());
}
HttpServletRequest request = (HttpServletRequest) requestEvent.getServletRequest();
ServletRequestAttributes attributes = new ServletRequestAttributes(request);
request.setAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE, attributes);
LocaleContextHolder.setLocale(request.getLocale());
RequestContextHolder.setRequestAttributes(attributes, true);
}
}
but this is not helping. Can anyone help. I am using springboot version ; 2.0.2.RELEASE.
There are several reasons as to why your implementation does not work.
Webflux is thread agnostic, which means that any thread can deal with anything at anytime in the application. If the application finds it efficiant to switch the current executing thread, it will do so.
Servlet applications on the other hand assigns one thread to each request and sticks with that thread throughtout execution.
ApplicationContext uses as you can see ServletRequests, so it is not usable in a Webflux application. It in turn uses threadlocal to store the request object to the designated thread.
In webflux you cant use threadlocal, bucase as soon as the application switches threads everything in threadlocal is gone. Thats why you get null.
So how do you pass data from thread to thread.
What you need to do is to implement a filter that intercepts the request, extracs the information you want and places it in the reactive context object.
https://projectreactor.io/docs/core/release/reference/#context
Here is a post that addresses the problem.
https://developpaper.com/implementation-of-requestcontextholder-in-spring-boot-webflux/

Apache Geode RegionExistsException

In the Pivotal Native Client I've setup a method to read and write a Geode cache region as follows:
public void GeodePut(string region, string key, string value)
{
CacheFactory cF = CacheFactory.CreateCacheFactory();
Cache c cF.Create();
RegionFactory rF = c.CreateRegionFactory(RegionShortcut.CACHING_PROXY);
IRegion<string, string> r = rF.Create<string, string>(region);
r[key] = value;
cache.Close();
}
when I call this multiple times I get RegionExistsException how do I get around that? Thanks
Solution is easy.
Add a try-catch block to catch the RegionExistsException, then in the catch segment replace the 'create' method with 'get'.
Change this: rF.Create
for this: rf.get
This works pretty well using Java, i would post the exact signature of the method you needed but im not using .Net native client.
Hope it helps :)
It's to do with the cache.Close() command. I no longer use cache.Close()

Ninject Inject Common DbContext Into Numerous Repositories

There’s something which I am doing that is working, but I think it can probably be done a lot better (and therefore, with more maintainability).
I am using Ninject to inject various things into a controller. The problem which I needed to solve is that the DbContext for each repository needed to be the same. That is, the same object in memory.
Whilst, the following code does achieve that, my Ninject common config file has started to get quite messy as I have to write similar code for each controller:
kernel.Bind<OrderController>().ToMethod(ctx =>
{
var sharedContext = ctx.Kernel.Get<TTSWebinarsContext>();
var userAccountService = kernel.Get<UserAccountService>();
ILogger logger = new Log4NetLogger(typeof(Nml.OrderController));
ILogger loggerForOrderManagementService = new Log4NetLogger(typeof(OrderManagementService));
var orderManagementService = new OrderManagementService(
new AffiliateRepository(sharedContext),
new RegTypeRepository(sharedContext),
new OrderRepository(sharedContext),
new RefDataRepository(),
new WebUserRepository(sharedContext),
new WebinarRepository(sharedContext),
loggerForOrderManagementService,
ttsConfig
);
var membershipService = new MembershipService(
new InstitutionRepository(sharedContext),
new RefDataRepository(),
new SamAuthenticationService(userAccountService),
userAccountService,
new WebUserRepository(sharedContext)
);
return new OrderController(membershipService, orderManagementService, kernel.Get<IStateService>(), logger);
}).InRequestScope();
Is there a neater way of doing this?
Edit
Tried the following code. As soon as I make a second request, an exception is chucked that the DbContext has already been disposed.
kernel.Bind<TTSWebinarsContext>().ToSelf().InRequestScope();
string baseUrl = HttpRuntime.AppDomainAppPath;
kernel.Bind<IStateService>().To<StateService>().InRequestScope();
kernel.Bind<IRefDataRepository>().To<RefDataRepository>().InRequestScope().WithConstructorArgument("context", kernel.Get<TTSWebinarsContext>());
var config = MembershipRebootConfig.Create(baseUrl, kernel.Get<IStateService>(), kernel.Get<IRefDataRepository>());
var ttsConfig = TtsConfig.Create(baseUrl);
kernel.Bind<MembershipRebootConfiguration>().ToConstant(config);
kernel.Bind<TtsConfiguration>().ToConstant(ttsConfig);
kernel.Bind<IAffiliateRepository>().To<AffiliateRepository>().InRequestScope().WithConstructorArgument("context", kernel.Get<TTSWebinarsContext>());
kernel.Bind<IWebinarRepository>().To<WebinarRepository>().InRequestScope().WithConstructorArgument("context", kernel.Get<TTSWebinarsContext>());
kernel.Bind<IWebUserRepository>().To<WebUserRepository>().InRequestScope().WithConstructorArgument("context", kernel.Get<TTSWebinarsContext>());
kernel.Bind<IOrderRepository>().To<OrderRepository>().InRequestScope().WithConstructorArgument("context", kernel.Get<TTSWebinarsContext>());
kernel.Bind<IInstitutionRepository>().To<InstitutionRepository>().WithConstructorArgument("context", kernel.Get<TTSWebinarsContext>());
kernel.Bind<IUserAccountRepository>().To<DefaultUserAccountRepository>().InRequestScope();
kernel.Bind<IRegTypeRepository>().To<RegTypeRepository>().InRequestScope().WithConstructorArgument("context", kernel.Get<TTSWebinarsContext>());
kernel.Bind<UserAccountService>().ToMethod(ctx =>
{
var userAccountService = new UserAccountService(config, ctx.Kernel.Get<IUserAccountRepository>());
return userAccountService;
});
kernel.Bind<IOrderManagementService>().To<OrderManagementService>().InRequestScope();
//RegisterControllers(kernel, ttsConfig);
kernel.Bind<AuthenticationService>().To<SamAuthenticationService>().InRequestScope();
kernel.Bind<IMembershipService>().To<MembershipService>().InRequestScope();
There's something about InRequestScope I'm misunderstanding.
Edit:
.InRequestScope() will ensure everything which gets injected that binding will receive exactly the same instance when during injection (creation) the HttpContext.Current is the same. That means when a client makes a request and the kernel is asked to provide instances with .InRequestScope(), it will return the same instance for the exact same request. Now when a client makes another request, another unique instance will be created.
When the request ends, ninject will dispose the instance in case it implements IDisposable.
However consider the following scenario:
public class A
{
private readonly DbContext dbContext;
public A(DbContext dbContext)
{
this.dbContext = dbContext;
}
}
and binding:
IBindingRoot.Bind<DbContext>().ToSelf().InRequestScope();
IBindingRoot.Bind<A>().ToSelf().InSingletonScope();
You got yourself a major problem. There's two scenarios how this can pan out:
You are trying to create an A outside of a request. It will fail. Instantiating the DbContext, ninject will look for HttpContext.Current - which is null at the time - and throw an Exception.
You are trying to create an A during a request. Instantiating will succeed. However, When you try to use some functionality of A (which is accessing DbContext in turn) after the request or during a new request, it will throw an ObjectDisposedException
To sum it up, an ObjectDisposedException when you access the DbContext can only be caused by two scenarios:
-you ar disposing the DbContext (or some component which in turn disposes the DbContext) before the request is over.
-you are keeping a reference to the DbContext (again, or to some component which in turn references the DbContext) across request boundaries.
That's it. Nothing complicated about this, but your object graph.
So what would help is drawing an object graph. Start from the root / request root. Then when you're done, start from the DbContext and check who's calling Dispose() on it. If there is no usage inside your code, it must be Ninject who's cleaning up when the request ends. That means, you need to check all references to the DbContext. Someone is keeping a reference across requests.
Original Answer:
You should look into scopes: https://github.com/ninject/ninject/wiki/Object-Scopes
Specifically, .InRequestScope() - or in case that is not appliccable to your problem - .InCallScope() should be interesting to you.
As you are already using .InRequestScope() for the original binding, i suggest that binding the shared context type also .InRequestScope() should be sufficient. It means every dependency of the OrderController will receive the same webinar context instance. Furthermore, if someone else in the same request wants to get a webinar context injected, he will also get the same instance.
You should look into scopes: https://github.com/ninject/ninject/wiki/Object-Scopes
Specifically, .InRequestScope() - or in case that is not appliccable to your problem - .InCallScope() should be interesting to you.
As you are already using .InRequestScope() for the original binding, i suggest that binding the shared context type also .InRequestScope() should be sufficient. It means every dependency of the OrderController will receive the same webinar context instance. Furthermore, if someone else in the same request wants to get a webinar context injected, he will also get the same instance.

Issue while running web service using batch job?

I have consumed a web service using visual studio and used managed code to call that in AX 2012.
Now if I am running the code in a simple job as:
static void CurrencyService(Args _args)
{
CurrencyConvert.Currency_Convert.CurrencyServiceClient convertcurrency;
CurrencyConvert.Currency_Convert.Currency currency;
System.ServiceModel.Description.ServiceEndpoint endPoint;
System.Type type;
System.Exception ex;
str s1;
try
{
type = CLRInterop::getType('CurrencyConvert.Currency_Convert.CurrencyServiceClient');
convertcurrency = AifUtil::createServiceClient(type);
endPoint = convertcurrency.get_Endpoint();
// endPoint.set_Address(new System.ServiceModel.EndpointAddress("http://localhost/HelloWorld"));
currency = convertcurrency.GetConversionRate(CurrencyConvert.Currency_Convert.CurrencyCode::AUD,CurrencyConvert.Currency_Convert.CurrencyCode::INR );
info(strFmt('%1', CLRInterop::getAnyTypeForObject(currency.get_Rate())));
}
catch(Exception::CLRError)
{
ex = CLRInterop::getLastException();
info(CLRInterop::getAnyTypeForObject(ex.ToString()));
}
}
Above job is working fine and producing results in a infolog.
Now, if a same piece of code is written under a class for batchjob(extending Runbasebatch class) as we normally do for any batch job, it is throwing an error as:
Microsoft.Dynamics.Ax.Xpp.ErrorException: Exception of type
'Microsoft.Dynamics.Ax.Xpp.ErrorException' was thrown.
at Dynamics.Ax.Application.BatchRun.runJobStatic(Int64 batchId) in
BatchRun.runJobStatic.xpp:line 38
at BatchRun::runJobStatic(Object[] )
at
Microsoft.Dynamics.Ax.Xpp.ReflectionCallHelper.MakeStaticCall(Type
type, String MethodName, Object[] parameters)
at BatchIL.taskThreadEntry(Object threadArg)
Other batch jobs except which used web services are working properly.
I have already tried many things such as : RunOn property of a class is set as "server" etc.
This is the case with each web service we have consumed.
Does anybody have a proper solution for this??
I am assuming that this is the same as on the Dynamics Ax community site post. So reading there, the error is not related to batch but to the following: "Could not find default endpoint element that references contract 'Currency_Convert.ICurrencyService' in the ServiceModel client configuration section.
This is because the endpoint is being searched in the AX32.exe.config file and this is not the one you need. You need to get it from the config file associated with your DLL.
To do this, you need to construct you client differently in AX. You need to use the AIF util because that way, the right config is used. Example:
type= CLRInterop::getType('DynamicsAxServices.WebServices.ZipCode.USAZipCodeServiceRef.PostalCodeServiceClient');
postalServiceClient = AifUtil::createServiceClient(type);
Apart from that, there is also an extra thing to whatch for. Separate environments would require different URL's and this can be solved by manually specifying your endpoint address and let it use a system parameter. (that way you can specify different configurations for DEV/TEST/PROD) (Note: below the endpoint address is hard coded and that should be a parameter)
static void Consume_GetZipCodePlaceNameWithEndPoint(Args _args)
{
DynamicsAxServices.WebServices.ZipCode.USAZipCodeServiceRef.PostalCodeServiceClient postalServiceClient;
DynamicsAxServices.WebServices.ZipCode.USAZipCodeServiceRef.PostalCodepostalCode;
System.ServiceModel.Description.ServiceEndpointendPoint;
System.ServiceModel.EndpointAddressendPointAddress;
System.Exceptionexception;
System.Typetype;
;
try
{
// Get the .NET type of the client proxy
type = CLRInterop::getType('DynamicsAxServices.WebServices.ZipCode.USAZipCodeServiceRef.PostalCodeServiceClient');
// Let AifUtil create the proxy client because it uses the VSAssemblies path for the config file
postalServiceClient = AifUtil::createServiceClient(type);
// Create and endpoint address, This should be a parameter stored in the system
endPointAddress = new System.ServiceModel.EndpointAddress ("http://www.restfulwebservices.net/wcf/USAZipCodeService.svc");
// Get the WCF endpoint
endPoint = postalServiceClient.get_Endpoint();
// Set the endpoint address.
endPoint.set_Address(endPointAddress);
// Use the zipcode to find a place name
postalCode = postalServiceClient. GetPostCodeDetailByPostCode("10001"); // 10001 is New York
// Use the getAnyTypeForObject to marshal the System.String to an Ax anyType
// so that it can be used with info()
info(strFmt('%1', CLRInterop::getAnyTypeForObject(postalCode.get_ PlaceName())));
}
catch(Exception::CLRError)
{
// Get the .NET Type Exception
exception = CLRInterop::getLastException();
// Go through the inner exceptions
while(exception)
{
// Print the exception to the infolog
info(CLRInterop::getAnyTypeForObject(exception.ToString()));
// Get the inner exception for more details
exception = exception.get_InnerException();
}
}
}
I was getting the same issue, finally its resolved.
Login to AOS machine with AOS service account and check if you can browse internet. If not then you need to set proxy for internet in IE.
So basically under AOS account, process could not connect to Webservice provider.
I have resolved this issue. I just end session all online user and stop/start AOS after doing ful cil. Maybe deleting XPPIL and Appl files helps before start the AOS service.