../E63259-01.epub /> ../E63259-01.mobi />

70 Using the Property Service

The Service Access Layer's property service provides a simple, scalable way for developers to access data and make it available to client applications.

This chapter includes the following topics:

70.1 What Is the Property Service?

This section describes the Property Service and its uses and its components.

70.1.1 Introduction

The property service is a mechanism for retrieving and updating data through REST or Java APIs. The data can be stored in any data source, such as relational databases, Oracle Metadata Service (MDS) repositories, and LDAP repositories. Unlike a data provider, which fetches data into the context of a scenario (Section 67.1, "What Are Data Providers?"), the property service can be used to fetch and update data outside the context of a scenario. In addition, the property service lets you create organized representations of data called property sets, each uniquely associated with a namespace. To find a property set, you simply look in its namespace using a REST request or Java method call. For information on scenarios, see Section 66.1.1, "Personalization Architecture."

Note:

As a convenience, WebCenter Portal provides a property service data provider that allows you to fetch data from a property set into the context of a scenario. For more information, see Section 70.5, "Using the Property Service Data Provider."

70.1.2 What is the Property Service Used For?

Many use cases for the Property Service and its features exist. An important use case is the ability to aggregate data from multiple sources and make the data available to scenarios. As you will see, the Property Service is integrated with the Conductor and scenarios through a data provider. The data provider provides access to data supplied from the Property Service inside the context of a scenario. For example, you could create a user profile that consists of data from several sources and then use that profile in multiple scenarios.

70.1.3 What are Property Sets?

A property set is simply a collection of related properties. For example, a property set might represent a collection of books and include properties like ISBN number, title, author, number of pages, and so on.

Each property set has a schema, called a property set definition. This definition specifies zero or more properties (members of the set), which can have names, descriptions, and data types. Think of a property set as an instantiation of a property set definition.

Figure 70-1 shows a property set definition in the visual editor in JDeveloper. Let's look at the parts of a property set definition one by one.

Figure 70-1 Modeling a Property Set Definition in JDeveloper

Description of Figure 70-1 follows
Description of "Figure 70-1 Modeling a Property Set Definition in JDeveloper"

First, the property set definition is modeled as a hierarchy. The visual editor in JDeveloper makes property set definition creation easy. First, at the top of the hierarchy, a namespace element is defined. All property sets exist in the context of a namespace. You can use the namespace name to find your property set definition with REST requests or Java method calls. In Figure 70-1, the namespace is called myProperties.

Next, the property set definition itself is created and named. In our example, the property set definition is called Employee. The next step is to populate the Employee property set definition with property mappings. Each property mapping has a name, a definition (like a data type), and a locator class associated with it. Figure 70-2 shows the dialog used to create a new property mapping, and the dropdown menu that lets you select a definition for the property mapping. Definitions include String, StringArray, Number, Int, DateTime, and several others. For example, a "name" property mapping might have a definition type of String. As you can see, property sets are particularly useful for modeling well-structured data such as user profiles.

Figure 70-2 Creating a Property Mapping

Description of Figure 70-2 follows
Description of "Figure 70-2 Creating a Property Mapping"

70.1.4 What is a Locator?

Each property set is associated with a Java component called a locator. A locator is a custom implementation of the ILocator class, and includes methods for retrieving, filtering, and updating property set data. In this sense, a locator is similar to a data provider (Section 67.1, "What Are Data Providers?").You can use the REST API (or Java API) to retrieve data directly to a client application, like a mobile application or a portal.

Note:

You can attach a locator class at the namespace level, the property set definition level, or at the individual property level. Locators are resolved in a specific order of precedence. Locators attached to individual properties take precedence over a property set definition-level locator, and so on. If no custom locator is specified, the default locator is used.

A default property set locator is provided with WebCenter Portal that retrieves and stores property set data to a pre-configured database. This default locator is used when no other is specified for the property set. If the default locator is insufficient for your use case, you can develop a custom locator. See also Section 70.7, "Implementing a Custom Locator."

70.1.5 Caching for the Property Service

The property service also includes an integrated caching service and an interface for writing data validation code. See Section 70.6, "Using the Property Service Caching Service."

70.1.6 Using the Property Service with Scenarios

If you are not familiar with concepts like the Conductor and scenarios, refer to Chapter 66, "Personalizing Oracle WebCenter Portal Applications."

