Java - Spring - put entries in map based on some condition - java

In a Java app which uses Spring (Spring version 3.2.3),
I have something like this:
<bean id="pm" class="com.test.PropertyManager">
<property name="targets">
<map>
<entry key="key01" value-ref="obj01" />
<entry key="key02" value-ref="obj02" />
<entry key="key03" value-ref="obj03" />
<entry key="key04" value-ref="obj04" />
<entry key="key05" value-ref="obj05" />
<entry key="key06" value-ref="obj06" />
</map>
</property>
</bean>
Is there any way to tell Spring to not put all entries in this map
but only some of them based on some property whose value can be
different for different environments the app is built for, and running in.
I mean, I am looking for something like:
<bean id="pm" class="com.test.PropertyManager">
<property name="targets">
<map>
<entry key="key01" value-ref="obj01" if="${env1}"/>
<entry key="key02" value-ref="obj02" if="${env1}"/>
<entry key="key03" value-ref="obj03" unless="${env1}"/>
<entry key="key04" value-ref="obj04" unless="${env1}"/>
<entry key="key05" value-ref="obj05" />
<entry key="key06" value-ref="obj06" />
</map>
</property>
</bean>
So e.g. I want two entries to be added when the app is in environment env1, two other entries to be added when the app is running in another env2, and yet two others to be always added.
Is that possible and if not, what are my alternatives?

