org.bibsonomy.lucene.util.LuceneResourceConverter.java Source code

Java tutorial

Introduction

Here is the source code for org.bibsonomy.lucene.util.LuceneResourceConverter.java

Source

/**
 *
 *  BibSonomy-Lucene - A blue social bookmark and publication sharing system.
 *
 *  Copyright (C) 2006 - 2011 Knowledge & Data Engineering Group,
 *                            University of Kassel, Germany
 *                            http://www.kde.cs.uni-kassel.de/
 *
 *  This program 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 2
 *  of the License, or (at your option) any later version.
 *
 *  This program 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 this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

package org.bibsonomy.lucene.util;

import static org.bibsonomy.lucene.util.LuceneBase.CFG_FLDINDEX;
import static org.bibsonomy.lucene.util.LuceneBase.CFG_FLDSTORE;
import static org.bibsonomy.lucene.util.LuceneBase.CFG_FULLTEXT_FLAG;
import static org.bibsonomy.lucene.util.LuceneBase.CFG_LIST_DELIMITER;
import static org.bibsonomy.lucene.util.LuceneBase.CFG_LUCENENAME;
import static org.bibsonomy.lucene.util.LuceneBase.CFG_PRIVATE_FLAG;
import static org.bibsonomy.lucene.util.LuceneBase.CFG_TYPEHANDLER;
import static org.bibsonomy.lucene.util.LuceneBase.FLD_MERGEDFIELDS;
import static org.bibsonomy.lucene.util.LuceneBase.FLD_PRIVATEFIELDS;
import static org.bibsonomy.util.ValidationUtils.present;

import java.lang.reflect.InvocationTargetException;
import java.util.Map;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Index;
import org.apache.lucene.document.Field.Store;
import org.bibsonomy.lucene.param.LucenePost;
import org.bibsonomy.lucene.param.typehandler.LuceneTypeHandler;
import org.bibsonomy.model.Post;
import org.bibsonomy.model.Resource;
import org.bibsonomy.model.User;
import org.bibsonomy.util.tex.TexDecode;

/**
 * class for converting bibsonomy post model objects to lucene documents
 * 
 * @author fei
 * @version $Id: LuceneResourceConverter.java,v 1.7 2010-07-16 12:12:00 nosebrain Exp $
 * 
 * @param <R> the resource to convert
 */
public abstract class LuceneResourceConverter<R extends Resource> {
    private static final Log log = LogFactory.getLog(LuceneResourceConverter.class);

    /** property map for configuring and mapping post model properties to lucene fields and vice versa */
    private Map<String, Map<String, Object>> postPropertyMap;

    /**
     * read property values from given lucene document and creates post model
     * 
     * @param doc
     * @return the post representation of the lucene document
     */
    public Post<R> writePost(final Document doc) {
        // initialize 
        final Post<R> post = this.createEmptyPost();

        // cycle though all properties and store the corresponding
        // values in the content hash map
        for (String propertyName : postPropertyMap.keySet()) {
            // get lucene index properties
            String fieldName = (String) postPropertyMap.get(propertyName).get(CFG_LUCENENAME);
            String propertyStr = doc.get(fieldName);

            if (!present(propertyStr))
                continue;

            @SuppressWarnings("unchecked")
            final LuceneTypeHandler<Object> typeHandler = (LuceneTypeHandler<Object>) postPropertyMap
                    .get(propertyName).get(CFG_TYPEHANDLER);

            Object propertyValue = null;
            if (typeHandler != null) {
                propertyValue = typeHandler.setValue(propertyStr);
            } else
                propertyValue = propertyStr;

            try {
                PropertyUtils.setNestedProperty(post, propertyName, propertyValue);
            } catch (Exception e) {
                log.error("Error setting property " + propertyName + " to " + propertyValue.toString(), e);
            }
        }

        // all done.
        return post;
    }

