How to extend Customer entity of Broadleaf Commerce? - broadleaf-commerce

I was trying to extend the Customer entity in my application based on DemoSite 5.0.1-GA. I had extended the original Customer interface and CustomerImpl class. Then added my CustomerImpl class into persistence-core.xml and applicationContext-entity.xml in the core project, overriding the bean with id "org.broadleafcommerce.profile.core.domain.Customer".
I could extend the Order entity successfully by these steps. But for the Customer entity, I found that I would always get an instance of org.broadleafcommerce.profile.core.domain.CustomerImpl, whether in relative entities like Order or directly get the "org.broadleafcommerce.profile.core.domain.Customer" bean from Spring context, but not an instance of my extended class as expected.
Here is my applicationContext-entity.xml, I omitted the attributes of the <beans> element:
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="org.broadleafcommerce.core.order.domain.Order" class="com.ddklife.core.ecommerce.domain.OrderImpl" scope="prototype"/>
<bean id="com.ddklife.core.autovending.domain.MachineChannel" class="com.ddklife.core.autovending.domain.MachineChannelImpl" scope="prototype"/>
<bean id="com.ddklife.core.autovending.domain.OrderChannelXref" class="com.ddklife.core.autovending.domain.OrderChannelXrefImpl" scope="prototype"/>
<bean id="org.broadleafcommerce.profile.core.domain.Customer" class="com.ddklife.core.customer.domain.CustomerImpl" scope="prototype"/>
</beans>
And here is my extended CustomerImpl class, I omitted all getters/setters methods:
package com.ddklife.core.customer.domain;
#Entity(name = "DdlCustomer")
#Inheritance(strategy = InheritanceType.JOINED)
#Table(name = "DDL_CUSTOMER")
#NamedQueries({
#NamedQuery(name="DD_READ_CUSTOMER_BY_WECHATOPENID", query="from DdlCustomer c where weChatOpenId = :weChatOpenId")
})
public class CustomerImpl extends org.broadleafcommerce.profile.core.domain.CustomerImpl implements Customer {
private static final long serialVersionUID = 1L;
#Column(name = "DDLIFE_POINTS")
protected Long ddlifePoints;
#Column(name = "WECHAT_OPEN_ID")
protected String weChatOpenId;
}
And here is my extended OrderImpl class, which could been loaded correctly from relative entities or using the getBean method of Spring context:
package com.ddklife.core.ecommerce.domain;
#Entity(name = "DdlOrder")
#Inheritance(strategy = InheritanceType.JOINED)
#Table(name = "DDL_ORDER")
public class OrderImpl extends org.broadleafcommerce.core.order.domain.OrderImpl implements Order {
private static final long serialVersionUID = 1L;
#Column(name = "STORE_TYPE")
protected String storeType;
#Column(name = "STORE_ID")
protected Long storeId;
#Column(name = "PAYMENT_QRCODE_URL")
protected String paymentQrcodeUrl;
#OneToMany(fetch = FetchType.LAZY, targetEntity = OrderChannelXrefImpl.class, mappedBy = "order", orphanRemoval = true,
cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
protected List<OrderChannelXref> allChannelXrefs = new ArrayList<OrderChannelXref>();
}

Can you post the entirety of your applicationContext-entity.xml? It should look like this:
<bean id="org.broadleafcommerce.profile.core.domain.Customer" class="com.mycompany.core.MyCustomer" scope="prototype" />
Things that could be going on:
You've got active sessions that already had a Broadleaf CustomerImpl stored there prior to your override; try clearing out all your cookies and trying again
You didn't do a mvn install of the core project prior to rebuilding the 'site' war file. When you go to build the site project, you need to make sure the core project is also included. You can do this with this Maven command from the root:
mvn -pl site -am clean install
That will ensure that the 'site' module and its dependencies (like core) are rebuilt

You need to add your new entity to :
/core/src/main/resources/META-INF/persistence-core.xml
<persistence-unit name="blPU" transaction-type="RESOURCE_LOCAL">
...
<class>com.mycompany.order.domain.MyOrderImpl</class>
...
</persistence-unit>

Related

How to save an entity for operations such as voting

