Write your own Audit Rule Extension in JDeveloper 12C

JDeveloper comes with a nice audit framework, one of the great things about this framework is that you can write your own code to check for specific standards or fire specific rules you want to check. If you want to write extensions in 11g I recommend one off the two following posts:
For 11R1 check Arvinder Singh's blog.
For 11R2 check John ‘JB’ Brock's blog.
JDeveloper 12C is more like the 11R2 way, but still differs in some things. Especially the blog entry by John 'JB' Brock was very useful to me.

For more information about creating Audit Rules, please check out my index page on topics around this subject.

Now, before you start, don’t forget to get the Extension SDK in JDeveloper, this is very easy to download through Help -> Check for Updates -> Extension SDK. In this example I wrote a simple rule, that checks the pagedef file for iterators and wether the cacheResults property is set to false. If so, it throws a warning to point out that this setting might not be the way you want it.

Start a new Application and pick the Extension Application:

Give it a good name and except all the defaults in the other steps. By default JDeveloper creates a Res.properties file for you that is your resource bundle. Next to that it creates an extension.xml and a Manifest.mf.

The extensions.xml is much cleaner in 12C, the Manifest takes over some tasks from this extension file. The great thing is that you can use the overview from the Extension.xml where you configure your extension and that JDeveloper automaticly generates the Manifest file for you:


Next you need to configure your hook in the Extension.xml, this is where you define your Java class where the actual rule magic happens.


As said, the overview works pretty good to configure what you need in the extension.xml, but I will also give the xml snipped from the source:
    
        
                            
                
                
                    sample-category
                    true
                    warning
                
                
                     nl.olrichs.abc.audits.inn.IterCacheAnalyzer
                                
                
                    JSF
                
            
        
    

In the triggers section, you define your audit-hook, fill in the category that it belongs to, I choose a sample-category. Set the properties on the rule-definition, make sure you give it a good ID, set the severity and put it in the correct category. Next you define your analyzer class, this is the Java Class you need to fire the rule.
Last but not least you need to define a project technology as trigger.

Next we can define some properties in the resource bundle that will be picked up automatically (notice that the resource bundle is coupled to your extension by the extension.xml):


So lets look at the actual Java class that is defined in the audit-hook. First off all, this class needs to extend the oracle.jdeveloper.audit.analyzer.Analyzer.
Next you need to inject the rule into the analyzer:
    @ExtensionResource("nl.olrichs.abc.audits.rule-invalid-iter-cache")
    private Rule CACHE_RESULT_FALSE;

Now you can hook into different enter and/or exit methods. In this example I only need the enter method for the document and the exit on the attribute. The code is in the snipped below, see the JavaDoc section for functional explanation:
   
    /**
     * Enter a document.
     * Check to see if this is a pageDefinition file. If not, we can stop here.
     */
    public void enter(AuditContext context, Document document) {
        String firstNodeOfdocument = document.getDocumentElement().getNodeName();
        if (!"pageDefinition".equals(firstNodeOfdocument)) {
            setEnabled(false);
        }
    }

    /**
     * Enter an element, put the element on the context. 
     */
    public void enter(AuditContext context, Element element) {
            context.setAttribute(elementKey, element);        
    }

    /**
     * Exit an attribute, check if this element is inside an iterator.
     * If so, check if we're an cacheResult attribute and check the value.
     * Report the results back to the Editor.
     */
    public void exit(AuditContext context, Attr attr) {
        if ("iterator".equals(attr.getOwnerElement().getNodeName()) &&
            "CacheResults".equals(attr.getName()) &&
            "false".equalsIgnoreCase(attr.getValue())) {
            context.report(CACHE_RESULT_FALSE);
        }
    }

Now that the rule is set up, lets look at running and testing this rule. What I do first is deploy the extension to the current platform:


After this, you can deside to Run or Debug the extension by right clicking the project and select Run or Debug Extension. You will see that a new instance of JDeveloper gets started and you can test your extension in here.

In the newly started JDeveloper, you can make a final check in your preferences to see the rule. Here you can configure your Audit profile. Go to Tools -> Preferences -> Audit -> Profiles:

Here you should see the category that you filled into your resource bundle and under it the rule that your just created. Make sure the checkbox is enabled so it will run.

I created a fake pageDef with an iterator and the cacheResult property set to false. You see that the rule gets fired and the configured message from the resource bundle is shown. You also see the warning on the right top in the source editor: