001: package com.sun.portal.search.providers;
002:
003: import java.util.*;
004: import java.lang.*;
005:
006: import com.sun.portal.search.soif.*;
007: import com.sun.portal.search.demo.*;
008: import com.sun.portal.search.util.Encoder;
009:
010: /**
011: * This class provides convenient methods to handle advanced search and
012: * also evolved from the frontend application requirements. <br><br>
013: * @see com.sun.portal.search.demo.Search
014: */
015: public class SearchContext extends Search {
016:
017: /* The left operand in a list element */
018: public static final String OPERAND = "1";
019:
020: /** The operation in a list element */
021: public static final String OPERATION = "2";
022:
023: /** The right operand in a list element */
024: public static final String VALUE = "3";
025:
026: /** corresponds to <CONTAINS> operation */
027: public static final String CONTAIN = "contain";
028:
029: /** corresponds to <NOT> <CONTAINS> operation */
030: public static final String NOTCONTAIN = "notcontain";
031:
032: /** corresponds to <NOT> operation */
033: public static final String NOT = "not";
034:
035: /** corresponds to <OR> operation */
036: public static final String ANY = "any";
037:
038: /** corresponds to <EXACT> string operation */
039: public static final String EXACT = "exact";
040:
041: /** corresponds to <ALL> string operation */
042: public static final String ALL = "all";
043:
044: /** corresponds to <PASSAGE> string operation */
045: public static final String PASSAGE = "passage";
046:
047: /** corresponds to '>' operation used to compare number type */
048: public static final String GREATER = "greater";
049:
050: /** corresponds to '<' operation used to compare number type */
051: public static final String LESS = "less";
052:
053: /** corresponds to '=' operation used to compare number type */
054: public static final String EQUAL = "equal";
055:
056: /** corresponds to 'not equal to' operation used to compare number type */
057: public static final String NOTEQUAL = "notequal";
058:
059: private StringBuffer scopebuf = null;
060: private boolean searchAllCategories = true;
061: private ArrayList criteria;
062:
063: private int page = 0;
064: private String browseCategory = "ROOT";
065:
066: /** Search Results related variables */
067: private int totalPages = 0;
068:
069: /**
070: * Public Constructor
071: * calls super()
072: */
073: public SearchContext() {
074: super ();
075: }
076:
077: /**
078: * Sets the current page value.
079: * <P>
080: * firstHit for searches is calculated based on the current
081: * page and viewHits.
082: * @param page is the current page value
083: */
084: public void setPage(int p) {
085: this .page = p;
086: }
087:
088: /**
089: * Gets the current page value
090: * @return the current page value
091: */
092: public int getPage() {
093: if (page == 0) {
094: // page not set. firstHit has to have a value.
095: if (firstHit >= 0 && viewHits > 0)
096: page = (firstHit / viewHits) + 1;
097: else
098: page = 1;
099: }
100:
101: return page;
102: }
103:
104: /**
105: * Gets the value of category
106: * <P>
107: * The category value is used to create the scope value in the
108: * <code> execute() </code> method.
109: * The scope and the category are combined together based
110: * on the type of request. taxonomy-request v/s rd-request
111: * @return The current category value
112: * @see #setSearchAllCategories(boolean)
113: */
114: public String getCategory() {
115: return browseCategory;
116: }
117:
118: /**
119: * Sets the category value.
120: * <P>
121: * category setting is mainly required if category search is needed.
122: * @param bc is the current category level, If the category is not set
123: * then the category is set to the root of the taxonomy tree and the search
124: * is executed for all categories.
125: * @see #getCategory()
126: * @see #setSearchAllCategories(boolean)
127: */
128: public void setCategory(String bc) {
129: if ((bc != null) && (!bc.equals("")))
130: this .browseCategory = bc;
131: }
132:
133: /**
134: * Sets the searchAllCategories property.
135: * <P>
136: * This property value is used in the <code>execute()</code> to create the scope
137: * @param all true implies that search should be in all the cateogories
138: * and false means that search should be within a specific category
139: */
140: public void setSearchAllCategories(boolean all) {
141: this .searchAllCategories = all;
142: }
143:
144: /**
145: * Sets the list of criteria for the scope.
146: * <P>
147: * Advanced search related methods.The list should have specific operands,
148: * operations and values. The list is then internally converted to a String
149: * query as per the search engine query language.
150: * @param c criteria list for the search query
151: */
152: public void setScope(ArrayList c) {
153: this .criteria = c;
154: String r_op = "";
155: scopebuf = new StringBuffer();
156:
157: for (int i = 0; i < c.size(); i++) {
158: String schema_name = (String) ((HashMap) c.get(i))
159: .get(this .OPERAND);
160: String operation = (String) ((HashMap) c.get(i))
161: .get(this .OPERATION);
162: String val = (String) ((HashMap) c.get(i)).get(this .VALUE);
163:
164: if (val != null && !val.equals("")) {
165: r_op = getRightOperator(operation, val);
166: if (i == (c.size() - 1)) {
167: parse(schema_name, operation, r_op, true);
168: } else {
169: parse(schema_name, operation, r_op, false);
170: }
171: }
172:
173: scope = scopebuf.toString();
174: if (scope.endsWith(" <AND> ")) {
175: scope = scope.substring(0, scope.length() - 7);
176: }
177: }
178: }
179:
180: /**
181: * Executes the query
182: * <P>
183: * Calls the parent <code>doQuery()</code> method after doing some preprocessing to the
184: * query string. Merges category, searchAllCategories, scope string into a final scope
185: * string.
186: * @exception Exception is thrown if any of the input parameters are not specified or if
187: * the resultset is null or if connection to the search server failed
188: *
189: */
190: public void execute() throws Exception {
191: if ((viewHits == 0) || (viewHits > 500))
192: viewHits = 8;
193:
194: if (firstHit == 0) {
195: // calculate firstHit. make sure viewHits has a value
196: firstHit = (viewHits * (getPage() - 1)) + 1;
197: }
198:
199: if ((RDMType.equals("taxonomy-request"))
200: && (queryLanguage.equals("taxonomy-basic"))) {
201: scope = "children* " + browseCategory;
202:
203: } else if ((RDMType.equals("taxonomy-request"))
204: && (scope.equals(""))) {
205: scope = "(id <STARTS> \""
206: + Encoder.quotedEscape(browseCategory) + "\")";
207:
208: } else if ((RDMType.equals("taxonomy-request"))
209: && (!scope.equals(""))) {
210: if (!searchAllCategories) {
211: scope = "(" + scope + ") <AND> (id <STARTS> \""
212: + Encoder.quotedEscape(browseCategory) + "\")";
213: } else {
214: }
215: } else if ((RDMType.equals("rd-request")) && (scope.equals(""))) {
216: scope = "(classification = \""
217: + Encoder.quotedEscape(browseCategory) + "\")";
218:
219: } else if ((RDMType.equals("rd-request"))
220: && (!scope.equals(""))) {
221: if (!searchAllCategories) {
222: scope = "(" + scope
223: + ") <AND> (classification <STARTS> \""
224: + Encoder.quotedEscape(browseCategory) + "\")";
225: }
226: } else {
227: }
228:
229: doQuery(firstHit, viewHits);
230: if (getResultStream() == null) {
231: throw new Exception("Search server error.");
232: }
233: int hitCount = getHitCount();
234: totalPages = (hitCount + viewHits - 1) / viewHits;
235: }
236:
237: /**
238: * Gets the total pages
239: * <P>
240: * Calculated based on the hitCount and viewHits.
241: * totalPages has no value if called before calling
242: * <code>execute()</code> first
243: * @return total pages
244: */
245: public int getTotalPages() {
246: return totalPages;
247: }
248:
249: /**
250: * Adds appropriate searchengine operators based on teh type of
251: * operation. Adds <SOR> for or type, adds quotes for exact type
252: * adds brackets for all other types
253: */
254: private String getRightOperator(String operation, String r_op) {
255: String new_op = "";
256:
257: if (operation.equals(SearchContext.ALL)
258: || operation.equals(SearchContext.PASSAGE)
259: || (r_op.equals(" "))) {
260: new_op = r_op;
261: } else if (operation.equals(SearchContext.EXACT)) {
262: new_op = "\"" + r_op + "\"";
263: } else if (operation.equals(SearchContext.ANY)) {
264: new_op = "<SOR> " + r_op;
265: } else {
266: new_op = r_op;
267: }
268:
269: return new_op;
270: }
271:
272: /**
273: * Appends the scope string based on the operation type
274: */
275: private void parse(String l_op, String operation, String r_op,
276: boolean last) {
277:
278: if (operation.equals(SearchContext.CONTAIN)) {
279: scopebuf.append("(" + l_op + " <CONTAINS> " + r_op + ")");
280: } else if (operation.equals(SearchContext.NOTCONTAIN)) {
281: scopebuf.append("<NOT> " + "(" + l_op + " <CONTAINS> "
282: + r_op + ")");
283: } else if (operation.equals(SearchContext.EQUAL)) {
284: scopebuf.append("(" + l_op + " = " + r_op + ")");
285: } else if (operation.equals(SearchContext.NOTEQUAL)) {
286: scopebuf.append("<NOT> " + "(" + l_op + " = " + r_op + ")");
287: } else if (operation.equals(SearchContext.LESS)) {
288: scopebuf.append("(" + l_op + " < " + r_op + ")");
289: } else if (operation.equals(SearchContext.GREATER)) {
290: scopebuf.append("(" + l_op + " > " + r_op + ")");
291: } else if (operation.equals(SearchContext.NOT)) {
292: scopebuf.append("<NOT> (" + r_op + ")");
293: } else if (operation.equals(SearchContext.ALL)) {
294: scopebuf.append("(" + r_op + ")");
295: // AND type
296: } else if (operation.equals(SearchContext.ANY)) {
297: scopebuf.append("(" + r_op + ")");
298: // OR type
299: } else if (operation.equals(SearchContext.EXACT)) {
300: scopebuf.append("(" + r_op + ")");
301: // quote
302: } else if (operation.equals(SearchContext.PASSAGE)) {
303: scopebuf.append("(<PASSAGE> " + r_op + ")");
304: } else {
305: scopebuf.append("(" + r_op + ")");
306: }
307:
308: if (!last) {
309: scopebuf.append(" <AND> ");
310: }
311: }
312:
313: /**
314: * Encodes > <, ", & characters
315: * @param s string that needs to be html encoded
316: */
317: public static String htmlEncode(String s) {
318: StringBuffer buf = new StringBuffer();
319: for (int i = 0; i < s.length(); i++) {
320: char c = s.charAt(i);
321: switch (c) {
322: case '<':
323: buf.append("<");
324: break;
325: case '>':
326: buf.append(">");
327: break;
328: case '&':
329: buf.append("&");
330: break;
331: case '"':
332: buf.append(""");
333: break;
334: // XXX case '\'':
335: //buf.append("'");
336: //break;
337: default:
338: buf.append(c);
339: break;
340: }
341: }
342: return buf.toString();
343: }
344: }
|