Skip to content

Commit c043b3a

Browse files
committed
SQLDev WorksheetAction Extension Example
1 parent c1704db commit c043b3a

File tree

10 files changed

+428
-260
lines changed

10 files changed

+428
-260
lines changed

sqldeveloper/extension/README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ Depending on requirements, this can be done in either XML or java and deployed b
66

77
### New
88

9+
* [WorksheetAction](java/WorksheetAction)
10+
How to add actions to the worksheet context menu and / or toolbar; execute the action directly or in a background task; and present advanced / detailed information in a result panel.
11+
912
* [Managing Extensions](./ManagingExtensions.md) - ([Issue 113](https://github.com/oracle/oracle-db-examples/issues/113)) How to add, disable, and remove extensions.
1013

1114
* [ConnectionHelper](java/ConnectionHelper)
@@ -14,8 +17,6 @@ Optionally accept connection info from the command line and/or on a [SocketServe
1417
* [ConnectionHelperClient](java/ConnectionHelperClient)
1518
A simple command line client for the ConnectionHelper socket server.
1619

17-
* Added resource reference for Philipp Salvisberg's [Example-based tutorials](https://github.com/PhilippSalvisberg/sqldev) to extend SQL Developer functionality. (external)
18-
1920

2021
### Contents
2122

sqldeveloper/extension/java/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,6 @@ Optionally accept connection info from the command line and/or on a [SocketServe
2525

2626
* [ConnectionHelperClient](ConnectionHelperClient)
2727
A simple command line client for the ConnectionHelper socket server.
28+
29+
* [WorksheetAction](WorksheetAction)
30+
How to add actions to the worksheet context menu and / or toolbar; execute the action directly or in a background task; and present advanced / detailed information in a result panel.
Lines changed: 76 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1,105 +1,82 @@
11
# SQL Developer Examples
22
## Worksheet Action
33

4-
Actions for the worksheet context menu and/or toolbar can be added via an ActionProvider registered in the extension.xml.
5-
6-
``` xml
7-
<extension xmlns="http://jcp.org/jsr/198/extension-manifest" id="@@extension.id@@" version="@@extension.version@@.@@extension.build@@" esdk-version="1.0"
8-
. . .
9-
<hook>
10-
<sqldev-worksheet-hook xmlns="http://xmlns.oracle.com/sqldeveloper/sqldev-worksheet">
11-
<provider>oracle.db.example.sqldeveloper.extension.worksheetAction.ExampleActionProvider</provider>
12-
</sqldev-worksheet-hook>
13-
</hook>
14-
</extension>
15-
```
16-
17-
``` java
18-
package oracle.dbtools.worksheet;
19-
20-
import oracle.dbtools.worksheet.extension.WorksheetHook;
21-
22-
/**
23-
* The <code>ActionProvider</code> interface provides a mechanism for
24-
* registering actions in the Worksheet. Worksheet actions can be registered for
25-
* either the toolbar, the context menu, or both. Panels can be registered for
26-
* displaying the results of actions.
27-
* <p>
28-
* ActionProvider instances are responsible for determining the enabled state of
29-
* an action as well as creating Tasks to execute the action.
30-
* <p>
31-
* Registration occurs through the use of an extension hook.
32-
* <p>
33-
*
34-
* @author jmcginni
35-
* @param <V>
36-
* @see WorksheetHook
37-
*
38-
*/
39-
public interface ActionProvider<V> {
40-
/**
41-
* Returns the number of actions supported by this provider.
42-
*
43-
* @return the number of supported actions
44-
*/
45-
int getActionsCount();
46-
47-
/**
48-
* Returns the action at the specified location.
49-
*
50-
* @param i
51-
* the index of the action
52-
* @return the WorksheetAction at the location
53-
* @throws IndexOutOfBoundsException
54-
* if the specified location is out of range
55-
*/
56-
WorksheetAction getActionAt(int i);
57-
58-
/**
59-
* Returns the number of panels supported by this provider.
60-
*
61-
* @return the number of supported panels
62-
*/
63-
int getPanelCount();
64-
65-
/**
66-
* Returns the panel at the specified location.
67-
*
68-
* @param i
69-
* the index of the panel
70-
* @return the WorksheetResultPanel at the location
71-
* @throws IndexOutOfBoundsException
72-
* if the specified location is out of range
73-
*/
74-
WorksheetResultPanel getPanelAt(int i);
75-
76-
/**
77-
* Returns a task that can be used to execute the action.
78-
*
79-
* @param id
80-
* a String identifying the action to perform
81-
* @param ctx
82-
* the WorksheetContext describing the current Worksheet
83-
* environment
84-
* @return a RaptorTask that encapsulates the running of the action
85-
*/
86-
WorksheetTaskWrapper<V> doAction(String id, WorksheetContext ctx);
87-
88-
/**
89-
* Returns whether the specified action should be enabled based on the
90-
* specified context.
91-
*
92-
* @param id
93-
* a String identifying the action to perform
94-
* @param ctx
95-
* the WorksheetContext describing the current Worksheet
96-
* environment
97-
* @return whether the action should be enabled.
98-
*/
99-
boolean checkActionEnabled(String id, WorksheetContext ctx);
100-
}
101-
102-
```
4+
Example extension showing how to add actions to the worksheet context menu and / or toolbar; execute the action directly or in a background task; and present information in a result panel.
5+
6+
7+
### Build it
8+
[Set up your environment](../../setup.md). If using the eclipse project, also modify paths in *SQLDeveloper.userlibraries* and import into eclipse. (This example was built using the "SQLDeveloper 20.1" Library)
9+
* Build and install using those instructions
10+
11+
### Try it
12+
13+
![WorksheetActionEnable image](images/WorksheetActionEnable.png)
14+
#### First time (Use the trigger to fully load the extension)
15+
* Open a worksheet
16+
* Select "Trigger/Load WorksheetAction Extension" from the context menu
17+
* Close the worksheet
18+
* Only have to do that the 1st time as extension.xml says to reload once loaded
19+
* Typically this would be part of a larger extension with natural triggers IMHO & not need this hack.
20+
21+
![WorksheetActionWorking image](images/WorksheetActionWorking.png)
22+
23+
#### Then (Extension loaded, now what?)
24+
* Open a worksheet
25+
* Positioning
26+
* * Toolbar: Has entries for BOTH (blue bug) and TOOLBAR_ONLY (yellow bug)
27+
* * Context menu: Has entries for BOTH (blue bug) and CONTEXT_MENU_ONLY (purple bug)
28+
* Enabling:
29+
* * BOTH - Enabled unless the worksheet connection is disconnected
30+
* * CONTEXT_MENU_ONLY - Always enabled
31+
* * TOOLBAR_ONLY - Enabled only when there is text in the editor
32+
* Running (*Open the task progress viewer* (View->Task Progress) *to see the task messages which do not show on the toolbar task viwer.*)
33+
* * The [ExampleActionTask](src/oracle/db/example/sqldeveloper/extension/worksheetAction/ExampleActionTask.java) sets up a ten second loop to demonstrate setting progress / status as well as checking for cancel/pause
34+
* * Try pause / resume / cancel
35+
* * Try running twice without closing result window - note the 2nd one 'replaces' the original. Try pinning the result & running again - a second result window should be used.
36+
* * try running multiple ones at the same time. You should see them stacked in the task viewer waiting on each other running one at a time.
37+
38+
### Change it
39+
* Read the section on How it works & play.
40+
* * How does it work if one of them has a different "connectionName"? (not blocked from running by others with a different name)
41+
* * How about sending null for callback & id? (no result panel, worksheet not locked when the task runs)
42+
* * How about adding your own listener to do something?
43+
* * . . .
44+
45+
46+
### How it works
47+
[extension.xml](etc/extension.xml)
48+
* In the trigger-hooks/triggers section, declares a dummy trigger action (*WorksheetAction.DUMMY*), with [DummyActionController](src/oracle/db/example/sqldeveloper/extension/worksheetAction/DummyActionController.java) as controller, always enabled on the context menu of any editor to load the extension.
49+
* In the hooks/jdeveloper-hook section, declares the actions (*WorksheetAction.BOTH*, *WorksheetAction.CONTEXT_MENU_ONLY*, *WorksheetAction.TOOLBAR_ONLY*) we will be adding with this extension.
50+
* and finally, hooks/sqldev-worksheet-hook declares the [ExampleActionProvider](src/oracle/db/example/sqldeveloper/extension/worksheetAction/ExampleActionProvider.java) that defines the processing for and integrates those actions with the worksheet.
51+
52+
[DummyActionController](src/oracle/db/example/sqldeveloper/extension/worksheetAction/DummyActionController.java)
53+
* As its name implies, this is a controller that does nothing. It and the associated action exist in this extension only to provide a mechanism to demand load the extension in the absence of any natural trigger(s).
54+
55+
[ExampleActionProvider](src/oracle/db/example/sqldeveloper/extension/worksheetAction/ExampleActionProvider.java)
56+
This is the brains of the outfit, it
57+
* Declares contants for the actions ids (matching the ids declared in extension.xml)
58+
* ```getActionAt``` Creates a worksheet action for each id specifying menu(s), section, and weight for each
59+
* ```doAction``` Executes the processing for each id with the context passed in. In this case, all three use an [ExampleActionTask](src/oracle/db/example/sqldeveloper/extension/worksheetAction/ExampleActionTask.java)
60+
* * NOTE: *If the action is quick* (think e.g., format text) *and isn't something that requires a task in its own right* (e.g., anything that talks to the database), you can do / invokeLater the action here and return null.
61+
* * For tasks, wraps that up for the worksheet along with any listeners and / or viewers desired. For a viewer, we are getting the one from the worksheet context (which is the toolbar task viewer), For listeners, this example adds
62+
* * * ```getTaskListenerList``` - Log task listener events (INFO/SEVERE for exceptions) controlled by LOG_TASK_EVENTS
63+
* * * ```getTaskUIListenerList``` - Log task UI listener events (INFO) controlled by LOG_TASK_UI_EVENTS
64+
* * * (*Uncomment* oracle.level = INFO *in logging.conf to have them show in the log window*)
65+
* ```checkActionEnabled``` is set up with different criteria for each action
66+
* * *WorksheetAction.BOTH* - return (we have a connection)
67+
* * *WorksheetAction.CONTEXT_MENU_ONLY* - return true (always enabled)
68+
* * *WorksheetAction.TOOLBAR_ONLY* - return (editor has text)
69+
70+
[ExampleActionTask](src/oracle/db/example/sqldeveloper/extension/worksheetAction/ExampleActionTask.java) - a dummy task to show the basic mechanics plus how to attach a result panel to the worksheet. Sets up a ten second loop to demonstrate setting progress / status as well as checking for cancel/pause
71+
* Why DatabaseQueryTask or derivative?
72+
* * It serializes executions against a string (connectionName).
73+
* * If you are going to access the worksheet's (or any shared) connection, you MUST use a task to do so.
74+
* * This can also be used to serialize executions of your actions.
75+
* How to set up a result panel
76+
* How to lock the worksheet while processing
77+
* How to support pause / cancel
78+
79+
[ExampleResultPanel](src/oracle/db/example/sqldeveloper/extension/worksheetAction/ExampleResultPanel.java)- a really simple result panel just allowing text to be appended.
10380

10481

10582

sqldeveloper/extension/java/WorksheetAction/etc/extension.xml

Lines changed: 58 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -16,109 +16,115 @@ limitations under the License.
1616
-->
1717

1818
<extension xmlns="http://jcp.org/jsr/198/extension-manifest"
19-
id="@@extension.id@@" version="@@extension.version@@.@@extension.build@@"
20-
esdk-version="1.0"
21-
rsbundle-class="@@extension.resources@@">
19+
id="@@extension.id@@"
20+
version="@@extension.version@@.@@extension.build@@"
21+
esdk-version="1.0" rsbundle-class="@@extension.resources@@">
2222

2323
<name>@@extension.name@@</name>
2424
<owner>@@extension.owner@@ @@extension.owner.url@@</owner>
2525

26-
<!--
27-
<feature-category xmlns="http://xmlns.oracle.com/ide/extension" id="example-category">
28-
<name>${CATEGORY_NAME}</name>
29-
<description>${CATEGORY_DESCRIPTION}</description>
30-
</feature-category>
31-
Duplicate category definitions cause a severe error to be logged.
32-
Only way around it from the outside I can think of is an extension just to add
33-
the category and all the others dependent on it.
34-
The pre-defined ones are:
35-
{db-category=Database, ide-category=IDE, db-migrations-category=Database Migrations,
36-
database-category=Database Development, java-se-category=Java SE,
37-
vcs-category=Version Control, xml-category=XML}
38-
and example-category=Examples, if you've installed the XMLPackedExample
39-
Not supplying a category or giving a non-existent one will just show the extension
40-
at the root of the features tree.
41-
-->
42-
<feature id="@@extension.id@@" xmlns="http://xmlns.oracle.com/ide/extension">
26+
<feature id="@@extension.id@@"
27+
xmlns="http://xmlns.oracle.com/ide/extension">
4328
<name>@@extension.name@@</name>
4429
<description>@@extension.descr@@</description>
4530
<type>
46-
<service can-user-disable="true" reload-if-used="true"/>
31+
<service can-user-disable="true"
32+
reload-if-used="true" />
4733
</type>
4834
</feature>
49-
<trigger-hooks xmlns="http://xmlns.oracle.com/ide/extension">
50-
<triggers xmlns:c="http://xmlns.oracle.com/ide/customization">
51-
<!-- Hack to add action to fully load the extension.
52-
Typically (IMHO) worksheet actions would be part of a larger extension
53-
with more natural triggers
54-
-->
55-
<actions xmlns="http://xmlns.oracle.com/jdeveloper/1013/extension">
35+
36+
<trigger-hooks
37+
xmlns="http://xmlns.oracle.com/ide/extension">
38+
<triggers
39+
xmlns:c="http://xmlns.oracle.com/ide/customization">
40+
<!-- Hack to add action to fully load the extension.
41+
Typically (IMHO) worksheet actions would be part of a larger extension
42+
with more natural triggers
43+
-->
44+
<actions
45+
xmlns="http://xmlns.oracle.com/jdeveloper/1013/extension">
5646
<action id="WorksheetAction.DUMMY">
5747
<properties>
58-
<property name="Name">${WORKSHEET_ACTION_DUMMY}</property>
48+
<property name="Name">${WORKSHEET_ACTION_DUMMY}
49+
</property>
5950
<!-- You could also use your own by putting path in rsbundle
6051
e.g., MY_ICON = /oracle/db/example/sqldeveloper/extension/dependency/icons/my_icon.png
6152
and referencing its key as res:${MY_ICON} -->
6253
<!-- <property name="SmallIcon">${OracleIcons.DUKE}</property> -->
6354
</properties>
6455
</action>
6556
</actions>
66-
<controllers xmlns="http://xmlns.oracle.com/ide/extension">
67-
<controller class="oracle.db.example.sqldeveloper.extension.worksheetAction.DummyActionController">
68-
<!-- Not needed if the context-menu-hook is using a rule to determine if it shows up at all? -->
57+
<controllers
58+
xmlns="http://xmlns.oracle.com/ide/extension">
59+
<controller
60+
class="oracle.db.example.sqldeveloper.extension.worksheetAction.DummyActionController">
6961
<update-rules>
7062
<update-rule rule="always-enabled">
71-
<action id="WorksheetAction.DUMMY"/>
63+
<action id="WorksheetAction.DUMMY" />
7264
</update-rule>
7365
</update-rules>
7466
</controller>
7567
</controllers>
7668
<context-menu-hook rule="always-enabled">
77-
<site idref="editor"/> <!-- can do multiple e.g.;, "db_nav;editor" -->
69+
<site idref="editor" /> <!-- can do multiple e.g.;, "db_nav;editor" -->
7870
<menu>
79-
<section xmlns="http://jcp.org/jsr/198/extension-manifest" id="SECTION_WINDOW_CTXT_MENU" weight="1.0">
80-
<item action-ref="WorksheetAction.DUMMY" weight="1.0"/>
71+
<section
72+
xmlns="http://jcp.org/jsr/198/extension-manifest"
73+
id="SECTION_WINDOW_CTXT_MENU" weight="1.0">
74+
<item action-ref="WorksheetAction.DUMMY"
75+
weight="1.0" />
8176
</section>
8277
</menu>
8378
</context-menu-hook>
84-
<!-- end of force load extension hack -->
85-
</triggers>
86-
</trigger-hooks>
79+
<!-- end of force load extension hack -->
80+
</triggers>
81+
</trigger-hooks>
82+
8783
<hooks>
88-
<jdeveloper-hook xmlns="http://xmlns.oracle.com/jdeveloper/1013/extension">
84+
<jdeveloper-hook
85+
xmlns="http://xmlns.oracle.com/jdeveloper/1013/extension">
8986
<actions>
9087
<action id="WorksheetAction.BOTH">
9188
<properties>
92-
<property name="Name">${WORKSHEET_ACTION_BOTH}</property>
89+
<property name="Name">${WORKSHEET_ACTION_BOTH}
90+
</property>
9391
<!-- You could also use your own by putting path in rsbundle
9492
e.g., MY_ICON = /oracle/db/example/sqldeveloper/extension/dependency/icons/my_icon.png
9593
and referencing its key as res:${MY_ICON} -->
96-
<property name="SmallIcon">${OracleIcons.DEBUG_BLUE}</property>
94+
<property name="SmallIcon">${OracleIcons.DEBUG_BLUE}
95+
</property>
9796
</properties>
9897
</action>
9998
<action id="WorksheetAction.CONTEXT_MENU_ONLY">
10099
<properties>
101-
<property name="Name">${WORKSHEET_ACTION_CONTEXT_MENU_ONLY}</property>
100+
<property name="Name">${WORKSHEET_ACTION_CONTEXT_MENU_ONLY}
101+
</property>
102102
<!-- You could also use your own by putting path in rsbundle
103103
e.g., MY_ICON = /oracle/db/example/sqldeveloper/extension/dependency/icons/my_icon.png
104104
and referencing its key as res:${MY_ICON} -->
105-
<property name="SmallIcon">${OracleIcons.DEBUG_PURPLE}</property>
105+
<property name="SmallIcon">${OracleIcons.DEBUG_PURPLE}
106+
</property>
106107
</properties>
107108
</action>
108109
<action id="WorksheetAction.TOOLBAR_ONLY">
109110
<properties>
110-
<property name="Name">${WORKSHEET_ACTION_TOOLBAR_ONLY}</property>
111+
<property name="Name">${WORKSHEET_ACTION_TOOLBAR_ONLY}
112+
</property>
111113
<!-- You could also use your own by putting path in rsbundle
112114
e.g., MY_ICON = /oracle/db/example/sqldeveloper/extension/dependency/icons/my_icon.png
113115
and referencing its key as res:${MY_ICON} -->
114-
<property name="SmallIcon">${OracleIcons.DEBUG_YELLOW}</property>
116+
<property name="SmallIcon">${OracleIcons.DEBUG_YELLOW}
117+
</property>
115118
</properties>
116119
</action>
117-
</actions>
118-
</jdeveloper-hook>
119-
<sqldev-worksheet-hook xmlns="http://xmlns.oracle.com/sqldeveloper/sqldev-worksheet">
120-
<provider>oracle.db.example.sqldeveloper.extension.worksheetAction.ExampleActionProvider</provider>
120+
</actions>
121+
</jdeveloper-hook>
122+
123+
<sqldev-worksheet-hook
124+
xmlns="http://xmlns.oracle.com/sqldeveloper/sqldev-worksheet">
125+
<provider>oracle.db.example.sqldeveloper.extension.worksheetAction.ExampleActionProvider
126+
</provider>
121127
</sqldev-worksheet-hook>
122-
</hooks>
123-
128+
</hooks>
129+
124130
</extension>

0 commit comments

Comments
 (0)