Tuesday Nov 08, 2011

Updating an existing file via the SDK

In my last post I showed how to add a file to an existing project, and have it show up in the project navigator. In this post, I'll give a very basic example of how to edit that file and have those changes show up in the editor right away.

This code is appropriate for both 11gR1 and 11gR2

Working with a files content in Java is usually done via the FileIO and buffers. When working with the content of a file that is already open in a JDev editor window, you want to do things a little bit differently.  Instead of modifying the file directly, we can use a TextNode and the acquireTextBuffer() method to get the TextBuffer that we will then modify. This will allow the IDE to handle the saving of the file to the filesystem, as well as updating the editor window so you see the changes as soon as they are made.


Setup

I've created a really simple xml file that I will use for this example.


I'm using a modified version of the FirstSample extension SDK sample project.

I've setup a context menu item in the extension.xml file that will only show in the Editor window when the context has an XML file being edited. Notice the "rule" setting. This is where the restriction is set.


I've done all of the work in the Controller classes handleEvent method. Here is what the try / catch block looks like



How it works

In the try / catch block above, we first make sure that we are dealing with a TextNode from the context that is passed to us from the context menu.

We then get a buffer that contains the current editors text.  We dump the entire buffer contents into a String variable and make the modifications to the string.

Once all of the modifications are made, we convert the String variable into a char array so that it can be used with the EditProcessor class.

The EditProcessor class is the magic of all this.  Instead of trying to do the buffer locks and beginEdit and endEdit methods ourselves, we can simply use the methods available to us from the EditProcessor and all of the undo state and locks will be handled for us.  It will even set the file in the editor to a dirty state so it shows that it has been modified.

The arguments that we pass into the doReplaceAll() method are:

-- char[] of the content that we want to be placed into the node.
-- the node that we want to change
-- true or false to set this change as undoable
-- a String that will show up in the Undo menu item.  It will read as "Undo <string message>"
-- the origin object.

You can read more about the other methods in the EditProcessor class from the JavaDocs

Conclusion

Don't use the file.io classes to modify a file that is currently open in the IDE editor window.  Instead, use a TextNode and the TextBuffer associated with the current context to let the IDE do most of the work for you.  And remember to take advantage of the EditProcessor class instead of trying to do all of the undo and buffer locking yourself.


Friday Oct 28, 2011

Adding files to an existing project

I've run into this question a few times now in the Jdeveloper forums and thought it would be a good topic for this blog.

There are multiple ways that you can add a file to a project in JDeveloper, but only one that will really get the file properly setup in the IDE framework.

NOTE: The code shown below will work in both 11gR1 and 11gR2.

Let's start by showing the entire code block and then breaking it down.


The first thing we have to do, is get the current project, so that we know where to write this new file to.  I'm running this chunk of code from the controller class of a Context Menu item that I created to show up in the Navigator.  This provides me with a context to work with and I can get the project with a simple getProject() call.

The most important thing to note in all of the file manipulation, is that we are NOT using the standard Java.io methods.  We are using URLFileSystem and URLFactory to do all of the work.  This makes sure that the file that we create is being integrated into the IDE framework properly.


A quick lesson in Navigator view and Directory structures

The Navigator window in the IDE, is not a representation of what is on the filesystem.  This is really important to understand. That Navigator is a representation of what is in your Application (.jws) and Project (.jpr) files.  There are many things in the filesystem that do not show up in the Navigator.  One thing in particular is an empty directory is filtered out and not shown at all. 

The Navigator also does it's own grouping of source files into a folder called Application Sources and other files located in non-source-path directories are grouped under a folder called Resources.

By default any files under the /src directory will be shown in the Application Sources folder of the Navigator window.

Here is a quick look at the CreateStructure sample project and how things look on the filesystem and in the navigator window.

Filesystem


Navigator

Notice how the directories that I created earlier (/src/test/name) do not show in the navigator window?

By default the navigator shows the directories under /src as the package id.  You can adjust how this is displayed by adjusting the package level value in the navigator display settings


Writing the file

Ok, back to the actual code now. You will see that I created a URL variable called path that points to the directory that I want to place the new file in.  I used the URLFileSystem method mkdirs() to make sure the directory is created before I try and place the file in it.  The nice thing about mkdir*s* versus mkdir is that it will create the entire path, including parent directories, if they don't already exist.

In the sample, I've just hardcoded the file name. You can get this from a dialog or whatever means you want. I then created a new URL using both the path and filename variables.