It is important to note that the property service is not directly tied to the Conductor. This means you can use the property service to retrieve and update data outside the context of a scenario. However, WebCenter Portal provides a property service data provider that lets you retrieve data from the property service into a scenario, where you can further filter and process the data, batch it with data from other scenarios, and take advantage of other data integration features, like business objects.

70.1.7 Architectural Overview

Figure 70-3 shows the overall architecture of the property service, as described in the previous sections.

Figure 70-3 Property Service Architecture

Description of Figure 70-3 follows
Description of "Figure 70-3 Property Service Architecture"

70.2 Creating a Property Set Definition in JDeveloper

This section explains how to create a new property set definition.

Note:

Generally, it's best to create clearly defined property definitions with one or more property mappings. However, a zero-element property set definition permits property sets to be created dynamically, and may be useful in some cases.

Note:

Property set definitions created in JDeveloper are imported into MDS during deployment. All property sets created at run-time that are based on those property set definitions are stored in the default database (or other persistence storage as configured through custom locators).

To create a property set definition in JDeveloper, follow these steps:

  1. Be sure the data integration components are included in your project classpaths. See Section 2.5, "Setting Up JDeveloper for Personalization."

  2. In the Application navigator, right-click your project and select New.

  3. In the New Gallery dialog, under the General category, select Personalization.

  4. In the Items part of the dialog, select Properties Namespace and click OK.

  5. In the Create Properties Namespace dialog, give the namespace a name.

  6. The Property Service editor opens in design view. Right-click the Property Namespace Definitions node and select Create New Property Set Definition, as shown in Figure 70-4.

    Figure 70-4 Creating a New Property Set Definition

    Description of Figure 70-4 follows
    Description of "Figure 70-4 Creating a New Property Set Definition"

  7. In the Create New Property Set Definition dialog, enter a name and click OK.

  8. Right-click the new property set definition node and select Create New Property Set Definition Mapping.

    Note:

    This dialog lets you define individual property mappings to include in the property set definition. Note that each property mapping can have a Locator Class. The default locator class looks in the default database for property set data. To obtain data from another source, you need to implement a custom locator. For more information, see Section 70.7, "Implementing a Custom Locator."
  9. In the Create/Edit Property Mapping dialog, give the property a name. Pick a Definition (like a data type) for the property. For example, a name might be type StringDef and an employee ID might be an IntDef (integer). You can also specify a Locator Class for the property. If you don't specify a Locator Class, the property uses the default Locator. See Section 70.1.4, "What is a Locator?."

  10. To create more properties, right-click the Property Set Definition node and follow these same steps.

  11. Save your work.

The property set definition must next be deployed to the server, where it can be used to instantiate new property sets.

70.3 Deploying the Property Set Definition

After you create a property set definition, you need to deploy it to a server. You can do this from JDeveloper, and deploy to either the Integrated WebLogic Server or to an external managed server. After you deploy the property set definition, you can access it through REST APIs, Java APIs, or in a scenario through the Property Service Data Provider.

In this example, we will deploy to the Integrated WebLogic Server instance.

  1. Create one or more property set definitions, as explained in Section 70.2, "Creating a Property Set Definition in JDeveloper."

  2. Decide where you intend to deploy to. The target server must be running.

  3. From the application menu, select Deploy Personalization Files.

  4. Select the deployment target:

    • To Last Selected Server – Deploys to the last selected server.

    • To Server – This option lets you select the server to deploy to.

    • To Filesystem – Deploys a Metadata Archive (MAR) file to the filesystem. This file can later be deployed to the server at a later time.

  5. For this example, select To Server.

  6. In the Deploy to Server dialog, select IntegratedWebLogicServer and DefaultServer as the server instance.

    Figure 70-5 The Deploy To Server Dialog

    Description of Figure 70-5 follows
    Description of "Figure 70-5 The Deploy To Server Dialog"

  7. Click OK. JDeveloper deploys the set definition files to the server. Technically, they are placed in a Metadata Archive (MAR) file, which is then deployed to the server. You can view the results of the deployment in the Deployment Log window, as shown in Figure 70-6.

    Figure 70-6 Deployment Log Window

    Description of Figure 70-6 follows
    Description of "Figure 70-6 Deployment Log Window"

Now that the property set definition is deployed, you can quickly test the deployment.