    /**
     * read property values from given object as defined in given propertyMap
     * 
     * @param post
     * @return the lucene document representation of the post
     */
    public Document readPost(final Post<R> post) {
        final Document retVal = new Document();
        // FIXME: default values should be configured via spring
        Index fldDefaultIndex = Field.Index.NOT_ANALYZED;
        Store fldDefaultStore = Field.Store.YES;
        Index fldIndex = fldDefaultIndex;
        Store fldStore = fldDefaultStore;

        // all fields are concatenated for full text search
        String mergedField = "";

        // all private fields are concatenated for full text search
        String privateField = "";

        //--------------------------------------------------------------------
        // cycle though all properties and store the corresponding
        // values in the content hash map
        //--------------------------------------------------------------------
        for (String propertyName : postPropertyMap.keySet()) {
            //----------------------------------------------------------------
            // retrieve property value from post object
            //----------------------------------------------------------------
            // extract property value from object
            Object property = null;
            String propertyValue = "";
            try {
                // get property from post object
                property = PropertyUtils.getProperty(post, propertyName);
                // only handle non-null values
                if (property != null) {
                    @SuppressWarnings("unchecked")
                    LuceneTypeHandler<Object> typeHandler = (LuceneTypeHandler<Object>) postPropertyMap
                            .get(propertyName).get(CFG_TYPEHANDLER);

                    // get property value
                    propertyValue = extractPropertyValue(postPropertyMap, typeHandler, propertyName, property);

                    // get lucene index configuration
                    final Index index = (Index) postPropertyMap.get(propertyName).get(CFG_FLDINDEX);
                    if (index != null) {
                        fldIndex = index;
                    } else {
                        fldIndex = fldDefaultIndex;
                    }
                    if (postPropertyMap.get(propertyName).get(CFG_FLDSTORE) != null) {
                        fldStore = (Store) postPropertyMap.get(propertyName).get(CFG_FLDSTORE);
                    } else {
                        fldStore = fldDefaultStore;
                    }
                }
            } catch (Exception e) {
                log.error("Error reading property '" + propertyName + "' from post object.", e);
            }
            //----------------------------------------------------------------
            // add property to the lucene document
            //----------------------------------------------------------------
            String luceneName = (String) postPropertyMap.get(propertyName).get(CFG_LUCENENAME);
            // FIXME: configure default value field wise via spring
            String defaultValue = "";
            if ((propertyValue != null) && (luceneName != null) && (!"".equals(propertyValue.trim()))) {
                // add field to the lucene document
                retVal.add(new Field(luceneName, propertyValue, fldStore, fldIndex));
                // add term to full text search field, if configured accordingly 
                if (present(postPropertyMap.get(propertyName).get(CFG_FULLTEXT_FLAG))
                        && (Boolean) postPropertyMap.get(propertyName).get(CFG_FULLTEXT_FLAG)) {
                    mergedField += CFG_LIST_DELIMITER + propertyValue;
                }
                // add term to private full text search field, if configured accordingly 
                if (present(postPropertyMap.get(propertyName).get(CFG_PRIVATE_FLAG))
                        && (Boolean) postPropertyMap.get(propertyName).get(CFG_PRIVATE_FLAG)) {
                    privateField += CFG_LIST_DELIMITER + propertyValue;
                }
            } else {
                // add empty field
                retVal.add(new Field(luceneName, defaultValue, fldStore, fldIndex));
            }
        }

        // store merged field
        retVal.add(new Field(FLD_MERGEDFIELDS, decodeTeX(mergedField), Field.Store.NO, Field.Index.ANALYZED));

        // store private field
        retVal.add(new Field(FLD_PRIVATEFIELDS, decodeTeX(privateField), Field.Store.YES, Field.Index.ANALYZED));

        // all done.
        return retVal;
    }

    /**
     * extracts property value from given object
     * 
     * @param bibTexPropertyMap TODO: unused
     * @param propertyName TODO: unused
     * @param item
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     * @throws NoSuchMethodException
     */
    private String extractPropertyValue(Map<String, Map<String, Object>> bibTexPropertyMap,
            LuceneTypeHandler<Object> typeHandler, String propertyName, Object item)
            throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        String itemValue = null;
        // get the string value for the given object
        if (typeHandler != null) {
            // if a type handler is set, use the type handler for rendering the string
            itemValue = typeHandler.getValue(item);
        } else {
            // if no type handler is set use Object.toString()
            itemValue = item.toString();
        }
        return itemValue;
    }

    /**
     * decode bibtex characters to corresponding utf8 characters
     * 
     * @param input
     * @return
     */
    private String decodeTeX(String input) {
        String mergedFieldUTF8 = null;
        try {
            mergedFieldUTF8 = TexDecode.decode(input);
        } catch (IllegalStateException e) {
            mergedFieldUTF8 = input;
            log.debug("Error decoding TeX-string '" + input + "'");
        }
        return mergedFieldUTF8;
    }

    private Post<R> createEmptyPost() {
        final R resource = this.createNewResource();
        final User user = new User();
        final Post<R> post = new LucenePost<R>();
        post.setResource(resource);
        post.setUser(user);
        post.getResource().recalculateHashes();
        return post;
    }

    protected abstract R createNewResource();

    /**
     * @param postPropertyMap the postPropertyMap to set
     */
    public void setPostPropertyMap(Map<String, Map<String, Object>> postPropertyMap) {
        this.postPropertyMap = postPropertyMap;
    }

    /**
     * @return the postPropertyMap
     */
    public Map<String, Map<String, Object>> getPostPropertyMap() {
        return this.postPropertyMap;
    }

}