Return-Path: Delivered-To: apmail-cocoon-cvs-archive@www.apache.org Received: (qmail 64582 invoked from network); 18 Nov 2004 16:25:38 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur-2.apache.org with SMTP; 18 Nov 2004 16:25:38 -0000 Received: (qmail 12792 invoked by uid 500); 18 Nov 2004 16:25:37 -0000 Delivered-To: apmail-cocoon-cvs-archive@cocoon.apache.org Received: (qmail 12727 invoked by uid 500); 18 Nov 2004 16:25:37 -0000 Mailing-List: contact cvs-help@cocoon.apache.org; run by ezmlm Precedence: bulk Reply-To: dev@cocoon.apache.org list-help: list-unsubscribe: list-post: Delivered-To: mailing list cvs@cocoon.apache.org Received: (qmail 12712 invoked by uid 99); 18 Nov 2004 16:25:36 -0000 X-ASF-Spam-Status: No, hits=-10.0 required=10.0 tests=ALL_TRUSTED,CLICK_BELOW,NO_REAL_NAME X-Spam-Check-By: apache.org Received: from [209.237.227.194] (HELO minotaur.apache.org) (209.237.227.194) by apache.org (qpsmtpd/0.28) with SMTP; Thu, 18 Nov 2004 08:25:31 -0800 Received: (qmail 64458 invoked by uid 65534); 18 Nov 2004 16:25:29 -0000 Date: 18 Nov 2004 16:25:29 -0000 Message-ID: <20041118162529.64453.qmail@minotaur.apache.org> From: jeremy@apache.org To: cvs@cocoon.apache.org Subject: svn commit: r76248 - in cocoon/trunk/src/blocks/querybean: . conf java java/org java/org/apache java/org/apache/cocoon java/org/apache/cocoon/bean java/org/apache/cocoon/bean/query samples samples/flow samples/forms samples/i18n samples/screens samples/stylesheets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 X-Virus-Checked: Checked X-Spam-Rating: minotaur-2.apache.org 1.6.2 0/1000/N Author: jeremy Date: Thu Nov 18 08:25:28 2004 New Revision: 76248 Added: cocoon/trunk/src/blocks/querybean/ cocoon/trunk/src/blocks/querybean/conf/ cocoon/trunk/src/blocks/querybean/conf/querybean.xsamples cocoon/trunk/src/blocks/querybean/java/ cocoon/trunk/src/blocks/querybean/java/org/ cocoon/trunk/src/blocks/querybean/java/org/apache/ cocoon/trunk/src/blocks/querybean/java/org/apache/cocoon/ cocoon/trunk/src/blocks/querybean/java/org/apache/cocoon/bean/ cocoon/trunk/src/blocks/querybean/java/org/apache/cocoon/bean/query/ cocoon/trunk/src/blocks/querybean/java/org/apache/cocoon/bean/query/ContextAccess.java cocoon/trunk/src/blocks/querybean/java/org/apache/cocoon/bean/query/SimpleLuceneCriterion.java cocoon/trunk/src/blocks/querybean/java/org/apache/cocoon/bean/query/SimpleLuceneCriterionBean.java cocoon/trunk/src/blocks/querybean/java/org/apache/cocoon/bean/query/SimpleLuceneQuery.java cocoon/trunk/src/blocks/querybean/java/org/apache/cocoon/bean/query/SimpleLuceneQueryBean.java cocoon/trunk/src/blocks/querybean/samples/ cocoon/trunk/src/blocks/querybean/samples/flow/ cocoon/trunk/src/blocks/querybean/samples/flow/QueryFavourites.js cocoon/trunk/src/blocks/querybean/samples/flow/QueryHistory.js cocoon/trunk/src/blocks/querybean/samples/flow/QuerySearcher.js cocoon/trunk/src/blocks/querybean/samples/flow/indexer.js cocoon/trunk/src/blocks/querybean/samples/flow/pager.js cocoon/trunk/src/blocks/querybean/samples/flow/query.js cocoon/trunk/src/blocks/querybean/samples/forms/ cocoon/trunk/src/blocks/querybean/samples/forms/advanced-binding.xml cocoon/trunk/src/blocks/querybean/samples/forms/advanced-fields.xml cocoon/trunk/src/blocks/querybean/samples/forms/advanced-model.xml cocoon/trunk/src/blocks/querybean/samples/forms/advanced-template.xml cocoon/trunk/src/blocks/querybean/samples/forms/simple-binding.xml cocoon/trunk/src/blocks/querybean/samples/forms/simple-fields.xml cocoon/trunk/src/blocks/querybean/samples/forms/simple-model.xml cocoon/trunk/src/blocks/querybean/samples/forms/simple-template.xml cocoon/trunk/src/blocks/querybean/samples/i18n/ cocoon/trunk/src/blocks/querybean/samples/i18n/messages_en.xml cocoon/trunk/src/blocks/querybean/samples/screens/ cocoon/trunk/src/blocks/querybean/samples/screens/cancelled.xml cocoon/trunk/src/blocks/querybean/samples/screens/error.xml cocoon/trunk/src/blocks/querybean/samples/screens/history.xml cocoon/trunk/src/blocks/querybean/samples/screens/index.xml cocoon/trunk/src/blocks/querybean/samples/screens/lucene-indexer.xml cocoon/trunk/src/blocks/querybean/samples/screens/results.xml cocoon/trunk/src/blocks/querybean/samples/sitemap.xmap cocoon/trunk/src/blocks/querybean/samples/stylesheets/ cocoon/trunk/src/blocks/querybean/samples/stylesheets/content2lucene.xsl cocoon/trunk/src/blocks/querybean/samples/stylesheets/lucene2simple-page.xsl Log: adding querybean block Added: cocoon/trunk/src/blocks/querybean/conf/querybean.xsamples ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/querybean/conf/querybean.xsamples Thu Nov 18 08:25:28 2004 @@ -0,0 +1,25 @@ + + + + + + + + Examples showing the use of Apache Lucene with CForms to search. + + + Added: cocoon/trunk/src/blocks/querybean/java/org/apache/cocoon/bean/query/ContextAccess.java ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/querybean/java/org/apache/cocoon/bean/query/ContextAccess.java Thu Nov 18 08:25:28 2004 @@ -0,0 +1,49 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.cocoon.bean.query; + +import org.apache.avalon.framework.context.Context; +import org.apache.avalon.framework.context.Contextualizable; + + +/** + * A component to help you get the Avalon Context. + * Probably only a temporary solution to getting this from within a FlowScript. + * cocoon.createObject (Packages.org.apache.cocoon.bean.query.ContextAccess); + * + * @version CVS $Id: ContextAccess.java 30941 2004-07-29 19:56:58Z vgritsenko $ + */ + +public class ContextAccess implements Contextualizable { + + private Context avalonContext; + + /* (non-Javadoc) + * @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context) + */ + public void contextualize(Context avalonContext) { + this.avalonContext = avalonContext; + } + + /** + * Return the Avalon Context + * @return The context object + */ + public Context getAvalonContext() { + return this.avalonContext; + } +} Added: cocoon/trunk/src/blocks/querybean/java/org/apache/cocoon/bean/query/SimpleLuceneCriterion.java ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/querybean/java/org/apache/cocoon/bean/query/SimpleLuceneCriterion.java Thu Nov 18 08:25:28 2004 @@ -0,0 +1,104 @@ +/* + Copyright 1999-2004 The Apache Software Foundation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package org.apache.cocoon.bean.query; + +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.search.Query; + + + +/** + * The interface of a criterion bean. + *

+ * This component defines an interface for searching. + * The idea is to abstract the process of searching into a Bean to be manipulated by CForms. + *

+ * + * @version CVS $Id: SimpleLuceneCriterion.java,v 1.1 2004/10/22 12:14:22 jeremy Exp $ + */ +public interface SimpleLuceneCriterion { + + /** + * The ANY_FIELD name of this bean. + *

+ * The value representing a query on any field in the index. + * ie. any + *

+ */ + public static final String ANY_FIELD = "any"; + + /** + * The ANY_MATCH name of this bean. + *

+ * The value representing a match on any of the terms in this criterion. + * ie. any + *

+ */ + public static final String ANY_MATCH = "any"; + + /** + * The ALL_MATCH name of this bean. + *

+ * The value representing a match on all of the terms in this criterion. + * ie. all + *

+ */ + public static final String ALL_MATCH = "all"; + + /** + * The LIKE_MATCH name of this bean. + *

+ * The value representing a fuzzy match on any of the terms in this criterion. + * ie. like + *

+ */ + public static final String LIKE_MATCH = "like"; + + /** + * The NOT_MATCH name of this bean. + *

+ * The value representing a prohibition on any of the terms in this criterion. + * ie. like + *

+ */ + public static final String NOT_MATCH = "not"; + + /** + * The PHRASE_MATCH name of this bean. + *

+ * The value representing a phrase match using all of the terms in this criterion. + * ie. like + *

+ */ + public static final String PHRASE_MATCH = "phrase"; + + /** + * Gets the org.apache.lucene.search.Query from the Criterion + *

+ * The analyzer specifies which org.apache.lucene.analysis.Analyzer to use for this search + *

+ * + * @param analyzer The org.apache.lucene.analysis.Analyzer to use to extract the Terms from this Criterion + */ + public Query getQuery (Analyzer analyzer); + + /** + * Gets the prohibited status from the Criterion + */ + public boolean isProhibited (); + +} Added: cocoon/trunk/src/blocks/querybean/java/org/apache/cocoon/bean/query/SimpleLuceneCriterionBean.java ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/querybean/java/org/apache/cocoon/bean/query/SimpleLuceneCriterionBean.java Thu Nov 18 08:25:28 2004 @@ -0,0 +1,266 @@ +/* + Copyright 1999-2004 The Apache Software Foundation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package org.apache.cocoon.bean.query; + +import java.io.IOException; +import java.io.StringReader; +import java.util.Vector; +import org.apache.cocoon.components.search.LuceneXMLIndexer; +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.analysis.Token; +import org.apache.lucene.analysis.TokenStream; +import org.apache.lucene.index.Term; +import org.apache.lucene.search.BooleanQuery; +import org.apache.lucene.search.FuzzyQuery; +import org.apache.lucene.search.PhraseQuery; +import org.apache.lucene.search.Query; +import org.apache.lucene.search.TermQuery; + + +/** + * The criterion bean. + *

+ * This object defines a Bean for holding a query criterion.
+ * The idea is to abstract the process of searching into a Bean to be manipulated by CForms.
+ * This Bean is designed to be persistable. + *

+ * + * @version CVS $Id: SimpleLuceneCriterionBean.java,v 1.1 2004/10/22 12:14:22 jeremy Exp $ + */ +public class SimpleLuceneCriterionBean implements SimpleLuceneCriterion, Cloneable { + + /** + * The Bean's ID. + */ + private Long mId; + + /** + * The Bean's index field to seach in. + */ + private String mField; + + /** + * The Bean's match value. + */ + private String mMatch; + + /** + * The Bean's search term. + */ + private String mTerm; + + /** + * Default constructor. + */ + public SimpleLuceneCriterionBean() { + } + + + /** + * Utility constructor. + * + * @param match the kind of match to use + * @param field the field to search + * @param term the terms to search for + */ + public SimpleLuceneCriterionBean(String field, String match, String term) { + mField = field; + mMatch = match; + mTerm = term; + } + + public Object clone() throws CloneNotSupportedException { + SimpleLuceneCriterionBean criterion = (SimpleLuceneCriterionBean)super.clone(); + return criterion; + } + + /** + * Gets the org.apache.lucene.search.Query from the Criterion + *

+ * The analyzer specifies which org.apache.lucene.analysis.Analyzer to use for this search. + *

+ * + * @param analyzer The org.apache.lucene.analysis.Analyzer to use to extract the Terms from this Criterion + */ + public Query getQuery (Analyzer analyzer) { + String field = mField; + Query query = null; + if (ANY_FIELD.equals (mField)) field = LuceneXMLIndexer.BODY_FIELD; + // extract Terms from the query string + TokenStream tokens = analyzer.tokenStream (field, new StringReader (mTerm)); + Vector words = new Vector (); + Token token; + while (true) { + try { + token = tokens.next (); + } catch (IOException e) { + token = null; + } + if (token == null) break; + words.addElement (token.termText ()); + } + try { + tokens.close (); + } catch (IOException e) {} // ignore + + // assemble the different matches + + if (ANY_MATCH.equals (mMatch)) { + if (words.size () > 1) { + query = new BooleanQuery (); + for (int i = 0; i < words.size (); i++) { + ((BooleanQuery)query).add (new TermQuery (new Term (field, (String)words.elementAt(i))), false, false); + } + } else if (words.size () == 1) { + query = new TermQuery (new Term (field, (String)words.elementAt(0))); + } + } + + if (ALL_MATCH.equals (mMatch)) { + if (words.size () > 1) { + query = new BooleanQuery (); + for (int i = 0; i < words.size (); i++) { + ((BooleanQuery)query).add (new TermQuery (new Term (field, (String)words.elementAt(i))), true, false); + } + } else if (words.size () == 1) { + query = new TermQuery (new Term (field, (String)words.elementAt(0))); + } + } + + if (NOT_MATCH.equals (mMatch)) { + if (words.size () > 1) { + query = new BooleanQuery (); + for (int i = 0; i < words.size (); i++) { + ((BooleanQuery)query).add (new TermQuery (new Term (field, (String)words.elementAt(i))), true, true); + } + } else if (words.size () == 1) { + query = new TermQuery (new Term (field, (String)words.elementAt(0))); + } + } + + if (LIKE_MATCH.equals (mMatch)) { + if (words.size () > 1) { + query = new BooleanQuery (); + for (int i = 0; i < words.size (); i++) { + ((BooleanQuery)query).add (new FuzzyQuery (new Term (field, (String)words.elementAt(i))), false, false); + } + } else if (words.size () == 1) { + query = new FuzzyQuery (new Term (field, (String)words.elementAt(0))); + } + } + + if (PHRASE_MATCH.equals (mMatch)) { + if (words.size () > 1) { + query = new PhraseQuery (); + ((PhraseQuery)query).setSlop (0); + for (int i = 0; i < words.size (); i++) { + ((PhraseQuery)query).add (new Term (field, (String)words.elementAt(i))); + } + } else if (words.size () == 1) { + query = new TermQuery (new Term (field, (String)words.elementAt(0))); + } + } + return query; + } + + /** + * Gets the prohibited status from the Criterion + */ + public boolean isProhibited () { + if (NOT_MATCH.equals (mMatch)) return true; + return false; + } + + + // Bean + + /** + * Gets the Bean's ID + * + * @return the Long ID of the Bean. + */ + public Long getId() { + return mId; + } + + /** + * Sets the Bean's ID + * + * @param id the Long ID of the Bean. + */ + public void setId(Long id) { + mId = id; + } + + /** + * Gets the Bean's field + * + * @return the String field of the Bean. + */ + public String getField() { + return mField; + } + + /** + * Sets the Bean's field.
+ * ie. which field would you like this Criterion to search in. + * + * @param field the String field of the Bean. + */ + public void setField(String field) { + mField = field; + } + + /** + * Gets the Bean's match + * + * @return the String match of the Bean. + */ + public String getMatch() { + return mMatch; + } + + /** + * Sets the Bean's match.
+ * ie. what kind of match do you want performed by this Criterion. + * + * @param match the String match of the Bean. + */ + public void setMatch(String match) { + mMatch = match; + } + + /** + * Gets the Bean's term + * + * @return the String term of the Bean. + */ + public String getTerm() { + return mTerm; + } + + /** + * Sets the Bean's term.
+ * ie. the string of search terms for this Criterion. + * + * @param term the String term of the Bean. + */ + public void setTerm(String term) { + mTerm = term; + } + +} Added: cocoon/trunk/src/blocks/querybean/java/org/apache/cocoon/bean/query/SimpleLuceneQuery.java ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/querybean/java/org/apache/cocoon/bean/query/SimpleLuceneQuery.java Thu Nov 18 08:25:28 2004 @@ -0,0 +1,67 @@ +/* + Copyright 1999-2004 The Apache Software Foundation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package org.apache.cocoon.bean.query; + +import java.io.IOException; +import java.util.List; +import org.apache.cocoon.components.search.LuceneCocoonSearcher; +import org.apache.cocoon.ProcessingException; + +/** + * The interface of a query bean. + *

+ * This component defines an interface for searching. + * The idea is to abstract the process of searching into a Bean to be manipulated by CForms. + *

+ * + * @version CVS $Id: SimpleLuceneQuery.java,v 1.1 2004/10/22 12:14:22 jeremy Exp $ + */ +public interface SimpleLuceneQuery { + + /** + * The AND_BOOL name of this bean. + *

+ * The value representing a Boolean AND operation. + * ie. and + *

+ */ + public static final String AND_BOOL = "and"; + + /** + * The OR_BOOL name of this bean. + *

+ * The value representing a Boolean OR operation. + * ie. or + *

+ */ + public static final String OR_BOOL = "or"; + + /** + * Gets the Bean to perform it's query + *

+ * The searcher specifies which LuceneCocoonSearcher to use for this search + * It needs to have been initialised properly before use + *

+ * + * @param searcher The LuceneCocoonSearcher to use for this search + * @return a List of Maps, each representing a Hit. + * @exception ProcessingException thrown by the searcher + * @exception IOException thrown when the searcher's directory cannot be found + */ + public List search (LuceneCocoonSearcher searcher) throws IOException, ProcessingException; + +} Added: cocoon/trunk/src/blocks/querybean/java/org/apache/cocoon/bean/query/SimpleLuceneQueryBean.java ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/querybean/java/org/apache/cocoon/bean/query/SimpleLuceneQueryBean.java Thu Nov 18 08:25:28 2004 @@ -0,0 +1,432 @@ +/* + Copyright 1999-2004 The Apache Software Foundation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package org.apache.cocoon.bean.query; + +import java.io.IOException; +import java.util.Iterator; +import java.util.List; +import java.util.Date; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Enumeration; + +import org.apache.lucene.document.Document; +import org.apache.lucene.document.Field; +import org.apache.lucene.search.Hits; +import org.apache.lucene.search.Query; +import org.apache.lucene.search.BooleanQuery; +import org.apache.cocoon.components.search.LuceneCocoonSearcher; +import org.apache.cocoon.ProcessingException; + + +/** + * The query bean. + *

+ * This object defines a Bean for searching.
+ * The idea is to abstract the process of searching into a Bean to be manipulated by CForms.
+ * This Bean is designed to be persistable. + *

+ * + * @version CVS $Id: SimpleLuceneQueryBean.java,v 1.1 2004/10/22 12:14:22 jeremy Exp $ + */ +public class SimpleLuceneQueryBean implements SimpleLuceneQuery, Cloneable { + + /** + * The DEFAULT_PAGE_SIZE of this bean. + * ie. 20 + */ + public static Long DEFAULT_PAGE_SIZE = new Long (20); + + /** + * The DEFAULT_PAGE of this bean. + * ie. 0 + */ + public static Long DEFAULT_PAGE = new Long (0); + + /** + * The SCORE_FIELD of this bean. + * This is the key of the Lucene Score as output by this Bean in each hit. + * ie. _lucene-score_ + */ + public static String SCORE_FIELD = "_lucene-score_"; + + /** + * The INDEX_FIELD of this bean. + * This is the key of the hit index as output by this Bean in each hit. + * ie. _lucene-index_ + */ + public static String INDEX_FIELD = "_lucene-index_"; + + /** + * The date this Query was created. + */ + private Date mDate; + + /** + * The Bean's list of Criteria. + */ + private List mCriteria; + + /** + * The Bean's ID. + */ + private Long mId; + + /** + * The Bean's current page. + */ + private Long mPage; + + /** + * The Bean's page isze. + */ + private Long mSize; + + /** + * The Bean's hit count. + */ + private Long mTotal; + + /** + * The Bean's query boolean. + */ + private String mBool; + + /** + * The Bean's query name. + */ + private String mName; + + /** + * The Bean's query type. + */ + private String mType; + + /** + * The Bean's owner. + */ + private String mUser; + + /** + * Default constructor. + */ + public SimpleLuceneQueryBean() { + } + + /** + * Utility constructor. + * + * @param type the type of this query + * @param bool the kind of boolean opperation to apply to each of it's Criteria + * @param match the kind of match to use for the generated Criterion + * @param field the field to search for the generated Criterion + * @param query the terms to search for the generated Criterion + */ + public SimpleLuceneQueryBean(String type, String bool, String match, String field, String query) { + mName = "My Query"; + mType = type; + mBool = bool; + mSize = DEFAULT_PAGE_SIZE; + mPage = DEFAULT_PAGE; + mTotal = null; + mUser = null; + mId = null; + this.addCriterion (new SimpleLuceneCriterionBean (field, match, query)); + } + + public Object clone() throws CloneNotSupportedException { + SimpleLuceneQueryBean query = (SimpleLuceneQueryBean)super.clone(); + query.setCriteria(new ArrayList(mCriteria.size())); + Iterator i = this.getCriteria().iterator (); + while (i.hasNext()) query.addCriterion((SimpleLuceneCriterionBean)((SimpleLuceneCriterionBean)i.next()).clone ()); + return query; + } + + /** + * Gets the Bean to perform it's query + *

+ * The searcher specifies which LuceneCocoonSearcher to use for this search.
+ * It needs to have been initialised properly before use.
+ * Each Map in the List returned by this method contains: + *

    + *
  • Each stored field from the Index
  • + *
  • SCORE_FIELD the Lucene score
  • + *
  • INDEX_FIELD the index of the hit
  • + *
+ *

+ * + * @param searcher The LuceneCocoonSearcher to use for this search + * @return a List of Maps, each representing a Hit. + * @exception ProcessingException thrown by the searcher + * @exception IOException thrown when the searcher's directory cannot be found + */ + public List search (LuceneCocoonSearcher searcher) throws IOException, ProcessingException { + BooleanQuery query = new BooleanQuery (); + Iterator criteria = mCriteria.iterator (); + boolean required = false; + if (AND_BOOL.equals (mBool)) required = true; + while (criteria.hasNext ()) { + SimpleLuceneCriterion criterion = (SimpleLuceneCriterion)criteria.next (); + Query subquery = criterion.getQuery (searcher.getAnalyzer ()); + query.add (subquery, required, criterion.isProhibited ()); + } + Hits hits = searcher.search (query); + mTotal = new Long (hits.length ()); + mDate = new Date (); + return page (hits); + } + + /** + * Outputs part of a Hit List according to the Bean's paging properties. + * + * @param hits The Lucene Hits you want to page + * @return a List of Maps, each representing a Hit. + * @exception IOException thrown when the searcher's directory cannot be found + */ + private List page (Hits hits) throws java.io.IOException { + ArrayList results = new ArrayList (); + int start = getPage().intValue () * getSize().intValue (); + if (start > mTotal.intValue ()) start = mTotal.intValue (); + int end = start + getSize().intValue (); + if (end > mTotal.intValue ()) end = mTotal.intValue (); + for (int i = start; i < end; i++) { + HashMap hit = new HashMap (); + hit.put (SCORE_FIELD, new Float (hits.score (i))); + hit.put (INDEX_FIELD, new Long (i)); + Document doc = hits.doc (i); + for (Enumeration e = doc.fields (); e.hasMoreElements (); ) { + Field field = (Field)e.nextElement (); + if (field.name ().equals (SCORE_FIELD)) continue; + if (field.name ().equals (INDEX_FIELD)) continue; + hit.put (field.name (), field.stringValue ()); + } + results.add (hit); + } + return (results); + } + + /** + * Gets the Bean's ID. + * + * @return the Long ID of the Bean. + */ + public Long getId() { + return mId; + } + + /** + * Sets the Bean's ID. + * + * @param id the Long ID of the Bean. + */ + public void setId(Long id) { + mId = id; + } + + /** + * Gets the Bean's name. + * + * @return the String name of the Bean. + */ + public String getName() { + return mName; + } + + /** + * Sets the Bean's Name. + * + * @param name the String name of the Bean. + */ + public void setName(String name) { + mName = name; + } + + /** + * Gets the Bean's type. + * + * @return the String type of the Bean. + */ + public String getType() { + return mType; + } + + /** + * Sets the Bean's type. + * + * @param type the String type of the Bean. + */ + public void setType(String type) { + mType = type; + } + + /** + * Gets the Bean's boolean operator. + * + * @return the String boolean of the Bean. + */ + public String getBool() { + return mBool; + } + + /** + * Sets the Bean's boolean operator. + * ie. which kind of boolean operation do you want performed on each Criterion. + * + * @param bool the String boolean of the Bean. + */ + public void setBool(String bool) { + mBool = bool; + } + + /** + * Gets the Bean's owner. + * + * @return the String owner of the Bean. + */ + public String getUser() { + return mUser; + } + + /** + * Sets the Bean's owner. + * + * @param user the String owner of the Bean. + */ + public void setUser(String user) { + mUser = user; + } + + /** + * Gets the Bean's page size + * + * @return the Long page size of the Bean. + */ + public Long getSize() { + if (mSize == null) { + return DEFAULT_PAGE_SIZE; + } else { + return mSize; + } + } + + /** + * Sets the Bean's page size. + * ie. how many hits do you want this Bean to show on in page. + * + * @param size the Long page size of the Bean. + */ + public void setSize(Long size) { + mSize = size; + } + + /** + * Gets the Bean's page index + * + * @return the Long page index of the Bean. + */ + public Long getPage() { + if (mPage == null) { + return DEFAULT_PAGE; + } else { + return mPage; + } + } + + /** + * Sets the Bean's page index. + * ie. which page do you want this Bean to show. + * + * @param page the Long page index of the Bean. + */ + public void setPage(Long page) { + mPage = page; + } + + /** + * Gets the Bean's hit count. + * + * @return the Long hit count of the Bean. + */ + public Long getTotal() { + return mTotal; + } + + /** + * Sets the Bean's hit count. + * + * @param total the Long hit count of the Bean. + */ + public void setTotal(Long total) { + mTotal = total; + } + + /** + * Gets the Bean's inception date. + * + * @return the Date of the Bean. + */ + public Date getDate() { + return mDate; + } + + /** + * Sets the Bean's inception date. + * + * @param date the Date inception date of the Bean. + */ + public void setDate(Date date) { + mDate = date; + } + + /** + * Gets the Bean's criteria. + * + * @return the List of Bean Query criteria. + */ + public List getCriteria() { + return mCriteria; + } + + /** + * Sets the Bean's criteria. + * + * @param criteria the List of Bean Query criteria. + */ + public void setCriteria(List criteria) { + mCriteria = criteria; + } + + /** + * Adds a Criterion the Bean. + * + * @param criterion the SimpleLuceneCriterionBean to add to the Bean. + */ + public void addCriterion(SimpleLuceneCriterionBean criterion) { + if (mCriteria == null) mCriteria = new ArrayList (); + mCriteria.add (criterion); + } + + /** + * Removes a Criterion from the Bean. + * + * @param criterion the SimpleLuceneCriterionBean to remove from the Bean. + */ + public void removeCriterion(SimpleLuceneCriterionBean criterion) { + if (mCriteria != null) mCriteria.remove (criterion); + } + +} Added: cocoon/trunk/src/blocks/querybean/samples/flow/QueryFavourites.js ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/querybean/samples/flow/QueryFavourites.js Thu Nov 18 08:25:28 2004 @@ -0,0 +1,49 @@ +/* + Copyright 1999-2004 The Apache Software Foundation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + + +// QueryFavourites constructor +function QueryFavourites(user) { + this._user = user; + // to be implemented using Apache OJB +} + +// add a Query to the QueryFavourites +QueryFavourites.prototype.add = function(query) { + // to be implemented using Apache OJB +} + +// remove a Query from the QueryFavourites +QueryFavourites.prototype.remove = function(id) { + // to be implemented using Apache OJB +} + +// get a Query from the QueryFavourites using it's ID +QueryFavourites.prototype.get = function(id) { + // to be implemented using Apache OJB + throw("error.no.favourite"); +} + +// get a list of Queries from the QueryFavourites +QueryFavourites.prototype.list = function() { + // to be implemented using Apache OJB + return new java.util.ArrayList(1); +} + +// close the QueryFavourites +QueryFavourites.prototype.close = function() { + // to be implemented using Apache OJB +} Added: cocoon/trunk/src/blocks/querybean/samples/flow/QueryHistory.js ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/querybean/samples/flow/QueryHistory.js Thu Nov 18 08:25:28 2004 @@ -0,0 +1,88 @@ +/* + Copyright 1999-2004 The Apache Software Foundation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +importClass(Packages.java.util.ArrayList); +importClass(Packages.java.lang.Long); + + +// QueryHistory Object Constructor +function QueryHistory(attr) { + try { + this._history = cocoon.session.getAttribute(attr); + if (this._history == null) { + this._history = new ArrayList(); + cocoon.session.setAttribute(attr, this._history); + } + } catch (error) { + cocoon.log.error(error); + } +} + +// add a Query to the QueryHistory +QueryHistory.prototype.add = function(item) { + this._history.add(item); +} + +// empty the QueryHistory +QueryHistory.prototype.clear = function() { + this._history.clear(); +} + +// remove a Query from the QueryHistory +QueryHistory.prototype.remove = function(item) { + this._history.remove(item); +} + +// return a list of the Queries in the QueryHistory, in reverse order +QueryHistory.prototype.list = function() { + var count = this._history.size(); + var history = new ArrayList(count); + var index = 0; + for (var position = 0; position < count; position++) { + index = count - position - 1; // reverse the order + history.add(position, {id: new Long(index), query: this._history.get(index)}); + } + return history; +} + +// get a Query from the QueryHistory, using it's ID, always returns a copy +QueryHistory.prototype.get = function(id) { + var clone, item; + try { + item = this._history.get(parseInt(id)); + } catch (e1) { + cocoon.log.error(e1); + throw("error.no.history"); + } + try { + clone = item.clone(); + } catch (e2) { + cocoon.log.error(e2); + throw("items stored in history need to be Cloneable"); + } + return clone; +} + +// move a Query to the top of the QueryHistory list +QueryHistory.prototype.promote = function(query) { + this._history.remove(query); + this._history.add(query); +} + +// get the size of the QueryHistory list +QueryHistory.prototype.size = function() { + return this._history.size(); +} Added: cocoon/trunk/src/blocks/querybean/samples/flow/QuerySearcher.js ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/querybean/samples/flow/QuerySearcher.js Thu Nov 18 08:25:28 2004 @@ -0,0 +1,121 @@ +/* + Copyright 1999-2004 The Apache Software Foundation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +importClass(Packages.org.apache.cocoon.components.search.LuceneCocoonSearcher); +importClass(Packages.org.apache.cocoon.components.search.LuceneCocoonHelper); +importClass(Packages.org.apache.cocoon.Constants); +importPackage(Packages.org.apache.cocoon.bean.query); + +cocoon.load("flow/pager.js"); + +// QuerySearcher constructor +function QuerySearcher(directory, analyzer) { + var contextAccess; + this._low = SimpleLuceneQueryBean.DEFAULT_PAGE_SIZE / 2; + this._high = SimpleLuceneQueryBean.DEFAULT_PAGE_SIZE * 5; + try { + contextAccess = cocoon.createObject(ContextAccess); + var index = new java.io.File(directory); + if (!index.isAbsolute()) { + var workDir = contextAccess.getAvalonContext().get(Constants.CONTEXT_WORK_DIR); + index = new java.io.File(workDir, directory); + } + if (!index.exists()) throw ("search.error.noindex"); + this._searcher = cocoon.getComponent(LuceneCocoonSearcher.ROLE); + this._searcher.setDirectory(LuceneCocoonHelper.getDirectory(index, false)); + if (this._searcher.getAnalyzer() == null) { + this._searcher.setAnalyzer(LuceneCocoonHelper.getAnalyzer(analyzer)); + } + } catch (error) { + cocoon.log.error(error); + throw (error); + } finally { + cocoon.disposeObject(contextAccess); + } +} + +// cleanup +QuerySearcher.prototype.close = function() { + cocoon.releaseComponent(this._searcher); +} + +// perform a search using a Query +QuerySearcher.prototype.search = function(query, history) { + if (query != null) { + var results = query.search(this._searcher); + history.add(query); + var historyid = new java.lang.Long(history.size() -1); + var nav = pagerNavigation(query.total, query.page, query.size); + return { results: results, nav: nav, query: query, id: historyid, tip: this.getTip(query) }; + } else { + throw("search.error.nohistory"); + } +} + +// perform a page using a Query +QuerySearcher.prototype.page = function(page, id, history) { + var p; + var query = history.get(id); + if (query != null) { + try { + p = new java.lang.Long(page); + } catch (error) { + p = SimpleLuceneQueryBean.DEFAULT_PAGE; + } + query.setPage(p); + var results = query.search(this._searcher); + //history.promote(query); // this was causing addition to history while paging (why?), did not want this ...... + var historyid = new java.lang.Long(history.size() -1); + var nav = pagerNavigation(query.total, query.page, query.size); + return { results: results, nav: nav, query: query, id: historyid }; + } else { + throw("search.error.nohistory"); + } +} + +// perform a quick search using params +QuerySearcher.prototype.quicksearch = function(type, bool, match, field, value, size, history) { + var s; + if ("".equals(match) || match == undefined) match = SimpleLuceneCriterion.ANY_MATCH; + if ("".equals(field) || field == undefined) field = SimpleLuceneCriterion.ANY_FIELD; + if ("".equals(bool) || bool == undefined) bool = null; + try { + s = new java.lang.Long(size); + } catch (error) { + s = SimpleLuceneQueryBean.DEFAULT_PAGE_SIZE; + } + var query = new SimpleLuceneQueryBean(type, bool, match, field, value); + query.setSize(s); + return this.search(query, history); +} + +// make a new query +QuerySearcher.prototype.newquery = function(type, bool, match, field) { + if ("".equals(match) || match == undefined) match = SimpleLuceneCriterion.ANY_MATCH; + if ("".equals(field) || field == undefined) field = SimpleLuceneCriterion.ANY_FIELD; + if ("".equals(bool) || bool == undefined) bool = SimpleLuceneQueryBean.OR_BOOL; + return new SimpleLuceneQueryBean(type, bool, match, field, ""); +} + + + + +QuerySearcher.prototype.getTip = function(query) { + return null; +} + + + Added: cocoon/trunk/src/blocks/querybean/samples/flow/indexer.js ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/querybean/samples/flow/indexer.js Thu Nov 18 08:25:28 2004 @@ -0,0 +1,118 @@ +/* + Copyright 1999-2004 The Apache Software Foundation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +importClass(Packages.org.apache.excalibur.source.SourceResolver); +importClass(Packages.java.net.URL); +importClass(Packages.java.io.File); +importClass(Packages.java.util.ArrayList); + + + +// flowscripts for indexing content for the Query Bean +// $Id: query.js,v 1.3 2004/10/22 12:14:23 jeremy Exp $ + +function createIndex () { + var cdir = cocoon.parameters["content-directory"] + var rdir = cocoon.parameters["result-directory"]; + var include = cocoon.parameters["include-pattern"]; + var exclude = cocoon.parameters["exclude-pattern"]; + var rsuffix = cocoon.parameters["result-suffix"]; + var files = new ArrayList(); + try { + var inRegExp = "undefined".equals(include) ? new RegExp(".*") : new RegExp(include); + var exRegExp = "undefined".equals(exclude) ? null : new RegExp(exclude); + var base = new File(new URL(resolve(cdir).getURI()).getFile()); + if (base.isDirectory()) { + getFiles(base, files, inRegExp, exRegExp); + } else { + throw("error.invalid.content"); + } + cocoon.sendPage(cocoon.parameters["screen"], + { + directory: cocoon.parameters["lucene-directory"], + analyzer: cocoon.parameters["lucene-analyzer"], + merge: cocoon.parameters["lucene-merge-factor"], + create: cocoon.parameters["lucene-create-index"], + files: files, + converter: new Converter(base, rdir, rsuffix), + content: cocoon.parameters["lucene-content"] + } + ); + } catch (error) { + cocoon.log.error(error); + cocoon.sendPage("screen/error", {message: error}); + } +} + +/** + * Utility function - resolve a URI to a Source + * + */ +function resolve(uri) { + try { + var resolver = cocoon.getComponent(SourceResolver.ROLE); + return resolver.resolveURI(uri); + } catch (error) { + cocoon.log.error("Unable to resolve source", error); + throw (error); + } finally { + cocoon.releaseComponent(resolver); + } +} + +function getFiles(dir, files, inRegExp, exRegExp) { + try { + var theFiles = dir.listFiles(); + for (var i = 0; i < theFiles.length; i++ ) { + var f = theFiles[i]; + if (f.isDirectory()) { + getFiles(f, files, inRegExp, exRegExp); + } else if (f.isFile()) { + if (f.canRead()) { + var apath = f.getAbsolutePath(); + if (inRegExp.test(apath)) { + if (exRegExp == null || !exRegExp.test(apath)) { + files.add(apath); + } + } + } + } + } + } catch (error) { + cocoon.log.error(error); + } +} + +function Converter (base, rdir, rsuffix) { + this._base = base.getAbsolutePath(); + this._rdir = rdir; + this._rsuffix = rsuffix; + if ("undefined".equals(this._rdir)) this._rdir = ""; + if ("undefined".equals(this._rsuffix)) this._rsuffix = ""; +} + +Converter.prototype.convert = function(file) { + var path = file.toString(); + // remove the absolute base path + path = path.substring(this._base.length() +1); + // replace the suffix, if a replacement was provided + if (!"".equals(this._rsuffix)) path = path.substring(0, path.lastIndexOf(".")) + this._rsuffix; + // prefix with the results path + path = this._rdir + path; + // replace windows path delimiters with http ones + path = path.replace( '\\', '/' ); + return path; +} \ No newline at end of file Added: cocoon/trunk/src/blocks/querybean/samples/flow/pager.js ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/querybean/samples/flow/pager.js Thu Nov 18 08:25:28 2004 @@ -0,0 +1,50 @@ +// flowscripts util for paging navigation +// $Id: pager.js,v 1.4 2004/07/05 14:40:31 savs Exp $ + + + +/* + Utility function to create a 'paging record' for the display of long paged lists of records +*/ + +function pagerNavigation(total, page, size) { + total = parseInt(total); // make sure JS realises they are Numbers, so we can add them without getting string concatenation !!! + page = parseInt(page); + size = parseInt(size); + var pages = Math.ceil(total/size); + var index = new java.util.ArrayList(); + var off = 5; // half the max # of slots to see + var start = 0; + var end = pages; + if (pages > (off*2)) { + if (page < off) { // if we are close to the left + start = 0; + end = start + (off*2); + } else if (page > (pages - off)) { // if we are close to the right + start = pages - (off*2); + end = pages; + } else { // we are somewhere in the middle + start = page - off; + end = page + off; + } + } + for (var i = start; i < end; i++) index.add(new java.lang.Integer(i)); + var firstIndex = 0; + var lastIndex = 0; + try { + firstIndex = index.get(0); + lastIndex = index.get(index.size()-1); + } catch (e) {} + var record = { + total: new java.lang.Integer( total), + next: total > ((page * size) + size) ? new java.lang.Integer(page + 1) : null, + prev: page > 0 ? new java.lang.Integer(page - 1) : null, + size: new java.lang.Integer(size), + page: new java.lang.Integer(page), + pages: new java.lang.Integer(pages), + index: index, + firstIndex: firstIndex, + lastIndex: lastIndex + }; + return record; +} Added: cocoon/trunk/src/blocks/querybean/samples/flow/query.js ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/querybean/samples/flow/query.js Thu Nov 18 08:25:28 2004 @@ -0,0 +1,146 @@ +/* + Copyright 1999-2004 The Apache Software Foundation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +// flowscripts for using the Query Bean +// $Id: query.js,v 1.3 2004/10/22 12:14:23 jeremy Exp $ + +cocoon.load("resource://org/apache/cocoon/forms/flow/javascript/Form.js"); +cocoon.load("flow/QuerySearcher.js"); +cocoon.load("flow/QueryHistory.js"); +cocoon.load("flow/QueryFavourites.js"); + +// display the User's Search History +function showHistory() { + var history = new QueryHistory(cocoon.parameters["history"]); + cocoon.sendPage(cocoon.parameters["screen"], {queries: history.list()}); +} + +// erase the User's Search History +function clearHistory() { + var history = new QueryHistory(cocoon.parameters["history"]); + history.clear(); + cocoon.sendPage(cocoon.parameters["screen"]); +} + +// display the User's Favourite Searches +/*function showFavourites() { + var favourites = null; + try { + favourites = new QueryFavourites(cocoon.parameters["user-id"]); + cocoon.sendPage(cocoon.parameters["screen"], {queries: favourites.list()}); + } catch (error) { + cocoon.log.error(error); + cocoon.sendPage("screen/error", {message: error}); + } finally { + if (favourites != null) favourites.close(); + } +}*/ + + +// add a history item to the User's Favourite Searches +/*function addFavourite() { + var history = new QueryHistory(cocoon.parameters["history"]); + var favourites = null; + try { + favourites = new QueryFavourites(cocoon.parameters["user-id"]); + var query = history.get(cocoon.parameters["hid"]); + if (query != null) { + favourites.add(query); + } + cocoon.sendPage(cocoon.parameters["screen"], {queries: favourites.list()}); + } catch (error) { + cocoon.log.error(error); + cocoon.sendPage("screen/error", {message: error}); + } finally { + if (favourites != null) favourites.close(); + } +}*/ + +// add an item from the User's Favourite Searches, using it's ID +/*function removeFavourite() { + var favourites = null; + try { + favourites = new QueryFavourites(cocoon.parameters["user-id"]); + favourites.remove(cocoon.parameters["fid"]); + cocoon.sendPage(cocoon.parameters["screen"], {queries: favourites.list()}); + } catch (error) { + cocoon.log.error(error); + cocoon.sendPage("screen/error", {message: error}); + } finally { + if (favourites != null) favourites.close(); + } +}*/ + +// perform searches +function doSearch() { + var screen = cocoon.parameters["screen"]; + var searcher = null; + var favourites = null; + var history = new QueryHistory(cocoon.parameters["history"]); + try { + searcher = new QuerySearcher(cocoon.parameters["lucene-directory"], cocoon.parameters["lucene-analyzer"]); + favourites = new QueryFavourites(); + var result = null; + if (!"".equals(cocoon.parameters["page"])) { // paging an existing Query + result = searcher.page(cocoon.parameters["page"], cocoon.parameters["hid"], history); + } else if (!"".equals(cocoon.parameters["query"])) { // running a quick Query + result = searcher.quicksearch(cocoon.parameters["type"], cocoon.parameters["bool"], cocoon.parameters["match"], cocoon.parameters["field"], cocoon.parameters["query"], cocoon.parameters["size"], history); + } else if (!"".equals(cocoon.parameters["fid"])) { // running a favourite Query + result = searcher.search(favourites.get(cocoon.parameters["fid"]), history); + } else if ("".equals(cocoon.parameters["hid"])) { // making a new Query to edit + var query = searcher.newquery(cocoon.parameters["type"], cocoon.parameters["bool"], cocoon.parameters["match"], cocoon.parameters["field"]); + if (edit(query)) { + result = searcher.search(query, history); + } else { + cocoon.sendPage("screen/cancelled", {message: "cancel.note"}); + return; + } + } else { // editing a Query from history + var query = history.get(cocoon.parameters["hid"]); + if (edit(query)) { + result = searcher.search(query, history); + } else { + cocoon.sendPage("screen/cancelled", {message: "cancel.note"}); + return; + } + } + cocoon.sendPage(screen, {result: result}); + } catch (error) { + cocoon.log.error(error); + cocoon.sendPage("screen/error", {message: error}); + } finally { + if (searcher != null) searcher.close(); + if (favourites != null) favourites.close(); + } +} + + +// allow the user to edit the query +function edit(query) { + var form = new Form(cocoon.parameters["form-definition"]); + form.createBinding(cocoon.parameters["bindingURI"]); + form.load(query); + form.showForm(cocoon.parameters["form"]); + if ("submit".equals(form.submitId)) { + form.save(query); + cocoon.log.debug("form submitted"); + query.id = null; // this is no longer a favourite, now it has been edited + return true; + } else { + cocoon.log.debug("form cancelled"); + return false; + } +} Added: cocoon/trunk/src/blocks/querybean/samples/forms/advanced-binding.xml ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/querybean/samples/forms/advanced-binding.xml Thu Nov 18 08:25:28 2004 @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file Added: cocoon/trunk/src/blocks/querybean/samples/forms/advanced-fields.xml ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/querybean/samples/forms/advanced-fields.xml Thu Nov 18 08:25:28 2004 @@ -0,0 +1,68 @@ + + + + + + + + + field.any.label + + + field.title.label + + + field.question.label + + + field.answer.label + + + field.source.label + + + field.s1@title.label + + + field.s2@title.label + + + field.person@name.label + + + field.p.label + + + field.link.label + + + field.code.label + + + field.abstract.label + + Added: cocoon/trunk/src/blocks/querybean/samples/forms/advanced-model.xml ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/querybean/samples/forms/advanced-model.xml Thu Nov 18 08:25:28 2004 @@ -0,0 +1,153 @@ + + + + + + + + + + + message.label + + + + + + + + query.name.label: + query.name.hint + + + + + + + + + query.bool.label: + query.bool.hint + + + + + search.or.bool + + + search.and.bool + + + + + + paging.size.label: + paging.size.hint + + + + + + + + + + + + paging.page.label: + paging.page.hint + + + + + paging.total.label: + paging.total.hint + + + + + cancel.label + cancel.hint + + + + submit.label + submit.hint + + + + + + + criterion.term.label: + criterion.term.hint + + + + + criterion.field.label: + criterion.field.hint + + + + + + + + + + criterion.match.label: + criterion.match.hint + + + + + search.any.match + + + search.all.match + + + search.like.match + + + search.phrase.match + + + search.not.match + + + + + + criterion.delete.label + criterion.delete.hint + + + + + + + criterion.add.label + criterion.add.hint + + + + \ No newline at end of file Added: cocoon/trunk/src/blocks/querybean/samples/forms/advanced-template.xml ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/querybean/samples/forms/advanced-template.xml Thu Nov 18 08:25:28 2004 @@ -0,0 +1,60 @@ + + + + + + + <i18n:text i18n:catalogue="local">search.page.title</i18n:text> : <i18n:text i18n:catalogue="local">advanced.page.title</i18n:text> + +

advanced.page.note

+ + +

+ + + advanced.query.label + query editor layout + + + + + + + + advanced.criterion.label + + + + + + + + + + + + + required.note + + +
+
+
\ No newline at end of file Added: cocoon/trunk/src/blocks/querybean/samples/forms/simple-binding.xml ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/querybean/samples/forms/simple-binding.xml Thu Nov 18 08:25:28 2004 @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file Added: cocoon/trunk/src/blocks/querybean/samples/forms/simple-fields.xml ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/querybean/samples/forms/simple-fields.xml Thu Nov 18 08:25:28 2004 @@ -0,0 +1,46 @@ + + + + + + + + + + + field.any.label + + + field.title.label + + + field.question.label + + + field.person@name.label + + Added: cocoon/trunk/src/blocks/querybean/samples/forms/simple-model.xml ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/querybean/samples/forms/simple-model.xml Thu Nov 18 08:25:28 2004 @@ -0,0 +1,105 @@ + + + + + + + + + + + message.label + + + + + + + + query.name.label: + query.name.hint + + + + + + + + + + + + + paging.size.label: + paging.size.hint + + + + + + + + + + + + paging.page.label: + paging.page.hint + + + + + paging.total.label: + paging.total.hint + + + + + cancel.label + cancel.hint + + + + submit.label + submit.hint + + + + criterion.term.label: + criterion.term.hint + + + + + criterion.field.label: + criterion.field.hint + + + + + + + + + + criterion.match.label: + criterion.match.hint + + + + + \ No newline at end of file Added: cocoon/trunk/src/blocks/querybean/samples/forms/simple-template.xml ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/querybean/samples/forms/simple-template.xml Thu Nov 18 08:25:28 2004 @@ -0,0 +1,50 @@ + + + + + + + + <i18n:text i18n:catalogue="local">search.page.title</i18n:text> : <i18n:text i18n:catalogue="local">simple.page.title</i18n:text> + + +

simple.page.note

+ + +

+ + + editor layout + + + +
+ + +
+
+
+ required.note + + +
+
+
\ No newline at end of file Added: cocoon/trunk/src/blocks/querybean/samples/i18n/messages_en.xml ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/querybean/samples/i18n/messages_en.xml Thu Nov 18 08:25:28 2004 @@ -0,0 +1,160 @@ + + + + + + + + + Document Abstract + FAQ Answer + Any Document field + Document Code + Document Link + Document Paragraph + Author Name + FAQ Question + Level 1 Section Title + Level 2 Section Title + Sample Source Code + Document Title + + + + document abstract + faq answer + any field + document code + document link + document paragraph + author name + faq question + section 1 title + section 2 title + sample source + document title + + + Criterion + You can edit and save this query for later use. + An advanced query + Query + + cancel this edit + Cancel + + add a new criterion + Add Criterion + delete this criterion + - + which fields to search in + Search Field + the way your search term is matched + Match + the word or words you are searching for + Word or Words + + Time + edit this query + Edit + Hits + No History + Query Bean : History + Queries + Query + re-search this query + Search + Title + Your query history has been cleared. + + the query bean samples home page + Home + + perform complex multi-criteria searches + New Advanced Query + perform simple single-criteria searches + New Simple Query + + the page to start from + Page + how many hits per page + Hits + how many hits this query gave last time it was used + Results + + the way your criteria match + Search Criteria + + the name this query will have in the history + Query Name + + that match + that match all of + that match some of + + Advanced Query + Edit this Query + Favourites + History + Clear History + New Query + Query Bean + Query + Documents + Simple Query + Documents + + contains all words in + contains any word in + is somthing like + does not contain + contains the phrase + + these criteria + this criterion + next + Number of pages + Page + Hits per page + previous + Rank + Total hits + Score + Title + URI + + you can edit this Query or save it for future use + view and edit your favourite queries + view your search history + create a new query of the same type as this one + + no results from your search, please try again + Enter some words and hit submit. + A simple query + * required + you cancelled your edit + + There was no query + You have no history at the moment + You need to make a Lucene Index first (click here to make one) + The content you wanted indexed did not exist, this sample indexes 'docs/xdocs', please ensure you have built Cocoon's documentation. + + + save changes and search + Submit + + Added: cocoon/trunk/src/blocks/querybean/samples/screens/cancelled.xml ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/querybean/samples/screens/cancelled.xml Thu Nov 18 08:25:28 2004 @@ -0,0 +1,23 @@ + + + + Cancelled + +

#{message}

+
+
Added: cocoon/trunk/src/blocks/querybean/samples/screens/error.xml ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/querybean/samples/screens/error.xml Thu Nov 18 08:25:28 2004 @@ -0,0 +1,27 @@ + + + + + + Error + +

#{message}

+
+

An error has occurred, please try again.

+
+
\ No newline at end of file Added: cocoon/trunk/src/blocks/querybean/samples/screens/history.xml ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/querybean/samples/screens/history.xml Thu Nov 18 08:25:28 2004 @@ -0,0 +1,97 @@ + + + + + + <i18n:text i18n:catalogue="local">history.page.title</i18n:text> + + + +

+ history.queries.title: + +

+ + + + + + + + + + + + + +
history.date.labelhistory.title.labelhistory.query.labelhistory.hits.label
+ + + + + ${item.query.name} + + search.subject.title + + search.${item.query.bool}.bool + + + + + search.criterion.label: + + + search.criteria.label: + + + +
    + +
  • + + search.${crit.field}.field + + + search.${crit.match}.match + + “${crit.value}” +
  • +
    +
+
+ ${item.query.total} + + history.search.label + + history.edit.label +
+
+ +

history.none

+
+
+
+
Added: cocoon/trunk/src/blocks/querybean/samples/screens/index.xml ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/querybean/samples/screens/index.xml Thu Nov 18 08:25:28 2004 @@ -0,0 +1,103 @@ + + + + + Query Bean Samples + +

+ NB. You need to make an index first.
+ If you have not already made an index of the Cocoon Documentation, you may do so here. +

+ +

Search

+

You can perform any of the following search types:

+
    +
  • Quick search: +
    + + +
    +
  • +
  • Simple search: perform simple single-criteria searches.
  • +
  • Advanced search: perform complex multi-criteria searches.
  • +
+ +

Queries

+

You can view, reuse, and re-edit your previous queries:

+
    +
  • History: your search history.
  • +
+ +

What it does.

+

Allows you to assemble complex Lucene Queries without having to use the Lucene Query Language. Keeps a list of the queries you have performed in it's history (for as long as your Session lasts). Allows you to re-use and edit them.

+ +

How does it work?

+

Through a combination of FlowScript (controller), CForms and JXTemplate (view), Beans (model), i18n and the CocoonLuceneSearcher component.

+

FlowScript

+ The FlowScript controls the flow of the application, it instansiates Beans, manages the History, chooses which Forms and Screens to display, controls the CocoonLuceneSearcher. +

CForms

+

Cocoon Forms provideds the infrastructure to manipulate the Beans via HTML Forms. That is to change the Properties of the Beans and add and remove Criteria.

+

JXTemplate

+

+ JXTemplate is used to show the results and the history (List of Query Beans). +

+ The results are in the form of a List of Maps. Each Map represents a search hit. It contains the url, score and rank of the document, plus any Index Fields you arranged to have stored in your Index by Lucene (in this sample, the only stored field is the title). +

+ The history is in the form of a List of Query Beans. +

+

Beans

+

The Beans represent an abstract (and potentially persistable) representation of your Query.

+

i18n

+

i18n is used to hold all of the display strings used by the Application. Form labels and hints, Query descriptions, Screen labels and hints, Error messages etc.

+

CocoonLuceneSearcher

+

This is the Component that does the actual searching. It is provided with the Lucene Directory and a Query by the Query Bean. If you give it a directory parameter that is a single folder name, it uses that folder in the Servlet Engine's Work Directory, if the parameter is an absolute file path, it uses that instead. It uses the default Analyser.

+ +

How to reuse this sample in your own projects?

+

Reuse the existing forms

+

If you are happy with the existing forms, then all that really needs to happen to be able to re-use this sample in your own projects it to set up the menu of Search Fields, so they match your Search Index.

+

When the Lucene Index of Cocoon Documentation that this sample uses is created, tags within the documents are turned into Lucene Index Fields, which can be searched individually. The names of these fields are for example: title, question, source, person@name etc.

+

Cocoon Forms is setup to load these menus (selection-lists) from their own files. The simple search form uses the file forms/simple-fields.xml, while the advanced search form uses the file forms/advanced-fields.xml.

+

Edit these files to match your own Search Index, for example, the item: +


+	field.title.label
+
+]]>
+ makes a menu item using the i18n key field.title.label as the menu text and title as the value, where the value matches one of your Index Fields. +