70.4 Testing the Property Set Definition Deployment

This section explores two ways that you can test the deployment of a property set definition. The first is by locating the property set definition through the REST APIs. The second is to use the Property Set Definition data provider in a scenario.

70.4.1 Locating the Property Set Definition Using REST

One way to locate the property sets available to you is to use a tool that lets you send REST requests and view responses. Many such tools and browser plugins exist. For information about using REST APIs, see Chapter 53, "Using Oracle WebCenter Portal REST APIs."

  1. In a REST client tool, enter this URL, where host and port are the host and port name where the WCPS server is running.

    http://host:port/wcps/api/property/resourceIndex
    
  2. Locate the namespace URI and enter its URL in the browser. For example:

    http://host:port/wcps/api/conductor/namespaces
    

    For example: http://myhost:7101/wcps/api/conductor/namespaces

  3. Look in the response for the property set namespace(s) you created. For example, if you created a property set namespace called Employee_Namespace (see Section 70.2, "Creating a Property Set Definition in JDeveloper"), the response will look similar to the response shown in Figure 70-7.

    Figure 70-7 REST Response Showing the Deployed Namespace Employee_Namespace

    Description of Figure 70-7 follows
    Description of "Figure 70-7 REST Response Showing the Deployed Namespace Employee_Namespace"

70.4.2 Locating the Property Set Definition Using the Data Provider

You can access deployed property set definitions in a scenario through the property service data provider. For details, see Section 70.5, "Using the Property Service Data Provider."

70.5 Using the Property Service Data Provider

The property service data provider (oracle.PropertiesServiceProvider) allows you to integrate property service data into a scenario. This provider lets you:

  • retrieve property sets for a specified property set definition

  • retrieve a property set by name

  • return a specific property from a property set

70.5.1 Accessing the Property Service Data Provider in a Scenario

You use the property service data provider like any other provider, by selecting the Invoke Data Provider function in a scenario:

  1. In the scenario editor, create a new scenario. For information on using the scenario editor, see Chapter 66, "Authoring Personalized Scenarios in JDeveloper."

  2. If asked, create a URL Connection to the server. Enter the following information in the URL Connection dialog.

    Field Name Value
    Name Conductor
    URL Endpoint http://host:port/wcps/api/conductor/resourceIndex

    for example: http://example.com:7101/wcps/api/conductor/resourceIndex

    Authentication Type Basic
    Username weblogic
    Password weblogic1
    Realm WCPS

  3. Click the Start node and select Add Following Statement and then Invoke Data Provider.

  4. Click the Invoke Provider node and select Invoke Provider Properties.

  5. In the Invoke Provider dialog, open the oracle.PropertiesServiceProvider node, then open LocalServerConnection and finally open GetProperiesResource nodes. See Figure 70-8.

Figure 70-8 Exposing the Property Service Data Provider Methods

Description of Figure 70-8 follows
Description of "Figure 70-8 Exposing the Property Service Data Provider Methods"

Select a method to execute and enter parameters at the bottom of the dialog. The parameters let you specify with the property set or property to retrieve. For details on the methods, see Section 70.5.2, "Property Service Data Provider Method Reference."

70.5.2 Property Service Data Provider Method Reference

This section describes each of the property service data provider methods. These methods let you gain access to property sets and their properties in a specified namespace.

70.5.2.1 getProperty(definition, set, property)

Retrieves a property from the current, default namespace.

Parameters:

  • definition – The name of a property set definition that exists in the default namespace.

  • set – The name of an instance of the property set definition.

  • property – The name of the property you wish to retrieve.

Returns:

An object of the property's type. Returns null if no property is found.

Example:

getProperty("EmployeeSetDef", "kjones", "address")

70.5.2.2 getProperty(namespace, definition, set, property)

Retrieves a property from the specified namespace.

Parameters:

  • namespace – The name of a namespace.

  • definition – The name of a property set definition that exists in the default namespace.

  • set – The name of an instance of the property set definition.

  • property – The name of the property you wish to retrieve.

Returns:

An object of the property's type.

Example:

getProperty("NS1", "EmployeeSetDef", "kjones", "address")

70.5.2.3 getPropertySet(definition, set)

Retrieves a property set in the current or default namespace.

Parameters:

  • definition – The name of a property set definition that exists in the default namespace.

  • set – The name of an instance of the property set definition.

