I have class AnnotatedCollectionInjection with #Resource annotated fields:
package LearnBook.part0.s9;
import LearnBook.Common;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
#Service("injectedAnnotatedCollection")
public class AnnotatedCollectionInjection {
#Resource(name = "map")
private Map<String, String> map;
#Resource(name = "props")
private Properties props;
#Resource(name = "set")
private Set<Integer> set;
#Resource(name = "list")
private List<Long> list;
#Override
public String toString() {
return "CollectionInjection{\n" +
"map=" + map +
", \nprops=" + props +
", \nset=" + set +
", \nlist=" + list +
"\n}";
}
public static void main(String ...args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"META-INF/spring/learnbook/part0/s9/a1.xml"
);
System.out.println(ctx.getBean("injectedAnnotatedCollection"));
}
}
Spring configuration (a1.xml) is here:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<context:annotation-config/>
<context:component-scan base-package="LearnBook.part0.s9"/>
<util:map id="map" map-class="java.util.HashMap" key-type="java.lang.String" value-type="java.lang.String">
<entry key="someValue" value="is value"/>
<entry key-ref="someKeyValue" value-ref="someStringValue"/>
</util:map>
<util:properties id="props">
<prop key="one">two</prop>
<prop key="DA">DO</prop>
</util:properties>
<util:list id="list" value-type="java.lang.Long">
<ref bean="someLongValue"/>
<value>2000</value>
</util:list>
<util:set id="set" value-type="java.lang.Integer">
<ref bean="someIntValue"/>
<value>200</value>
</util:set>
<bean id="someStringValue"
class="java.lang.String"
c:_0="Some string value"/>
<bean id="someKeyValue"
class="java.lang.String"
c:_0="Some key value"/>
<bean id="someLongValue"
class="java.lang.Long"
c:_0="25"/>
<bean id="someIntValue"
class="java.lang.Integer"
c:_0="7"/>
</beans>
But field is null, why?:
CollectionInjection{
map=null,
props=null,
set=null,
list=null
}
If i create setter and move annotation to it, i haven't get changes (map field also is null):
private Map<String, String> map;
#Resource(name = "map")
public void setMap(Map<String, String> map) {
this.map = map;
}
Your configuration looks fine as long as the file is present in the class path given META-INF/spring/learnbook/part0/s9/a1.xml.
Just ran the test by lowering the package name as learnBook.part0.s9, <context:component-scan base-package="learnBook.part0.s9"/> and with FileSystemXmlApplicationContext instead of ClassPathXmlApplicationContext
public static void main(String ...args) {
ApplicationContext ctx = new FileSystemXmlApplicationContext(
"C://fullyQualifiedPathTo//a1.xml"
);
System.out.println(ctx.getBean("injectedAnnotatedCollection"));
}
Received the output successfully.
CollectionInjection{
map={someValue=is value, Some key value=Some string value},
props={one=two, DA=DO},
set=[7, 200],
list=[25, 2000]
}
Related
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd">
<context:component-scan base-package="com.packt.webstore.domain" />
<context:annotation-config></context:annotation-config>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" >
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/Webstore"></property>
<property name="username" value="root"></property>
<property name="password" value="password"></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'productController': Unsatisfied
dependency expressed through field 'productRepository'; nested
exception is
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'productRepositoryImpl': Unsatisfied
dependency expressed through method 'setDataSource' parameter 0;
nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type 'javax.sql.DataSource' available: expected at
least 1 bean which qualifies as autowire candidate. Dependency
annotations: {}
package com.packt.webstore.domain.repository.impl;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Repository;
import com.packt.webstore.domain.Product;
import com.packt.webstore.domain.repository.ProductRepository;
#Repository
public class ProductRepositoryImpl implements ProductRepository {
private NamedParameterJdbcTemplate jdbcTemplate;
#Autowired
private void setDataSource(DataSource dataSource) {
this.jdbcTemplate=new NamedParameterJdbcTemplate(dataSource);
}
#Override
public List<Product> getAllProducts() {
Map<String, Object>params=new HashMap<String,Object>();
List<Product>result=jdbcTemplate.query("SELECT * FROM PRODUCTS", params, new ProductMapper());
return result;
}
private static final class ProductMapper implements org.springframework.jdbc.core.RowMapper<Product> {
public Product mapRow(ResultSet rs,int rownum) throws SQLException{
Product product=new Product();
product.setName(rs.getString("name"));
return product;
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<mvc:annotation-driven enable-matrix-variables="true"></mvc:annotation-driven>
<context:component-scan base-package="com.packt"/>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/" p:suffix=".jsp" />
</beans>
package com.packt.webstore.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import com.packt.webstore.domain.repository.ProductRepository;
#Controller
public class ProductController {
#Autowired
private ProductRepository productRepository;
#RequestMapping("/products")
public String list(Model model) {
model.addAttribute("products",productRepository.getAllProducts());
return "products";
}
}
it looks like you din't configure data-source in xml file
try to add below configuration in xml file
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/yourdbname" />
<property name="username" value="root" />
<property name="password" value="password" />
</bean>
You need to define DataSource bean in your XML file then only use can use #Autowired annotation to configure that bean or you can use #Autowired annotation in the following way:
#Autowired
private NamedParameterJdbcTemplate jdbcTemplate;
How to create timer task (cron-based) without it execution on each node i.e. one execution per one time point in timetable using Apache Ingite?
I have cluster that consists in 2 nodes and application (war) with timer-task. In non-cluster mode application works well. But it has inside timer-task (ie. start each 5 minutes), that works with shared resources.
I try to do it. But IngiteScheduler#scheduleLocal deploys and runs task on each node, if both application instance started (each application instance try to start same timer task).
I assume that ignite have mechanism for deploy task with id fot it...
Thanks.
Update 18.12.2018:
(thank #alamar for idea)
Below I show source and test for successful solutuion:
IgniteTimerTest.java:
package com.stackoverflow.question53780890.test;
import com.stackoverflow.question53780890.JobRunner;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteServices;
import org.apache.ignite.resources.SpringResource;
import org.apache.ignite.services.Service;
import org.apache.ignite.services.ServiceContext;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.io.ClassPathResource;
import java.io.Serializable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class IgniteTimerTest {
private static final ExecutorService ES = Executors.newFixedThreadPool(5);
#Test
public void test() throws Exception {
Future<ConfigurableApplicationContext> applicationContextFutureOne = ES.submit(() -> create(ConfigOne.class));
Future<ConfigurableApplicationContext> applicationContextFutureTwo = ES.submit(() -> create(ConfigTwo.class));
try (ConfigurableApplicationContext applicationContextOne = applicationContextFutureOne.get();
ConfigurableApplicationContext applicationContextTwo = applicationContextFutureTwo.get();) {
Ignite igniteOne = applicationContextOne.getBean(Ignite.class);
Ignite igniteTwo = applicationContextTwo.getBean(Ignite.class);
IgniteServices servicesOne = igniteOne.services();
IgniteServices servicesTwo = igniteTwo.services();
servicesOne.deployClusterSingleton(TestTimerRunner.class.getName(), new TestTimerRunner());
Thread.sleep(JobRunner.PERIOD * 3);
servicesTwo.deployClusterSingleton(TestTimerRunner.class.getName(), new TestTimerRunner());
Thread.sleep(JobRunner.PERIOD * 3);
applicationContextOne.close();
Thread.sleep(JobRunner.PERIOD * 3);
int countValue = JobRunner.getConterValue();
Assertions.assertTrue(9 <= countValue && countValue <= 11);
}
}
private ConfigurableApplicationContext create(Class mainClass) {
ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(mainClass);
return context;
}
class TestTimerRunner implements Serializable, Service {
#SpringResource(resourceClass = JobRunner.class)
private transient JobRunner jobRunner;
public TestTimerRunner() {
}
#Override
public void cancel(ServiceContext ctx) {
jobRunner.stop();
}
#Override
public void init(ServiceContext ctx) throws Exception {
}
#Override
public void execute(ServiceContext ctx) throws Exception {
jobRunner.start();
}
}
#Configuration
#ImportResource("classpath:common.xml")
public static class ConfigOne {
#Bean
public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() {
PropertySourcesPlaceholderConfigurer holder = new PropertySourcesPlaceholderConfigurer();
holder.setLocation(new ClassPathResource("one.properties"));
return holder;
}
}
#Configuration
#ImportResource("classpath:common.xml")
public static class ConfigTwo {
#Bean
public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() {
PropertySourcesPlaceholderConfigurer holder = new PropertySourcesPlaceholderConfigurer();
holder.setLocation(new ClassPathResource("two.properties"));
return holder;
}
}
}
JobRunner.java:
package com.stackoverflow.question53780890;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.TaskScheduler;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.atomic.AtomicInteger;
public class JobRunner implements Runnable {
public static final long PERIOD = 5_000;
private static AtomicInteger counter = new AtomicInteger();
#Autowired
private TaskScheduler taskScheduler;
private ScheduledFuture<?> job;
public static int getConterValue() {
return counter.get();
}
public void start() {
job = taskScheduler.scheduleAtFixedRate(this, PERIOD);
}
public void stop() {
job.cancel(true);
}
#Override
public void run() {
counter.incrementAndGet();
}
}
common.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">
<task:annotation-driven executor="myExecutor" scheduler="myScheduler"/>
<task:executor id="myExecutor" pool-size="5"/>
<task:scheduler id="myScheduler" pool-size="5"/>
<bean id="jobRunner" class="com.stackoverflow.question53780890.JobRunner"/>
<bean id="ignite" class="org.apache.ignite.IgniteSpringBean">
<property name="configuration" ref="igniteConfiguration"/>
</bean>
<bean id="igniteConfiguration" class="org.apache.ignite.configuration.IgniteConfiguration">
<property name="igniteInstanceName" value="${igniteInstanceName}"/>
<property name="discoverySpi">
<bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
<property name="ipFinder">
<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder"
p:addresses-ref="igniteNodesAddresses"/>
</property>
<property name="joinTimeout" value="20000"/>
<property name="localPort" value="${igniteLocalPort}"/>
<property name="localPortRange" value="1"/>
</bean>
</property>
<property name="communicationSpi">
<bean class="org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi">
<property name="localPort" value="${communicationSpiPort}"/>
</bean>
</property>
</bean>
<bean id="igniteNodesAddresses" class="org.springframework.util.StringUtils"
factory-method="commaDelimitedListToStringArray">
<constructor-arg type="java.lang.String" value="${igniteNodes}"/>
</bean>
</beans>
one.properties:
igniteLocalPort=47501
communicationSpiPort=47101
igniteNodes=localhost:47501,localhost:47502
igniteInstanceName=one
two.properties:
igniteLocalPort=47502
communicationSpiPort=47102
igniteNodes=localhost:47501,localhost:47502
igniteInstanceName=two
I think you could deploy a singleton service which will do scheduleLocal in its execute() and de-schedule in its cancel() method. This way it will be failed over to next node and properly re-schedule your tasks if current node leaves.
I'm new to neo4j and spring in combination and spring at all. When I start debugging, I get the following exception:
Exception in thread "main"
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
bean named 'getSessionFactory' available
Can anyone help me please?
apllication-context.xml:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:neo4j="http://www.springframework.org/schema/data/neo4j"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/data/neo4j
http://www.springframework.org/schema/data/neo4j/spring-neo4j.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="de.unileipzig.analyzewikipedia.neo4j" />
<!--neo4j:config storeDirectory="C:/temp/neo4jdatabase" base-package="de.unileipzig.analyzewikipedia.neo4j.dataobjects"/-->
<neo4j:repositories base-package="de.unileipzig.analyzewikipedia.neo4j.repositories"/>
<tx:annotation-driven />
<bean id="graphDatabaseService" class="org.springframework.data.neo4j.support.GraphDatabaseServiceFactoryBean"
destroy-method="shutdown" scope="singleton">
<constructor-arg value="C:/develop/uni/analyze-wikipedia-netbeans/database"/>
<constructor-arg>
<map>
<entry key="allow_store_upgrade" value="true"/>
</map>
</constructor-arg>
</bean>
</beans>
Startup-Class
package de.unileipzig.analyzewikipedia.neo4j.console;
import de.unileipzig.analyzewikipedia.neo4j.dataobjects.Article;
import de.unileipzig.analyzewikipedia.neo4j.service.ArticleService;
import java.io.File;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Neo4JConsole {
/**
* MAIN: start the java file
*
* #param args as string array
*/
public static void main(String[] args) {
String cwd = (new File(".")).getAbsolutePath();
ApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml");
ArticleService service = (ArticleService) context.getBean("articleService");
Article art = createArticle();
createArticle(service, art);
System.out.println("Article created");
}
private static Article createArticle() {
Article article = new Article();
article.setTitle("Title");
return article;
}
private static Article createArticle(ArticleService service, Article art) {
return service.create(art);
}
}
Thank you.
Do you have this configuration?
#Configuration
#EnableNeo4jRepositories("org.neo4j.cineasts.repository")
#EnableTransactionManagement
#ComponentScan("org.neo4j.cineasts")
public class PersistenceContext extends Neo4jConfiguration {
#Override
public SessionFactory getSessionFactory() {
return new SessionFactory("org.neo4j.cineasts.domain");
}
}
For more information, try to look here
I made a WSS4JInInterceptor in a spring bean configuration file as follows
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
xmlns:jaxrs="http://cxf.apache.org/jaxrs"
xsi:schemaLocation="http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxrs
http://cxf.apache.org/schemas/jaxrs.xsd">
<jaxws:endpoint id="book"
implementor="net.ma.soap.ws.endpoints.IBookEndPointImpl" address="/bookAuth">
<jaxws:inInterceptors>
<bean class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor"></bean>
<bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
<constructor-arg>
<map>
<entry key="action" value="UsernameToken" />
<entry key="passwordType" value="PasswordText" />
<entry key="passwordCallbackClass" value="net.ma.soap.ws.service.ServerPasswordCallback"></entry>
</map>
</constructor-arg>
</bean>
</jaxws:inInterceptors>
</jaxws:endpoint>
</beans>
The ServerPasswordCallBack.java looks like the following
package net.ma.soap.ws.service;
import java.io.IOException;
import java.util.ResourceBundle;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.wss4j.common.ext.WSPasswordCallback;
public class ServerPasswordCallback implements CallbackHandler {
private static final String BUNDLE_LOCATION = "zuth";
private static final String PASSWORD_PROPERTY_NAME = "auth.manager.password";
private static String password;
static {
final ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_LOCATION);
password = bundle.getString(PASSWORD_PROPERTY_NAME);
}
#Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
pc.setPassword(password);
}
}
With the password verification, everything work just fine.
I'd like to know if there's any other way to enhance the handle(Callback) method to make it more sophisticated so it would be able to check more than just one parameter, for example if i can make it check an access token, it would be much more better.
the password property is defined in zuth_fr_FR.properties file as follows
auth.manager.password=najah
If you want to do some custom validation on your username and token (such as verify against a directoryservice using LDAP or something similar) you can write your own custom UsernameTokenValidator overriding verifyPlaintextPassword(UsernameToken usernameToken) of UsernameTokenValidator and hook it up to your WSS4JInInterceptor adding the following to your bean definition
<property name="wssConfig">
<ref bean="usernameTokenWssConfig"/>
</property>
And add the referenced class to your codebase:
#Component("usernameTokenWssConfig")
public class usernameTokenWssConfigWSSConfig {
public usernameTokenWssConfig() {
setValidator(WSSecurityEngine.USERNAME_TOKEN, new CustomUsernameTokenValidator());
setRequiredPasswordType(WSConstants.PASSWORD_TEXT);
}
}
I built a CXF based soap web service and i was trying to add some security aspects using the WS-Security by following the steps of this tutorial.
I got the An error was discovered processing the header
Here are the important classes that add the security aspects to the soap ws
ServerPasswordCallback.java
import java.io.IOException;
import java.util.ResourceBundle;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.wss4j.common.ext.WSPasswordCallback;
public class ServerPasswordCallback implements CallbackHandler {
private static final String BUNDLE_LOCATION = "auth";
private static final String PASSWORD_PROPERTY_NAME = "auth.manager.password";
private static String password;
static {
final ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_LOCATION);
password = bundle.getString(PASSWORD_PROPERTY_NAME);
}
#Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
pc.setPassword(password);
}
}
ClientPasswordCallback.java
import java.io.IOException;
import java.util.ResourceBundle;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.wss4j.common.ext.WSPasswordCallback;
public class ClientPasswordCallback implements CallbackHandler {
private static final String BUNDLE_LOCATION = "auth";
private static final String PASSWORD_PROPERTY_NAME = "auth.manager.password";
private static String password;
static {
final ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_LOCATION);
password = bundle.getString(PASSWORD_PROPERTY_NAME);
}
#Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
pc.setPassword(password);
}
}
AuthServiceFactory.java
public final class AuthServiceFactory {
private static final ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {
"com/company/auth/service/cxfClient.xml"
});
public AuthServiceFactory() {
}
public AuthService getService() {
return (AuthService) context.getBean("client");
}
}
auth_fr_FR
auth.manager.password=*****
cxfClient.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
xmlns:jaxrs="http://cxf.apache.org/jaxrs"
xsi:schemaLocation="http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxrs
http://cxf.apache.org/schemas/jaxrs.xsd">
<bean id="proxyFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
<property name="serviceClass" value="com.company.auth.service.AuthService" />
<property name="address"
value="http://localhost:8080/CXFSOAP-WebService/corporateAuth" />
<property name="inInterceptors">
<list>
<ref bean="logIn" />
</list>
</property>
<property name="outInterceptors">
<list>
<ref bean="logOut" />
<ref bean="saajOut" />
<ref bean="wss4jOut" />
</list>
</property>
</bean>
<bean id="client" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean"
factory-bean="proxyFactory" factory-method="create" />
<bean id="logIn" class="org.apache.cxf.interceptor.LoggingInInterceptor" />
<bean id="logOut" class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
<bean id="saajOut" class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor" />
<bean id="wss4jOut" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
<constructor-arg>
<map>
<entry key="action" value="UsernameToken" />
<entry key="user" value="ws-client" />
<entry key="passwordType" value="PasswordText" />
<entry key="passwordCallbackClass" value="com.company.auth.service.ClientPasswordCallback" />
</map>
</constructor-arg>
</bean>
</beans>
This file is for the client configuration
beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
xmlns:jaxrs="http://cxf.apache.org/jaxrs"
xsi:schemaLocation="http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxrs
http://cxf.apache.org/schemas/jaxrs.xsd">
<jaxws:endpoint id="bookShelfService"
implementor="com.company.auth.service.AuthServiceImpl" address="/corporateAuth">
<jaxws:inInterceptors>
<bean class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor"></bean>
<bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
<constructor-arg>
<map>
<entry key="action" value="UsernameToken" />
<entry key="passwordType" value="PasswordText" />
<entry key="passwordCallbackClass" value="com.company.auth.service.ServerPasswordCallback"></entry>
</map>
</constructor-arg>
</bean>
</jaxws:inInterceptors>
</jaxws:endpoint>
</beans>
This file is for the server configuration
Client.java
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import com.company.auth.bean.Employee;
import com.company.auth.service.AuthService;
public class Client {
public Client() {
super();
}
public static void main(String[] args) {
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(AuthService.class);
factory.setAddress("http://localhost:8080/CXFSOAP-WebService/corporateAuth");
AuthService client = (AuthService) factory.create();
Employee employee = client.getEmployee("22222");
System.out.println("Server said: "+employee.getLastName()+" "+employee.getFirstName());
System.exit(0);
}
}
This is the client code that consumes the soap web service.
before adding the security configuration, the server was up and running and the client consumed the function of the soap api successfully but after the security modification, when the client attempts to use the web service function i get this error
org.apache.cxf.binding.soap.SoapFault: A security error was encountered when verifying the message
at org.apache.cxf.ws.security.wss4j.WSS4JUtils.createSoapFault(WSS4JUtils.java:216)
at org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.handleMessageInternal(WSS4JInInterceptor.java:329)
at org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.handleMessage(WSS4JInInterceptor.java:184)
at org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.handleMessage(WSS4JInInterceptor.java:93)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308)
at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.apache.wss4j.common.ext.WSSecurityException: An
error was discovered processing the header
at org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.checkActions(WSS4JInInterceptor.java:370)
at org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.handleMessageInternal(WSS4JInInterceptor.java:313)
... 34 more
I tried to manually add some wsse headers in the soap envelope but it didn't work.
I solved my problem by modifying the AuthServiceFactory.java class and the ClientPasswordCallback.java and the descriptor deployment file and i added a auth2_Fr_fr.properties file.
AuthServiceFactory.java
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.company.auth.bean.Employee;
public final class AuthServiceFactory {
private static final ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
new String[] { "com/company/auth/service/cxfClient.xml" });
public AuthServiceFactory() {
}
public AuthService getService() {
return (AuthService) context.getBean("client");
}
public static void main(String[] args) {
AuthServiceFactory authSer = new AuthServiceFactory();
AuthService client = authSer.getService();
Employee employee = client.getEmployee("22222");
System.out.println("Server said: " + employee.getLastName() + " " + employee.getFirstName());
System.exit(0);
}
}
ClientPasswordCallback.java
import java.io.IOException;
import java.util.ResourceBundle;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.wss4j.common.ext.WSPasswordCallback;
public class ClientPasswordCallback implements CallbackHandler {
private static final String BUNDLE_LOCATION = "auth2";
private static final String PASSWORD_PROPERTY_NAME = "auth.manager.password";
private static String password;
static {
final ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_LOCATION);
password = bundle.getString(PASSWORD_PROPERTY_NAME);
}
#Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
pc.setPassword(password);
}
}
auth2_fr_Fr.properties
auth.manager.password=123456