+ Once your CForms selection-lists are setup, you will want to edit the existing i18n message keys in i18n/messages_en.xml and/or provide new message files in your own language. +

+ The last thing you may choose to do, is to supply some CSS for the screens. The history and results screens supply what is hopefully a rich enough +collection of CSS Classes, have a look at the HTML output to see what there is.

+ +

New Forms

+

If you know CForms, it would be relatively easy to develop your own Forms (Model, Binding and Template). If you follow the existing naming scheme and you choose a new name for your form, it may not even be necessary to edit the Sitemap. +

Depending on how different your Forms are to the supplied ones, it may or may not be necessary to edit the FlowScript. It is quite possible that this will not be required.

+

New Beans

+

+ It is possible to build Lucene Queries that are more complex, or specialised than those produced by these sample Beans. To do so you would have to at least implement your own CriterionBean. You would probably need to rewrite the FlowScript to handle your new Bean. +

It would also be possible to implement different kinds of Queries, like those that used the Hibernate Criterion API.

+

+ There are two Interfaces and two Bean Implementations of those Interfaces in the sample. o.a.c.bean.query.SimpleLuceneQuery and o.a.c.bean.query.SimpleLuceneQueryBean represent a Query, which has a Collection of o.a.c.bean.query.SimpleLuceneCriterion (o.a.c.bean.query.SimpleLuceneCriterionBean) Beans. +

