JDeveloper & ADF af:inputListOfValues: enable case insensitive search

This blog entry describes a use case which is based on a question in the OTN JDeveloper & ADF forum.

Use case
In a data entry form there is one attribute which gets its values from an input list of values (af:inputListOfValues). The af:inputListOfValues component offers an input text field and a search facility which allows the use to look up the correct data. However, the look up uses a case sensitive search by default. The question is how to use a case insensitive search for the af:inputListOfValues to make the usability better for the user?

Implementation
The implementation of this use case can be done declarative, there is no java code needed. The sample, which you can download using the link provided at the end of the post, uses the Oracle HR schema to show how to do this. It build using JDeveloper 11.1.1.5.0 but should work in other versions too. We use the employees and jobs table from the HR schema. In the UI we use an input form for the employees and get the JobId via an af:inputListOfValues where the use can search for the right JobId.
The sample uses the default ‘Fusion Web Application’ application template as basis. The model project uses the two tables (employees and jobs) as business model. In the UI the search part of the af:inputListOfValues uses the ‘All Queriable Attributes’ for the search popup which is the automatically created view criteria for a view object. It shows all attributes of a view object which have the queriable property set to true. You find this property in the attribute section of the view object.
If you setup the LOV attribute in the emplyoees view object the default way, you end up with an inputListOfValues in the UI like:

inputListOfValue: Search popup using all queriable attributes

inputListOfValue: Search popup using all queriable attributes

Note that you have to use ‘A’ to find something. Using ‘a’ will not find anything. This is the problem we solve in this blog.

To implement an case insensitive search we have to create another view criteria in the Jobs view object. There we declare that we want to ‘Ignore Case’ for the attributes we are searching for. The final result of the view criteria looks like

JobsView: Create View Criteria

JobsView: Create View Criteria

Once this is saved we can open the EmployeesView and setup the model drivel LOV for the JobId of an employee row. Open the EmployeesView view object , select the Attributes node, select the JobId attribute and open the ‘List of Values’ for it. There we add a new entry resulting in the image below:

EmployeesView: setup LOV for JobId

EmployeesView: setup LOV for JobId

The essential part is to switch to the ‘UI Hints’ tab and there change the view criteria to use from ‘All Queriable Attributes’ to the view criteria created in the previous step.

EmployeesView: use own view criteria

EmployeesView: use own view criteria

Now after all is saved and compiled, lets run the application and see that the search popup for the af:inputListOfValues now uses our view criteria and indeed the search is case insensitive.

Search popup using case insensitive search

Search popup using case insensitive search

You can download the sample using this link: BlogCaseInsensitiveInputLOV.zip
The sample is build using JDev 11.1.1.5.0 and uses the HR schema.
The sample contains two pages Empdefault and Emp. Empdefault uses the normal LOV view criteria. The Emp page uses the view criteria created with case insensitive search.

Advertisements

JDeveloper: access resources from the applications jar or classpath in the Model or ViewController

This bog describes how to read resources, which are part of the applications classpath and are deployed with the application.

Use Case
You want to read a resource e.g. a property file in the model layer or the view layer or an image which is part of the deployed application. As you don’t know where exactly the application is deployed, you can’t use the normal java.io.* classes as they require an absolute path to the file to read.

Implementation
In the Sample which is provided with this blog (see the link at the end of the blog) we read a properties file ‘model.properties’ in the model layer and make the values abailable via a service method in the application module. In the view layer we similar read another properties file ‘view.properties’ which we access through a bean method.

The UI consists of only one page which has two panelForms. Each has an inputText component where you can enter the key of the property you want to read, a button to activate a method to read the property and an outputText to show the result.

Running application

Running application

Model project resources:

# Model resources
ModuleName=BARTPAppModule
CreationDate=2012-08-01
EmptyKey=

ViewController project resources:

## Properties file for hte view controller
ViewControllerName=Hallo ik bin ein Berliner
CreateDate=2012-08-02

After entering a key value we get the values displayed:

Running application after getting some values

Running application after getting some values