Returns:

A Map object containing the property set.

Example:

getPropertySet("EmployeeSetDef", "kjones")

70.5.2.4 getPropertySet(namespace, definition, set)

Retrieves a property set in the specified namespace.

Parameters:

  • namespace – The name of a namespace.

  • definition – The name of a property set definition that exists in the default namespace.

  • set – The name of an instance of the property set definition.

Returns:

A Map object containing the property set.

Example:

getPropertySet("NS1", "EmployeeSetDef", "kjones")

70.5.2.5 getPropertySets(definition, search, restrictions)

Retrieves a list of property sets that are instances of the specified property set definition. The list can be managed with optional search and restrictions parameters. The method looks in the current or default namespace.

Parameters:

  • definition – The name of a property set definition that exists in the default namespace.

  • search – (Optional) Apply the provided search expression (a string) to retrieve the specified property sets. If null, all property sets for the provided property sets will be retrieved (within the pagination context).

  • restrictions – (Optional) A List object specifying a list of properties. The method will only retrieve the provided in this list. If null, all properties are retrieved.

Returns:

An object of the property's type.

Example:

getProperty("EmployeeSetDef", "tmyProp:equals:someValue")

Other search string examples:

myFavoriteHobbies:contains:campingtps-created-on:gt:1980-01-01T00:00:00.000-070

70.5.2.6 getPropertySets(namespace, definition, search, restrictions)

Retrieves a list of property sets that are instances of the specified property set definition. The list can be managed with optional search and restrictions parameters. The method looks in the specified namespace only.

Parameters:

  • namespace – The name of a namespace.

  • definition – The name of a property set definition that exists in the default namespace.

  • search – (Optional) Apply the provided search expression to retrieve the specified property sets. If null, all property sets for the provided property sets will be retrieved (within the pagination context).

  • restrictions – (Optional) A List object specifying a list of properties. The method will only retrieve the provided in this list. If null, all properties are retrieved.

Returns:

An object of the property's type.

Example:

getProperty("NS1", "EmployeeSetDef", "tmyProp:equals:someValue")

Other search string examples:

myFavoriteHobbies:contains:campingtps-created-on:gt:1980-01-01T00:00:00.000-070

70.6 Using the Property Service Caching Service

The property service includes a built-in caching layer that automatically caches property sets when they are returned. The property service uses the Oracle Coherence, an in-memory data grid caching solution that provides fast access to frequently used data. For detailed information on configuring Oracle Coherence, see the Oracle Coherence Documentation.

The property service cache configuration file is located in:

$ORACLE_HOME/user_projects/applications/<domain>/conductor-extensions-library/WEB-INF/classes.

You are free to modify the default cache configuration file, or add other cache configuration files if desired. All cache factories instantiated by the property service are specific to the property service classloader. The cache configuration file is located in:

$ORACLE_HOME/user_projects/applications/<domain>/conductor-extensions-library/WEB-INF/classes.

The configurations can be changed to suit the end-user needs, but the names of the caches must remain unchanged.

70.7 Implementing a Custom Locator

Each property set is associated with a Java component called a locator. A locator is a custom implementation of the ILocator class, and includes methods for retrieving, filtering, and updating property set data. If the default locator is insufficient for your use case, you can develop a custom locator.

This section describes how to implement a simple custom locator, configure it, and invoke it. Even though this is a basic example, it illustrates many important aspects of custom locator development and use.

For a general introduction to locators, see Section 70.1.4, "What is a Locator?."

70.7.1 Overview of the Example and Prerequisites

Before you begin developing a custom locator in JDeveloper, be sure you have things set up properly. There are a few configurations that you need to make or verify for your environment. For details, see Section 2.5, "Setting Up JDeveloper for Personalization."

Note:

In this example, the locator is created in an Fusion Web Application in JDeveloper. You can also create function providers in WebCenter Portal applications or any other type of JDeveloper application that includes Java capabilities.

Our example describes how to create a locator that accesses book-related data, like author, title, and IBSN number. Here, the raw data is simply hardcoded into a Java class, but a the locator could be written similarly to access data in a database.

We also illustrate using the Data Access Object (DAO) pattern to delegate data access from the locator, a commonly used approach. Whether the data is a library of books, a user database, or an inventory system, the same pattern applies.