+ The bool property of the QueryBean specifies how the multiple criteria are combined. The field property of the CriterionBean specifies which Index Field to search, the match property specifies how to match that field and the value property, is the string from which Terms are extracted. All the rest is candy. +

+

Persistance

+

Both the Query and Criterion Beans were designed to be Persistable using one of the Object-Relational mapping tools like Hibernate, JDO, ORO etc. (This is why they have the unused id property).

+
+
+ Added: cocoon/trunk/src/blocks/querybean/samples/screens/lucene-indexer.xml ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/querybean/samples/screens/lucene-indexer.xml Thu Nov 18 08:25:28 2004 @@ -0,0 +1,35 @@ + + + + + + + + + ${content}${entry} + + + + \ No newline at end of file Added: cocoon/trunk/src/blocks/querybean/samples/screens/results.xml ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/querybean/samples/screens/results.xml Thu Nov 18 08:25:28 2004 @@ -0,0 +1,130 @@ + + + + + + <i18n:text i18n:catalogue="local">${result.query.type}.page.title</i18n:text>: ${result.query.name} + + +

+ search.subject.title + + search.${result.query.bool}.bool + + + + + search.criterion.label: + + + search.criteria.label: + + + +

    + +
  • + + search.${item.field}.field + + + search.${item.match}.match + + “${item.term}”. +
  • +
    +
