catalina.base system property override in spring-boot? - eclipse

My project uses the catalina.base system property to get resources relative to that property's folder location. When working in Eclipse, I pass -Dcatalina.base=. as a VM argument to the application's Main class.
My Main class is implemented like this:
#ComponentScan
#EnableAutoConfiguration
public class Main {
private static final Logger logger = LogManager.getLogger();
public static void main(String[] args) {
if ( logger.isDebugEnabled() ) {
String debugCatalinaBase = System.getProperty("catalina.base");
// here catalinaBase is set to "." as expected.
logger.debug("catalinaBase: {}", debugCatalinaBase);
}
SpringApplication.run(Main.class, args);
}
}
As part of this project, I then have an ApplicationConfig class which is implemented like this:
#Configuration
public class ApplicationConfig {
private static final Logger logger = LogManager.getLogger();
#Value("${catalina.base}")
private String catalinaBase;
#Bean
public Properties jndiProperties() {
if ( logger.isDebugEnabled() ) {
String debugCatalinaBase = System.getProperty("catalina.base");
// here catalinaBase is set to "C:\Users\theUser\AppData\Local\Temp\tomcat.8558104871268204693.8081". NOT as expected!!!
logger.debug("catalinaBase: {}", debugCatalinaBase);
}
Properties properties = new Properties();
properties.setProperty(Context.INITIAL_CONTEXT_FACTORY,
CnsContextFactory.class.getName());
properties.setProperty(Context.PROVIDER_URL,
"file:" + catalinaBase + "\\conf\\jndi.properties");
return properties;
}
#Bean( name = "propertyConfigurer" )
public static PropertySourcesPlaceholderConfigurer propertyConfigurer() {
PropertySourcesPlaceholderConfigurer configurer =
new PropertySourcesPlaceholderConfigurer();
return configurer;
}
}
As you can see in the code snippet's comments, in ApplicationConfig the catalina.base system property has changed and I am not sure why or where this happened?
For info, my project uses spring-boot-starter-xxx:1.1.4.RELEASE jars, and spring-xxx:4.0.6.RELEASE jars.
Also, I have another project which follows pretty much the same overall pattern and uses the same jars and that project always sees catalina.base set to "." as expected. So I am wondering if the problem has something to do with the order in which spring configurations are loaded in the problematic project or something along those lines?
Thanks in advance for any help on this.
PM

String Boot calls Tomcat.setBaseDir(...) from TomcatEmbeddedServletContainerFactory using a temporary directory as the source. Tomcat actually sets the catalina.base property when the initBaseDir() method in org.apache.catalina.startup.Tomcat is called.
You need to add server.tomcat.basedir to your application.properties if you don't want Spring Boot to use a temp folder.

Related

How to properly create Spring Cloud Task with custom parameters?

According to the samples here (actually - timestamp task), I have implemented a small task class:
#SpringBootApplication
#EnableTask
#EnableConfigurationProperties({ RestProcessorTaskProperties.class })
public class RestProcessorTaskApplication {
public static void main(String[] args) {
SpringApplication.run(RestProcessorTaskApplication.class, args);
}
#Autowired
private RestProcessorTaskProperties config;
// some fields and beans
#Bean
public CommandLineRunner run(RestTemplate restTemplate) {
return args -> {
// doing some stuff
};
}
}
and then I've created Properties class (in the same package)
#ConfigurationProperties("RestProcessor")
public class RestProcessorTaskProperties {
private String host = "http://myhost:port";
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
}
But after I've registered task on my local Spring Cloud Data Server, I see numerous parameters, that, I suppose, was added automatically. I those mean parameters like:
abandon-when-percentage-full java.lang.Integer
abandoned-usage-tracking java.lang.Boolean
acceptors java.lang.Integer
access-to-underlying-connection-allowed java.lang.Boolean
and others...
Is it possible somehow to hide (or remove) them, so that when launching task I could configure only those parameters, that was added by me (single host property in my example above)?
By default Spring Cloud Data Flow will show you all the available properties for a boot application. However, you can create a whitelist of properties that you wish to show.
Here is a link to the Spring Cloud Data Flow reference doc that will discuss how to do this: http://docs.spring.io/spring-cloud-dataflow/docs/current/reference/htmlsingle/#spring-cloud-dataflow-stream-app-whitelisting.
And here is link to the timestamp starter app that has an example of this: https://github.com/spring-cloud/spring-cloud-task-app-starters/tree/master/spring-cloud-starter-task-timestamp

guice JpaPersistModule with runtime configuration

I need to share datasource with JpaPersistModule. This datasource is provided by guice injector.
Now the problem I have to build module during configuration phase, but datasource is available only in runtime.
Currently I have following code:
public class MyJpaConfigurationModule implements Module {
private Map<String, Object> jpaProperties = new HashMap<>();
private Module jpaModule = new JpaPersistModule("peristenceUnit").properties(jpaProperties);
public void configure(Binder binder) {
binder.requestInjection(this);
binder.install(jpaModule);
}
#Provides #Singleton
public DataSource provideDatasource() {
return ..... // some data source
}
#Inject
public void setJpaProperties(DataSource dataSource, PersistService persistService) {
jpaProperties.put("dataSource", dataSource);
persistService.start();
}
}
I have checked and it seems that jpa properties map is everywhere injected by reference, so my runtime changes should become visible, but what if this changes in future?
What is the correct way to resolve such conflicts?

Xtext Elements Access

