/* * Red Bee Browser * * Copyright (c) 2013 Tran Dinh Thoai <dthoai@yahoo.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 3. * * 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 * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package com.redbee.schema; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.StringReader; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Properties; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.CachingTokenFilter; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.index.Term; import org.apache.lucene.queryParser.MultiFieldQueryParser; import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.BooleanClause.Occur; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.FieldValueFilter; import org.apache.lucene.search.Filter; import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.search.MultiPhraseQuery; import org.apache.lucene.search.NGramPhraseQuery; import org.apache.lucene.search.NumericRangeFilter; import org.apache.lucene.search.NumericRangeQuery; import org.apache.lucene.search.PhraseQuery; import org.apache.lucene.search.PrefixFilter; import org.apache.lucene.search.PrefixQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.QueryWrapperFilter; import org.apache.lucene.search.Sort; import org.apache.lucene.search.SortField; import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.TermRangeFilter; import org.apache.lucene.search.TermRangeQuery; import org.apache.lucene.search.WildcardQuery; import org.apache.lucene.search.highlight.Highlighter; import org.apache.lucene.search.highlight.Scorer; import org.apache.lucene.search.highlight.SimpleFragmenter; import org.apache.lucene.search.highlight.SimpleHTMLFormatter; import org.apache.lucene.util.Version; import com.redbee.CodeTool; public class Entity { public static final String STRING = "s"; public static final String DOUBLE = "d"; public static final String FLOAT = "f"; public static final String INTEGER = "i"; public static final String LONG = "l"; public static final String ANALYZED = "a"; public static final String ALL_KINDS = "|s|d|f|i|l|a|"; public static final String SCHEMA = "F4f8cc93237f50"; public static final String ID = "F4f8cce61643dd"; public static final String CREATED = "F4f8cd83fcca31"; public static final String UPDATED = "F4f8cd84e2b74a"; public static final String KIND = "F4f8cd9c8ee13d"; public static final String MARK = "F4f8cda27d62fb"; protected Properties data = new Properties(); protected Properties schema = new Properties(); protected Handler handler = null; public Entity(Handler handler) { this.handler = handler; registerDefault(); } public void register(String field, String type) { if (ALL_KINDS.indexOf("|" + type + "|") < 0) return; schema.put(field, type); saveSchema(); } public void setSchema(String src) { String[] fields = src.split("\\|"); schema.clear(); for (int i = 0; i < fields.length && i + 1 < fields.length; i+= 2) { register(fields[i + 1], fields[i]); } registerDefault(); saveSchema(); } public String getSchema() { String tag = data.getProperty(SCHEMA); if (tag == null) tag = ""; return tag; } public void fromString(String src) { data.clear(); schema.clear(); try { ByteArrayInputStream bais = new ByteArrayInputStream(src.getBytes("UTF-8")); data.load(bais); bais.close(); } catch (Exception e) { } loadSchema(); } public String toString() { String tag = ""; try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); data.store(baos, ""); tag = baos.toString(); baos.close(); } catch (Exception e) { } return tag; } public String getString(String field) { String tag = data.getProperty(field); if (tag == null) tag = ""; return tag; } public void setString(String field, String value) { if (schema.containsKey(field)) { if (value == null) value = ""; data.setProperty(field, value); } } public double getDouble(String field) { double tag = 0; try { tag = Double.parseDouble(getString(field)); } catch (Exception e) { tag = 0; } return tag; } public void setDouble(String field, double value) { setString(field, Double.toString(value)); } public float getFloat(String field) { float tag = 0; try { tag = Float.parseFloat(getString(field)); } catch (Exception e) { tag = 0; } return tag; } public void setFloat(String field, float value) { setString(field, Float.toString(value)); } public long getLong(String field) { long tag = 0; try { tag = Long.parseLong(getString(field)); } catch (Exception e) { tag = 0; } return tag; } public void setLong(String field, long value) { setString(field, Long.toString(value)); } public int getInteger(String field) { int tag = 0; try { tag = Integer.parseInt(getString(field)); } catch (Exception e) { tag = 0; } return tag; } public void setInteger(String field, int value) { setString(field, Integer.toString(value)); } public String getId() { return getString(ID); } public void setId(String src) { setString(ID, src); } public String getKind() { return getString(KIND); } public void setKind(String src) { setString(KIND, src); } public String getMark() { return getString(MARK); } public void setMark(String src) { setString(MARK, src); } public Date getCreated() { return new Date(getLong(CREATED)); } public Date getUpdated() { return new Date(getLong(UPDATED)); } public boolean exists() { if (handler == null) { return false; } else { return handler.exists(getId()); } } public void save() { if (handler != null) { long now = new Date().getTime(); if (handler.exists(getId())) { setLong(UPDATED, now); handler.update(this); } else { setLong(CREATED, now); setLong(UPDATED, now); handler.create(this); } } } public int count(String kind, Query query, int max) { if (handler != null) { return handler.count(kind, query, max); } return 0; } public int count(String kind, Query query, Sort sort, int max) { if (handler != null) { return handler.count(kind, query, sort, max); } return 0; } public int count(String kind, Query query, Filter filter, int max) { if (handler != null) { return handler.count(kind, query, filter, max); } return 0; } public int count(String kind, Query query, Filter filter, Sort sort, int max) { if (handler != null) { return handler.count(kind, query, filter, sort, max); } return 0; } public List<Entity> search(String kind, Query query, int max) { if (handler != null) { return handler.search(kind, query, max); } return new ArrayList<Entity>(); } public List<Entity> search(String kind, Query query, Sort sort, int max) { if (handler != null) { return handler.search(kind, query, sort, max); } return new ArrayList<Entity>(); } public List<Entity> search(String kind, Query query, Filter filter, int max) { if (handler != null) { return handler.search(kind, query, filter, max); } return new ArrayList<Entity>(); } public List<Entity> search(String kind, Query query, Filter filter, Sort sort, int max) { if (handler != null) { return handler.search(kind, query, filter, sort, max); } return new ArrayList<Entity>(); } public List<Entity> search(String kind, Query query, int pagesize, int pageno) { if (handler != null) { return handler.search(kind, query, pagesize, pageno); } return new ArrayList<Entity>(); } public List<Entity> search(String kind, Query query, Sort sort, int pagesize, int pageno) { if (handler != null) { return handler.search(kind, query, sort, pagesize, pageno); } return new ArrayList<Entity>(); } public List<Entity> search(String kind, Query query, Filter filter, int pagesize, int pageno) { if (handler != null) { return handler.search(kind, query, filter, pagesize, pageno); } return new ArrayList<Entity>(); } public List<Entity> search(String kind, Query query, Filter filter, Sort sort, int max, int pagesize, int pageno) { if (handler != null) { return handler.search(kind, query, filter, sort, pagesize, pageno); } return new ArrayList<Entity>(); } public void load(String id) { if (handler != null) { handler.load(id, this); } } public BooleanQuery newBooleanQuery() { return new BooleanQuery(); } public BooleanClause newBooleanClause(Query query, Occur occur) { return new BooleanClause(query, occur); } public Occur occurMust() { return Occur.MUST; } public Occur occurMustNot() { return Occur.MUST_NOT; } public Occur occurShould() { return Occur.SHOULD; } public MatchAllDocsQuery newMatchAllDocsQuery() { return new MatchAllDocsQuery(); } public MultiPhraseQuery newMultiPhraseQuery() { return new MultiPhraseQuery(); } public PhraseQuery newPhraseQuery() { return new PhraseQuery(); } public NGramPhraseQuery newNGramPhraseQuery(int n) { return new NGramPhraseQuery(n); } public Term newTerm(String field, String value) { return new Term(field, value); } public NumericRangeQuery<Double> newDoubleRangeQuery(String field, Double min, Double max, boolean minInclusive, boolean maxInclusive) { return NumericRangeQuery.newDoubleRange(field, min, max, minInclusive, maxInclusive); } public NumericRangeQuery<Double> newDoubleRangeQuery(String field, int precisionStep, Double min, Double max, boolean minInclusive, boolean maxInclusive) { return NumericRangeQuery.newDoubleRange(field, precisionStep, min, max, minInclusive, maxInclusive); } public NumericRangeQuery<Float> newFloatRangeQuery(String field, Float min, Float max, boolean minInclusive, boolean maxInclusive) { return NumericRangeQuery.newFloatRange(field, min, max, minInclusive, maxInclusive); } public NumericRangeQuery<Float> newFloatRangeQuery(String field, int precisionStep, Float min, Float max, boolean minInclusive, boolean maxInclusive) { return NumericRangeQuery.newFloatRange(field, precisionStep, min, max, minInclusive, maxInclusive); } public NumericRangeQuery<Integer> newIntegerRangeQuery(String field, Integer min, Integer max, boolean minInclusive, boolean maxInclusive) { return NumericRangeQuery.newIntRange(field, min, max, minInclusive, maxInclusive); } public NumericRangeQuery<Integer> newIntegerRangeQuery(String field, int precisionStep, Integer min, Integer max, boolean minInclusive, boolean maxInclusive) { return NumericRangeQuery.newIntRange(field, precisionStep, min, max, minInclusive, maxInclusive); } public NumericRangeQuery<Long> newLongRangeQuery(String field, Long min, Long max, boolean minInclusive, boolean maxInclusive) { return NumericRangeQuery.newLongRange(field, min, max, minInclusive, maxInclusive); } public NumericRangeQuery<Long> newLongRangeQuery(String field, int precisionStep, Long min, Long max, boolean minInclusive, boolean maxInclusive) { return NumericRangeQuery.newLongRange(field, precisionStep, min, max, minInclusive, maxInclusive); } public PrefixQuery newPrefixQuery(Term term) { return new PrefixQuery(term); } public TermQuery newTermQuery(Term term) { return new TermQuery(term); } public TermRangeQuery newTermRangeQuery(String field, String lowerTerm, String upperTerm, boolean includeLower, boolean includeUpper) { return new TermRangeQuery(field, lowerTerm, upperTerm, includeLower, includeUpper); } public WildcardQuery newWildcardQuery(Term term) { return new WildcardQuery(term); } public FieldValueFilter newFieldValueFilter(String field, boolean negate) { return new FieldValueFilter(field, negate); } public NumericRangeFilter<Double> newDoubleRangeFilter(String field, Double min, Double max, boolean minInclusive, boolean maxInclusive) { return NumericRangeFilter.newDoubleRange(field, min, max, minInclusive, maxInclusive); } public NumericRangeFilter<Double> newDoubleRangeFilter(String field, int precisionStep, Double min, Double max, boolean minInclusive, boolean maxInclusive) { return NumericRangeFilter.newDoubleRange(field, precisionStep, min, max, minInclusive, maxInclusive); } public NumericRangeFilter<Float> newFloatRangeFilter(String field, Float min, Float max, boolean minInclusive, boolean maxInclusive) { return NumericRangeFilter.newFloatRange(field, min, max, minInclusive, maxInclusive); } public NumericRangeFilter<Float> newFloatRangeFilter(String field, int precisionStep, Float min, Float max, boolean minInclusive, boolean maxInclusive) { return NumericRangeFilter.newFloatRange(field, precisionStep, min, max, minInclusive, maxInclusive); } public NumericRangeFilter<Integer> newIntegerRangeFilter(String field, Integer min, Integer max, boolean minInclusive, boolean maxInclusive) { return NumericRangeFilter.newIntRange(field, min, max, minInclusive, maxInclusive); } public NumericRangeFilter<Integer> newIntegerRangeFilter(String field, int precisionStep, Integer min, Integer max, boolean minInclusive, boolean maxInclusive) { return NumericRangeFilter.newIntRange(field, precisionStep, min, max, minInclusive, maxInclusive); } public NumericRangeFilter<Long> newLongRangeFilter(String field, Long min, Long max, boolean minInclusive, boolean maxInclusive) { return NumericRangeFilter.newLongRange(field, min, max, minInclusive, maxInclusive); } public NumericRangeFilter<Long> newLongRangeFilter(String field, int precisionStep, Long min, Long max, boolean minInclusive, boolean maxInclusive) { return NumericRangeFilter.newLongRange(field, precisionStep, min, max, minInclusive, maxInclusive); } public PrefixFilter newPrefixFilter(Term term) { return new PrefixFilter(term); } public QueryWrapperFilter newQueryWrapperFilter(Query query) { return new QueryWrapperFilter(query); } public TermRangeFilter newTermRangeFilter(String fieldName, String lowerTerm, String upperTerm, boolean includeLower, boolean includeUpper) { return new TermRangeFilter(fieldName, lowerTerm, upperTerm, includeLower, includeUpper); } public SortField newSortField(String field, int type, boolean reverse) { return new SortField(field, type, reverse); } public Sort newSort() { return new Sort(); } public Sort newSort(SortField... fields) { return new Sort(fields); } public Sort newSort(SortField field) { return new Sort(field); } public Query parseQuery(String[] queries, String[] fields) throws Exception { return MultiFieldQueryParser.parse(Version.LUCENE_36, queries, fields, new StandardAnalyzer(Version.LUCENE_36)); } public Query parseQuery(String[] queries, String[] fields, BooleanClause.Occur[] flags) throws Exception { return MultiFieldQueryParser.parse(Version.LUCENE_36, queries, fields, flags, new StandardAnalyzer(Version.LUCENE_36)); } public Query parseQuery(String query, String[] fields, BooleanClause.Occur[] flags) throws Exception { return MultiFieldQueryParser.parse(Version.LUCENE_36, query, fields, flags, new StandardAnalyzer(Version.LUCENE_36)); } public String highlight(Query query, String text, String field, int fragmentSize, int maxNumFragments, String separator) throws Exception { Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_36); CachingTokenFilter tokenStream = new CachingTokenFilter(analyzer.tokenStream(field, new StringReader(text))); SimpleHTMLFormatter formatter = new SimpleHTMLFormatter(); Scorer scorer = new org.apache.lucene.search.highlight.QueryScorer(query); Highlighter highlighter = new Highlighter(formatter, scorer); highlighter.setTextFragmenter(new SimpleFragmenter(fragmentSize)); tokenStream.reset(); String rv = highlighter.getBestFragments(tokenStream, text, maxNumFragments, separator); return rv.length() == 0 ? text : rv; } protected void registerDefault() { register(SCHEMA, "s"); register(ID, "s"); register(CREATED, "l"); register(UPDATED, "l"); register(KIND, "s"); register(MARK, "s"); } protected void saveSchema() { String tag = ""; for (Object key : schema.keySet()) { if (tag.length() > 0) tag += "|"; tag += schema.get(key) + "|" + key; } data.put(SCHEMA, tag); } protected void loadSchema() { String src = data.getProperty(SCHEMA); if (src == null) src = ""; String[] fields = src.split("\\|"); schema.clear(); for (int i = 0; i < fields.length && i + 1 < fields.length; i+= 2) { register(fields[i + 1], fields[i]); } registerDefault(); String tag = ""; for (Object key : schema.keySet()) { if (tag.length() > 0) tag += "|"; tag += schema.get(key) + "|" + key; } data.put(SCHEMA, tag); } public void delete() { delete(getId()); } public void delete(String id) { if (handler != null) { handler.delete(id); } } public SortField sortFieldDoc() { return SortField.FIELD_DOC; } public SortField sortFieldScore() { return SortField.FIELD_SCORE; } public int sortFieldLong() { return SortField.LONG; } public int sortFieldInteger() { return SortField.INT; } public int sortFieldDouble() { return SortField.DOUBLE; } public int sortFieldFloat() { return SortField.FLOAT; } public int sortFieldString() { return SortField.STRING_VAL; } public boolean getBoolean(String name) { return getBoolean(name, false); } public boolean getBoolean(String name, boolean defValue) { String val = getString(name); boolean tag = defValue; if ("true".equalsIgnoreCase(val)) tag = true; if ("false".equalsIgnoreCase(val)) tag = false; return tag; } public void setBoolean(String name, boolean value) { setString(name, value + ""); } public Date getDate(String name) { return new Date(getLong(name)); } public void setDate(String name, Date value) { setLong(name, value.getTime()); } public List<String> getMultipleString(String name) { List<String> tag = new ArrayList<String>(); String val = getString(name); String[] fields = val.split("\n"); for (int i = 0; i < fields.length; i++) { String item = fields[i]; item = CodeTool.replace(item, "\\n", "\n"); item = CodeTool.replace(item, "\\\\", "\\"); tag.add(item); } return tag; } public void setMultipleString(String name, List<String> value) { String tag = ""; for (int i = 0; i < value.size(); i++) { String item = value.get(i); item = CodeTool.replace(item, "\\", "\\\\"); item = CodeTool.replace(item, "\n", "\\n"); if (i > 0) tag += "\n"; tag += item; } setString(name, tag); } public List<Integer> getMultipleInteger(String name) { return getMultipleInteger(name, 0); } public List<Integer> getMultipleInteger(String name, int defValue) { List<Integer> tag = new ArrayList<Integer>(); String[] fields = getString(name).split("\n"); for (int i = 0; i < fields.length; i++) { Integer item = defValue; try { item = Integer.parseInt(fields[i]); } catch (Exception e) { } tag.add(item); } return tag; } public void setMultipleInteger(String name, List<Integer> value) { String tag = ""; for (int i = 0; i < value.size(); i++) { if (i > 0) tag += "\n"; tag += value.get(i) + ""; } setString(name, tag); } public List<Long> getMultipleLong(String name) { return getMultipleLong(name, 0); } public List<Long> getMultipleLong(String name, long defValue) { List<Long> tag = new ArrayList<Long>(); String[] fields = getString(name).split("\n"); for (int i = 0; i < fields.length; i++) { long item = defValue; try { item = Long.parseLong(fields[i]); } catch (Exception e) { } tag.add(item); } return tag; } public void setMultipleLong(String name, List<Long> value) { String tag = ""; for (int i = 0; i < value.size(); i++) { if (i > 0) tag += "\n"; tag += value.get(i) + ""; } setString(name, tag); } public List<Float> getMultipleFloat(String name) { return getMultipleFloat(name, 0); } public List<Float> getMultipleFloat(String name, float defValue) { List<Float> tag = new ArrayList<Float>(); String[] fields = getString(name).split("\n"); for (int i = 0; i < fields.length; i++) { float item = defValue; try { item = Float.parseFloat(fields[i]); } catch (Exception e) { } tag.add(item); } return tag; } public void setMultipleFloat(String name, List<Float> value) { String tag = ""; for (int i = 0; i < value.size(); i++) { if (i > 0) tag += "\n"; tag += value.get(i) + ""; } setString(name, tag); } public List<Double> getMultipleDouble(String name) { return getMultipleDouble(name, 0); } public List<Double> getMultipleDouble(String name, double defValue) { List<Double> tag = new ArrayList<Double>(); String[] fields = getString(name).split("\n"); for (int i = 0; i < fields.length; i++) { double item = defValue; try { item = Double.parseDouble(fields[i]); } catch (Exception e) { } tag.add(item); } return tag; } public void setMultipleDouble(String name, List<Double> value) { String tag = ""; for (int i = 0; i < value.size(); i++) { if (i > 0) tag += "\n"; tag += value.get(i) + ""; } setString(name, tag); } public List<Boolean> getMultipleBoolean(String name) { return getMultipleBoolean(name, false); } public List<Boolean> getMultipleBoolean(String name, boolean defValue) { List<Boolean> tag = new ArrayList<Boolean>(); String[] fields = getString(name).split("\n"); for (int i = 0; i < fields.length; i++) { boolean item = defValue; if ("true".equalsIgnoreCase(fields[i])) item = true; if ("false".equalsIgnoreCase(fields[i])) item = false; tag.add(item); } return tag; } public void setMultipleBoolean(String name, List<Boolean> value) { String tag = ""; for (int i = 0; i < value.size(); i++) { if (i > 0) tag += "\n"; tag += value.get(i) + ""; } setString(name, tag); } public List<Date> getMultipleDate(String name) { return getMultipleDate(name, "yyyy-MM-dd", new Date()); } public List<Date> getMultipleDate(String name, String format) { return getMultipleDate(name, format, new Date()); } public List<Date> getMultipleDate(String name, String format, Date defValue) { List<Date> tag = new ArrayList<Date>(); String[] fields = getString(name).split("\n"); SimpleDateFormat sdf = new SimpleDateFormat(format); for (int i = 0; i < fields.length; i++) { Date item = defValue; try { item = sdf.parse(fields[i]); } catch (Exception e) { } tag.add(item); } return tag; } public void setMultipleDate(String name, List<Date> value) { setMultipleDate(name, "yyyy-MM-dd", value); } public void setMultipleDate(String name, String format, List<Date> value) { String tag = ""; SimpleDateFormat sdf = new SimpleDateFormat(format); for (int i = 0; i < value.size(); i++) { try { String item = sdf.format(value.get(i)); if (i > 0) tag += "\n"; tag += item; } catch (Exception e) { } } setString(name, tag); } public static class Handler { public boolean exists(String id) { return false; } public void create(Entity src) { } public void update(Entity src) { } public void load(String id, Entity src) { } public void delete(String id) { } public List<Entity> search(String kind, Query query, int max) { return new ArrayList<Entity>(); } public List<Entity> search(String kind, Query query, Sort sort, int max) { return new ArrayList<Entity>(); } public List<Entity> search(String kind, Query query, Filter filter, int max) { return new ArrayList<Entity>(); } public List<Entity> search(String kind, Query query, Filter filter, Sort sort, int max) { return new ArrayList<Entity>(); } public List<Entity> search(String kind, Query query, int pagesize, int pageno) { return new ArrayList<Entity>(); } public List<Entity> search(String kind, Query query, Sort sort, int pagesize, int pageno) { return new ArrayList<Entity>(); } public List<Entity> search(String kind, Query query, Filter filter, int pagesize, int pageno) { return new ArrayList<Entity>(); } public List<Entity> search(String kind, Query query, Filter filter, Sort sort, int pagesize, int pageno) { return new ArrayList<Entity>(); } public int count(String kind, Query query, int max) { return 0; } public int count(String kind, Query query, Sort sort, int max) { return 0; } public int count(String kind, Query query, Filter filter, int max) { return 0; } public int count(String kind, Query query, Filter filter, Sort sort, int max) { return 0; } } }