Don't fear the Audit -- Part 1

Have you ever looked at the JDeveloper IDE, while you're writing code, and seen the warnings or errors that come up in the left and right gutters? Have you thought, "wouldn't it be great if the editor caught XYZ in my code?"

Well, you can write your own Audit extension to have the IDE look for just about anything.

The Audit Framework that comes with JDeveloper is very powerful, and really not that hard to extend.  It can help with maintaining company standards, or enforcing efficiency and protocol standards that may be set by your team.

You can even go as far as to write transforms (fixes) that will make the changes to the code for you when it finds something that you pre-defined.

For this topic, I'm going to use a project that I wrote specifically for this example.  You can download the entire project as a .zip file and place it into your work directory if you like.  I'm using JDeveloper 11gR2 for this example project. If you don't have this latest release, you can still follow along and I will try to point out the differences between the R1 syntax and the newer R2 syntax.

UPDATE (02/17/2012): There has been a nice write up about this topic, specifically done for 11gR1 over on Arvinder Singh's blog If you are using 11gR1 (11.1.1.x) then I would head over there as well.

In Part One of this topic, I'll cover the writing of the analyzer, to find the suspect code and send a report to the IDE.  In Part Two, I'll cover how to write a transform to automate the modification of what you report in the analyzer.

For most audits setting up the analyzer and having it report something to the IDE is all you need to do.

This is broken down into two parts.

  • Declarative entries in the extension.xml file
  • Analyzer class

The Extension.xml 

Let's start in the extension.xml file and work from there.

As you can see, we are going to add an <audit-hook> element to the file.  If you are using JDev 11gR1, this will go into the <hooks> section, if you are using 11gR2, this goes into the <triggers> section. Otherwise, the syntax is the same.

Let's take a closer look at each of the elements in the example above.

The <audit-hook> ID parameter must be a unique id.

The <category-definition> is what tells the IDE where to display the rules when you look at the Tools >> Preferences >> Audits >> Profiles dialog.
There is a label, description, and message parameter for the category-definition element. I've set these in a Resource file instead of putting them directly in the extension.xml file.  I've done the same thing for the <rule-definition> element. Here is what that resource file looks like.


The <rule-definition> element is really where everything is setup.


The ID parameter has to be a unique string.

The category is set to the category that you defined above, or an existing category that you know the ID of.

Enabled is set to true or false.  This is very important.  If this is set to true, the IDE will run your audit as soon as the file is loaded in the editor.  It's best to set this to False until you know what impact your audit is going to have on performance of the editor.  If you do something really time intensive in the analyzer class, it could bring the editor to a crawl.

The severity element can be set to one of four options.

  • Error
  • Warning
  • Incomplete
  • Advisory
  • Assist

All of these have a different way of displaying in the IDE when they are encountered by the audit framework. The Error value will stop the compiler from completing until the issue is resolved.

The parameter element is optional.  This is what you will use to pass any values back from the audit.  You may want to pass a value back to be used in the message that is displayed in the editor when you mouse over the issue.  Take a look at the Resource file example that I included above, and you will see how I am using the "currentsize" parameter in my message.

Multiple Rules can be setup in an audit-hook element.  However only one analyzer class can be referenced per audit-hook so it's best to group rules into common analyzers.

The <analyzer-definition> element is set to point to the analyzer class that the rules will be implemented in.

The Analyzer Class

The analyzer class is where all of the real work is done.

An analyzer class must be a subclass of oracle.jdeveloper.audit.analyzer.Analyzer.


Before Audit begins each traversal, it creates new Analyzers instances, creates and configures new Rule instances, and injects the rules into the analyzers. The @ExtensionResource annotation on the INVALID_FETCH_SIZE field instructs Audit to inject the instance of the Invalid Fetch Size rule into the field. The analyzer will need the instance stored in that field to report an issue.

In this class you can implement validation code for the workspace (application), project, document, and element.  In the traversal, the audit framework will visit the objects in the model as follows:

  • Enter Root
  • Enter Workspace
  • Enter Document
  • Enter Element
  • Exit Element
  • Exit Document
  • Exit Workspace
  • Exit Root

For this example, I don't have any validating to do in the workspace or project methods, so I'll skip down the document method and start there.


In this method I check to see if the first node in the document is "ViewObject" and if the file name ends with VO.xml. If this criteria is not met, then we set the setEnabled() method to false, disabling the audit for this traversal.

When the setEnabled() method is set to False, it stops the traversal from going any deeper into the process.  It will immediately start the return trip in the traversal and call the appropriate Exit methods.