+

+ + ${result.tip} + + + + + <i18n:text i18n:catalogue="local">search.section.title</i18n:text> + + + +
+

+ search.pagenumber.label: #{format-number(result/nav/page+1,'#')}. + search.pagecount.label: #{result/nav/pages}. + search.recordcount.label: #{result/nav/total}. + search.pagesize.label: #{result/nav/size}. +

+

+ + + search.previous.label  + + + ... + + + + #{format-number(.+1,'#')} + #{format-number(.+1,'#')} + + + ... + + + search.next.label + + +

+
+
+ + + + + + + + + + + + + + + + + +
search.rank.labelsearch.score.labelsearch.title.label
#{format-number($index +1,'#')}#{format-number($score,'##%')}#{url}#{title}
+
+ + +

search.norecords.note

+
+
+
+
Added: cocoon/trunk/src/blocks/querybean/samples/sitemap.xmap ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/querybean/samples/sitemap.xmap Thu Nov 18 08:25:28 2004 @@ -0,0 +1,249 @@ + + + + + + + + + + + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + _query_bean_history_ + org.apache.lucene.analysis.standard.StandardAnalyzer + + cocoon-docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Added: cocoon/trunk/src/blocks/querybean/samples/stylesheets/content2lucene.xsl ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/querybean/samples/stylesheets/content2lucene.xsl Thu Nov 18 08:25:28 2004 @@ -0,0 +1,41 @@ + + + + + + + <xsl:apply-templates/> + + + + + + <xsl:value-of select="@title"/> + + + + + + + + + + \ No newline at end of file Added: cocoon/trunk/src/blocks/querybean/samples/stylesheets/lucene2simple-page.xsl ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/querybean/samples/stylesheets/lucene2simple-page.xsl Thu Nov 18 08:25:28 2004 @@ -0,0 +1,57 @@ + + + + + + + Lucene Index + +

+ + Welcome + +

+
    +
  • merge-factor -
  • +
  • create -
  • +
  • directory -
  • +
  • analyzer -
  • +
+ + + + +
urlelapsed-time
+
+
+
+ + + + + + + + + + + +
\ No newline at end of file