The main steps include:

  • Define a Book property set definition.

  • Let the property service know about the Book property set definition.

  • Implement the IPropertyLocator interface to load properties from a Book object.

70.7.2 Creating a Property Set Definition

Following the general instructions in Section 70.2, "Creating a Property Set Definition in JDeveloper," create a new property set definition with these parts:

  • Call the namespace book.property.locator.

  • Call the property set definition BookPropertySetDefinition

  • Add three property mappings of type StringDef called title, author, and ISBN.

Figure 70-9 shows this simple definition in the visual editor in JDeveloper.

Figure 70-9 Example Property Set Definition for a Book

Description of Figure 70-9 follows
Description of "Figure 70-9 Example Property Set Definition for a Book"

For now, we will use the default locator class. Later, we will change the default to use our new custom locator implementation.

70.7.3 Making Up Data: Implement a Simple Library Class

The class in Example 70-1 simply creates a Map from hardcoded, static book data. The book's titles are used as the Map keys. In a real use case, data would come from an external data source, like a library database.

Example 70-1 A Class to Create Book Data

package locator;
 
import java.util.HashMap;
import java.util.Map;
 
class Library {
    static String [] titles = {"Into Thin Air", "Climbing Everest", "Rocky Mountains"};
    static String [] ISBNs = {"0-201-69581-2", "0-423-78123-1", "0-321-23425-2"};
    static String [] authors = {"Jon Krakauer", "Fooey Handley", "Rick Bicknell"};
 
    // Keyed by title
    private static Map<String, Book> library = new HashMap<String,Book>();
    
    static void generateLibrary() {
        for (int i=0; i<titles.length; i++)
        {
            Book book = new Book(titles[i], authors[i], ISBNs[i]);
            library.put(book.getTitle(), book);
        }
    }
   
   static Book getBook(String title) {
     return library.get(title);
   }
}

70.7.4 Backing the Data with a JavaBean

The JavaBean class in Example 70-2 represents the book attributes hardcoded into our Library class: title, author, and ISBN number. To simplify the example code, we add a getProperty(String name) method. In practice, JavaBean introspection is a better practice.

Example 70-2 A Simple JavaBean Representing Book Data

package locator;
 
 
public class Book
{
    String title;
    String author;
    String ISBN;
    
    public Book(String title, String author, String ISBN) {
      setTitle(title);
      setAuthor(author);
      setISBN(ISBN);
    }
 
    public void setTitle(String title) {
        this.title = title;
    }
 
    public String getTitle() {
        return title;
    }
 
    public void setAuthor(String author) {
        this.author = author;
    }
 
    public String getAuthor() {
        return author;
    }
 
    public void setISBN(String ISBN) {
        this.ISBN = ISBN;
    }
 
    public String getISBN() {
        return ISBN;
    }
    
    String getProperty(String propName) {
         if (propName.equals("ISBN")) {
           return getISBN();
         }
         if (propName.equals("title")) {
           return getTitle();
         }
         if (propName.equals("author")) {
           return getAuthor();
         }
         return null;  
    }
}

70.7.5 Implementing a Java Data Access Object

The DAO class is more interesting than the previous classes. Here, the DAO does the hard work of fetching data from a source. In this case, the source is our Library object, but it could be a database, REST service, or other source.

Example 70-3 A Data Access Object Implementation

package model;
 
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import oracle.wcps.property.IContext;
import oracle.wcps.property.IProperty;
import oracle.wcps.property.IPropertyDefinition;
import oracle.wcps.property.IPropertyDefinitionName;
import oracle.wcps.property.IPropertyMapping;
import oracle.wcps.property.IPropertyName;
import oracle.wcps.property.IPropertyService;
import oracle.wcps.property.IPropertySet;
import oracle.wcps.property.IPropertySetDefinition;
import oracle.wcps.property.ServiceFactory;
import oracle.wcps.property.Type;
import oracle.wcps.property.model.Property;
 
class BookPropertyDAO {
    IPropertyService service;
    
    // Generate the library that will provide our backing store.
    static
    {
        Library.generateLibrary();
    }
 
    /**
     * Assume the name of the PropertySet is the title of the book.
     */
    void loadProperties(IPropertySet propertySet,
                        IPropertySetDefinition iPropertySetDefinition,
                        List<IPropertyName> propertyNames, IContext context) throws Exception
    {
 
        String title = propertySet.getName().getName();
        Book book = Library.getBook(title);
        loadProperties(book, propertySet, iPropertySetDefinition,
                       propertyNames, context);
    }
 