If this method passes, then it continues down into the Enter method for the Element. You do not need to do a setEnabled(true).


Here we check to make sure that the FetchSize element exists and if so, and if it does, we check to see if a value has been set. We do our test to see if the value is greater then 100 and if so, we return the report, adding our parameter that we set in the extension.xml.

If we had created multiple rules in the extension.xml file, and they all defined some kind of audit on a ViewObject, we could do multiple validations here in this method. 

You would need to add an additional @ExtensionRegistry and "private Rule" definition for each rule at the top of the class, and then set the report variable to send out the report to the different rules as needed.

To run your audit, you can click on whichever object you want to run the audit against (Workspace, Project, file) and then click on the Build menu in the main menu bar. At the very bottom of the menu list, you will see "Audit <object>".


You'll notice in the example above, I have the Project selected in the Navigator window, and in the Build menu, it is showing "Audit Audit-Sample.jpr" which will run my audit against all of the files in the project.

To make sure your audit rule will be run, look at the Tools >> Preferences >> Audits >> Profiles dialog and make sure your rule is checked.

Getting Audit Extensions to load in 11gR2

If you are working with 11gR2, you will find that the audit extension will not fully load when you run it.  Looking at Help >> About >> Extensions you will see that your extension has "Triggers loaded" but it never gets to "Fully loaded". This is a result of the lazy loading feature introduced with 11gR2.  To get the extension to load when it's first initialized, we add the following element to the <audit-hook> element.

        <trigger>
          <technology>ADFbc</technology>
        </trigger>

The value for <technology> is a technologyKey and will cause the extension to be loaded when a project is initialized that uses this technology.  For this example, I've set it to ADFbc since I am doing an audit against an ADF application with the ADFbc feature enabled.

Conclusion...

In this post I covered the basics of creating an audit extension that audits and XML file. In Part Two I add a transform (fix) to this same project.

A very special Thank You! to Louis Tribble (Audit Framework master) and Jun Shozaki who spent countless hours traveling the internal roads of the Audit framework, and thankfully documenting them. Without these two developers, this topic would not be written.

As usual...  Comments are always encouraged.  Toss out your experiences and questions for others to learn from. All are welcome.
Comments:

Hi John,

I tried your's sample and then to change that property bundle values but it not changed.What is showing in first time it's maintaining the same state .

I tried like this way:
sample-category.label=Vass Lee(ESDK)
sample-category.description=Vass Lee Test
rule-invalid-fetch-size.label=Vass Lee Rule.

Above changes are not reflected in my wizard. Can you give some advise to me ?.

I am using Jdeveloper 11.1.2(11gR2) version.

i am waiting for yours reply.

Thanks,
Vass Lee

Posted by Vass Lee on September 15, 2011 at 09:04 AM PDT #

Hi Vass,

Take a look at my recent post about caching issue with 11gR2 (Cleaning up after yourself). It may be what you are running into.

If setting that -clean argument doesn't work, let me know and we'll look a little deeper.

Posted by guest on September 15, 2011 at 09:34 AM PDT #

Hi John,

Thanks for your reply.After deploying your sample proejct i am getting this jar(oracle.ide.extsamples.audits.jar) to this location
" D:\Oracle\Middleware\jdeveloper\jdev\extensions\oracle.ide.extsamples.audits.jar"

After that i got rule in Audit wizard.Next i removed that jar from that location.Now i am getting the following error in my Audit wizard.

java.lang.NullPointerException
at oracle.jdeveloper.audit.service.ProfileRepository.getProfiles(ProfileRepository.java:81)
at oracle.jdevimpl.audit.profile.ProfileModel.<init>(ProfileModel.java:104)
at oracle.jdevimpl.audit.profile.AuditProfilePanel.onEntry(AuditProfilePanel.java:287)
at oracle.ide.panels.MDDPanel.enterTraversableImpl(MDDPanel.java:1220)
at oracle.ide.panels.MDDPanel.enterTraversable(MDDPanel.java:1201)
at oracle.ide.panels.MDDPanel.access$1200(MDDPanel.java:128)
at oracle.ide.panels.MDDPanel$Tsl.updateSelectedNavigable(MDDPanel.java:1657)
at oracle.ide.panels.MDDPanel$Tsl.updateSelection(MDDPanel.java:1525)
at oracle.ide.panels.MDDPanel$Tsl.actionPerformed(MDDPanel.java:1519)
at javax.swing.Timer.fireActionPerformed(Timer.java:291)
at javax.swing.Timer$DoPostEvent.run(Timer.java:221)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:642)
at java.awt.EventQueue.access$000(EventQueue.java:85)
at java.awt.EventQueue$1.run(EventQueue.java:603)
at java.awt.EventQueue$1.run(EventQueue.java:601)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:612)
at oracle.javatools.internal.ui.EventQueueWrapper._dispatchEvent(EventQueueWrapper.java:169)
at oracle.javatools.internal.ui.EventQueueWrapper.dispatchEvent(EventQueueWrapper.java:151)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:178)
at java.awt.Dialog$1.run(Dialog.java:1046)
at java.awt.Dialog$3.run(Dialog.java:1098)
at java.security.AccessController.doPrivileged(Native Method).

