Change domain class cache setting outside of domain class - caching

I have a plugin that has a bunch of domain classes. This plugin is used by multiple applications.
My problem is that I can't specify the mapping->cache setting in the domain classes themselves (as they need to have different values depending up the application that uses them). For example, in Application A, I'd like to have domain class X read-only cached, and domain class Y not cached. In Application B, I'd like to have domain class X transactional cached, and domain class Y read-only cached.
What I'd like (I'm hoping this is already available) is something like:
grails.gorm.default.mapping { cache true }
But instead of being global, I can apply to just a specific domain class, something like:
grails.gorm.com.integralblue.domain.User.mapping { cache true }
Someone had suggested having each domain class checking the grails config, something like:
static mapping = {
cache: Holders.grailsApplication.config.com.package.Person.cache ?: false
}
And the Config:
com.package.Person.cache = true
but I'd like to avoid that if possible
Thanks!

The approach which you have mentioned should be used in the ideal case scenario.
I agree that changes has to be made in the plugin and the application as well.
Ideally, domain classes in the plugin should provide a lenient mapping which can be overriden.
If you have used grails.gorm.default.mapping { cache true } in the plugin or cache: true or which ever mapping in the domain class, then it can easliy be overriden in the application according to need. For example:
//Domain class in Plugin
class Person{
static mapping = {
cache: 'read-only'
}
}
Since mapping is nothing but a static block in a groovy object it can easily by metaClassed in concerned application at runtime like
//Application A:
Person.metaClass.'static'.mapping = {
cache 'transactional'
}
//Application B:
Person.metaClass.'static'.mapping = {
cache 'read-write'
}
(Untested)
If you want to do the same thing collectively for all the domain classes then the domain class artefact can be used as below
//Application A BootStrap
grailsApplication.domainClasses.each{
it.clazz.metaClass.'static'.mapping = {cache 'transactional'}
}
selectively:
//Application A BootStrap
def personClazz =
grailsApplication.domainClasses.find{it.clazz.simpleName == 'Person'}.clazz
personClazz .metaClass.'static'.mapping = {cache 'transactional'}
*Either of the cases you have to do some modification in Applications using the plugin.

Related

How to create routes configuration itself dynamically

