I have a 3-tier application I have to modify. I'm totally new to the entire webstuff of Java, so bear with me please.
Currently the application has a UI, Application and Database layer but I am attempting to decouple the SQL database from the database layer using dependency injection.
So at some point I'm not going to need SQL server credentials in my application because the database backend might be plain text.
The point is that the current SQL credentials are stored in the web.xml file as init-parameters. These are fetched in servlet code as follows:
String cfgfile = getInitParameter("config_file");
properties.load(new FileInputStream(cfgfile));
//Some code..
properties.getProperty("dbUser");
This happens in the front-end, is passed to the applicationlayer constructor, which passes it on to the database constructor.
So this works, but the credentials are just passed along to the data access layer to then create a SQLDatabase.
So I figured I'd just pull these credentials in inside the SQL specific class. However, I'm stuck on how to get them out of the web.xml file.
I tried using getServletContext() but that doesnt seem to work.
I can imagine that there is no notion of any servlet at the DAL level, so I'm stuck on how to fix this.
Register ServletContextListener to load Init parameters at server start-up.
Load properties and make it visible to other classes statically.
Sample code:
public class AppServletContextListener implements ServletContextListener {
private static Properties properties;
#Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
String cfgfile = servletContextEvent.getServletContext().getInitParameter("config_file");
properties.load(new FileInputStream(cfgfile));
//Some code..
properties.getProperty("dbUser");
}
public static Properties getProperties(){
return properties;
}
}
web.xml:
<listener>
<listener-class>com.x.y.z.AppServletContextListener</listener-class>
</listener>
<context-param>
<param-name>config_file</param-name>
<param-value>config_file_location</param-value>
</context-param>
You are correct that the web.xml seems the wrong place to be defining database credentials.
It sounds like you really want to define the database credentials as properties and inject them directly into your data access layer.
As you are using Spring you might want to consider defining a DataSource within your context.xml and either defining the credentials directly in there or using a properties file. Have a look at the Spring documentation for more details.
Related
I have a file on a server available via Https I want to access using Spring's Resource abstraction. I want Spring to resolve the resource and inject it into the constructor of my Bean like this:
public class MyClass {
public MyClass(
#Value("https://myserver.com/myfile") Resource resource) {
// do something using the resource
}
}
The issue is that I cannot figure out how to include the username and password for basic authentication into this pattern. I tried the "common" style
#Value("https://username:password#myserver.com/myfile")
but it looks like this is not understood correctly. The server is responding with HTTP status 401 - Unauthorized. I copied the string and perfomed the same query using wget and it worked. So there is no issue with my credentials but most likely with the syntax used to define the resource.
Is there a valid syntax for this in Spring or must I fetch the config in an alternative way setting the Authentication header by hand?
This feels wrong, and I'd prefer it if you didn't do it this way...but you can rely on #Value to inject the property value. Note the use of #Autowired here.
#Component
public class MyClass {
private String resourceUrl;
#Autowired
public MyClass(#Value(${external.resource.url}) String resourceUrl) {
this.resourceUrl = resourceUrl;
}
// The rest of your code
}
Then you could place into the property external.resource.url whichever value you liked...including your full URL with username and password.
I want to call attention that this is probably not a desirable thing to do, since you want to be able to inject the URL, username and password as separate things into your application. This gives you an idea of how you can accomplish it with one component, and while I strongly encourage you to split this up instead (and whatever you do, do not check the properties file in with those values into your source control), I leave the mechanical part of splitting this into more values as an exercise for the reader.
In my SpringBoot application, I pass my keycloak configuration parameters in the application.properties file. However, I'd like to know if there is a way to let keycloak read these parameters from the code rather than from application.properties.
For example, I retrieve the Realm, Server URL, ClientID and other parameters from a database, I'd like to tell keycloak to read from the database directly or from String that I declare when it launches.
Is that possible?
Thank you
Similar to KeycloakSpringBootConfigResolver, your database reader class must implement KeycloakConfigResolver and should be provided as bean.
public class KeycloakDBConfigResolver implements org.keycloak.adapters.KeycloakConfigResolver {
#Override
public KeycloakDeployment resolve(OIDCHttpFacade.Request request) {
//Read keycloak configuration from Database
}
}
resolve() method should read keycloak configuration from Database and construct KeycloakDeployment.
I have a web form that enables one to update the appliaction.properties, so that user does not have to go to the file and edit it. I wants to load the value from the application.properties file and display in the web form textfield. After the user edit the some changes, user can update the application.properties file.
Question - How can I bind my web form to application.properties file other than using #value in Spring? As the key/value pairs might be updated through web form, I believe #value is not the right choice.
The application properties are for the settings the application needs to load when it starts up, and then connects to a database for example, with the username and password specified in that file (although environment variables can also be used.)
You shouldn't really edit this file at run-time, with the exception of using the Refresh Scope annotation. But I don't advise you do that as it's fairly hard in practice to achieve an application which supports changing configuration at run-time.
There is also Spring Cloud Config server for reloading properties at run-time and that provides a REST API although you mainly just use git with that one.
But the key is here that they are all mentioning configuration which is only something developers do. I also don't think you want to use the filesystem for storing your state, much rather have database. There are many reasons to use a file system over a database I won't go into them now.
I will make the assumption you are a beginner looking at your rep. Best advice I can give you is to watch what everyone else is doing and learn from that first. Most of the time people are all doing similar things because it is the right thing to do. If you can't find anybody else changing properties files based on form submissions in their spring app but rather using databases you probably want to go with the database.
We were in a similar situation last month where client need update in configuration file in run time.
We created a central Spring component that loads all properties from file using #Value
#Component
public class ConfigurationManagerComponent{
#Value("conf.username")
private String userName;
#Value("conf.email");
private String email;
/*
* All your attributes
*/
//getters and setters
public String getUserName(){
return this.userName;
}
public void setUserName(String userName){
// first set the value to this class (component)
this.userName=userName;
//second save this value in the properties file
//a specific method you have to implement
saveproperties("conf.username",userName);
}
/*
* Do like this for all your getters and setters
*/
}
Then, in any time you need to get or save properties, just inject this component and use its getters and setters
#Autowired
ConfigurationManagerComponent configComponent;
String myActualUserName=configComponent.getUserName();
So then you can get all your data in your controller from config component and set them to your spring model to fill form in webpage, and when saving after edit, you can always use setters of your config component(update class and properties file).
This method is not a standard, just a solution we employed to resolve a problem, it's giving good results right now.
You can also check Apache commons configuration Here for other solutions..
Hope this will help.
I'm working to develop a multi-tenant Play Framework 2.1 application. I intend to override the onRequest method of the GlobalSettings class to load and set a custom configuration based on the subdomain of the request. Problem is, I don't see how this would be possible in Play 2.x.
I can override system properties at the command line when starting the server, but how can I do this programmatically in Java code for each request?
The code would look something like this (I assume):
#Override
public play.mvc.Action onRequest(Request request, Method actionMethod) {
//Look up configuration settings in Cache based on request subdomain
//(i.e. Cache.get("subdomain.conf"))
//if not in cache:
//load appropriate configuration file for this subdomain (java.io.File)
//set new configuration from file for this request
//cache the configuration for future use in a new thread
//else
//set configuration from cache for this request
return super.onRequest(request, actionMethod);
}
}
Looking up the URL and getting/setting the cache is easy, but I cannot figure out how to SET a new configuration programmatically for Play Framework 2.1 and the documentation is a little light on things like this.
Any thoughts? Anyone know a better, more efficient way to do this?
So, in a sort of roundabout way, I created the basis for a multi-tenant Play application using a Scala Global. There may be a more efficient way to implement this using a filter, but I'm finding this seems to work so far. This does not appear to be as easily implemented in Java.
Instead of using the configuration file, I'm using the database. I assume it would be far more efficient to use a key-value cache, but this seems to work for now.
In Global.scala:
object Global extends GlobalSettings {
override def onRouteRequest(request: RequestHeader): Option[Handler] = {
if (request.session.get("site").isEmpty){
val id = models.Site.getSiteIDFromURL(request.host)
request.session.+("site" -> id)
}
super.onRouteRequest(request)
}
}
And then, obviously, you have to create a database model to query the site based on the request domain and/or the session value set in the request. If anyone knows a better way I'd love to hear it.
Here's what I'm trying to do:
public void init(ServletConfig config) {
// ...
URL url = new URL("http://myhost:port/path/to/otherservlet");
// ... do stuff with contents of url
}
This works fine, but myhost and port are hardcoded and I want to avoid that. I want
URL url = new URL("/path/to/otherservlet");
but that's not valid. I've also tried
config.getServletContext().getResource("/path/to/otherservlet");
but that only works on static files.
How can I use the result of getting one servlet to initialize another? I don't want to use RequestDispatcher's forward() or include() methods -- the results of otherservlet are intended for use in the init() method, not to be sent in the response.
If possible, I think the better approach is to refactor the code for the other servlet into a class somewhere that can be called directly for the output that you need.
I wouldn't be surprised to find that it can't be done. I think toby's answer (split the code out into a common class) is the best approach, but if that's really not possible, try encoding the host and port to be used for local requests as context parameters in the server's web.xml file:
<context-param>
<param-name>localhost</param-name>
<param-value>localhost</param-value>
</context-param>
<context-param>
<param-name>localport</param-name>
<param-value>8080</param-value>
</context-param>
and get the values with context.getInitParameter("localhost") etc. You could also try to determine the values dynamically, but you might have to wait for a request to come in so you can use something like HttpUtils.getRequestURL(req) - I don't know any other way to do it.
Maybe it'd work if you prepend that URL with the servlet context.
I agree that a refactoring sounds like a better idea. If it's an init operation, and both servlets are in the same context, perhaps the parameters can be externalized to a file or database in such a way that both can pick them up.
I wouldn't like an init to be too extensive.