    private void loadProperties(Book book, IPropertySet propertySet,
                         IPropertySetDefinition iPropertySetDefinition,
                         List<IPropertyName> propertyNames, IContext context) throws Exception
    {
        Map<IPropertyName, IPropertyMapping> mappings =
            iPropertySetDefinition.getPropertyMappings();
        
        // Null propertyNames is valid, and indicates to get all properties
        if (propertyNames==null)
        {
            propertyNames = new ArrayList<IPropertyName>();
            propertyNames.addAll(mappings.keySet());
        }
 
        // Loop over all property names, create a Property value, and add it to the Property set
        // for (IPropertyName pname : propertyNames)
        {
            String value = book.getProperty(pname.getName());
            if (value != null)
            {
                IPropertyMapping mapping = mappings.get(pname);
                addProperty(value, pname, propertySet, mapping, context);
            }
        }
    }
 
    // Add typed properties according to the information in our mappings
    private void addProperty(String value, IPropertyName pname,
                             IPropertySet propertySet, IPropertyMapping mapping, IContext context)
    {
        // The property mappings could be useful if we wanted to get the individual
        //PropertyDefinitions and inspect their type.
        IPropertyDefinitionName pdefName = mapping.getPropertyDefinitionName();
        
        // We need the namespace to look up our property definitions
        if (service==null)
        {
            String ns = propertySet.getNamespaceName().getName();
            System.err.println("Using namespace: " + ns);
            //service = ServiceFactory.getPropertyService(IContext.NULL, ns);
            service = ServiceFactory.getPropertyService(context, ns);
        }
        
        IPropertyDefinition pdef =
            service.getPropertyDefinition(context, pdefName);
            //service.getPropertyDefinition(IContext.NULL, pdefName);
        
        Type type = pdef.getType();
 
        IProperty ps = Property.builder().withProperty(pname, value, type).build();
        
        System.err.println("Adding " + ps.getName() + " of type " + ps.getType());
        propertySet.putProperty(pname, ps);
    }
}

70.7.6 Implementing the ILocator Class

Finally, Example 70-4 lists the locator class itself. The first thing to notice is that we are implementing ILocator. The interface includes several methods that enable a locator to do full CRUD (create, read, update, delete) operations. However, our example only implement the loadProperties(), which corresponds to the "read" operation. For more information on this interface, you can refer to the WebCenter Portal API Reference (Javadoc).

Another important point is that the loadProperties() method delegates to the DAO. The DAO class has an identical method called loadProperties() that does the work of fetching data from the Library data store.

Example 70-4 Example Locator Class

package locator;
 
import java.util.List;
 
import java.util.Map;
 
import oracle.wcps.property.IContext;
import oracle.wcps.property.INamespaceName;
import oracle.wcps.property.IPagedList;
import oracle.wcps.property.IPropertyLocator;
import oracle.wcps.property.IPropertyMapping;
import oracle.wcps.property.IPropertyName;
import oracle.wcps.property.IPropertySet;
import oracle.wcps.property.IPropertySetDefinition;
import oracle.wcps.property.IPropertySetDefinitionName;
import oracle.wcps.property.filter.PropertySetFilterContext;
import oracle.wcps.property.filter.expression.PropertySetExpression;
 
public class BookPropertyLocator implements IPropertyLocator
{
    private BookPropertyDAO dao;
 
    // Must have a public default constructor, since the Property Service instantiates
    // this
 
    public BookPropertyLocator()
    {
        dao = new BookPropertyDAO();
    }
 
