Oracle® Fusion Applications Developer's Guide 11g Release 7 (11.1.7) Part Number E15524-08 |
|
|
PDF · Mobi · ePub |
This chapter provides information on advanced topics for Oracle Enterprise Crawl and Search Framework (ECSF), including enabling and managing search, and troubleshooting ECSF.
This chapter includes the following sections:
Section 32.4, "Enabling Search on Tree Structure-based Source Systems"
Section 32.9, "Using the External ECSF Web Service for Integration"
ECSF offers additional functionality to enhance the search experience. In addition to search on business objects, ECSF supports search on Fusion file attachments, WebCenter tags, and tree structure-based source systems. ECSF also allows you to set up federated search so that users can search across Oracle Fusion Applications product families or across multiple Oracle Secure Enterprise Search (Oracle SES) instances.
Advanced topics also include using the external ECSF web service to integrate ECSF with Oracle Fusion Applications, localizing ECSF artifacts for international users, and information for troubleshooting ECSF.
ECSF supports the capability to crawl Oracle Fusion Applications file attachments that are associated with ECSF searchable objects and stored in the Oracle WebCenter Content repository.
References to files in the content repository are stored in a special database table and are retrieved by using a view object named oracle.apps.fnd.applcore.attachments.uiModel.view.AttachmentsVO
. Using a view link, you can make the AttachmentsVO
a child of another view object. If a searchable object has a child AttachmentsVO
, then ECSF automatically makes sure that the attachments are crawled when the searchable object is crawled.
At the time the searchable object is crawled, ECSF includes a content link in the document that is sent to Oracle SES for each attachment. When Oracle SES receives the data feed and finds the content link, it calls back to ECSF to retrieve the content of the attachment. ECSF then invokes an application programming interface (API) method that retrieves the attachment content from the content server and returns it to Oracle SES. Oracle SES indexes the searchable object and attachment content as one item.
The API handles authentication and authorization.
To make file attachments crawlable:
Add the Applications Core (Attachments) library to your project.
This adds the Attachment-Model.jar
and Common-Model.jar
files, located in JDEV_HOME
\jdeveloper\jdev\oaext\adflib
, to your projects.
Create a view link between the searchable object and the AttachmentsVO
to make AttachmentsVO
a child of the searchable object.
Note:
When you design your view object for search, make sure that you configure view links to generate only the Destination Accessor and not the Source Accessor.
On the searchable object, define a view link accessor that points to the view link. For information, see Section 18.2.2, "How to Create Attachment View Links."
ECSF supports the capability to crawl searchable objects with Oracle WebCenter Portal tags so that tags can be used as keywords or filters for search in Oracle Fusion Applications. A tag is a meaningful term attached to an object. Tags can be used for various purposes such as categorization, to-dos, and priorities. For more information, see the "Integrating the Tags Service" chapter in Oracle Fusion Middleware Developer's Guide for Oracle WebCenter Portal (Oracle Fusion Applications Edition).
Note:
ECSF does not support search using private tags.
Tags are single words stored as space-separated strings in the application database and are retrieved by using a view object called TagSVO
(service view object). You must create a view link to make TagSVO
a child object. At crawl time, the view link is used to locate TagSVO
. Figure 32-1 illustrates crawl time with tags.
Purchase Order 123 has two tags, Computer
and Dell
. ECSF adds the tags for each record of the searchable object to the indexable document before the document is sent to Oracle SES for indexing. ECSF also creates a reserved attribute (of type string) called ECSF_TAGS
to store tags in Oracle SES.
At query time, users can specify tag values as keywords or as filters. When tag values are input as keywords, the tag value is treated as a query string and returns results that include the objects with the specified tag. When tag values are used as filters, the tags are added to QueryMetaData
and the query is run with filters on ECSF_TAGS
. Only the objects with the specified tags are returned. Figure 32-2 and Figure 32-3 illustrates the difference between query time without a tag and query time with a tag.
Note:
Tags cannot be searched as individual entities.
In Figure 32-2, the indexed document for Purchase Order 123 contains two tags, Computer
and Dell
. The query on John
returns all the documents that contain John
. The results display the title, body, and all tags for the documents.
In Figure 32-3, query on the Purchase Order John
and tag Dell
returns only the documents that contain John
AND the Dell
tag. The results display the title, body, and all tags for the documents. If both Dell
and Computer
were specified as tags, then the query would return only the documents that contain both tags (that is, Dell
AND Computer
). You cannot specify tags using the OR condition (that is, Dell
OR Computer
), so the query cannot return documents that contain either the Dell
tag or the Computer
tag.
Enabling search on WebCenter Portal tags allows tags to be added to indexable documents and stored in the reserved attribute called ECSF_TAGS
in Oracle SES. Tags can then be used as keywords or filters for search.
Perform the following tasks to enable search on WebCenter Portal tags:
Create a view link between the searchable object and the TagSVO
. For information, see Section 14.6.5, "How to Implement Tags in Oracle Fusion Applications Search."
Note:
When you design your view object for search, make sure that you configure view links to generate only the Destination Accessor and not the Source Accessor.
The view link must use the accessor name tagSVO
so that the search extension can navigate to the child object when it crawls.
Add tags to the indexable document.
Add tags to the query.
You can also perform the following tasks to customize search on WebCenter Portal tags:
Modify the tags in the indexable document.
Register change listeners.
To crawl tags, you must use Tag APIs to add tags to indexable documents. You can use Tag APIs in the search extension code.
To add tags to indexable documents:
Create a search extension that extends DefaultSearchPlugin
, implements PreIndexProcessor
, and includes a method called preIndexProcess
that adds tags to some objects.
Note:
If you place the search extension in the Oracle WebLogic Server shared library, then the ECSF library (ecsf.jar
) must be present in the shared library in order for ECSF to load the PreIndexProcessor
interface.
Redeploy and crawl the objects.
You can implement code, such as the sample code shown in Example 32-1, in the search extension to extend DefaultSearchPlugin
.
Example 32-1 Sample Code for Adding Tags to Indexable Documents
public class runtime.TestPlugin extends DefaultSearchPlugin implements PreIndexProcessor { public void preIndexProcess(SearchContext ctx, List <IndexableDocument> documents) { for( IndexableDocument doc : documents) { Object ename = doc.getFieldValue("ENAME"); if (ename != null && "Zebra".equalsIgnoreCase(ename.toString())) { doc.addTags(new String[] { "Black","White","Stripes" }); //doc.getTags and doc.clearTags can also be used here for(String tag : doc.getTags()) { system.err.println(tag);//print out tag to stand err } } } } }
This extension adds three tags (Black
, White
, and Stripes
) to a user named Zebra
.
After tags are crawled into Oracle SES, you can perform keyword searches on tags or filter on tags. QueryMetaData
accepts tags for querying. When one or more tags are added to QueryMetaData
, the query runs with filters on ECSF_TAGS
.
Example 32-2 illustrates how tags are used for querying.
Example 32-2 Sample API for Querying With Tags
public void tagTest() { SearchCtrl searchCtrl = new SearchCtrl(); SearchHits searchHits = null; SearchContext searchContext = null; QueryMetaDataImpl queryMetaData = new QueryMetaDataImpl(); queryMetaData.setQueryString("%"); queryMetaData.setPageSize(10); queryMetaData.setCurrentPage(1); String engineInstName = "SES"; String groupName = "runtime.EmpView"; SearchGroup[] sgs = new SearchGroup[] {searchCtrl.getSearchGroup(engineInstName , groupName); queryMetaData.setSearchGroups(sgs); searchContext = ContextFactory.getSearchContext(); searchContext.bindUser("scott"); try { //clear tags so query tag through keywords queryMetaData.clearTags(); queryMetaData.setQueryString("Black White"); searchHits = searchCtrl.runQuery(searchContext, queryMetaData); //Zebra is found //filter by tags queryMetaData.setQueryString("%"); queryMetaData.addTag("White"); searchHits = searchCtrl.runQuery(searchContext, queryMetaData); //Mickey is found //filter by tags queryMetaData.addTag("White"); queryMetaData.addTag("Black"); searchHits = searchCtrl.runQuery(searchContext, queryMetaData); //Zebra is found //filter by tag that exists and tag that does not exist queryMetaData.clearTags(); queryMetaData.addTag("Stripes"); queryMetaData.addTag("Dots"); searchHits = searchCtrl.runQuery(searchContext, queryMetaData); //no result is found //filter by tag that does not exist queryMetaData.clearTags(); queryMetaData.addTag("Dots"); searchHits = searchCtrl.runQuery(searchContext, queryMetaData); //no result is found }
Adding tags for querying forces the query to find results where indexed documents contain the added tags. When more than one tag is added, the resulting documents must contain both tags. Documents containing only one of the tags are not returned.
Query SES retrieves tags all the time. The searcher adds tags to IndexedDocument
by using setTags
. In case of null
in the attribute, no tags are added. IndexedDocument.getTags
returns all the tags in the document.
You can override tags in the lifecycle methods provided by ECSF. For example, if required, you can add tags to an indexable document in the IndexablePostProcess
by using the APIs provided on the IndexableDocument
:
void addTags(String[] tags)
adds a list of strings as tags to the document. Duplicates are removed.
Collection<String> getTags()
returns a list of tags associated with the document.
void clearTags()
clears tags associated with the document.
You can extend the incremental crawling mechanism by registering change listeners, which use the WebCenter Portal tagging framework to identify objects that need to be updated in the search engine. Implement the oracle.ecsf.ChangeListener
interface in a search extension to customize the runtime logic that detects changes in the searchable objects. Example 32-3 illustrates a sample implementation of ChangeListener
.
Example 32-3 Sample Implementation of ChangeListener
public class TestPlugin extends DefaultSearchPlugin implements ChangeListener { public Iterator getChangeList(SearchContext ctx, String changeType) { return new MyChangeIterator(ctx, changeType); } } public class MyChangeIterator extends ChangeIterator { private Date lastTimeCrawled; private int mCount; private int mIndex = 0; public MyChangeIterator (SearchContext ctx, String changeType) { super(ctx, changeType); Date lastTimeCrawled = ctx.getSearchableObject().getLastTimeCrawled(); //if this value is null, ECSF is doing an initial crawl if(lastTimeCrawled==null) { setDone(true); }else { //find how many has been changed since that date mCount = 100; //example } } protected List populate(SearchContext ctx) { List nextList = new ArrayList(); //the following code marks Zebra has been changed PrimaryKey pk = new PrimaryKey(); Pk.put("ENAME", "Zebra"); NextList.add(pk); setDone(true); //tells ECSF there are no more return nextList; } }
The method Iterator getChangeList (SearchContext ctx, String changeType)
returns an iterator (ChangeIterator
) over a list of primary keys for the searchable object (ctx.getSearchableObject
).
The primary keys returned from the change listener are logged in the ECSF change log table before an incremental control feed is constructed.
In addition to supporting the crawling and searching of relational-based objects through view objects or Java Database Connectivity (JDBC), ECSF supports the capability to crawl data in hierarchical tree-based data structures, or tree structures, and to identify items for indexing to enable full-text search. A tree structure is a common data structure, such as a file system on a computer hard disk, used to organize a large number of items. Oracle Business Intelligence is an example of a source system that is organized in a tree structure. For more information about Oracle Business Intelligence Suite Enterprise Edition and its supported search functionality, see the "Managing Objects in the Oracle BI Presentation Catalog" chapter in Oracle Business Intelligence Suite Enterprise Edition User's Guide.
By default, ECSF supports database crawling using Oracle ADF technology. To support crawling data that is organized in tree structures, you can extend the abstract implementation of the CrawlableFactory oracle.ecsf.data.tree.AbstractTreeWalker
. The extension converts the data stored at tree nodes into documents that Oracle SES receives through Really Simple Syndication (RSS) feeds and indexes.
Note:
Crawling relies on the integrator's implementation that is based on their underlying data structures and accessibility of the items to be indexed.
Note:
ECSF currently does not provide an interface for converting information in source systems to indexable documents. It is assumed that data structures of an indexable item are proprietary to the source system, and the interface for converting an item pertaining such a structure to indexable document are the responsibility of the integrator.
A searchable object holds metadata about the source system. It can be either an Oracle ADF view object with ECSF annotation or a class that extends oracle.ecsf.meta.SearchableObject
. For tree structure-based source systems, the searchable object is not view object-based, so ECSF does not load the view object. Instead, it loads a Java class that extends and implements the searchable object. When requested with a ConfigFeed
URL, ECSF identifies the searchable object that holds the search metadata required by ECSF. Non-view object-based searchable objects can be grouped into search categories. Figure 32-4 illustrates the data flow for search on tree structure-based source systems.
Figure 32-4 Data Flow for Search Using ECSF Tree Crawler
The integration of ECSF with the source system allows an Oracle SES instance to crawl the source system data. The Source System DataNode
, which is exposed to the ECSF tree crawler, formulates the data structure and pulls data from the source system server using web services. ECSF converts the tree nodes into documents that Oracle SES receives through RSS feeds and indexes. The source system implements a security service. When data from the source system is indexed in the Oracle SES, it is guarded against access by the security service.
A security extension is needed to implement source and document-level security. A searchable object has a method of getting a search extension instance based on the metadata. To associate a search extension with a searchable object, configure it from the Search navigation tab of the overview editor in JDeveloper. For more information, see Section 28.2.3, "How to Make View Objects Searchable."
ECSF also extends its attachment implementation to enable the implementer to open the stream for data pulling attachments that are associated with a particular node. For more information, see Section 32.2, "Enabling Search on Fusion File Attachments."
Enable search on tree structure-based source systems by:
Crawling tree structures
Integrating search functionality for tree structures
Implementing administration using ECSF interfaces
ECSF offers Java classes that provide support for traversing tree structure-based data sources and identifying items for indexing. To implement search for these data sources, complete the following tasks:
Create a searchable object by extending the oracle.ecsf.data.tree.SearchableTreeObject
class.
Implement a crawlable tree node to extract document metadata.
Extend AbstractTreeWalker
to traverse the tree.
Implement security.
Implement the attachments interface to stream the documents to Oracle SES.
Deploy and start the ECSF servlet.
Configure Oracle SES to crawl ECSF.
Before you begin:
Install the ECSF seed data records in the ECSF schema of the Oracle Fusion Applications database using Seed Data Framework (SDF). For information, see Chapter 56, "Initializing Oracle Fusion Application Data Using the Seed Data Loader."
Create a searchable object by extending the oracle.ecsf.data.tree.SearchableTreeObject
class, as shown in Example 32-4. When you create a searchable object for a tree object, you create a Java class, the SearchableTreeDirectory
class, that is part of your implementation Java archive (JAR) file.
Example 32-4 Sample Code for SearchableTreeDirectory Class
package oracle.ecsf.test.tree; import oracle.ecsf.data.tree.SearchableTreeObject; public class SearchableTreeDirectory extends SearchableTreeObject { //override the security plug to be used public void initializeConfig() { setPlugInName(SecurityPlugin.class.getName()); //add a custom attribute //see processNode method where you must set attribute value //for this attribute for the indexable document DocumentDefinition docdef = this.getDocument(); FieldDefinitionImpl field = new FieldDefinitionImpl("CUSTOM_ATTR"); field.setBinding("CUSTOM_ATTR"); //this flag indicates that this attribute be stored in SES field.setStored(true); docdef.addField(field); } //override the crawlable factory to be used public String getCrawlableFactoryName() { return FileTreeCrawler.class.getName(); } //override the method to get the location and the name of the last crawled timestamp file //this is optional, if it is not overridden, the default location is the temporary directory of the //system, that is, in unix/linux, it is "/tmp" and in Windows, it is "c:/temp"; the default file name is // ".ecsf." concatenated with the object name, in this case "oracle.ecsf.test.tree.SearchableTreeDirectory" public String getFileName() { return "./.ecsf.oracle.ecsf.test.tree.SearchableTreeDirectory"; } }
You must override the initializeConfig
method to create search metadata dynamically for your searchable object, including adding a custom attribute, setting the security plug-in class name, and so on.
You must override getCrawlableFactoryName()
to return the class name of your extension of AbstractTreeWalker
.
Override getFileName
if you want to persist the last crawled timestamp in a particular location.
For information, see Section 32.4.1.3, "Extending AbstractTreeWalker."
A crawlable tree node represents a node in your tree structure. When crawled, each node on the tree structure is wrapped in this object. This node is created by the extension of AbstractTreeWalker
. For more details on each method, see the Javadoc for ECSF.
Implement a crawlable tree node by extending the oracle.ecsf.data.tree.CrawlableTreeNode
class to create a tree node class called CrawlableTreeNodeImpl
, as shown in Example 32-5, for extracting document metadata. The tree node class models the tree structure repository.
Example 32-5 Sample Code for CrawlableTreeNodeImpl Class
package oracle.ecsf.data.tree; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.Date; import oracle.ecsf.IndexableDocument; import oracle.ecsf.meta.PrimaryKey; import oracle.ecsf.data.tree.CrawlableTreeNode; public class CrawlableTreeNodeImpl extends CrawlableTreeNode { String[] filesToHandle=new String[]{"java", "xml"}; private File file; //Creates a node with a fully qualified name. public CrawlableTreeNodeImpl(String name) { super(name); file = new File(name); this.setPath(file.getPath()); this.setName(file.getName()); } //Internal. Determine whether a file should //be indexed. private boolean handleFile(File file) { if(file ==null) return false; if(file.isDirectory()) return false; for(String ext : filesToHandle) { if(file.getName().endsWith(ext)) return true; } return false; } //Test if a file must be indexed. public boolean isIndexable() { return handleFile(file); } /* * Gets the last modified date. */ public Date getLastModified() { if (file == null) { return null; } else { return new Date(file.lastModified()); } } public void processNode(IndexableDocument doc) { try { StringBuffer indexContent = new StringBuffer(); FileReader fileReader = new FileReader(file); BufferedReader br = new BufferedReader(fileReader); String strd = br.readLine(); while (strd != null) { indexContent.append("\n" + strd); strd = br.readLine(); } if (file.getName().endsWith("xml")) { PrimaryKey keys = new PrimaryKey(); keys.put("Name", file.getName()); keys.put("Path", file.getPath()); doc.addAttachment(new AttachmentImpl(keys)); } br.close(); fileReader.close(); doc.setContent(indexContent.toString()); doc.setFieldValue("CUSTOM_ATTR", "This is custom attributes to be saved in SES"); doc.setAttributeValue("CUSTOM_ATTR", "This value is custom attribute value"); doc.overrideAccessURL("path=" + file.getPath() + "&name="+file.getName()); } catch (Exception e) { //handle errors } } protected void init() { super.init(); if (!isLeaf()) { File[] files = file.listFiles(); if (files != null) { for (int i = 0; i < files.length; i++) { addChildNode(new CrawlableTreeNodeImpl(files[i].getAbsolutePath())); } } } } private static boolean isLink(File file) { try { if (!file.exists()) { return true; } else { String cnnpath = file.getCanonicalPath(); String abspath = file.getAbsolutePath(); return !abspath.equals(cnnpath); } } catch (IOException ex) { System.err.println(ex); return true; } } public boolean isLeaf() { return file == null "example" --> In the processNode method, you must extract any metadata information about the document (for example, setTitle, setKeyword, setContent) and populate the indexable document that is passed in. You can also add any custom attributes to the indexable documents, such as the isLeaf method that determines whether a node is a folder or a document. This method is used by the crawlable factory to determine how to traverse the tree.
To provide the methods that enables Oracle SES to traverse tree structures and index the content items, extend AbstractTreeWalker
by creating the abstract tree crawler class, called FileTreeCrawler
, as shown in Example 32-6. FileTreeCrawler
is invoked as a factory to create a crawlable tree node as defined in Section 32.4.1.2, "Implementing a Crawlable Tree Node." The tree walker works with CrawlableTreeNode
to provide the generic framework for traversing a tree structure and indexing the content items in the repository. It also uses TreeSplitter
to divide the repository into branches to enhance the crawling performance.
Example 32-6 Sample Code for FileTreeCrawler Class
package oracle.ecsf.data.tree; import oracle.ecsf.meta.SearchableObject; public class FileTreeCrawler extends AbstractTreeWalker { // //The application determine the root path. // String root="/home/cbrown"; /** *Constructs a CrawlableFactory from a searchable object. */ public FileTreeCrawler() { super(); } public FileTreeCrawler(SearchableObject searchableObject) { super(searchableObject); } // //Creates root node // public CrawlableTreeNode createCrawlable() { return new CrawlableTreeNodeImpl(root); } // //Creates a node for a given path //if you cannot construct the path. // public CrawlableTreeNode createCrawlable(String path) { return new CrawlableTreeNodeImpl(path); } //Tests if a node is crawlable protected boolean isIndexable(CrawlableTreeNode node) { CrawlableTreeNodeImpl fNode = (CrawlableTreeNodeImpl) node; return fNode.isIndexable(); } }
When Oracle SES crawls the searchable object, an instance of FileTreeCrawler
is created by ECSF. It traverses the tree structure by calling the methods defined in the FileTreeCrawler
class. It goes through two passes. First, it collects only the structure information, and based on that, it forms a control feed that contains all the folders that need to be visited for collecting documents. The isIndexable
method determines whether a particular node is indexed by Oracle SES. You can also use it to place filters to control the type of document to be indexed.
When creating the FileTreeCrawler
class, you must implement two constructors. One takes no parameters, and the other takes a searchable object where you can perform configurations specific to your application, if required.
Security rules on the documents indexed by Oracle SES is controlled by access control lists (ACLs). This is achieved by creating a search plug-in that implements the oracle.ecsf.Secure
interface for the searchable object. When you implement a security extension for the searchable object, it is used to serve as the authorization module for indexed content in Oracle SES.
Note:
ECSF uses the generic term ACL to describe how Oracle SES and ECSF pass security information and perform security checks by using the information described in the ACL.
ECSF is secured by a plugable security service, which is called when users try to search the indexed content. By default, ECSF provides an implementation based on Oracle Platform Security for Java. It is mainly used for authenticating and authorizing users into the system. However, if you have a non-Oracle security provider, or you want to use your own security implementation, you must extend the ECSF security service. Example 32-7 illustrates the skeleton of a security extension.
Example 32-7 Sample of Security Service
package oracle.ecsf.data.tree; import oracle.ecsf.SearchContext; import oracle.ecsf.SecurityService; import oracle.ecsf.util.SecurityServiceFactory; public class SecurityServiceImpl implements SecurityService{ public String[] listSupportedFormats() { return new String[]{"BIEE"}; } public String authenticate(SearchContext ctx, String userName, String password, String format) { return userName; } public String isUserValid(SearchContext ctx, String userName, String format) { return userName; } public String[] getSecurityValues(SearchContext ctx, String userName, String attrName, String objectId) { //Get keys for an attribute. return new String[]{}; } }
The security extension is a Java class that implements a securable interface. There are five methods available. Example 32-8 illustrates the skeleton of such class.
Example 32-8 Sample Security Extension
package oracle.ecsf.data.tree; import oracle.ecsf.IndexableDocument; import oracle.ecsf.SearchContext; import oracle.ecsf.SearchSecurityException; import oracle.ecsf.Securable; public class SecurityPlugin implements Securable{ public boolean isAclEnabled(SearchContext ctx) { return true; } //The ACL for the document public String[] getAcl(SearchContext ctx, IndexableDocument doc) { return new String[]{"cbrown"}; } //The keys to the ACL for the document for ctx.getUserName() public String[] getSecurityKeys(SearchContext ctx) { return new String[]{}; } //The ACL for the document, hashed against an attribute public String[] getSecureAttrAcl(SearchContext ctx, IndexableDocument doc, String attributeName) { return new String[]{}; } //The keys to the ACL for the document for ctx.getUserName(), hashed agains an attribute public String[] getSecureAttrKeys(SearchContext ctx, String attributeName) { return new String[]{}; } //Returns configuration parameters for the extension, not used often public String[] getSecurableParams() throws SearchSecurityException { return new String[]{}; } }
Your search plug-in must be assigned to the searchable object, as shown in Example 32-4.
Implementing the attachments interface, shown in Example 32-9, allows you to index binary files such as Word documents, Excel spreadsheets, PDF files, and so on.
Example 32-9 Attachments Interface Implementation
package oracle.ecsf.data.tree; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.OutputStream; import java.util.HashMap; import java.util.Map; import oracle.ecsf.Attachment; import oracle.ecsf.SearchContext; import oracle.ecsf.meta.PrimaryKey; public class AttachmentImpl implements Attachment { PrimaryKey primaryKey; public AttachmentImpl() { } public AttachmentImpl(Map map) { primaryKey = new PrimaryKey(); primaryKey.putAll(map); } public String getType() { return "text/xml"; } public void initialize(SearchContext ctx, Map paramMap, PrimaryKey keys) { primaryKey = new PrimaryKey(); primaryKey.putAll(keys); } public void read(SearchContext ctx, OutputStream stream) { String path = (String)primaryKey.get("Path"); File file = new File(path); try { FileReader fileReader = new FileReader(file); BufferedReader br = new BufferedReader(fileReader); String strd = br.readLine(); while (strd != null) { stream.write(strd.getBytes()); strd = br.readLine(); } } catch (IOException e) { //Handle errors } } //Contains configuration parameters needed to read the attachment //This map can be an empty one as shown in this example. public Map getParameters() { Map parameters = new HashMap(); return parameters; } //Name value pairs need to identify a specific attachment. public PrimaryKey getPrimaryKey() { return primaryKey; } }
After you implement this class, you can add any number of attachments to an indexable document in the processNode
method of CrawlableTreeNode
. The attachment must contain enough information in its primary key for you to open the attachment when requested by the read method, where you simply use the information stored in the primary key to read the document and write to the output stream passed to you.
Before Oracle SES can crawl your file system, you need an Oracle WebLogic Server instance to which you can deploy the ECSF servlet. For example, you can use the Integrated WebLogic Server container.
To deploy and start the ECSF server:
Create a Java project in JDeveloper.
Add ecsf.jar
to its class path.
Develop your extensions.
Edit web.xml
to add the servlet mapping in Example 32-10.
Example 32-10 SearchFeedServlet Mapping
<servlet> <servlet-name>SearchFeedServlet</servlet-name> <servlet-class>oracle.ecsf.feed.SearchFeedServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>SearchFeedServlet</servlet-name> <url-pattern>/searchfeedservlet/*</url-pattern> </servlet-mapping>
To use a custom security service, you must add -Doracle.ecsf.security.service=
classnameOfSecurityService
. Otherwise, Oracle Platform Security for Java security service is used.
Open ecsf.jar
, right-click oracle.ecsf.feed.SearchFeedServlet
, and select Run. The ECSF servlet starts, and the system is ready to be crawled.
Oracle SES must be installed, then configured to crawl ECSF. Install Oracle SES 11.2.1, then perform the following steps to configure Oracle SES with the necessary information for crawling tree structure-based data sources and identifying items for indexing.
To configure Oracle SES:
In Oracle SES, create a data source of data source type, for example, Oracle Fusion.
For General, complete the following:
Name: your data source name
Oracle SES supports string values of up to 100 characters.
Configuration URL: http://
yourhost:port/appname/pathname/searchableObjectName
/ConfigFeed
Authentication Type: NATIVE
User ID: username
Password: password
Scratch Directory: /tmp
or c:\tmp
or empty
Maximum number of connection attempts: 3
For Authentication, complete the following:
Authorization: ACLs Controlled by the Source
HTTP endpoint for authorization: http://
yourhost:port/appname/pathname
/SecurityService?engineInstID=
EngineInstanceID
User ID: username
Password: password
Business Component: searchableObjectName
Display URL Prefix: prefix of url for Oracle SES UI
Create a data source group:
From Search Tab/Source Group, click the Create button.
Provide a name.
Select Fusion Data Type to filter the data source.
Shuttle the data source to the right column.
Click Finish.
Activate the identity extension:
From Global Settings, select Identity Management Setup.
Select Oracle Fusion from the list.
Click Activate. If it is already activated, deactivate it, then reactivate it.
For HTTP endpoint for authentication, enter http://
yourhost:port/appname/pathname
/SecurityService
.
Enter your user name and password.
If Oracle SES is needed, create a federated trusted entity:
From Global Settings, select Federation Trusted Entities.
For Entity Name, enter your user name.
Select the Use Identity Plug-in checkbox for the authentication option.
(Optional) Include the Oracle SES client Java archive (JAR) in your class path, as shown in Example 32-11, to query Oracle SES through API.
Example 32-11 Class Path with Oracle SES Client Java Archive
public SearchHits doSearch(String soName, String query, int pageSize, int page) { SearchHits searchHits = null; String searchGroupName = GROUP_NAME; long engineInstId = -1; SearchContext searchContext = ContextFactory.getSearchContext(); QueryMetaData qmd = new QueryMetaDataImpl(); qmd.setQueryString(query); qmd.setPageSize(pageSize); qmd.setCurrentPage(page); SearchGroup group = new SearchGroup(searchGroupName, searchGroupName, -1, null, SearchContext.LOCAL); SearchGroup[] groups = new SearchGroup[] { group }; qmd.setSearchGroups(groups); SearchableGroup sg = MetaDataManager.getSearchableGroup(-1, searchGroupName); sg.addSearchableObject(soName); SearchableObject so = MetaDataManager.getSearchableObject(soName); searchContext.setSearchableObject(so); SearchEngine engine = SearchEngineManager.getSearchEngine(engineInstId); try { Searcher searcher = engine.getSearcher(searchContext); searchHits = searcher.search(searchContext, qmd); } catch (Throwable e) { return null; } return searchHits; }
In the ECSF architecture, search related artifacts can be stored in any persistent storage. The metadata manager obtains these artifacts via configuration store abstraction. For Oracle Fusion Applications, a database-based configuration store is developed that can load configuration from the ECSF tables in the Oracle Fusion Applications database.
If you decide not to use the ECSF database-based configuration store for the metadata, you can implement your own configuration store by implementing the oracle.ecsf.meta.Configuration
interface.
The search related artifacts are loaded into memory through VOConfiguration
during runtime to be used for crawling, query, and administration. If information is not stored in a database, as in the case of Oracle Business Intelligence that stores its information in a tree structure-based source system, ECSF provides a flexible way to load the runtime objects through an interface (Configuration
) placed between MetaDataManager
and your configuration storage so that runtime objects are not restricted to being loaded from the database. Figure 32-5 illustrates the runtime architecture that includes the Configuration
interface, which provides an alternative mechanism for loading runtime objects.
Figure 32-5 Runtime Architecture with Configuration Interface
A system property determines which configuration, VOConfiguration
or a custom configuration, to use during runtime. In Figure 32-5, the BIConfiguration
class is an example of a custom configuration that extends the existing AbstractConfiguration
class.
Integrate search functionality for tree structures by extending the AbstractConfiguration
class and using your configuration class.
The MetaDataManager
class determines which configuration to call based on how you set the oracle.ecsf.configuration.class
system property. For example,
System.setProperty("oracle.ecsf_configuration_class", "oracle.ecsf.meta.impl.BIConfiguration");
sets the property to use BIConfiguration
. If this property is not set, or an implementation class does not exist for this property, MetaDataManager
calls VOConfiguration
by default.
The Configuration
interface, shown in Example 32-12, contains the methods implemented by VOConfiguration
or a custom configuration to load runtime objects.
Example 32-12 Configuration Interface
public interface Configuration { /** * Returns all search engine instances. * @return a list of search engine instances available. */ public List<MetaEngineInstance> getEngineInstances(); /** * Returns engine parameters in a hashmap for a given engine * instance. * @param engineId the engine instance id * @return Hashmap configuration parameter */ public Map getEngineParameters(long engineId); /** * Returns a searchable group for a given search engine instance, by name. * @param engineId The identification of the engine instance. * @param name The name of the searchable group. * @return a searchable group. Null if not found. */ public SearchableGroup getSearchableGroup(long engineId, String name); /** * Returns a searchable object for a given search engine instance by class * name. * @param engineId The identification of the engine instance. * @param name The class name of the searchable object. * @return a searchable object, null if not found. */ public SearchableObject getSearchableObject(long engineId, String name); /** * Returns a list of searchable groups for a given search engine instance. * @param engineId The indentification of the engine instance. * @return a list of searchable groups, empty if not found. */ public List<SearchableGroup> getSearchableGroups(long engineId); /** * Requests a reload of the configuration. Implementation should reload the * objects from persistent storage. */ public void reload(); }
The Configuration
interface includes the getEngineParameters()
method so you can get and set the search engine parameters needed for ECSF runtime in the absence of a database.
The AbstractConfiguration
class implements the necessary functionalities common to all non-database uptakers regardless of where the runtime object information is stored. You must complete the implementation by using your own custom class that extends AbstractConfiguration
. For information, see Section 32.4.2.5, "Extending AbstractConfiguration."
Example 32-13 illustrates the implementation of AbstractConfiguration
. In this implementation, getSearchableGroups()
loads the available groups from the Oracle SES instance. These groups are treated as external groups, and therefore advanced search and facets are not supported in this scenario.
Example 32-13 Sample AbstractConfiguration Implementation
public abstract class AbstractConfiguration implements Configuration { public AbstractConfiguration() { super(); MetaEngineInstance engine = new MetaEngineInstance(); engine.setId(-1L); engines.add(engine); } public List<MetaEngineInstance> getEngineInstances() { return engines; } public List<SearchableGroup> getSearchableGroups(long engineId) { if(groups == null) { groups = new ArrayList<SearchableGroup>(); try { Map map = SESAdmin.getGroups(ContextFactory.getSearchContext(), engineId); for (Object key : map.keySet()) { SearchableGroup sg = new SearchableGroup(key.toString()); sg.setDisplayName((String)map.get(key)); sg.setIsExternal(true); sg.setEngineInstanceId(engineId); groups.add(sg); } } catch (SearchException e) { e.printStackTrace(); } } return groups; } public SearchableGroup getSearchableGroup(long engineId, String s) { for (SearchableGroup group : getSearchableGroups(engineId)) { if (group.getName().equals(s)) { return group; } } return null; } public SearchableObject getSearchableObject(long engineId, String s) { SearchableObject so = loadSOFromClass(s); if (so != null) { so.setSearchEngineInstanceId(engineId); } return so; } protected SearchableObject loadSOFromClass(String className) { try { if (className.equals(SearchableObject.class.getName())) { return null; } Class cls = Thread.currentThread().getContextClassLoader().loadClass(className); if (cls != null) { Object object = null; try { object = cls.newInstance(); } catch (InstantiationException e) { return null; } catch (IllegalAccessException e) { return null; } if (object instanceof SearchableObject) { //this is the only path a searchable object will be created SearchableObject so = (SearchableObject)object; so.setDocument(new VODocumentImpl("root")); return so; } else { return null; } } else { return null; } } catch (ClassNotFoundException e) { return null; } } public void reload() { //do nothing } private List<SearchableGroup> groups = null; private List<MetaEngineInstance> engines= new ArrayList<MetaEngineInstance>(); }
In this implementation, there is only one engine instance but following MetaDataManager
convention, a list of engine instances is returned.
Since the searchable objects are not stored in the database, you must implement a Java class to define each searchable object. Example 32-14 shows the sample implementation for EmpView.java
.
Example 32-14 Sample Searchable Object Class
package runtime; //package where runtime objects reside import java.util.logging.Logger; import oracle.ecsf.meta.AbstractDocumentDefinition; import oracle.ecsf.meta.DocumentDefinition; import oracle.ecsf.meta.FieldDefinitionImpl; import oracle.ecsf.meta.SearchableObject; import oracle.ecsf.util.ECSFLoggerFactory; public class EmpView extends SearchableObject { private static Logger sLogger = ECSFLoggerFactory.getLogger(EmpView.class.getName()); private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; public EmpView() { super(""); setName(getClass().getName()); } public EmpView(String name) { super(name); } /** * Override to initalize document. * @param document */ public final void setDocument(AbstractDocumentDefinition document) { super.setDocument(document); initDoc(document); } private void initDoc(AbstractDocumentDefinition documentDefintion) { FieldDefinitionImpl field = new FieldDefinitionImpl("Ename"); field.setBinding("ENAME"); field.setPrimaryKey(false); field.setStored(true); documentDefintion.addField(field); field = new FieldDefinitionImpl("Empno"); field.setBinding("EMPNO"); field.setPrimaryKey(true); field.setStored(true); documentDefintion.addField(field); field = new FieldDefinitionImpl(DocumentDefinition.ECSF_SO_NAME); field.setBinding(DocumentDefinition.ECSF_SO_NAME); field.setPrimaryKey(false); field.setStored(true); documentDefintion.addField(field); } }
Each searchable object is loaded using a class of the same name.
You can extend the AbstractConfiguration
class with the BIConfiguration
class, as shown in Example 32-15, to define your own way of loading runtime objects that is specific to your environment.
Example 32-15 Sample Implementation for BIConfiguration
package oracle.ecsf.meta.impl; import java.util.HashMap; import java.util.Map; public class BIConfiguration extends AbstractConfiguration { public BIConfiguration() { } public Map getEngineParameters(long engineId) { HashMap map = new HashMap(); map.put("SES_ADMIN_USERNAME", "searchsys"); map.put("SES_ADMIN_PASSWORD", "welcome1"); map.put("SES_ADMIN_SESSION_TIMEOUT", "10"); map.put("SES_ADMIN_SERVICE", "http://sesserver.com:7777/search/api/admin/AdminService"); map.put("SES_QUERY_SERVICE", "http://sesserver.com:7777/search/query/OracleSearch"); map.put("SES_QUERY_PROXY_USERNAME", "scott"); map.put("SES_QUERY_PROXY_PASSWORD", "tiger"); map.put("SES_QUERY_SESSION_TIMEOUT", "10"); map.put("ECSF_DATA_SERVICE", "http://wlsserver.com:7101/approot/searchfeedservlet/"); map.put("ECSF_SECURITY_USERNAME", "scott"); map.put("ECSF_SECURITY_PASSWORD", "tiger"); map.put("ECSF_SECURITY_SERVICE", "http://wlsserver.com:7101/approot/searchfeedservlet/"); map.put("ECSF_REDIRECT_SERVICE", "http://wlsserver.com:7101/approot/searchfeedservlet/"); return map; } //add search group and search object used for SESAdmin public List<SearchableGroup> getSearchableGroups(long engineId) { if(searchGroups == null) { searchGroups = new ArrayList(super.getSearchableGroups(engineId)); SearchableGroup sgAdmin = new SearchableGroup(GROUP_NAME_ADMIN); sgAdmin.setIsExternal(false); sgAdmin.setEngineInstanceId(ENGINE_ID); SearchableObject so = super.loadSOFromClass(OBJECT_NAME_ADMIN); sgAdmin.addSearchableObject(so); searchGroups.add(sgAdmin); } return searchGroups; } private List<SearchableGroup> searchGroups = null; private static final long ENGINE_ID = -1L; private static final String GROUP_NAME_ADMIN = "runtime.EmpViewAdminTest"; private static final String OBJECT_NAME_ADMIN = "runtime.EmpViewAdminTest"; }
Recent Searches will save the user's top 10 most recent searches. The maximum number of recent searches that are saved can be configured. Recent Searches will display in the UI with the search keywords as their name and the user can use the recent search to requery. Recent Searches can be deleted one at a time, or all Recent Searches for a specified user can be deleted.
The Recent Search feature uses the SaveSearch database table and dataobjects, which already exist. The SEARCH_TYPE column added to the ECSF_SVSEARCH table specifies whether a search is SAVED or RECENT. If necessary, make sure to update the SavedSearchManager so that it handles this column.
Recent Searches uses these components:
RecentSearchManager Class
The RecentSearchManager will manage the creation, deletion and retrieval of recent searches from the database.
SavedSearchManager Class
When a Saved Search is created, the SEARCH_TYPE column in the ECSF_SVSEARCH database table will be set to the appropriate value, and the SavedSearchManager will retrieve only searches that are of type SAVED.
ECSF_SVSEARCH Database Table
The existing ECSF_SVSearch database table will store the information for recent searches, using the SEARCH_TYPE column to store the Search Type.
This class, shown in Example 32-16, manages the Recent Searches.
Example 32-16 RecentSearchManager API
/** * Returns a List of recent RecentSearch data objects for the * current user defined in the SearchContext * * @param ctx the current SearchContext * @return List< RecentSearch > list of recent RecentSearches * @throws SearchException */ public List<RecentSearch> getRecentSearches(SearchContext ctx) throws SearchException /** * Returns a List of recent RecentSearch data objects for the * current user defined in the SearchContext and the specified * caller context * @param ctx - the current SearchContext * @param callerCtx - the caller context * @return List<RecentSearch> - list of recent RecentSearches ordered * from most recent to oldest * @throws SearchException */ public List<RecentSearch> getRecentSearches(SearchContext ctx, String callerCtx) throws SearchException /** * Creates a new recent search * * @param ctx - the SearchContext * @param searchDescription - the description of the saved search * @param queryDetails - recent saved search query information * @return RecentSearch * @throws SearchException */ public RecentSearch createRecentSearch(SearchContext ctx, String searchDescription, QueryMetaData queryDetails) throws SearchException /** * Creates a new recent search * * @param ctx - the SearchContext * @param searchDescription - the description of the saved search * @param queryDetails - recent saved search query information * @param callerCtx - the caller context * @return RecentSearch * @throws SearchException */ public RecentSearch createRecentSearch(SearchContext ctx, String searchDescription, QueryMetaData queryDetails, String callerCtx) throws SearchException /** * Deletes the specified Recent Search from the database * * @param ctx - the SearchContext * @param recentSearch - the Recent Search to delete * @throws SearchException */ public void deleteRecentSearch(SearchContext ctx, SavedSearch savedSearch) throws SearchException /** * Deletes all of the recent searches for the current user specified in the SearchContext * * @param ctx - the SearchContext * @throws SearchException */ public void deleteRecentSearchesForUser(SearchContext ctx) throws SearchException /** * Deletes all of the recent searches for the current user specified * in the SearchContext with the specified callerCtx * * @param ctx the - SearchContext * @param callerCtx - the caller context * @throws SearchException */ public void deleteRecentSearchesForUser(SearchContext ctx, String callerCtx) throws SearchException
Recent Searches are managed only from the current application container, so the RecentSearchManager only handles recent searches that are found in the local application database, regardless of the ECSF Scope (LOCAL/GLOBAL). RecentSearchManager will not call to other search applications for recent searches.
Important: When a RecentSsearch query is run, the query is run as usual using the defined Scope and Federation, so a federated query will go across the wire to the search applications if required.
Recent Searches are not implicitly created by ECSF. For a Recent Search to be saved, the RecentSearchManager.createRecentSearch API must be called.
The call to get the Recent Searches will return a list ordered from most recent to oldest recent search.
For performance, the list of recent searches returned will not contain the RecentSearchDetails information for the Recent Searches. The fact that this information is not available in the Recent Search dataobject is transparent to the client. When the client wants the details and calls RecentSearch.getRecentSearchDetails() on the Recent Search, the dataobject automatically will retrieve the RecentSearchDetails from the database.
By default, the maximum number of Recent Searches for each user is limited to 10. This number can be configured using a Java system property:
oracle.ecsf.recent.search.max.num
This property can be set using the Java -D option or the ecsf.properties file.
Note:
If the oracle.ecsf.recent.search.max.num property is set to an invalid number or 0, recent searches are disabled and a message is printed to the log.
The isEnabled(SearchContext ctx) API indicates whether Recent Search functionality is enabled. If Recent Search is disabled, calling the other methods in RecentSearchManager will result in an UnsupportedOperationException.
When Recent Search records are retrieved from the database, the SQL limits the number of records based on the system property (or the default of 10), so that only the most recent records are returned.
When the RecentSearchManager creates a new Recent Search, it first checks if the user already has the maximum number of Recent Searches stored in the database. If the user does not, a new Recent Search is created. If the user has exceeded the maximum number of Recent Searches allowed, the oldest Recent Search record is deleted and then the new Recent Search is saved into the database.
During the creation of a new Recent Search, at most one older Recent Search record may be deleted. Because the maximum number of Recent Searches is configurable, if this property is changed, there may be more Recent Search records in the database than allowed per user, and the Recent Search records should be manually cleaned from the database to clean up any extra records.
When a new Recent Search is created, due to the ECSF_SVSEARCH database table constraint on the NAME being unique per user, the RecentSearchManager will generate a unique name for the Recent Search using the database RowId for the new record and the queryString input by the user:
String searchName = rowId + ": " + queryDetails.getQueryString();
This will maintain the constraint of having a unique name for each recent SavedSearch record. The UI will want to display the keyword string as the Recent Search name. The keyword string can be obtained from the SavedSearch dataobject using its getKeywordSrchStr method:
String recentSearchDisplayName = recentSearch. getKeywordSrchStr();
To run a Recent Search, the RecentSearchDetails can be retrieved from the RecentSearch object and then SearchCtrl.runQuery can be used to run the query on the queryMetaData in the RecentSearchDetails. If the query is federated, it will run as usual using federation. All of the necessary details for this are stored in the queryMetaData object:
RecentSearchDetails recentSearchDetails = recentSearch.getRecentSearchDetails(); QueryMetaData qmd = recentSearchDetails.getQueryDetails(); SearchHits hits = searchCtrl.runQuery(qmd);
The callerCtx passed into some of the RecentSearchManager methods is a column used by the UI to tag searches. For example, the Global Search UI will only want to display recent searches that were performed inside the Global Search UI, so the callerCtx will be used when creating and retrieving searches.
Database Schema for Recent Searches
Recent Search uses the ECSF_SVSEARCH and ECSF_SVSEARCH_DETAILS database tables. To support Recent Search, these schema changes have been made:
SEARCH_TYPE has been added to ECSF_SVSEARCH:
SEARCH_TYPE VARCHAR2(20) default 'SAVED' NOT NULL
The unique constraint on the ECSF_SVSEARCH table includes the SEARCH_TYPE column.
CONSTRAINT ECSF_SVSEARCH_UK1 UNIQUE (NAME, USERID, CALLER_CTX, SEARCH_TYPE)
The existing ECSF_SVSEARCH_N1, ECSF_SVSEARCH_N2, and ECSF_SVSEARCH_U2 Indexes for the ECSF_SVSEARCH table include the SEARCH_TYPE column.
CREATE INDEX ECSF_SVSEARCH_N1 ON ECSF_SVSEARCH (USERID, SEARCH_TYPE); CREATE INDEX ECSF_SVSEARCH_N2 ON ECSF_SVSEARCH (USERID, CALLER_CTX, SEARCH_TYPE); CREATE INDEX ECSF_SVSEARCH_U2 ON ECSF_SVSEARCH (NAME, USERID, CALLER_CTX, SEARCH_TYPE);
The ECSF_SVSEARCH_DETAILS table is constrained on the Foreign Key to ECSF_SVSEARCH so that corresponding search details are automatically deleted whenever an ECSF_SVSEARCH record is deleted.
ALTER TABLE ECSF_SVSEARCH_DETAILS ADD ( CONSTRAINT ECSF_SVSEARCH_DETAILS_FK1 FOREIGN KEY (SVSEARCH_ID) REFERENCES ECSF_SVSEARCH (ID) ON DELETE CASCADE ) ;
RecentSearch Dataobject
The RecentSeach and RecentSearchDetails dataobjects are used. A RecentSearch dataobject is just like SavedSearch except for the details method:
/** * Retrieve the RecentSearchDetails for this recent search. * * @return recent search details */ public RecentSearchDetails getRecentSearchDetails()
ECSF provides the services and federation to enable users to search across Oracle Fusion Applications product families or across multiple Oracle SES instances. For more information, see the "Managing Search with Oracle Enterprise Crawl and Search Framework" chapter in the Oracle Fusion Applications Administrator's Guide.
Set up ECSF services and federation by:
Creating the SearchDB connection on Oracle WebLogic Server
Updating the application deployment profile with the Target Directory for Searchable Objects
Updating the application to point to the ECSF Service shared library
Adding the ECSF Runtime Library
Adding searchable objects and their dependencies to the Search application
Setting the system parameter for web service
Packaging and deploying the Search application
Setting up the ECSF client for federation
Setting the SearchContext
scope to GLOBAL
Integrating federation across Oracle Fusion Applications product families
The Oracle WebLogic Server instance to which the application is deployed must have a SearchDB
connection. The application deployment descriptors are set so that the application does not automatically generate and synchronize weblogic-jdbc.xml
descriptors during deployment. This setting prevents you from receiving the deployment error No credential mapper entry found for password indirection
when you package or deploy from the command line or from Oracle JDeveloper. Because of this, you must manually create the SearchDB
connection on Oracle WebLogic Server instance.
To create the SearchDB connection:
In the Domain Structure tree of the Oracle WebLogic Server Administration Console, navigate to Services, then JDBC, then Data Sources.
See if there is any data source with Java Naming and Directory Interface (JNDI) value jdbc/SearchDBDS
. If not, proceed to the next step.
Click the New.
On the Connection Properties page, complete the fields with the following values:
JNDI Name: jdbc/SearchDBDS
Database Type: Oracle
Database Driver: Oracle Driver (Thin) 901,92,10,11
Click Next, and complete the configuration according to your data source.
All searchable objects and their dependencies must be packaged within the Search application enterprise archive (EAR) file for each product family. You must set the target directory for the Java archive (JAR) files containing the searchable objects and their dependencies in the application deployment descriptor so that they are packaged with the enterprise archive.
To set the target directory for searchable objects:
In the Application Navigator, right-click the application name and navigate to Application Properties, then Deployment.
The deployment descriptor file (for example, Search_Application1.ear
, where Search
is your application name) appears in the left pane.
Click the deployment descriptor file and select Edit.
From the Edit EAR Deployment Profile Properties menu navigate to File Groups > VOLib > Contributors, click Add, and set the directory to point to {FULL_PATH_TO_BUILD_FILE}/deploy/lib/
, for example, /ade/view_name/fusionapps/crm/deploy/lib
.
This directory is empty, but during the pre-enterprise archive step in the build file the directory becomes populated with all of the dependent Java archive (JAR) files. Including this directory in the application deployment descriptor ensures that these dependent Java archive (JAR) files are packaged with the enterprise archive.
Click OK.
The ECSF Service shared library eliminates the need for ECSF libraries to be packaged into the Search application for each product family. Instead, applications that depend on ECSF libraries can reference the ECSF shared library that is deployed to the Oracle WebLogic Server instance. The ECSF Service shared library contains the following Java archive (JAR) files:
ecsf_MiddleTier.war
ecsf_MiddleTier.jar
ecsf_Common.jar
You must update the Oracle WebLogic Server deployment descriptor file (weblogic-application.xml
) by adding the reference to the ECSF Service shared library (oracle.ecsf.service
), as shown in Example 32-17.
Example 32-17 Reference to the ECSF Service Shared Library
<library-ref> <library-name>oracle.ecsf.service</library-name> </library-ref> <library-context-root-override> <context-root>searchservice</context-root> <override-value>REPLACE _CONTEXT_ROOT</override-value> </library-context-root-override>
Replace REPLACE _CONTEXT_ROOT
with the context root that is desired for the Search application's ECSF Service.
The ECSF Service shared library is automatically deployed to the Integrated WebLogic Server instance by the ECSF extension in JDeveloper through the JDeveloper Application Development Runtime Service (ADRS). However, you must manually deploy the ECSF Service shared library to the standalone Oracle WebLogic Server.
After you update the application deployment profile, update the project by adding the ECSF Runtime Library.
To add the ECSF Runtime Library:
Right-click the project and select Project Properties.
Select the Libraries and Classpath category and click the Add Library button.
In the Add Library dialog, select ECSF Runtime Server
from the list of available libraries.
Click OK to save your selection and close the Add Library dialog.
Set the oracle.ecsf.service.ws.timeout
system parameter to specify the web service timeout value in milliseconds. If no value is specified, then 90,000 milliseconds is used. You can set the system parameter in either the Java system properties or in the ecsf.properties
file.
Set the oracle.ecsf.service.ws.timeout
system parameter in Java System Properties to specify the web service timeout value.
To set the system parameter using Java system properties:
In the Application Navigator, right-click ViewController and select Project Properties.
In the Project Properties dialog, select Run/Debug/Profile in the left panel.
Select Default in the Run Configurations list, then click the Edit button.
In the Edit Run Configuration dialog, select Launch Settings in the left panel.
Enter -Doracle.ecsf.service.ws.timeout=
n (where n is the desired value in milliseconds) in the Java Options field, then click OK.
Click OK.
Set the oracle.ecsf.service.ws.timeout
system parameter in the ecsf.properties
file to specify the web service timeout value by adding the following line to the ecsf.properties
file available in the application classpath:
oracle.ecsf.service.ws.timeout=
n
where n is the desired value in milliseconds.
When the application deployment descriptor points to the right directory you can run the ant
targets to package and deploy the EAR file. You can run the ant
targets from the command line or from Oracle JDeveloper.
Package and deploy the Search application by issuing the following commands in the directory where the build file is located:
ant -f build-crmsearch.xml ear
ant -Ddeployenvfile=/scratch/deploy.xml -f build-crmsearch.xml deploy
where build-crmsearch.xml
is the build file for the Search application.
The enterprise archive step in the build file includes the pre-enterprise archive step, so there is no need to manually run the pre-enterprise archive step. The enterprise archive target also runs a postenterprise archive step that deletes all the files from the deploy/lib
directory after the enterprise archive is packaged, resulting in a clean folder.
You can use Oracle JDeveloper to package and deploy the Search application.
To package and deploy the Search application from Oracle JDeveloper:
Run the pre-enterprise archive steps by opening the build file, right-clicking the open file editor, and selecting Run ant target > lrg - writeGraph > pre-ear.
This step runs the pre-enterprise archive steps that are required for copying required Java archive (JAR) files to the directory specified in the Search application deployment descriptor. All the files in that directory is packaged into the enterprise archive file in the APP-INF/lib
file where the ECSF WAR can locate them.
Package the enterprise archive by right-clicking the application and selecting Deploy > To ear.
Deploy the enterprise archive by right-clicking the application and selecting Deploy > To IntegratedWebLogicServer.
The Search application must be updated if there are new searchable objects to add to the application or if any of the dependencies for existing searchable objects change.
If there are no new searchable objects but dependencies have changed, you only need to run the dependentJar
ant target and package and deploy the enterprise archive (for information, see Section 32.6.6, "How to Package and Deploy the Search Application").
However, if you are adding new searchable objects to the application, then you must add the new searchable objects to the Search application build file and run the dependentJar
ant target, then repackage and redeploy the enterprise archive (for information, see Section 32.6.6, "How to Package and Deploy the Search Application").
To connect to the Search application for each Oracle Fusion Applications product family (collectively called global search applications), you must configure the client application so that when it sends the Search application server a request, it also sends valid encrypted proxy user credentials to the server.
The client that calls the Search application must be configured with information on where to find the global Search applications. This information is stored in the connections.xml
of the client application. The connections.xml file of the client application must contain a reference name element corresponding to each remote ECSF component to which the client application connects.
Set up the ECSF client application by:
Adding encryption keys to cwallet.sso
and default-keystore.jks
Adding the keystore to jps-config.xml
Creating the proxy user
Updating connections.xml
The security header is encrypted before being sent to the server, so the cwallet and default-keystore files for both the client and server must be configured for the encryption to function properly. Use the Oracle WebLogic Scripting Tool to create the encryption keys in cwallet.sso
and default-keystore.jks
. For more information, see Oracle Fusion Middleware Oracle WebLogic Scripting Tool.
The following four new entries appear in cwallet.sso
and default-keystore.jks
:
> createCred(map="oracle.wsm.security", key="keystore-csf-key", user="owsm", password="welcome1", desc="Keystore key") > createCred(map="oracle.wsm.security", key="enc-csf-key", user="orakey", password="welcome1", desc="Encryption key") > createCred(map="oracle.wsm.security", key="sign-csf-key", user="orakey", password="welcome1", desc="Signing key") > createCred(map="oracle.wsm.security", key="basic.credentials", user="weblogic", password="weblogic1", desc="User credentials key")
Oracle WebLogic Scripting Tool updates the files directly on the server you specify, so no redeployment is necessary.
In order for the client to be able to use the encryption keystore entries, you must configure the jps-config.xml
file for the client application.
Add the following entries to jps-config.xml
:
Under serviceProviders
:
<serviceProvider type="KEY_STORE" name="keystore.provider" class="oracle.security.jps.internal.keystore.KeyStoreProvider"> </serviceProvider>
Under serviceInstances
:
<serviceInstance name="keystore" provider="keystore.provider" location="./default-keystore.jks"> <description>Default JPS Keystore Service</description> <property name="keystore.type" value="JKS"/> <property name="keystore.csf.map" value="oracle.wsm.security"/> <property name="keystore.pass.csf.key" value="keystore-csf-key"/> <property name="keystore.sig.csf.key" value="sign-csf-key"/> <property name="keystore.enc.csf.key" value="enc-csf-key"/> </serviceInstance>
Under the default jpsContext
:
<serviceInstanceRef ref="keystore"/>
For more information, see Oracle Fusion Middleware Oracle WebLogic Scripting Tool.
The proxy user must exist on both the client and server. The client's cwallet.sso
must also include an entry for the proxy user so that the username and password can be encrypted when they are placed in the security header before being sent to the server. Use Oracle WebLogic Scripting Tool to create an entry for the user in cwallet.sso
, as shown in Example 32-18.
Example 32-18 Sample Proxy User Entry
createCred(map="oracle.wsm.security", key="test.user", user="weblogic", password="weblogic1", desc="User credentials key")
The key (in this example, test.user
) for the new entry is used in connections.xml
.
The connection between the ECSF client and each of the remote ECSF service components is defined in the connections.xml
file in the ECSF client. The connections.xml
file contains a list of reference name elements that correspond to each ECSF service component. You must edit the connections.xml
file to define the application server connection parameters.
To define the connection parameters:
Expand Application Resources, then Descriptors, then ADF Meta-INF, and open the connections.xml
file.
Add the reference name elements, as shown in Example 32-19.
Example 32-19 Sample Reference Element
<Reference name="{/oracle/ecsf/service/query/common/crm/}SearchService" className="oracle.adf.model.connection.webservice.impl.WebServiceConnectionImpl" xmlns=""> <Factory className="oracle.adf.model.connection.webservice.api.WebServiceConnectionFactory"/> <RefAddresses> <XmlRefAddr addrType="WebServiceConnection"> <Contents> <wsconnection description="http://localhost:7101/CrmSearchService/AppModuleSearchService?WSDL" service="{/oracle/ecsf/service/query/common/}AppModuleSearchService"> <model name="{/oracle/ecsf/service/query/common/}AppModuleSearchService" xmlns="http://example.com/ws/model"> <service name="{/oracle/ecsf/service/query/common/}AppModuleSearchService"> <port name="AppModuleSearchServiceSoapHttpPort" binding="{/oracle/ecsf/service/query/common/}AppModuleSearchServiceSoapHttp"> <soap addressUrl="http://localhost:7101/CrmSearchService/AppModuleSearchService" xmlns="http://schemas.xmlsoap.org/wsdl/soap/"/> </port> </service> </model> </wsconnection> </Contents> </XmlRefAddr> </RefAddresses> </Reference> <Reference name="{/oracle/ecsf/service/query/common/hcm/}SearchService" className="oracle.adf.model.connection.webservice.impl.WebServiceConnectionImpl" xmlns=""> <Factory className="oracle.adf.model.connection.webservice.api.WebServiceConnectionFactory"/> <RefAddresses> <XmlRefAddr addrType="WebServiceConnection"> <Contents> <wsconnection description="http://localhost:7101/HcmSearchService/AppModuleSearchService?WSDL" service="{/oracle/ecsf/service/query/common/}AppModuleSearchService"> <model name="{/oracle/ecsf/service/query/common/}AppModuleSearchService" xmlns="http://example.com/ws/model"> <service name="{/oracle/ecsf/service/query/common/}AppModuleSearchService"> <port name="AppModuleSearchServiceSoapHttpPort" binding="{/oracle/ecsf/service/query/common/}AppModuleSearchServiceSoapHttp"> <soap addressUrl="http://localhost:7101/HcmSearchService/AppModuleSearchService" xmlns="http://schemas.xmlsoap.org/wsdl/soap/"/> </port> </service> </model> </wsconnection> </Contents> </XmlRefAddr> </RefAddresses> </Reference> <Reference name="{/oracle/ecsf/service/query/common/fscm/}SearchService" className="oracle.adf.model.connection.webservice.impl.WebServiceConnectionImpl" xmlns=""> <Factory className="oracle.adf.model.connection.webservice.api.WebServiceConnectionFactory"/> <RefAddresses> <XmlRefAddr addrType="WebServiceConnection"> <Contents> <wsconnection description="http://localhost:7101/FscmSearchService/AppModuleSearchService?WSDL" service="{/oracle/ecsf/service/query/common/}AppModuleSearchService"> <model name="{/oracle/ecsf/service/query/common/}AppModuleSearchService" xmlns="http://example.com/ws/model"> <service name="{/oracle/ecsf/service/query/common/}AppModuleSearchService"> <port name="AppModuleSearchServiceSoapHttpPort" binding="{/oracle/ecsf/service/query/common/}AppModuleSearchServiceSoapHttp"> <soap addressUrl="http://localhost:7101/FscmSearchService/AppModuleSearchService" xmlns="http://schemas.xmlsoap.org/wsdl/soap/"/> </port> </service> </model> </wsconnection> </Contents> </XmlRefAddr> </RefAddresses> </Reference>
Web service security must be enforced by policy at the domain or instance level by configuration. For information, see Oracle Fusion Middleware Oracle WebLogic Server Administration Console Online Help.
Save.
Redeploy the client application.
ECSF Query APIs can either invoke the ECSF service component internally (GLOBAL
) or locally (LOCAL
). To set the ECSF calls to be routed to the ECSF service component, you must set the scope of the search context to GLOBAL
, as shown in Example 32-20.
Example 32-20 Client Methods
SearchContext ctx = ContextFactory.getSearchContext(); ctx.setScope("GLOBAL"); ArrayList<SearchEngineInstance> engineInstances = (ArrayList<SearchEngineInstance>)searchCtrl.getEngineInstances();
When the SearchContext
scope is set to GLOBAL
, the parameters defined for the remote engine instance in the database are used to access metadata objects and perform query related functions on the remote engine instance. For more information, see the "Managing Search with Oracle Enterprise Crawl and Search Framework" chapter in the Oracle Fusion Applications Administrator's Guide.
Use the ECSF API, as shown in Example 32-21, to integrate federation across Oracle Fusion Applications product families.
Example 32-21 Sample API for Implementing Federated Search
SearchCtrl searchCtrl = new SearchCtrl(); SearchHits searchHits = null; QueryMetaDataImpl queryMetaData = new QueryMetaDataImpl(); queryMetaData.setQueryString("*"); queryMetaData.setPageSize(10); queryMetaData.setCurrentPage(1); ctx.setScope(SearchContext.GLOBAL); ctx.setCurrLocale(Locale.US); ArrayList<SearchGroup> allGroups = new ArrayList<SearchGroup>(); ArrayList<SearchGroup> searchGroups = new ArrayList<SearchGroup>(); ArrayList<SearchEngineInstance> engineInstances = (ArrayList<SearchEngineInstance>)searchCtrl.getEngineInstances(); for (SearchEngineInstance engineInstance : engineInstances) { allGroups.addAll(engineInstance.getSearchGroups()); } for (SearchGroup searchGroup : allGroups) { if (searchGroup.getName().equals("runtime.EmpView") || searchGroup.getName().equals("Service Request")) { searchGroups.add(searchGroup); } } SearchGroup sgs[] = searchGroups.toArray(new SearchGroup[searchGroups.size()]); queryMetaData.setSearchGroups(sgs); try { searchHits = searchCtrl.runQuery(ctx, queryMetaData); } catch (Exception e) { e.printStackTrace(); }
In the example, ECSF runtime gets the runtime.EmpView
search category (search group) from an engine instance.
ECSF supports federation across Oracle SES instances, which allows users to query across multiple Oracle SES instances defined in the client's own ECSF component. In Figure 32-6, the ECSF client is connected to one ECSF service component, which depends on one database and two Oracle SES instances.
Federation occurs on the client through the Searcher
class. For each Oracle SES instance, ECSF runtime groups the search categories belonging to an Oracle SES instance and creates a federation node for it. Separate queries are issued in separate threads for each Oracle SES instance. The results from these queries are merged by ECSF runtime and returned to the user.
Note:
You cannot federate both Oracle SES instances and ECSF service components in the same query. ECSF runtime can only create federation nodes for either each Oracle SES instance (for federated Oracle SES) or each ECSF service component (for federated search).
Example 32-22 illustrates how you can integrate federation across Oracle SES instances.
Example 32-22 Sample API for Integrating Federated Oracle SES
SearchContext ctx = ContextFactory.getSearchContext(); ctx.setScope(SearchContext.LOCAL); SearchGroup[] sgs = new SearchGroup[] { new SearchGroup("runtime.EmpView", "runtime.EmpView", 1), new SearchGroup("runtime.EmpView", "runtime.EmpView", 17) }; queryMetaData.setSearchGroups(sgs); try { searchHits = searchCtrl.runQuery(ctx, queryMetaData); } catch (Exception e) { bException = true; }
In the example, two Oracle SES search engine instances are defined.
You can use a Java API to raise change events synchronously with asynch flag = false
when searchable object records are modified. Raising events using SQL writes records to the ECSF_SEARCHABLE_CHANGE_LOG
table of the database.
You can raise change events synchronously by implementing code like the sample code in Example 32-23.
Example 32-23 Sample Code for Raising Events Using SQL
SearchEventInvocation searchEventInvocation = new SearchEventInvocation(); PrimaryKey primaryKey = new PrimaryKey(); primaryKey.put("PartyId", "12322"); SearchChangeLogEvent changeEvent = new SearchChangeLogEvent(pk); changeEvent.setSearchObjectName("oracle.ecsf.search.demo.EmpVO"); changeEvent.setChangeType(IndexableDocument.INSERT); searchEventInvocation.raiseEvent(changeEvent, false);
You can use the following ChangeType
parameters:
IndexableDocument.DELETE
IndexableDocument.UPDATE
IndexableDocument.INSERT
When using the SearchEventInvocation.raiseEvent(PrimaryKey eventPK, boolean useFabric)
method to create change log records, the keys in the eventPK
map must be aliases of view object attributes. A view object's alias can be found by opening the view object in JDeveloper, or by calling the getBinding()
method of the appropriate oracle.ecsf.meta.FieldDefinition
instance. Also, the eventPK
map must contain an entry for every attribute that is part the primary key makeup. Otherwise, the raiseEvent
method throws an exception.
For more information, see the Javadoc for ECSF.
In addition to Java APIs, Oracle Enterprise Crawl and Search Framework (ECSF) provides an external web service for you to integrate ECSF with Oracle Fusion Applications. This web service allows you to build a custom search user interface that enables Oracle Fusion Applications users to search across multiple ECSF service components through a web service client. As an alternative to using Java APIs, you can invoke the external ECSF web service from Oracle Fusion Applications to perform query related functions in both LOCAL
and GLOBAL
scopes. Using a web service client, users can query across multiple Oracle SES instances in LOCAL
scope or across multiple ECSF service components in GLOBAL
scope.
The external ECSF web service reuses the web service already provided by an ECSF component and exposes the methods described in Table 32-1.
Table 32-1 ECSF Web Service Methods
Method | Description |
---|---|
|
Returns a saved search based on the name passed in to the |
|
Returns the saved searches based on the caller context passed in to the |
|
Saves the search passed in to the |
|
Deletes the saved search passed in to the |
|
Returns the saved search details based on the saved search passed in to the |
|
Returns search hits based on the request passed in to the |
|
Returns the engine instances based on the engine type ID passed in to the |
The Web Service Description Language (WSDL), shown in Example 32-24, defines the message endpoints and the request and reply messages of the ECSF web service. The XSD, shown in Example 32-25, defines the XML schema of the ECSF web service. Refer to the WSDL and XSD to understand and interact with the ECSF web service.
Example 32-24 ECSF Web Service WSDL
<wsdl:definitions name="AppModuleSearchService" targetNamespace="/oracle/ecsf/service/query/common/" xmlns:errors="http://xmlns.example.com/adf/svc/errors/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="/oracle/ecsf/service/query/common/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:types="/oracle/ecsf/service/query/common/types/"> <wsdl:import namespace="http://xmlns.example.com/adf/svc/errors/" location="classpath:/META-INF/wsdl/ServiceException.wsdl"/> <wsdl:types> <schema xmlns="http://www.w3.org/2001/XMLSchema"> <import namespace="/oracle/ecsf/service/query/common/types/" schemaLocation="AppModuleSearchService.xsd"/> </schema> </wsdl:types> <wsdl:message name="AppModuleSearchService_search"> <wsdl:part name="parameters" element="types:search"/> </wsdl:message> <wsdl:message name="AppModuleSearchService_searchResponse"> <wsdl:part name="parameters" element="types:searchResponse"/> </wsdl:message> <wsdl:message name="AppModuleSearchService_saveSearch"> <wsdl:part name="parameters" element="types:saveSearch"/> </wsdl:message> <wsdl:message name="AppModuleSearchService_saveSearchResponse"> <wsdl:part name="parameters" element="types:saveSearchResponse"/> </wsdl:message> <wsdl:message name="AppModuleSearchService_getSavedSearches"> <wsdl:part name="parameters" element="types:getSavedSearches"/> </wsdl:message> <wsdl:message name="AppModuleSearchService_getSavedSearchesResponse"> <wsdl:part name="parameters" element="types:getSavedSearchesResponse"/> </wsdl:message> <wsdl:message name="AppModuleSearchService_getSavedSearchDetails"> <wsdl:part name="parameters" element="types:getSavedSearchDetails"/> </wsdl:message> <wsdl:message name="AppModuleSearchService_getSavedSearchDetailsResponse"> <wsdl:part name="parameters" element="types:getSavedSearchDetailsResponse"/> </wsdl:message> <wsdl:message name="AppModuleSearchService_getSavedSearch"> <wsdl:part name="parameters" element="types:getSavedSearch"/> </wsdl:message> <wsdl:message name="AppModuleSearchService_getSavedSearchResponse"> <wsdl:part name="parameters" element="types:getSavedSearchResponse"/> </wsdl:message> <wsdl:message name="AppModuleSearchService_getEngineInstances"> <wsdl:part name="parameters" element="types:getEngineInstances"/> </wsdl:message> <wsdl:message name="AppModuleSearchService_getEngineInstancesResponse"> <wsdl:part name="parameters" element="types:getEngineInstancesResponse"/> </wsdl:message> <wsdl:message name="AppModuleSearchService_getDisplayName"> <wsdl:part name="parameters" element="types:getDisplayName"/> </wsdl:message> <wsdl:message name="AppModuleSearchService_getDisplayNameResponse"> <wsdl:part name="parameters" element="types:getDisplayNameResponse"/> </wsdl:message> <wsdl:message name="AppModuleSearchService_deleteSearch"> <wsdl:part name="parameters" element="types:deleteSearch"/> </wsdl:message> <wsdl:message name="AppModuleSearchService_deleteSearchResponse"> <wsdl:part name="parameters" element="types:deleteSearchResponse"/> </wsdl:message> <wsdl:portType name="AppModuleSearchService"> <wsdl:documentation/> <wsdl:operation name="search"> <wsdl:input message="tns:AppModuleSearchService_search"/> <wsdl:output message="tns:AppModuleSearchService_searchResponse"/> <wsdl:fault name="ServiceException" message="errors:ServiceException"/> </wsdl:operation> <wsdl:operation name="saveSearch"> <wsdl:input message="tns:AppModuleSearchService_saveSearch"/> <wsdl:output message="tns:AppModuleSearchService_saveSearchResponse"/> <wsdl:fault name="ServiceException" message="errors:ServiceException"/> </wsdl:operation> <wsdl:operation name="getSavedSearches"> <wsdl:input message="tns:AppModuleSearchService_getSavedSearches"/> <wsdl:output message="tns:AppModuleSearchService_getSavedSearchesResponse"/> <wsdl:fault name="ServiceException" message="errors:ServiceException"/> </wsdl:operation> <wsdl:operation name="getSavedSearchDetails"> <wsdl:input message="tns:AppModuleSearchService_getSavedSearchDetails"/> <wsdl:output message="tns:AppModuleSearchService_getSavedSearchDetailsResponse"/> <wsdl:fault name="ServiceException" message="errors:ServiceException"/> </wsdl:operation> <wsdl:operation name="getSavedSearch"> <wsdl:input message="tns:AppModuleSearchService_getSavedSearch"/> <wsdl:output message="tns:AppModuleSearchService_getSavedSearchResponse"/> <wsdl:fault name="ServiceException" message="errors:ServiceException"/> </wsdl:operation> <wsdl:operation name="getEngineInstances"> <wsdl:input message="tns:AppModuleSearchService_getEngineInstances"/> <wsdl:output message="tns:AppModuleSearchService_getEngineInstancesResponse"/> <wsdl:fault name="ServiceException" message="errors:ServiceException"/> </wsdl:operation> <wsdl:operation name="getDisplayName"> <wsdl:input message="tns:AppModuleSearchService_getDisplayName"/> <wsdl:output message="tns:AppModuleSearchService_getDisplayNameResponse"/> <wsdl:fault name="ServiceException" message="errors:ServiceException"/> </wsdl:operation> <wsdl:operation name="deleteSearch"> <wsdl:input message="tns:AppModuleSearchService_deleteSearch"/> <wsdl:output message="tns:AppModuleSearchService_deleteSearchResponse"/> <wsdl:fault name="ServiceException" message="errors:ServiceException"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="AppModuleSearchServiceSoapHttp" type="tns:AppModuleSearchService"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="search"> <soap:operation soapAction="/oracle/ecsf/service/query/common/search"/> <wsdl:input> <soap:body use="literal"/> </wsdl:input> <wsdl:output> <soap:body use="literal"/> </wsdl:output> <wsdl:fault name="ServiceException"> <soap:fault name="ServiceException" use="literal" encodingStyle=""/> </wsdl:fault> </wsdl:operation> <wsdl:operation name="saveSearch"> <soap:operation soapAction="/oracle/ecsf/service/query/common/saveSearch"/> <wsdl:input> <soap:body use="literal"/> </wsdl:input> <wsdl:output> <soap:body use="literal"/> </wsdl:output> <wsdl:fault name="ServiceException"> <soap:fault name="ServiceException" use="literal" encodingStyle=""/> </wsdl:fault> </wsdl:operation> <wsdl:operation name="getSavedSearches"> <soap:operation soapAction="/oracle/ecsf/service/query/common/getSavedSearches"/> <wsdl:input> <soap:body use="literal"/> </wsdl:input> <wsdl:output> <soap:body use="literal"/> </wsdl:output> <wsdl:fault name="ServiceException"> <soap:fault name="ServiceException" use="literal" encodingStyle=""/> </wsdl:fault> </wsdl:operation> <wsdl:operation name="getSavedSearchDetails"> <soap:operation soapAction="/oracle/ecsf/service/query/common/getSavedSearchDetails"/> <wsdl:input> <soap:body use="literal"/> </wsdl:input> <wsdl:output> <soap:body use="literal"/> </wsdl:output> <wsdl:fault name="ServiceException"> <soap:fault name="ServiceException" use="literal" encodingStyle=""/> </wsdl:fault> </wsdl:operation> <wsdl:operation name="getSavedSearch"> <soap:operation soapAction="/oracle/ecsf/service/query/common/getSavedSearch"/> <wsdl:input> <soap:body use="literal"/> </wsdl:input> <wsdl:output> <soap:body use="literal"/> </wsdl:output> <wsdl:fault name="ServiceException"> <soap:fault name="ServiceException" use="literal" encodingStyle=""/> </wsdl:fault> </wsdl:operation> <wsdl:operation name="getEngineInstances"> <soap:operation soapAction="/oracle/ecsf/service/query/common/getEngineInstances"/> <wsdl:input> <soap:body use="literal"/> </wsdl:input> <wsdl:output> <soap:body use="literal"/> </wsdl:output> <wsdl:fault name="ServiceException"> <soap:fault name="ServiceException" use="literal" encodingStyle=""/> </wsdl:fault> </wsdl:operation> <wsdl:operation name="getDisplayName"> <soap:operation soapAction="/oracle/ecsf/service/query/common/getDisplayName"/> <wsdl:input> <soap:body use="literal"/> </wsdl:input> <wsdl:output> <soap:body use="literal"/> </wsdl:output> <wsdl:fault name="ServiceException"> <soap:fault name="ServiceException" use="literal" encodingStyle=""/> </wsdl:fault> </wsdl:operation> <wsdl:operation name="deleteSearch"> <soap:operation soapAction="/oracle/ecsf/service/query/common/deleteSearch"/> <wsdl:input> <soap:body use="literal"/> </wsdl:input> <wsdl:output> <soap:body use="literal"/> </wsdl:output> <wsdl:fault name="ServiceException"> <soap:fault name="ServiceException" use="literal" encodingStyle=""/> </wsdl:fault> </wsdl:operation> </wsdl:binding> <wsdl:service name="AppModuleSearchService"> <wsdl:port name="AppModuleSearchServiceSoapHttpPort" binding="tns:AppModuleSearchServiceSoapHttp"> <soap:address location="http://localhost:7101/Application1-ViewController-context-root/AppModuleSearchService"/> </wsdl:port> </wsdl:service> </wsdl:definitions>
Example 32-25 ECSF Web Service XSD
<schema xmlns="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="/oracle/ecsf/service/query/common/types/" xmlns:tns="/oracle/ecsf/service/query/common/types/" xmlns:ns0="http://xmlns.example.com/adf/svc/errors/"> <import namespace="http://xmlns.example.com/adf/svc/errors/" schemaLocation="classpath:/META-INF/wsdl/ServiceException.xsd"/> <element name="search"> <complexType> <sequence> <element name="userName" type="string"/> <element name="queryMetadataRequest" type="string"/> </sequence> </complexType> </element> <element name="searchResponse"> <complexType> <sequence> <element name="result" type="string"/> </sequence> </complexType> </element> <element name="saveSearch"> <complexType> <sequence> <element name="userName" type="string"/> <element name="savedSearchRequest" type="string"/> </sequence> </complexType> </element> <element name="saveSearchResponse"> <complexType> <sequence> <element name="result" type="string"/> </sequence> </complexType> </element> <element name="getSavedSearches"> <complexType> <sequence> <element name="userName" type="string"/> <element name="savedSearchRequest" type="string"/> </sequence> </complexType> </element> <element name="getSavedSearchesResponse"> <complexType> <sequence> <element name="result" type="string"/> </sequence> </complexType> </element> <element name="getSavedSearchDetails"> <complexType> <sequence> <element name="userName" type="string"/> <element name="savedSearchRequest" type="string"/> </sequence> </complexType> </element> <element name="getSavedSearchDetailsResponse"> <complexType> <sequence> <element name="result" type="string"/> </sequence> </complexType> </element> <element name="getSavedSearch"> <complexType> <sequence> <element name="userName" type="string"/> <element name="savedSearchRequest" type="string"/> </sequence> </complexType> </element> <element name="getSavedSearchResponse"> <complexType> <sequence> <element name="result" type="string"/> </sequence> </complexType> </element> <element name="getEngineInstances"> <complexType> <sequence> <element name="userName" type="string"/> <element name="engineInstanceRequest" type="string"/> </sequence> </complexType> </element> <element name="getEngineInstancesResponse"> <complexType> <sequence> <element name="result" type="string"/> </sequence> </complexType> </element> <element name="getDisplayName"> <complexType> <sequence> <element name="userName" type="string"/> <element name="displayNameRequest" type="string"/> </sequence> </complexType> </element> <element name="getDisplayNameResponse"> <complexType> <sequence> <element name="result" type="string"/> </sequence> </complexType> </element> <element name="deleteSearch"> <complexType> <sequence> <element name="userName" type="string"/> <element name="savedSearchRequest" type="string"/> </sequence> </complexType> </element> <element name="deleteSearchResponse"> <complexType> <sequence> <element name="result" type="string"/> </sequence> </complexType> </element> </schema>
Each of the web service methods takes in a username and a request XML. The username is used to bind to the SearchContext. The request XML is passed to the SearchService to perform query related functions.
The request XMLs for the web service methods are based on the following request XSDs:
The request XMLs for the getSavedSearch()
, getSavedSearches()
, saveSearch()
, deleteSearch()
, and getSavedSearchDetails()
methods are based on the SavedSearch request XSD, shown in Example 32-26.
Example 32-26 SavedSearch Request XSD
<?xml version="1.0" encoding="US-ASCII" ?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.example.com" targetNamespace="http://www.example.com" elementFormDefault="qualified"> <xsd:element name="request"> <xsd:complexType> <xsd:sequence> <xsd:element ref="savedSearch"/> <xsd:element name="name" type="xsd:string"/> <xsd:element name="callerctx" type="xsd:string"/> <xsd:element name="locale" type="xsd:string"/> <xsd:element name="scope" type="xsd:string"/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="savedSearch"> <xsd:complexType> <xsd:sequence> <xsd:element name="description" type="xsd:string"/> <xsd:element name="callerctx" type="xsd:string"/> <xsd:element name="query" type="xsd:string"/> <xsd:element name="ispublic" type="xsd:boolean"/> <xsd:element name="userid" type="xsd:string"/> <xsd:element name="detailsid" type="xsd:integer" minOccurs="0"/> <xsd:element ref="queryMetaData"/> </xsd:sequence> <xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="id" type="xsd:integer" use="required"/> </xsd:complexType> </xsd:element> <xsd:element name="queryMetaData"> <xsd:complexType> <xsd:sequence> <xsd:element name="query" type="xsd:string"/> <xsd:element name="page" type="xsd:integer"/> <xsd:element name="lang" type="xsd:string"/> <xsd:element name="pageSize" type="xsd:integer"/> <xsd:element name="searchCtrl" type="xsd:string" minOccurs="0"/> <xsd:element name="soname" type="xsd:string" minOccurs="0"/> <xsd:element name="facetPaths" minOccurs="0"> <xsd:complexType> <xsd:sequence> <xsd:element name="facetPath" maxOccurs="unbounded"> <xsd:complexType> <xsd:sequence> <xsd:element name="value" maxOccurs="unbounded" minOccurs="0"> <xsd:complexType> <xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="value" type="xsd:string" use="required"/> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="categories" minOccurs="0"> <xsd:complexType> <xsd:sequence> <xsd:element name="category" maxOccurs="unbounded" minOccurs="0"> <xsd:complexType> <xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="eid" type="xsd:integer" use="required"/> <xsd:attribute name="compid" type="xsd:integer" use="required"/> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="tags" type="xsd:string" minOccurs="0"/> <xsd:element name="filters" minOccurs="0"> <xsd:complexType> <xsd:sequence> <xsd:element name="filter" maxOccurs="unbounded"> <xsd:complexType> <xsd:simpleContent> <xsd:extension base="xsd:string"> <xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="operator" type="xsd:string" use="required"/> <xsd:attribute name="type" type="xsd:string" use="required"/> </xsd:extension> </xsd:simpleContent> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema>
The SavedSearch request XSD describes the set of rules that the request XMLs must follow to be valid. Examples of valid request XMLs include the following:
getSavedSearch()
<request> <name>ECSF_JUNIT_SVSEARCH</name> <callerctx>null</callerctx> <locale>en_us</locale> <scope>LOCAL</scope> /*use GLOBAL for global scope*/ </request>
getSavedSearches()
<request> <callerctx>%</callerctx> <locale>en_us</locale> <scope>LOCAL</scope> /*use GLOBAL for global scope*/ </request>
saveSearch()
<request> <savedSearch name="ECSF_JUNIT_SVSEARCH" id="1" compid="2"> <description> <![CDATA[Updated Description]]> </description> <callerctx> <![CDATA[]]> </callerctx> <query> <![CDATA[]]> </query> <ispublic> <![CDATA[false]]> </ispublic> <userid> <![CDATA[junit]]> </userid> <detailsid> <![CDATA[1]]> </detailsid> <queryMetaData> <query> <![CDATA[%]]> </query> <page>1</page> <lang>en</lang> <pageSize>10</pageSize> <categories> <category name="runtime.EmpView" eid="1" compid="0"></category> </categories> </queryMetaData> </savedSearch> <name></name> <callerctx>null</callerctx> <locale>en_us</locale> <scope>LOCAL</scope> /*use GLOBAL for global scope*/ </request>
deleteSearch()
<request> <savedSearch name="DeleteSavedSearch" id="100010033142848" compid="2"> <description> <![CDATA[Junit Saved Search]]> </description> <callerctx> <![CDATA[CRM]]> </callerctx> <query> <![CDATA[%]]> </query> <ispublic> <![CDATA[false]]> </ispublic> <userid> <![CDATA[junit]]> </userid> <detailsid> <![CDATA[100010033142849]]> </detailsid> <queryMetaData> <query> <![CDATA[%]]> </query> <page>1</page> <lang>en</lang> <pageSize>10</pageSize> <categories> <category name="runtime.EmpView" eid="1" compid="3"></category> </categories> </queryMetaData> </savedSearch> <name></name> <callerctx>null</callerctx> <locale>en_us</locale> <scope>LOCAL</scope> /*use GLOBAL for global scope*/ </request>
getSavedSearchDetails()
<request> <savedSearch name="SavedSearch" id="100010033142848" compid="2"> <description> <![CDATA[Junit Federation Saved Search]]> </description> <callerctx> <![CDATA[CRM]]> </callerctx> <query> <![CDATA[%]]> </query> <ispublic> <![CDATA[false]]> </ispublic> <userid> <![CDATA[junit]]> </userid> <detailsid> <![CDATA[100010033142849]]> </detailsid> </savedSearch> <callerctx>null</callerctx> <locale>en_us</locale> <scope>LOCAL</scope> /*use GLOBAL for global scope*/ </request>
The request XML for the search(String userName, String queryMetaDataRequest)
method is based on the QueryMetaData request XSD, shown in Example 32-27.
Example 32-27 QueryMetaData Request XSD
<?xml version="1.0" encoding="US-ASCII" ?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.example.com" targetNamespace="http://www.example.com" elementFormDefault="qualified"> <xsd:element name="request"> <xsd:complexType> <xsd:sequence> <xsd:element ref="queryMetaData"/> <xsd:element name="locale" type="xsd:string"/> <xsd:element name="scope" type="xsd:string"/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="queryMetaData"> <xsd:complexType> <xsd:sequence> <xsd:element name="query" type="xsd:string"/> <xsd:element name="page" type="xsd:integer"/> <xsd:element name="lang" type="xsd:string"/> <xsd:element name="pageSize" type="xsd:integer"/> <xsd:element name="searchCtrl" type="xsd:string" minOccurs="0"/> <xsd:element name="soname" type="xsd:string" minOccurs="0"/> <xsd:element name="facetPaths" minOccurs="0"> <xsd:complexType> <xsd:sequence> <xsd:element name="facetPath" maxOccurs="unbounded"> <xsd:complexType> <xsd:sequence> <xsd:element name="value" maxOccurs="unbounded" minOccurs="0"> <xsd:complexType> <xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="value" type="xsd:string" use="required"/> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="categories" minOccurs="0"> <xsd:complexType> <xsd:sequence> <xsd:element name="category" maxOccurs="unbounded" minOccurs="0"> <xsd:complexType> <xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="eid" type="xsd:integer" use="required"/> <xsd:attribute name="compid" type="xsd:integer" use="required"/> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="tags" type="xsd:string" minOccurs="0"/> <xsd:element name="filters" minOccurs="0"> <xsd:complexType> <xsd:sequence> <xsd:element name="filter" maxOccurs="unbounded"> <xsd:complexType> <xsd:simpleContent> <xsd:extension base="xsd:string"> <xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="operator" type="xsd:string" use="required"/> <xsd:attribute name="type" type="xsd:string" use="required"/> </xsd:extension> </xsd:simpleContent> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema>
The QueryMetaData request XSD describes the set of rules that the request XMLs must follow to be valid. An example of a valid request XML for search()
is:
<request> <queryMetaData> <query> <![CDATA[*]]> </query> <page>1</page> <lang>en</lang> <pageSize>10</pageSize> <categories> <category name="runtime.EmpView" eid="1" compid="2"></category> </categories> </queryMetaData> <locale>en_us</locale> <scope>LOCAL</scope> /*use GLOBAL for global scope*/ </request>
The request XML for the getEngineInstances(String userName, String engineInstanceRequest)
method is based on the engineInstanceRequest request XSD, shown in Example 32-28.
Example 32-28 engineInstanceRequest Request XSD
<?xml version="1.0" encoding="US-ASCII" ?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.example.com" targetNamespace="http://www.example.com" elementFormDefault="qualified"> <xsd:element name="request"> <xsd:complexType> <xsd:sequence> <xsd:element name="enginetypeid"/> <xsd:element name="locale" type="xsd:string"/> <xsd:element name="scope" type="xsd:string"/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema>
The engineInstanceRequest request XSD describes the set of rules that the request XMLs must follow to be valid. An example of a valid request XML for getEngineInstances()
is:
<request> <enginetypeid>-1</enginetypeid> <locale>en_us</locale> <scope>LOCAL</scope> /*use GLOBAL for global scope*/ </request>
For each of the web service calls, if the call is successful an XML string is returned. If the web service call results in an error, a service error XML string is returned. The client can then call the ServiceUtil()
class to deserialize the XML string into ECSF runtime metadata objects or deserialize the service error XML string into an exception message.
When the query web service requests are successful, a response message is returned. The XML strings for successful web service calls are based on the XSDs for the following methods:
If any of the query web service requests result in an exception, the exception is wrapped in a service error XML response message.The service error XML strings are based on the following XSD:
<?xml version="1.0" encoding="US-ASCII" ?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.example.com" targetNamespace="http://www.example.com" elementFormDefault="qualified"> <xsd:element name="serviceError"> <xsd:complexType> <xsd:sequence> <xsd:element name="code" type="xsd:string" minOccurs="0"/> <xsd:element name="message" type="xsd:string"/> <xsd:element name="stack" type="xsd:string"/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema>
The web service response message for the method String getSavedSearch(String userName, String savedSearchRequest)
is based on the following XSD:
<?xml version="1.0" encoding="US-ASCII" ?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.example.com" targetNamespace="http://www.example.com" elementFormDefault="qualified"> <xsd:element name="savedSearch"> <xsd:complexType> <xsd:sequence> <xsd:element name="description" type="xsd:string"/> <xsd:element name="callerctx" type="xsd:string"/> <xsd:element name="query" type="xsd:string"/> <xsd:element name="ispublic" type="xsd:boolean"/> <xsd:element name="userid" type="xsd:string"/> <xsd:element name="detailsid" type="xsd:integer" minOccurs="0"/> <xsd:element ref="queryMetaData"/> </xsd:sequence> <xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="id" type="xsd:integer" use="required"/> </xsd:complexType> </xsd:element> <xsd:element name="queryMetaData"> <xsd:complexType> <xsd:sequence> <xsd:element name="query" type="xsd:string"/> <xsd:element name="page" type="xsd:integer"/> <xsd:element name="lang" type="xsd:string"/> <xsd:element name="pageSize" type="xsd:integer"/> <xsd:element name="searchCtrl" type="xsd:string" minOccurs="0"/> <xsd:element name="soname" type="xsd:string" minOccurs="0"/> <xsd:element name="facetPaths" minOccurs="0"> <xsd:complexType> <xsd:sequence> <xsd:element name="facetPath" maxOccurs="unbounded"> <xsd:complexType> <xsd:sequence> <xsd:element name="value" maxOccurs="unbounded" minOccurs="0"> <xsd:complexType> <xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="value" type="xsd:string" use="required"/> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="categories" minOccurs="0"> <xsd:complexType> <xsd:sequence> <xsd:element name="category" maxOccurs="unbounded" minOccurs="0"> <xsd:complexType> <xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="eid" type="xsd:integer" use="required"/> <xsd:attribute name="compid" type="xsd:integer" use="required"/> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="tags" type="xsd:string" minOccurs="0"/> <xsd:element name="filters" minOccurs="0"> <xsd:complexType> <xsd:sequence> <xsd:element name="filter" maxOccurs="unbounded"> <xsd:complexType> <xsd:simpleContent> <xsd:extension base="xsd:string"> <xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="operator" type="xsd:string" use="required"/> <xsd:attribute name="type" type="xsd:string" use="required"/> </xsd:extension> </xsd:simpleContent> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema>
The web service response message for the method String getSavedSearches(String userName, String savedSearchRequest)
is based on the following XSD:
<?xml version="1.0" encoding="US-ASCII" ?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.example.com" targetNamespace="http://www.example.com" elementFormDefault="qualified"> <xsd:include schemaLocation="saved-search.xsd"/> <xsd:element name="savedSearches"> <xsd:complexType> <xsd:sequence> <xsd:element ref="savedSearch" maxOccurs="unbounded" minOccurs="0"/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema>
The web service response message for the method String saveSearch(String userName, String savedSearchRequest)
is the same as the response for getSavedSearch()
. For information, see Section 32.9.4.1, "getSavedSearch()."
The web service response message for the method String deleteSearch(String userName, String savedSearchRequest)
is the string success
.
The web service response message for the method String getSavedSearchDetails(String userName, String savedSearchRequest)
is based on the following XSD:
<?xml version="1.0" encoding="US-ASCII" ?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.example.com" targetNamespace="http://www.example.com" elementFormDefault="qualified"> <xsd:element name="savedSearchDetails"> <xsd:complexType> <xsd:sequence> <xsd:element ref="queryMetaData"/> </xsd:sequence> <xsd:attribute name="savedSearchId" type="xsd:integer" use="required"/> <xsd:attribute name="id" type="xsd:integer" use="required"/> </xsd:complexType> </xsd:element> <xsd:element name="queryMetaData"> <xsd:complexType> <xsd:sequence> <xsd:element name="query" type="xsd:string"/> <xsd:element name="page" type="xsd:integer"/> <xsd:element name="lang" type="xsd:string"/> <xsd:element name="pageSize" type="xsd:integer"/> <xsd:element name="searchCtrl" type="xsd:string" minOccurs="0"/> <xsd:element name="soname" type="xsd:string" minOccurs="0"/> <xsd:element name="facetPaths" minOccurs="0"> <xsd:complexType> <xsd:sequence> <xsd:element name="facetPath" maxOccurs="unbounded"> <xsd:complexType> <xsd:sequence> <xsd:element name="value" maxOccurs="unbounded" minOccurs="0"> <xsd:complexType> <xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="value" type="xsd:string" use="required"/> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="categories" minOccurs="0"> <xsd:complexType> <xsd:sequence> <xsd:element name="category" maxOccurs="unbounded" minOccurs="0"> <xsd:complexType> <xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="eid" type="xsd:integer" use="required"/> <xsd:attribute name="compid" type="xsd:integer" use="required"/> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="tags" type="xsd:string" minOccurs="0"/> <xsd:element name="filters" minOccurs="0"> <xsd:complexType> <xsd:sequence> <xsd:element name="filter" maxOccurs="unbounded"> <xsd:complexType> <xsd:simpleContent> <xsd:extension base="xsd:string"> <xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="operator" type="xsd:string" use="required"/> <xsd:attribute name="type" type="xsd:string" use="required"/> </xsd:extension> </xsd:simpleContent> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema>
The web service response message for the method String search(String userName, String queryMetaDataRequest)
is based on the following XSD:
<?xml version="1.0" encoding="US-ASCII" ?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.example.com" targetNamespace="http://www.example.com" elementFormDefault="qualified"> <xsd:include schemaLocation="query-metadata.xsd"/> <xsd:element name="searchResults"> <xsd:complexType> <xsd:sequence> <xsd:element name="hitsMetaData" minOccurs="0"> <xsd:complexType> <xsd:sequence> <xsd:element name="query" type="xsd:string"/> <xsd:element name="page" type="xsd:integer"/> <xsd:element name="pages" type="xsd:integer"/> <xsd:element name="hits" type="xsd:integer"/> <xsd:element ref="queryMetaData"/> <xsd:element name="categories" minOccurs="0"> <xsd:complexType> <xsd:sequence> <xsd:element name="category" maxOccurs="unbounded"> <xsd:complexType> <xsd:sequence> <xsd:element name="searchableObjects" minOccurs="0"> <xsd:complexType> <xsd:sequence> <xsd:element name="searchableObject" maxOccurs="unbounded"> <xsd:complexType> <xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="id" type="xsd:integer" use="required"/> <xsd:attribute name="lastTimeCrawled" type="xsd:integer" use="optional"/> <xsd:attribute name="displayName" type="xsd:string" use="required"/> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:sequence> <xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="id" type="xsd:integer" use="required"/> <xsd:attribute name="eid" type="xsd:integer" use="required"/> <xsd:attribute name="external" type="xsd:string" use="required"/> <xsd:attribute name="displayName" type="xsd:string" use="required"/> <xsd:attribute name="scope" type="xsd:string" use="required"/> <xsd:attribute name="applid" type="xsd:string" use="required"/> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="altwords" type="xsd:string" minOccurs="0"/> <xsd:element name="timespent" type="xsd:integer"/> <xsd:element name="facets" minOccurs="0"> <xsd:complexType> <xsd:sequence> <xsd:element name="facet" maxOccurs="unbounded" minOccurs="0"> <xsd:complexType> <xsd:sequence> <xsd:element name="pathEntry" maxOccurs="unbounded" minOccurs="0"> <xsd:complexType> <xsd:attribute name="pname" type="xsd:string" use="required"/> <xsd:attribute name="pdispname" type="xsd:string" use="required"/> <xsd:attribute name="pisleaf" type="xsd:boolean" use="required"/> <xsd:attribute name="value" type="xsd:string" use="required"/> <xsd:attribute name="count" type="xsd:integer" use="required"/> <xsd:attribute name="displayValue" type="xsd:string" use="required"/> </xsd:complexType> </xsd:element> <xsd:element name="entries" minOccurs="0"> <xsd:complexType> <xsd:sequence> <xsd:element name="entry" maxOccurs="unbounded"> <xsd:complexType> <xsd:attribute name="value" type="xsd:string" use="required"/> <xsd:attribute name="displayValue" type="xsd:string" use="required"/> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:sequence> <xsd:attribute name="root" type="xsd:string" use="required"/> <xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="dispname" type="xsd:string" use="required"/> <xsd:attribute name="isleaf" type="xsd:boolean" use="required"/> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="filters" minOccurs="0"> <xsd:complexType> <xsd:sequence> <xsd:element name="filter" maxOccurs="unbounded"> <xsd:complexType> <xsd:simpleContent> <xsd:extension base="xsd:string"> <xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="operator" type="xsd:string" use="required"/> <xsd:attribute name="type" type="xsd:string" use="required"/> </xsd:extension> </xsd:simpleContent> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="results" minOccurs="0"> <xsd:complexType> <xsd:sequence> <xsd:element name="result" maxOccurs="unbounded"> <xsd:complexType> <xsd:sequence> <xsd:element name="title" type="xsd:string"/> <xsd:element name="displayUrl" type="xsd:string"/> <xsd:element name="score" type="xsd:integer"/> <xsd:element name="searchableObject" minOccurs="0"> <xsd:complexType> <xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="eid" type="xsd:integer" use="required"/> </xsd:complexType> </xsd:element> <xsd:element name="content" type="xsd:string"/> <xsd:element name="keywords" type="xsd:string" minOccurs="0"/> <xsd:element name="lang" type="xsd:string"/> <xsd:element name="attributes"> <xsd:complexType> <xsd:sequence> <xsd:element name="attribute" maxOccurs="unbounded" minOccurs="0"> <xsd:complexType> <xsd:simpleContent> <xsd:extension base="xsd:string"> <xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="binding" type="xsd:string" use="required"/> <xsd:attribute name="type" type="xsd:string" use="required"/> <xsd:attribute name="displayName" type="xsd:string" use="required"/> </xsd:extension> </xsd:simpleContent> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="tags" type="xsd:string" minOccurs="0"/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema>
The web service response message for the method String getEngineInstances(String userName, String engineInstanceRequest)
is based on the following XSD:
<?xml version="1.0" encoding="US-ASCII" ?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.example.com" targetNamespace="http://www.example.com" elementFormDefault="qualified"> <xsd:element name="engineInstances"> <xsd:complexType> <xsd:sequence> <xsd:element name="engineInstance" maxOccurs="unbounded" minOccurs="0"> <xsd:complexType> <xsd:sequence> <xsd:element name="category" maxOccurs="unbounded" minOccurs="0"> <xsd:complexType> <xsd:sequence> <xsd:element name="searchableObjects" minOccurs="0"> <xsd:complexType> <xsd:sequence> <xsd:element name="searchableObject" maxOccurs="unbounded" minOccurs="0"> <xsd:complexType> <xsd:sequence> <xsd:element name="fieldDefs" minOccurs="0"> <xsd:complexType> <xsd:sequence> <xsd:element name="fieldDef" maxOccurs="unbounded" minOccurs="0"> <xsd:complexType> <xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="binding" type="xsd:string" use="required"/> <xsd:attribute name="dataType" type="xsd:string" use="required"/> <xsd:attribute name="isStored" type="xsd:boolean" use="required"/> <xsd:attribute name="isSecure" type="xsd:boolean" use="required"/> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="facetDefs" minOccurs="0"> <xsd:complexType> <xsd:sequence> <xsd:element name="facetDef" maxOccurs="unbounded"> <xsd:complexType> <xsd:sequence> <xsd:element name="facetEntryDef" maxOccurs="unbounded" minOccurs="0"> <xsd:complexType> <xsd:attribute name="value" type="xsd:string" use="required"/> <xsd:attribute name="displayValue" type="xsd:string" use="required"/> </xsd:complexType> </xsd:element> </xsd:sequence> <xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="binding" type="xsd:string" use="required"/> <xsd:attribute name="displayName" type="xsd:string" use="required"/> <xsd:attribute name="isleaf" type="xsd:boolean" use="required"/> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="actionDefs" minOccurs="0"> <xsd:complexType> <xsd:sequence> <xsd:element name="actionDef" maxOccurs="unbounded" minOccurs="0"> <xsd:complexType> <xsd:sequence> <xsd:element name="target" type="xsd:string"/> <xsd:element name="title" type="xsd:string"/> <xsd:element name="params" minOccurs="0"> <xsd:complexType> <xsd:sequence> <xsd:element name="param" maxOccurs="unbounded" minOccurs="0"> <xsd:complexType> <xsd:simpleContent> <xsd:extension base="xsd:string"> <xsd:attribute name="name" type="xsd:string" use="required"/> </xsd:extension> </xsd:simpleContent> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:sequence> <xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="isDefault" type="xsd:string" use="required"/> <xsd:attribute name="type" type="xsd:string" use="required"/> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:sequence> <xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="id" type="xsd:integer" use="required"/> <xsd:attribute name="displayName" type="xsd:string" use="required"/> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:sequence> <xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="eid" type="xsd:integer" use="required"/> <xsd:attribute name="id" type="xsd:integer" use="required"/> <xsd:attribute name="external" type="xsd:boolean" use="required"/> <xsd:attribute name="displayName" type="xsd:string"/> <xsd:attribute name="scope" type="xsd:string" use="required"/> <xsd:attribute name="applid" type="xsd:string" use="required"/> </xsd:complexType> </xsd:element> </xsd:sequence> <xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="id" type="xsd:integer" use="required"/> <xsd:attribute name="engineType" type="xsd:string" use="required"/> <xsd:attribute name="engineTypeId" type="xsd:integer" use="required"/> <xsd:attribute name="displayName" type="xsd:string" use="required"/> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema>
Invoke the ECSF web service by creating a JAX-WS proxy using the Oracle JDeveloper Web Service Proxy wizard. Then, modify the client Java class named AppModuleSearchServiceSoapHttpPortClient
to add calls to the ECSF web service.
Note:
It is assumed that the web service is deployed and running on a remote Oracle WebLogic Server instance.
Creating a JAX-WS web service proxy using the Oracle JDeveloper Create Web Service Proxy wizard generates all classes and Java files for the web service enabled methods under the package oracle.ecsf.service.query.common
.
To create a JAX-WS web service proxy:
In the Application Navigator, right-click the project in which you want to create the web service proxy, and choose New.
In the New Gallery, expand Business Tier, select Web Services and then Web Service Proxy, and click OK.
On the Select Web Service Description page of the wizard, enter the URL for the WSDL that was generated when the application was deployed on the Oracle WebLogic Server, for example, http://myhost.us.example.com:7101/CrmSearchService/AppModuleSearchService?WSDL
, then tab out of the field.
If the Next button is not enable, click Why Not? to understand what problem JDeveloper encountered when trying to read the WSDL document. If necessary, fix the problem after verifying the URL and repeat this step.
When the wizard displays an enabled Next button, then Oracle JDeveloper has recognized and validated the WSDL document.
For Specify Default Mapping Options, enter or choose a Java package name for the generated web service proxy class.
Click Next.
Continue through the pages of the wizard to specify details about the web service proxy. For more information about each page of the wizard, press F1 or click Help.
Click Finish.
Copy the following files from the system11.xxx/DefaultDomain/config/fmwconfig
Oracle WebLogic Server directory to the JAX-WS Client application's META-INF
directory.
jps-config.xml
cwallet.sso
default-keystore.jks
After you create the JAX-WS proxy, modify the AppModuleSearchServiceSoapHttpPortClient
class to include the calls to web service methods. Example 32-29 shows an example of a modified class.
Example 32-29 Sample Client Class
import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Properties; import javax.xml.namespace.QName; import javax.xml.ws.BindingProvider; import oracle.ecsf.SearchException; import oracle.ecsf.SearchHits; import oracle.ecsf.client.SearchGroup; import oracle.ecsf.client.dataobject.SavedSearch; import oracle.ecsf.client.dataobject.SavedSearchDetails; import oracle.ecsf.impl.QueryMetaDataImpl; import oracle.ecsf.meta.MetaEngineInstance; import oracle.ecsf.service.query.common.AppModuleSearchService; import oracle.ecsf.service.query.common.AppModuleSearchService_Service; import oracle.ecsf.service.query.ws.marshaller.ServiceUtil; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class AppModuleSearchServiceSoapHttpPortClient { private AppModuleSearchService_Service appModuleSearchServiceService; AppModuleSearchService appModuleSearchService; String wlsHost = null; String wlsPort = null; String wlsPassword = null; final Long engineInstanceId = 1L; public AppModuleSearchServiceSoapHttpPortClient() { initialize(); } public void initialize() throws Exception { if (System.getProperty("oracle.ecsf.debug.jdev") == null) { System.setProperty("oracle.security.jps.config", findFile("META-INF/jps-config.xml")); } try { //calling method initializeWLSparams to read parameter from file ecsf.properties initializeWLSParams(); URL aURL = new URL("http://" + wlsHost + ":" + wlsPort + "/CrmSearchService/AppModuleSearchService?WSDL"); QName qName = new QName("/oracle/ecsf/service/query/common/", "AppModuleSearchService"); appModuleSearchServiceService = new AppModuleSearchService_Service(aURL, qName); appModuleSearchService = appModuleSearchServiceService.getAppModuleSearchServiceSoapHttpPort(); ((BindingProvider)appModuleSearchService).getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "weblogic"); ((BindingProvider)appModuleSearchService).getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, wlsPassword); } catch (Exception e) { e.printStackTrace(); System.out.println("Excpetion " + e); } } /** * invoke the getEngineInstances() method exposed in WebService. */ public void testGetEngineInstance() { ServiceUtil sUtil = new ServiceUtil(); try { String query = "<request><enginetypeid>2</enginetypeid><locale>en-US</locale><scope>LOCAL</scope></request>"; String response = appModuleSearchService.getEngineInstances("weblogic", query); Collection<MetaEngineInstance> instances = sUtil.toEngineInstances(response); } catch (Exception e) { } } /** * invoke the search() method exposed in WebService. */ public void testSearch() { ServiceUtil sUtil = new ServiceUtil(); String request = "<request><queryMetaData><query><![CDATA[*]]></query><page>1</page><lang>en</lang><pageSize>10</pageSize><categories><category name=\"EmpSearch\" eid=\"100010024205617\" compid=\"100010026129681\"></category></categories></queryMetaData><request>"; try { String response = appModuleSearchService.search("weblogic", request); SearchHits hits = sUtil.toSearchHits(response); } catch (Exception e) { } } /** * invoke the getSavedSearch() method exposed in WebService. */ public void testGetSavedSearch() { ServiceUtil sUtil = new ServiceUtil(); try { String request = "<request><name>TestServiceproxy</name><callerctx>GLOBAL</callerctx><locale>en-US</locale><scope></scope></request>"; String response = appModuleSearchService.getSavedSearch("weblogic", request); SavedSearch ss = sUtil.toSavedSearch(response); } catch (Exception e) { } } /** * invoke the getSavedSearches() method exposed in WebService. */ public void testgetSavedSearches() { ServiceUtil sUtil = new ServiceUtil(); try { String request = "<request><name></name><callerctx>LOCAL</callerctx><locale>en-US</locale><scope>LOCAL</scope></request>"; String response = appModuleSearchService.getSavedSearches("weblogic", request); ArrayList<SavedSearch> savedSearches = sUtil.toSavedSearches(response); } catch (Exception e) { } } /** * invoke the savedSearch() method exposed in WebService. */ public void testSaveSearch() { ServiceUtil sUtil = new ServiceUtil(); try { SavedSearch savedSearch = createSavedSearch("TestServiceproxy"); String request = sUtil.toString(savedSearch, true); appModuleSearchService.saveSearch("weblogic", request); } catch (Exception e) { } } /** * invoke the getSavedSearchDetails() method exposed in WebService. */ public void testGetSavedSearchDetails() { ServiceUtil sUtil = new ServiceUtil(); try { String ssRequest = "<request><name>TestServiceproxy</name><callerctx>GLOBAL</callerctx><locale>en-US</locale><scope></scope></request>"; String ssResponse = appModuleSearchService.getSavedSearch("weblogic", ssRequest); String request = "<request>" + ssResponse + "<callerctx>null</callerctx><locale>en_us</locale><scope>LOCAL</scope></request>"; String response = appModuleSearchService.getSavedSearchDetails("weblogic", request); SavedSearchDetails ssDetails = sUtil.toSavedSearchDetails(response); } catch (Exception e) { } } /** * invoke the deleteSearch() method exposed in WebService. */ public void testDeleteSavedSearch() { try { String ssRequest = "<request>QA<name>TestServiceproxy</name><callerctx>GLOBAL</callerctx><locale>en-US</locale><scope></scope></request>"; String ssResponse = appModuleSearchService.getSavedSearch("weblogic", ssRequest); String request = "<request>" + ssResponse + "<callerctx>null</callerctx><locale>en_us</locale><scope>LOCAL</scope></request>"; String response = appModuleSearchService.deleteSearch("weblogic", request); } catch (Exception e) { } } private SavedSearch createSavedSearch(String sSearchName) throws SearchException { QueryMetaDataImpl queryMetaData = new QueryMetaDataImpl(); queryMetaData.setQueryString("%"); queryMetaData.setPageSize(10); queryMetaData.setCurrentPage(1); SearchGroup[] sgs = new SearchGroup[] { new SearchGroup("EmpSearch", "EmpSearch", engineInstanceId, null, null) }; queryMetaData.setSearchGroups(sgs); SavedSearch savedSearch = new SavedSearch(SavedSearch.VAL_INVALID_ID, "weblogic", null, null, null, sSearchName, "search created for WS interop", null, queryMetaData.getQueryString(), false, "GLOBAL"); SavedSearchDetails ssd = new SavedSearchDetails(1L, "weblogic", null, null, null, SavedSearch.VAL_INVALID_ID, queryMetaData, null); savedSearch.setSavedSearchDetails(ssd); return savedSearch; } private void initializeWLSParams() { //load wls host/port and ses wls host/port from ecsf.properties Properties prop = new Properties(); FileInputStream fis; try { fis = new FileInputStream(System.getenv("T_WORK") + File.separator + "ecsf.properties"); prop.load(fis); fis.close(); wlsHost = prop.getProperty("WLS_HOST"); wlsPort = prop.getProperty("WLS_PORT"); wlsPassword = prop.getProperty("WLS_PWD"); } catch (FileNotFoundException e) { System.out.println("File not found exeception : " + e.getMessage()); } catch (IOException e) { System.out.println("IO exception : " + e.getMessage()); } } private String findFile(String findme) { ClassLoader loader = Thread.currentThread().getContextClassLoader(); URL u = loader.getResource(findme); String fullname = u.getFile(); return fullname; } }
The sample client class illustrates how each of the methods are called and how the XMLs are deserialized.
When developing applications for international users, it is necessary to customize the display of data by adding locale-specific components and translating text.
Locales identify a specific language and geographic region. You must customize how ECSF presents and formats messages (that is, the data displayed to users) based on their locale. Locale affects:
Messages that you create during design time (for example, facet display names) and are displayed to the users who perform the queries.
Messages you create during deployment (for example, searchable object names, search category names, and index schedule names displayed during crawl management).
Crawlable content.
ECSF must determine the locale to display the messages in the appropriate language for the user.
ECSF provides a way for you to use translated strings to define the Title, Body, and Keywords properties of searchable objects.
The ECSFFormat
class provides two functions that can be called in Groovy expressions:
format(String key, Object param1, Object param 2,...)
takes in a resource bundle key name, as well as up to ten parameters, to be added to the formatted string. This function allows you to use translatable strings in the Groovy expression for the Title, Body, and Keywords properties.
getLabel(String attributeName)
takes in an attribute name and gets the translated label for this attribute. This function provides a way for you to get the translated value of an attribute label.
ECSF also reserves a Groovy entity formatter that provides two functions:
formatter.format(String key, Object param1, Object param 2,...)
allows you to format a string based on a template.
formatter.getLabel(String attributeName)
can be used to retrieve the UI label defined for an attribute.
To use translated strings in Groovy expressions, you must:
Associate a resource bundle to the view object.
Use the format()
function in the Groovy expressions for the Title, Body, and Keywords properties.
Associate a translated label to the attribute.
Use the getLabel()
function in the Groovy expressions for the Title, Body, and Keywords properties.
To define translatable strings for use as part of the crawlable search properties, you must associate a resource bundle to the view object and define the translatable strings on the resource bundle.
To add resource bundles to view objects:
In the overview editor, select the General navigation tab.
Click the Add icon in the Custom Properties table header and select Translatable Property to open the Select Text Resource dialog.
Select a resource bundle from the Resource Bundle dropdown menu.
Note:
If there is no resource bundle associated with the view object, then an external resource bundle is created in the application. Save the new resource bundle externally.
In the Display Value field, enter a string to associate with the key in the page's resource bundle. For example, enter
Identification Number: {0}. {1} {2} {3} {4} {5} {6}
.
In the Key field, enter a string to uniquely identify a locale-specific object in the resource bundle. For example, enter EMPVIEW_BODY
.
In the Description field, enter a description of any length for the key and value pair. For example, enter body value for crawling
.
Click Save and Select.
A new entry is added to the resource bundle, and the resource bundle is associated to the view object.
To use the translatable string in the Groovy expression for Title, Body, and Keywords, you can write a Groovy expression to call the formatter.format()
function with the key to the resource bundle entry as an input parameter. The other input parameters are standard Groovy input parameters.
For example, if the EMPVIEW_BODY
translatable string is defined as:
EMPVIEW_BODY=Identification Number: {0}. {1} {2} {3} {4} {5} {6}
then you can use the following Groovy expression for the Body property:
formatter.format("EMPVIEW_BODY", Deptno, Empno ((DeptView.size() > 0) ? "Dept:" : ""), DeptView.Dname, ((StatesEAView.size() > 0) ? "State:" : ""), StatesEAView.Name, TestTransient)
The resource bundle key name, as well as up to ten parameters are added to the formatted string.
For date attributes, you can write a Groovy expression to call formatter.format(String attributeName)
, without a resource bundle key as an input parameter, to correctly format the date attribute value as part of the Groovy expression.
In order for an attribute's label to be displayed in the correct locale, you must associate a resource bundle entry to the attribute.
To add labels to attributes:
In the overview editor, select the Attributes navigation tab.
Select the desired attribute in the Attributes table and click the Edit selected attribute(s) icon.
In the Edit Attribute dialog, select Control Hints to open the Control Hints page.
Click the icon next to the Label Text field to open and use the Select Text Resource dialog.
Select a resource bundle from the Resource Bundle dropdown menu.
Note:
If there is no resource bundle associated with the view object, then an external resource bundle is created in the application. Save the new resource bundle externally.
In the Display Value field, enter a string to associate with the key in the page's resource bundle.
In the Key field, enter a string to uniquely identify a locale-specific object in the resource bundle.
In the Description field, enter a description of any length for the key and value pair.
Click Save and Select.
A new entry is added to the resource bundle, and the resource bundle is associated to the view object attribute.
In order for the translated value of an attribute label to be crawled in the correct locale, the function getLabel()
must be called as part of the Groovy expression for Title, Body, and Keywords, as shown in Figure 32-7.
Figure 32-7 Example of Calling the getLabel() Function
In the example, formatter.getLabel("Ename")
retrieves the translated value of the attribute's label from the view object definition.
Calling the getLabel()
function retrieves the translated value of the attribute's label from the view object definition for crawling.
If not previously loaded for the current user's locale, facet display values are loaded by querying the list of values (LOV) associated with the facet in the context of the current user at query time. Whatever values or display values returned by querying the LOV in the context of the current user are loaded and returned as part of the facet in the query result for display in the user interface.
There are many ways to configure LOVs for localization. Two of them are described here: using the VL table and using resource bundles.
Facets are displayed in a tree.
Facet Display Name Facet Entry Display Name Facet Entry Display Name ...
The facet display name is translated per the resource bundle supported by Oracle Application Development Framework (Oracle ADF). The facet entry display names are translated per the LOV definition with context locale binding.
For example:
Organization Vision USA Vision Canada
Organization
is translated via the Oracle ADF resource bundle with key ORGANIZATION_ID
.
To translate Vision USA
and Vision Canada
, you need to create a view object based on the VL table that supports localization, for example, HR_ALL_ORGANIZATION_UNITS_VL
.
After this view object is created and used as the LOV for the BUSINESS_UNIT_ID
of the base searchable object, the value for the field name is pulled from the VL table with the correct locale of the current user. For information on how to create facets, see Section 28.4.4, "How to Implement Faceted Navigation."
When your facet is localized, Oracle Fusion Applications Search UI requests facet definitions from ECSF when users performs a search. ECSF will load the facet definition, including facet names from the resource bundle based on user's locale. When the user clicks the facet, ECSF will execute the LOV for the facet and retrieve the data from the database based on the current user's language setting. In the example, the organization name will be displayed to the user in his language. When the user clicks on a particular node, such as Vision USA
, ECSF will perform a query against the search engine with a filter on Organization Id = 204
where 204
is the organization ID for Vision USA
.
Facet display names can be localized with Oracle ADF resource bundles. When you create a facet, specify the name of a facet by referring to a resource key. At runtime, when the resource bundle is translated, the correct display name will be retrieved based on the user's locale. Localization of facet entries are supported by view object based LOVs. The view object must be designed to support localization.
Note:
Since facets are cached for performance, internationalized messages must be cached with the locale.
If the display name is not available for the current locale, the facet name is used.
ECSF uses LOVs to support facets, and the LOV display values must be translatable. The data sources of the LOVs used for facets can be view objects with static data or view objects with dynamic data (pulled from database through SQL). Display values of LOVs whose data sources are view objects with static data are displayed using the resource file corresponding to the application's current locale. Display values of LOVs populated with dynamic content can be translated based on the locale in the user's context.
You can translate the LOV display values based on the locale in the user's context by adding a language code column to the view object. The following instructions are based on the example provided in Section 28.4.4, "How to Implement Faceted Navigation." It assumes that you have an EmpView
base view object with a working LOV on the StatesView
view object already defined.
To translate LOV display values:
Add a LANG
column (VARCHAR2) to the STATES
table.
Populate the LANG
column for all rows with a 2-character ISO639 code (for example, en
or fr
).
Add the LANG
column to the States
entity object and StatesView
view object. Alternatively, you can re-create it from scratch.
Create a view criteria on StatesView
(on the view object, navigate to Query > View Criteria > +
and click the Add Criteria button) with the following values:
Attribute: Lang
Operator: equal to
Operand: Bind Variable
For Parameter, click New to create a bind variable with the following values:
Name: UserLang
ValueType: Expression
Click OK, and click OK again.
Navigate to EmpView > View Accessors
, select StatesView1
, and click Edit.
In the Edit View Accessor dialog, select the view accessor (StatesViewCriteria
) in the Available list and click the Move icon to add it to the Selected list.
Edit the UserLang
bind variable from StatesView
by entering the following Groovy expression that evaluates to the user's current language:
adf.context.locale.getLanguage()
The view criteria (similar to a defined WHERE
clause) on StatesView
and a bind variable named UserLang
are created. The EmpView
base view object is configured to use the view criteria when querying StatesView
and the value of the bind variable is set to the user's current language. During runtime, only the records where LANG
matches the locale.getLanguage()
of the locale is returned.
Crawl management display names—that is, the searchable object names, search category names, and index schedule names displayed during crawl management—must be translated to the language of the administration tool user. Enabling translation for these display names is handled in the database through the translation table so that it can be shared across runtime, the ECSF Command Line Administration Utility, and Fusion Applications Control.
Note:
For Fusion Applications Control, the display name for searchable objects, search categories, and index schedules is in the language of the object created by the administration users.
Deployment to Oracle SES is not based on translated fields.
Localize the crawl management display names by translating the seed data that you create in English. For information see Chapter 56, "Initializing Oracle Fusion Application Data Using the Seed Data Loader."
Content crawled into Oracle SES can support different languages. For searchable objects with dynamic content (content pulled from a database through view objects), ECSF supports one language per business object instance. An example is a sales order created by a customer with a particular language. In other words, ECSF only supports language on a per record or row basis.
While ECSF supports only one language per object instance, each instance can be a different language. ECSF detects the language for a given document. For information, see Section 32.10.6, "How to Determine Locale."
In addition to dynamic content, searchable objects can contain template content. Templates are text formats you create to form the body, title, keywords, action titles, parameters, and so on. In ECSF, you use Groovy scripting language to create expressions for some fields. The language must be identified to translate Groovy-enabled fields into the appropriate language before they are sent to the search engine. Localization for Groovy-enabled fields is supported by formatting functions.
ECSF provides a set of formatting functions based on Java Text Format Function. These formatting functions allow you more flexibility to build your desired formats. Example 32-30 illustrates the use of a Groovy function with Java Text Formatting to form the body for localization.
Example 32-30 Using Groovy Function to Translate the Body
formatter.format("EMPLOYEE_TEMPLATE", FirstName, LastName, EmailAddress, ZipCode) for (item in doc.getChildDocs("Reports")) { formatter.format("REPORTS_TEMPLATE", item.fields.FIRST_NAME, item.fields.LAST_NAME); }
EMPLOYEE_TEMPLATE
and REPORTS_TEMPLATE
are keys to two translatable templates that are stored in a resource bundle. The template must be a legal format string for java.text.MessageFormat
. (FirstName
, LastName
, EmailAddress
, and ZipCode
refer to view object attributes.)
To illustrate how the expression is resolved during runtime, see Table 32-2 for a sample view object, Table 32-3 for a sample child view object, and Example 32-31 for a sample resource bundle.
Table 32-2 Sample Parent View Object (Employee)
ID | FirstName | LastName | EmailAddress | ZipCode |
---|---|---|---|---|
1 |
John |
Wayne |
john.wayne@example.com |
94065 |
2 |
Chris |
Smith |
chris.smith@example.com |
94066 |
Table 32-3 Sample Child View Object (Reports)
ParentID | FIRST_NAME | LAST_NAME |
---|---|---|
1 |
John |
Doe |
1 |
Jake |
Ray |
2 |
Bob |
Barley |
2 |
Chris |
Carpenter |
Example 32-31 Sample Resource Bundle
id=EMPLOYEE_MESSAGE,message="Employee {0} {1} with email address {2} works in zipcode {4}" id=REPORTS_TEMPLATE,message=" direct reports {0} {1}"
Note:
This example is strictly used to illustrate functionality. Concatenation of words using two resource messages is not translation friendly.
The following shows the resulting data sent to Oracle SES during runtime:
Employee John Wayne with email address john.wayne@example.com works in zipcode 94065 direct report named John Doe has a direct report named Jake Ray Employee Chris Smith with email address chris.smith@example.com works in zipcode 94066 direct report named Bob Barley has a direct report named Chris Carpenter
Resource bundles are used to store language variations, while translation is the responsibility of Oracle Fusion Applications i18n support infrastructure.
To display messages in the appropriate language for the user, ECSF must determine the locale. How ECSF determines locale varies by module.
The Search page, an extension of Oracle JDeveloper, uses the locale of the Java Virtual Machine (JVM). This locale is set at either the machine level or at JDeveloper level. For information about setting the JVM locale for JDeveloper, see the JDeveloper online help.
The ECSF Command Line Administration Utility, a standalone and single user application, uses the default locale returned by Locale.getDefault()
.
You can specify the locale of the data to be indexed by using any of the following methods:
Language field
Crawler's language preference
Java Virtual Machine (JVM) default locale
You can specify a view object attribute as a language field for a searchable object by using the Search page. For information, see Section 28.2.3.1, "Setting Search Property Values for View Objects."
The value of this field for each instance is the language for the instance.
If you do not specify a language field for a given searchable object, ECSF uses the language preference of the crawler user. This implementation is application specific. ECSF obtains a session user through identity manager, and obtains the locale for the user while crawling data. There must be a crawler user with a proper locale profile, including language preference, created for Oracle Fusion Applications. This user's language preference is used as the default language if a language field does not exist.
If no crawler language is available, JVM's default locale (Locale.getDefault()
) is used to identify the language, and the JVM default language is used.
The user who calls the ECSF query time API must bind the locale to SearchContext
. If the locale is not set in the search context, ECSF attempts to get from ADFContext
. If that fails, the default locale, shown in Example 32-32, is used.
This section outlines the use of the diagnostic tests available in the ECSF application. The diagnostic service can be reached in a browser by appending Diagnostics to the ECSF data service URL. The data service URL will be shown on the Search Engine Instance Parameters tab in the Oracle Enterprise Manager Fusion Applications Control.
All test results will include the number of failures and errors, and the time taken in milliseconds to execute the test.
Tests that are marked as protected require the ECSF_All_Services permission to access.
These tests are used to diagnose issues in query functionality.
This test can be used as a sanity check to ensure that queries are returning data. The test queries for all records from the selected category. Table 32-4 lists the parameters.
Table 32-4 Parameters for Simple Query
Name | Type | Description |
---|---|---|
Searchable Group |
Drop-down |
The search category against which to invoke the category. The format of the parameter is <category>@<engine instance>. The selection [All Groups] can be made to search against all of the displayed groups. |
Note: The engine instance SES proxy user is used for the search and the search keyword is "*".
Result
Indicates if any search hits and facets are returned. The actual data are not displayed due to security reasons.
This test provides information about the selected searchable object and validates groovy expressions for the underlying view object. Table 32-5 lists the parameter of this test.
Table 32-5 Parameter for Searchable Object Metadata
Name | Type | Description |
---|---|---|
Searchable Object |
Drop-down |
The search object to inspect. The format of the parameter is <object>@<engine instance>. |
Results
Searchable object configuration, including its display name, view object name, ID, schema name, registered engine instance, associated schedule, and associated categories.
Searchable object status including if it is deployed, if it is active, and if the latest engine instance parameters have been applied to it. The deployment and crawl statuses of the associated schedule are also displayed, along with the deployment statuses of associated categories.
View object information, including the driving table, plugin class, if the plugin is ACL enabled, view object SQL select statement, view object fields, and child references.
Results of the body, title, keywords, and default action title validations.
Display of top-level facets. Actual data are obfuscated due to security reasons.
Searchable object actions.
This test displays the searchable groups for an engine instance. Table 32-6 lists the parameters of this test.
Table 32-6 Parameters for Searchable Groups Test
Name | Type | Description |
---|---|---|
Engine Instance Name |
Drop-down |
Name of the engine instance. |
Note: All searchable groups in the search application are displayed.
Result
Searchable groups for this engine instance, along with their associated searchable objects.
This test can be used as a more granular check to ensure that queries are returning data. Table 32-7 lists the parameters of this test.
Table 32-7 Parameters for Advanced Query Test (Protected)
Name | Type | Description |
---|---|---|
Searchable Group |
Drop-down |
The search category to invoke the category against. The format of the parameter is <category>@<engine instance>. The selection [All Groups] can be made to search against all of the displayed groups. |
Query Language (optional) |
String |
Specify a language for the query (language short code, such as "en"). If no language is specified then the currently configured language will be used. |
User Name |
String |
The user name to search with. Only data visible to this user will be shown. |
Query String |
String |
String to search for. |
Results
Result hit count: The number of hits for the first page of results (up to 10).
Estimate hit count: The estimated total hit count will for this query.
Alternate keywords if any.
Top-level facets including counts.
Search results: The title, body, and attribute values for the first page of results (up to 10 records) will be shown.
These tests are used to diagnose issues in crawler functionality, including ECSF feed generation.
This tests crawling of the object, splitting of its table, and processing of data feeds. Table 32-8 lists the parameters of this test.
Table 32-8 Parameters for Crawl Searchable Object Test
Name | Type | Description |
---|---|---|
Searchable Object |
Drop-down |
The search object to crawl. The format of the parameter is <object>@<engine instance>. |
Incremental Crawl |
Checkbox |
Tests incremental crawl on the Searchable Object, otherwise a full initial crawl will be simulated. |
Number of Batches to test |
Input (integer) |
Number of data feeds to execute (such as batches). -1 can be specified to process all data feeds/batches (not recommended for large data sets). |
Note: The engine instance crawl user is used for this test.
Results
SQL statement for the searchable object.
Statistics on each work unit (batch) including the number of documents crawled, the time taken, and the rate of documents processed by ECSF.
Total statistics for all work units processed.
This test displays information about the engine instance, tests proxy login into SES, tests ECSF security service authentication, and displays ECSF metadata as well as SES metadata. Table 32-9 lists the parameter of this test.
Table 32-9 Parameter for SES Instance Test
Name | Type | Description |
---|---|---|
Engine Instance Name |
Drop-down |
Select the ECSF engine instance to test. |
Results
SES admin endpoint.
ECSF service endpoint.
Result of proxy login into SES with stored credentials.
ECSF security service authentication status.
Search groups in ECSF.
Source groups in SES.
Index schedules in ECSF including the statuses in ECSF.
Index schedules in SES including the statuses in SES.
Searchable objects in ECSF.
Data sources in SES.
Number of configured proxy logins (federated trusted entities) in SES.
Configured identity plugin URL in SES.
This tests splitting of the table and generates the complete control feed for a searchable object. Table 32-10 lists the parameters of this test.
Table 32-10 Parameters for Control Feed Test
Name | Type | Description |
---|---|---|
Searchable Object |
Drop-down |
Select the searchable object. |
Incremental Crawl |
Checkbox |
If checked, it tests incremental crawl on the searchable object; otherwise a full initial crawl will be simulated. |
Note: The engine instance crawl user is used for this test.
Result
Complete control feed (including list of data feeds).
Tests a data feed for a searchable object. This tests crawling of the object, splitting of its table, and processing of data feeds. Table 32-11 lists the parameters of this test.
Table 32-11 Parameter for Data Feed (Protected) Test
Name | Type | Description |
---|---|---|
Data Feed URL |
Input (String) |
Enter a full data feed URL for a searchable object. |
Note: The part of the URL that points to the ECSF data service will be ignored. Instead the data feed will be invoked against the data service stored in the database for the object's associated engine instance.
Result
Complete XML data feed.
These tests provide information about the configuration of the ECSF environment.
This test lists the ECSF search engine instance parameters. Table 32-12 lists the parameter of this test.
Table 32-12 Parameter for Configuration Parameters Test
Name | Type | Description |
---|---|---|
Engine Instance |
Drop-down |
Specify the engine instance to inspect. |
Result
Values of the search engine instance parameters. Usernames will be obfuscated for security reasons.
This test retrieves environment information such as ECSF properties and ECSF jar extraction path on the server.
Results
System properties that begin with "oracle.ecsf".
Location of the Java class for this test on the server.
This tests the connection to the SearchDB data source.
Results
Displays if the application was able to obtain the connection successfully.
If connection is successful displays the connection URL.
This tests the application extension session for the given user. Table 32-13 lists the parameter of this test.
Table 32-13 Parameter for Application Extension/ApplCore Session Locale (Protected) Test
Name | Type | Description |
---|---|---|
User Name |
Input (String) |
Specify the user for the test. |
Results
Initializes the application extension session for the user.
Locale for the ApplCore session.
These tests are used to diagnose issues in the security layer of the ECSF application.
This tests various security functionalities for a user. Table 32-14 lists the parameters of this test.
Table 32-14 Parameters for Security (Protected) Test
Name | Type | Description |
---|---|---|
User Name |
Input (String) |
Specify the user to test. |
Permission (optional) |
Input (String) |
Specify a permission to check for the user. The format of the permission should be TYPE:NAME:ACTIONS. |
Engine Instance Name |
Drop-down |
The engine instance is used when retrieving credentials for non APPID users. |
Results
Checks that the user exists in the system.
Checks that the user has the given permission.
Checks that the user has access to the oracle.ecsf credential map.
Displays if the user has access to all ECSF services.
Displays if the user has access to the Diagnostics service if it does not have access to all services.
Checks that the credentials for the user can be obtained from the credential store.
This tests system access to the credential store. Table 32-15 lists the parameters of this test.
Table 32-15 Parameter for Credential Store Test
Name | Type | Description |
---|---|---|
Engine Instance Name |
Drop-down |
The engine instance determines which map to access in the credential store. |
Result
Checks that the system can write to the credential store by creating and removing credentials for a dummy user.
This tests the security plugin of a searchable object for a user. Table 32-16 lists the parameters of this test.
Table 32-16 Parameters for Security Plugin (Protected) Test
Name | Type | Description |
---|---|---|
Searchable Object |
Drop-down |
The search object to test against. The format of the parameter is <object>@<engine instance>. |
User Name |
Input (String) |
Specify the user to test. |
Attribute Name (optional) |
Input (String) |
The security attribute to use for the test. If no attribute is given then the default security attribute will be used. |
Results
Security attribute values for the user from the plugin.
Security principals for the user.
This section describes common problems that you might encounter when using ECSF and explains how to solve them.
The following are common problems you may encounter and solutions that solve them:
You remove the ECSF Runtime Server library from the project and save, but the library reappears in your project.
Problem
The Common-Model.jar
file that you added to your project contains a dependency on ECSF Runtime Server.
Solution
Remove the Common-Model.jar
file.
Your feed request made through either Oracle SES or the browser returns no data.
Problem
After you initially crawl the data source, subsequent feed requests result in incremental feeds (that is, feeds that contain only changes in data).
Solution
Override the incremental feed by performing one of the following tasks:
Through Oracle SES, start full indexing from the Fusion Applications Control. For information, see the "Starting Full Indexing" section in Oracle Fusion Applications Administrator's Guide.
Through the browser, append ?forceInitialCrawl=true
to the config feed.
You receive an error indicating that the execution time of the configuration or data feed execution thread is exceeding the timeout settings, for example:
Error: name has been busy for "elapsedTime" seconds working on the request "curReq", which is more than the configured time (StuckThreadMaxTime) of "maxTime" seconds.
Following are two possible causes and solutions for this issue:
Problem
A SQL script being executed by ECSF for the configuration feed or data feed is taking a long time to execute.
Solution
Enable SQL tracing to find long-running SQL processes, and tune the SQL script to reduce the execution time.
Problem
ECSF is unexpectedly running longer than the configured time.
Solution
Increase the Oracle WebLogic Server warning timeout setting.
You receive Class Not Found
errors when you run the ECSF servlet.
Problem
When you created the ECSF application, you did not select the Fusion Web Application (ADF) template.
Solution
Add the Fusion Web Application (ADF) template through Application Properties.
You receive a java.lang.OutOfMemoryError: PermGen space
exception when you deploy the ECSF application to Oracle WebLogic Server instance or when you run the application.
Problem
MaxPermSize
is set too low.
Solution
Increase MaxPermSize
by starting the WebLogic JVM using the -XX:MaxPermSize=256m
parameter.
If you start the ECSF servlet from within JDeveloper using the Integrated WebLogic Server:
Go to the jdev cache directory /.jdeveloper/DefaultDomain/bin
.
Open setDomainEnv.sh
.
Locate the line that contains -XX:MaxPermSize=128m
, and change it to -XX:MaxPermSize=256m
.
Oracle ADF/UI Shell pages fail to load or a blank page appears. You receive the following exception in the JDeveloper Log window:
java.lang.NoClassDefFoundError: oracle/ecsf/client/SearchCtrl at oracle.apps.fnd.applcore.globalSearch.ui.ecsf.ECSFSearchUtils.getSearchControl(ECSFSearchUtils.java:67)
Problem
The ECSF Client library is missing from the project class path.
Solution
Update the project class path with the ECSF Client library.
You encounter memory leaks while using the ECSF query API to define the Oracle Fusion Applications Search user interface.
Problem
SearchContext
is implemented as a ThreadLocal
variable, which is created when ContextFactory.getSearchContext()
is first called in the current Thread. All subsequent calls to getSearchContext()
within the same Thread results in that instance being returned. Since the ThreadLocal
variable remains associated with the Thread, memory leaks occur.
Solution
After the completion of your Oracle Fusion Applications Search UI logic and before results are returned to the UI for rendering, you must call the SearchContext.release
method.
When the SearchContext.release
method is called on the SearchContext
, the instance of the ThreadLocal
is removed from the current Thread. A subsequent call to getSearchContext
then results in the creation of a new instance of the SearchContext
ThreadLocal
variable. The SearchContext.release
method also implicitly call releaseConnection()
.
Note:
If you call SearchContext.release
and then need to call getSearchContext()
again within the same Thread, then you must set any parameters you need on the SearchContext
again as it is a brand new instance.
The table spaces required are:
SEARCH_DATA
SEARCH_INDEX
SEARCH_TEMP
Verify the details for SEARCH_DATA using this SQL statement:
select FILE_NAME, TABLESPACE_NAME, BYTES, MAXBYTES, BLOCKS, MAXBLOCKS from sys.dba_data_files where TABLESPACE_NAME = 'SEARCH_DATA';
Use this command to add additional table space for SEARCH_DATA:
ALTER TABLESPACE SEARCH_DATA ADD DATAFILE '/slot/ems7248/oracle/db/apps_st/data/SEARCH_DATA_3.dbf' SIZE 1052M AUTOEXTEND ON;
The DBF filepath will depend on the environment being used. To learn the exact DBF file to be used, use the select command shown above. For example: /slot/ems7248/oracle/db/apps_st/data/SEARCH_DATA_3.dbf
To delete an additional datafile:
ALTER TABLESPACE SEARCH_DATA DELETE DATAFILE '/slot/ems7248/oracle/db/apps_st/data/SEARCH_DATA_9.dbf';
The same steps can be used to add additional data files for other table spaces.
On a provisioned environment, the crawls will not work for all users. The users will need to be modified.
Pre-requisite: Find the application role for which the user must be added.
As an example, take the Application role ZCA_CRM_FUSION_SEARCH_CRAWL_DUTY and assign sales_admin to this role. ZCA_CRM_FUSION_SEARCH_CRAWL_DUTY is the application role that is necessary for a user to access the feeds.
Login to CRM EM with the required credentials.
Right-click CRMDomain and select Security > Application Roles.
Select the Stripe as crm and in Roles enter ZCA_CRM_FUSION_SEARCH_CRAWL_DUTY and search.
Click the role ZCA_CRM_FUSION_SEARCH_CRAWL_DUTY and click Add to add the sales_admin user.
Click OK.
The user sales_admin now can be used for crawling.
Problem
The endpoints for the search applications are not up and running.
Solution
Set the correct search application endpoints in the connections.xml file of the client application. Make sure the IS_ACTIVE
parameter corresponding to this search engine instance is set to "Y". Make sure the IS_ACTIVE
parameter corresponding to this search engine instance is set to "Y" in the ECSF_PARAMETER
table.
Problem
If your search application only contains one category and the category is secured, the Global Search UI will display this error message if this category does not pass the permission check. In this case, no categories are available for search.
Solution
Usually this is because the permission set on the searchable object is not accessible to the logged-in user, causing the secured category to not be returned by the search application.
Problem
Search_Server1 is not up and running.
Solution
Bounce if required.
Problem
wsm-pm is not up and running. For example, wsm-pm is hosted in the SCM_CommonServer for FSCM.
Solution
Bounce if required.
Problem
The identity management setup in SES administration is pointing to an invalid URL combination and the proxy user cannot log into ECSF security service.
Solution
Change the identity management setup to point to the correct url using the correct username and password.
Problem
The response from the Search servers may be very slow and the Search UI is unable to fetch all the results.
Solution
Increase the WS timeout using this parameter in the startup section on the WLS console for the Search Server
-Doracle.ecsf.service.ws.timeout=500000
Problem
In B16, the category drop-down is not displayed in the main UI page. The Global Search UI does not load categories until an initial search is performed by clicking the Search button. The Global Search UI will show this error if getting categories failed against all the search applications. The endpoints for the search applications are not up and running or the search applications are inactive in the database.
Solution
Set the correct search application endpoints in the connections.xml file of the client application. Make sure the IS_ACTIVE
parameter corresponding to this search engine instance is set to "Y". Make sure the IS_ACTIVE
parameter corresponding to this search engine instance is set to "Y" in the ECSF_PARAMETER
table.
Cause
If the search applications are up and running but this error is displayed, all the search applications probably are returning errors.
Look for the following line in the messages logged in the client server log, such as CustomerServer-diagnostics.log:
at oracle.ecsf.service.query.ws.marshaller.ServiceUtil.toError(ServiceUtil.java:1499)
Cause
The crawl for the data sources under this category was not successful.
Solution
Log into SES administration and check that the schedule for the data source indexed successfully.
Cause
This exception may occur on the SES when a user tries to run a schedule. This is caused if the administration server and the manager servers are not started from the correct locations. (Console/node manager)
Solution
The adminserver must be started using nodemanager and all other managed servers must be started by using the Administration console.
On most of the provisioned environments, the ESS logs will be found in <APPLTOP>/instance/ess/rfd. This will contain the crawl records for all the crawls run on the SES installed in that environment. If the location of these logs is changed, log in to the Enterprise Manager farm and update the RequestFileDirectory
attribute.
The SES crawls may fail due to various reasons. Some of the most common issues are listed here.
Check if the ESS and search_server1 managed servers are running on the Common domain. If these are not running, the crawls will fail.
Check if the corresponding Search server is in the "RUNNING" state.
Check if the END points mentioned in the SES Source page are accessible.
Check if the database has sufficient space to accommodate the crawled data. Check first query to increase the table space.
Verify the security attributes for the Searchable View Object (SVO). Also verify if the passwords for CRAWL_APPIDs are correct.
Check that these users are not locked: FUSION_APPS_FSCM_SES_CRAWL_APPID, FUSION_APPS_CRM_SES_CRAWL_APPID, and FUSION_APPS_HCM_SES_CRAWL_APPID.
The SES Administration page uses "searchsys" as the default user for logging in. The password for SES can be discovered using WebLogic Server Scripting Tools (WLST) commands.
Connect to WLST.
Run the command:
listCred(map="oracle.apps.security",key="FUSION_APPS_ECSF_SES_ADMIN-KEY")
Sample output:
Already in Domain Runtime Tree [Name : searchsys, Description : null, expiry Date : null] PASSWORD:welcome1
To diagnose ECSF problems in the development environment, you can view the log messages in the Oracle WebLogic Server at DOMAIN_HOME/servers/SERVER_NAME/logs/SERVER_NAME-diagnostic.log
.
You can configure the log level for ECSF by using Fusion Applications Control or Oracle WebLogic Scripting Tool. For information, see the "Configuring Settings for Log Files" chapter in the Oracle Fusion Middleware Administrator's Guide.
The log level for ECSF can be set to the following values:
TRACE
for FINE
NOTIFICATION
for INFO (default level)
WARNING
for WARNING
ERROR
for SEVERE
The following ECSF loggers can be used for logger name:
oracle.ecsf.AdminLogger
oracle.ecsf.ClientLogger
oracle.ecsf.RuntimeLogger