In one of my use case, i have all my route information in a json file and i want to read the file and create the routes accordingly.
for example,
if i have declared route like this in my json config file
{
"config": [
{
"routeSrcSystem": "System1",
"routes": [
{
"fromRoute": {
"type": "default",
"typeValue": "direct:CMStart"
},
"toRoute": {
"type": "http"
"typeMethod": "POST",
"typeContent": "application/json",
"typeValue": "http://localhost:8080/v1/System1/inboundMessage"
}
}
]
}
]
}
then i able to create the routes as below dynamically. but here though its dynamic,the route definition is not dynamic because i have used one "from" and one "to" definition but parameter for this definition i am passing dynamically.
public class GenerateRouter extends RouteBuilder {
private RoutesMetadata routesMetadata;
public GenerateRouter(CamelContext context,RoutesMetadata routesMetadata) {
super(context);
this.routesMetadata=routesMetadata;
}
#Override
public void configure() throws Exception {
from(routesMetadata.getFromRoute().getTypeValue())
.setHeader(Exchange.HTTP_METHOD, simple(routesMetadata.getToRoute().getTypeMethod()))
.setHeader(Exchange.CONTENT_TYPE, constant(routesMetadata.getToRoute().getTypeContent()))
.to(routesMetadata.getToRoute().getTypeValue());
}
}
But i would like to do the route definition itself dynamically. for example, i have route config like this,
{
"config": [
{
"routeSrcSystem": "System1",
"routes": [
{
"fromRoute": {
"type": "default",
"typeValue": "direct:CMStart"
},
"toRoute1": {
"type": "http"
"typeMethod": "POST",
"typeContent": "application/json",
"typeValue": "http://localhost:8080/v1/System1/inboundMessage"
}
"toRoute2": {
"type": "http"
"typeMethod": "POST",
"typeContent": "application/json",
"typeValue": "http://localhost:8080/v1/System2/inboundMessage"
}
}
]
}
]
}
then in my route definition i need to add one more "to" definition dynamically. its just example. it could be more dynamic. for example, configuration can be changed to introduce "process" or "bean" or "class" definition. so based on the config, we need to decide how many "to" to be created and how many "process" to be created and etc. I might need to call the next rest end point after some validation and etc and some times i need to call kafka to put the message in queue. i do see an option to list all routes in a list and execute it but i think we need to have flexibility to add process or to or class definition before we call next end point and this has to be based on configuration.
public class GenerateRouter extends RouteBuilder {
private RoutesMetadata routesMetadata;
public GenerateRouter(CamelContext context,RoutesMetadata routesMetadata) {
super(context);
this.routesMetadata=routesMetadata;
}
#Override
public void configure() throws Exception {
from(routesMetadata.getFromRoute().getTypeValue())
.setHeader(Exchange.HTTP_METHOD, simple(routesMetadata.getToRoute().getTypeMethod()))
.setHeader(Exchange.CONTENT_TYPE, constant(routesMetadata.getToRoute().getTypeContent()))
.to(routesMetadata.getToRoute().getTypeValue())
.setHeader(Exchange.HTTP_METHOD, simple(routesMetadata.getToRoute().getTypeMethod()))
.setHeader(Exchange.CONTENT_TYPE, constant(routesMetadata.getToRoute().getTypeContent()))
.to(routesMetadata.getToRoute().getTypeValue());
}
}
I saw some information where route definition itself can be defined dynamically and i am doing research on it. but meantime i would like to post this here to get experts opinion. Also, please suggest whether I am using the camel on right way? because in my use case i am thinking to add "to" definition to which pass the class name dynamically based on configuration file, so that application developer can do their logic for transformation, enrich or manipulation in this class on the fly before deliver to target system. please let me know if we have any better approach. also, let me know whether XML way of doing is good way or defining own config file in json format is a good way to create dynamic route.
i am planning to read the json file and create a router definition as a string dynamically. but i would need to load this string as a definition in context it seems. i think i am missing this part.
.to("class:com.xxx.camel.layoutTransform?method=layout()")
if we provide all these configurations in xml file and if camel supports to create the route definition automatically using this file then we can consider this option as well.
Below is the one of the way from another source to create the router definition using XML file. within the XML, we have router information defined and this xml considered as a string and this string is converted as router-definition object and finally added into context.
<routes
xmlns=\"http://camel.apache.org/schema/spring\">
<route>
<from uri='direct:c'/>
<to uri='mock:d'/>
</route>
</routes>
CamelContext context = new DefaultCamelContext();
context.setTracing(true);
String xmlString = "<routes xmlns=\"http://camel.apache.org/schema/spring\"><route><from uri='direct:c'/><to uri='mock:d'/></route></routes>";
InputStream is = new ByteArrayInputStream(xmlString.getBytes());
RoutesDefinition routes = context.loadRoutesDefinition(is);
context.addRouteDefinitions(routes.getRoutes());
context.start();
ProducerTemplate template = null;
template = context.createProducerTemplate();
template.start();
template.sendBody("direct:c", "HelloC");
Thread.sleep(10000);
context.stop();
I would like to do the similar concept using java dsl definition as a string.
for example, if i have string as below then can this be converted as a router definition?
String dslString = "from("direct:starting").to("seda:end")";
Here is my use case. Sometime, we want to call 2 http services as below
from("direct:start").to(http://localhost:8080/service1).to("http://localhost:8080/service2")
Somtimes we might need to call 3 services as like below
from("direct:start").to(http://localhost:8080/service1).to("http://localhost:8080/service2").to("http://localhost:8080/service3")
sometimes we need to do transformation before we invoke service2 as like below.
from("direct:start").to(http://localhost:8080/service1).to("class:com.xxx.yyy").to("http://localhost:8080/service2").to("http://localhost:8080/service3")
In the even driven architecture, we will have set of routes must be defined for each event types. so the idea is, if we define these routes in a table for each event type, then at the time of service start up all the routes will be loaded in context and will be started. I am able to do the same in XML DSL way but trying to do the same in java DSL.
Thanks in advance!
Camel supports defining all details about routes in a particular XML-based format. This page has links to that (and other) DSLs.
You could definitely come up with your own DSL and build routes dynamically, but that's a lot of work if you want to support all the things a full Camel DSL would support. I would suspect that is not the right solution for whatever your use-case.
If you have certain patterns to your routes, you can create fairly dynamic Camel route-builders that are driven by some configuration. To make this concrete, let's say you have many use cases that follow a very similar pattern... say, consumer data from files in a folder, do a few transformations from a menu of (say) 10-15 transformations, and then sends output to one of many queues.
Since you have various possible combinations, it could make sense to configure those details in file etc. and then build some routes off that. The trade-off is not different from any other place where you have to decide if it is clearer to just code the 10 things you want, or to make something more complex but generic.
Essentially, you would still be creating a DSL or sorts, but one that is closer to your use case.

reading appSettings from asp.net core webapi

I have an asp.net core 2 webapi service. I want to read appsettings.json but I cannot figure it out. As usual, when I search the internet I get a dozen completely different answers based on various versions of the framework that ultimately don't seem to work.
As an example appsettings.json:
"AppSettings": {
"Domain": "http://localhost"
}
Firstly I tried this:
Added via nuget Microsoft.Extensions.Configuration and Microsoft.Extensions.Configuration.Json
In my ConfigureServices method I added:
services.AddSingleton<IConfiguration>(Configuration);
In my Controller I injected the config:
IConfiguration iconfig;
public ValuesController(IConfiguration iConfig)
{
iconfig = iConfig;
}
To retrieve it:
return "value: " + iconfig.GetValue<string>("AppSettings:Domain");
I can see the controller constructor being called and passing in a config, but the value is always null.
I did notice that Startup already passes in an IConfiguration. Is it a case of yet another change in implementation and i need to do something different?
[edit]
I've now read
https://joonasw.net/view/aspnet-core-2-configuration-changes
Which says it's all change again and it's auto injected, but after following the code it doesn't actually say how you get your hands on the data in your controller.
You can take a look at my answer here: https://stackoverflow.com/a/46940811/2410655
Basically you create a class that matches the properties you define in appsettings.json file (In the answer it's the AppSettings class).
And then in ConfigureServices(), you inject that class using services.Configure<>. That class will be available in all Controllers by DI.
To access its data, you can take a look at #aman's original question post from the link above.
public class HomeController : Controller
{
private readonly AppSettings _mySettings;
public HomeController(IOptions<AppSettings> appSettingsAccessor)
{
_mySettings = appSettingsAccessor.Value;
}
}

How to override a web api route?

I am trying to standardize an extension model for our REST API development team. We need to provide default implementation of routes, while allowing for custom implementations of routes that replace the default as well.
As a simple example if we have a GET route api/users like this:
public class DefaultUsersController : ApiController
{
[HttpGet]
[Route("api/users", Order = 0)]
public IEnumerable<string> DefaultGetUsers()
{
return new List<string>
{
"DefaultUser1",
"DefaultUser2"
};
}
}
We expect the default work like this:
Now a developer wants to change the behavior of that route, he should be able to simply define the same route with some mechanism to imply their implementation should be the one used, instead of the default. My initial thinking was to use the Order property on the Route attribute since that's what it appears to be there for, as a way to provide a priority (in ascending order) when an ambiguous route is discovered. However it's not working that way, consider this custom implementation that we want to override the default api/users route:
public class CustomUsersController : ApiController
{
[HttpGet]
[Route("api/users", Order = -1)]
public IEnumerable<string> CustomGetUsers()
{
return new List<string>
{
"CustomUser1",
"CustomUser2"
};
}
}
Notice the Order property is set to -1 to give it a lower priority value than the default, which is set to 0. I would have thought this would be used by the DefaultHttpControllerSelector, but it isn't. From the DefaultHttpControllerSelector:
And we end up with this exception being returned in the response:
Is it possible Microsoft just missed the logic/requirement to use Order as a route disambiguator and this is a bug? Or is there another simple way to override a route, hopefully with an attribute?
I have pretty much the same problem. I am creating a starter site, but I want users to be able to redefine to behaviour of a Controller, especially if there is a bug.
I use Autofac to resolve the Controller, but even when I register the new controller as the old one, the original one gets selected.
What I'll do is probably go with URL Rewriting. Especially since this issue is temporary in my case. However, I would be interested if someone has a better option.

ZF2: Injecting Session management into a service

I'm familiar with how to use the Session in ZF2, e.g.
$user_session = new Container('user');
$user_session->username = 'JohnDoe';
This is fine, but if I'm trying to persist session data in one of my business logic services I'd strongly prefer to inject a session management object/service into my service's constructor, like in this pseudocode:
class BusinessSvc{
protected $sessionSvc;
function __construct($sessionSvc){
$this->sessionSvc = $sessionSvc;
}
public function doBusinessLayerStuff(){
... do stuff ...
$this->sessionSvc->store('lastOrderNumber', '1234');
... do stuff ...
}
}
I would think the framework would provide this functionality, but I can't find it anywhere. I could always write my own, but didn't want to reinvent the wheel.
The answer was a lot simpler than I realized. Once instantiated, a Container instance itself can be injected into the business service and provide it with access to the session. If using phpunit to later test the service, the object could be mocked with an array or an instance of ArrayObject.
In Module.php's getServiceConfig method:
'MyModule\Service\BusinessService' => function($sm) {
// Container doesn't need to use this name but it seems sensible.
$container = new Container('MyModule\Service\BusinessService');
return new Service\BusinessService($container);
},

Make Doctrine use result cache by default

I'm binding Memcache to Doctrine and it seems I have to useResultCache explicitly in every query. Is it possible to make it true by default, with the ability to useResultCache(false) where it's not needed?
Create a wrapper class/function that explicitly sets useResultCache(true) and use that everywhere instead of the native function.
I know this question is old, but I'll write up the best answer that comes into my mind.
1) Abstract away your dependency to interface ( i.e. - use dependency injection pattern to inject EntityManager into your class that creates queries and use EntityManagerInterface instead )
Now, either:
a) [ Better, but longer ] Create a new composition-related implementation for EntityManagerInterface, that will proxy calls to original entityManager and will set result cache flag to true:
<?php
class CachedEntityManager implements EntityManagerInterface {
private $proxiedManager;
public function __construct(EntityManagerInterface $proxiedManager) {
$this->proxiedManager = $proxiedManager;
}
public function createQuery($dql = '') {
$query = $this->proxiedManager->createQuery($dql);
$query->useResultCache(true);
}
[... proxy all the calls forth to proxiedManager ...]
}
b) [ Not as good, but shorter ] Extend the EntityManager class and override the createQuery. Remember that this in general is not a good practice and you should definitely not write anything in that class anymore but instead refactor into a) :
<?php
class CachedEntityManager extends EntityManager {
public function createQuery($dql = '') {
$query = parent::createQuery($dql);
$query->useResultCache(true);
}
}
You can hack the Doctrine core a little by setting the default value of $_useResultCache to TRUE in \Doctrine\ORM\AbstractQuery. This will make all queries use the resultCacheDriver by default, and you can easily turn the cache off for individual queries using $query->useResultCache(FALSE)
It's a useful little hack that saves you a lot of typing, but be careful; I've found that the caching driver won't cache lazy-loaded associations that haven't been initialized (which is obvious now I think about it). Sometimes it's safer to just turn result caching on for each individual query.

Resources