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.DocumentAttributeFactory;
025import org.kuali.rice.kew.api.document.attribute.DocumentAttributeInteger;
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.BigInteger;
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_LONG_T")
059//@Sequence(name="KREW_SRCH_ATTR_S",property="searchableAttributeValueId")
060@NamedQueries({
061        @NamedQuery(name="SearchableAttributeLongValue.FindByDocumentId", query="select s from SearchableAttributeLongValue as s where s.documentId = :documentId"),
062        @NamedQuery(name="SearchableAttributeLongValue.FindByKey", query="select s from SearchableAttributeLongValue as s where s.documentId = :documentId and s.searchableAttributeKey = :searchableAttributeKey")
063})
064public class SearchableAttributeLongValue implements SearchableAttributeValue, Serializable {
065
066    private static final long serialVersionUID = 5786144436732198346L;
067
068    private static final String ATTRIBUTE_DATABASE_TABLE_NAME = "KREW_DOC_HDR_EXT_LONG_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]+$";
073    private static final String ATTRIBUTE_XML_REPRESENTATION = KewApiConstants.SearchableAttributeConstants.DATA_TYPE_LONG;
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_LONG_ID")
083        private String searchableAttributeValueId;
084    @Column(name="KEY_CD")
085        private String searchableAttributeKey;
086    @Column(name="VAL")
087        private Long 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 SearchableAttributeLongValue() {
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(convertStringToLong(value));
110    }
111
112    private Long convertStringToLong(String value) {
113        if (org.apache.commons.lang.StringUtils.isEmpty(value)) {
114            return null;
115        } else {
116            return Long.valueOf(value.trim());
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.getLong(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).applyPattern(DEFAULT_FORMAT_PATTERN);
133        return format.format(getSearchableAttributeValue().longValue());
134    }
135
136        /* (non-Javadoc)
137         * @see org.kuali.rice.kew.docsearch.SearchableAttributeValue#getAttributeDataType()
138         */
139        public String getAttributeDataType() {
140                return ATTRIBUTE_XML_REPRESENTATION;
141        }
142
143        /* (non-Javadoc)
144         * @see org.kuali.rice.kew.docsearch.SearchableAttributeValue#getAttributeTableName()
145         */
146        public String getAttributeTableName() {
147                return ATTRIBUTE_DATABASE_TABLE_NAME;
148        }
149
150    /* (non-Javadoc)
151         * @see org.kuali.rice.kew.docsearch.SearchableAttributeValue#allowsWildcardsByDefault()
152         */
153        public boolean allowsWildcards() {
154                return DEFAULT_WILDCARD_ALLOWANCE_POLICY;
155        }
156
157    /* (non-Javadoc)
158         * @see org.kuali.rice.kew.docsearch.SearchableAttributeValue#allowsCaseInsensitivity()
159         */
160        public boolean allowsCaseInsensitivity() {
161                return ALLOWS_CASE_INSENSITIVE_SEARCH;
162        }
163
164    /* (non-Javadoc)
165         * @see org.kuali.rice.kew.docsearch.SearchableAttributeValue#allowsRangeSearches()
166         */
167        public boolean allowsRangeSearches() {
168                return ALLOWS_RANGE_SEARCH;
169        }
170
171        /* (non-Javadoc)
172         * @see org.kuali.rice.kew.docsearch.SearchableAttributeValue#isPassesDefaultValidation()
173         */
174        public boolean isPassesDefaultValidation(String valueEntered) {
175
176        boolean bRet = true;
177        boolean bSplit = false;
178
179                if (StringUtils.contains(valueEntered, SearchOperator.BETWEEN.op())) {
180                        List<String> l = Arrays.asList(valueEntered.split("\\.\\."));
181                        for(String value : l){
182                                bSplit = true;
183                                if(!isPassesDefaultValidation(value)){
184                                        bRet = false;
185                                }
186                        }
187                }
188                if (StringUtils.contains(valueEntered, SearchOperator.OR.op())) {
189                        //splitValueList.addAll(Arrays.asList(StringUtils.split(valueEntered, KRADConstants.OR_LOGICAL_OPERATOR)));
190                        List<String> l = Arrays.asList(StringUtils.split(valueEntered, SearchOperator.OR.op()));
191                        for(String value : l){
192                                bSplit = true;
193                                if(!isPassesDefaultValidation(value)){
194                                        bRet = false;
195                                }
196                        }
197                }
198                if (StringUtils.contains(valueEntered, SearchOperator.AND.op())) {
199                        //splitValueList.addAll(Arrays.asList(StringUtils.split(valueEntered, KRADConstants.AND_LOGICAL_OPERATOR)));
200                        List<String> l = Arrays.asList(StringUtils.split(valueEntered, SearchOperator.AND.op()));
201                        for(String value : l){
202                                bSplit = true;
203                                if(!isPassesDefaultValidation(value)){
204                                        bRet = false;
205                                }
206                        }
207                }
208
209                if(bSplit){
210                        return bRet;
211                }
212
213                Pattern pattern = Pattern.compile(DEFAULT_VALIDATION_REGEX_EXPRESSION);
214                Matcher matcher = pattern.matcher(SQLUtils.cleanNumericOfValidOperators(valueEntered).trim());
215                if(!matcher.matches()){
216                        bRet = false;
217                }
218
219                return bRet;
220
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            Long lower = convertStringToLong(lowerValue);
230            Long upper = convertStringToLong(upperValue);
231            if ( (lower != null) && (upper != null) ) {
232                return (lower.compareTo(upper) <= 0);
233            }
234            return true;
235        }
236        return null;
237    }
238
239    public String getOjbConcreteClass() {
240        return ojbConcreteClass;
241    }
242
243    public void setOjbConcreteClass(String ojbConcreteClass) {
244        this.ojbConcreteClass = ojbConcreteClass;
245    }
246
247    public DocumentRouteHeaderValue getRouteHeader() {
248        return routeHeader;
249    }
250
251    public void setRouteHeader(DocumentRouteHeaderValue routeHeader) {
252        this.routeHeader = routeHeader;
253    }
254
255    public String getDocumentId() {
256        return documentId;
257    }
258
259    public void setDocumentId(String documentId) {
260        this.documentId = documentId;
261    }
262
263    public String getSearchableAttributeKey() {
264        return searchableAttributeKey;
265    }
266
267    public void setSearchableAttributeKey(String searchableAttributeKey) {
268        this.searchableAttributeKey = searchableAttributeKey;
269    }
270
271    public Long getSearchableAttributeValue() {
272        return searchableAttributeValue;
273    }
274
275    public void setSearchableAttributeValue(Long searchableAttributeValue) {
276        this.searchableAttributeValue = searchableAttributeValue;
277    }
278
279    public String getSearchableAttributeValueId() {
280        return searchableAttributeValueId;
281    }
282
283    public void setSearchableAttributeValueId(String searchableAttributeValueId) {
284        this.searchableAttributeValueId = searchableAttributeValueId;
285    }
286
287        //@PrePersist
288        public void beforeInsert(){
289                OrmUtils.populateAutoIncValue(this, KEWServiceLocator.getEntityManagerFactory().createEntityManager());
290        }
291
292    @Override
293    public DocumentAttributeInteger toDocumentAttribute() {
294        BigInteger integer = null;
295        if (getSearchableAttributeValue() != null) {
296            integer = BigInteger.valueOf(getSearchableAttributeValue().longValue());
297        }
298        return DocumentAttributeFactory.createIntegerAttribute(getSearchableAttributeKey(), integer);
299    }
300
301    @Override
302    public int hashCode() {
303        final int prime = 31;
304        int result = 1;
305        result = prime * result + ((this.documentId == null) ? 0 : this.documentId.hashCode());
306        result = prime * result + ((this.searchableAttributeKey == null) ? 0 : this.searchableAttributeKey.hashCode());
307        result = prime * result
308                + ((this.searchableAttributeValue == null) ? 0 : this.searchableAttributeValue.hashCode());
309        return result;
310    }
311
312    @Override
313    public boolean equals(Object obj) {
314        if (this == obj)
315            return true;
316        if (obj == null)
317            return false;
318        if (getClass() != obj.getClass())
319            return false;
320        SearchableAttributeLongValue other = (SearchableAttributeLongValue) obj;
321        if (this.documentId == null) {
322            if (other.documentId != null)
323                return false;
324        } else if (!this.documentId.equals(other.documentId))
325            return false;
326        if (this.searchableAttributeKey == null) {
327            if (other.searchableAttributeKey != null)
328                return false;
329        } else if (!this.searchableAttributeKey.equals(other.searchableAttributeKey))
330            return false;
331        if (this.searchableAttributeValue == null) {
332            if (other.searchableAttributeValue != null)
333                return false;
334        } else if (!this.searchableAttributeValue.equals(other.searchableAttributeValue))
335            return false;
336        return true;
337    }
338
339}
340