I want to use my system environment variables (i.e use variable FOO that I have defined in my .bash_profile export FOO=BAR) for values in Spring's applicationContext.xml;
For example:
<bean id="dataSource" ...>
<property name="jdbcUrl" value="${FOO}" />
...
</bean>
I use both the Maven-tomcat-plugin and Tomcat inside IntelliJ to run my server.
Right now when my webapp starts up, it can't find the system variables.
What do I have to do to get Spring to read from my system environment variables?
P.S. I have already checked out how to read System environment variable in Spring applicationContext, but doesn't seem to work for me
System environment variables are different to the JVM system properties - which the spring PropertyPlaceholderConfigurer gives you access to. So you'd need to add to the JVM command:
java ... -DFOO=${FOO}
(where -DFOO is defining "FOO" as a JVM system property and ${FOO} is inserting the "BAR" value from your "FOO" environment variable)
See also the ServletContextPropertyPlaceholderConfigurer - with the SYSTEM_PROPERTIES_MODE_OVERRIDE property and a few other options.
try this (Spring Expression Language)
<bean id="dataSource" ...>
<property name="jdbcUrl" value="#{systemEnvironment.FOO}" />
...
</bean>
or add this line
<context:property-placeholder/>
to application context
Related
I have a question regarding an Autosys job that I have been picking my head on but could not figure out. So, basically I have this AutoSys job that runs old spring boot application via a script File. When I say old, it uses spring.xml for dependency injection with context.getBean("beadIdFromSpringXml") as the process of generating bean as shown in below code:
# This is spring.xml file context
<context:property-placeholder
location="classpath:application-${spring.profiles.active}.properties" />
<bean id="myBean" class="com.example.MyBean">
<property name="propName1" value="${prop1}"/>
<property name="propName2" value="${prop2}"/>
</bean>
The bean is generated like example below:
public static void main(String[] args)
{
MyBean beanVariable = (MyBean) context
.getBean("myBean");
Then we have a script file that is run by AutoSys that starts the java project as shown below:
# If I echo ${PROFILE} here I do get "int" in logs
java -Dspring.profiles.active="${PROFILE}" .............
When starting the Job, it always ends up in runtime error by saying it cannot create the bean "myBean" cause it cannot find the {prop1}. So my guess is that the ${spring.profiles.active} is not being fetched by the spring boot app correctly. Has anyone faced this error before?
I expected to be able to do something like this in my server.xml, but I could not get it to work:
<variable name="my.ldap.url" value="${LDAP_URL}" />
Setting it in jvm.options or server.env do not seem to be options either from what I can tell. Neither of those are parsing environment variables from my tests.
-Dmy.ldap.url=$LDAP_URL
Setting properties in my own files and using environment variables did not seem to work either. I tried something like this in my server.xml
<library id="configs">
<fileset dir="${server.config.dir}/configs" includes="*.properties" />
</library>
So I'm just lost for ideas right now. How do I take environment variables and inject them into an Open Liberty application as application properties?
I searched high and low for documentation on this, with no success.
In Jboss I was able to accomplish simple via
bin/standalone.sh -Dmy.ldap.url=$LDAP_URL
It should work for you exactly the way it does in Jboss:
wlp/bin/server start server1 -Dmy.ldap.url=$LDAP_URL
Your <variable> definition would create a Liberty configuration variable that resolves to the value of LDAP_URL in the environment, but it would not be set as a java system property.
If you're still seeing problems with passing the value on the command line you could check all java system properties by running:
wlp/bin/server dump {server name}
In the output zip file, the dump_{timestamp}/introspections/JavaRuntimeInformation.txt will show both the command line arguments and all defined java system properties.
I'd consider using Microprofile config, checkout this guide and see it does answer your questions.
It shows you how to inject variables using following schema:
#Inject #ConfigProperty(name="port")
private int port;
assuming there is PORT env entry in your system.
You can also use env variables in server configuration using server.xml for example:
<properties.db2.jcc serverName="${JDBC_HOST}" portNumber="${JDBC_PORT}" databaseName="${JDBC_DB}" sslConnection="${JDBC_SSL}"
user="${JDBC_ID}" password="${JDBC_PASSWORD}"/>
Details here https://openliberty.io/docs/latest/reference/config/server-configuration-overview.html
For your library point you would have to add it to your application via classloader, so I wouldn't recommend that. Like this:
<application name="myapp" type="ear" location="myapp.ear">
<classloader commonLibraryRef="configs" />
</application>
Hope it solves your problems.
The final answer I found to this, is you can inject environment variables into properties using the <appProperties> tag in your server.xml
Documentation is here
https://openliberty.io/guides/microprofile-config-intro.html#configuring-as-an-appproperties-element-scoped-by-application
A simple example of this using an environment variable looks like ...
<webApplication location="my.war" type="war">
<appProperties>
<property name="my.ldap.url" value="${LDAP_URL}"/>
</appProperties>
</webApplication>
First of all, I tried this with Liferay CE portal-7.1.0-GA1 and Liferay portal 7.0 CE GA1. I will explain details of my process. My portal-ext.properties (Liferay HOME folder) looks:
jdbc.ext.driverClassName=oracle.jdbc.OracleDriver
jdbc.ext.url=jdbc:oracle:thin:#localhost:1521:db
jdbc.ext.username=xxx
jdbc.ext.password=xxx
JARs:
- ojdbc14.jar (\liferay-portal-7.0-ce-ga1\tomcat-8.0.32\lib)
- liferay-portal-oracledb-support-1.0 and liferay-portal-oracledb-support-1.0-SNAPSHOT (liferay-portal-7.0-ce-ga1\tomcat-8.0.32\webapps\ROOT\WEB-INF\lib)
- added ext-spring.xml (\modules\DemoService\DemoService-service\build\resources\main\META-INF\spring)
Code for ext-spring.xml
<?xml version="1.0"?>
<beans default-destroy-method="destroy" default-init-method="afterPropertiesSet" xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!--bean class="com.liferay.portal.dao.jdbc.spring.DataSourceFactoryBean"
id="liferayDataSourceFactory">
<property name="propertyPrefix" value="jdbc.ext." />
<property name="properties">
<props>
<prop key="custom.jndi.name">extDataSource</prop>
</props>
</property>
</bean-->
<bean class="com.liferay.portal.dao.jdbc.spring.DataSourceFactoryBean"
id="liferayDataSourceFactory">
<property name="propertyPrefix" value="jdbc.ext." />
</bean>
<bean
class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy"
id="liferayDataSource">
<property name="targetDataSource" ref="liferayDataSourceFactory" />
</bean>
<alias alias="extDataSource" name="liferayDataSource" />
</beans>
Getting this ERROR:
00:10:31,259 ERROR [http-nio-8080-exec-5][render_portlet_jsp:131] null
java.lang.NullPointerException
at com.service.service.CountryLocalServiceUtil.getCountriesCount(CountryLocalServiceUtil.java:207)
at com.demo.portlet.DemoPortlet.doView(DemoPortlet.java:39)
at com.liferay.portal.kernel.portlet.LiferayPortlet.doDispatch(LiferayPortlet.java:302)
at com.liferay.portal.kernel.portlet.bridges.mvc.MVCPortlet.doDispatch(MVCPortlet.java:474)
at javax.portlet.GenericPortlet.render(GenericPortlet.java:262)
at com.liferay.portal.kernel.portlet.bridges.mvc.MVCPortlet.render(MVCPortlet.java:294)
at com.liferay.portlet.FilterChainImpl.doFilter(FilterChainImpl.java:103)
at com.liferay.portlet.ScriptDataPortletFilter.doFilter(ScriptDataPortletFilter.java:57)
at com.liferay.portlet.FilterChainImpl.doFilter(FilterChainImpl.java:100)
at com.liferay.portal.kernel.portlet.PortletFilterUtil.doFilter(PortletFilterUtil.java:64)
at com.liferay.portal.kernel.servlet.PortletServlet.service(PortletServlet.java:105)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at com.liferay.portal.osgi.web.servlet.context.helper.internal.ServletContextHelperRegistrationImpl$PortletServletWrapper.service(ServletContextHelperRegistrationImpl.java:507)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.eclipse.equinox.http.servlet.internal.registration.EndpointRegistration.service(EndpointRegistration.java:153)
at org.eclipse.equinox.http.servlet.internal.servlet.FilterChainImpl.doFilter(FilterChainImpl.java:50)
at com.liferay.portal.osgi.web.servlet.context.helper.internal.ServletContextHelperRegistrationImpl$RestrictPortletServletRequestFilter.doFilter(ServletContextHelperRegistrationImpl.java:527)
at org.eclipse.equinox.http.servlet.internal.registration.FilterRegistration.doFilter(FilterRegistration.java:121)
at org.eclipse.equinox.http.servlet.internal.servlet.FilterChainImpl.doFilter(FilterChainImpl.java:45)
at org.eclipse.equinox.http.servlet.internal.servlet.ResponseStateHandler.processRequest(ResponseStateHandler.java:71)
Country is entity in service.xml, after Gradle building service, CountryLocalServiceUtil is generated. If you are using Liferay 7, this is simple process of creating first app.
This is generated class, I can give the code:
From Portlet, I just called function CountryLocalServiceUtil.getCountriesCount()
this function in CountryLocalServiceUtil is:
public static int getCountriesCount() {
return getService().getCountriesCount();
}
Open declaration is:
CountryLocalService.java #Transactional(propagation = Propagation.SUPPORTS,
readOnly = true)
public int getCountriesCount();
You're running Liferay 7.x CE. Note that Liferay Community Edition (CE) does only support Open Source databases, e.g. no Oracle. There's a community provided add-on that adds support for Oracle and other commercial databases, but you don't indicate that you've installed it.
Thus, it seems that you're running Liferay from a supported database, and try to connect to Oracle in your "jdbc.ext" database. I'd expect this to not work, as it would require the servicebuilder mapping to Oracle, though they're not contained in CE.
You can always go with pure JDBC (e.g. no service builder), or try Antonio's plugin. Currently I'm only aware that it's out for 7.0, not for 7.1 (but I might be wrong here)
I am almost sure your problem is not the database but the service object not being available as your issue is no due getCountriesCount() but on getService().
As an experiment, try not using the *Util class but an OSGi #Reference for the service you want, this should rule out the database as an issue (at least for this matter). if you cannot get the service, you will probably find better troubleshooting information than a NPE being thrown in the *Util class.
As an example, in your component:
#Reference
private volatile CountryLocalService countryLocalService;
There are examples all over Liferay's source, like:
https://github.com/liferay/liferay-portal/blob/180d89ccaa80b86e68402c73a1483cd9e1817311/modules/apps/export-import/export-import-resources-importer/src/main/java/com/liferay/exportimport/resources/importer/internal/util/ImporterFactory.java
In local environment , we can configure some connection Environment properties in a property file, and then use them by context:property-placeholder. for example:
<context:property-placeholder location="classpath:resources-local.properties"/>
<smtp:endpoint host="${smtp.host}" port="${smtp.port}" user="${smtp.user}" password="${smtp.password}" name="NotificationEmail" doc:name="SMTP" to="${smtp.to}" from="${smtp.from}" subject="error" />
But when I deploy the app to cloudhub,I can set the connection info as Environment variables.We don't need to import the resources-local.properties file.We can still use the properties as
<smtp:endpoint host="${smtp.host}" port="${smtp.port}" user="${smtp.user}" password="${smtp.password}" name="NotificationEmail" doc:name="SMTP" to="${smtp.to}" from="${smtp.from}" subject="error" />
here is the question,how can I use Environment variables setted on cloudhub in java class.How can I get the smtp.host value in java class???
David told me that I can use them as they available as system properties.
But How to use the system properties in java class..
Any advise?? Thanks a lot!
The best option is to inject them into your class via Spring. E.g.:
<bean class="my.java.Object">
<property name="smtp" value="${smtp.host}">
</bean>
However, getting it as a system property via System.getProperty("smtp.host") will also work.
From a java class, just use System.getProperty("smtp.host");
I try to get an Environment variable specified in Tomcat's server.xml in a 'PropertyPlaceholderConfigurer' located in my jpa-spring.xml file.
So far, the setup looks as follows:
Tomcat server.xml
<Environment description="Identifies the server environement"
name="server-env"
type="java.lang.String"
value="dev" />
The in WebContent/META-INF/context.xml:
<Context>
<ResourceLink name="server-env" global="server-env" type="java.lang.String"/>
</Context>
Which is referenced in WebContent/WEB-INF/web.xml like:
<resource-env-ref>
<description>Identifies server environement</description>
<resource-env-ref-name>server-env</resource-env-ref-name>
<resource-env-ref-type>java.lang.String</resource-env-ref-type>
</resource-env-ref>
<!-- Spring Integration -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/config/jpa-spring.xml
</param-value>
</context-param>
And in /WEB-INF/config/jpa-spring.xml I try to get that variable as a replacement:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>WEB-INF/config/db.${server-env}.properties</value>
</list>
</property>
</bean>
This is a setup I put together using information from several articles found on the web.
However, I get an error like ...
Could not resolve placeholder 'server-env' in [WEB-INF/config/db.${server-env}.properties] as system property: neither system property nor environment variable found
05 Nov 2011 14:45:13,385 org.springframework.web.context.ContextLoader
ERROR Context initialization failed
org.springframework.beans.factory.BeanInitializationException: Could not load properties; nested exception is java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/config/db.${server-env}.properties]
... when starting tomcat.
What is the right approach to achieve what I am looking for?
I know that this question is similar to this, and this question. However, I even couldn't figure it out with the information from these answers.
Here are my suggestion
With the current set up, its really going to be complicated to read JNDI property server-env and use the same to load the property file.
The way you have assembled the spring application (and PropertyPlaceholderConfigurer), spring will try to look for the property server-env first in OS environment then in java system properties (passed from command using -D option). It finds it at neither of these places and hence fails.
So currently the easiest way out right now is to pass the value of server-env form command prompt of your application server (where you invoke java ; typical syntax would be -Dserver-env=dev). I leave this to you to figure out.
if above option appears a bit complicated, another easier way out is set an environment variable with name server-env to its appropriate values (on Windows its set server-env=dev. Plz check respect OS documentations for this).
Those Environment elements are setting up JNDI. Getting values out of JNDI isn't supported, by default, by any simple syntactic sugar in Spring.
http://www.theserverside.com/news/thread.tss?thread_id=35474#179220
might give you some useful ideas.