I have a service class that I expose as jaxws using the Grails Cxf plugin. In my service I have to inject another service class which I use in my web services. If I make the service field public I get unnecessary service methods generated like below:
retrieveLastRecordUpdateDate
setPricingContractService
retrieveRecordsUpdatedFromDate
retrieveAllRecordsByInsurance
getPricingContractService
If I make the field private I cannot inject the service class. How can I both inject the service and not expose it as a web service? Simplified code below:
class PricingContractWebService {
static expose = EndpointType.JAX_WS
def pricingContractService // private?
#WebMethod( operationName="retrieveAllRecordsByInsurance" )
#WebResult( name="pricingContractList" )
#XmlElement(name="healthCareCompany", required=true)
List<PricingContractDTO> retrieveAllRecordsByInsurance(#WebParam(partName = "HealthCareCompany", name = "healthCareCompany", ) final HealthCareCompany healthCareCompany) {
def pricingContractDTOList = []
pricingContractDTOList
}
#WebMethod( operationName="retrieveLastRecordUpdateDate" )
#WebResult( name="lastUpdateDate" )
Date retrieveLastRecordUpdateDate() {
}
#WebMethod( operationName="retrieveRecordsUpdatedFromDate" )
#WebResult( name="pricingContractList" )
#XmlElement(name="updateDate", required=true)
List<PricingContractDTO> retrieveRecordsUpdatedFromDate(#WebParam(name = "updateDate") final Date date) {
def pricingContractDTOList = []
pricingContractDTOList
}
}
You should make service endpoint private and add #Autowired before endpoint declaration:
#Autowired
private PricingContractService pricingContractService
Related
My test case uses #SpringBootTest annotations to bring up the context and has Autowired some repository. Testcontainer is started in #BeforeAll() method. The problem is RestClientConfig is being initialized/injected before #BeforeAll() in test case. When testcontainer starts, it exports some dynamic port.
I have to set some fixed port in testcontainer 34343 and use the same port in properties file for RestClientConfig.
container = new ElasticsearchContainer(ELASTICSEARCH_IMAGE)
.withEnv("discovery.type", "single-node")
.withExposedPorts(9200)
.withCreateContainerCmdModifier(cmd -> cmd.withHostConfig(
new HostConfig().withPortBindings(new PortBinding(Ports.Binding.bindPort(34343), new ExposedPort(9200)))));
Is there a way to start container and get its dynamic port then use it to initialize RestClientConfig?
I didn't use annoation #Testcontainers though. Is it needed?
Newer versions of Spring provide #DynamicPropertySource for exactly this use case:
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/test/context/DynamicPropertySource.html
Your code should look roughly like this:
#SpringJUnitConfig(...)
#Testcontainers
class ExampleIntegrationTests {
#Container
static ElasticsearchContainer elastic= new ElasticsearchContainer(ELASTICSEARCH_IMAGE)
.withEnv("discovery.type", "single-node");
// ...
#DynamicPropertySource
static void elasticProperties(DynamicPropertyRegistry registry) {
registry.add("spring.elasticsearch.uris", elastic::getHttpHostAddress);
}
}
You can use context configuration initialiser to set properties during runtime, which you can later use in your RestClientConfig.
Let me show you on the example of Postgresql container setup:
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class)
#ContextConfiguration(initializers = AbstractTestcontainersTest.DockerPostgreDataSourceInitializer.class)
public abstract class AbstractTestcontainersTest {
protected static final String DB_CONTAINER_NAME = "postgres-auth-test";
protected static PostgreSQLContainer<?> postgreDBContainer =
new PostgreSQLContainer<>(DockerImageName.parse("public.ecr.aws/docker/library/postgres:12.10-alpine")
.asCompatibleSubstituteFor("postgres"))
.withUsername("postgres")
.withPassword("change_me")
.withInitScript("db.sql")
.withCreateContainerCmdModifier(cmd -> cmd.withName(DB_CONTAINER_NAME))
.withDatabaseName("zpot_main");
#BeforeAll
public static void beforeAll() throws ShellExecutionException {
postgreDBContainer.start();
}
#AfterAll
public static void afterAll() {
postgreDBContainer.stop();
}
public static class DockerPostgreDataSourceInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(ConfigurableApplicationContext applicationContext) {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(
applicationContext,
"spring.datasource.url=" + postgreDBContainer.getJdbcUrl(),
"spring.datasource.username=" + postgreDBContainer.getUsername(),
"spring.datasource.password=" + postgreDBContainer.getPassword()
);
}
}
}
All the configuration is done in DockerPostgreDataSourceInitializer, where I set all the properties I need. You also need to annotate your test class with #ContextConfiguration annotaion. You can do something similar with your ElasticSearchContainer. As I just checked the ElasticSearchContainer has a method getHttpHostAddress() which returns host+dynamic_port combination for your container. You can get that host-port pair and set in in properties to be used later in your client configuration. If you need just port you can call container.getMappedPort(9200) and again set that port in properties.
Regarding #Testcontainers annotation, you need it if you want testcontainers to manage your container lifecycle. In that case you also need to annotate container with #Container annotation. Your container will be started either once before all test methods in a class if your container is a static field or before each test method if it's a regular field. You can read more about that here: https://www.testcontainers.org/test_framework_integration/junit_5/#extension.
Or you can start your container manually either in #BeforeAll or #BeforeEach annotated setup methods. In other words no, you don't have to use #Testcontainers annotation.
I have an Azure Functions project that leverages Dependency Injection (Startup.cs injects services based on the different interfaces). Those services that implement the interfaces are using constructor dependency injection as well.
In one of those implementations, I want to call a method on a Durable Entity, but I prefer not to make the DurableEntityClient part of the method signature (as other implementations might not need the EntityClient at all). So therefore, I was hoping to see that IDurableEntityClient injected in the constructor of my class.
But it turns out the value is null. Wondering if this is something that is supported and feasible? (to have a DI-friendly way of injecting classes that want to get the EntityClient for the Functions runtime they are running in)
Some code snippets:
Startup.cs
builder.Services.AddSingleton<IReceiver, TableReceiver>();
Actual Function
public class ItemWatchHttpTrigger
{
private IReceiver _receiver;
public ItemWatchHttpTrigger(IReceiver receiver)
{
_receiver = receiver;
}
[FunctionName("item-watcher")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = "item/{itemId}")]
HttpRequest request, string itemId, [DurableClient] IDurableEntityClient client, ILogger logger)
{
// Actual implementation
}
}
Referenced class
public class TableReceiver : IReceiver
{
private IDurableEntityClient _entityClient;
public TableReceiver(IDurableEntityClient client)
{
_entityClient = client; // client is null :(
}
}
Based on the answer of my github issue, it seems it is possible to inject this in Startup, since the 2.4.0 version of the Microsoft.Azure.WebJobs.Extensions.DurableTask package:
Some code snippets:
Startup.cs
builder.Services.AddSingleton<IReceiver, TableReceiver>();
builder.Services.AddDurableClientFactory();
Referenced class
public class TableReceiver : IReceiver
{
private IDurableEntityClient _entityClient;
public TableReceiver(IDurableClientFactory entityClientFactory, IConfiguration configuration)
{
_entityClient = entityClientFactory.CreateClient(new DurableClientOptions
{
TaskHub = configuration["TaskHubName"]
});
}
}
Github issue
Grails services are abstractions used for implementing business logic (as well as connecting to backing services/DBs, etc.) outside of a controller. So in a typical controller you might have:
class DashboardController {
StatisticsService statsService
def index() {
// Fetches all the stats that need to be displayed to the
// admin on the dashboard.
AdminDashboardMetrics adm = statsService.getAdminStats()
render(view: "/dashboard", model: [ adm: adm ])
}
}
Here, Grails automatically injects the DashboardController with a bean instance of StatisticsService (provided of course that the service was properly created with grails create-service ...).
But what happens when I need to access StatisticsService outside of a controller, and particularly, under src/groovy?
// src/groovy/com/example/me/myapp/FizzBuzzer.groovy
class FizzBuzzer {
StatisticsService statsService
FizzBuzzer(StatisticsService statsService) {
super()
this.statsService = statsService
}
def doSomething(MyData input) {
MoreData result = statsService.calculate(input)
// use 'result' somehow, etc....
}
}
How do I properly inject FizzBuzzer with the same StatisticsService instance ad what is passed into DashboardController?
You can inject grails service in spring bean by defining injection login in resources.groovy under conf > spring
As I made an ExampleService and Example class in src/groovy
ExampleService
class ExampleService {
def serviceMethod() {
println "do something"
}
}
Example Class under src/groovy
class Example {
ExampleService exampleService
def doSomething() {
def result = exampleService.serviceMethod()
}
}
resources.groovy under conf>spring
beans = {
ex(Example){ bean ->
exampleService = ref('exampleService')
}
}
so I can define Example ex as spring bean in grails-app and it will have ExampleService injected by itself.
Hope this helps. Thanks
You can also get a service using grails.util.Holders
Example:
For injecting MyService service class, use Holders.applicationContext.getBean("myService")
Where "myService" is the name of your service class in lower camel case.
One way of achieving this is by using ServletContext-
ApplicationContext ctx = (ApplicationContext)ServletContextHolder.
getServletContext().getAttribute(GrailsApplicationAttributes.APPLICATION_CONTEXT)
statisticsService = (StatisticsService ) ctx.getBean("statisticsService ")
see this blog - http://www.grailsbrains.com/availing-grails-goodies-in-srcjava-or-srcgroovy/
Grails 2.4.5 here. I did a grails create-service com.example.service.Simple which created a SimpleService for me, which I then modified to look like so:
class SimlpeService {
SimpleClient simpleClient
Buzz doSomething(String derp) {
// ...
Fizz fizz = simpleClient.doSomething(derp)
// ...
fizz.asBuzz()
}
}
I can now "inject" controllers with SimpleService like so:
class MyController {
SimpleService simpleService
def index() {
// etc...
}
}
But how do I configure/wire SimpleService with the correct SimpleClient instance. Let's pretend SimpleClient is typically built like so:
SimpleClient simpleClient = SimpleClientBuilder
.withURL('http://simpleclientdev.example.com/simple')
.withAuth('luggageCombo', '12345')
.isOptimized(true)
.build()
Depending on what environment I'm in, I may want my SimpleClient instance to connect to simpleclientdev.example.com, simpleclientqa.example.com, or even simpleclient.example.com. Also, I may use different auth credentials, and I might/might not want it to be "optimized", etc. The point is: How do I inject the SimpleService with a SimpleClient instance?
You can use the Java's PostConstruct annotation on one of your method in your service to do the stuff you want. From the docs:
The PostConstruct annotation is used on a method that needs to be
executed after dependency injection is done to perform any
initialization.
SimpleService.groovy
import javax.annotation.PostConstruct
class SimlpeService {
private SimpleClient simpleClient
def grailsApplication
#PostConstruct
void postConstruct() {
def config = grailsApplication.config.client.data
SimpleClient simpleClient = SimpleClientBuilder
.withURL(config.url)
.withAuth('luggageCombo', config.username)
.isOptimized(config.optimized)
.build()
}
Buzz doSomething(String derp) {
// ...
Fizz fizz = simpleClient.doSomething(derp)
// ...
fizz.asBuzz()
}
}
So, Grails or Spring will call this method postConstruct() automatically when all the dependencies (in this case grailsApplication) for this service are resolved and any of the service method is invoked.
This has been taken care that that method must invoke before you access any field member or method of the SimpleService.
Now, everything is already configured like you mentioned that you may need to call different URL with different credential, just you have to define them in your Config.groovy as:
environments {
development {
client {
data {
url = "simpleclientdev.example.com"
username = "test"
optimized = false
}
}
}
production {
client {
data {
url = "simpleclient.example.com"
username = "johndoe"
optimized = true
}
}
}
}
Now when you do run-app with development mode and calling simpleService.doSomething() in your example controller will automatically hit the simpleclientdev.example.com URL with test credential and when you deploy it using production environment, the same simpleService.doSomething() method will hit simpleclient.example.com with optimized set to true.
Update
The key point here based on your question is that we will not be injecting different instances of SimpleService since services are singleton by default. Instead we are changing the value's associated with the service based on the environment.
Sounds like you need to understand a bit more about how to leverage Spring maybe?
Grails Spring Docs
You can also do things like so in your Service class
#PostConstruct
void init() {
//configure variables, etc here ...
log.debug("Initialised some Service...")
}
I am lookin for a way to let the admin-role of my grails-app add a "feature"/"plugin"
to the running server, so that the system makes use of it instantly.
To be more concrete here is a small example:
package domains
abstract class Provider {
def protected name;
def protected activated = false;
def private valid;
def Provider( providerName ) {
if( providerName != null ) {
name = providerName;
valid = true;
else valid = false;
}
def isValid() { valid }
def getName() { name }
def isActivated() { activated }
def setActivated( bool ) { activaed = bool }
abstract List<String> search( String searchKey );
}
Some Subclass:
package googleprovider
import Provider;
class GoogleProvider extends Provider {
def GooleProvider( active ) {
super( "Google" );
activated = active;
}
#Override
List<String> search( String searchKey ) {
return ["http://www.google.com"]
}
}
Now every "plugin"/"feature" should extend from Provider and be placed as what ever file in a directory "plugins/providers/".
And the server should create an instance of this GoogleProvider on an "onAdd"-event or something leashed by that admin.
Is there any chance this could be done? Or am I totally dreaming?
If it is somehow possible and it's just that I am going a completly wrong direction,
just tell me! ;-)
Thanks for your time!
I suggest you look for plugins that registers new Artefacts, so in your startup you can lookup for this classes. You can also create a folder in grails-app to store the providers classes.
See the Grails Dao Artefacts plugin, for example. It creates the daos folder inside grails-app, and consider all classes as a DAO Artefact. You also gain the ability of use Depenceny Injection in your classes (e.g. services).
Some points to look
Install Script creates the directory
You have some classes that declare the Artefact
The plugin descriptor is responsible to register them as Spring Beans
More info in
Grails developer wiki
Blog post with example