net.groupbuy.entity.Product.java Source code

Java tutorial

Introduction

Here is the source code for net.groupbuy.entity.Product.java

Source

/*
 * Copyright 2005-2013 shopxx.net. All rights reserved.
 * Support: http://www.shopxx.net
 * License: http://www.shopxx.net/license
 */
package net.groupbuy.entity;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import javax.persistence.CascadeType;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.Lob;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.PrePersist;
import javax.persistence.PreRemove;
import javax.persistence.PreUpdate;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.validation.Valid;
import javax.validation.constraints.Digits;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;

import net.groupbuy.BigDecimalNumericFieldBridge;
import net.groupbuy.CommonAttributes;
import net.groupbuy.util.FreemarkerUtils;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import org.dom4j.io.SAXReader;
import org.hibernate.search.annotations.Analyzer;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.FieldBridge;
import org.hibernate.search.annotations.Index;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.annotations.NumericField;
import org.hibernate.search.annotations.Similarity;
import org.hibernate.search.annotations.Store;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.core.io.ClassPathResource;
import org.wltea.analyzer.lucene.IKAnalyzer;
import org.wltea.analyzer.lucene.IKSimilarity;

import com.fasterxml.jackson.annotation.JsonProperty;

import freemarker.template.TemplateException;

/**
 * Entity - ?
 * 
 * @author SHOP++ Team
 * @version 3.0
 */
@Indexed
@Similarity(impl = IKSimilarity.class)
@Entity
@Table(name = "xx_product")
@SequenceGenerator(name = "sequenceGenerator", sequenceName = "xx_product_sequence")
public class Product extends BaseEntity {

    private static final long serialVersionUID = 2167830430439593293L;

    /** ?? */
    public static final String HITS_CACHE_NAME = "productHits";

    /**  */
    public static final int HITS_CACHE_INTERVAL = 600000;

    /** ? */
    public static final int ATTRIBUTE_VALUE_PROPERTY_COUNT = 20;

    /** ???? */
    public static final String ATTRIBUTE_VALUE_PROPERTY_NAME_PREFIX = "attributeValue";

    /** ? */
    public static final String FULL_NAME_SPECIFICATION_PREFIX = "[";

    /** ? */
    public static final String FULL_NAME_SPECIFICATION_SUFFIX = "]";

    /**  */
    public static final String FULL_NAME_SPECIFICATION_SEPARATOR = " ";

    /** ?? */
    private static String staticPath;

    /**
     * ?
     */
    public enum OrderType {

        /** ?? */
        topDesc,

        /** ?? */
        priceAsc,

        /** ?? */
        priceDesc,

        /** ??? */
        salesDesc,

        /** ?? */
        scoreDesc,

        /** ?? */
        dateDesc
    }

    /** ? */
    private String sn;

    /** ?? */
    private String name;

    /**  */
    private String fullName;

    /**  */
    private BigDecimal price;

    /** ? */
    private BigDecimal cost;

    /**  */
    private BigDecimal marketPrice;

    /**  */
    private String image;

    /** ?? */
    private String unit;

    /** ?? */
    private Integer weight;

    /**  */
    private Integer stock;

    /** ? */
    private Integer allocatedStock;

    /**  */
    private String stockMemo;

    /** ? */
    private Long point;

    /** ? */
    private Boolean isMarketable;

    /** ? */
    private Boolean isList;

    /** ? */
    private Boolean isTop;

    /** ?? */
    private Boolean isGift;

    /** ? */
    private String introduction;

    /**  */
    private String memo;

    /** ?? */
    private String keyword;

    /** ? */
    private String seoTitle;

    /** ?? */
    private String seoKeywords;

    /** ??? */
    private String seoDescription;

    /**  */
    private Float score;

    /**  */
    private Long totalScore;

    /**  */
    private Long scoreCount;

    /**  */
    private Long hits;

    /**  */
    private Long weekHits;

    /**  */
    private Long monthHits;

    /** ? */
    private Long sales;

    /** ? */
    private Long weekSales;

    /** ? */
    private Long monthSales;

    /**  */
    private Date weekHitsDate;

    /**  */
    private Date monthHitsDate;

    /** ? */
    private Date weekSalesDate;

    /** ? */
    private Date monthSalesDate;

    /** ?0 */
    private String attributeValue0;

    /** ?1 */
    private String attributeValue1;

    /** ?2 */
    private String attributeValue2;

    /** ?3 */
    private String attributeValue3;

    /** ?4 */
    private String attributeValue4;

    /** ?5 */
    private String attributeValue5;

    /** ?6 */
    private String attributeValue6;

    /** ?7 */
    private String attributeValue7;

    /** ?8 */
    private String attributeValue8;

    /** ?9 */
    private String attributeValue9;

    /** ?10 */
    private String attributeValue10;

    /** ?11 */
    private String attributeValue11;

    /** ?12 */
    private String attributeValue12;

    /** ?13 */
    private String attributeValue13;

    /** ?14 */
    private String attributeValue14;