Note : Now i followed your this link also
http://blogs.oracle.com/jdevextensions/entry/cleaning_up_after_yourself

Here how to solve this error ? While removing your jar only i am getting this error.
Can you post your email id here ?.

Posted by Vass Lee on September 15, 2011 at 06:29 PM PDT #

Hi Vass,

Make sure you have the -clean program argument set in the default Run configuration, like I mention in that blog post. In 11gR2, just removing the .jar files is not going to completely clean things up.

If you are getting this error after restarting the IDE itself, and not running the extension from the Run Extension feature, then try adding the -clean argument to the command line startup call.

Example:
jdev -clean

You can reach me in email at first.last<at>oracle.com

Posted by John 'JB' Brock on September 16, 2011 at 02:49 AM PDT #

Hi John 'JB' Brock,

In this sample I have some doubts.

http://blogs.oracle.com/jdevextensions/entry/don_t_fear_the_audit#comments

1.How can I identified which VO .xml currently selected ?.
2.Suppose I want apply my rule to java file.
In my case what are the method parameters required ?.
How to indentify selected java file?.

I am waiting for yours reply…

Can you send test mail to this id : rengasamya@zsl.com

Thanks ,
Vass Lee

Posted by Vass Lee on September 18, 2011 at 11:18 PM PDT #

Hi John,

I was wondering if I can write custom Analyzers for Detecting issues with Html and JS files.
If yes what would be the parameter to the enter method?

Also I noticed that there are JSLint related rules in the basic rules. Is JSLint integrated with JDeveloper?

Any help on how I can analyze files other than Java and XML would be of great help to me.

Many Thanks !!

Regards
Harish

Posted by guest on September 21, 2011 at 11:01 AM PDT #

Harish,

You can write an analyzer that will work with HTML as the constructs are DOM constructs just like XML.

There is a JavaScript Model as well with the base class being JSElement. Unfortunately, we are just finding out that we don't have the javadoc for the JavaScript model publicly released, so that's going to make it a bit difficult to work with. The model is quite extensive. The JLint rules that you see are implemented by a couple of modules that are using the JavaScript model.

Here's a trick that I was told about for seeing what's going on in the audit framework when working with undocumented models:

Write an analyzer that has a void enter(AuditContext, Object) and void exit (AuditContext, Object) methods and in those, prints out whatever gets visited (indenting is useful!). Those methods will get invoked for absolutely everything that can be visited.

We have some internal folks doing audits against CSS files, properties files, and to some degree offline database files using PLSQL. That's besides the normal XML and Java files of course.

Feel free to drop me a note directly if this just brings up more questions. :-)

Posted by John 'JB' Brock on September 21, 2011 at 02:22 PM PDT #

Vass,

I already sent this in email, and in the forum post, so I'm just going to point to the Forum for the answer to this last question. Hopefully it's easier to try and keep things in one place.

https://forums.oracle.com/forums/thread.jspa?messageID=9885930&tstart=0#9885930

Thanks

Posted by John 'JB' Brock on September 21, 2011 at 02:28 PM PDT #

Thanks John !!! Appreciate it. I was actually Evaluating Tools for auditing with in our project.

Your Input is definitively helpful !!!

Regards
Harish

Posted by guest on September 21, 2011 at 03:28 PM PDT #

Hi John,

How do I use ojAudit by separating it from JDeveloper.
I mean what are the executables and jar files needed to run it standalone.

Thanks,
Arvinder Singh.

Posted by guest on February 09, 2012 at 12:10 AM PST #

Hi Arvinder,

It is not possible to run ojAudit without the JDev installation. They can not be separated.

--jb

Posted by John 'JB' Brock on February 09, 2012 at 07:18 AM PST #

Hi John,

