| Oracle Internet File System Developer Reference Release 9.0.1.1.0 Part Number A90093-02 |
|
This chapter describes how to build search applications with Oracle 9iFS selectors and searches.
Searching is a way to locate information stored in Oracle 9iFS. A search dynamically retrieves information from the repository based on criteria about the information. For example, you might search for all documents whose Name contains the word XML. The search returns the documents that meet that criteria at the time that it is executed. Subsequently, if new documents are created that meet the criteria, executing the search again automatically retrieves these documents as well.
Oracle 9iFS allows you to store, search, and work with information in an object-oriented manner. All information, including documents, folders, users, and groups, are defined as objects; that is, instances of Oracle 9iFS classes (e.g., Document, Folder, DirectoryUser, and DirectoryGroup). The Oracle 9iFS Java API allows you to work with these objects without having to know the complexities of how the information is stored in the database. For example, you can fetch a document, modify it, and save it in the repository as a single object instead of several rows across different tables. In the same manner, Oracle 9iFS allows you to query for information and work with query results in an object-oriented manner. Rather than constructing complex SQL queries that join the tables across which the information is stored, you can query for objects based on criteria about their class, attributes, content, and relationship to other objects.
The Oracle 9iFS Java API enables you to leverage both the power of searching against a relational database and the ease of use of an object-oriented programming environment. The API allows you to build queries and work with query results in an object-oriented manner using Java. When the query is executed, Oracle 9iFS automatically translates the query's Java construct into a SQL select statement and executes the query against the Oracle 9iFS schema. Therefore, you can query for and manipulate documents, folders, and other information as Java objects without having to know how their attributes and content are stored in the underlying database tables.
The Oracle 9iFS Java API provides two primary interfaces to query for objects in Oracle 9iFS:
Selectors provide a convenient way to execute simple queries in the repository. If you need to search against a single class of information with static criteria, then a selector will be the most convenient and quickest way to do so.
select all Documents whose Owner is 'WTalman' and whose ModifiedDate is greater than 'January 01, 2001'
Selectors are constructed from three components: a string specifying the class, a string specifying the search criteria, and a SortSpecification object, which specifies how the results are to be sorted. Figure 8-1 illustrates the construct of a selector.
Selectors operate under the following rules:
The Oracle 9iFS Java API provides two classes in the oracle.ifs.beans package for constructing selectors.
The Selector class is used to construct and execute the search. Table 8-1 lists the key methods on the Selector class.
The SortSpecification class is used to construct the sort criteria set on the selector with the setSortSpecification() method. Table 8-2 lists the key methods on the SortSpecification class.
To construct a selector, execute it, and retrieve the query results, follow these steps:
The first step is to instantiate the Selector class.
Selector selector = new Selector();
Specify the names of the classes that the query should select, such as FOLDER and DOCUMENT. The classes specified will be included in the SQL FROM clause generated by Oracle 9iFS. In this case, the selector will query for instances of the Attribute class.
selector.setSearchClassname("ATTRIBUTE");
Specify if the selector should query recursively across any subclasses of the specified classes.
selector.setRecursiveSearch(false);
Specify the query criteria by constructing a string that will constitute the SQL WHERE clause (without the word "WHERE"), then pass the string to the setSearchSelection() method on Selector. In this case, the selector will search for all instances of the ATTRIBUTE class whose DATATYPE is Boolean.
s = "DATATYPE = " + Attribute.ATTRIBUTEDATATYPE_BOOLEAN; selector.setSearchSelection(s);
Construct a SortSpecification to hold the sort order criteria for the query results. The attributes specified in the SortSpecification must be attributes on the class specified for the selector.
new SortSpecification() is called to instantiate a SortSpecification. The SortSpecification object will hold all of the sort criteria.
addSortQualifiers() is called on the SortSpecification to create an array of attributes and sort orders in the SortSpecification. In this case, the selector sort the results of the search by the NAME and REQUIRED attributes on the ATTRIBUTE class.
setSortSpecification() method is called on the selector to add the sort criteria to the search.
ss = new SortSpecification(); ss.addSortQualifiers(new String[] {"NAME", "REQUIRED"}, new boolean[] {false, true}); selector.setSortSpecification(ss);
There are two ways to execute a selector and retrieve query results:
You can call the getItems() method to execute the selector and work with the query results as an array. Subsequently, you can loop through the array to retrieve each query result.
LibraryObject[] results = selector.getItems(); LibraryObject lo; int count = (results == null) ? 0 : results.length; for (int i = 0; i < count; i++) {lo = results[i];
}
You can fetch specific items from the array by specifying their index position in the getItems() method.
LibraryObject lo = selector.getItems(i);
If you expect your search to return many results, but you don't want to get them all at once, you can use a cursor.
resetItems() method.
openItems() method on the selector.
nextItem() method on the selector.
closeItems() method is called on the selector to close the search after cursor-based access.
selector.resetItems(); selector.openItems(); int count = selector.getItemCount(); LibraryObject lo; for (int i = 0; i < count; i++) { lo = selector.nextItem(); } selector.closeItems();
Example 8-2 illustrates how to construct and execute a selector to query for all Attributes in Oracle 9iFS whose datatype is Boolean and to sort the results, as in the following SQL query:
SELECT * FROM ATTRIBUTE WHERE DATATYPE = BOOLEAN
ORDER BY NAME DESC, REQUIRED
Selector selector = new Selector(session);
selector.setSearchClassname("ATTRIBUTE");
selector.setRecursiveSearch(false);
String s = "DATATYPE = " +
Attribute.ATTRIBUTEDATATYPE_BOOLEAN;selector.setSearchSelection(s);
SortSpecification ss = new SortSpecification(); ss.addSortQualifiers(new String[] {"NAME", "REQUIRED"}, new boolean[] {false, true}); selector.setSortSpecification(ss);
LibraryObject[] attributes = selector.getItems();
Attribute att; int count = (attributes == null) ? 0 : attributes.length; for (int i = 0; i < count; i++) { att = (Attribute) attributes[i]; }
att = (Attribute) selector.getItems(0); att = (Attribute) selector.getItems(count - 1);
selector.resetItems(); selector.openItems(); count = selector.getItemCount(); for (int i = 0; i < count; i++) { attribute = (Attribute) selector.nextItem(); }
Using a selector is sufficient for querying a single class of information with simple query criteria. However, selectors do not allow you to construct queries that join multiple classes, specify content and relationship criteria, or use bind variables.
Searches provide a more robust interface for constructing and executing complex queries in the repository. Searches can query against multiple classes of information based on criteria about attributes, content, folders, other relationships, and arbitrary metadata. You can dynamically assemble the components of a search and pass in bind variables. You can also save search criteria persistently so that it can be used to execute the search later.
find all Documents and Folders that are in my Home Folder, whose ModifiedDate is less than <VariableDate>, and whose Name contains 'XML' or whose Content contains 'XML'
The Oracle 9iFS Search object model uses four primary Java objects to construct and execute queries, manipulate search results, and save search criteria:
The Search object model enables you to assemble complex queries in an object-oriented manner using SearchSpecifications. A SearchSpecification is a Java construct that is used to dynamically assemble the components of the query. Figure 8-2, "Search Object Model" illustrates how each component of the SQL select statement for your query against the repository can be expressed as a Java object, including the FROM clause, the WHERE clause, each EXPRESSION in the WHERE clause, and the ORDER BY clause. These various components are assembled into a SearchSpecification, which is then passed to a Search object that is used to execute the query. When Oracle 9iFS executes the query, it automatically generates the SQL select statement and runs the query against the repository. Subsequently, Oracle 9iFS returns the results of the query as an array of objects, which you can read and manipulate.
Table 8-3 illustrates how the components of a Search Specification map to the components of a SQL query.
Table 8-3 SQL to Java Comparison
In this manner, the Oracle 9iFS Search interface enables you to programmatically assemble complex queries in an object-oriented manner. Using a Java structure to define your query gives you the flexibility to manipulate each component, dynamically modify the query, and run it multiple times against the repository. It also frees you from having to know the complexities of the underlying Oracle 9iFS schema.
Oracle 9iFS uses the following Java objects to construct the components of a SearchSpecification:
The Oracle 9iFS Search object model provides another type of object, Search, to execute the query. Once the SearchSpecification is assembled, it is used to create a new search. The search is then used to:
When a search is executed, Oracle 9iFS returns as an array of result hits for each object that met the search criteria. The result hits are sorted in the array according to the sort criteria specified in the SearchSpecification. Each result hit is represented in the array by a SearchResultObject. The SearchResultObject can be used to retrieve the actual object that incurred the result hit.
The objects returned are instances of the result classes specified in the SearchClassSpecification. Each object consists of any attributes and content pertaining to the object's class.
By retrieving the object from the SearchResultObject, a search application can display and manipulate any of the object's attributes and content without having to make a second call to retrieve the object from the repository. However, if the search application needs to display or manipulate related objects (e.g., a parent folder), then the application needs to perform a second operation to retrieve the related object from the repository.
SearchSpecifications can be saved persistently in Oracle 9iFS as SearchObjects. SearchObjects store the search criteria so that users can reconstruct and execute the search at any time. Since only the search criteria is saved, the search will dynamically return the objects that currently meet the search criteria.
SearchObjects provide a powerful means for user's to access information in the repository. For example, SearchObjects could be defined to locate information pertaining to a particular topic by storing criteria about attributes and content which indicate relevance to that topic. Researchers could use the SearchObjects to more easily find information on the topic. SearchObjects could also be used to implement virtual folders that dynamically organize the repository into sets of objects that have common attributes, content, or relationships. As new objects are created in the repository, they will automatically be referenced in the virtual folders to which they pertain. In this manner, SearchObjects provide a powerful way to organize the repository without requiring users to manually place objects in folders.
Since the SearchObject class extends PublicObject, users can share SearchObjects by applying AccessControlLists. AccessControlLists specify how the SearchObject can be accessed by users and groups. SearchObjects can also be foldered to make them more accessible to users.
To learn more about applying AccessControlLists to PublicObjects, see Chapter 15, "Security".
The Oracle 9iFS Java API provides a set of Java classes for constructing and executing searches, and working with search results in custom applications. The oracle.ifs.search package includes the following Java classes for constructing the search:
The oracle.ifs.beans package includes the following two Java classes for executing the search, retrieving the search results, and saving the search criteria:
SearchSpecification is an abstract class for assembling all components of the search. AttributeSearchSpecification and ContextSearchSpecification extend this class. You do not instantiate the SearchSpecification class, but instead instantiate either of its subclasses depending on the search criteria.
The AttributeSearchSpecification class is used to construct searches that do not contain criteria about the content of documents.
Oracle 9iFS automatically optimizes the search in accordance with the nature of its criteria. A search that does not include content criteria (e.g., "find all documents whose owner is 'user1'") performs better if constructed with an AttributeSearchSpecification than if constructed with a ContextSearchSpecification.
Table 8-4 lists the most commonly used methods of the AttributeSearchSpecification class.
The ContextSearchSpecification class is used when constructing a search that contains content criteria (e.g., "find all documents whose content contains 'XML'"). The SearchQualification component of a ContextSearchSpecification should have at least one ContextQualification.
|
Note: Context is a former name of Oracle Text, the database feature used optionally by Oracle 9iFS to index the contents of documents in the repository. |
Since ContextSearchSpecification extends AttributeSearchSpecification, it possesses the same methods defined in Table 8-4. Table 8-5 lists the additional methods provided with the ContextSearchSpecification class.
The SearchClassSpecification class is used to specify the classes that will be searched. You can also specify if the search should execute recursively across any subclasses of the specified classes. When a search includes criteria that joins multiple classes of information, the SearchClassSpecification allows you to specify which classes should be returned. Table 8-6 lists the most commonly used methods of the SearchClassSpecification class.
SearchQualification is an abstract class for assembling the search criteria. AttributeQualification, FolderRestrictQualification, ContextQualification, ExistenceQualification, FreeFormQualification, PropertyQualification, JoinQualification and SearchClause extend this class, and are used to construct different types of conditions. All conditions are ultimately combined together into a single SearchQualification that is passed to the setSearchQualification() method on the SearchSpecification.
The AttributeQualification class is used to construct a condition about the value of an attribute.
Table 8-7 lists the most commonly used constants and methods of the AttributeQualification class.
The ContextQualification class is used to construct a condition about the content of documents.
Table 8-8 lists the most commonly used constants and methods of the ContextQualification class.
|
Note: For more information about syntax rules for text query strings against Oracle Text, see the Oracle9i SQL Reference Manual. |
The FolderRestrictQualification is used to construct a condition that the search should be limited to a specified folder or folder branch.
Table 8-9 lists the most commonly used methods of the FolderRestrictQualification class.
The ExistenceQualification is used to construct a condition that an attribute's value matches one of a list of possible values, or that an attribute's value matches the value of an attribute of another object.
Table 8-10 lists the most commonly used methods of the ExistenceQualification class.
The PropertyQualification represents a condition about a property in the object's PropertyBundle.
Table 8-11 lists the most commonly used methods of the PropertyQualification class.
The FreeFormQualification class is used to include any other types of conditions via a free-form string of SQL syntax.
Table 8-12 lists the most commonly used methods of the FreeFormQualification class.
|
|
Determine the String that contains the SQL expression |
JoinQualification is used to construct a join when including conditions about a related object.
Table 8-13 lists the most commonly used methods of the JoinQualification class.
|
|
Determine the left-hand side and right-hand side of the join condition. |
|
|
Retrieves the class for either attribute specified in the join condition. |
The SearchClause is used to assemble the components of the SearchQualification. SearchClause combines conditions using logical operators. SearchClause can combine other SearchClauses, allowing you to nest multiple SearchClauses into a single SearchQualification.
Table 8-14 lists the most commonly used constants and methods of the SearchClause class.
SearchSortSpecification constructs the sort order for the search results.
Table 8-15 lists the most commonly used constants and methods of the SearchSortSpecification class.
The Search class is used to execute the query and retrieve the results. When the SearchSpecification is constructed, it is passed to the setSearchSpecification() method on Search. Subsequently, the open() method is called to pass in bind variables and execute the search. At this time, Oracle 9iFS compiles a SQL select statement from the SearchSpecification and executes the query against the Oracle 9iFS schema.
Table 8-16 lists the most commonly used methods of the Search class.
The SearchResultObject class is used to work with the results of the search. The next() method returns a SearchResultObject which represents a single search result. The SearchResultObject is used to retrieve the object which met the search criteria.
Table 8-17 lists the most commonly used methods of the SearchResultObject class.
The SearchObject class is used to save search criteria persistently in the repository. The SearchObject stores a SearchSpecification so that it can be used to reconstruct and execute a search multiple times.
Table 8-18 lists the most commonly used methods of the SearchObject class.
To construct, execute, and save a search, your application performs these tasks:
The first step in building a search application is constructing a SearchSpecification. If the query includes Document content criteria, you will construct a ContextSearchSpecification. Otherwise, you will construct an AttributeSearchSpecification.
AttributeSearchSpecification asp = new AttributeSearchSpecification();
ContextSearchSpecification csp = new ContextSearchSpecification();
To specify the classes of information that will be searched and included in the search results, construct a SearchClassSpecification and pass it to the setClassSpecification() method on the SearchSpecification.
// Following code constructs a SearchClassSpecification // to represent the SELECT and FROM clauses in a query. // // e.g., SELECT Document, Category // FROM Document, Category, Folder
String [] classNames = new String[] {"Document", "Category", "Folder"}; String [] aliasNames = new String[] {"d", "c", "f"}; Boolean [] delBvrs = new Boolean [] {false, false, false}; Boolean [] recBvrs = new Boolean [] {false, true, false};
SearchClassSpecification scp = new SearchClassSpecification(classNames, aliasNames, delBvrs, recBvrs);
scp.addResultClass("Document"); scp.addResultClass("Category");
asp.setSearchClassSpecification(scp);
For each condition in the query criteria, construct an instance of the appropriate SearchQualification subclass:
To construct a condition based on the value of an attribute, you will create an AttributeQualification. To construct an AttributeQualification, specify the three primary components of the condition: the attribute, the comparison operator, and the value.
AttributeQualification aq1 = new AttributeQualification();
aq1.setAttribute(PublicObject.NAME_ATTRIBUTE); aq1.setOperator(AttributeQualification.LIKE); aq1.setValue("Oracle 9iFS");
aq1.setCaseIgnored(true);
AttributeQualification aq1 = new AttributeQualification();
LATE_BIND_OPER constant.
aq1.setAttribute(PublicObject.NAME_ATTRIBUTE); aq1.setOperator(AttributeQualification.EQUAL); aq1.setValue(SearchQualification.LATE_BIND_OPER);
AttributeQualification aq1 = new AttributeQualification();
aq1.setAttribute(PublicObject.CREATEDATE_ATTRIBUTE); aq1.setOperator(AttributeQualification.LESS_THAN);
Date today = new Date(); AttributeValue av = AttributeValue.newAttributeValue(today); aq1.setValue(av, session);
aq1.setDateComparisionLevel(AttributeQualification.DATE_COMP_DAY);
AttributeQualification aq1 = new AttributeQualification();
aq1.setAttribute(PublicObject.ACL_ATTRIBUTE); aq1.setOperator(AttributeQualification.EQUAL);
Collection aclColl = session.getSystemAccessControlListCollection(); SystemAccessControlList publicAcl = (SystemAccessControlList) aclColl.getItems("PUBLIC"); AttributeValue av = AttributeValue.newAttributeValue(publicAcl); aq1.setValue(av);
To specify the condition that the search should be restricted to objects referenced by a folder, construct a FolderRestrictQualification. FolderRestrictQualifications allow you to search in a specific folder, or across a branch of a folder hierarchy.
FolderRestrictQualification frq1 = new FolderRestrictQualification();
Folder startFolder = session.getPrimaryUserProfile().getHomeFolder(); frq1.setStartFolder(startFolder);
frq1.setMultiLevel(true);
frq1.setSearchClassname(Document.CLASS_NAME);
FolderRestrictQualification frq1 = new FolderRestrictQualification();
frq1.setStartFolder(SearchQualification.LATE_BIND_OPER);
frq1.setSearchClassName(PublicObject.CLASS_NAME);
To join search criteria based on related objects, construct a JoinQualification. A JoinQualification is comprised of two attributes that are tested for equality. When constructing the JoinQualification, you will specify the attribute and its class for each side of the comparison (e.g., Document.CreateDate = Folder.CreateDate). If you are joining two classes based on an attribute that has an object datatype, the other side of the join would only specify the class of the object that the attribute would hold (e.g., Document.Owner = DirectoryUser). Since Oracle 9iFS is an object-oriented system, attributes with an object datatype reference the object, not a specific attribute on that object.
JoinQualification jq1 = new JoinQualification();
jq1.setLeftAttribute(Document.CLASS_NAME,PublicObject.OWNER_ATTRIBUTE);
jq1.setRightAttribute(DirectoryUser.CLASS_NAME, null);
To specify a condition about the content of documents; that is, instances of the Document class and its subclasses, construct a ContextQualification. ContextQualifications are constructed from two primary components: a text query string, and a unique name.
When executing the search, Oracle 9iFS employs Oracle Text to search across an index of the document's content. When the SQL is generated, the content condition will take the form of a CONTAINS clause (e.g., CONTAINS(<index>, <text query string>, <order prefix>) > 0 ). The <index> parameter is determined by Oracle 9iFS based on the indexes generated on installation. The <text query string> is passed untouched from the value you supply to the setQuery() method. Therefore, the the value supplied to the setQuery() method must comply with Oracle Text's syntax rules for text query strings. The <order prefix> parameter is constructed by Oracle 9iFS from the value supplied to the setName() method.
When Oracle Text searches for documents based on content criteria, it ranks the documents according to their relevance to the criteria. Each document is given a score between 0 and 100, 100 representing the most relevant documents. You can sort the results of the search based on the score by including the Name of the ContextQualification in the SearchSortSpecification.
To use a ContextQualification to specify a content condition, you should:
ContentObject class or a subclass of ContentObject in the SearchClassSpecification.
ContentObject class with the Document class or Document subclass that pertain to other conditions (e.g., AttributeQualifications, FolderRestrictQualifications) about the information
ContextQualification cq1 = new ContextQualification();
cq.setQuery("XML");
String contextClauseName = "CQ1"; cq.setName(contextClauseName);
SearchSortSpecification sortSpec; sortSpec.add(Document.CLASS_NAME, ContextQualification.ORDER_PREFIX + "." + ctxClauseName, true);
String [] classNames = new String[] {"Document", "ContentObject"}; SearchClassSpecification scp = new SearchClassSpecification(classNames); scp.addResultClass("Document"); JoinQualification jq1 = new JoinQualification(); jq1.setLeftAttribute(Document.CLASS_NAME, Document.CONTENTOBJECT_ATTRIBUTE); jq1.setRightAttribute(ContentObject.CLASS_NAME, null);
To include a condition that an a Attribute matches one of a list of possible values, construct an ExistenceQualification. When constructing an ExistenceQualification, you will specify the attribute on the left-hand side of the comparison, and a list of values on the right-hand side of the comparison. The attribute can be any scalar attribute. Currently, Oracle 9iFS does not support specifying array type attributes as the left-hand side of the comparison. The list of values can be specified either as another attribute of type scalar or array, or as an AttributeValue[] array.
// Suppose you want to look for, all documents // whose name appears in STRINGVALUE attribute of any PROPERTY // Generates query - DOCUMENT.Name in (select STRINGVALUE from PROPERTY) // This shows scalar attributes on both LHS and RHS.
ExistenceQualification eq1 = new ExistenceQualification();
eq1.setLeftAttribute(Document.CLASS_NAME, PublicObject.NAME_ATTRIBUTE);
eq1.setRightAttribute(Property.CLASS_NAME, Property.STRINGVALUE_ATTRIBUTE);
// Suppose you want to look for, all documents whose name appears in // STRINGVALUES array type attribute in a property. // Generates query - DOCUMENT.Name in (select STRINGVALUES[] // from PROPERTY) // This flattens out the array attribute on the right hand side // and generates a concatenated list of all values in // STRINGVALUES attribute in each row.
ExistenceQualification eq1 = new ExistenceQualification();
eq1.setLeftAttribute(Document.CLASS_NAME, PublicObject.NAME_ATTRIBUTE);
eq1.setRightAttribute(Property.CLASS_NAME, Property.STRINGVALUES_ATTRIBUTE);
// Suppose you want to look for documents whose name is // in {"FOO", "BAR", "NOTES"}, // then you use the EQ in the following manner.
ExistenceQualification eq1 = new ExistenceQualification();
eq1.setLeftAttribute(Document.CLASS_NAME, PublicObject.NAME_ATTRIBUTE);
AttributeValue [] avArray = new AttributeValue[3]; avArray[0] = AttributeValue.newAttributeValue("FOO"); avArray[1] = AttributeValue.newAttributeValue("BAR"); avArray[2] = AttributeValue.newAttributeValue("NOTES"); eq1.setRightAttributeValue(avArray);
To specify a condition about a property in the object's PropertyBundle, construct a PropertyQualification. PropertyQualifications are comprised of: the name of the property, the value of the property, and a comparison operator. The value must be supplied as an instance of AttributeValue so that Oracle 9iFS can automatically compare the value to the property's Value attribute regardless of its datatype. In addition, constructing a PropertyQualification will automatically add another Search class for the class of the object that possesses the PropertyBundle.
PropertyQualification pq = new PropertyQualification();
pq.setClassname(Document.CLASS_NAME);
pq.setPropertyName("color"); pq.setOperatorType(AttributeQualification.EQUAL); pq.setValue(AttributeValue.newAttributeValue("RED")); pq.setCaseIgnored(ignoreCase);
PropertyQualification.
PropertyQualification pq = new PropertyQualification();
pq.setClassname(Document.CLASS_NAME);
pq.setPropertyName("expire-date"); pq.setOperatorType(AttributeQualification.EQUAL); pq.setValue( AttributeValue.newAttributeValue( new GregorianCalendar(1995, 0, 15).getTime())); pq.setDateComparisonLevel(AttributeQualification.DATE_COMP_MONTH); // Using DOCUMENT(or any object type) type attribute value // This looks for a particular document in a property // containing DOCUMENT objects
PropertyQualification.
PropertyQualification pq = new PropertyQualification();
pq.setClassname(Document.CLASS_NAME);
pq.setPropertyName("related-docs"); pq.setOperatorType(AttributeQualification.EQUAL); pq.setValue(AttributeValue.newAttributeValue(new Document[] {d}));
PropertyQualification.
PropertyQualification pq = new PropertyQualification();
pq.setClassname(Document.CLASS_NAME);
AttributeValue srchDate = AttributeValue.newAttributeValue( new GregorianCalendar(1995, 0, 1).getTime()); pq.setPropertyName("expire-date"); pq.setOperatorType(AttributeQualification.EQUAL); pq.setLateBoundDataType(srchDate.getDataType());
To include an ad-hoc SQL expression in the WHERE clause generated by Oracle 9iFS, construct a FreeFormQualification. The FreeFormQualification class provides a hook for advanced developers to specify search criteria that cannot be constructed by Oracle 9iFS. For example, a custom search application may need to build a search based on Oracle Text indexes on an attribute (e.g., Description) that is not full-text indexed automatically by Oracle 9iFS. To do so, the application can construct a FreeFormQualification that constructs a CONTAINS() function on that attribute. Or, an application may need to use other SQL functions (e.g., SUM) that are not yet automatically generated by the Oracle 9iFS API.
The SQL expression specified in the FreeFormQualification will not be validated by Oracle 9iFS. In addition, FreeFormQualifications don't support late binding. Therefore, the SQL string cannot contain '?'.
Using FreeFormQualifications requires that you have a good understanding of the Oracle 9iFS schema. The search application can only access secure tables in the Oracle 9iFS schema if the current session user is an administrator and if AdministrationMode is turned on for the session (e.g., ifsSession.setAdministrationMode(true)).
The SQL generated by the FreeFormQualification is inserted into the WHERE clause generated by Oracle 9iFS. Therefore, you can not use FreeFormQualifications for executing DDL or DML statements, nor for constructing complete SQL select statements.
// Create a FreeFormQualification to find CONTENTOBJECTS // that are greater than the average content size.
FreeFormQualification ffq= new FreeFormQualification();
String sqlExpression = "co.contentsize > " + "(select AVG(contentsize) " + "from odm_contentobject c, odm_document d " + "where c.id = d.contentobject)"); ffq.setSqlExpression(sqlExpression);
If your search includes more than one condition, combine the conditions into a single SearchQualification. After constructing each condition as an instance of the corresponding SearchQualification subclass, combine the conditions together into a tree of nested criteria by constructing SearchClauses. Pass the resulting SearchClause to the setSearchQualification() method to set the search criteria for the SearchSpecification.
SearchClauses can be used to combine two conditions together with Boolean operators (e.g., AND and OR). In this case, the SearchClause is comprised of a left-hand side condition, right-hand side condition, and the Boolean operator.
SearchClauses can also be used to construct negative statements with the operator NOT. In this case, the SearchClause is comprised of the operator, and the right-hand side condition.
You can nest SearchClauses by passing a SearchClause in as the left-hand and/or right-hand side of another SearchClause (e.g., <condition> OR (<condition> AND <condition>)).
/* * SearchClauses are used to construct the following WHERE statement: * WHERE (Document.contentobject = ContentObject * AND ContentObject.Format = Format) * AND (Document.name = ? AND Format.extension = 'html') * OR (Document.owner = ? AND Format.name = 'MS Word') */
JoinQualification jq1 = new JoinQualification(); jq1.setLeftAttribute("DOCUMENT", "CONTENTOBJECT"); jq1.setRightAttribute("CONTENTOBJECT");
JoinQualification jq2 = new JoinQualification(); jq2.setLeftAttribute("CONTENTOBJECT", "FORMAT"); jq2.setRightAttribute("FORMAT");
AttributeQualification aq1 = new AttributeQualification(); aq1.setAttribute("DOCUMENT", "NAME"); aq1.setOperatorType("="); aq1.setValue("?"); AttributeQualification aq2 = new AttributeQualification() aq2.setAttribute("FORMAT", "EXTENSION"); aq2.setOperatorType("="); aq2.setValue("html");
AttributeQualification aq3 = new AttributeQualification(); aq3.setAttribute("DOCUMENT", "OWNER"); aq3.setOperatorType("="); aq3.setValue("?"); AttributeQualification aq4 = new AttributeQualification(); aq4.setAttribute("FORMAT", "NAME"); aq4.setOperatorType("="); aq4.setValue("MS Word");
SearchClause sc1 = new SearchClause(aq1, aq2, SearchClause.AND); SearchClause sc2 = new SearchClause(aq3, aq4, SearchClause.AND); SearchClause sc3 = new SearchClause(jq1, jq2, SearchClause.AND); SearchClause sc4 = new SearchClause(sc1, sc2, SearchClause.OR); SearchClause scComplete = new SearchClause(sc3, sc4, SearchClause.AND);
Alternatively, the SearchClause class provides methods that you can use to build and retrieve the clause with more granular control. This may be useful if you want to reuse or manipulate components of the SearchClause in the application.
JoinQualification jq1 = new JoinQualification(); jq1.setLeftAttribute("DOCUMENT", "CONTENTOBJECT"); jq1.setRightAttribute("CONTENTOBJECT");
JoinQualification jq2 = new JoinQualification(); jq2.setLeftAttribute("CONTENTOBJECT", "FORMAT"); jq2.setRightAttribute("FORMAT");
AttributeQualification aq1 = new AttributeQualification(); aq1.setAttribute("DOCUMENT", "NAME"); aq1.setOperatorType("="); aq1.setValue("?");
aq2.setAttribute("FORMAT", "EXTENSION"); aq2.setOperatorType("="); aq2.setValue("html");
AttributeQualification aq3 = aq2.clone(); aq3.setValue("txt");
SearchClause sc1 = new SearchClause(); sc1.setLeftSearchQualification(aq1); sc1.setRightSearchQualification(aq2); sc1.setOperatorType(SearchClause.AND);
SearchClause sc2 = sc1.clone(); sc2.setRightSearchQualification(aq3); sc2.setOperatorType(SearchClause.AND);
SearchClause sc3 = new SearchClause(jq1, jq2, SearchClause.AND); SearchClause sc4 = new SearchClause(sc1, sc2, SearchClause.OR); SearchClause scComplete = new SearchClause(sc3, sc4, SearchClause.AND);
To specify the sort order for the search results, construct a SearchSortSpecification. The SearchSortSpecification class provides methods for specifying the attributes and their classes that will be used to order the results. The class also provides constants and methods for specifying whether the results should be listed in ASCENDING or DESCENDING order.
The easiest way to construct a SearchSortSpecification is by using the following constructor to initialize it with a set of sort criteria:
SearchSortSpecification ss = new SearchSortSpecification( new String[] {"CATEGORY", "FOLDER"}, new String[] {"NAME", "NAME"}, new boolean[] {SearchSortSpecification.ASCENDING, SearchSortSpecification.ASCENDING});
Alternatively, the SearchSortSpecification class provides methods that you can use to build and retrieve the sort criteria with more granular control. This may be useful if you want to reuse or manipulate components of the SearchSortSpecification in the application.
SearchSortSpecification ss = new SearchSortSpecification(); ss.add("CATEGORY", "NAME", SearchSortSpecification.ASCENDING); ss.add("FOLDER", "NAME", SearchSortSpecification.ASCENDING);
Once the query criteria has been assembled into a SearchSpecification, execute the query with the Search class. The Search class provides methods for passing in bind variables and executing the search. The Search class also provides methods for traversing the results of the search.
AttributeSearchSpecification asp = new AttributeSearchSpecification();
SearchClassSpecification scp = new SearchClassSpecification("DOCUMENT'); asp.setSearchClassnames(scp);
AttributeQualification aq3 = new AttributeQualification(); aq.setAttribute("DOCUMENT", "OWNER"); aq.setOperatorType("="); aq.setValue("?"); asp.setSearchQualification(aq);
Search srch = new Search(session, asp);
AttributeValue[] bindValues = new AttributeValue[1]; DirectoryUser dsUser = session.getDirectoryUser(); bindValues[0] = AttributeValue.newAttributeValue(dsUser);
srch.open(bindValues);
srch.close();
To fetch the results of your search, you can use the open() method to open a cursor on the search and then use the next() method to fetch each resulting object. The next() method will return a SearchResultObject that represents a single search hit. Subsequently, you can call the getLibraryObject() method on the SearchResultObject to retrieve the piece of information that incurred the hit by meeting the search criteria.
open() method executes the query.
srch.open(bindValues);
int i; SearchResultObject sro = srch.next(); LibraryObject lo; while (sro != null) { lo = sro.getLibraryObject(); try { sro = srch.next(); } catch (IfsException e) { if (e.getErrorCode() == 22000) { break; } else { e.printStackTrace(); } } }
srch.close();
To save the search criteria persistently in the repository, you can construct a SearchObject from the SearchSpecification. To construct a SearchObject, follow these steps:
SearchSpecification ss = ....
SearchObjectDefinition sod = new SearchObjectDefinition(session); sod.setAttributeByUpperCaseName("NAME", AttributeValue.newAttributeValue("XML Research")); Collection aclColl = session.getSystemAccessControlListCollection(); AccessControlList acl = (AccessControlList) aclColl.getItems("Public"); sod.setAttributeByUpperCaseName("ACL" AttributeValue.newAttributeValue(acl)); Folder folder = session.getUser().getPrimaryUserProfile().getHomeFolder(); sod.setAddToFolderOption(folder);
sod.setSearchSpecification(ss);
SearchObject so = session.createPublicObject(sod);
Oracle 9iFS is installed with sample code that helps you get started working with the Java API. The API sample code is located in the <ORACLE_HOME>/9ifs/samplecode/oracle/ifs/examples/devdoc/api directory.
Table 8-19 lists the API sample code that is relevant to this chapter.
|
|
![]() Copyright © 2001 Oracle Corporation. All Rights Reserved. |
|