001    /**
002     * Copyright 2005-2013 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     */
016    package org.kuali.rice.kew.docsearch;
017    
018    import org.apache.commons.lang.StringUtils;
019    import org.hibernate.annotations.GenericGenerator;
020    import org.hibernate.annotations.Parameter;
021    import org.kuali.rice.core.api.search.SearchOperator;
022    import org.kuali.rice.core.framework.persistence.jdbc.sql.SQLUtils;
023    import org.kuali.rice.core.framework.persistence.jpa.OrmUtils;
024    import org.kuali.rice.kew.api.document.attribute.DocumentAttributeDecimal;
025    import org.kuali.rice.kew.api.document.attribute.DocumentAttributeFactory;
026    import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
027    import org.kuali.rice.kew.service.KEWServiceLocator;
028    import org.kuali.rice.kew.api.KewApiConstants;
029    
030    import javax.persistence.CascadeType;
031    import javax.persistence.Column;
032    import javax.persistence.Entity;
033    import javax.persistence.FetchType;
034    import javax.persistence.GeneratedValue;
035    import javax.persistence.Id;
036    import javax.persistence.JoinColumn;
037    import javax.persistence.ManyToOne;
038    import javax.persistence.NamedQueries;
039    import javax.persistence.NamedQuery;
040    import javax.persistence.Table;
041    import javax.persistence.Transient;
042    import java.io.Serializable;
043    import java.math.BigDecimal;
044    import java.sql.ResultSet;
045    import java.sql.SQLException;
046    import java.text.DecimalFormat;
047    import java.text.NumberFormat;
048    import java.util.Arrays;
049    import java.util.List;
050    import java.util.regex.Matcher;
051    import 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    })
064    public 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