let's take a youtube video page for example. after the page is rendered. you can upvote or downvote the video, and comment.
I'm having a similar case here. where an article is displayed with it's title and body(text). and I want to add the option for user so that they can vote. Two Entity looks like this:
public class Article implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private BigInteger id;
private User from;
private String title;
private String body;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "article")
private List<VoteArticle> votes = new ArrayList<>();
public class VoteArticle implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private BigInteger id;
#ManyToOne
#JoinColumn(name = "Article_ID", referencedColumnName = "id")
private Article article;
and I have jsf view that have a view param as the article's id article.xhtml?t=4
before rendering the view I look up and setup the article in the RequestScoped Bean (ArticleBean), then The view is rendered.
now as we all know since the bean is #RequestScoped all fields are re-initiliazed for every next request. So My question is, Do I need to get the article entity from the database every time I need to make an operation (voting, commenting) or is there a better way?
Right now my solution is to take the parameter view ".xhtml?t" and make a new Article entity, set its Id and use it.
Is something wrong with my solution? how do you implement such case? Thanks.
It sounds like setting your controller code to #ViewScoped instead of #RequestScoped would solve your problem.
You could make a method init() and give it a #PostConstruct annotation. Within init() you can pull your Article object from the database. Because the controller is view scoped these objects will stay until the user leaves the page.
You can call methods like voteUp() voteDown() on your ViewScoped controller via ajax calls and modify your Article object without having to pull it fresh from the DB each time.

PrimeFaces Wizard is not reset

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
}

Retrieving selectOneMenu complex object as selected item

I'm beginning with JSF (Mojarra 2.2 and Glassfish 4) and currently practicing with a web application which job is to store Clients and their Orders in DB.
When creating a new Order, one feature is to allow choosing an existing client from a JSF <h:selectOneMenu>. An Order entity stores a Client entity among other attributes...
I've followed BalusC's great answer about prepopulating a <h:selectOneMenu> from a DB (here), and have successfully populated mine from data stored in an eager ApplicationScoped ManagedBean, but I can't manage to retrieve the selected item in the backing bean as complex object. It is always null.
This is driving me mad and your help will be truly appreciated!
Here are the relevant code snippets:
#ManagedBean(eager = true)
#ApplicationScoped
public class Data implements Serializable {
private static final long serialVersionUID = 1L;
#EJB
private ClientDao clientDao;
private List<Client> clients;
#PostConstruct
private void init() {
clients = clientDao.lister();
}
public List<Client> getClients() {
return clients;
}
}
Order creation bean (note: 'commande' means order ;)
#ManagedBean
#RequestScoped
public class CreerCommandeBean implements Serializable {
private static final long serialVersionUID = 1L;
private Commande commande;
private String choixNouveauClient = "nouveauClient";
#EJB
private CommandeDao commandeDao;
public CreerCommandeBean() {
commande = new Commande();
}
public void inscrire() {
System.out.println("client : " + commande.getClient()); // prints **NULL**
// ... orderService to store in DB
}
... getters and setters
Client converter:
#FacesConverter(value = "clientConverter", forClass = Client.class)
public class ClientConverter implements Converter {
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (value == null) {
return null;
}
Data data = context.getApplication().evaluateExpressionGet(context, "#{data}", Data.class);
for (Client c : data.getClients()) {
if (c.getId().toString().equals(value)) {
return c;
}
}
throw new ConverterException(new FacesMessage(String.format("Cannot convert %s to Client", value)));
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
return (value instanceof Client) ? String.valueOf(((Client) value).getId()) : null;
}
}
Facelet excerpt:
<p:outputPanel id="gridContainerAncienClient">
<p:selectOneMenu value="#{creerCommandeBean.commande.client}"
rendered="#{creerCommandeBean.choixNouveauClient == 'ancienClient'}">
<f:converter converterId="clientConverter" />
<f:selectItems value="#{data.clients}" var="cli"
itemValue="#{cli}" itemLabel="#{cli.prenom} #{cli.nom}" />
</p:selectOneMenu>
</p:outputPanel>
CreerCommandeBean is #RequestScoped. That means it will live only for one request.
When you select a client to be assigned to #{creerCommandeBean.commande.client} you do this by a request. #{creerCommandeBean.commande.client} is now the selected client. Then the request is over, the bean gets destroyed and your "changes" are lost.
When you try to retrieve that data, you do that by a request again: A new instance of CreerCommandeBean is created and the constructor assigns the property commande with a new instance of Commande whose property client again is probably null.
Solution:
Use a broader scope. e.g. #ViewScoped which makes the bean "live" as long as you stay in the same view - no matter how many requests you make.
Tip:
Read BalusC's Post on Communication is JSF 2.0. Parts might be slightly different in JSF 2.2 but it's still a good and comprehensive introduction.
I got stuck with similar problem, only to realize that I forgot to implement equals() and hashCode() method in my Object. Client Class in this case.
I should blame myself for skipping the instructions in BalusC's blog.
"...Please note the Object#equals() implementation. This is very important for JSF. After conversion, it will compare the selected item against the items in the list. As the Object#equals() also require Object#hashCode(), this is implemented as well...."

