I know you can create several custom environment for grails.
My question is i want these custom environment to be for production mode (each environment for each department with different DB and configuration).
Are there any special way to define them ? if i deploy them as is, will the war be performant or a testing war ?
Thanks
The correct way to address this is through the use of Externalized Configuration.
By doing so you will give each department the flexibility of configuring your application for their environment and you won't need to package your application for each department.
I don't have a complete solution, but I'll share what I know.
The ServletContext provides init parameters that can be set up outside of the app. The servlet container then makes them available to the app/context. The method which returns these parameters is called initParameterNames().
For example, lets say I'm running the app with Tomcat 8 and the app is called example-app. To set up some init parameters I'd create the file $CATALINA_BASE/conf/Catalina/localhost/example-app.xml
In the file, I'd save my parameters like this:
<Context>
<Parameter name="environments.production.dataSource.url" value="jdbc:h2:anotherProdDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE" override="true" />
</Context>
From Grails I would be able to access this value from the ServletContext. For example, from a GSP I can read the value like this:
application.getInitParameter('environments.production.dataSource.url')
Ideally, I would merge the init parameters with the Grails config (grailsApplication.config) early in the start up process so that the init parameters override the Grails config. But I could not figure out how to it. The Grails config is accessible from GrailsAutoConfiguration (and apparently modifiable) like this:
import grails.boot.GrailsApp
import grails.boot.config.GrailsAutoConfiguration
import grails.boot.config.GrailsApplicationPostProcessor
import grails.core.GrailsApplication
class Application extends GrailsAutoConfiguration {
static void main(String[] args) {
GrailsApp.run(Application, args)
}
GrailsApplicationPostProcessor grailsApplicationPostProcessor() {
def processor = super.grailsApplicationPostProcessor()
processor.grailsApplication.config.setAt('environments.production.dataSource.url', 'testing...')
return processor
}
}
But I don't know how access the ServletContext within the grailsApplicationPostProcessor() in order to override the Grails config with init parameters.
Related
I'm starting a new project using Symfony 3.3. I'm would like to use the new autoconfigure/autowiring features but I'm running into an "issue" I'm not sure how to solve.
I have the following services definition coming from an external bundle:
command_bus:
class: Name\Space\To\MessageBusSupportingMiddleware
...
event_bus:
class: Name\Space\To\MessageBusSupportingMiddleware
...
Both services are based on the same "MessageBusSupportingMiddleware" class but their intention is totally different of course.
Now I want Symfony 3.3 to automatically inject the "command_bus" service into my controller. But for this, I would have to use the class in the constructor like this:
public function __construct(
MessageBusSupportingMiddleware $commandBus
){
$this->commandBus = $commandBus;
}
In this case though, Symfony complains because it actually finds several service definition related to this class and so it cannot know which one to provide.
How do you think I could handle this situation ?
I actually find a way to overcome this situation.
I have create two classes in my own project:
class CommandBus extends MessageBusSupportingMiddleware
{
}
class EventBus extends MessageBusSupportingMiddleware
{
}
Their only purpose is to be able to override the default service definition from the external bundle and use different implementation to be able to autowire them. My service override configuration is simply done in a services.yml file as such:
services:
command_bus:
class: CoreBundle\Bus\CommandBus
event_bus:
class: CoreBundle\Bus\EventBus
We make a lot of use of spring security core and rest plugins in many apps. So instead of configuring it in each and every app, we decided to create a private plugin to do this functionality by following Burt's blog to convert grails application to plugins.
Specified spring security core and rest in BuidConfig.groovy of private plugin.
We created MyCoreConfig.groovy file and included all spring security core and rest configuration in it, so we can merge this config with Main application config.
The problem is configuration files like BuildConfig.groovy,Config.groovy and resources.groovy(we have customUserDetailsService bean) are excluded while packaging plugin. So we are merging config and resource file in following way
def doWithSpring = {
// TODO Implement runtime spring config (optional)
mergeConfig(application)
userDetailsService(com.organisation.app.CustomUserDetailsService){
grailsApplication = ref('grailsApplication')
}
}
def onConfigChange = { event ->
// TODO Implement code that is executed when the project configuration changes.
// The event is the same as for 'onChange'.
this.mergeConfig(application)
}
private void mergeConfig(GrailsApplication app) {
ConfigObject currentConfig = app.config.grails.myCoreConfig
ConfigSlurper slurper = new ConfigSlurper(Environment.getCurrent().getName());
ConfigObject secondaryConfig = slurper.parse(app.classLoader.loadClass("MyCoreConfig"))
ConfigObject config = new ConfigObject();
config.putAll(secondaryConfig.myCoreConfig.merge(currentConfig))
app.config.grails.myCoreConfig= config;
}
Plugin works fine when all config and resource files are in their respective places.
When we test plugin by commenting configuration from Config.groovy so as to take it from newly created MyCoreConfig.groovy and deleting resources.groovy so as it can take from doWithSpring closure, spring security's core and rest functionality doesn't work.
We even packaged the plugin as jar and included in our main application, and as expected it didn't work either.
So is this approach to extract common functionality in a private plugin which depends on public plugins correct?
Where are we going wrong?
Do people separately configure spring security core or rest in every app or do they follow different methodology to achieve this?
Any pointers in the right direction would be of great help.
Thanks a ton.
Apologies, since there are lots of links out there and I have tried a few examples including stuff that already works within my project(s) that are non plugin:
What I have tried:
Within my Plugin descriptor:
def doWithSpring = {
someService(SomeService)
}
Then within my end src/groovy
//def someService = Holders.grailsApplication.mainContext.getBean 'someService'
def someService
None of above works...
If I instantiate the service everything appears to work fine, I would prefer to inject it and its just taking a lot of time doing something rather basic :(
SomeService someService=new SomeService()
Any help would be appreciated
Not that I have ever seen it before (within a plugin) should I include conf/spring/resources.groovy and initialise bean in there ?
In this case, like most cases, there's a way to access what you want without using holders. The Groovy class implements ServletContextListener, so there's a contextInitialized method with a ServletContextEvent event containing the ServletContext. So it wasn't necessary to use the ServletContextHolder to get the ServletContext - it was right there. You can see from the FAQ that the Spring ApplicationContext is stored in the ServletContext as an attribute. Once you have that, you can access whatever Spring beans you want; in this case the jenkinsService and the grailsApplication beans (you can get the config directly from the grailsApplication without using Holders for that.
I made these changes and did a bunch of cleanup, and sent a pull request.
You can inject your service in a src/groovy class like so:
import com.example.SomeService
import grails.util.Holders
class SrcGroovy {
SomeService someService = Holders.applicationContext.getBean("someService")
// ...
}
I have two Grails Projects in Eclipse. I am referencing one project inside the other with the Configure Build Path setup. Running tests however throws an error java.lang.IllegalStateException: Method on class [com.example.domain.Phone] was used outside of a Grails application. If running in the context of a test using the mocking API or bootstrap Grails correctly.
Normally this is fixed with a #Mock (using Mockito) or mockDomain(), but I am not in a unit test so these items are not seen.
How can I test my service layer through an integration test if it cannot see my domain objects that I need to use? These domain objects are separated because of the need to use them across multiple projects.
If your GORM classes are not in the same package as your Application class then you need to add the ComponentScan annotation to the Application class to indicate where you GORM classes are. Example:
#ComponentScan(basePackages=['foo.bar', 'my.company'])
class Application {
....
If you are writing tests do not forget:
Annotations in Spec. #IntegrationTest is important
#ContextConfiguration(loader = SpringApplicationContextLoader, classes = ConfigTest)
#EnableAutoConfiguration
#IntegrationTest
class PaymentServiceSpec extends Specification{
// Tests with GORM entities
}
Class where hibernate is injected
#SpringBootApplication
#Import(HibernateGormAutoConfiguration)
class CoreConfigTest {
}
Because of #IntegrationTest it is necessary to have an Application class for tests
#SpringBootApplication
class TestApplication {
static void main(String[] args) {
run TestApplication, args
}
}
I am using this dependencies:
runtime 'org.postgresql:postgresql:9.3-1102-jdbc41'
compile("org.grails:gorm-hibernate4-spring-boot:1.1.0.RELEASE") {
exclude module: 'spring-boot-cli'
exclude module: 'groovy-all'
}
compile("org.springframework.boot:spring-boot-starter-jdbc:1.2.2.RELEASE")
There is GORM for Spring Boot available. Examples in https://spring.io/guides/gs/accessing-data-gorm/
If you are writing tests, you can use the HibernateTestMixin or use HibernateDatastoreSpringInitializer to initialize GORM.
I've a Grails project where I replaced Log4j with Logback. Now I also want to use the org.slf4j.Logger instead of org.apache.commons.logging.Log class for logging. How can I change the default log object which is placed by Dependency Injection to every Controller/Service/Domain class?
I searched within the BuildConfig.groovy and Config.groovy files but I couldn't find any configuration for this? I also looked at grails-app/src/templates/artifacts/Controller.groovy but I still couldn't find any place where this could be configured...
Shure, I could get my own instance of an org.slf4j.Logger, but then I'd have to declare it within every class like
private static Logger lbLogger = LoggerFactory.getLogger(MyClass.class)
and that's not what I want - I'd love to just replace injected Logger object.
Does anybody have any suggestions on this topic?
I can't recall how the log object been injected, but anyway you can inject your own logger into controller, service or domain object.
In BootStrap:
def doWithDynamicMethods = { applicationContext ->
// def logger = SLF4J new instance
application.controllerClasses.each { controllerClass ->
controllerClass.metaClass.getLogger = {-> logger }
}
}
This is the idea, sorry I don't have the Grails env now so I can not make a workable code.