Source Code Cross Referenced for EtxSqlHandler.java in  » Database-ORM » MMBase » org » mmbase » storage » search » implementation » database » informix » excalibur » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database ORM » MMBase » org.mmbase.storage.search.implementation.database.informix.excalibur 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:
003:        This software is OSI Certified Open Source Software.
004:        OSI Certified is a certification mark of the Open Source Initiative.
005:
006:        The license (Mozilla version 1.0) can be read at the MMBase site.
007:        See http://www.MMBase.org/license
008:
009:         */
010:        package org.mmbase.storage.search.implementation.database.informix.excalibur;
011:
012:        import java.io.*;
013:        import java.util.*;
014:
015:        import org.mmbase.bridge.Field;
016:        import org.mmbase.module.core.*;
017:        import org.mmbase.storage.StorageManagerFactory;
018:        import org.mmbase.storage.search.*;
019:        import org.mmbase.storage.search.implementation.database.*;
020:        import org.mmbase.util.logging.*;
021:        import org.w3c.dom.*;
022:        import org.xml.sax.*;
023:
024:        /**
025:         * The Etx query handler adds support for Excalibur Text Search constraints,
026:         * when used with an Informix database and an Excalibur Text Search datablade.
027:         * This class is provided as a coding example of a ChainedSqlHandler.
028:         * <p>
029:         * On initialization, the handler reads a list of etx-indices from a
030:         * configuration file.
031:         * This configurationfile must be named <em>etxindices.xml</em> and located
032:         * inside the <em>databases</em> configuration directory.
033:         * It's dtd is located in the directory
034:         * <code>org.mmbase.storage.search.implementation.database.informix.excalibur.resources</code>
035:         * in the MMBase source tree and
036:         * <a href="http://www.mmbase.org/dtd/etxindices.dtd">here</a> online.
037:         *
038:         * @author Rob van Maris
039:         * @version $Id: EtxSqlHandler.java,v 1.10 2007/06/12 10:59:41 michiel Exp $
040:         * @since MMBase-1.7
041:         */
042:        // TODO RvM: (later) add javadoc, elaborate on overwritten methods.
043:        public class EtxSqlHandler extends ChainedSqlHandler implements 
044:                SqlHandler {
045:
046:            private static final Logger log = Logging
047:                    .getLoggerInstance(EtxSqlHandler.class);
048:
049:            /**
050:             * The indexed fields, stored as {@link #BuilderField BuilderField}
051:             *  instances.
052:             */
053:            private Set<String> indexedFields = new HashSet<String>();
054:
055:            /**
056:             * Creates a new instance of EtxueryHandler.
057:             *
058:             * @param successor Successor in chain or responsibility.
059:             */
060:            public EtxSqlHandler(SqlHandler successor) throws IOException {
061:                super (successor);
062:                init();
063:            }
064:
065:            // javadoc is inherited
066:            public void appendConstraintToSql(StringBuilder sb,
067:                    Constraint constraint, SearchQuery query, boolean inverse,
068:                    boolean inComposite) throws SearchQueryException {
069:                // Net effect of inverse setting with constraint inverse property.
070:                boolean overallInverse = inverse ^ constraint.isInverse();
071:
072:                if (constraint instanceof  StringSearchConstraint) {
073:                    // TODO: test for support, else throw exception
074:                    // TODO: support maxNumber for query with etx constraint.
075:                    StringSearchConstraint stringSearchConstraint = (StringSearchConstraint) constraint;
076:                    StepField field = stringSearchConstraint.getField();
077:                    Map<String, Object> parameters = stringSearchConstraint
078:                            .getParameters();
079:
080:                    // TODO: how to implement inverse,
081:                    // it is actually more complicated than this:
082:                    if (overallInverse) {
083:                        sb.append("NOT ");
084:                    }
085:                    sb.append("etx_contains(").append(
086:                            getAllowedValue(field.getStep().getAlias()))
087:                            .append(".").append(
088:                                    getAllowedValue(field.getFieldName()))
089:                            .append(", Row('");
090:
091:                    Iterator<String> iSearchTerms = stringSearchConstraint
092:                            .getSearchTerms().iterator();
093:                    while (iSearchTerms.hasNext()) {
094:                        String searchTerm = iSearchTerms.next();
095:                        sb.append(searchTerm);
096:                        if (iSearchTerms.hasNext()) {
097:                            sb.append(" ");
098:                        }
099:                    }
100:                    sb.append("', '");
101:                    switch (stringSearchConstraint.getSearchType()) {
102:                    case StringSearchConstraint.SEARCH_TYPE_WORD_ORIENTED:
103:                        sb.append("SEARCH_TYPE = WORD");
104:                        break;
105:
106:                    case StringSearchConstraint.SEARCH_TYPE_PHRASE_ORIENTED:
107:                        sb.append("SEARCH_TYPE = PHRASE_EXACT");
108:                        break;
109:
110:                    case StringSearchConstraint.SEARCH_TYPE_PROXIMITY_ORIENTED:
111:                        Integer proximityLimit = (Integer) parameters
112:                                .get(StringSearchConstraint.PARAM_PROXIMITY_LIMIT);
113:                        if (proximityLimit == null) {
114:                            throw new IllegalStateException(
115:                                    "Parameter PARAM_PROXIMITY_LIMIT not set "
116:                                            + "while trying to perform proximity oriented search.");
117:                        }
118:                        sb.append("SEARCH_TYPE = PROX_SEARCH(").append(
119:                                proximityLimit).append(")");
120:                        break;
121:
122:                    default:
123:                        throw new IllegalStateException(
124:                                "Invalid searchtype value: "
125:                                        + stringSearchConstraint
126:                                                .getSearchType());
127:                    }
128:
129:                    switch (stringSearchConstraint.getMatchType()) {
130:                    case StringSearchConstraint.MATCH_TYPE_FUZZY:
131:                        Float fuzziness = (Float) parameters
132:                                .get(StringSearchConstraint.PARAM_FUZZINESS);
133:                        int wordScore = Math
134:                                .round(100 * fuzziness.floatValue());
135:                        sb.append(" & PATTERN_ALL & WORD_SCORE = ").append(
136:                                wordScore);
137:                        break;
138:
139:                    case StringSearchConstraint.MATCH_TYPE_LITERAL:
140:                        break;
141:
142:                    case StringSearchConstraint.MATCH_TYPE_SYNONYM:
143:                        log
144:                                .warn("Synonym matching not supported. Executing this query with literal matching instead: "
145:                                        + query);
146:                        break;
147:
148:                    default:
149:                        throw new IllegalStateException(
150:                                "Invalid matchtype value: "
151:                                        + stringSearchConstraint.getMatchType());
152:                    }
153:
154:                    sb.append("'))");
155:
156:                } else {
157:                    getSuccessor().appendConstraintToSql(sb, constraint, query,
158:                            inverse, inComposite);
159:                }
160:            }
161:
162:            // javadoc is inherited
163:            public int getSupportLevel(int feature, SearchQuery query)
164:                    throws SearchQueryException {
165:                int support;
166:                switch (feature) {
167:                case SearchQueryHandler.FEATURE_MAX_NUMBER:
168:                    // optimal with etx index on field, and constraint is
169:                    // StringSearchConstraint, with no additonal constraints.
170:                    Constraint constraint = query.getConstraint();
171:                    if (constraint != null
172:                            && constraint instanceof  StringSearchConstraint
173:                            && hasEtxIndex(((StringSearchConstraint) constraint)
174:                                    .getField())
175:                            && !hasAdditionalConstraints(query)) {
176:                        support = SearchQueryHandler.SUPPORT_OPTIMAL;
177:                    } else {
178:                        support = getSuccessor()
179:                                .getSupportLevel(feature, query);
180:                    }
181:                    break;
182:                default:
183:                    support = getSuccessor().getSupportLevel(feature, query);
184:                }
185:                return support;
186:            }
187:
188:            // javadoc is inherited
189:            public int getSupportLevel(Constraint constraint, SearchQuery query)
190:                    throws SearchQueryException {
191:                int support;
192:
193:                if (constraint instanceof  StringSearchConstraint
194:                        && hasEtxIndex(((StringSearchConstraint) constraint)
195:                                .getField())) {
196:                    StringSearchConstraint stringSearchConstraint = (StringSearchConstraint) constraint;
197:                    // StringSearchConstraint on field with etx index:
198:                    // - none if matchtype = MATCH_TYPE_SYNONYM
199:                    // - otherwise: weak support if other stringsearch constraints are present
200:                    // - otherwise: optimal support
201:                    if (stringSearchConstraint.getMatchType() == StringSearchConstraint.MATCH_TYPE_SYNONYM) {
202:                        support = SearchQueryHandler.SUPPORT_NONE;
203:                    } else if (containsOtherStringSearchConstraints(query
204:                            .getConstraint(), stringSearchConstraint)) {
205:                        support = SearchQueryHandler.SUPPORT_WEAK;
206:                    } else {
207:                        support = SearchQueryHandler.SUPPORT_OPTIMAL;
208:                    }
209:                } else {
210:                    support = getSuccessor().getSupportLevel(constraint, query);
211:                }
212:                return support;
213:            }
214:
215:            /**
216:             * Tests if an Excelibur Text Search index has been made for this field.
217:             *
218:             * @param field the field.
219:             * @return true if an Excelibur Text Search index has been made for this field,
220:             *         false otherwise.
221:             */
222:            public boolean hasEtxIndex(StepField field) {
223:                boolean result = false;
224:                if (field.getType() == Field.TYPE_STRING
225:                        || field.getType() == Field.TYPE_XML) {
226:                    result = indexedFields.contains(field.getStep()
227:                            .getTableName()
228:                            + "." + field.getFieldName());
229:                }
230:                return result;
231:            }
232:
233:            /**
234:             * Tests if the query contains additional constraints, i.e. on relations
235:             * or nodes.
236:             *
237:             * @param query the query.
238:             * @return true if the query containts additional constraints,
239:             *         false otherwise.
240:             */
241:            protected boolean hasAdditionalConstraints(SearchQuery query) {
242:                Iterator<Step> iSteps = query.getSteps().iterator();
243:                while (iSteps.hasNext()) {
244:                    Step step = iSteps.next();
245:                    if (step instanceof  RelationStep
246:                            || step.getNodes().size() > 0) {
247:                        // Additional constraints on relations or nodes.
248:                        return true;
249:                    }
250:                }
251:                // No additonal constraints:
252:                return false;
253:            }
254:
255:            /**
256:             * Tests if a constaint is/contains another stringsearch constraint than
257:             * the specified one. Recursively seaches through all childs of composite
258:             * constraints.
259:             *
260:             * @param constraint the constraint.
261:             * @param searchConstraint the stringsearch constraint.
262:             * @return true if the constraint is/contains another stringsearch constraint
263:             *             than the given one, false otherwise.
264:             */
265:            protected boolean containsOtherStringSearchConstraints(
266:                    Constraint constraint,
267:                    StringSearchConstraint searchConstraint) {
268:                if (constraint instanceof  CompositeConstraint) {
269:                    // Composite constraint.
270:                    Iterator<Constraint> iChildConstraints = ((CompositeConstraint) constraint)
271:                            .getChilds().iterator();
272:                    while (iChildConstraints.hasNext()) {
273:                        Constraint childConstraint = iChildConstraints.next();
274:                        if (containsOtherStringSearchConstraints(
275:                                childConstraint, searchConstraint)) {
276:                            // Another stringsearch constraint found in childs.
277:                            return true;
278:                        }
279:                    }
280:                    // No other stringsearch constraint found in childs.
281:                    return false;
282:
283:                } else if (constraint instanceof  StringSearchConstraint
284:                        && constraint != searchConstraint) {
285:                    // Anther stringsearch constraint.
286:                    return true;
287:
288:                } else {
289:                    // Not another stringsearch constraint and not a composite.
290:                    return false;
291:                }
292:            }
293:
294:            /**
295:             * Initializes the handler by reading the etxindices configuration file
296:             * to determine which fields have a etx index.
297:             * <p>
298:             * The configurationfile must be named <em>etxindices.xml</em> and located
299:             * inside the <em>databases</em> configuration directory.
300:             *
301:             * @throw IOException When a failure occurred while trying to read the
302:             *        configuration file.
303:             */
304:            private void init() throws IOException {
305:                File etxConfigFile = new File(MMBaseContext.getConfigPath()
306:                        + "/databases/etxindices.xml");
307:                XmlEtxIndicesReader configReader = new XmlEtxIndicesReader(
308:                        new InputSource(new BufferedReader(new FileReader(
309:                                etxConfigFile))));
310:
311:                for (Iterator<Element> eSbspaces = configReader
312:                        .getSbspaceElements(); eSbspaces.hasNext();) {
313:                    Element sbspace = eSbspaces.next();
314:
315:                    for (Iterator<Element> eEtxIndices = configReader
316:                            .getEtxindexElements(sbspace); eEtxIndices
317:                            .hasNext();) {
318:                        Element etxIndex = eEtxIndices.next();
319:                        String table = configReader.getEtxindexTable(etxIndex);
320:                        String field = configReader.getEtxindexField(etxIndex);
321:                        String index = configReader.getEtxindexValue(etxIndex);
322:                        try {
323:                            String builderField = toBuilderField(table, field);
324:                            indexedFields.add(builderField);
325:                            log.service("Registered etx index \"" + index
326:                                    + "\" for builderfield " + builderField);
327:                        } catch (IllegalArgumentException e) {
328:                            log.error("Failed to register etx index \"" + index
329:                                    + "\": " + e);
330:                        }
331:                    }
332:                }
333:            }
334:
335:            /**
336:             * Finds builderfield corresponding to the database table and field names.
337:             *
338:             * @param dbTable The tablename used in the database.
339:             * @param dbField The fieldname used in the database.
340:             * @return The corresponding builderfield represented by a string of the
341:             *         form &lt;buildername&gt;.&lt;fieldname&gt;.
342:             * @throws IllegalArgumentException when an invalid argument is supplied.
343:             */
344:            static String toBuilderField(String dbTable, String dbField) {
345:                // package visibility!
346:                MMBase mmbase = MMBase.getMMBase();
347:                StorageManagerFactory factory = mmbase
348:                        .getStorageManagerFactory();
349:                String tablePrefix = mmbase.getBaseName() + "_";
350:
351:                if (!dbTable.startsWith(tablePrefix)) {
352:                    throw new IllegalArgumentException("Invalid tablename: \""
353:                            + dbTable + "\". "
354:                            + "It should start with the prefix \""
355:                            + tablePrefix + "\".");
356:                }
357:
358:                String builderName = dbTable.substring(tablePrefix.length());
359:                MMObjectBuilder builder;
360:                try {
361:                    builder = mmbase.getBuilder(builderName);
362:                } catch (BuilderConfigurationException e) {
363:                    // Unknown builder.
364:                    builder = null;
365:                }
366:
367:                if (builder == null) {
368:                    throw new IllegalArgumentException("Unknown builder: \""
369:                            + builderName + "\".");
370:                }
371:
372:                Iterator<String> iFieldNames = builder.getFieldNames()
373:                        .iterator();
374:                while (iFieldNames.hasNext()) {
375:                    String fieldName = iFieldNames.next();
376:                    if (factory.getStorageIdentifier(fieldName).equals(dbField)) {
377:                        return builderName + "." + fieldName;
378:                    }
379:                }
380:
381:                throw new IllegalArgumentException(
382:                        "No field corresponding to database field \"" + dbField
383:                                + "\" found in builder \"" + builderName
384:                                + "\".");
385:            }
386:
387:        }
w__w___w__.___j___a_va2__s.___c___o__m | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.