MOXy un/marshal an object belonging to two different lists

This is my scenario.
I have a NodeElement class with two lists, inLinks and outLinks.
the Link class has two refrences to NodeElement, one for source and the other for target.
#XmlAccessorType(XmlAccessType.FIELD)
class NodeLement{
#XmlElement(name="link")
#XmlElementWrapper
private List<Link> inLinks = new ArrayList<Link>();
#XmlElement(name="link")
#XmlElementWrapper
private List<Link> outLinks = new ArrayList<Link>();
...
}
#XmlAccessorType(XmlAccessType.FIELD)
class Link{
#XmlInverseReference(mappedBy="inLinks")
private NodeElement source;
#XmlInverseReference(mappedBy="outLinks")
private NodeElement target;
public NodeElement getSource() {
return source;
}
public void setSource(NodeElement source) {
this.source = source;
this.source.getInLink().add(this);
}
public NodeElement getTarget() {
return target;
}
public void setTarget(NodeElement target) {
this.target = target;
this.target.getOutLink().add(this);
}
}
The test class
class test {
public static void main(String args[]) throws JAXBException, FileNotFoundException {
//rootelement
ContainerElement c = new ContainerElement();
Link link = new Link();
NodeElement target = new NodeElement();
NodeElement source = new NodeElement();
link.setSource(source);
link.setTarget(target);
c.addChild(target);
c.addChild(source);
JAXBContext jc = JAXBContext.newInstance(ContainerElement.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(c, new File(XML_MODEL));
}
}
The result :
<?xml version="1.0" encoding="UTF-8"?>
<containerElement>
<ID>427485825424142</ID>
<inLinks/>
<outLinks/>
<children>
<child xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="NodeElement">
<ID>427520478709873</ID>
<inLinks/>
<outLinks>
<link xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Link">
<ID>427582226289815</ID>
</link>
</outLinks>
</child>
<child xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="NodeElement">
<ID>427548409900894</ID>
<inLinks>
<link xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Link">
<ID>427582226289815</ID>
</link>
</inLinks>
<outLinks/>
</child>
</children>
</containerElement>
Obviously, i get two instances of Link when unmarshaling, each one has either the source or the target as null and the other target/source correctly set.
How could i fix this so the unmarshaling provides one instance of Link correctly initialized ?
I was thinking of using before and after marshal to resolve the relation between the source and the target but I am just learning JAXB, so any help would be appreciated
There are two kinds of way to represent relationships in XML:
Containment (i.e. #XmlElement) the referenced object is represented as child elements.
Reference (i.e. #XmlIDREF) the referenced object is represented with a foreign key (see: http://blog.bdoughan.com/2010/10/jaxb-and-shared-references-xmlid-and.html).
Every object (other than the root object) must be reachable through exacttly one containment relationship. Optionally it may be referenced by one or more reference relationships.
If you are looking to mix these concepts where the first time an object is encountered it is represented via containment and then subsequent times it is represented by reference then check out the following answer that contains a full example.
Can JAXB marshal by containment at first then marshal by #XmlIDREF for subsequent references?

How to save theme in Primefaces

I want to use Primefaces ThemeSwitcher. I'm interested how I can save the selected theme when I reload the web application. For example how I can set the theme name as variable from database?
You won't be needing the ThemeSwitcher to effect the kind of persistence you're looking for.
Simply perform the database lookup for the theme in a ServletContextListener and then store the value in the servlet context, possibly overriding whatever you've set in the web.xml
public Class MyContextListener implements ServletContextListener{
public void contextInitialized(ServletContextEvent sce){
String selectedTheme = myThemeDAO.getConfiguredTheme();
sce.getServletContext().setInitParameter("primefaces.THEME",selectedTheme);
}
}
link your ThemeSwitcher component to a managedBean and add a listener linked to a ajax event:
<h:form id="form-theme">
<p:themeSwitcher id="defaultSwitcher" value="#{themeSwitcherBean.theme}">
<f:selectItems value="#{themeSwitcherBean.themes}" />
<p:ajax listener="#{themeSwitcherBean.saveTheme}" />
</p:themeSwitcher>
</h:form>
in your managedbean create the method who call saveTheme, that going to call a class to persist in database, and call the the class for the database when start to get the theme who had saved into the database:
#SessionScoped
#ManagedBean(name="themeSwitcherBean")
public class ThemeSwitcherBean implements Serializable{
private Map<String, String> themes;
private String theme;
private GuestPreferences gp;
private void setGp(GuestPreferences gp) {
this.gp = gp;
}
public Map<String, String> getThemes() {
return themes;
}
public String getTheme() {
return theme;
}
public void setTheme(String theme) {
this.theme = theme;
}
#PostConstruct
public void init() {
setGp(new GuestPreferences()); // persistent class
setTheme(gp.getTheme()); // theme from the database;
themes = new TreeMap<String, String>();
themes.put("Aristo", "aristo");
themes.put("Black-Tie", "black-tie");
themes.put("Blitzer", "blitzer");
themes.put("Bluesky", "bluesky");
themes.put("Bootstrap", "bootstrap");
themes.put("Casablanca", "casablanca");
themes.put("Cupertino", "cupertino");
themes.put("Dark-Hive", "dark-hive");
themes.put("Dot-Luv", "dot-luv");
themes.put("Eggplant", "eggplant");
themes.put("Excite-Bike", "excite-bike");
themes.put("Flick", "flick");
themes.put("Glass-X", "glass-x");
themes.put("Hot-Sneaks", "hot-sneaks");
themes.put("Humanity", "humanity");
themes.put("Le-Frog", "le-frog");
themes.put("Midnight", "midnight");
themes.put("Mint-Choc", "mint-choc");
themes.put("Overcast", "overcast");
themes.put("Pepper-Grinder", "pepper-grinder");
themes.put("Redmond", "redmond");
themes.put("Rocket", "rocket");
themes.put("Sam", "sam");
themes.put("Smoothness", "smoothness");
themes.put("South-Street", "south-street");
themes.put("Start", "start");
themes.put("Sunny", "sunny");
themes.put("Swanky-Purse", "swanky-purse");
themes.put("Trontastic", "trontastic");
themes.put("UI-Darkness", "ui-darkness");
themes.put("UI-Lightness", "ui-lightness");
themes.put("Vader", "vader");
}
public void saveTheme() {
gp.setTheme(theme); // theme to database
}
}
method theme from class GuestPreferences is going to persist to the database
#SessionScoped
public class GuestPreferences {
public String getTheme(){
//return the theme from the database
}
public void setTheme(String theme){
//send the theme to the database
}
}
the form to send and receive data from the database depends of you prefer:
* jdbc
* jta
* jpa
for example, jta, make a persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="NAME-WHAT-YOU-WANT" transaction-type="JTA">
<provider>CLASS-OF-YOUR-PROVIDER</provider>
<jta-data-source>YOUR-DATASOURCE</jta-data-source>
<class>PATH-OF.GuestPreferences</class>
<properties>
<property name="NAME-OF-PROPERTY-TO-FORM-A-JDBC-URL" value="VALUE-OF-PROPERTY"/>
<property name="NAME-OF-PROPERTY-TO-FORM-A-JDBC-URL" value="VALUE-OF-PROPERTY"/>
<property name="NAME-OF-PROPERTY-TO-FORM-A-JDBC-URL" value="VALUE-OF-PROPERTY"/>
</properties>
</persistence-unit>
</persistence>
in a resources class you can declare:
#SuppressWarnings("unused")
#Produces
#PersistenceContext
private EntityManager em;
then, you can use it in your GuestPreferences class:
#Inject
private EntityManager em;
em.getTransaction().begin();
Query query = em.createQuery("SELECT u FROM user_table u where u.iduser=:iduser");
query.setParameter("iduser", "THEME-USER-ID");
User resultUser = (User) query.getResultList();
em.getTransaction().commit();
if(User!=null){
return resultUser.getTheme();
}
code above assumes you have a table called user_table where a user has a iduser, name ..., and a theme column, and it assumes you have an object called User to manage users
One more way to do this: include stylesheet to your pages template:
<h:body>
<h:outputStylesheet library="primefaces-#{themesBean.theme}" name="theme.css" /> </h:body>
Where #{themesBean.theme} variable reffers to name of your theme.
P.S. tested in PF5
I think setting selected theme in session would help:
session.setAttribute
Edit web.xml through code:
http://illegalargumentexception.blogspot.co.at/2008/08/java-using-xmlbeans-to-edit-webxml.html
<context-param>
<param-name>primefaces.THEME</param-name>
<param-value>EDITME</param-value>
</context-param>
Or create method before loading your page to choose the theme from db. (cleaner solution)

Resources