    /**
     * Load property values, optionally returning only a subset of those.
     * @param context the IContext containing parameters passed in from the PropertyService
     * @param iPropertySet The PropertySet into which the retrieved values will be loaded
     * @param iPropertySetDefinition The PropertySetDefinition defining the 'shape' of the properties
     * @param propertyNames List of PropertyNames to load.  If null, all will be loaded.
     */
    public void loadProperties(IContext context, IPropertySet iPropertySet,
                               IPropertySetDefinition iPropertySetDefinition,
                               List<IPropertyName> propertyNames)
    {
        try
            
            // Delegate to BookProperDAO
            dao.loadProperties(iPropertySet, iPropertySetDefinition, propertyNames, context);
        } 
        catch (Exception e) {
            throw new RuntimeException("Cannot load properties ", e);
        }
    }
 
 
    /**
     * Filter properties; load/return those properties that only match the filter criteria.
     * @param context the IContext containing parameters passed in from the PropertyService
     * @param iNamespaceName
     * @param iPropertySetDefinitionName
     * @param propertySetFilterContext
     * @return
     */
    public IPagedList<IPropertySet> filter(IContext context, INamespaceName iNamespaceName,
                                           IPropertySetDefinitionName iPropertySetDefinitionName,
                                           PropertySetFilterContext propertySetFilterContext)
    {
        return null;   //To Be Implemented
    }
 
    // As a read-only implementation, we don't support this
    public void storeProperties(IContext context, IPropertySet iPropertySet,
                                IPropertySetDefinition iPropertySetDefinition,
                                List<IPropertyName> list)
    {
        throw new UnsupportedOperationException("BookPropertyLocator is read-only");
    }
 
    // As a read-only implementation, we don't support this
    public void removeProperties(IContext context, IPropertySet iPropertySet,
                                 List<IPropertyName> list)
    {
        throw new UnsupportedOperationException("BookPropertyLocator is read-only");
    }
 
    // As a read-only implementation, we don't support this
    public void removeProperties(IContext context, INamespaceName iNamespaceName,
                                 IPropertySetDefinitionName iPropertySetDefinitionName)
    {
        throw new UnsupportedOperationException("BookPropertyLocator is read-only");
    }
    
    public int count(IContext context, INamespaceName p1, IPropertySetDefinitionName p2, PropertySetExpression p3) 
    { 
        return 0;
    }
}
;

Let's look a the loadProperties() method of the ILocator interface in a little more detail. This method takes these parameter types:

  • IContext – The IContext object is the vehicle for authentication. An object of this type is passed in from the property service. It includes data like the username and password credentials of the logged in user. For example, you could retrieve the user name and password like this:

    String u = context.getProperty(IContext.USERNAME_KEY);
    string p = context.getProperty(IContext.PASSWORD_KEY);
    

    You can also retrieve the request object and use it to obtain the credentials, or other request information:

    HttpServletRequest request = context.getProperty(IContext.HTTP_REQUEST_KEY)
    
  • IPropertySet – The retrieved property set values are loaded into this object.

  • IPropertySetDefinition – The object that defines the "shape" of the data. This shape is based on the PropertySetDefinition you created previously, in Section 70.7.2, "Creating a Property Set Definition."

  • List<IPropertyName> – This object provides a list of PropertyName objects to load. If null, all PropertyName objects are loaded.

Now that the example classes are finished, we can compile, deploy, and use the locator.

70.7.7 Updating the PropertySetDefinition with the Custom Locator

When we created the property set definition previously, we used the default Locator. Now that we have implemented a custom locator, we need to add it to the definition.

  1. Locate the ns_book.property.locator.xml file in the Resources folder of your project.

  2. Right-click the Locators node in the design view and select Edit Locator Info.

  3. Click the Add icon (a plus symbol) and enter BookPropertyLocator in the New Locator dialog, as shown in Figure 70-10, and click OK.

    Figure 70-10 Adding the Custom Locator

    Description of Figure 70-10 follows
    Description of "Figure 70-10 Adding the Custom Locator"

  4. In the Locator Map Configuration dialog, add the Unassigned Properties to the Locator Assigned Properties list. When you are finished, author, title, and ISBN should be listed as assigned properties.

  5. Click OK.

  6. In the design view, you will see the custom locator now appears in the Locator Info node.

  7. Save your work.

70.7.8 Compiling and Deploying the Example

Before deploying, compile your project by whatever method is customary to you. For example, in JDeveloper, you can select Make from the Build menu.

To deploy your property namespace definition to the server, follow the instruction in Section 70.3, "Deploying the Property Set Definition."

You also need to deploy your custom locator classes to the server, follow these steps:

70.7.8.1 Setting Up the JAR File Structure

