I'm trying to convert a Grails 2 app into a couple of Spring Boot apps, with the re-use for now with all the GSPs. Nice boot plugin created by Lari Hotari & Graeme Rocher
https://github.com/grails/grails-boot
I'm trying to see a way that I can use content negoeation I followed a useful spring blog on the topic and I've been looking into the GspAutoConfiguration See link for more info
Doesn't appear to be a simple way that I can see to still use the GSP Template Engine from the GSP configuration to confgure content negotiation in the MvcConfig in the configureContentNegotiation bean
Gradle.build
def grailsVersion = '2.4.4'
compile "org.grails:grails-gsp-spring-boot:1.0.0"
compile "org.grails:grails-web-gsp:$grailsVersion"
compile "org.grails:grails-web-gsp-taglib:$grailsVersion"
compile "org.grails:grails-web-jsp:$grailsVersion"
compile("javax.servlet.jsp:javax.servlet.jsp-api:2.3.1")
//ensures that the embedded servlet container doesn’t interfere with the servlet container to which the war file will be deployed
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat:1.2.3.RELEASE'
(snipped ...)
Spring MVC Configuration
#Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {
(snippet...)
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false)
.favorParameter(true)
.parameterName("format")
.ignoreAcceptHeader(true)
.useJaf(false)
.defaultContentType(MediaType.TEXT_HTML)
.mediaType("json", MediaType.APPLICATION_JSON)
}
/**
* Create the CNVR. Specify the view resolvers to use explicitly. Get Spring to inject
* the ContentNegotiationManager created by the configurer (see previous method).
*/
#Bean
public ViewResolver contentNegotiatingViewResolver(ContentNegotiationManager manager) {
// Define the view resolvers
List<ViewResolver> resolvers = new ArrayList<ViewResolver>();
//NOT this simple due to the way GspAutoConfiguration ovverrides so much view based behaviour
InternalResourceViewResolver r2 = new InternalResourceViewResolver()
r2.setPrefix("/templates/views")
r2.setSuffix(".gsp")
resolvers.add(r2)
JsonViewResolver r1 = new JsonViewResolver()
resolvers.add(r1)
// Create the CNVR plugging in the resolvers and the content-negotiation manager
ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
resolver.setViewResolvers(resolvers);
resolver.setContentNegotiationManager(manager);
return resolver;
}
}
Related
I wonder how I can invoke a custom health indicator:
in the same application
of another Spring Boot application
My application is split into a base application (rather a configuration) A which implements nearly all the functionality (having no main method) and another application B (having a main method ;-) ) having the base configuration as a dependency in the POM.
In A I have implemented a custom HealthIndicator:
#Component
#RequiredArgsConstructor
public class AdapterDownstreamHealthIndicator implements HealthIndicator {
private RestTemplate restTemplate;
private String downStreamUrl = "http://localhost:8081/actuator";
public AdapterDownstreamHealthIndicator(RestTemplate restTemplate, String downStreamUrl) {
this.restTemplate = restTemplate;
this.downStreamUrl = downStreamUrl;
}
#Override
public Health health() {
// try {
// JsonNode resp = restTemplate.getForObject(downStreamUrl + "/health", JsonNode.class);
// if (resp.get("status").asText().equalsIgnoreCase("UP")) {
// System.out.println("JUHUUUUUUUUUUU!!!!");
// return Health.up().build();
// }
// } catch (Exception ex) {
// return Health.down(ex).build();
// }
return Health.down().build();
}
}
In my application.properties I have some actuator properties:
management.endpoints.web.exposure.include=health,info,prometheus,adapterDownstream
spring.jackson.serialization.INDENT_OUTPUT=true
management.endpoint.health.show-details=always
When I enter http://localhost:9091/actuator/health/adapterDownstream in a browser the debugger does not stop in the health() method and I simply get an empty page displayed.
I already tried to extend AbstractHealthIndicator instead of implementing HealthIndicator interface.
What am I doing wrong that the custom health indicator is not recognized?
In the end I want to make some kind of deep health check to test all components being used in my application. Maybe using CompositeHealthContributor should be used???
As I described I have a dependency A which has NO main method which is loaded into my application B as a dependency in the POM. So far I tried to implement the custom healthcheck class/the health indicator in this dependency/module A.
The simple solution is to add a
#ComponentScan(basePackages = "path.to.actuator") to the main method of the application.
The pact-jvm-provider-spring states that for junit5 provider test, it is not required to use the spring library.
However, #PactBroker annotation depends on the system properties. Is there a way to get this working for application properties via the Spring Property Resolver. I tried to create something similar to SpringEnvironmentResolver.kt and used it in the context setup. But that did not work.
#Provider("api-provider-app")
#PactBroker
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#ActiveProfiles("test")
public class PactVerificationTest {
#LocalServerPort
private int port;
#Autowired
private Environment environment;
#TestTemplate
#ExtendWith(PactVerificationInvocationContextProvider.class)
void testTemplate(Pact pact, Interaction interaction, HttpRequest request,
PactVerificationContext context) {
context.setTarget(new HttpTestTarget("localhost", port));
context.setValueResolver(new SpringResolver(environment));
context.verifyInteraction();
}
}
I get the following error
Invalid pact broker host specified ('${pactbroker.host:}'). Please provide a valid host or specify the system property 'pactbroker.host'.
Update
After some more searching found out that the setTarget was not working and that needs to be moved to #BeforeEach method.
#BeforeEach
void setContext(PactVerificationContext context) {
context.setValueResolver(new SpringResolver(environment));
context.setTarget(new HttpTestTarget("localhost", port));
}
The following snippet helped it work with #PactFolder annotation. But the #PactBroker with properties is still not working
There is a new module added to Pact-JVM that extends the JUnit5 support to allow values to be configured in the Spring Context. See https://github.com/DiUS/pact-jvm/tree/master/provider/pact-jvm-provider-junit5-spring. It will be released with the next version of Pact-JVM, which will be 4.0.7.
Requirement
For Cloud, datastore needs to change namespace dynamically. (example store kind as per company Name)
Used Spring cloud DataRepository with Springboot for same
Issue
We need to declare spring.cloud.gcp.datastore.namespace in application.properties which is static.
Is there any way to change this dynamically with CRUDReposity of spring cloud
Thanks in advance
You can change anything you want in your application.properties at runtime using Spring Cloud Config.
Spring Cloud Config provides server-side and client-side support for externalized configuration in a distributed system. With the Config Server, you have a central place to manage external properties for applications across all environments. The concepts on both client and server map identically to the Spring Environment and PropertySource abstractions, so they fit very well with Spring applications but can be used with any application running in any language.
Just as a quick example on how you can use this , you should firstly add the dependency : eg gradlecompile group: 'org.springframework.cloud', name: 'spring-cloud-starter', version: '1.1.1.RELEASE', then you need to add the #RefreshScope on the desired configuration bean.
You will be able to view your current config at a certain endpoint, like "applicationConfig: [classpath:/application.properties]": {
"my.property": "value1",
etc
And then you can change the properties as you wish doing a POST request like :
curl -X POST http://localhost:8080 -d my.property=value2
There is also a nice article about dynamically reloading the properties in a Spring application here. It is nice because they actually display more ways that you can achieve that.
You can use DatastoreNamespaceProvider which can dynamically return needed namespace.
Was added in this PR PR
Also see this discussion here and this recommendation
#Component
#RequiredArgsConstructor
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
public class HeaderValueProvider implements Supplier<String>, DatastoreNamespaceProvider {
private final HttpServletRequest httpServletRequest;
#Override
public String get() {
return httpServletRequest.getHeader("someHeader");
}
}
And this
#Component
public class UserContextProvider implements DatastoreNamespaceProvider, Consumer<UUID> {
private static final ThreadLocal<UUID> USER_CONTEXT = new ThreadLocal<>();
#Override
public String get() {
return ofNullable(USER_CONTEXT.get())
.map(UUID::toString)
.orElse(null);
}
#Override
public void accept(UUID uuid) {
USER_CONTEXT.set(uuid);
}
}
What seemed to be a simple task has turned out to be a few hours of suffering.
I am building a Spring 3.1 MVC application on the JavaEE 6 and Servlet 3.0.1 api without a web.xml file. I have a WebMvcConfiguration class like this fragment:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "be.collectortools.collectorsite")
public class MvcConfig extends WebMvcConfigurationSupport {
#Bean
public ReloadableResourceBundleMessageSource messageSourceBean() {
String[] basenames = {"classpath:messages"};
ReloadableResourceBundleMessageSource resourceBundle = new ReloadableResourceBundleMessageSource();
resourceBundle.setBasenames(basenames);
resourceBundle.setDefaultEncoding("UTF-8");
return resourceBundle;
}
}
I have successfully setup Apache Tiles 2.2.2 together with 2 basic controllers.
Now I would like to add ResourceBundles to the working Spring/Tiles application and I can't get them to work.
After searching I found some this that might go wrong:
Do I use fmt:message key="application.header" or should I use spring:message code="application.header" in my JSP pages? The first ignores not found values the second throws errors.
I use ReloadableResourceBundleMessageSource which should be 'better' or at least newer then ResourceBundleMessageSource is this ok?
ReloadableResourceBundleMessageSource loads files from more locations so I have specified classpath:
I placed the messages.properties file in the src/main/resources folder
Is it still correct that, when not adding a locale to the end of a bundle's name, this is used as a (default) fallback? Either way adding the "en_US" locale doesn't help.
The error:
root cause
javax.servlet.jsp.JspTagException: No message found under code 'application.header' for locale 'en_US'.
org.springframework.web.servlet.tags.MessageTag.doStartTagInternal(MessageTag.java:184)
also the war file is not being run inside Eclipse I deploy it manually to my local tomcat 7.0.23. This also allows me to see the deployed file structure more easily and gives me better control.
I have no clue what is I am doing wrong any help would be appreciated.
The MessageSource bean has to be named messageSource not messageSourceBean - if you change your #Bean to the following it should resolve the messages correctly:
#Bean
public ReloadableResourceBundleMessageSource messageSource() {
String[] basenames = {"classpath:messages"};
ReloadableResourceBundleMessageSource resourceBundle = new ReloadableResourceBundleMessageSource();
resourceBundle.setBasenames(basenames);
resourceBundle.setDefaultEncoding("UTF-8");
return resourceBundle;
}
I have 2 POJOs, in which one of them is an EJB and the other is a helper class.
//EJB Bean class
#Singleton
#LocalBean
#Startup
public class EJBBean{
#PostConstruct
public void init(){
HelperClass helper = new HelperClass();
helper.init();
}
}
//Helper class
public class HelperClass{
private static Log LOG = LogFactory.getLog("HelperClass");
private static Long currentTime = new Date().getTime();
public void init(){
//Some statements that use Log and do other Initialization
}
}
When I deploy this EJB jar I am getting an error
java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
I have the commons-logging-1.1.1.jar in the classpath; also, I have configured it to use Log4J. As a standalone app that is without EJB meta-data it works fine. Am I missing some EJB config?
BTW I am pretty new to EJB. I am using GlassFish 3.1, Eclipse Helios as IDE and EJB3.1.
This could be because you put the commons-logging-1.1.1.jar into the wrong directory or because your server already provides server-wide library which consists of logging classes.
By the way - I remember a lot of strange 'NoClassDefFoundError' because of mixing commons-logging, log4j and slf4j (especially in mismatching versions).