Jonas Maurus wrote:
>
[snip]
>
> You're welcome. Wait until we have done the other modifications (feedback and
> searching) :-).
>
Hello Jonas,
Thanks for contributing this localization code to the project. I see
you have some other stuff in the pipeline as well which is great!
Would you be interested in sharing your ideas for searching in
jyve/turbine? Unlike localization, I would like to contribute something
here if I can be of help to you, whether a feature spec, a few lines of
code,
or just user-land feedback.
Don't know how far along your team is, but I just had some questions:
1.Did you take Jon *'s suggestion from a while back and think about
using OPaL for this functionality and/or making a more generic search
service as part of Turbine?
2.If it's a jyve specific implementation, are you replacing the
SearchGlobal / SearchResults screens with
something else entirely, or just tweaking what's there?
3.If the latter: conceptually, is parsing a search query string an
action, or part of a screen? Ie, should you put search string parsing
routines into an action module, pass the query string in as a parameter
from SearchGlobal, then access the parsed string from SearchResults with
a data.user.getTemp("search") kinda thing?
4. How do you localize a search? Is it reasonable to force non-english
speakers to use and/or/not within a query?
In the interest of shut-up-already-and-post-code, I spent my lunch hour
today and worked up a little something to help me find out what's
already in there and where it could go. I attached my draft below -
it's a mess and not ready for prime time, so I didn't bother doing a
premature diff (let me know if that would help, though). The objective
was:
1. Do something minimalist to elicit commentary.
2. Work with the existing code before suggesting we throw it out and
start over.
3. Use my admittedly "script kiddie" level abilties to implement a
simple boolean search.
So I tacked on some code to SearchResults.java to support AND and OR
with multiple search terms.
I'd like to get back the ability to search on a long multi word string
without having it be "or"'d, however, so I guess parsing for ""'s to
signify a quoted string is next. Then maybe parse for ![NOT]. Perhaps
same time tommorrow. ;)
Criticism/discussion welcome, or just tell me to go away... ;)
Regards,
~Eric
package org.apache.jyve.screens;
/*
* Copyright (c) 1997-1999 The Java Apache Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the Java Apache
* Project for use in the Apache JServ servlet engine project
* <http://java.apache.org/>."
*
* 4. The names "Apache JServ", "Apache JServ Servlet Engine", "Jyve",
* "Apache Jyve", "Jyve Project", "Apache Jyve Project" and
* "Java Apache Project" must not be used to endorse or promote products
* derived from this software without prior written permission.
*
* 5. Products derived from this software may not be called "Apache JServ"
* nor may "Apache" nor "Apache JServ" appear in their names without
* prior written permission of the Java Apache Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the Java Apache
* Project for use in the Apache JServ servlet engine project
* <http://java.apache.org/>."
*
* THIS SOFTWARE IS PROVIDED BY THE JAVA APACHE PROJECT "AS IS" AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE JAVA APACHE PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Java Apache Group. For more information
* on the Java Apache Project and the Apache JServ Servlet Engine project,
* please see <http://java.apache.org/>.
*
*/
// JDK Stuff
import java.io.*;
import java.sql.*;
import java.util.*;
// Servlet Stuff
import javax.servlet.*;
import javax.servlet.http.*;
// External Stuff
import org.apache.turbine.modules.*;
import org.apache.turbine.util.*;
import org.apache.turbine.util.access.*;
import org.apache.turbine.util.db.*;
import com.workingdogs.village.*;
import org.apache.ecs.*;
import org.apache.ecs.html.*;
// Own Stuff
import org.apache.jyve.localization.*;
public class SearchResults extends Screen
{
public ConcreteElement build( RunData data ) throws Exception
{
data.setTitle(TurbineServices.getInstance().getService(TurbineServices.LOCALIZATION).getString("SEARCHRESULTS_TITLE"));
ElementContainer ec = new ElementContainer();
ec.addElement ( ScreenLoader.getInstance().eval ( data, "SearchGlobal" ) );
ec.addElement ( new HR().setSize(1).setNoShade(true));
ec.addElement (new
B(TurbineServices.getInstance().getService(TurbineServices.LOCALIZATION).getString("SEARCHRESULTS_SEARCHRESULTMSG"))
);
ec.addElement ( new P() );
String search = data.parameters.getString("search", null );
if ( search == null || search.length() == 0 )
{
data.setMessage
(TurbineServices.getInstance().getService(TurbineServices.LOCALIZATION).getString("SEARCHRESULTS_NOVALIDSEARCH"));
data.setScreen ("SearchGlobal");
}
// get a connection to the db
DBConnection db = DBBroker.getInstance().getConnection();
Connection connection = db.getConnection();
StringBuffer sql = new StringBuffer();
sql.append ( "select distinct" );
sql.append ( " p.project_id, p.project_value " );
sql.append ( ", f.faq_id, f.faq_value " );
sql.append ( ", t.topic_id, t.topic_value " );
sql.append ( ", q.question_id, q.question_value " );
sql.append ( ", a.answer_id, a.answer_value " );
sql.append ( ", p.deleted, f.deleted " );
sql.append ( ", t.deleted, q.deleted " );
sql.append ( ", a.deleted " );
sql.append ( " from " );
sql.append ( " project p, faq f, topic t, question q, answer a " );
sql.append ( " where " );
sql.append ( " p.project_id=f.project_id " );
sql.append ( " and " );
sql.append ( " f.faq_id=t.faq_id " );
sql.append ( " and " );
sql.append ( " t.topic_id=q.topic_id " );
sql.append ( " and " );
sql.append ( " q.question_id=a.question_id " );
sql.append ( " and " );
sql.append ( " p.deleted='N' " );
sql.append ( " and " );
sql.append ( " f.deleted='N' " );
sql.append ( " and " );
sql.append ( " t.deleted='N' " );
sql.append ( " and " );
sql.append ( " q.deleted='N' " );
sql.append ( " and " );
sql.append ( " a.deleted='N' " );
sql.append(buildSearchCriteria(search,"or"));
/*
sql.append ( " and " );
sql.append ( " (p.project_value LIKE '%" );
sql.append ( search );
sql.append ( "%' " );
sql.append ( " OR " );
sql.append ( " t.topic_value LIKE '%" );
sql.append ( search );
sql.append ( "%' " );
sql.append ( " OR " );
sql.append ( " f.faq_value LIKE '%" );
sql.append ( search );
sql.append ( "%' " );
sql.append ( " OR " );
sql.append ( " q.question_value LIKE '%" );
sql.append ( search );
sql.append ( "%' " );
sql.append ( " OR " );
sql.append ( " a.answer_value LIKE '%" );
sql.append ( search );
sql.append ( "%')" );
*/
// execute the query
QueryDataSet qds = new QueryDataSet( connection, sql.toString());
int size = 0;
try
{
qds.fetchRecords();
size = qds.size();
if ( size > 0 )
{
Table table = new Table().setBorder(0).setCellPadding(5);
TR top = new TR().setBgColor("006666");
top.addElement ( new TD().addElement (
new
Font().addElement(TurbineServices.getInstance().getService(TurbineServices.LOCALIZATION).getString("SEARCHRESULTS_PROJECTMSG")).setColor(HtmlColor.white).setSize(4)
)
);
top.addElement ( new TD().addElement (
new
Font().addElement(TurbineServices.getInstance().getService(TurbineServices.LOCALIZATION).getString("SEARCHRESULTS_FAQMSG")).setColor(HtmlColor.white).setSize(4)
)
);
top.addElement ( new TD().addElement (
new
Font().addElement(TurbineServices.getInstance().getService(TurbineServices.LOCALIZATION).getString("SEARCHRESULTS_TOPICMSG")).setColor(HtmlColor.white).setSize(4)
)
);
top.addElement ( new TD().addElement (
new
Font().addElement(TurbineServices.getInstance().getService(TurbineServices.LOCALIZATION).getString("SEARCHRESULTS_QUESTIONMSG")).setColor(HtmlColor.white).setSize(4)
)
);
table.addElement ( top );
for ( int i=0;i<size;i++ )
{
String project_value =
qds.getRecord(i).getValue("project_value").asString();
String faq_value =
qds.getRecord(i).getValue("faq_value").asString();
String topic_value =
qds.getRecord(i).getValue("topic_value").asString();
String question_value =
qds.getRecord(i).getValue("question_value").asString();
int project_id = qds.getRecord(i).getValue("project_id").asInt();
int faq_id = qds.getRecord(i).getValue("faq_id").asInt();
int topic_id = qds.getRecord(i).getValue("topic_id").asInt();
int question_id = qds.getRecord(i).getValue("question_id").asInt();
DynamicURI pduri = new DynamicURI(data, "DisplayProjects",
"SetAll")
.addPathInfo("project_id", project_id );
DynamicURI fduri = new DynamicURI(data, "DisplayFaqs", "SetAll")
.addPathInfo("project_id", project_id )
.addPathInfo("faq_id", faq_id );
DynamicURI tduri = new DynamicURI(data, "DisplayTopics", "SetAll")
.addPathInfo("project_id", project_id )
.addPathInfo("faq_id", faq_id )
.addPathInfo("topic_id", topic_id );
DynamicURI qduri = new DynamicURI(data, "DisplayQuestionAnswer",
"SetAll")
.addPathInfo("project_id", project_id )
.addPathInfo("faq_id", faq_id )
.addPathInfo("topic_id", topic_id )
.addPathInfo("question_id", question_id );
TR tr = new TR().setBgColor("CCCCCC");
tr.addElement (
new TD().addElement ( new A()
.addElement(project_value).setHref ( pduri.toString() ) )
);
tr.addElement (
new TD().addElement ( new A()
.addElement(faq_value).setHref ( fduri.toString() ) ) );
tr.addElement (
new TD().addElement ( new A()
.addElement(topic_value).setHref ( tduri.toString() ) ) );
tr.addElement (
new TD().addElement ( new A()
.addElement(question_value).setHref ( qduri.toString() ) )
);
table.addElement ( tr );
}
ec.addElement ( table );
}
else
{
data.setMessage
(TurbineServices.getInstance().getService(TurbineServices.LOCALIZATION).getString("SEARCHRESULTS_NOMATCHMSG"));
return ScreenLoader.getInstance().eval ( data, "SearchGlobal" );
}
}
finally
{
if ( qds != null ) qds.close();
DBBroker.getInstance().releaseConnection(db);
}
ec.addElement ( new P());
ec.addElement (
TurbineServices.getInstance().getService(TurbineServices.LOCALIZATION).getString("SEARCHRESULTS_TOTALMSG")
+ size );
ec.addElement ( new P());
return ec;
}
private String buildSearchCriteria(String search, String conj)
{
StringTokenizer searchTokenizer = new StringTokenizer(search);
StringBuffer searchBuffer = new StringBuffer();
if (searchTokenizer.countTokens() > 1)
{
boolean conjunction = true;
while (searchTokenizer.hasMoreTokens())
{
String searchToken = searchTokenizer.nextToken();
if (searchTokenizer.hasMoreTokens())
{
if (conjunction)
{
searchBuffer.append(" '%"+searchToken+"%' ");
conjunction = false;
}
else
{
if (searchToken.equalsIgnoreCase("and") ||
searchToken.equalsIgnoreCase("or"))
{
searchBuffer.append( " "+searchToken.toUpperCase()+" ");
conjunction = true;
}
else
{
searchBuffer.append(" " + conj.toUpperCase() + "
'%"+searchToken+"%' ");
}
}
}
else
{
if (!conjunction) searchBuffer.append(" " + conj.toUpperCase());
searchBuffer.append(" '%"+searchToken+"%' ");
}
}
}
else searchBuffer.append(" '%" + search + "%' ");
StringBuffer sqlBuffer = new StringBuffer();
String[] dbFields = {"p.project_value",
"t.topic_value",
"f.faq_value",
"q.question_value",
"a.answer_value"};
sqlBuffer.append ( " AND ( ");
for (int i=0; i < dbFields.length; i++)
{
sqlBuffer.append ( " ( " );
StringTokenizer tokenizer = new StringTokenizer(searchBuffer.toString());
while (tokenizer.hasMoreTokens())
{
String token = tokenizer.nextToken();
if (!(token.equalsIgnoreCase("and") || token.equalsIgnoreCase("or")))
sqlBuffer.append ( dbFields[i]+" LIKE " );
sqlBuffer.append ( token + " ");
}
if (i < dbFields.length - 1) sqlBuffer.append ( " ) OR " );
}
sqlBuffer.append ( " ) ) " );
return sqlBuffer.toString();
}
}