I then created a new TextNode to represent our new file, and I called a method that I wrote called writeDefaultText(). This just adds a comment to the top of our new file so that it's not empty.  The editor handles files with a little something in them better. I believe most folks that take the time to write an extension that adds a file, is going to seed that file with some pre-generated code anyway.

Here is a look at the writeDefaultText() method

After we have some content in the file we do sav of the file in it's own try / catch block. 


Updating the Navigator

Finally we need to update the Navigator window so that it displays our new file as part of the project.


Conclusion

While you can use the standard java.io classes to create the file on the filesystem, it's best to use the URLFileSystem methods provided by the IDE to do this.  It's really a pretty easy thing to do once you know the proper methods to use.

As always, don't hesitate to add your comments and experiences to the comments section so others can learn from your coding experiences as well.


Friday Sep 16, 2011

Find your way Home

I often find myself working in one extension.xml file, while I have another extension.xml file, from a different application, open as a reference.  When working with multiple applications open, you can get in a state where the file you're looking at in the editor, is not really located in the application that is shown in the Navigator. 

It can be confusing and a bit of a pain to have to select the application from the pulldown in the navigator and switch back and forth.

Well, you don't have to.  When you are in the editor for a specific file, just type Alt-Home and the Navigator will sync to whatever application and project that file is located in.  Quick and Easy!

 Hope this helps others as much as it has helped me.

Friday Sep 09, 2011

Cleaning up after yourself -- Deleting test extensions

When developing extensions, you often need to run the extension to test something, then make some changes, and run it again.  Often many times in a row.  If you're like me, you use the "Run Extension" option in the IDE a lot.  I'm constantly checking menu placements, and dialog look and feel, etc. while I'm developing the extension. Sometimes you run into issues where it just doesn't seem like the new changes are taking effect and you want to clean up the old extension files and start with a fresh environment.

NOTE:  These steps are for when you are doing a lot of start and stop testing.  You should not need to do this all of the time. Nor should you have to leave the caching setting, mentioned below, in place for normal development.

While JDeveloper does not officially support the uninstall of extensions (you can setup your extension to be disabled), there are ways to delete the extension while doing development so you aren't running into potential caching issues or just running into older versions of the jar files.

Cleaning things up

If you are doing everything in one jar file, it's really simple to clean things up and make sure you are not running into an older version of your extension. If your extensions is more complex, you will need to know what artifacts your extension is putting in what places, in order to clean them up.

One of the fastest ways to see what is being deployed, is to click on the "Deploy to Target Platform" in the context menu for your project.

This will open a Deployment Log window and you can see everything that is being deployed and to which locations.

Working with 11gR1

Once you know the location and name of the artifacts, close JDeveloper and open your favorite file manager to delete those files and/or directories.  After the files have been deleted, start JDeveloper back up.

Working with 11gR2

If you are working with the latest version of 11gR2, you will need to do the step above as well as a couple more steps to make sure you are not running into some potential caching issues.

First, when you add an extension via the Check for Updates feature in JDeveloper, information about that extension is added to an info file. This file is located at: <mw_home>/jdeveloper/configuration/cfu_bundles.info.  You will need to open this file in a text editor and remove the lines that pertain to your extension.  Be very careful that you don't remove lines that may be related to someone else's extension or an extension that you still want loaded. 

Second, when you right-click on the project and select "Run Extension" the IDE uses the default Run configuration for the project to startup the new IDE instance. To avoid potential caching issues when you are testing your extension, you will want to add a program argument to the default run configuration.

Double-click on the project name in the navigator and it will open the Project Properties dialog.  Select the Run/Debug/Profile option at the bottom left of the dialog


The Default run configuration should be selected, and you can just click on Edit to open it.


Look for the Program Arguments field and enter " -clean " in the field. With this argument you will have all of the caching cleared each time you use the Run Extension feature.  It does not remove any files or data.  It just cleans up the cache so that you are loading new versions of the extension libraries each time the command is run.

This is not something that you want to add to the actual IDE startup command, or have in place all of the time as it can remove some of the performance benefits that are new in 11gR2.

Conclusion

These couple of steps can save a lot of frustration at times.  I hope it helps others while doing the testing of your extensions.  I did mention above that you can setup your extensions to allow the end-user to disable them at runtime.  If you are interested in how to do that, please let a comment and if enough people are interested, I'll put up a separate post on how to do that in both R1 and R2.

As usual, comments are always welcome and encouraged!


Wednesday May 11, 2011

Letting the Usage Reporting feature show you the way