Let’s start with the implementation in the model layer. In the application module implementation class we add a service method which is implemented as singleton (for the module), meaning that the resource is only loaded once and stored in the application module. Activation and passivation don’t need to be handled here, as the resource is read again after each activation as the local variable mModelProperties will be null after an activation.

public class BARFPAppModuleImpl extends ApplicationModuleImpl implements BARFPAppModule {
    private static ADFLogger _logger = ADFLogger.createADFLogger(BARFPAppModuleImpl.class);
    private static String PROPERTY_FILE = "de/hahn/blog/accessresourcesfrompath/model/resources/model.properties";
    Properties mModelProperties = null;

    /**
     * Returns the value of a property read from the model property file
     * @param key of the property to retrieve
     * @return value of the key or null if not found
     */
    public String getModelResource(String key) {
        // read property file only once
        if (mModelProperties == null) {
            initProperties();
        }

        return mModelProperties.getProperty(key);
    }

    /**
     * load the properties from the resource file
     */
    private void initProperties() {
        InputStream asStream = this.getClass().getClassLoader().getResourceAsStream(PROPERTY_FILE);
        if (asStream == null) {
            _logger.severe("Could not load property file: '" + PROPERTY_FILE + "'");
            mModelProperties = new Properties();
            return;
        }

        mModelProperties = new Properties();
        try {
            mModelProperties.load(asStream);
        } catch (IOException e) {
            e.printStackTrace();
            _logger.warning("Can't load properties: " + e.getMessage());
        }
        _logger.info("Model properties loaded!");
    }
...
}

The essential part is to use the class loader to read the resource as stream (line 24). The class loader allows us to read resources from the class path itself without knowing the absolute path in the file system. You only need to know the package structure and replace the ‘.’ which delimit the packages with the ‘/’. The class loader can then access all folders relative from its own load point. For more information check ClassLoader java doc.
The rest of the implementation is easy now. The same technique is used in the bean of the view controller project. Here we implement the method in a bean which we call on the click of a button ‘getViewReource’.

public class ResourceReaderBean {
    private static ADFLogger _logger =
        ADFLogger.createADFLogger(ResourceReaderBean.class);
    private Properties mViewProperties = null;
    private static String PROPERTY_FILE =
        "de/hahn/blog/accessresourcesfrompath/view/resource/view.properties";

    private void initProperties() {
        // instead of using the de.hahn.testproxy.backingbeans.test.properties you have to use de/hahn/testproxy/backingbeans/test.properties
        InputStream asStream =
            this.getClass().getClassLoader().getResourceAsStream(PROPERTY_FILE);
        if (asStream == null) {
            // file not found
            _logger.info("File not found: '" + PROPERTY_FILE + "'");
            return;
        }
        mViewProperties = new Properties();
        try {
            mViewProperties.load(asStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (!mViewProperties.isEmpty()) {
            _logger.info("Properties loaded: " + mViewProperties.toString());
        }

    }

    public void getViewResourceListner(ActionEvent actionEvent) {
        String value = "";
        // read property file only once
        if (mViewProperties == null)
            initProperties();

        BindingContainer bindingContainer =
            BindingContext.getCurrent().getCurrentBindingsEntry();
        AttributeBinding attrKey =
            (AttributeBinding)bindingContainer.getControlBinding("ViewResourceKey1");
        String key = (String)attrKey.getInputValue();
        if (mViewProperties != null && key != null) {
            String val = mViewProperties.getProperty(key);
            AttributeBinding attrValue =
                (AttributeBinding)bindingContainer.getControlBinding("ViewResourceValue1");
            attrValue.setInputValue(val);
        }
    }
...
}

The key to load from the resource is read from the binding variable ‘ViewResourceKey1’, the returned value is put back into the binding variable ‘ViewResourceValue1’. Both are defined in the variables section of the pageDef of the ShowProperty.jspx page.

You can download the sample from here BlogAccessResourcesFromPath.zip.
The sample was built with JDev 11.1.1.6.0 and uses the HR schema.