/*************************************************************************
*
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: QueryFactoryImpl.java,v $
*
* $Revision: 1.2 $
*
* last change: $Author: rt $ $Date: 2005/09/09 16:59:24 $
*
* The Contents of this file are made available subject to
* the terms of GNU Lesser General Public License Version 2.1.
*
*
* GNU Lesser General Public License Version 2.1
* =============================================
* Copyright 2005 by Sun Microsystems, Inc.
* 901 San Antonio Road, Palo Alto, CA 94303, USA
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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.sun.xmlsearch.xml.qe;
import java.util.StringTokenizer;
import java.text.MessageFormat;
import com.sun.xmlsearch.xml.*;
import com.sun.xmlsearch.util.IntegerArray;
final class QueryFactoryImpl {
private static final MessageFormat StepFormat =
new MessageFormat("{0}[@{1}=\"{2}\"]");
private final Query _emptyQueryInstance = new EmptyQuery();
private static final MessageFormat StepFormat2 =
new MessageFormat("{0}[{1,number,integer}]");
public Query makeQuery(XmlIndex env, String context,
int nColumns, int nHits) {
ContextTables contextInfo = env.getContextInfo();
if (context == null)
return new Query(env, nColumns, nHits, null);
else if (context.indexOf('|') != -1) { // alternatives
StringTokenizer alts = new StringTokenizer(context, " |");
IntegerArray codes = new IntegerArray();
while (alts.hasMoreTokens()) {
String alt = alts.nextToken();
int code = contextInfo.linkCode(alt);
if (code != -1)
codes.addNew(code);
else
System.err.println("invalid (in the collection) tag name: " + alt);
}
switch (codes.cardinality()) {
case 0:
return _emptyQueryInstance;
case 1:
return new Query1(env, nColumns, nHits, null, codes.at(0));
default:
return new Query4(env, nColumns, nHits, null,
codes.toIntArray());
}
}
else if (context.indexOf("//") != -1) { // ancestor
StringTokenizer elements = new StringTokenizer(context, " /");
int ancestor = contextInfo.linkCode(elements.nextToken());
int code = contextInfo.linkCode(elements.nextToken());
// ancestor
return new Query3(env, nColumns, nHits, null, code, ancestor);
}
else if (context.indexOf("/") != -1) { // parent (or path)
StringTokenizer elements = new StringTokenizer(context, " /");
int nTokens = elements.countTokens();
if (nTokens == 2) {
int parent = contextInfo.linkCode(elements.nextToken());
int code = contextInfo.linkCode(elements.nextToken());
// parent
return new Query2(env, nColumns, nHits, null, code, parent);
}
else if (nTokens > 2) {
IntegerArray codes = new IntegerArray();
while (elements.hasMoreTokens()) {
String parentStar = elements.nextToken();
int code = contextInfo.linkCode(parentStar);
if (code != -1)
codes.addNew(code);
else
System.err.println("invalid (in this collection) tag name: " +
parentStar);
}
return new Query5(env, nColumns, nHits, null,
codes.toIntArray());
}
else
return _emptyQueryInstance;
}
else if (context.indexOf("@") != -1) { // attribute
int code = -1, markerStartCode = -1, markerStopCode = -1;
try {
Object[] parts = StepFormat.parse(context);
final String element = (String)parts[0];
final String attribute = (String)parts[1];
final String value = (String)parts[2];
final String marker = "<" + element
+ '<' + attribute + '<' + value;
System.out.println(marker);
code = contextInfo.linkCode(element);
markerStartCode = env.fetch("+" + marker);
markerStopCode = env.fetch("-" + marker);
System.out.println("markerStartCode = " + markerStartCode);
System.out.println("markerStopCode = " + markerStopCode);
}
catch (Exception e) {
System.err.println(e);
}
if (code != -1 && markerStartCode != -1 && markerStopCode != -1)
return new Query6(env, nColumns, nHits, null, code,
markerStartCode, markerStopCode);
else
return _emptyQueryInstance;
}
else if (context.indexOf("[") != -1) { // step elementn[n]
int code = -1;
try {
Object[] parts = StepFormat2.parse(context);
final String element = (String)parts[0];
int n = ((Long)parts[1]).intValue();
code = contextInfo.linkCode(element);
System.out.println("element = " + element + " seq = " + n);
if (code != -1)
return new Query7(env, nColumns, nHits, null, code, n);
}
catch (Exception e) {
System.err.println(e);
}
return _emptyQueryInstance;
}
else {
int code = contextInfo.linkCode(context);
if (code != -1)
return new Query1(env, nColumns, nHits, null, code);
else
return _emptyQueryInstance;
}
}
/** when query conditions cannot be met,
eg. search in non-existing elements
this no-op Query is returned
*/
private final class EmptyQuery extends Query {
private final ConceptData _conceptDataInstance;
// !!! structure of Query still needs to be (unnecessarily) created
public EmptyQuery() {
super(null, 0, 0, null);
_conceptDataInstance = new ConceptData() {
public void generateFillers(RoleFiller[] array, int pos) {}
};
}
public final ConceptData makeConceptData(int query, int col, int concept,
double score) {
return _conceptDataInstance;
}
}
/** Query1: search w/i bounds of instances of a named element type
eg. search in TITLE
*/
private class Query1 extends Query {
protected final int _searchFieldCode;
public Query1(XmlIndex env, int nColumns, int nHits,
double[] missingPenalties, int fieldCode) {
super(env, nColumns, nHits, missingPenalties);
_searchFieldCode = fieldCode;
}
public ConceptData makeConceptData(int query, int col, int concept,
double score) {
return new ConceptData1(concept, col, score, query,
_nColumns, _ctx, _searchFieldCode);
}
} // end of Query1
/** Query2: search w/i bounds of instances of a named element type
AND constrained parent type
eg. search in SCENE/TITLE
*/
private final class Query2 extends Query1 {
private final int _parentCode;
public Query2(XmlIndex env, int nColumns, int nHits,
double[] missingPenalties,
int fieldCode, int parentCode) {
super(env, nColumns, nHits, missingPenalties, fieldCode);
_parentCode = parentCode;
}
public final ConceptData makeConceptData(int query, int col, int concept,
double score) {
return new ConceptData2(concept, col, score, query,
_nColumns, _ctx,
_searchFieldCode, _parentCode);
}
}
/** Query3: search w/i bounds of instances of a named element type
AND constrained ancestor type
eg. search in SCENE//LINE
*/
private final class Query3 extends Query1 {
private final int _ancestorCode;
public Query3(XmlIndex env, int nColumns, int nHits,
double[] missingPenalties,
int fieldCode, int ancestorCode) {
super(env, nColumns, nHits, missingPenalties, fieldCode);
_ancestorCode = ancestorCode;
}
public final ConceptData makeConceptData(int query, int col, int concept,
double score) {
return new ConceptData3(concept, col, score, query,
_nColumns, _ctx,
_searchFieldCode, _ancestorCode);
}
}
/** Query4: search w/i bounds of instances of one
of the named element types
*/
private final class Query4 extends Query {
private final int[] _codes;
public Query4(XmlIndex env, int nColumns, int nHits,
double[] missingPenalties, int[] alternatives) {
super(env, nColumns, nHits, missingPenalties);
_codes = alternatives;
}
public final ConceptData makeConceptData(int query, int col, int concept,
double score) {
return new ConceptData4(concept, col, score, query,
_nColumns, _ctx,
_codes);
}
}
/** Query5: search w/i subtrees with a path ancestry
*/
private final class Query5 extends Query {
private final int[] _codes;
public Query5(XmlIndex env, int nColumns, int nHits,
double[] missingPenalties, int[] path) {
super(env, nColumns, nHits, missingPenalties);
_codes = path;
}
public final ConceptData makeConceptData(int query, int col, int concept,
double score) {
return new ConceptData5(concept, col, score, query,
_nColumns, _ctx,
_codes);
}
} // end of Query5
/** Query6: search w/i elements with specified attribute value
*/
private final class Query6 extends Query {
protected final int _searchFieldCode;
protected final int _markerStartCode;
protected final int _markerStopCode;
public Query6(XmlIndex env, int nColumns, int nHits,
double[] missingPenalties,
int fieldCode, int markerStartCode, int markerStopCode) {
super(env, nColumns, nHits, missingPenalties);
_searchFieldCode = fieldCode;
_markerStartCode = markerStartCode;
_markerStopCode = markerStopCode;
}
public ConceptData makeConceptData(int query, int col, int concept,
double score) {
return new ConceptData1(concept, col, score, query,
_nColumns, _ctx, _searchFieldCode);
}
public boolean zoned() {
return true;
}
public void addControlConceptData(Search search, int queryNo) {
search.addConceptData(new ConceptDataStart(_markerStartCode,
queryNo, this));
search.addConceptData(new ConceptDataStop(_markerStopCode,
queryNo, this));
}
} // end of Query6
/** Query7: search w/i elements that are nth child of same type
*/
private final class Query7 extends Query {
protected final int _searchFieldCode;
protected final int _seqNumber;
public Query7(XmlIndex env, int nColumns, int nHits,
double[] missingPenalties,
int fieldCode, int seqNumber) {
super(env, nColumns, nHits, missingPenalties);
_searchFieldCode = fieldCode;
_seqNumber = seqNumber;
}
public ConceptData makeConceptData(int query, int col, int concept,
double score) {
return new ConceptData7(concept, col, score, query,
_nColumns, _ctx, _searchFieldCode,
_seqNumber);
}
} // end of Query7
}