I am working with ojaudit for my project in Oracle.
I came across the following link to create customized rules using an AuditWizard.
http://www.oracle.com/technetwork/developer-tools/jdev/auditwizard-viewlet-swf-091991.html
But this works with JDeveloper 10g and I am using JDeveloper 11g Release 1. Do you know of any such tool for JDeveloper 11g Release 1?

Thanks in advance.
Arvinder Singh

Posted by Arvinder Singh on February 12, 2012 at 11:59 PM PST #

Do you know of any AuditWizard that works with JDeveloper 11G Release 1?

Thanks,
Arvinder Singh.

Posted by Arvinder Singh on February 13, 2012 at 12:04 AM PST #

Hi Arvinder,

I've never seen this before. I'll ask around the engineering team to see if this is something that still exists. I'm not aware of anything similar to it in the 11g product or from the 3rd Party / OpenSource update center.

Posted by John 'JB' Brock on February 13, 2012 at 07:27 AM PST #

Hi John,

Thanks for the informative blogs. We were able to write a lot of custom audit rules that were specific to our projects.

We now have a requirement where we need to check if the xml encoding is mentioned as part of every xml document. Unfortunately the getXMLEncoding method which when invoked on any Document object always returns null.

Any ideas ?

Regards,
Ajit

Posted by Ajit Gopalan on June 26, 2012 at 09:50 PM PDT #

Hi Ajit,

Glad to hear you've been able to make use of the blog info. I don't know the answer to your question right off my head. I'm checking into it now and hope to have an answer back to you shortly.

--jb

Posted by John 'JB' Brock on June 27, 2012 at 07:55 AM PDT #

Ajit, what version of JDev are you working with?

Posted by John 'JB' Brock on June 27, 2012 at 09:33 AM PDT #

Ajit,

The engineers are telling me that this is expected. Here is the proper way to get what you are looking for.

***************************************************
String specififedEncoding = null;
XmlDeclarationInfo xmlDecl = xmlModel.getDomModel().getXmlDeclarationInfo();
if (xmlDecl != null)
{
specifiedEncoding = xmlDecl.getEncoding();
}

if (specifiedEncoding == null)
{
//log a violation!
}
***************************************************

Hope this helps you out.

Posted by John 'JB' Brock on June 27, 2012 at 10:13 AM PDT #

John,

Thanks for the reply. We are currently working on JDev 11.1.1.6.0.

I tried out your earlier tip of passing in a Object to the visitor method ( enter(AuditContext,Object obj)) and printed out the various objects visited. I see the Document, XMLAttr and XMLText objects.
What would the "enter" method declaration look like for the snippet you pasted above ?

Regards,
Ajit

Posted by Ajit Gopalan on June 27, 2012 at 12:22 PM PDT #

Without writing up a PoC for this, I would think that it would have to be placed in the Enter method for the Document context Ajit.

Give that a quick try in your code and let me know if it works or not. If not, I'll try putting something together on my end to test it out.

Posted by John 'JB' Brock on June 28, 2012 at 08:25 AM PDT #

Thats what I tried in the first place John. It simply doesnt work. I am able to get all the attributes of the document element perfectly, just not the xml declaration that precedes it.
Please let me know.

Regards,
Ajit

Posted by Ajit Gopalan on June 28, 2012 at 10:23 AM PDT #

ok, let's take this offline and figure it out with some code. I'll post the solution back up here in comments after have the answer.

Please contact me directly at john<dot>brock@oracle<dot>com

Posted by John 'JB' Brock on June 28, 2012 at 10:25 AM PDT #

Ajit,

To get the XmlModel that you need to work with in that code snip, do this:

((XmlModelAdapter) context.getModel()).getXmlModel()

You should be able to get this XmlModel from within the Document context Enter method.

Posted by John 'JB' Brock on June 29, 2012 at 08:23 AM PDT #

It works perfectly John. Thanks for all the help !!

Ajit

Posted by Ajit Gopalan on June 29, 2012 at 09:15 PM PDT #

Hi
I have to create audit rule who will check the class name should be start with capital letter.
i am using jdeveloper 11.1.1.6,,plz provide me solution

Posted by mayank on May 17, 2013 at 03:35 AM PDT #

Post a Comment:
  • HTML Syntax: NOT allowed
About

profile image
My name is John 'JB' Brock.
This Blog will focus on tips and tricks for working with the JDeveloper Extension SDK.
I hope to bring clarity to some of the mysteries around developing extensions for JDeveloper.


Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today