I am trying to dinamically update the users credentials in next way: When de admin pushes a button a new role is added to every standard user in database. The disconnected users have not problem, because when they login the custom authentication provider loads all his roles from db, but the logued users cant access to the new available sections, because the authentication object has not the new role. In order to solve this i tried many mechanisms, but the rightfull and less intrusive i saw was using listeners. Here is the idea: when the admin pushes the button, the db is updated and a new custom event is triggered and processed. This event produces, in theory, a reauthentication for each active user AND IT DOES, just that only for the user who triggered the event(the admin).
Now, i want to know why does it, why the event doesnt apply to every SecurityContextHolder and just to the one who triggered it. I though the problem was in the scope of the bean, so i gave it a session scope, but throws an error. Please, if anyone can help me.
Here is the properly code
My dispatcher servlet
<?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:p="http://www.springframework.org/schema/p"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
<context:component-scan base-package="printer">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/"
p:suffix=".jsp" />
//nothing that matters here
<bean id="reauthenticating" class="printer.Security.Events.ReauthenticatingEventsPostProcessor" scope="prototype"/>
The event
public class ReauthenticatingUseronRoleChangeEvent extends ApplicationEvent {
private static final long serialVersionUID = 1L;
private String roleType;
private String actionType;
public ReauthenticatingUseronRoleChangeEvent(Object source,String roleType, String actionType) {
super(source);
this.roleType = roleType;
this.actionType = actionType;
}
public String getRoleType() {
return roleType;
}
public String getActionType() {
return actionType;
}
The event trigger which is my UserService
public class UserService_Impl implements UserService,ApplicationEventPublisherAware{
#Override
public void publishAccessToDownloadEvent() {
.....
enter code here
#Override
public void publishAccessToDownloadEvent() {
publisher.publishEvent(new ReauthenticatingUseronRoleChangeEvent(this, "ROLE_DOWNLOAD", "add"));
}
Here is the event listener. This is where i get lost, doesnt suppose it is executed for every user????
public class ReauthenticatingEventsPostProcessor implements ApplicationListener<ReauthenticatingUseronRoleChangeEvent> {
#Autowired
#Qualifier("userDao")
UserDAO userDao;
#Override
public void onApplicationEvent(ReauthenticatingUseronRoleChangeEvent e) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority> (auth.getAuthorities());
Role r=new Role();
r.setRole(e.getRoleType());
authorities.add(r);
Authentication newAuth = new UsernamePasswordAuthenticationToken(auth.getPrincipal(),auth.getCredentials(),authorities);
SecurityContextHolder.getContext().setAuthentication(newAuth);
}
}
#Override
public void setApplicationEventPublisher(ApplicationEventPublisher aep) {
this.publisher=aep;}
As i said above, the listener works fine, just that not as suppossed. Instead execute him for each user, does it for the user who triggered the event only.
Related
I've seen a hundred examples of this:
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportResource;
#SpringBootApplication
#ImportResource("classpath:applicationContext.xml")
public class MySpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(MySpringBootApplication.class, args);
}
}
And I have been on a rabbit trail for many hours now.
I am building a framework....and I need load (a handful of dependencies, not all of them...) from the xml dependency injection file (aka, "beans") :
applicationContext.xml
and I need to name to be dynamic, not hard coded.
String myValue = "DefaultEnvVarValue";
String envValue = System.getenv("MYENVVARIABLENAME");
if (null != envValue )
{
myValue=envValue;
}
String topLevelAppContextFileName = "applicationContext." + myValue + ".xml";
Without springboot, I would do this:
ApplicationContext context = new ClassPathXmlApplicationContext(topLevelAppContextFileName);
Is there a way to pull this off with SpringBoot?
I found PropertySourcesPlaceholderConfigurer for property files, but cannot find anything for the dependency injection.
Sidenote:
Before I get a "xml bad" comment, most of my dependencies are annotation based. But I'm making a framework for others to use, and therefore I need a handful of them to be xml-driven.....aka, I have a legit reason to have some of the DI be xml driven.
This could work -
Config
public class DemoApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(ConfigurableApplicationContext ac) {
ac = new ClassPathXmlApplicationContext(topLevelAppContextFileName);
}
}
Main
public static void main(String args[]) {
new SpringApplicationBuilder(Application.class)
.initializers(new DemoApplicationContextInitializer())
.run(
}
For future readers, I ended up doing this:
#SpringBootApplication
#ImportResource({"classpath*:applicationContext.xml"})
public class MySpringBootApplication {
public static void main(String[] args) {
try {
URL resource = MySpringBootApplication.class.getResource("/applicationContext.xml");
if (null == resource || StringUtils.isBlank(resource.getPath())) {
throw new FileNotFoundException("applicationContext.xml not found. The entry dependency injection file must be applicationContext.xml");
}
org.springframework.context.ConfigurableApplicationContext applicationContext = SpringApplication.run(MySpringBootApplication.class, args);
And then I put the "dynamic" part in the inside applicationContext.xml file.
Note the ":" delimiter that will allow a default value if the environment variable does not exist.
<?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"
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">
<import resource="projectContext.${MYENVVARIABLENAME:DefaultEnvVarValue}.xml"/>
That was simpler to implement, even though I technically have 2 files, instead of one.
So if the environment variable does not exist, it will default to importing the second file called:
projectContext.DefaultEnvVarValue.xml
I need to integrate my webservice (Axis2) in spring integration: I have spring-axis2-message.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/integration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:stream="http://www.springframework.org/schema/integration/stream"
xmlns:ws="http://www.springframework.org/schema/integration/ws"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/stream
http://www.springframework.org/schema/integration/stream/spring-integration-stream.xsd
http://www.springframework.org/schema/integration/ws
http://www.springframework.org/schema/integration/ws/spring-integration-ws.xsd">
<chain input-channel="messageChannelIN" output-channel="messageChannelOUT">
<ws:header-enricher >
<ws:soap-action value="getMessageService"/>
</ws:header-enricher>
<ws:outbound-gateway uri="http://localhost:8080/axis2-webservice/services/wservices?wsdl" reply-channel="messageChannelOUT"/>
</chain>
<!-- The response from the service is logged to the console. -->
<stream:stdout-channel-adapter id="messageChannelOUT" append-newline="true" />
</beans:beans>
And a TestAxis2.java
package org.neos.spring.test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.integration.support.channel.BeanFactoryChannelResolver;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.core.DestinationResolver;
public class TestAxis2 {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"/META-INF/spring/integration/spring-axis2-message.xml");
DestinationResolver<MessageChannel> channelResolver = new BeanFactoryChannelResolver(context);
String requestXml =
"<getMessageService xmlns=\"http://service.ws.axis2.neos.org\">" +
"<name>HUGO</name>"
+ "</getMessageService>";
// Create the Message object
Message<String> message = MessageBuilder.withPayload(requestXml).build();
// Send the Message to the handler's input channel
MessageChannel channel = channelResolver.resolveDestination("messageChannelIN");
channel.send(message);
}
}
The program run very well and I can see in the console the next response:
<?xml version="1.0" encoding="UTF-8"?><ns:getMessageServiceResponse xmlns:ns="http://service.ws.axis2.neos.org"><ns:return>HELLO HUGO!, WELCOME TO WEBSERVICE AXIS1 hola</ns:return></ns:getMessageServiceResponse>
My question is how Can I manipulate/How can get the response in Java program because I need the response. I tried to do a lot of things but unfortunately did not work anything I only can see the response in the console but I need to manipulate the response.
I do not how can I access this configuration or if I need to configurate other things.
access<stream:stdout-channel-adapter id="messageChannelOUT" append-newline="true" />
Can Anyone help me please?
Use a Messaging Gateway.
public interface Gateway
String sendAndReceive(String out);
}
<int:gateway service-interface="foo.Gateway"
default-request-channel="messageChannelIN" />
Remove the output-channel from the chain
The reply will be returned to the caller via the gateway
Gatweway gw = context.getBean(Gateway.class);
...
String reply = gw.sendAndReceive(requestXml);
This has the added bonus of not exposing your application to the messaging infrastructure.
It's working my program right now!!. Thanks for your help Gary Russell!!! your comments were very useful.
The final code was:
xml configuration
........
<chain input-channel="messageChannelIN">
<ws:header-enricher>
<ws:soap-action value="getMessageService"/>
</ws:header-enricher>
<ws:outbound-gateway uri="http://localhost:8080/axis2-webservice/services/wservices?wsdl" />
</chain>
<gateway id="messageChannelOUT" service-interface="org.neos.spring.ws.service.GatewayAxis" default-request-channel="messageChannelIN"/>
Java Code:
public interface GatewayAxis {
#Gateway
String sendAndReceive(String out);}
TestAxis2
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"/META-INF/spring/integration/spring-axis2-message.xml");
GatewayAxis gateway = context.getBean(GatewayAxis.class);
String requestXml =
"<getMessageService xmlns=\"http://service.ws.axis2.neos.org\">" +
"<name>HUGO</name>"
+ "</getMessageService>";
String reply = gateway.sendAndReceive(requestXml);
System.out.println(reply);
}
I read the documentation here, but I think that the Spring documentation is sometimes complex and hard to understand, so I need a little explanation about BeanNameViewResolver.
Can I get a code example?
As explained in the documentation,BeanNameViewResolver resolves Views declared as beans. Most of the time you need it for some special-purpose views.
For example, we need to render an Excel spreadsheet.
For the Excel generation you will Apache POI
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.6</version>
</dependency>
So, you subclass AbstractExcelView and implement your custom logic to render a spreadsheet based on model values.
public class CustomExcelView extends AbstractExcelView {
#Override
protected void buildExcelDocument(Map model, HSSFWorkbook workbook,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
Map<String,String> revenueData = (Map<String,String>) model.get("revenueData");
//create a wordsheet
HSSFSheet sheet = workbook.createSheet("Revenue Report");
HSSFRow header = sheet.createRow(0);
header.createCell(0).setCellValue("Month");
header.createCell(1).setCellValue("Revenue");
int rowNum = 1;
for (Map.Entry<String, String> entry : revenueData.entrySet()) {
//create the row data
HSSFRow row = sheet.createRow(rowNum++);
row.createCell(0).setCellValue(entry.getKey());
row.createCell(1).setCellValue(entry.getValue());
}
}
}
and the controller simply adds the data
package com.example;
import java.util.HashMap;
import java.util.Map;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
#Controller
#RequestMapping("/excelview")
public class ExcelController {
public String getExcel(Model model){
Map<String,String> revenueData = new HashMap<String,String>();
revenueData.put("Jan-2010", "$100,000,000");
revenueData.put("Feb-2010", "$110,000,000");
revenueData.put("Mar-2010", "$130,000,000");
revenueData.put("Apr-2010", "$140,000,000");
revenueData.put("May-2010", "$200,000,000");
model.addAttribute("revenueData",revenueData);
return "myExcelView";
}
}
Then declaring an BeanNameViewResolver makes it available to controllers: when controller returns String with view name myExcelView, your spreadsheet will be rendered.
<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"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="com.example" />
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />
<bean id="myExcelView" class="com.example.CustomExcelView" />
</beans>
I need help!
so the following code works for me (Pure JUnit code)
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration("classpath:/importMasterConfig.xml")
public class FeatureWrittenInJavaUsingSteps {
#Before()
public void setup(){
/*do something*/
}
#After
public void tearDown()
{
/*Do something*/
}
#Autowired
ItemServiceController service;
#Test
public void callingStepFunctionsExample(){
ItemServiceControllerTestsSteps steps = new ItemServiceControllerTestsSteps(service);
steps.I_prepare_a_X_item_for_the_X_dealer("only images and pricing", "furniture");
steps.I_perform_the_X_inventory_service_call("createItem");
steps.I_should_get_the_X_response_code("200");
steps.the_inventory_service_response_result_should_be_a_X_object("Vertical Item");
}
}
However, when I try to run this code using the Cucumber Feature, it can't seem to build correctly. I am assuming I am setting up the project wrong.
Here is my Step code:
#ContextConfiguration("classpath:cucumber.xml")
public class ItemServiceControllerTestsSteps {
//Common variables across steps - currently only local.
private VerticalItem itemToCreate;
private ServiceResponse response;
//Step specific variables.
#Autowired
private ItemServiceController itemService;
public ItemServiceControllerTestsSteps(ItemServiceController service){
itemService = service;
}
#Before()
public void setup(){/*Do something*/}
#After()
public void tearDown(){/*Do Something*/}
#Given("^I prepare a \"(.*)\" item for the \"(.*)\" dealer$")
public VerticalItem I_prepare_a_X_item_for_the_X_dealer(String itemType, String dealerType){ //Step function and factory in one.
/*Do stuff*/}
#When("^I perform the \"(.*)\" inventory service call$")
public void I_perform_the_X_inventory_service_call(String actionType){
/*Do Stuff*/}
#Then("^I should get the \"(.*)\" response code$")
public void I_should_get_the_X_response_code(String codeType){/*Do stuff*/}
#Then("^the inventory service response result should be a \"(.*)\" object$")
public void the_inventory_service_response_result_should_be_a_X_object(String expectedClassType){ /*Do Stuff*/}
}
Here is my cucumber.xml file:
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="cucumber.runtime.java.spring stepDefinitions"/>
<context:annotation-config/>
<import resource="classpath:importMasterConfig.xml"/>
</beans>
Finally here is my Runner Class:
#RunWith(Cucumber.class)
#CucumberOptions(plugin = {"pretty", "rerun:rerun.txt", "html:target/local-html-report/"},
glue = "stepDefinitions.ItemServiceControllerTestsSteps")
public class CucumberRunner {}
If someone can please enlighten me why the JUnit runner works and the cucumber one doesn't I would be a very happy camper!
In the above code, I did a few things wrong but lets cover the big ones.
1) My Glue code String was incorrect, I need to pass in the package name, not the file name (should have been just stepDefinitions)
2) I was using Spring 3 instead of Spring 4 with Cucumber 1.2.2 - The latest Cucumber requires Spring 4.
The other stuff wasn't actually related to Spring and Cucumber.
Step definitions should be instance methods on the step definitions classes, and not class (static) methods.
Step definitions classes are instantiated (on demand) for each scenario, so no state should be leaked between scenarios.
This question already has answers here:
Why is my Spring #Autowired field null?
(21 answers)
Closed 8 years ago.
I've got a NullPointerException that is bugging the hell out of me. In my cursory research on SO I've found that this is usually happening when people are not autowiring their jdbctemplate, but as far as I can tell that should be wiring correctly. As a heads up I'm still learning the basics of Spring, and the code I'm working with is part of a legacy project.
ReportDaoImpl
#Service
public class ReportDaoImpl implements ReportDao {
#Autowired JdbcTemplate jdbcTemplate;
private static final Logger log = Logger.getLogger(ReportDaoImpl.class);
private static final String SELECT_ALL_ACCOUNT_INFO = "SELECT acct_name, login_name, pswd FROM PG_PAYPAL_ACCOUNTS";
#Autowired
public ReportDaoImpl(DataSource dataSource)
{
log.debug("attempt building");
jdbcTemplate = new JdbcTemplate(dataSource);
log.debug("building complete");
}
#Override
public ArrayList<String[]> getReportAccounts() {
log.debug("looking for accounts");
List<Map<String, Object>> resultList;
String[] accountDetails;
ArrayList<String[]> accounts = new ArrayList<String[]>();
try{
log.debug("Excecuting Query");
resultList = jdbcTemplate.queryForList(SELECT_ALL_ACCOUNT_INFO);
log.debug("Query Results");
log.debug(resultList.toString());
if(resultList != null && resultList.size() > 0){
for(Map<String, Object> temprow: resultList){
log.debug("Mapping Query Results to Account POJO");
accountDetails = new String[3];
accountDetails[0] = (String) temprow.get("acct_name");
accountDetails[1] = (String) temprow.get("login_name");
accountDetails[2] = (String) temprow.get("pswd");
log.debug("Single account details");
log.debug(accountDetails.toString());
log.debug("Adding single account to accounts array");
accounts.add(accountDetails);
}
}
return accounts;
} catch (Exception e){
log.debug("NO RESULTS: " + e);
System.out.println("NO RESULTS: " + e);
return null;
}
}
}
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: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.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config/>
<context:component-scan base-package="org.test.testpackage.report" annotation-config="false" />
<context:property-placeholder location="classpath:project-be.properties" />
<import resource="classpath:db-config.xml"/>
<bean id="pgReportService" name="pgReportService" class="org.test.testpackage.report.service.AccountLookup" scope="singleton" />
<bean id="jdbcTemplate" name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
Thanks so much!
The question is hard to read. What are you executing that is actually generating a NullPointerException?
For what I understand of your question you might be having a common mistake in Spring: If your variable jdbcTemplate is autowired in the ReportDaoImpl class then this class must be created also by autowiring and not by manual instantiation. Same thing happens for DataSource.
This means:
ReportDaoImpl reportDaoImp = new ReportDaoImpl(dataSource);
will not have an instatiated dataSource (non instantiated jdbcTemplate), because it is you who is actually making the instantiation and not letting Spring to do it.
So you need to specify a bean for ReportDaoImpl in your Application class, such as:
#Autowired
public ReportDaoImpl(DataSource dataSource){
ReportDaoImpl reportDaoImp = new ReportDaoImp();
reportDaoImp.setDataSource(dataSource);
return reportDaoImp;
}
And in the class where you use ReportDaoImp define an attribute:
#Autowired
ReportDaoImpl reportDaoImp;
This will instantiate DataSource (if the a bean for DataSource is also defined) and then instantiate a ReportDaoImpl passing this instance of DataSource.
Edit:
Actually this question answers might answer yours: Why is my Spring #Autowired field null?