Some times when you're looking to start an extension project, you're just not quite sure where to start to accomplish the task that you have in mind.  Maybe it's something that is already possible in JDeveloper, but you just want to modify it in some way, or do things a little bit differently then the current functionality.

One way to look at what is going on behind the scenes, is to enable the Usage Reporting feature in JDeveloper and look at the usage log that is generated after you do a certain process in the JDeveloper UI.

prefereces setting for Usage Reporting feature

This report will not show you the code that you have to write, but it will show you the extension classes being called when you perform certain steps in the IDE, and that could be enough to give you something to look up in the javadocs and get going in the right direction 

Of course this will only happen if you have opt-in to the usage-reporting feature in the first place. Which you can do on the Preferences panel as shown above.

What the Usage Reporting feature does, is create an xml file after each IDE session. It records some of the API usages during that session. A session is defined as the time in the IDE from startup to close.

By default the usage log is saved to the location shown below on a windows machine. This install was done with the Local Users option selected during the installation. The location could vary depending on how you did your installation.

C:\Documents and Settings\<username>\Application Data\JDeveloper\system11.1.1.5.37.60.13\o.ide.usages-tracking

The systemXXX number will vary depending on which version of JDeveloper you have installed.  The one above, shows the version number for JDeveloper 11.1.1.5.0 (the newest version as of this post)

The Trick...

There is one trick to being able to actually look at the usage log, before it's sent off to Oracle. 
To stop the file from just being sent and erased as soon as you close JDeveloper,  you will need to set some bogus proxy info in the Tools --> Preferences --> Web Browser and Proxy panel.

proxy settings in preferences

The file will stay in that location until JDeveloper can connect again. If you don't want the file to be sent, just go ahead and delete it after you are done, or move it to another location.

The data that is gathered is used internally by the JDeveloper product management and engineering teams to help make more educated decisions on feature updates and enhancements, as well as adding new features down the road.

Here is the contents of an actual report that was created as the result of opening an extension.xml file and then opening a .java file.


<?xml version = '1.0' encoding = 'UTF-8'?>
<usages xmlns="http://xmlns.oracle.com/jdeveloper/110000/usages-tracking-data">
   <hash n="system-info">
      <value n="build-label" v="JDEVADF_11.1.1.5.0_GENERIC_110409.0025.6013"/>
      <value n="dev-build" v="false"/>
      <value n="guid" v="07dd49ee-012e-1000-8001-0a9a27d99b84"/>
      <value n="jdk-version" v="1.6.0_24"/>
      <value n="operating-system" v="Windows XP"/>
      <value n="product-edition" v="oracle.studio, oracle.j2ee, oracle.jdeveloper"/>
      <value n="product-name" v="Oracle JDeveloper 11g Release 1"/>
      <value n="product-version" v="11.1.1.5.37.60.13"/>
      <value n="session-end-time" v="1305043200531"/>
      <value n="session-id" v="1305043105550"/>
      <value n="session-start-time" v="1305043105550"/>
      <value n="user-role" v="<none>"/>
    </hash>
    <hash n="usage-data">
      <list n="activities">
        <hash>
           <value n="extension-product-id" v="oracle.jdevimpl.extensiondt.editor.ExtensionManifestEditor"/>
           <value n="property-id" v="oracle.jdeveloper.extensiondt.model.ExtensionManifestNode"/>
           <value n="time-stamp" v="1305043182769"/>
           <value n="usage-type" v="OPEN_EDITOR"/>
        </hash>
       <hash>
         <value n="extension-product-id" v="oracle.jdevimpl.extensiondt.editor.ExtensionManifestEditor"/>
         <value n="property-id" v="oracle.jdeveloper.extensiondt.model.ExtensionManifestNode"/>
         <value n="time-stamp" v="1305043182832"/>
         <value n="usage-type" v="ACTIVATE_EDITOR"/>
       </hash>
       <hash>
         <value n="extension-product-id" v="oracle.ide.ceditor.CodeEditor"/>
         <value n="property-id" v="oracle.jdeveloper.model.JavaSourceNode"/>
         <value n="time-stamp" v="1305043190096"/>
         <value n="usage-type" v="OPEN_EDITOR"/>
       </hash>
       <hash>
         <value n="extension-product-id" v="oracle.ide.ceditor.CodeEditor"/>
         <value n="property-id" v="oracle.jdeveloper.model.JavaSourceNode"/>
         <value n="time-stamp" v="1305043190767"/>
         <value n="usage-type" v="ACTIVATE_EDITOR"/>
       </hash>
     </list>
   </hash>
</usages>

As usual, please feel free to post any questions or personal experiences in the comments.

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