If you are unfamiliar with JAR file creation in JDeveloper, this section explains how to set up your JAR file structure (a deployment profile) to ensure that all the required elements are included.

  1. Right-click your project (in this example, the project called Model) in the Application Navigator and select Project Properties.

  2. In the Project Properties dialog, select Deployment.

  3. Click New.

  4. Select JAR File as the Archive Type and give the JAR a name.

  5. Click OK.

  6. In the JAR Options dialog, select Contributors.

  7. Be sure that Project Output Directory, Project Source Path, and Project Dependencies are selected, as shown in Figure 70-11.

    Figure 70-11 Selecting Project Output Contributors

    Description of Figure 70-11 follows
    Description of "Figure 70-11 Selecting Project Output Contributors"

  8. Select Filters.

  9. Select the Patterns tab.

  10. In the Patterns tab, add the following file patterns to include and exclude specific types of files from the JAR.

    Figure 70-12 shows these patterns after they have been added to the list.

    • Include **.class

    • Exclude **.java

    • Exclude **.txt

    • Exclude **.html

    Figure 70-12 Selecting JAR File Contents

    Description of Figure 70-12 follows
    Description of "Figure 70-12 Selecting JAR File Contents"

  11. Click OK, and then OK in the Project Properties dialog.

  12. Save your project.

70.7.8.2 Create a JAR File

After the JAR deployment profile is set, you are ready to generate a JAR file from your project.

  1. Right-click the project (in this case, the Model project) in the Application Navigator and select Deploy.

  2. Select the JAR file you want to deploy. This is the name you gave the file in Section 70.7.8.1, "Setting Up the JAR File Structure."

  3. In the Deployment Action dialog, select Deploy to JAR file and click Finish.

The JAR file is placed in your project directory. You can view it on the file system in: <Workspace_Directory>/Model/deploy. For example, if your Workspace is called MyProviders, you might find the JAR here: C:\JDeveloper\mywork\MyProviders\Model\deploy.

70.7.8.3 Copy the JAR File to the Server

You must copy the JAR file to the server.

  1. Copy the JAR file that you created in the previous step. As noted previously, the file is located in <Workspace_Directory\Model\deploy.

  2. Paste the JAR file into the DefaultDomain of your server, here:

    $DOMAIN_HOME/locator-extensions-library/WEB-INF/lib

    For example:

    C:\JDeveloper\system11.1.7.40.63.82\DefaultDomain\locator-extensions-library\WEB-INF\lib

  3. Restart the server.

70.7.9 Creating a Scenario to Use the Locator

Follow these basic steps to create a scenario. For more information on creating scenarios, see Section 66.2.2, "Authoring Personalized Scenarios in JDeveloper."

  1. Create a new scenario called BookPropertyScenario.

  2. Add an Invoke Provider node to the scenario.

  3. Edit the provider properties.

  4. In the list of known providers, open the oracle.PropertiesServiceProvider node and drill down to the provider methods.

  5. Select the GetProperty(namespace, definition, set, property) method.

  6. Add the following parameter values:

    Table 70-1 Parameter Values for the Locator

    Parameter Value

    namespace

    book.property.locator

    definition

    BookPropertySetDefinition

    set

    Into Thin Air

    property

    author


  7. Remember to specify a return variable in the Edit Provider Properties dialog. For this example, call the variable property.

  8. Create a return statement to return the property value. Remember, you must use expression language (EL) format for the return variable: ${property}.

  9. Save the scenario and run it.

70.7.10 Viewing the Scenario XML Source

The XML source code for the scenario created in the previous section looks like this:

<scenario:scenario xmlns:common="http://xmlns.oracle.com/wcps/conductor/common/1.0.0" xmlns:scenario="http://xmlns.oracle.com/wcps/conductor/scenarios/1.0.0">
  <body>
  <call-provider>
      <provider-name>oracle.PropertiesServiceProvider</provider-name>
      <method-name>GetProperty</method-name>
      <variable>property</variable>
      <input>
        <parameter>
            <common:name>namespace</common:name>
            <common:value>book.property.locator</common:value>
        </parameter>
        <parameter>
            <common:name>definition</common:name>
            <common:value>BookPropertySetDefinition</common:value>
        </parameter>
        <parameter>
            <common:name>set</common:name>
            <common:value>Into Thin Air</common:value>
        </parameter>
        <parameter>
            <common:name>property</common:name>
            <common:value>ISBN</common:value>
        </parameter>
      </input>
    </call-provider>
    <return>
      <expression>${property}</expression>
    </return>
  </body>
  <name>BookPropertyScenario</name>
</scenario:scenario>