    /** ?15 */
    private String attributeValue15;

    /** ?16 */
    private String attributeValue16;

    /** ?17 */
    private String attributeValue17;

    /** ?18 */
    private String attributeValue18;

    /** ?19 */
    private String attributeValue19;

    /** ? */
    private ProductCategory productCategory;

    /** ? */
    private Goods goods;

    /** ? */
    private Brand brand;

    /** ? */
    private List<ProductImage> productImages = new ArrayList<ProductImage>();

    /**  */
    private Set<Review> reviews = new HashSet<Review>();

    /**  */
    private Set<Consultation> consultations = new HashSet<Consultation>();

    /**  */
    private Set<Tag> tags = new HashSet<Tag>();

    /** ? */
    private Set<Member> favoriteMembers = new HashSet<Member>();

    /**  */
    private Set<Specification> specifications = new HashSet<Specification>();

    /**  */
    private Set<SpecificationValue> specificationValues = new HashSet<SpecificationValue>();

    /**  */
    private Set<Promotion> promotions = new HashSet<Promotion>();

    /**  */
    private Set<CartItem> cartItems = new HashSet<CartItem>();

    /** ? */
    private Set<OrderItem> orderItems = new HashSet<OrderItem>();

    /** ? */
    private Set<GiftItem> giftItems = new HashSet<GiftItem>();

    /**  */
    private Set<ProductNotify> productNotifies = new HashSet<ProductNotify>();

    /**  */
    private Map<MemberRank, BigDecimal> memberPrice = new HashMap<MemberRank, BigDecimal>();

    /** ? */
    private Map<Parameter, String> parameterValue = new HashMap<Parameter, String>();

