How can I ovveride CustomerStateRequestProcessor#resolveAuthenticatedCustomer function in broadleaf?
I tried this:-
#Component("blCustomerStateRequestProcessor")
public class MyCustomerStateRequestProcessor extends
CustomerStateRequestProcessor {
#Resource(name = "blCustomerService")
protected CustomerService customerService;
#Override
public Customer resolveAuthenticatedCustomer(Authentication authentication) {
if (authentication instanceof OpenIDAuthenticationToken) {
OpenIDAuthenticationToken openIDAuthenticationToken = (OpenIDAuthenticationToken) authentication;
if (openIDAuthenticationToken.isAuthenticated()) {
return (Customer) openIDAuthenticationToken.getPrincipal();
} else {
return null;
}
} else {
return super.resolveAuthenticatedCustomer(authentication);
}
}
}
Added context component scan :-
<context:component-scan base-package="org.broadleafcommerce.common.web.security,com.mycompany.web.request.processor" />
This resulted in :-
org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'blCustomerStateRequestProcessor' for bean class [org.broadleafcommerce.profile.web.core.security.CustomerStateRequestProcessor] conflicts with existing, non-compatible bean definition of same name and class [com.mycompany.web.request.processor.MyCustomerStateRequestProcessor]
I am trying to overrid resolveAuthenticatedCustomer method for OpenIdAuthenticationToken.
Thanks
Rather than use component-scanning to redefine the bean, remove that annotation and do it via XML instead.
So your class definition would change to:
public class MyCustomerStateRequestProcessor extends
CustomerStateRequestProcessor {
...
}
And then in any of your applicationContext.xml files (except for the servlet one) add this:
<bean id="blCustomerStateRequestProcessor" class="com.yourcompany.site.web.MyCustomerStateRequestProcessor" />
Note that this pattern is the same for overriding any Broadleaf-defined beans.
Related
From what I've read of the Spring #ContextConfiguration annotation, it's possible to load multiple XML context files, or multiple JavaConfig classes. What I need is to load from one XML context file and one class. All the examples I've seen either load all XML, or all classes, but not both.
I'm trying to do this because I want my test class, which is just there to verify expected Spring wiring, to load my default applicationContext.xml file (presently just a copy stored in "src/test/resources, and trying to figure out how to directly specify the default one) along with a JavaConfig class that specifies some JNDI resources that need to be available. For the purposes of my test, I only need to set those JNDI resources to dummy strings, but I'd really like to specify them in an inline static class instead of an external XML file, because my tests are going to have to verify that some settings are equal to those dummy strings, and it's more maintainable if both the values and the checks are in the same file.
What I have so far, and what I've tried, can be illustrated with this:
#RunWith(SpringRunner.class)
#ContextConfiguration(value = {"/testApplicationContext.xml", "/testResources.xml"})
//#ContextHierarchy({
// #ContextConfiguration("/testApplicationContext.xml"),
// #ContextConfiguration(classes = SpringWiringTest.Config.class)
//})
#TestPropertySource(properties = { "env = tomcat", "doNotifications = false" })
public class SpringWiringTest {
And this at the end of the class:
#Configuration
public static class Config {
#Bean public String uslDatasourcesList() { return "abc"; }
#Bean public String atgDatasourcesList() { return "abc"; }
#Bean public String uslTableNamePrefixsList() { return "abc"; }
#Bean public String atgTableNamePrefixsList() { return "abc"; }
#Bean public String doNotifications() { return "false"; }
#Bean public DataSource abc() { return new DriverManagerDataSource(); }
}
If I comment out the first #ContextConfiguration and comment back in the #ContextHierarchy block, I get an error like this:
Error creating bean with name 'uslDatasourcesList': Invocation of init
method failed; nested exception is
javax.naming.NoInitialContextException: Need to specify class name in
environment or system property, or as an applet parameter, or in an
application resource file: java.naming.factory.initial
Update:
Using the guideline of picking either JavaConfig or XML as the "entry point" to configuration, here are some modified excerpts that show what I'm trying:
#RunWith(SpringRunner.class)
#ContextConfiguration
//#ContextConfiguration(value = {"file:src/main/webapp/WEB-INF/applicationContext.xml", "/testResources.xml"})
#TestPropertySource(properties = { "env = tomcat", "doNotifications = false" })
public class SpringWiringTest {
...
#BeforeClass
public static void setup() throws Exception {
SimpleNamingContextBuilder builder = SimpleNamingContextBuilder.emptyActivatedContextBuilder();
DataSource ds = new DriverManagerDataSource();
builder.bind("java:comp/env/abc", ds);
}
...
#Configuration
#ImportResource("file:src/main/webapp/WEB-INF/applicationContext.xml")
public static class Config {
#Bean public String uslDatasourcesList() { return "abc"; }
#Bean public String atgDatasourcesList() { return "abc"; }
#Bean public String uslTableNamePrefixsList() { return "abc"; }
#Bean public String atgTableNamePrefixsList() { return "abc"; }
#Bean public String doNotifications() { return "false"; }
#Bean public DataSource abc() { return new DriverManagerDataSource(); }
}
}
When I run my test, the bottom "Caused by" in the exception says this:
Caused by: javax.naming.NameNotFoundException: Name
[uslDatasourcesList] not bound; 1 bindings: [java:comp/env/abc]
In the alternate version, using the commented-out "#ContextConfiguration" (and commenting out the Config class and its annotations), this error does not occur.
Note that this the meat of my "testResources.xml" file:
<bean id="uslDatasourcesList" class="java.lang.String"> <constructor-arg value="abc"/> </bean>
<bean id="atgDatasourcesList" class="java.lang.String"> <constructor-arg value="abc"/> </bean>
<bean id="uslTableNamePrefixList" class="java.lang.String"> <constructor-arg value="abc"/> </bean>
<bean id="atgTableNamePrefixList" class="java.lang.String"> <constructor-arg value="abc"/> </bean>
<bean id="doNotifications" class="java.lang.String"> <constructor-arg value="false"/> </bean>
<bean id="abc" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
</bean>
Note that the bean mentioned in the error message, "uslDatasourcesList" is defined in both versions, but it's not working in the version with JavaConfig and XML mixed.
It almost appears that the beans in the "#ImportResource" annotation are evaluated on their own, before the beans declared in the JavaConfig class are merged into it.
This is clearly documented in the Spring Reference Manual in the section named Mixing XML, Groovy scripts, and annotated classes.
In summary, ...
... you will have to pick one as the entry point, and that one will have to include or import the other.
Thus, the following should hopefully solve your problem.
#RunWith(SpringRunner.class)
#ContextConfiguration
#TestPropertySource(properties = { "env = tomcat", "doNotifications = false" })
public class SpringWiringTest {
// ...
#Configuration
#ImportResource({"/testApplicationContext.xml", "/testResources.xml"})
static class Config {
// ...
}
}
I would like to pass an value to a managed bean under the hood. So I have this managed bean:
#ManagedBean(name = "mbWorkOrderController")
#SessionScoped
public class WorkOrderController {
// more attributes...
private WorkOrder workOrderCurrent;
// more code here...
public WorkOrder getWorkOrderCurrent() {
return workOrderCurrent;
}
public void setWorkOrderCurrent(WorkOrder workOrderCurrent) {
this.workOrderCurrent = workOrderCurrent;
}
}
It holds a parameter workOrderCurrent of the custom type WorkOrder. The class WorkOrder has an attribute applicant of type String.
At the moment I am using a placeholder inside my inputtext to show the user, what he needs to type inside an inputText.
<p:inputText id="applicant"
value="#{mbWorkOrderController.workOrderCurrent.applicant}"
required="true" maxlength="6"
placeholder="#{mbUserController.userLoggedIn.username}" />
What I want to do, is to automatically pass the value of mbUserController.userLoggedIn.username to mbWorkOrderController.workOrderCurrent.applicant and remove the inputText for applicant completely from my form.
I tried to use c:set:
<c:set value="#{mbUserController.userLoggedIn.username}" target="#{mbWorkOrderController}" property="workOrderCurrent.applicant" />
But unfortunatelly I get a javax.servlet.ServletException with the message:
The class 'WorkOrderController' does not have the property 'workOrderCurrent.applicant'.
Does anybody have an advice?
The class 'WorkOrderController' does not have the property 'workOrderCurrent.applicant'.
Your <c:set> syntax is incorrect.
<c:set value="#{mbUserController.userLoggedIn.username}"
target="#{mbWorkOrderController}"
property="workOrderCurrent.applicant" />
You seem to be thinking that the part..
value="#{mbWorkOrderController.workOrderCurrent.applicant}"
..works under the covers as below:
WorkOrderCurrent workOrderCurrent = mbWorkOrderController.getWorkOrderCurrent();
workOrderCurrent.setApplicant(applicant);
mbWorkOrderController.setWorkOrderCurrent(workOrderCurrent);
This isn't true. It works under the covers as below:
mbWorkOrderController.getWorkOrderCurrent().setApplicant(applicant);
The correct <c:set> syntax is therefore as below:
<c:set value="#{mbUserController.userLoggedIn.username}"
target="#{mbWorkOrderController.workOrderCurrent}"
property="applicant" />
That said, all of this isn't the correct solution to the concrete problem you actually tried to solve. You should perform model prepopulating in the model itself. This can be achieved by using #ManagedProperty to reference another bean property and by using #PostConstruct to perform initialization based on it.
#ManagedBean(name = "mbWorkOrderController")
#SessionScoped
public class WorkOrderController {
#ManagedProperty("#{mbUserController.userLoggedIn}")
private User userLoggedIn;
#PostConstruct
public void init() {
workOrderCurrent.setApplicant(userLoggedIn.getUsername());
}
// ...
}
Perhaps you could explain the context a bit more, but here's another solution. If you're navigating from another page, you can pass some identifier of work WorkOrder in the URL, like this http://host:port/context/page.xhtml?workOrderId=1.
Then, you can set the identifier in the managed bean like this:
<h:html>
<f:viewParam name="workOrderId" value="#{mbWorkOrderController.id}"/>
</h:html>
You'll have to add a new property to your bean:
public class WorkOrderController {
private long id;
public long getId() { return id; }
public void setId(long id) { this.id = id; }
// ...
}
And then, after the property has been set by JSF, you can find the work order in a lifecycle event:
<h:html>
<f:viewParam name="workOrderId" value="#{mbWorkOrderController.id}"/>
<f:event type="preRenderView" listener="#{mbWorkOrderController.findWorkOrder()}"/>
</h:html>
public class WorkOrderController {
private long id;
public long getId() { return id; }
public void setId(long id) { this.id = id; }
public void findWorkOrder() {
this.workOrderCurrent = null /* some way of finding the work order */
}
// ...
}
This strategy has the advantage of letting you have bookmarkable URLs.
I'm trying to develop a custom component that will need to call a method from the backingbean to get some data from the bb (this will be called in the decode phase after a certain Ajax call) with one parameter (it will come in the ajax call).
The problem I'm having is that I define the attribute as a MethodExpression (in the taglibrary and the component), I get the Ajax post, decode the parameter and when I try to get the Method binding from the component I get the following error:
javax.el.PropertyNotFoundException: /easyFaces.xhtml #19,151
dataSource="#{theBean.loadDataFromSource}": The class
'ar.com.easytech.faces.test.homeBean' does not have the property
'loadDataFromBean'.
Here is the relevant code.. (and please let me know if this is not the correct way to do this..)
taglib:
<attribute>
<display-name>Data Source</display-name>
<name>dataSource</name>
<required>true</required>
<type>javax.el.MethodExpression</type>
<method-signature>java.util.List theDataSource(java.lang.String)</method-signature>
</attribute>
Component definition:
public class Autocomplete extends HtmlInputText implements ClientBehaviorHolder
...
public MethodExpression getDataSource() {
return (MethodExpression) getStateHelper().eval(PropertyKeys.dataSource);
}
public void setDataSource(MethodExpression dataSource) {
getStateHelper().put(PropertyKeys.dataSource, dataSource);
}
and finally the rendered method that generates the error:
private List<Object> getData(FacesContext context, Autocomplete autocomplete, String data) {
Object dataObject = null;
MethodExpression dataSource = autocomplete.getDataSource();
if (dataSource != null) {
try {
dataObject = dataSource.invoke(context.getELContext(), new Object[] {data});
return convertToList(dataObject);
} catch (MethodNotFoundException e) {
logger.log(Level.INFO,"Method not found: {0}", dataSource.getExpressionString() );
}
}
return null;
}
Here is the method from the BB
public List<String> autcompleteFromSource(String param) {
List<String> tmpData = new ArrayList<String>();
tmpData.add("XXA_TABLE_A");
tmpData.add("XXA_TABLE_B");
tmpData.add("XXA_TABLE_C");
return tmpData;
}
And the .xhtml with the component
<et:autocomplete id="autoc" minLength="3" delay="500" value="#{easyfacesBean.selectedValue}" dataSource="#{easyfacesBean.autcompleteFromSource}" />
The thing is if I define a method getAutocompleteFromSource() it recognised the method and the error changes to can't convert list to MethodExpression, so evidently it is simply interpreting the autocompleteFromSource as a simple property and not a method definition, is this even the correct way to call method from BB? (giving that it's not an actual action nor validation )
I found the solution for this, as it turns out you also need to define a "Handler"to define the Method Signature, so I created the handler and added to the taglib and everything started to work fine..just for reference.. here is the handler..
Regards
public class AutocompleteHandler extends ComponentHandler {
public AutocompleteHandler(ComponentConfig config) {
super(config);
}
protected MetaRuleset createMetaRuleset(Class type) {
MetaRuleset metaRuleset = super.createMetaRuleset(type);
metaRuleset.addRule(new MethodRule("dataSource", List.class, new Class[] { String.class }));
return metaRuleset;
}
}
We are using the PrimeFaces 4.0 + spring 4 on Tomcat 7.
I go to PrimeFaces show case, open the wizard, type first name and last name hit the next button. Then I select other menus from left panel ( like AutoComplete ) I go back to wizard the first name and last name fields are clear. That is what I expected.
I developed a wizard same as above but every time I come back to wizard page the wizard still holds the previously entered value and is not reset.
My managed bean is as below ( I have used ViewScoped no SessionScope which mentioned in documents):
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#Named
#ViewScoped
public class AccountController {
#Valid
private Account account = new Account()
//Setters and getters
}
Edited:
I found that the problem is for integration of JSF and Spring. When I remove the #Named and use #ManagedBean it works fine. Any comments?!
Spring does not have a built in support for JSF ViewScope, but you can add this scope to JSF as:
public class ViewScope implements Scope {
public Object get(String name, ObjectFactory<?> objectFactory) {
Map<String, Object> viewMap = FacesContext.getCurrentInstance()
.getViewRoot().getViewMap();
if (viewMap.containsKey(name)) {
return viewMap.get(name);
} else {
Object object = objectFactory.getObject();
viewMap.put(name, object);
return object;
}
}
public Object remove(String name) {
return FacesContext.getCurrentInstance().getViewRoot().getViewMap()
.remove(name);
}
public String getConversationId() {
return null;
}
public void registerDestructionCallback(String name, Runnable callback) {
// Not supported
}
public Object resolveContextualObject(String key) {
return null;
}
}
Please refer to http://blog.primefaces.org/?p=702
And in your applicationConetext.xml
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="view">
<bean class="utils.ViewScope" />
</entry>
</map>
</property>
</bean>
And finally:
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#Named
#ViewScoped
#Scope("view")
public class AccountController {
#Valid
private Account account = new Account()
//Setters and getters
}
Let's start with an example :
In my JPA entity
public class User {
#Pattern("^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*#([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9})$", message="invalidEmailResourceBundleKey")
private String email;
#Min(5, message="minimumResourceBundleKey")
private int age;
...
}
In my JSF Bean
public class UserBean {
private User user;
// do i have to redefine it here, since it's already a part of the user ?
##Pattern("^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*#([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9})$")
public String getEmail() {
return user.getEmail();
}
public void setEmail(String s) {
user.setEmail(s);
}
// do i have to redefine it here, since it's already a part of the user ?
#Min(5, message="minimumResourceBundleKey")
public int getAge() {
return user.getAge();
}
public void setAge(int age) {
user.setAge(age);
}
}
Is it possible to reuse the the validations for the entities for the JSF beans that actually delegates the method calls to the entities, so that i dont have to redefine the bean validations on the JSF beans ?
Can i even extend the reusing to the level of the error message in resource bundle, and whether the message can be parameterized with {0} etc like the usual ? I wonder if there's any example on the web for this, since i've been unable to find none.
Please share your thoughts on this ..
Thank you !
You don't need to redefine them if you don't unnecessarily flatten the bean properties. Just have a getUser() instead.
public class UserManager {
private User user;
public User getUser() {
return user;
}
}
And bind to the properties of the JPA entity directly.
<h:inputText value="#{userManager.user.email}" />
<h:inputText value="#{userManager.user.age}" />
Unrelated to the concrete problem, your email regex will fail for internationalized domain names (IDN) which are introduced last year. I'd fix the regex to not only accept latin characters. See also this answer for an example.