Java tutorial
/* * SearchProxy.java * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU 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 Library General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Author: Winter Lau (javayou@gmail.com) * http://dlog4j.sourceforge.net * */ package com.liusoft.dlog4j.search; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.StringTokenizer; import org.apache.commons.beanutils.ConvertUtils; import org.apache.commons.beanutils.NestedNullException; import org.apache.commons.beanutils.PropertyUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.Term; import org.apache.lucene.queryParser.QueryParser; import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.Hits; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.Sort; import org.apache.lucene.search.SortField; import com.liusoft.dlog4j.beans.DiaryBean; /** * ?? * * <pre> * ?? * ????? * ?? * ?? * </pre> * * @author Winter Lau */ public class SearchProxy { private final static Log log = LogFactory.getLog(SearchProxy.class); public final static int MAX_RESULT_COUNT = 200; //?? private final static String CLASSNAME_FIELD = "___className"; private static String _baseIndexPath; public static void init(String _base_index_path) { _baseIndexPath = _base_index_path; if (!_baseIndexPath.endsWith(File.separator)) _baseIndexPath += File.separator; } /** * * @param doc * @throws Exception */ public static synchronized void add(SearchEnabled doc) throws Exception { if (doc == null) return; Document lucene_doc = new Document(); //Set keyword field String key = getField(doc, doc.getKeywordField()); lucene_doc.add(Keyword(doc.getKeywordField(), key)); //Set identity(classname) of object lucene_doc.add(Keyword(CLASSNAME_FIELD, doc.getClass().getName())); //Set storage field String[] storeFields = doc.getStoreFields(); for (int i = 0; storeFields != null && i < storeFields.length; i++) { String propertyValue = getField(doc, storeFields[i]); if (propertyValue != null) lucene_doc.add(Keyword(storeFields[i], propertyValue)); } //Set indexed field String[] indexFields = doc.getIndexFields(); for (int i = 0; indexFields != null && i < indexFields.length; i++) { String propertyValue = getField(doc, indexFields[i]); lucene_doc.add(UnStored(indexFields[i], propertyValue)); } //Write document IndexWriter writer = getWriter(doc.name()); try { writer.addDocument(lucene_doc); writer.optimize(); } finally { try { writer.close(); } catch (Exception e) { log.error("Error occur when closing IndexWriter", e); } finally { writer = null; } lucene_doc = null; } } /** * * @param doc * @return * @throws Exception */ public static synchronized int remove(SearchEnabled doc) { if (doc == null) return -1; IndexReader reader = null; try { reader = getReader(doc.name()); String pvalue = getField(doc, doc.getKeywordField()); Term keyTerm = new Term(doc.getKeywordField(), pvalue); return reader.deleteDocuments(keyTerm); } catch (Exception e) { log.error("Error where delete index of " + doc, e); } finally { if (reader != null) try { reader.close(); } catch (Exception e) { log.error("Error occur when closing IndexReader", e); } finally { reader = null; } } return -1; } /** * * @param doc * @return * @throws Exception */ public static void update(SearchEnabled doc) throws Exception { if (doc == null) return; remove(doc); add(doc); } /** * ? * @param params * @return * @throws Exception */ public static List search(SearchParameter params) throws Exception { if (params == null) return null; SearchEnabled searching = (SearchEnabled) params.getSearchObject().newInstance(); StringBuffer path = new StringBuffer(_baseIndexPath); path.append(searching.name()); File f = new File(path.toString()); if (!f.exists()) return null; IndexSearcher searcher = new IndexSearcher(path.toString()); //? BooleanQuery comboQuery = new BooleanQuery(); int _query_count = 0; StringTokenizer st = new StringTokenizer(params.getSearchKey()); while (st.hasMoreElements()) { String q = st.nextToken(); String[] indexFields = searching.getIndexFields(); for (int i = 0; i < indexFields.length; i++) { QueryParser qp = new QueryParser(indexFields[i], analyzer); try { Query subjectQuery = qp.parse(q); comboQuery.add(subjectQuery, BooleanClause.Occur.SHOULD); _query_count++; } catch (Exception e) { log.error("Add query parameter failed. key=" + q, e); } } } if (_query_count == 0)//? return null; //?? MultiFilter multiFilter = null; HashMap conds = params.getConditions(); if (conds != null) { Iterator keys = conds.keySet().iterator(); while (keys.hasNext()) { if (multiFilter == null) multiFilter = new MultiFilter(0); String key = (String) keys.next(); multiFilter.add(new FieldFilter(key, conds.get(key).toString())); } } /* * Creates a sort, possibly in reverse, * by terms in the given field with the type of term values explicitly given. */ SortField[] s_fields = new SortField[2]; s_fields[0] = SortField.FIELD_SCORE; s_fields[1] = new SortField(searching.getKeywordField(), SortField.INT, true); Sort sort = new Sort(s_fields); Hits hits = searcher.search(comboQuery, multiFilter, sort); int numResults = hits.length(); //System.out.println(numResults + " found............................"); int result_count = Math.min(numResults, MAX_RESULT_COUNT); List results = new ArrayList(result_count); for (int i = 0; i < result_count; i++) { Document doc = (Document) hits.doc(i); //Java Object result = params.getSearchObject().newInstance(); Enumeration fields = doc.fields(); while (fields.hasMoreElements()) { Field field = (Field) fields.nextElement(); //System.out.println(field.name()+" -- "+field.stringValue()); if (CLASSNAME_FIELD.equals(field.name())) continue; //? if (!field.isStored()) continue; //System.out.println("=========== begin to mapping ============"); //String --> anything Class fieldType = getNestedPropertyType(result, field.name()); //System.out.println(field.name()+", class = " + fieldType.getName()); Object fieldValue = null; if (fieldType.equals(Date.class)) fieldValue = new Date(Long.parseLong(field.stringValue())); else fieldValue = ConvertUtils.convert(field.stringValue(), fieldType); //System.out.println(fieldValue+", class = " + fieldValue.getClass().getName()); setNestedProperty(result, field.name(), fieldValue); } results.add(result); } return results; } /** * ? * @param obj * @param field * @return * @throws IllegalAccessException * @throws InvocationTargetException * @throws NoSuchMethodException * @throws SecurityException * @throws NoSuchFieldException * @throws IntrospectionException */ private static Class getNestedPropertyType(Object obj, String field) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException, SecurityException, NoSuchFieldException, IntrospectionException { StringTokenizer st = new StringTokenizer(field, "."); Class nodeClass = obj.getClass(); while (st.hasMoreElements()) { String f = st.nextToken(); PropertyDescriptor[] props = Introspector.getBeanInfo(nodeClass).getPropertyDescriptors(); for (int i = 0; i < props.length; i++) { if (props[i].getName().equals(f)) { nodeClass = props[i].getPropertyType(); continue; } } } return nodeClass; } /** * * @param obj * @param field * @param value * @throws IllegalAccessException * @throws InvocationTargetException * @throws NoSuchMethodException * @throws IntrospectionException * @throws InstantiationException */ private static void setNestedProperty(Object obj, String field, Object value) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException, IntrospectionException, InstantiationException { StringTokenizer st = new StringTokenizer(field, "."); Class nodeClass = obj.getClass(); StringBuffer tmp_prop = new StringBuffer(); while (st.hasMoreElements()) { String f = st.nextToken(); if (tmp_prop.length() > 0) tmp_prop.append('.'); tmp_prop.append(f); PropertyDescriptor[] props = Introspector.getBeanInfo(nodeClass).getPropertyDescriptors(); for (int i = 0; i < props.length; i++) { if (props[i].getName().equals(f)) { if (PropertyUtils.getNestedProperty(obj, tmp_prop.toString()) == null) { nodeClass = props[i].getPropertyType(); PropertyUtils.setNestedProperty(obj, f, nodeClass.newInstance()); } continue; } } } PropertyUtils.setNestedProperty(obj, field, value); } /** * ? * @param name * @return * @throws IOException */ private static IndexReader getReader(String name) throws IOException { StringBuffer path = new StringBuffer(_baseIndexPath); path.append(name); try { return IndexReader.open(path.toString()); } finally { path = null; } } /** * ? * @param name * @return * @throws IOException */ private static IndexWriter getWriter(String name) throws IOException { StringBuffer path = new StringBuffer(_baseIndexPath); path.append(name); String index_path = path.toString(); File rp = new File(index_path); if (!rp.exists()) rp.mkdirs(); int wc = 0; //waiting for the lock of indexes while (wc < 10 && IndexReader.isLocked(index_path)) { try { Thread.sleep(100); } catch (InterruptedException e) { return null; } wc++; } path.append(File.separator); path.append(SEGMENTS); File segments = new File(path.toString()); try { boolean bCreate = !segments.exists(); return new IndexWriter(index_path, new StandardAnalyzer(), bCreate); } finally { path = null; segments = null; rp = null; } } private final static String SEGMENTS = "segments"; /** * ? * @param obj * @param field * @return * @throws IllegalAccessException * @throws InvocationTargetException * @throws NoSuchMethodException */ private static String getField(Object obj, String field) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { try { Object fieldValue = PropertyUtils.getNestedProperty(obj, field); if (fieldValue instanceof String) return (String) fieldValue; if (fieldValue instanceof Date) return Long.toString(((Date) fieldValue).getTime()); return String.valueOf(fieldValue); } catch (NestedNullException e) { } return null; } private static StandardAnalyzer analyzer = new StandardAnalyzer(); protected static final Field Keyword(String name, String value) { return new Field(name, value, Field.Store.YES, Field.Index.UN_TOKENIZED); } protected static final Field Text(String name, String value) { return new Field(name, value, Field.Store.YES, Field.Index.TOKENIZED); } protected static final Field UnStored(String name, String value) { return new Field(name, value, Field.Store.NO, Field.Index.TOKENIZED); } /** * ? * @param args * @throws Exception */ public static void main(String[] args) throws Exception { //? DiaryBean log = new DiaryBean(); /* log.setAuthor("Winter Lau"); System.out.println(getField(log, "author")); log.setOwner(new UserBean(123)); log.getOwner().setNickname(""); System.out.println(getField(log, "owner.nickname")); Class ft = PropertyUtils.getPropertyType(log, "owner.id"); Object fv = ConvertUtils.convert("119", ft); PropertyUtils.setNestedProperty(log, "owner.id", fv); System.out.println(getField(log, "owner.id")); */ setNestedProperty(log, "site.title", "JavaYou"); setNestedProperty(log, "site.friendlyName", "Java"); System.out.println(getNestedPropertyType(log, "site.id").getName()); System.out.println(log.getSite().getTitle()); System.out.println(log.getSite().getFriendlyName()); } }