001/**
002 * Copyright 2005-2016 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.kew.docsearch;
017
018import org.apache.commons.lang.StringUtils;
019import org.hibernate.annotations.GenericGenerator;
020import org.hibernate.annotations.Parameter;
021import org.kuali.rice.core.api.search.SearchOperator;
022import org.kuali.rice.core.framework.persistence.jdbc.sql.SQLUtils;
023import org.kuali.rice.core.framework.persistence.jpa.OrmUtils;
024import org.kuali.rice.kew.api.document.attribute.DocumentAttributeDecimal;
025import org.kuali.rice.kew.api.document.attribute.DocumentAttributeFactory;
026import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
027import org.kuali.rice.kew.service.KEWServiceLocator;
028import org.kuali.rice.kew.api.KewApiConstants;
029
030import javax.persistence.CascadeType;
031import javax.persistence.Column;
032import javax.persistence.Entity;
033import javax.persistence.FetchType;
034import javax.persistence.GeneratedValue;
035import javax.persistence.Id;
036import javax.persistence.JoinColumn;
037import javax.persistence.ManyToOne;
038import javax.persistence.NamedQueries;
039import javax.persistence.NamedQuery;
040import javax.persistence.Table;
041import javax.persistence.Transient;
042import java.io.Serializable;
043import java.math.BigDecimal;
044import java.sql.ResultSet;
045import java.sql.SQLException;
046import java.text.DecimalFormat;
047import java.text.NumberFormat;
048import java.util.Arrays;
049import java.util.List;
050import java.util.regex.Matcher;
051import java.util.regex.Pattern;
052
053/**
054 *
055 * @author Kuali Rice Team (rice.collab@kuali.org)
056 */
057@Entity
058@Table(name="KREW_DOC_HDR_EXT_FLT_T")
059//@Sequence(name="KREW_SRCH_ATTR_S",property="searchableAttributeValueId")
060@NamedQueries({
061        @NamedQuery(name="SearchableAttributeFloatValue.FindByDocumentId", query="select s from SearchableAttributeFloatValue as s where s.documentId = :documentId"),
062        @NamedQuery(name="SearchableAttributeFloatValue.FindByKey", query="select s from SearchableAttributeFloatValue as s where s.documentId = :documentId and s.searchableAttributeKey = :searchableAttributeKey")
063})
064public class SearchableAttributeFloatValue implements SearchableAttributeValue, Serializable {
065
066    private static final long serialVersionUID = -6682101853805320760L;
067
068    private static final String ATTRIBUTE_DATABASE_TABLE_NAME = "KREW_DOC_HDR_EXT_FLT_T";
069    private static final boolean DEFAULT_WILDCARD_ALLOWANCE_POLICY = false;
070    private static final boolean ALLOWS_RANGE_SEARCH = true;
071    private static final boolean ALLOWS_CASE_INSENSITIVE_SEARCH = false;
072    private static final String DEFAULT_VALIDATION_REGEX_EXPRESSION = "[-+]?[0-9]*\\.?[0-9]+";
073    private static final String ATTRIBUTE_XML_REPRESENTATION = KewApiConstants.SearchableAttributeConstants.DATA_TYPE_FLOAT;
074    private static final String DEFAULT_FORMAT_PATTERN = "";
075
076    @Id
077    @GeneratedValue(generator="KREW_SRCH_ATTR_S")
078        @GenericGenerator(name="KREW_SRCH_ATTR_S",strategy="org.hibernate.id.enhanced.SequenceStyleGenerator",parameters={
079                        @Parameter(name="sequence_name",value="KREW_SRCH_ATTR_S"),
080                        @Parameter(name="value_column",value="id")
081        })
082        @Column(name="DOC_HDR_EXT_FLT_ID")
083        private String searchableAttributeValueId;
084    @Column(name="KEY_CD")
085        private String searchableAttributeKey;
086    @Column(name="VAL")
087        private BigDecimal searchableAttributeValue;
088    @Transient
089    protected String ojbConcreteClass; // attribute needed for OJB polymorphism - do not alter!
090
091    @Column(name="DOC_HDR_ID")
092        private String documentId;
093    @ManyToOne(fetch=FetchType.EAGER, cascade={CascadeType.PERSIST})
094        @JoinColumn(name="DOC_HDR_ID", insertable=false, updatable=false)
095        private DocumentRouteHeaderValue routeHeader;
096
097    /**
098     * Default constructor.
099     */
100    public SearchableAttributeFloatValue() {
101        super();
102        this.ojbConcreteClass = this.getClass().getName();
103    }
104
105    /* (non-Javadoc)
106     * @see org.kuali.rice.kew.docsearch.SearchableAttributeValue#setupAttributeValue(java.lang.String)
107     */
108    public void setupAttributeValue(String value) {
109        this.setSearchableAttributeValue(convertStringToBigDecimal(value));
110    }
111
112    private BigDecimal convertStringToBigDecimal(String value) {
113        if (org.apache.commons.lang.StringUtils.isEmpty(value)) {
114            return null;
115        } else {
116            return new BigDecimal(value);
117        }
118    }
119
120        /* (non-Javadoc)
121         * @see org.kuali.rice.kew.docsearch.SearchableAttributeValue#setupAttributeValue(java.sql.ResultSet, java.lang.String)
122         */
123        public void setupAttributeValue(ResultSet resultSet, String columnName) throws SQLException {
124                this.setSearchableAttributeValue(resultSet.getBigDecimal(columnName));
125        }
126
127    /* (non-Javadoc)
128     * @see org.kuali.rice.kew.docsearch.SearchableAttributeValue#getSearchableAttributeDisplayValue(java.util.Map)
129     */
130    public String getSearchableAttributeDisplayValue() {
131            NumberFormat format = DecimalFormat.getInstance();
132            ((DecimalFormat)format).toPattern();
133            ((DecimalFormat)format).applyPattern(DEFAULT_FORMAT_PATTERN);
134            return format.format(getSearchableAttributeValue().doubleValue());
135        }
136
137    /* (non-Javadoc)
138         * @see org.kuali.rice.kew.docsearch.SearchableAttributeValue#getAttributeDataType()
139         */
140        public String getAttributeDataType() {
141                return ATTRIBUTE_XML_REPRESENTATION;
142        }
143
144        /* (non-Javadoc)
145         * @see org.kuali.rice.kew.docsearch.SearchableAttributeValue#getAttributeTableName()
146         */
147        public String getAttributeTableName() {
148                return ATTRIBUTE_DATABASE_TABLE_NAME;
149        }
150
151    /* (non-Javadoc)
152         * @see org.kuali.rice.kew.docsearch.SearchableAttributeValue#allowsWildcardsByDefault()
153         */
154        public boolean allowsWildcards() {
155                return DEFAULT_WILDCARD_ALLOWANCE_POLICY;
156        }
157
158    /* (non-Javadoc)
159         * @see org.kuali.rice.kew.docsearch.SearchableAttributeValue#allowsCaseInsensitivity()
160         */
161        public boolean allowsCaseInsensitivity() {
162                return ALLOWS_CASE_INSENSITIVE_SEARCH;
163        }
164
165    /* (non-Javadoc)
166         * @see org.kuali.rice.kew.docsearch.SearchableAttributeValue#allowsRangeSearches()
167         */
168        public boolean allowsRangeSearches() {
169                return ALLOWS_RANGE_SEARCH;
170        }
171
172        /* (non-Javadoc)
173         * @see org.kuali.rice.kew.docsearch.SearchableAttributeValue#isPassesDefaultValidation()
174         */
175    public boolean isPassesDefaultValidation(String valueEntered) {
176
177        boolean bRet = true;
178        boolean bSplit = false;
179
180                if (StringUtils.contains(valueEntered, SearchOperator.BETWEEN.op())) {
181                        List<String> l = Arrays.asList(valueEntered.split("\\.\\."));
182                        for(String value : l){
183                                bSplit = true;
184                                if(!isPassesDefaultValidation(value)){
185                                        bRet = false;
186                                }
187                        }
188                }
189                if (StringUtils.contains(valueEntered, SearchOperator.OR.op())) {
190                        //splitValueList.addAll(Arrays.asList(StringUtils.split(valueEntered, KRADConstants.OR_LOGICAL_OPERATOR)));
191                        List<String> l = Arrays.asList(StringUtils.split(valueEntered, SearchOperator.OR.op()));
192                        for(String value : l){
193                                bSplit = true;
194                                if(!isPassesDefaultValidation(value)){
195                                        bRet = false;
196                                }
197                        }
198                }
199                if (StringUtils.contains(valueEntered, SearchOperator.AND.op())) {
200                        //splitValueList.addAll(Arrays.asList(StringUtils.split(valueEntered, KRADConstants.AND_LOGICAL_OPERATOR)));
201                        List<String> l = Arrays.asList(StringUtils.split(valueEntered, SearchOperator.AND.op()));
202                        for(String value : l){
203                                bSplit = true;
204                                if(!isPassesDefaultValidation(value)){
205                                        bRet = false;
206                                }
207                        }
208                }
209
210                if(bSplit){
211                        return bRet;
212                }
213
214                Pattern pattern = Pattern.compile(DEFAULT_VALIDATION_REGEX_EXPRESSION);
215                Matcher matcher = pattern.matcher(SQLUtils.cleanNumericOfValidOperators(valueEntered).trim()); 
216                if(!matcher.matches()){
217                        bRet = false;
218                }
219
220                return bRet;
221
222    }
223
224    /* (non-Javadoc)
225     * @see org.kuali.rice.kew.docsearch.SearchableAttributeValue#isRangeValid(java.lang.String, java.lang.String)
226     */
227    public Boolean isRangeValid(String lowerValue, String upperValue) {
228        if (allowsRangeSearches()) {
229            BigDecimal lower = null;
230            BigDecimal upper = null;
231            try{
232                lower = convertStringToBigDecimal(lowerValue);
233                upper = convertStringToBigDecimal(upperValue);
234            }catch(NumberFormatException ex){
235                return false;
236            }
237            if ( (lower != null) && (upper != null) ) {
238                return (lower.compareTo(upper) <= 0);
239            }
240            return true;
241        }
242        return null;
243    }
244
245        public String getOjbConcreteClass() {
246        return ojbConcreteClass;
247    }
248
249    public void setOjbConcreteClass(String ojbConcreteClass) {
250        this.ojbConcreteClass = ojbConcreteClass;
251    }
252
253    public DocumentRouteHeaderValue getRouteHeader() {
254        return routeHeader;
255    }
256
257    public void setRouteHeader(DocumentRouteHeaderValue routeHeader) {
258        this.routeHeader = routeHeader;
259    }
260
261    public String getDocumentId() {
262        return documentId;
263    }
264
265    public void setDocumentId(String documentId) {
266        this.documentId = documentId;
267    }
268
269    public String getSearchableAttributeKey() {
270        return searchableAttributeKey;
271    }
272
273    public void setSearchableAttributeKey(String searchableAttributeKey) {
274        this.searchableAttributeKey = searchableAttributeKey;
275    }
276
277    public BigDecimal getSearchableAttributeValue() {
278        return searchableAttributeValue;
279    }
280
281    public void setSearchableAttributeValue(BigDecimal searchableAttributeValue) {
282        this.searchableAttributeValue = searchableAttributeValue;
283    }
284
285    /**
286     * @deprecated USE method setSearchableAttributeValue(BigDecimal) instead
287     */
288    public void setSearchableAttributeValue(Float floatValueToTranslate) {
289        this.searchableAttributeValue = null;
290        if (floatValueToTranslate != null) {
291            this.searchableAttributeValue = new BigDecimal(floatValueToTranslate.toString());
292        }
293    }
294
295    public String getSearchableAttributeValueId() {
296        return searchableAttributeValueId;
297    }
298
299    public void setSearchableAttributeValueId(String searchableAttributeValueId) {
300        this.searchableAttributeValueId = searchableAttributeValueId;
301    }
302
303        //@PrePersist
304        public void beforeInsert(){
305                OrmUtils.populateAutoIncValue(this, KEWServiceLocator.getEntityManagerFactory().createEntityManager());
306        }
307
308    @Override
309    public DocumentAttributeDecimal toDocumentAttribute() {
310        return DocumentAttributeFactory.createDecimalAttribute(getSearchableAttributeKey(), getSearchableAttributeValue());
311    }
312
313
314}
315