There are different options:
If you need a different bean configuration per environment you could use profiles:
<beans profile="dev">
<bean id="pm" class="com.test.PropertyManager">
<property name="targets">
...
</property>
</bean>
</beans>
<beans profile="production">
<bean id="pm" class="com.test.PropertyManager">
<property name="targets">
...
</property>
</bean>
</beans>
More on XML profiles: http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-definition-profiles-xml
If you need more flexibility use a factory (with Java config, that's straightforward):
public class PropertyManagerFactory {
public static PropertyManager getInstance() {
// Your initialization code (check env vars to build the map...)
}
}
Bean definition (notice the factory-method):
<bean id="propertyManager" class="com.test.PropertyManagerFactory" factory-method="getInstance" />
Usage (what's returned by the getInstance method will be injected here):
<bean id="accountService" class="com.test.AccountServiceImpl">
<property name="propertyManager" ref="propertyManager"/>
</bean>
More info on using factory methods: http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-factory-class-static-factory-method

Related

Dynamically Injecting a Map

I have the following field called someMap in which I need to inject a map at runtime depending upon the inputs I have received.
I have tried using the #Resource annotaion but it is tightly coupled to the beanId specified in the xml file.
#Resource(name="someMap")
private final Map<String,String> someMap;
<bean id="someMap" class="java.util.HashMap">
<constructor-arg>
<map>
<entry key="Engraving1" value="#Engraving1" />
<entry key="Engraving2" value="#Engraving2" />
<entry key="Engraving3" value="#Engraving3" />
<entry key="LeaveBlank" value="#LeaveBlank" />
</map>
</constructor-arg>
</bean>
<bean id="someOtherMap" class="java.util.HashMap">
<constructor-arg>
<map>
<entry key="Descirption" value="#Desc" />
<entry key="Engraving2" value="#Engraving2" />
<entry key="Engraving3" value="#Engraving3" />
<entry key="UniqueId" value="$60034" />
</map>
</constructor-arg>
</bean>
What I want is to get rid of this tight coupling & initialize the someMap field to a differnt flavour of the Map defined in spring xml let's say someOtherMap
You can't change the annotation dynamic without using Reflection , so you can't change the name of reousece.
#Resource(name="NAME")
But it is very easy to define two bean with different property or constrctor-arg.
<bean id="boss" class="***">
<property name="mydata">
<bean class="HashMap">
</bean>
</property>
</bean>
if you just want one bean definition with different data, XML and Annotation should not work. factory-method or setMethod will work for it, you need some java code.

Is it possible call a properties file to instance a user and password in Apache CXF Blueprint for a Web Service?

I'm relative new with Fuse and WebServices.
I did a SOAP WebService with a BasicAuthAuthorizationInterceptor, this is the actual context and it's working:
<cxf:cxfEndpoint address="/SampleEp" id="insertSomethingToDB" serviceClass="com.example.sample_ep.SampleEp" wsdlURL="wsdl/SampleEP.wsdl">
<cxf:inInterceptors>
<ref component-id="securityInterceptor"/>
</cxf:inInterceptors>
</cxf:cxfEndpoint>
<bean
class="com.example.middleware.BasicAuthAuthorizationInterceptor" id="securityInterceptor">
<property name="users">
<map>
<entry key="user" value="password"/>
</map>
</property>
</bean>
So, to add more security, I'll tried to put the users in a properties file outside the project, this is the idea:
<cxf:cxfEndpoint address="/SampleEp" id="insertSomethingToDB" serviceClass="com.example.sample_ep.SampleEp" wsdlURL="wsdl/SampleEP.wsdl">
<cxf:inInterceptors>
<ref component-id="securityInterceptor"/>
</cxf:inInterceptors>
</cxf:cxfEndpoint>
<bean
class="com.example.middleware.BasicAuthAuthorizationInterceptor" id="securityInterceptor">
<property name="users">
<map>
<entry key="${cxf.user}" value="${cxf.password}"/>
</map>
</property>
</bean>
<bean> add some code to add a *.properties file outside the project </bean>
It is that possible?
Or I'm really bad with this?
Ok, I tried a few of things with Jasypt, JAAS and get the solution:
<ext:property-placeholder>
<ext:location>file:/this/is/your/path/to/your/propertie/file/cxf.properties
</ext:location>
</ext:property-placeholder>
<cxf:cxfEndpoint address="/SampleEp" id="insertSomethingToDB"
serviceClass="com.example.sample_ep.SampleEp" wsdlURL="wsdl/SampleEP.wsdl">
<cxf:inInterceptors>
<ref component-id="securityInterceptor" />
</cxf:inInterceptors>
</cxf:cxfEndpoint>
<bean class="com.example.middleware.BasicAuthAuthorizationInterceptor"
id="securityInterceptor">
<property name="users">
<map>
<entry key="${cxf.user}" value="${cxf.password}" />
</map>
</property>
</bean>
Just only add to your Blueprint header:
xmlns:ext="http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.0.0"
And voilĂ , it's working with a secure user/pass validation outside your project :D
And the most important thing, the properties file needs this format:
#cxf.properties
cxf.user=administrator
cxf.password=password

Multiple AttributeRepository in CAS

I'm using CAS (JASIG) 3.5.2 server. I have two LDAP server configured for authentication as authenticationHandlers.
Now, I have a requirement to pass user attribute in Validation Response. I am able to configure CAS to return user attributes from one of the LDAP servers with attributeRepository bean.
I'm not able to figure out how we can configure CAS to get user attributes from multiple LDAPs.
Following config I have tried.
<bean id="attributeRepository" class="org.jasig.services.persondir.support.ldap.LdapPersonAttributeDao">
<property name="contextSource" ref="openldap-contextSource" />
<property name="requireAllQueryAttributes" value="true" />
<property name="baseDN" value="dc=myorg,dc=com" />
<property name="queryAttributeMapping">
<map>
<entry key="username" value="uid" />
</map>
</property>
<property name="resultAttributeMapping">
<map>
<entry key="sn" value="lastName" />
<entry key="givenName" value="firstName" />
<entry key="mail" value="email" />
</map>
</property>
</bean>
This configuration works, if we want single LDAP to get user. If I try to rename the bean name it gives me error in initialization.
Can any one suggest approach to achieve this?
You need to define two attribute repositories, merge them and call the merged one "attributeRepository"
https://github.com/Jasig/person-directory#mergingpersonattributedaoimpl

Custom timeout configuration per operation using Spring

I am using a Soap WS and I have to customize timeout configuration per operation. The customization is actually done with cxf and its http-conf:conduit, which cannot be customized to the operation level.
My actual configuration is :
<bean id="proxyFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
<property name="serviceClass" value="com.package.PortType" />
<property name="address" ref="URL_WS" />
</bean>
<bean id="URL_WS" class="java.lang.String">
<constructor-arg value="http://serveraddress/Service"/>
</bean>
<http-conf:conduit name="http://serveraddress/Service.*">
<http-conf:client ConnectionTimeout="10000" ReceiveTimeout="10000"/>
</http-conf:conduit>
With this configuration, all the timeout of this WS are up to 10000ms.
As explained above, I would like to customize it to the operation level, I have found this link and tried to follow the process, but I'm in front of a problem of implementation, but I only com.ibm.wsdl.util.xml.QNameUtils in my classpath which has for the factory-method :
public static QName newQName(Node paramNode), method which takes a org.w3c.dom.Node.
I tried to change the code with this implementation coming to:
<bean id="proxyFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
<property name="delegate">
<jaxws:client serviceClass="com.package.PortType" address="URL_WS" >
<jaxws:outInterceptors>
<bean class="com.package.CustomTimeoutInterceptor">
<property name="receiveTimeoutByOperationName">
<map key-type="javax.xml.namespace.QName" value-type="java.lang.Long">
<entry value="10">
<key>
<bean class="com.ibm.wsdl.util.xml.QNameUtils" factory-method="newQName">
<!-- I don't know what to put here -->
</bean>
</key>
</entry>
</map>
</property>
</bean>
</jaxws:outInterceptors>
</jaxws:client>
</property>
</bean>
The Node's implementation I have is com.sun.org.apache.xerces.internal.dom.NodeImpl. I don't know which NodeImpl' subclass I have to use and how to create it to make it working in a bean way, I'm kinda losing myself in the documentation with these different implementations and these different dom Levels.
I just would like to create an Object subClass of Node which would work in this QNameUtils method
OR
find a different way to customize my configuration
I finally solved this problem, here is the working solution:
I kept the CustomTimeoutInterceptor of the link, mixed the solution with the help of this link.
I also kept my initial configuration, and I found that the javax.xml.namespace.QName had a factory method. I just added this part to my configuration:
<!-- Creation of the bean for the interceptor -->
<bean id="timeoutSetter" class="com.package.CustomTimeoutInterceptor">
<property name="receiveTimeoutByOperationName">
<map key-type="javax.xml.namespace.QName" value-type="java.lang.Long">
<entry value="20000">
<key>
<bean class="javax.xml.namespace.QName" factory-method="valueOf">
<constructor-arg value="{http://serveraddress/Service}Operation1" />
</bean>
</key>
</entry>
</map>
</property>
</bean>
<!-- I had the interceptor the list of outInterceptors -->
<cxf:bus>
<cxf:outInterceptors>
<ref bean="timeoutSetter"/>
</cxf:outInterceptors>
</cxf:bus>

Keys of Spring beans as Map<String,Foo>

trying to instantiate a Map in Spring I found an odd (to me) behaviour.
I am using the following piece of XML to create the Map:
<bean id="fooBean" class="it.arch.fe.util.Foo">
<property name="prop1" value="val1"></property>
<property name="prop2" value="val2"></property>
</bean>
<bean id="barBean" class="it.arch.fe.util.Foo">
<property name="prop1" value="val3"></property>
<property name="prop2" value="val4"></property>
</bean>
<bean id="mapOfFoos" class="org.springframework.beans.factory.config.MapFactoryBean">
<property name="targetMapClass">
<value>java.util.HashMap</value>
</property>
<property name="sourceMap">
<map>
<entry key="foo" value-ref="fooBean" />
<entry key="bar" value-ref="barBean" />
</map>
</property>
</bean>
I manage to instantiate and Autowire this Map in my code, but I am having an issue with the keys:
I wanted a map with keys "foo" and "bar", but they appear to be "fooBean" and "barBean".
Is this supposed to happen?
Is there a way to use the "key" properties as keys, as it would seem the obvious behaviour?
(I don't want to change the names of the beans to foo and bar, because I already declared two beans with these names and the logic I would like to follow needs the keys to be "foo" and "bar")
EDIT: Starting from Trever Shick's answer I found a way to resolve the practical problem, but I'm still trying to understand why this happened.
just use a map, don't use a MapFactoryBean for your mapOfFoos
<beans xmlns:util="http://www.springframework.org/schema/"
xsi:schemaLocation="http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.0.xsd">
<util:map id="mapOfFoos">
<entry key="foo" value-ref="fooBean" />
<entry key="bar" value-ref="barBean" />
</util:map>
Since I found I can't instantiate a Map by itself as a bean without a MapFactoryBean or as a property inside another bean, I resolved in another way:
I made another class, InnerFoo with attributes prop1 and prop2, where I put the properties I had in the previous Foo, so now my Map<String,InnerFoo> is the only attribute of Foo, this is my xml snippet:
<bean id="fooBean" class="it.arch.fe.util.InnerFoo">
<property name="prop1" value="val1"></property>
<property name="prop2" value="val2"></property>
</bean>
<bean id="barBean" class="it.arch.fe.util.InnerFoo">
<property name="prop1" value="val3"></property>
<property name="prop2" value="val4"></property>
</bean>
<bean id="mapOfFoos" class="it.arch.fe.util.Foo">
<property name="mapping">
<map>
<entry key="foo" value-ref="fooBean" />
<entry key="bar" value-ref="barBean" />
</map>
</property>
</bean>

Categories

Resources