I have written in Xtext:
grammar org.xtext.example.dsl.Dsl with org.eclipse.xtext.common.Terminals
generate dsl "http://www.xtext.org/example/dsl/Dsl"
Dsl :
(elements += Type)*
;
Type:
System
;
System:
'The system' name = ID 'consists of the following:
;
And now I run the editor and type in a system name.
How can I acces the System name in my Eclipse file?
Here is the soulution.
Write the following code in src folder in org.example.somthing.generator package and class is Something.xtend (.xtend)
This is for code generation and it is generated by xtext. You will find doGenerate(Resource resource, IFileSystemAccess fsa) method write following code in that method..
class DomainmodelGenerator implements IGenerator {
#Inject extension IQualifiedNameProvider
override void doGenerate(Resource resource, IFileSystemAccess fsa) {
for(e: resource.allContents.toIterable.filter(DSL)) {
fsa.generateFile("abcd.txt",e.compile)
}
def compile(DSL d) '''
«d.System.name»'''
}
Now you have to write the main class to call the method of above class..
Here is the code...
public class Main {
#Inject
private Provider<ResourceSet> resourceSetProvider;
#Inject
private IResourceValidator validator;
#Inject
private IGenerator generator;
#Inject
private JavaIoFileSystemAccess fileAccess;
public static void main(String[] args) {
Injector injector = new DomainmodelStandaloneSetupGenerated()
.createInjectorAndDoEMFRegistration();
Main main = injector.getInstance(Main.class);
main.runGenerator("sample.dmodel");
}
protected void runGenerator(String string) {
// load the resource
ResourceSet set = resourceSetProvider.get();
Resource resource = set.getResource(URI.createURI(string), true);
List<Issue> list = validator.validate(resource, CheckMode.ALL,
CancelIndicator.NullImpl);
if (!list.isEmpty()) {
for (Issue issue : list) {
System.err.println(issue);
}
return;
}
// configure and start the generator
fileAccess.setOutputPath("output/");
generator.doGenerate(resource, fileAccess);
System.out.println("Code generation finished.");
}
}

How to access XSSAPI from custom jsp Java class?

I am creating a custom tag library using http://www.cqblueprints.com/xwiki/bin/view/Blue+Prints/Writing+A+JSP+Custom+Tag+Library to produce XSS-proof links from my custom components. I have taken this to a tag since I will need to do other bits of work and to avoid writing scriptlets on the JSP files (I have posted the code at the end).
I wanted to use the XSSAPI from my Java class, but looking at the javadoc for XSSAPI I see that it's an interface; when using it in a JSP file it's an object that is initialized invoking <cq:defineObjects/>.
Does anyone have any ideas on how to do this? There is a method in the XSSAPI class called getRequestSpecificAPI(slingRequest) but it's not static, and I have run out of ideas right now.
#JspTag
public class FixInternalLinkTag extends CqSimpleTagSupport {
private String pathToPage;
#Override
public void doTag() throws JspException, IOException {
XSSAPI xssAPI; // ToDo how to get a reference to this?
urlPointingToPage = xssAPI.getValidHref(urlPointingToPage);
getJspWriter().write(urlPointingToPage);
}
public String getPathToPage() {
return pathToPage;
}
#JspTagAttribute(required = true, rtexprvalue = true)
public void setPathToPage(String pathToPage) {
this.pathToPage = pathToPage;
}
}
If you make your tag class an osgi service
#Component(immediate = true, metatype = true, description = "User Group Finder")
#Service
public class MyClass { ...
you can then use
#Reference
XSSAPI xssapi;
to pull in the implementation of XSSAPI. Then you can use it
xssapi.getRequestSpecificAPI(slingRequest);

How to get plugins by setting a path

I created console c# project. and in the code I have made a module. My code looks like this.
[Import]
public IMessageSender MessageSender { get; set; }
public static void Main(string[] args)
{
Program p = new Program();
p.Run();
}
public void Run()
{
Compose();
Console.ReadLine(MessageSender.Send("Message Sent"));
}
private void Compose()
{
AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
public interface IMessageSender
{
string Send(string message);
}
[Export(typeof(IMessageSender))]
public class EmailSender : IMessageSender
{
public void Send(string message)
{
return message;
}
}
It works perfectly fine. But now I added a new project in my solution and added module into that
AnotherProject->EmailSender.cs
[Export(typeof(IMessageSender))]
public class EmailSender : IMessageSender
{
public void Send(string message)
{
return message;
}
}
Now in the main console program I changed some of my code.
private void Compose()
{
var catalog = new DirectoryCatalog(path);
//AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
But now when I run this program. It doesnt load the module. MessageSender in main program is null. What wrong I have done.
There are a few things you need to check:
Have you correctly referenced the assemblies?
The DirectoryCatalog by default uses the search pattern *.dll. Because you have a console application, which uses the .exe extension, no exports in that assembly will get picked up by the DirectoryCatalog - with the default search pattern. You'll likely want to use an AggregateCatalog, passing in the DirectoryCatalog (*.dll), and either another DirectoryCatalog (*.exe), or an AssemblyCatalog, of the entry assembly.
You currently have one [Import] where you may end up with multiple [Export(typeof(IMessageSender))], you didn't state that you have moved the EmailSender to the class library, merely that you have created a new one, which means you'll likely end up with a cardinality mismatch where it is expecting a sinple import, you have many exports. This will explicitly throw an exception, which is what will happen even it couldn't find a single instance of IMessageSender, because your [Import] attribute is not set to allow a default value where no part can be provided. If you need to be fault tollerant, you can use [Import(AllowDefault = true)]
Incidentally... the above code won't compile, I assume it was just an example and not a copy-paste from your current code?
public void SendMessage(string message)
{
return message;
}
You're retuning a message to a void method - that can't be done, and it also means that EmailSender doesn't correctly implement IMessageSender. Not too bothered, as I think it is an example more than actual code.