/* Copyright (2006-2012) Schibsted ASA
* This file is part of Possom.
*
* Possom is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Possom is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Possom. If not, see <http://www.gnu.org/licenses/>.
*/
package no.sesat.search.result;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* A simple implementation of a search result item.
* Is not multi-thread safe.
* Mutates on setter methods.
* Delegates all fields (of all types) to the one map.
*
* Any field "recordid" is considered as a key to equality between result items.
*
*
* @version <tt>$Id$</tt>
*/
public class BasicResultItem implements ResultItem {
private static final String URL_KEY = "url";
private static final String TITLE_KEY = "title";
private final HashMap<String,Serializable> fields = new HashMap<String,Serializable>();
private final Map<String,Serializable> fieldsReadOnly = Collections.unmodifiableMap(fields);
/**
*
*/
public BasicResultItem(){}
/**
*
* @param title
* @param url
*/
protected BasicResultItem(final String title, final String url){
fields.put(TITLE_KEY, StringChopper.chop(title, -1));
fields.put(URL_KEY, StringChopper.chop(url, -1));
}
/**
*
* @param copy
*/
public BasicResultItem(final ResultItem copy){
for(String fieldName : copy.getFieldNames()){
fields.put(fieldName, copy.getObjectField(fieldName));
}
}
/**
*
* @param field
* @param value
* @return
*/
public BasicResultItem addField(final String field, final String value) {
fields.put(field, StringChopper.chop(value, -1));
return this;
}
/**
*
* @param field
* @return
*/
public String getField(final String field) {
assert null == fields.get(field) || fields.get(field) instanceof String
: field + " is not a String. It is a "
+ (null != fields.get(field) ? fields.get(field).getClass().getSimpleName() : "null");
final String fieldValue = (String) fields.get(field);
return fieldValue != null && fieldValue.trim().length() > 0 ? fieldValue : null;
}
/**
* JavaBean standards access (read-only) to the fields map. Useful for JSPs.
* @return the fields map, via Collections.unmodifiableMap(..)
*/
public Map<String,Serializable> getFields(){
return fieldsReadOnly;
}
/**
*
* @param field
* @return
*/
public Serializable getObjectField(final String field) {
return fields.get(field);
}
/**
*
* @param field
* @param value
* @return
*/
public BasicResultItem addObjectField(final String field, final Serializable value) {
fields.put(field, value);
return this;
}
/**
*
* @param field
* @return
*/
public Integer getInteger(final String field) {
assert null == fields.get(field) || fields.get(field) instanceof Integer || fields.get(field) instanceof String
: field + " is not a Integer (or String). It is a "
+ (null != fields.get(field) ? fields.get(field).getClass().getSimpleName() : "null");
return null != fields.get(field)
? fields.get(field) instanceof Integer
? (Integer)fields.get(field)
: Integer.parseInt((String) fields.get(field))
: null;
}
/**
*
* @param field
* @param maxLength
* @return
*/
public String getField(final String field, final int maxLength) {
assert null == fields.get(field) || fields.get(field) instanceof String
: field + " is not a String. It is a "
+ (null != fields.get(field) ? fields.get(field).getClass().getSimpleName() : "null");
final String fieldValue = (String) fields.get(field);
return fieldValue != null && fieldValue.trim().length() > 0
? StringChopper.chop(fieldValue, maxLength)
: null;
}
/** Returns a defensive copy of the field names existing in this resultItem.
*
* @return
*/
public Collection<String> getFieldNames() {
return Collections.unmodifiableSet(fields.keySet());
}
/** Returns a live copy of the field's collection.
*
* If field is of String type, it is wrapped in a collection as a single entry.
*
* @param field
* @return
*/
public Collection<String> getMultivaluedField(final String field) {
assert null == fields.get(field) || fields.get(field) instanceof Collection || fields.get(field) instanceof String
: field + " is not a Collection (or String). It is a "
+ (null != fields.get(field) ? fields.get(field).getClass().getSimpleName() : "null");
return fields.get(field) instanceof Collection
? (Collection<String>) fields.get(field)
: Collections.singletonList((String)fields.get(field));
}
/**
*
* @param field
* @param value
* @return
*/
public BasicResultItem addToMultivaluedField(final String field, final String value) {
if (! fields.containsKey(field)) {
fields.put(field, new ArrayList<String>());
}
final Collection<String> previousValues = (Collection<String>) fields.get(field);
previousValues.add(value);
return this;
}
@Override
public boolean equals(final Object obj) {
boolean result = false;
if( obj instanceof ResultItem ){
final ResultItem other = (ResultItem) obj;
if (other.getField("recordid") != null && getField("recordid") != null) {
result = getField("recordid").equals(other.getField("recordid"));
}else{
result = true;
for(String fieldName : other.getFieldNames()){
if (other.getObjectField(fieldName) == null) {
result &= null == getObjectField(fieldName);
} else {
result &= other.getObjectField(fieldName).equals(getObjectField(fieldName));
}
}
}
}else{
result = super.equals(obj);
}
return result;
}
@Override
public int hashCode() {
if (getField("recordid") != null) {
return getField("recordid").hashCode();
} else {
// there nothing else to this object than the fields map.
return fields.hashCode();
}
}
public String getUrl() {
return getField(URL_KEY);
}
public ResultItem setUrl(final String url) {
return addField(URL_KEY, url);
}
public String getTitle() {
return getField(TITLE_KEY);
}
public ResultItem setTitle(final String title) {
return addField(TITLE_KEY, title);
}
}