    static {
        try {
            File shopxxXmlFile = new ClassPathResource(CommonAttributes.SHOPXX_XML_PATH).getFile();
            org.dom4j.Document document = new SAXReader().read(shopxxXmlFile);
            org.dom4j.Element element = (org.dom4j.Element) document
                    .selectSingleNode("/groupbuy/template[@id='productContent']");
            staticPath = element.attributeValue("staticPath");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * ??
     * 
     * @return ?
     */
    @JsonProperty
    @Field(store = Store.YES, index = Index.UN_TOKENIZED)
    @Pattern(regexp = "^[0-9a-zA-Z_-]+$")
    @Length(max = 100)
    @Column(nullable = false, unique = true, length = 100)
    public String getSn() {
        return sn;
    }

    /**
     * ?
     * 
     * @param sn
     *            ?
     */
    public void setSn(String sn) {
        this.sn = sn;
    }

    /**
     * ???
     * 
     * @return ??
     */
    @JsonProperty
    @Field(store = Store.YES, index = Index.TOKENIZED, analyzer = @Analyzer(impl = IKAnalyzer.class))
    @NotEmpty
    @Length(max = 200)
    @Column(nullable = false)
    public String getName() {
        return name;
    }

    /**
     * ??
     * 
     * @param name
     *            ??
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * ?
     * 
     * @return 
     */
    @JsonProperty
    @Field(store = Store.YES, index = Index.NO)
    @Column(nullable = false)
    public String getFullName() {
        return fullName;
    }

    /**
     * 
     * 
     * @param fullName
     *            
     */
    public void setFullName(String fullName) {
        this.fullName = fullName;
    }

    /**
     * ?
     * 
     * @return 
     */
    @JsonProperty
    @Field(store = Store.YES, index = Index.UN_TOKENIZED)
    @NumericField
    @FieldBridge(impl = BigDecimalNumericFieldBridge.class)
    @NotNull
    @Min(0)
    @Digits(integer = 12, fraction = 3)
    @Column(nullable = false, precision = 21, scale = 6)
    public BigDecimal getPrice() {
        return price;
    }

    /**
     * 
     * 
     * @param price
     *            
     */
    public void setPrice(BigDecimal price) {
        this.price = price;
    }

    /**
     * ??
     * 
     * @return ?
     */
    @Min(0)
    @Digits(integer = 12, fraction = 3)
    @Column(precision = 21, scale = 6)
    public BigDecimal getCost() {
        return cost;
    }

    /**
     * ?
     * 
     * @param cost
     *            ?
     */
    public void setCost(BigDecimal cost) {
        this.cost = cost;
    }

    /**
     * ?
     * 
     * @return 
     */
    @Field(store = Store.YES, index = Index.NO)
    @Min(0)
    @Digits(integer = 12, fraction = 3)
    @Column(nullable = false, precision = 21, scale = 6)
    public BigDecimal getMarketPrice() {
        return marketPrice;
    }

    /**
     * 
     * 
     * @param marketPrice
     *            
     */
    public void setMarketPrice(BigDecimal marketPrice) {
        this.marketPrice = marketPrice;
    }

    /**
     * ?
     * 
     * @return 
     */
    @JsonProperty
    @Field(store = Store.YES, index = Index.NO)
    @Length(max = 200)
    public String getImage() {
        return image;
    }

    /**
     * 
     * 
     * @param image
     *            
     */
    public void setImage(String image) {
        this.image = image;
    }

    /**
     * ???
     * 
     * @return ??
     */
    @JsonProperty
    @Field(store = Store.YES, index = Index.NO)
    @Length(max = 200)
    public String getUnit() {
        return unit;
    }

    /**
     * ??
     * 
     * @param unit
     *            ??
     */
    public void setUnit(String unit) {
        this.unit = unit;
    }

    /**
     * ???
     * 
     * @return ??
     */
    @Field(store = Store.YES, index = Index.NO)
    @Min(0)
    public Integer getWeight() {
        return weight;
    }

    /**
     * ??
     * 
     * @param weight
     *            ??
     */
    public void setWeight(Integer weight) {
        this.weight = weight;
    }

    /**
     * ?
     * 
     * @return 
     */
    @Field(store = Store.YES, index = Index.NO)
    @Min(0)
    public Integer getStock() {
        return stock;
    }

    /**
     * 
     * 
     * @param stock
     *            
     */
    public void setStock(Integer stock) {
        this.stock = stock;
    }

    /**
     * ??
     * 
     * @return ?
     */
    @Field(store = Store.YES, index = Index.NO)
    @Column(nullable = false)
    public Integer getAllocatedStock() {
        return allocatedStock;
    }

    /**
     * ?
     * 
     * @param allocatedStock
     *            ?
     */
    public void setAllocatedStock(Integer allocatedStock) {
        this.allocatedStock = allocatedStock;
    }

    /**
     * ?
     * 
     * @return 
     */
    @Length(max = 200)
    public String getStockMemo() {
        return stockMemo;
    }

    /**
     * 
     * 
     * @param stockMemo
     *            
     */
    public void setStockMemo(String stockMemo) {
        this.stockMemo = stockMemo;
    }

    /**
     * ??
     * 
     * @return ?
     */
    @Field(store = Store.YES, index = Index.NO)
    @Min(0)
    @Column(nullable = false)
    public Long getPoint() {
        return point;
    }

    /**
     * ?
     * 
     * @param point
     *            ?
     */
    public void setPoint(Long point) {
        this.point = point;
    }

    /**
     * ??
     * 
     * @return ?
     */
    @Field(store = Store.YES, index = Index.UN_TOKENIZED)
    @NotNull
    @Column(nullable = false)
    public Boolean getIsMarketable() {
        return isMarketable;
    }

    /**
     * ?
     * 
     * @param isMarketable
     *            ?
     */
    public void setIsMarketable(Boolean isMarketable) {
        this.isMarketable = isMarketable;
    }

    /**
     * ??
     * 
     * @return ?
     */
    @Field(store = Store.YES, index = Index.UN_TOKENIZED)
    @NotNull
    @Column(nullable = false)
    public Boolean getIsList() {
        return isList;
    }

    /**
     * ?
     * 
     * @param isList
     *            ?
     */
    public void setIsList(Boolean isList) {
        this.isList = isList;
    }

    /**
     * ??
     * 
     * @return ?
     */
    @Field(store = Store.YES, index = Index.UN_TOKENIZED)
    @NotNull
    @Column(nullable = false)
    public Boolean getIsTop() {
        return isTop;
    }

    /**
     * ?
     * 
     * @param isTop
     *            ?
     */
    public void setIsTop(Boolean isTop) {
        this.isTop = isTop;
    }

    /**
     * ???
     * 
     * @return ??
     */
    @JsonProperty
    @Field(store = Store.YES, index = Index.UN_TOKENIZED)
    @NotNull
    @Column(nullable = false)
    public Boolean getIsGift() {
        return isGift;
    }

    /**
     * ??
     * 
     * @param isGift
     *            ??
     */
    public void setIsGift(Boolean isGift) {
        this.isGift = isGift;
    }

    /**
     * ??
     * 
     * @return ?
     */
    @Field(store = Store.YES, index = Index.TOKENIZED, analyzer = @Analyzer(impl = IKAnalyzer.class))
    @Lob
    public String getIntroduction() {
        return introduction;
    }

    /**
     * ?
     * 
     * @param introduction
     *            ?
     */
    public void setIntroduction(String introduction) {
        this.introduction = introduction;
    }

    /**
     * ?
     * 
     * @return 
     */
    @Length(max = 200)
    public String getMemo() {
        return memo;
    }

    /**
     * 
     * 
     * @param memo
     *            
     */
    public void setMemo(String memo) {
        this.memo = memo;
    }

    /**
     * ???
     * 
     * @return ??
     */
    @Field(store = Store.YES, index = Index.TOKENIZED, analyzer = @Analyzer(impl = IKAnalyzer.class))
    @Length(max = 200)
    public String getKeyword() {
        return keyword;
    }

    /**
     * ??
     * 
     * @param keyword
     *            ??
     */
    public void setKeyword(String keyword) {
        if (keyword != null) {
            keyword = keyword.replaceAll("[,\\s]*,[,\\s]*", ",").replaceAll("^,|,$", "");
        }
        this.keyword = keyword;
    }

    /**
     * ??
     * 
     * @return ?
     */
    @Length(max = 200)
    public String getSeoTitle() {
        return seoTitle;
    }

    /**
     * ?
     * 
     * @param seoTitle
     *            ?
     */
    public void setSeoTitle(String seoTitle) {
        this.seoTitle = seoTitle;
    }

    /**
     * ???
     * 
     * @return ??
     */
    @Length(max = 200)
    public String getSeoKeywords() {
        return seoKeywords;
    }

    /**
     * ??
     * 
     * @param seoKeywords
     *            ??
     */
    public void setSeoKeywords(String seoKeywords) {
        if (seoKeywords != null) {
            seoKeywords = seoKeywords.replaceAll("[,\\s]*,[,\\s]*", ",").replaceAll("^,|,$", "");
        }
        this.seoKeywords = seoKeywords;
    }

    /**
     * ????
     * 
     * @return ???
     */
    @Length(max = 200)
    public String getSeoDescription() {
        return seoDescription;
    }

    /**
     * ???
     * 
     * @param seoDescription
     *            ???
     */
    public void setSeoDescription(String seoDescription) {
        this.seoDescription = seoDescription;
    }

    /**
     * ?
     * 
     * @return 
     */
    @Field(store = Store.YES, index = Index.UN_TOKENIZED)
    @NumericField
    @Column(nullable = false, precision = 12, scale = 6)
    public Float getScore() {
        return score;
    }

    /**
     * 
     * 
     * @param score
     *            
     */
    public void setScore(Float score) {
        this.score = score;
    }

    /**
     * ?
     * 
     * @return 
     */
    @Column(nullable = false)
    public Long getTotalScore() {
        return totalScore;
    }

    /**
     * 
     * 
     * @param totalScore
     *            
     */
    public void setTotalScore(Long totalScore) {
        this.totalScore = totalScore;
    }

    /**
     * ?
     * 
     * @return 
     */
    @Field(store = Store.YES, index = Index.UN_TOKENIZED)
    @Column(nullable = false)
    public Long getScoreCount() {
        return scoreCount;
    }

    /**
     * 
     * 
     * @param scoreCount
     *            
     */
    public void setScoreCount(Long scoreCount) {
        this.scoreCount = scoreCount;
    }

    /**
     * ?
     * 
     * @return 
     */
    @Field(store = Store.YES, index = Index.UN_TOKENIZED)
    @Column(nullable = false)
    public Long getHits() {
        return hits;
    }

    /**
     * 
     * 
     * @param hits
     *            
     */
    public void setHits(Long hits) {
        this.hits = hits;
    }

    /**
     * ?
     * 
     * @return 
     */
    @Field(store = Store.YES, index = Index.NO)
    @Column(nullable = false)
    public Long getWeekHits() {
        return weekHits;
    }

    /**
     * 
     * 
     * @param weekHits
     *            
     */
    public void setWeekHits(Long weekHits) {
        this.weekHits = weekHits;
    }

    /**
     * ?
     * 
     * @return 
     */
    @Field(store = Store.YES, index = Index.NO)
    @Column(nullable = false)
    public Long getMonthHits() {
        return monthHits;
    }

    /**
     * 
     * 
     * @param monthHits
     *            
     */
    public void setMonthHits(Long monthHits) {
        this.monthHits = monthHits;
    }

    /**
     * ??
     * 
     * @return ?
     */
    @Field(store = Store.YES, index = Index.UN_TOKENIZED)
    @Column(nullable = false)
    public Long getSales() {
        return sales;
    }

    /**
     * ?
     * 
     * @param sales
     *            ?
     */
    public void setSales(Long sales) {
        this.sales = sales;
    }

    /**
     * ??
     * 
     * @return ?
     */
    @Field(store = Store.YES, index = Index.NO)
    @Column(nullable = false)
    public Long getWeekSales() {
        return weekSales;
    }

    /**
     * ?
     * 
     * @param weekSales
     *            ?
     */
    public void setWeekSales(Long weekSales) {
        this.weekSales = weekSales;
    }

    /**
     * ??
     * 
     * @return ?
     */
    @Field(store = Store.YES, index = Index.NO)
    @Column(nullable = false)
    public Long getMonthSales() {
        return monthSales;
    }

    /**
     * ?
     * 
     * @param monthSales
     *            ?
     */
    public void setMonthSales(Long monthSales) {
        this.monthSales = monthSales;
    }

    /**
     * ?
     * 
     * @return 
     */
    @Column(nullable = false)
    public Date getWeekHitsDate() {
        return weekHitsDate;
    }

    /**
     * 
     * 
     * @param weekHitsDate
     *            
     */
    public void setWeekHitsDate(Date weekHitsDate) {
        this.weekHitsDate = weekHitsDate;
    }

    /**
     * ?
     * 
     * @return 
     */
    @Column(nullable = false)
    public Date getMonthHitsDate() {
        return monthHitsDate;
    }

    /**
     * 
     * 
     * @param monthHitsDate
     *            
     */
    public void setMonthHitsDate(Date monthHitsDate) {
        this.monthHitsDate = monthHitsDate;
    }

    /**
     * ??
     * 
     * @return ?
     */
    @Column(nullable = false)
    public Date getWeekSalesDate() {
        return weekSalesDate;
    }

    /**
     * ?
     * 
     * @param weekSalesDate
     *            ?
     */
    public void setWeekSalesDate(Date weekSalesDate) {
        this.weekSalesDate = weekSalesDate;
    }

    /**
     * ??
     * 
     * @return ?
     */
    @Column(nullable = false)
    public Date getMonthSalesDate() {
        return monthSalesDate;
    }

    /**
     * ?
     * 
     * @param monthSalesDate
     *            ?
     */
    public void setMonthSalesDate(Date monthSalesDate) {
        this.monthSalesDate = monthSalesDate;
    }

    /**
     * ??0
     * 
     * @return ?0
     */
    @Length(max = 200)
    public String getAttributeValue0() {
        return attributeValue0;
    }

    /**
     * ?0
     * 
     * @param attributeValue0
     *            ?0
     */
    public void setAttributeValue0(String attributeValue0) {
        this.attributeValue0 = attributeValue0;
    }

    /**
     * ??1
     * 
     * @return ?1
     */
    @Length(max = 200)
    public String getAttributeValue1() {
        return attributeValue1;
    }

    /**
     * ?1
     * 
     * @param attributeValue1
     *            ?1
     */
    public void setAttributeValue1(String attributeValue1) {
        this.attributeValue1 = attributeValue1;
    }

    /**
     * ??2
     * 
     * @return ?2
     */
    @Length(max = 200)
    public String getAttributeValue2() {
        return attributeValue2;
    }

    /**
     * ?2
     * 
     * @param attributeValue2
     *            ?2
     */
    public void setAttributeValue2(String attributeValue2) {
        this.attributeValue2 = attributeValue2;
    }

    /**
     * ??3
     * 
     * @return ?3
     */
    @Length(max = 200)
    public String getAttributeValue3() {
        return attributeValue3;
    }

    /**
     * ?3
     * 
     * @param attributeValue3
     *            ?3
     */
    public void setAttributeValue3(String attributeValue3) {
        this.attributeValue3 = attributeValue3;
    }

    /**
     * ??4
     * 
     * @return ?4
     */
    @Length(max = 200)
    public String getAttributeValue4() {
        return attributeValue4;
    }

    /**
     * ?4
     * 
     * @param attributeValue4
     *            ?4
     */
    public void setAttributeValue4(String attributeValue4) {
        this.attributeValue4 = attributeValue4;
    }

    /**
     * ??5
     * 
     * @return ?5
     */
    @Length(max = 200)
    public String getAttributeValue5() {
        return attributeValue5;
    }

    /**
     * ?5
     * 
     * @param attributeValue5
     *            ?5
     */
    public void setAttributeValue5(String attributeValue5) {
        this.attributeValue5 = attributeValue5;
    }

    /**
     * ??6
     * 
     * @return ?6
     */
    @Length(max = 200)
    public String getAttributeValue6() {
        return attributeValue6;
    }

    /**
     * ?6
     * 
     * @param attributeValue6
     *            ?6
     */
    public void setAttributeValue6(String attributeValue6) {
        this.attributeValue6 = attributeValue6;
    }

    /**
     * ??7
     * 
     * @return ?7
     */
    @Length(max = 200)
    public String getAttributeValue7() {
        return attributeValue7;
    }

    /**
     * ?7
     * 
     * @param attributeValue7
     *            ?7
     */
    public void setAttributeValue7(String attributeValue7) {
        this.attributeValue7 = attributeValue7;
    }

    /**
     * ??8
     * 
     * @return ?8
     */
    @Length(max = 200)
    public String getAttributeValue8() {
        return attributeValue8;
    }

    /**
     * ?8
     * 
     * @param attributeValue8
     *            ?8
     */
    public void setAttributeValue8(String attributeValue8) {
        this.attributeValue8 = attributeValue8;
    }

    /**
     * ??9
     * 
     * @return ?9
     */
    @Length(max = 200)
    public String getAttributeValue9() {
        return attributeValue9;
    }

    /**
     * ?9
     * 
     * @param attributeValue9
     *            ?9
     */
    public void setAttributeValue9(String attributeValue9) {
        this.attributeValue9 = attributeValue9;
    }

    /**
     * ??10
     * 
     * @return ?10
     */
    @Length(max = 200)
    public String getAttributeValue10() {
        return attributeValue10;
    }

    /**
     * ?10
     * 
     * @param attributeValue10
     *            ?10
     */
    public void setAttributeValue10(String attributeValue10) {
        this.attributeValue10 = attributeValue10;
    }

    /**
     * ??11
     * 
     * @return ?11
     */
    @Length(max = 200)
    public String getAttributeValue11() {
        return attributeValue11;
    }

    /**
     * ?11
     * 
     * @param attributeValue11
     *            ?11
     */
    public void setAttributeValue11(String attributeValue11) {
        this.attributeValue11 = attributeValue11;
    }

    /**
     * ??12
     * 
     * @return ?12
     */
    @Length(max = 200)
    public String getAttributeValue12() {
        return attributeValue12;
    }

    /**
     * ?12
     * 
     * @param attributeValue12
     *            ?12
     */
    public void setAttributeValue12(String attributeValue12) {
        this.attributeValue12 = attributeValue12;
    }

    /**
     * ??13
     * 
     * @return ?13
     */
    @Length(max = 200)
    public String getAttributeValue13() {
        return attributeValue13;
    }

    /**
     * ?13
     * 
     * @param attributeValue13
     *            ?13
     */
    public void setAttributeValue13(String attributeValue13) {
        this.attributeValue13 = attributeValue13;
    }

    /**
     * ??14
     * 
     * @return ?14
     */
    @Length(max = 200)
    public String getAttributeValue14() {
        return attributeValue14;
    }

    /**
     * ?14
     * 
     * @param attributeValue14
     *            ?14
     */
    public void setAttributeValue14(String attributeValue14) {
        this.attributeValue14 = attributeValue14;
    }

    /**
     * ??15
     * 
     * @return ?15
     */
    @Length(max = 200)
    public String getAttributeValue15() {
        return attributeValue15;
    }

    /**
     * ?15
     * 
     * @param attributeValue15
     *            ?15
     */
    public void setAttributeValue15(String attributeValue15) {
        this.attributeValue15 = attributeValue15;
    }

    /**
     * ??16
     * 
     * @return ?16
     */
    @Length(max = 200)
    public String getAttributeValue16() {
        return attributeValue16;
    }

    /**
     * ?16
     * 
     * @param attributeValue16
     *            ?16
     */
    public void setAttributeValue16(String attributeValue16) {
        this.attributeValue16 = attributeValue16;
    }

    /**
     * ??17
     * 
     * @return ?17
     */
    @Length(max = 200)
    public String getAttributeValue17() {
        return attributeValue17;
    }

    /**
     * ?17
     * 
     * @param attributeValue17
     *            ?17
     */
    public void setAttributeValue17(String attributeValue17) {
        this.attributeValue17 = attributeValue17;
    }

    /**
     * ??18
     * 
     * @return ?18
     */
    @Length(max = 200)
    public String getAttributeValue18() {
        return attributeValue18;
    }

    /**
     * ?18
     * 
     * @param attributeValue18
     *            ?18
     */
    public void setAttributeValue18(String attributeValue18) {
        this.attributeValue18 = attributeValue18;
    }

    /**
     * ??19
     * 
     * @return ?19
     */
    @Length(max = 200)
    public String getAttributeValue19() {
        return attributeValue19;
    }

    /**
     * ?19
     * 
     * @param attributeValue19
     *            ?19
     */
    public void setAttributeValue19(String attributeValue19) {
        this.attributeValue19 = attributeValue19;
    }

    /**
     * ??
     * 
     * @return ?
     */
    @NotNull
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(nullable = false)
    public ProductCategory getProductCategory() {
        return productCategory;
    }

    /**
     * ?
     * 
     * @param productCategory
     *            ?
     */
    public void setProductCategory(ProductCategory productCategory) {
        this.productCategory = productCategory;
    }

    /**
     * ??
     * 
     * @return ?
     */
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(nullable = false, updatable = false)
    public Goods getGoods() {
        return goods;
    }

    /**
     * ?
     * 
     * @param goods
     *            ?
     */
    public void setGoods(Goods goods) {
        this.goods = goods;
    }

    /**
     * ??
     * 
     * @return ?
     */
    @ManyToOne(fetch = FetchType.LAZY)
    public Brand getBrand() {
        return brand;
    }

    /**
     * ?
     * 
     * @param brand
     *            ?
     */
    public void setBrand(Brand brand) {
        this.brand = brand;
    }

    /**
     * ??
     * 
     * @return ?
     */
    @Valid
    @ElementCollection
    @CollectionTable(name = "xx_product_product_image")
    public List<ProductImage> getProductImages() {
        return productImages;
    }

    /**
     * ?
     * 
     * @param productImages
     *            ?
     */
    public void setProductImages(List<ProductImage> productImages) {
        this.productImages = productImages;
    }

    /**
     * ?
     * 
     * @return 
     */
    @OneToMany(mappedBy = "product", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
    public Set<Review> getReviews() {
        return reviews;
    }

    /**
     * 
     * 
     * @param reviews
     *            
     */
    public void setReviews(Set<Review> reviews) {
        this.reviews = reviews;
    }

    /**
     * ?
     * 
     * @return 
     */
    @OneToMany(mappedBy = "product", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
    public Set<Consultation> getConsultations() {
        return consultations;
    }

    /**
     * 
     * 
     * @param consultations
     *            
     */
    public void setConsultations(Set<Consultation> consultations) {
        this.consultations = consultations;
    }

    /**
     * ?
     * 
     * @return 
     */
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "xx_product_tag")
    @OrderBy("order asc")
    public Set<Tag> getTags() {
        return tags;
    }

    /**
     * 
     * 
     * @param tags
     *            
     */
    public void setTags(Set<Tag> tags) {
        this.tags = tags;
    }

    /**
     * ??
     * 
     * @return ?
     */
    @ManyToMany(mappedBy = "favoriteProducts", fetch = FetchType.LAZY)
    public Set<Member> getFavoriteMembers() {
        return favoriteMembers;
    }

    /**
     * ?
     * 
     * @param favoriteMembers
     *            ?
     */
    public void setFavoriteMembers(Set<Member> favoriteMembers) {
        this.favoriteMembers = favoriteMembers;
    }

    /**
     * ?
     * 
     * @return 
     */
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "xx_product_specification")
    @OrderBy("order asc")
    public Set<Specification> getSpecifications() {
        return specifications;
    }

    /**
     * 
     * 
     * @param specifications
     *            
     */
    public void setSpecifications(Set<Specification> specifications) {
        this.specifications = specifications;
    }

    /**
     * ?
     * 
     * @return 
     */
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "xx_product_specification_value")
    @OrderBy("specification asc")
    public Set<SpecificationValue> getSpecificationValues() {
        return specificationValues;
    }

    /**
     * 
     * 
     * @param specificationValues
     *            
     */
    public void setSpecificationValues(Set<SpecificationValue> specificationValues) {
        this.specificationValues = specificationValues;
    }

    /**
     * ?
     * 
     * @return 
     */
    @ManyToMany(mappedBy = "products", fetch = FetchType.LAZY)
    public Set<Promotion> getPromotions() {
        return promotions;
    }

    /**
     * 
     * 
     * @param promotions
     *            
     */
    public void setPromotions(Set<Promotion> promotions) {
        this.promotions = promotions;
    }

    /**
     * ?
     * 
     * @return 
     */
    @OneToMany(mappedBy = "product", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
    public Set<CartItem> getCartItems() {
        return cartItems;
    }

    /**
     * 
     * 
     * @param cartItems
     *            
     */
    public void setCartItems(Set<CartItem> cartItems) {
        this.cartItems = cartItems;
    }

    /**
     * ??
     * 
     * @return ?
     */
    @OneToMany(mappedBy = "product", fetch = FetchType.LAZY)
    public Set<OrderItem> getOrderItems() {
        return orderItems;
    }

    /**
     * ?
     * 
     * @param orderItems
     *            ?
     */
    public void setOrderItems(Set<OrderItem> orderItems) {
        this.orderItems = orderItems;
    }

    /**
     * ??
     * 
     * @return ?
     */
    @OneToMany(mappedBy = "gift", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    public Set<GiftItem> getGiftItems() {
        return giftItems;
    }

    /**
     * ?
     * 
     * @param giftItems
     *            ?
     */
    public void setGiftItems(Set<GiftItem> giftItems) {
        this.giftItems = giftItems;
    }

    /**
     * ?
     * 
     * @return 
     */
    @OneToMany(mappedBy = "product", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
    public Set<ProductNotify> getProductNotifies() {
        return productNotifies;
    }

    /**
     * 
     * 
     * @param productNotifies
     *            
     */
    public void setProductNotifies(Set<ProductNotify> productNotifies) {
        this.productNotifies = productNotifies;
    }

    /**
     * ?
     * 
     * @return 
     */
    @ElementCollection(fetch = FetchType.LAZY)
    @CollectionTable(name = "xx_product_member_price")
    public Map<MemberRank, BigDecimal> getMemberPrice() {
        return memberPrice;
    }

    /**
     * 
     * 
     * @param memberPrice
     *            
     */
    public void setMemberPrice(Map<MemberRank, BigDecimal> memberPrice) {
        this.memberPrice = memberPrice;
    }

    /**
     * ??
     * 
     * @return ?
     */
    @ElementCollection(fetch = FetchType.LAZY)
    @CollectionTable(name = "xx_product_parameter_value")
    public Map<Parameter, String> getParameterValue() {
        return parameterValue;
    }

    /**
     * ?
     * 
     * @param parameterValue
     *            ?
     */
    public void setParameterValue(Map<Parameter, String> parameterValue) {
        this.parameterValue = parameterValue;
    }

    /**
     * ??
     * 
     * @param attribute
     *            ?
     * @return ?
     */
    @Transient
    public String getAttributeValue(Attribute attribute) {
        if (attribute != null && attribute.getPropertyIndex() != null) {
            try {
                String propertyName = ATTRIBUTE_VALUE_PROPERTY_NAME_PREFIX + attribute.getPropertyIndex();
                return (String) PropertyUtils.getProperty(this, propertyName);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * ?
     * 
     * @param attribute
     *            ?
     * @param value
     *            ?
     */
    @Transient
    public void setAttributeValue(Attribute attribute, String value) {
        if (attribute != null && attribute.getPropertyIndex() != null) {
            if (StringUtils.isEmpty(value)) {
                value = null;
            }
            if (value == null || (attribute.getOptions() != null && attribute.getOptions().contains(value))) {
                try {
                    String propertyName = ATTRIBUTE_VALUE_PROPERTY_NAME_PREFIX + attribute.getPropertyIndex();
                    PropertyUtils.setProperty(this, propertyName, value);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * ????
     * 
     * @return ?????
     */
    @Transient
    public List<Product> getSiblings() {
        List<Product> siblings = new ArrayList<Product>();
        if (getGoods() != null && getGoods().getProducts() != null) {
            for (Product product : getGoods().getProducts()) {
                if (!this.equals(product)) {
                    siblings.add(product);
                }
            }
        }
        return siblings;
    }

    /**
     * ?
     * 
     * @return 
     */
    @JsonProperty
    @Transient
    public String getPath() {
        Map<String, Object> model = new HashMap<String, Object>();
        model.put("id", getId());
        model.put("createDate", getCreateDate());
        model.put("modifyDate", getModifyDate());
        model.put("sn", getSn());
        model.put("name", getName());
        model.put("fullName", getFullName());
        model.put("seoTitle", getSeoTitle());
        model.put("seoKeywords", getSeoKeywords());
        model.put("seoDescription", getSeoDescription());
        model.put("productCategory", getProductCategory());
        try {
            return FreemarkerUtils.process(staticPath, model);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TemplateException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * ?
     * 
     * @return 
     */
    @JsonProperty
    @Transient
    public String getThumbnail() {
        if (getProductImages() != null && !getProductImages().isEmpty()) {
            return getProductImages().get(0).getThumbnail();
        }
        return null;
    }

    /**
     * ?
     * 
     * @return 
     */
    @Transient
    public Set<Promotion> getValidPromotions() {
        Set<Promotion> allPromotions = new HashSet<Promotion>();
        if (getPromotions() != null) {
            allPromotions.addAll(getPromotions());
        }
        if (getProductCategory() != null && getProductCategory().getPromotions() != null) {
            allPromotions.addAll(getProductCategory().getPromotions());
        }
        if (getBrand() != null && getBrand().getPromotions() != null) {
            allPromotions.addAll(getBrand().getPromotions());
        }
        Set<Promotion> validPromotions = new TreeSet<Promotion>();
        for (Promotion promotion : allPromotions) {
            if (promotion != null && promotion.hasBegun() && !promotion.hasEnded()
                    && promotion.getMemberRanks() != null && !promotion.getMemberRanks().isEmpty()) {
                validPromotions.add(promotion);
            }
        }
        return validPromotions;
    }

    /**
     * ??
     * 
     * @return ?
     */
    @Transient
    public Integer getAvailableStock() {
        Integer availableStock = null;
        if (getStock() != null && getAllocatedStock() != null) {
            availableStock = getStock() - getAllocatedStock();
            if (availableStock < 0) {
                availableStock = 0;
            }
        }
        return availableStock;
    }

    /**
     * ??
     * 
     * @return ?
     */
    @Transient
    public Boolean getIsOutOfStock() {
        return getStock() != null && getAllocatedStock() != null && getAllocatedStock() >= getStock();
    }

    /**
     * ?
     * 
     * @param promotion
     *            
     * @return ?
     */
    @Transient
    public boolean isValid(Promotion promotion) {
        if (promotion == null || !promotion.hasBegun() || promotion.hasEnded() || promotion.getMemberRanks() == null
                || promotion.getMemberRanks().isEmpty()) {
            return false;
        }
        if (getValidPromotions().contains(promotion)) {
            return true;
        }
        return false;
    }

    /**
     * ??
     */
    @PreRemove
    public void preRemove() {
        Set<Member> favoriteMembers = getFavoriteMembers();
        if (favoriteMembers != null) {
            for (Member favoriteMember : favoriteMembers) {
                favoriteMember.getFavoriteProducts().remove(this);
            }
        }
        Set<Promotion> promotions = getPromotions();
        if (promotions != null) {
            for (Promotion promotion : promotions) {
                promotion.getProducts().remove(this);
            }
        }
        Set<OrderItem> orderItems = getOrderItems();
        if (orderItems != null) {
            for (OrderItem orderItem : orderItems) {
                orderItem.setProduct(null);
            }
        }
    }

    /**
     * ???
     */
    @PrePersist
    public void prePersist() {
        if (getStock() == null) {
            setAllocatedStock(0);
        }
        setScore(0F);
    }

    /**
     * ??
     */
    @PreUpdate
    public void preUpdate() {
        if (getStock() == null) {
            setAllocatedStock(0);
        }
        if (getTotalScore() != null && getScoreCount() != null && getScoreCount() != 0) {
            setScore((float) getTotalScore() / getScoreCount());
        } else {
            setScore(0F);
        }
    }

}