4184 |
20 Mar 08 |
nicklas |
1 |
<?xml version="1.0" encoding="UTF-8"?> |
4184 |
20 Mar 08 |
nicklas |
2 |
<!DOCTYPE chapter PUBLIC |
4184 |
20 Mar 08 |
nicklas |
3 |
"-//Dawid Weiss//DTD DocBook V3.1-Based Extension for XML and graphics inclusion//EN" |
4184 |
20 Mar 08 |
nicklas |
4 |
"../../../../lib/docbook/preprocess/dweiss-docbook-extensions.dtd"> |
4184 |
20 Mar 08 |
nicklas |
5 |
<!-- |
4223 |
15 Apr 08 |
nicklas |
$Id$ |
4184 |
20 Mar 08 |
nicklas |
7 |
|
4184 |
20 Mar 08 |
nicklas |
Copyright (C) 2008 |
4184 |
20 Mar 08 |
nicklas |
9 |
|
4184 |
20 Mar 08 |
nicklas |
This file is part of BASE - BioArray Software Environment. |
4184 |
20 Mar 08 |
nicklas |
Available at http://base.thep.lu.se/ |
4184 |
20 Mar 08 |
nicklas |
12 |
|
4184 |
20 Mar 08 |
nicklas |
BASE is free software; you can redistribute it and/or |
4184 |
20 Mar 08 |
nicklas |
modify it under the terms of the GNU General Public License |
4477 |
05 Sep 08 |
jari |
as published by the Free Software Foundation; either version 3 |
4184 |
20 Mar 08 |
nicklas |
of the License, or (at your option) any later version. |
4184 |
20 Mar 08 |
nicklas |
17 |
|
4184 |
20 Mar 08 |
nicklas |
BASE is distributed in the hope that it will be useful, |
4184 |
20 Mar 08 |
nicklas |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
4184 |
20 Mar 08 |
nicklas |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4184 |
20 Mar 08 |
nicklas |
GNU General Public License for more details. |
4184 |
20 Mar 08 |
nicklas |
22 |
|
4184 |
20 Mar 08 |
nicklas |
You should have received a copy of the GNU General Public License |
4509 |
11 Sep 08 |
jari |
along with BASE. If not, see <http://www.gnu.org/licenses/>. |
4184 |
20 Mar 08 |
nicklas |
25 |
--> |
4184 |
20 Mar 08 |
nicklas |
26 |
|
4206 |
04 Apr 08 |
nicklas |
27 |
<chapter id="extensions_developer"> |
5782 |
04 Oct 11 |
nicklas |
28 |
<?dbhtml dir="extensions" filename="index.html" ?> |
4206 |
04 Apr 08 |
nicklas |
29 |
<title>Extensions developer</title> |
4184 |
20 Mar 08 |
nicklas |
30 |
|
4206 |
04 Apr 08 |
nicklas |
31 |
<sect1 id="extensions_developer.overview"> |
5782 |
04 Oct 11 |
nicklas |
32 |
<?dbhtml filename="overview.html" ?> |
4184 |
20 Mar 08 |
nicklas |
33 |
<title>Overview</title> |
4184 |
20 Mar 08 |
nicklas |
34 |
<para> |
5640 |
24 May 11 |
nicklas |
35 |
The BASE application includes an extensions mechanism that makes it possible |
4184 |
20 Mar 08 |
nicklas |
36 |
to dynamically add functions to the GUI without having to edit the JSP code. |
4184 |
20 Mar 08 |
nicklas |
37 |
It is, for example, possible to add menu items in the menu and toolbar buttons |
4184 |
20 Mar 08 |
nicklas |
38 |
in selected toolbars. |
4184 |
20 Mar 08 |
nicklas |
39 |
</para> |
4184 |
20 Mar 08 |
nicklas |
40 |
|
4184 |
20 Mar 08 |
nicklas |
41 |
<para> |
4184 |
20 Mar 08 |
nicklas |
42 |
Go to the |
4184 |
20 Mar 08 |
nicklas |
43 |
<menuchoice> |
5640 |
24 May 11 |
nicklas |
44 |
<guimenu>Administrate</guimenu> |
5640 |
24 May 11 |
nicklas |
45 |
<guimenuitem>Plug-ins & extensions</guimenuitem> |
5640 |
24 May 11 |
nicklas |
46 |
<guimenuitem>Overview</guimenuitem> |
4184 |
20 Mar 08 |
nicklas |
47 |
</menuchoice> |
4184 |
20 Mar 08 |
nicklas |
48 |
menu to display a list of possible extension points and all installed |
4184 |
20 Mar 08 |
nicklas |
49 |
extensions. From this page, if you are logged in with enough permissions, |
4184 |
20 Mar 08 |
nicklas |
50 |
it is also possible to configure the extensions system, enable/disable |
5737 |
14 Sep 11 |
nicklas |
51 |
extensions, etc. Read more about this in <xref linkend="plugins" />. |
4184 |
20 Mar 08 |
nicklas |
52 |
</para> |
4184 |
20 Mar 08 |
nicklas |
53 |
|
4184 |
20 Mar 08 |
nicklas |
54 |
<para> |
4184 |
20 Mar 08 |
nicklas |
55 |
Extensions can come in two forms, either as an XML file in the |
4184 |
20 Mar 08 |
nicklas |
56 |
<emphasis>BASE Extensions XML</emphasis> format or as a JAR file. |
5640 |
24 May 11 |
nicklas |
57 |
A JAR file is required when the extension needs to execute custom-made |
4184 |
20 Mar 08 |
nicklas |
58 |
code or use custom resources such as icons, css stylesheets, or |
4184 |
20 Mar 08 |
nicklas |
59 |
JSP files. |
4184 |
20 Mar 08 |
nicklas |
60 |
</para> |
4184 |
20 Mar 08 |
nicklas |
61 |
|
4223 |
15 Apr 08 |
nicklas |
62 |
<itemizedlist> |
4223 |
15 Apr 08 |
nicklas |
63 |
<title>More reading</title> |
4223 |
15 Apr 08 |
nicklas |
64 |
<listitem> |
4223 |
15 Apr 08 |
nicklas |
65 |
<para> |
5737 |
14 Sep 11 |
nicklas |
66 |
<xref linkend="plugins" />. |
4223 |
15 Apr 08 |
nicklas |
67 |
</para> |
4223 |
15 Apr 08 |
nicklas |
68 |
</listitem> |
4223 |
15 Apr 08 |
nicklas |
69 |
|
4223 |
15 Apr 08 |
nicklas |
70 |
<listitem> |
4223 |
15 Apr 08 |
nicklas |
71 |
<para> |
5781 |
04 Oct 11 |
nicklas |
72 |
<xref linkend="core_api.extensions" />. |
4223 |
15 Apr 08 |
nicklas |
73 |
</para> |
4223 |
15 Apr 08 |
nicklas |
74 |
</listitem> |
4223 |
15 Apr 08 |
nicklas |
75 |
</itemizedlist> |
4223 |
15 Apr 08 |
nicklas |
76 |
|
4206 |
04 Apr 08 |
nicklas |
77 |
<sect2 id="extensions_developer.examplecode"> |
4184 |
20 Mar 08 |
nicklas |
78 |
<title>Download code examples</title> |
4184 |
20 Mar 08 |
nicklas |
79 |
|
4184 |
20 Mar 08 |
nicklas |
80 |
<para> |
5640 |
24 May 11 |
nicklas |
81 |
The code examples in this chapter can be downloaded from the |
5640 |
24 May 11 |
nicklas |
82 |
BASE plug-ins site: |
7982 |
14 Jun 21 |
nicklas |
83 |
<ulink url="https://baseplugins.thep.lu.se/wiki/net.sf.basedb.examplecode" |
7982 |
14 Jun 21 |
nicklas |
84 |
>https://baseplugins.thep.lu.se/wiki/net.sf.basedb.examplecode</ulink> |
4184 |
20 Mar 08 |
nicklas |
85 |
</para> |
4184 |
20 Mar 08 |
nicklas |
86 |
</sect2> |
4184 |
20 Mar 08 |
nicklas |
87 |
|
4206 |
04 Apr 08 |
nicklas |
88 |
<sect2 id="extensions_developer.terminology"> |
4184 |
20 Mar 08 |
nicklas |
89 |
<title>Terminology</title> |
4184 |
20 Mar 08 |
nicklas |
90 |
|
4184 |
20 Mar 08 |
nicklas |
91 |
<variablelist> |
4184 |
20 Mar 08 |
nicklas |
92 |
<varlistentry> |
4184 |
20 Mar 08 |
nicklas |
93 |
<term>Extension point</term> |
4184 |
20 Mar 08 |
nicklas |
94 |
<listitem> |
4184 |
20 Mar 08 |
nicklas |
95 |
<para> |
5640 |
24 May 11 |
nicklas |
96 |
An extensions point is a place in the BASE core or web client interface |
5640 |
24 May 11 |
nicklas |
97 |
where it is possible to extend the functionality with custom extensions. An |
4184 |
20 Mar 08 |
nicklas |
98 |
extension point has an ID which must be unique among all existing |
4184 |
20 Mar 08 |
nicklas |
99 |
extension points. Extension points registered by the BASE web client all |
5640 |
24 May 11 |
nicklas |
100 |
starts with <code>net.sf.basedb.clients.web</code> prefix. The |
4184 |
20 Mar 08 |
nicklas |
101 |
extension point also defines an |
4184 |
20 Mar 08 |
nicklas |
102 |
<interfacename docapi="net.sf.basedb.util.extensions">Action</interfacename> |
5640 |
24 May 11 |
nicklas |
103 |
subclass that all extensions must implement. |
4184 |
20 Mar 08 |
nicklas |
104 |
</para> |
4184 |
20 Mar 08 |
nicklas |
105 |
</listitem> |
4184 |
20 Mar 08 |
nicklas |
106 |
</varlistentry> |
4184 |
20 Mar 08 |
nicklas |
107 |
|
4184 |
20 Mar 08 |
nicklas |
108 |
<varlistentry> |
4184 |
20 Mar 08 |
nicklas |
109 |
<term>Extension</term> |
4184 |
20 Mar 08 |
nicklas |
110 |
<listitem> |
4184 |
20 Mar 08 |
nicklas |
111 |
<para> |
4184 |
20 Mar 08 |
nicklas |
112 |
An extensions is a custom addition to the BASE web client |
5640 |
24 May 11 |
nicklas |
113 |
interface or core API. This can mean a new menu item in the menu or a |
4184 |
20 Mar 08 |
nicklas |
114 |
new button in a toolbar. An extension must provide an |
4184 |
20 Mar 08 |
nicklas |
115 |
<interfacename docapi="net.sf.basedb.util.extensions">ActionFactory</interfacename> |
4184 |
20 Mar 08 |
nicklas |
116 |
that knows how to create actions that fits the requirements |
4184 |
20 Mar 08 |
nicklas |
117 |
from the extension point the extension is extending. |
4184 |
20 Mar 08 |
nicklas |
118 |
</para> |
4184 |
20 Mar 08 |
nicklas |
119 |
</listitem> |
4184 |
20 Mar 08 |
nicklas |
120 |
</varlistentry> |
4184 |
20 Mar 08 |
nicklas |
121 |
|
4184 |
20 Mar 08 |
nicklas |
122 |
<varlistentry> |
4184 |
20 Mar 08 |
nicklas |
123 |
<term>Action</term> |
4184 |
20 Mar 08 |
nicklas |
124 |
<listitem> |
4184 |
20 Mar 08 |
nicklas |
125 |
<para> |
4184 |
20 Mar 08 |
nicklas |
126 |
An <interfacename docapi="net.sf.basedb.util.extensions">Action</interfacename> |
4184 |
20 Mar 08 |
nicklas |
127 |
is an interface definition which provides an extension point enough |
4184 |
20 Mar 08 |
nicklas |
128 |
information to make it possible to render the action as HTML. |
4184 |
20 Mar 08 |
nicklas |
129 |
An action typically has methods such as, <code>getTitle()</code>, |
4184 |
20 Mar 08 |
nicklas |
130 |
<code>getIcon()</code> and <code>getOnClick()</code>. |
4184 |
20 Mar 08 |
nicklas |
131 |
</para> |
4184 |
20 Mar 08 |
nicklas |
132 |
</listitem> |
4184 |
20 Mar 08 |
nicklas |
133 |
</varlistentry> |
4184 |
20 Mar 08 |
nicklas |
134 |
|
4184 |
20 Mar 08 |
nicklas |
135 |
<varlistentry> |
4184 |
20 Mar 08 |
nicklas |
136 |
<term>Action factory</term> |
4184 |
20 Mar 08 |
nicklas |
137 |
<listitem> |
4184 |
20 Mar 08 |
nicklas |
138 |
<para> |
4184 |
20 Mar 08 |
nicklas |
139 |
An <interfacename docapi="net.sf.basedb.util.extensions">ActionFactory</interfacename> |
4184 |
20 Mar 08 |
nicklas |
140 |
is an object that knows how to create actions of some specific type, for |
4184 |
20 Mar 08 |
nicklas |
141 |
example menu item actions. Action factories are part of an |
4184 |
20 Mar 08 |
nicklas |
142 |
extension definition and can usually be configured with parameters |
4184 |
20 Mar 08 |
nicklas |
143 |
from the XML file. BASE ships with several implementations of |
4184 |
20 Mar 08 |
nicklas |
144 |
action factories for all defined extension points. Still, if your |
4184 |
20 Mar 08 |
nicklas |
145 |
extension needs a different implementation you can easily create your |
4184 |
20 Mar 08 |
nicklas |
146 |
own factory. |
4184 |
20 Mar 08 |
nicklas |
147 |
</para> |
4184 |
20 Mar 08 |
nicklas |
148 |
</listitem> |
4184 |
20 Mar 08 |
nicklas |
149 |
</varlistentry> |
4184 |
20 Mar 08 |
nicklas |
150 |
|
4184 |
20 Mar 08 |
nicklas |
151 |
<varlistentry> |
4184 |
20 Mar 08 |
nicklas |
152 |
<term>Renderer</term> |
4184 |
20 Mar 08 |
nicklas |
153 |
<listitem> |
4184 |
20 Mar 08 |
nicklas |
154 |
<para> |
4184 |
20 Mar 08 |
nicklas |
155 |
A <interfacename docapi="net.sf.basedb.util.extensions">Renderer</interfacename> |
4184 |
20 Mar 08 |
nicklas |
156 |
is an object that knows how to convert the information in an action to |
4184 |
20 Mar 08 |
nicklas |
157 |
HTML. The use of renderers are optional. Some extension points use a |
4223 |
15 Apr 08 |
nicklas |
158 |
"hard-coded" approach that renders the actions directly on the JSP file. |
4184 |
20 Mar 08 |
nicklas |
159 |
Some extension points uses a locked renderer, while other extension |
4184 |
20 Mar 08 |
nicklas |
160 |
points provides a default renderer, but allows extensions to supply their |
5640 |
24 May 11 |
nicklas |
161 |
own if they want to. Renderers are mostly used by the web client extensions, |
5640 |
24 May 11 |
nicklas |
162 |
not so much by the core extensions. |
4184 |
20 Mar 08 |
nicklas |
163 |
</para> |
4184 |
20 Mar 08 |
nicklas |
164 |
</listitem> |
4184 |
20 Mar 08 |
nicklas |
165 |
</varlistentry> |
4184 |
20 Mar 08 |
nicklas |
166 |
|
4184 |
20 Mar 08 |
nicklas |
167 |
<varlistentry> |
4184 |
20 Mar 08 |
nicklas |
168 |
<term>Renderer factory</term> |
4184 |
20 Mar 08 |
nicklas |
169 |
<listitem> |
4184 |
20 Mar 08 |
nicklas |
170 |
<para> |
4184 |
20 Mar 08 |
nicklas |
171 |
A <interfacename docapi="net.sf.basedb.util.extensions">RendererFactory</interfacename> |
4184 |
20 Mar 08 |
nicklas |
172 |
is an object that knows how to create renderers. Renderer factories can |
4184 |
20 Mar 08 |
nicklas |
173 |
be part of both extension points and extensions. In most other aspects |
4184 |
20 Mar 08 |
nicklas |
174 |
renderer factories are very similar to action factories. |
4184 |
20 Mar 08 |
nicklas |
175 |
</para> |
4184 |
20 Mar 08 |
nicklas |
176 |
</listitem> |
4184 |
20 Mar 08 |
nicklas |
177 |
</varlistentry> |
5487 |
15 Nov 10 |
nicklas |
178 |
|
5487 |
15 Nov 10 |
nicklas |
179 |
<varlistentry> |
5640 |
24 May 11 |
nicklas |
180 |
<term>Error handler factory</term> |
5487 |
15 Nov 10 |
nicklas |
181 |
<listitem> |
5487 |
15 Nov 10 |
nicklas |
182 |
<para> |
5487 |
15 Nov 10 |
nicklas |
183 |
An <interfacename docapi="net.sf.basedb.util.extensions">ErrorHandlerFactory</interfacename> |
5487 |
15 Nov 10 |
nicklas |
184 |
is an object that knows how to handle error that occur when executing extensions. |
5640 |
24 May 11 |
nicklas |
185 |
An error handler factory is defined as part of an extension point and handles all |
5640 |
24 May 11 |
nicklas |
186 |
errors related to the extensions of that extension point. In most other aspects |
5487 |
15 Nov 10 |
nicklas |
187 |
error handler factories are similar to renderer and action factories. If the |
5487 |
15 Nov 10 |
nicklas |
188 |
extension point doesn't define an error handler factory, the system will |
5487 |
15 Nov 10 |
nicklas |
189 |
select a default that only writes a message to the log file |
5487 |
15 Nov 10 |
nicklas |
190 |
<classname docapi="net.sf.basedb.util.extensions">LoggingErrorHandlerFactory</classname> |
5487 |
15 Nov 10 |
nicklas |
191 |
</para> |
5487 |
15 Nov 10 |
nicklas |
192 |
</listitem> |
5487 |
15 Nov 10 |
nicklas |
193 |
</varlistentry> |
4184 |
20 Mar 08 |
nicklas |
194 |
|
4184 |
20 Mar 08 |
nicklas |
195 |
<varlistentry> |
4208 |
07 Apr 08 |
nicklas |
196 |
<term>Client context</term> |
4184 |
20 Mar 08 |
nicklas |
197 |
<listitem> |
4184 |
20 Mar 08 |
nicklas |
198 |
<para> |
4208 |
07 Apr 08 |
nicklas |
199 |
A <classname docapi="net.sf.basedb.util.extensions">ClientContext</classname> |
4208 |
07 Apr 08 |
nicklas |
200 |
is an object which contains information about the current user session. |
4184 |
20 Mar 08 |
nicklas |
201 |
It is for example, possible to get information about the logged in |
4184 |
20 Mar 08 |
nicklas |
202 |
user, the currently active item, etc. |
4184 |
20 Mar 08 |
nicklas |
203 |
</para> |
4184 |
20 Mar 08 |
nicklas |
204 |
|
4184 |
20 Mar 08 |
nicklas |
205 |
<para> |
4184 |
20 Mar 08 |
nicklas |
206 |
In the BASE web client the context is always a |
4184 |
20 Mar 08 |
nicklas |
207 |
<classname docapi="net.sf.basedb.clients.web.extensions">JspContext</classname>. |
4208 |
07 Apr 08 |
nicklas |
208 |
Wherever a <classname>ClientContext</classname> object is provided as a |
4208 |
07 Apr 08 |
nicklas |
209 |
parameter it is always safe to cast it to a <classname>JspContext</classname> |
5640 |
24 May 11 |
nicklas |
210 |
object. Extension points in the core usually use a |
5640 |
24 May 11 |
nicklas |
211 |
<classname>ClientContext</classname>. |
4184 |
20 Mar 08 |
nicklas |
212 |
</para> |
4184 |
20 Mar 08 |
nicklas |
213 |
|
4184 |
20 Mar 08 |
nicklas |
214 |
<para> |
4184 |
20 Mar 08 |
nicklas |
215 |
The context can also be used by an extension to request that a specific |
4184 |
20 Mar 08 |
nicklas |
216 |
javascript or stylesheet file should be included in the HTML code. |
4184 |
20 Mar 08 |
nicklas |
217 |
</para> |
4184 |
20 Mar 08 |
nicklas |
218 |
</listitem> |
4184 |
20 Mar 08 |
nicklas |
219 |
</varlistentry> |
4184 |
20 Mar 08 |
nicklas |
220 |
|
4184 |
20 Mar 08 |
nicklas |
221 |
</variablelist> |
4184 |
20 Mar 08 |
nicklas |
222 |
|
4184 |
20 Mar 08 |
nicklas |
223 |
|
4184 |
20 Mar 08 |
nicklas |
224 |
</sect2> |
4184 |
20 Mar 08 |
nicklas |
225 |
</sect1> |
4184 |
20 Mar 08 |
nicklas |
226 |
|
4206 |
04 Apr 08 |
nicklas |
227 |
<sect1 id="extensions_developer.helloworld"> |
5782 |
04 Oct 11 |
nicklas |
228 |
<?dbhtml filename="helloworld.html" ?> |
4184 |
20 Mar 08 |
nicklas |
229 |
<title>Hello world as an extension</title> |
4184 |
20 Mar 08 |
nicklas |
230 |
|
4184 |
20 Mar 08 |
nicklas |
231 |
<para> |
4184 |
20 Mar 08 |
nicklas |
232 |
We will use the classical Hello world as the first simple example |
4184 |
20 Mar 08 |
nicklas |
233 |
of an extension. This extension will add a new menu item in the |
4184 |
20 Mar 08 |
nicklas |
234 |
menu which displays a popup with the text "Hello world!" when |
6812 |
30 Mar 15 |
nicklas |
235 |
selected. |
4184 |
20 Mar 08 |
nicklas |
236 |
</para> |
4184 |
20 Mar 08 |
nicklas |
237 |
|
6812 |
30 Mar 15 |
nicklas |
238 |
<orderedlist> |
6812 |
30 Mar 15 |
nicklas |
239 |
<listitem> |
4184 |
20 Mar 08 |
nicklas |
240 |
<para> |
6812 |
30 Mar 15 |
nicklas |
241 |
Start by creating an empty directory in some suitable |
6812 |
30 Mar 15 |
nicklas |
242 |
location on your hard disk. Inside this directory, create two more |
6812 |
30 Mar 15 |
nicklas |
243 |
directories <filename>META-INF</filename> and |
6812 |
30 Mar 15 |
nicklas |
244 |
<filename>resources</filename>. |
4184 |
20 Mar 08 |
nicklas |
245 |
</para> |
6812 |
30 Mar 15 |
nicklas |
246 |
</listitem> |
6812 |
30 Mar 15 |
nicklas |
247 |
|
6812 |
30 Mar 15 |
nicklas |
248 |
<listitem> |
6812 |
30 Mar 15 |
nicklas |
249 |
<para> |
6812 |
30 Mar 15 |
nicklas |
250 |
Copy the XML code below and save it to <filename>META-INF/extensions.xml</filename> |
6812 |
30 Mar 15 |
nicklas |
251 |
in your newly created directory. It is important that you get the filename |
6812 |
30 Mar 15 |
nicklas |
252 |
correct. |
6812 |
30 Mar 15 |
nicklas |
253 |
</para> |
6812 |
30 Mar 15 |
nicklas |
254 |
|
6812 |
30 Mar 15 |
nicklas |
255 |
<programlisting language="xml"> |
4184 |
20 Mar 08 |
nicklas |
256 |
<![CDATA[ |
4184 |
20 Mar 08 |
nicklas |
257 |
<?xml version="1.0" encoding="UTF-8" ?> |
4184 |
20 Mar 08 |
nicklas |
258 |
<extensions xmlns="http://base.thep.lu.se/extensions.xsd"> |
4184 |
20 Mar 08 |
nicklas |
259 |
<extension |
4184 |
20 Mar 08 |
nicklas |
260 |
id="net.sf.basedb.clients.web.menu.extensions.helloworld" |
4184 |
20 Mar 08 |
nicklas |
261 |
extends="net.sf.basedb.clients.web.menu.extensions" |
4184 |
20 Mar 08 |
nicklas |
262 |
> |
4184 |
20 Mar 08 |
nicklas |
263 |
<index>1</index> |
6812 |
30 Mar 15 |
nicklas |
264 |
<about safe-scripts="1"> |
4184 |
20 Mar 08 |
nicklas |
265 |
<name>Hello world</name> |
4184 |
20 Mar 08 |
nicklas |
266 |
<description> |
4208 |
07 Apr 08 |
nicklas |
267 |
The very first extensions example. Adds a "Hello world" |
4208 |
07 Apr 08 |
nicklas |
268 |
menu item that displays "Hello world" in a javascript |
4208 |
07 Apr 08 |
nicklas |
269 |
popup when selected. |
4184 |
20 Mar 08 |
nicklas |
270 |
</description> |
4184 |
20 Mar 08 |
nicklas |
271 |
</about> |
4184 |
20 Mar 08 |
nicklas |
272 |
<action-factory> |
4208 |
07 Apr 08 |
nicklas |
273 |
<factory-class> |
4184 |
20 Mar 08 |
nicklas |
274 |
net.sf.basedb.clients.web.extensions.menu.FixedMenuItemFactory |
4184 |
20 Mar 08 |
nicklas |
275 |
</factory-class> |
4184 |
20 Mar 08 |
nicklas |
276 |
<parameters> |
6812 |
30 Mar 15 |
nicklas |
277 |
<id>hello-world</id> |
4184 |
20 Mar 08 |
nicklas |
278 |
<title>Hello world!</title> |
4184 |
20 Mar 08 |
nicklas |
279 |
<tooltip>This is to test the extensions system</tooltip> |
5971 |
17 Feb 12 |
nicklas |
280 |
<icon>/images/info.png</icon> |
6812 |
30 Mar 15 |
nicklas |
281 |
<script>~/hello.js</script> |
4184 |
20 Mar 08 |
nicklas |
282 |
</parameters> |
4184 |
20 Mar 08 |
nicklas |
283 |
</action-factory> |
4184 |
20 Mar 08 |
nicklas |
284 |
</extension> |
4184 |
20 Mar 08 |
nicklas |
285 |
</extensions> |
4184 |
20 Mar 08 |
nicklas |
286 |
]]> |
4184 |
20 Mar 08 |
nicklas |
287 |
</programlisting> |
6812 |
30 Mar 15 |
nicklas |
288 |
<para> |
6812 |
30 Mar 15 |
nicklas |
289 |
This file is the most important one when creating extensions |
6812 |
30 Mar 15 |
nicklas |
290 |
since it is used to tell BASE about the extensions (and |
6812 |
30 Mar 15 |
nicklas |
291 |
plug-ins) in the package. See below for more information. |
6812 |
30 Mar 15 |
nicklas |
292 |
</para> |
6812 |
30 Mar 15 |
nicklas |
293 |
</listitem> |
6812 |
30 Mar 15 |
nicklas |
294 |
|
6812 |
30 Mar 15 |
nicklas |
295 |
<listitem> |
6812 |
30 Mar 15 |
nicklas |
296 |
<para> |
6812 |
30 Mar 15 |
nicklas |
297 |
Copy the javascript code below and save it to <filename>resources/hello.js</filename> |
6812 |
30 Mar 15 |
nicklas |
298 |
in your newly created directory. Once again, it is important that the filename |
6812 |
30 Mar 15 |
nicklas |
299 |
is correct. |
6812 |
30 Mar 15 |
nicklas |
300 |
</para> |
6812 |
30 Mar 15 |
nicklas |
301 |
<programlisting language="javascript"> |
6812 |
30 Mar 15 |
nicklas |
302 |
<![CDATA[ |
6812 |
30 Mar 15 |
nicklas |
303 |
var HelloWorld = function() |
6812 |
30 Mar 15 |
nicklas |
304 |
{ |
6812 |
30 Mar 15 |
nicklas |
305 |
var hello = {}; |
6812 |
30 Mar 15 |
nicklas |
306 |
|
6812 |
30 Mar 15 |
nicklas |
307 |
/** |
6812 |
30 Mar 15 |
nicklas |
308 |
Executed once when the page is loaded. Typically |
6812 |
30 Mar 15 |
nicklas |
309 |
used to bind events to fixed control elements. |
6812 |
30 Mar 15 |
nicklas |
310 |
*/ |
6812 |
30 Mar 15 |
nicklas |
311 |
hello.initMenuItems = function() |
6812 |
30 Mar 15 |
nicklas |
312 |
{ |
6812 |
30 Mar 15 |
nicklas |
313 |
// Bind event handlers the menu items. |
6812 |
30 Mar 15 |
nicklas |
314 |
// First parameter is the ID of the menu item |
6812 |
30 Mar 15 |
nicklas |
315 |
// Second parameter is the event to react to (=click) |
6812 |
30 Mar 15 |
nicklas |
316 |
// Last parameter is the function to execute |
6812 |
30 Mar 15 |
nicklas |
317 |
Events.addEventHandler('hello-world', 'click', hello.helloWorld); |
6812 |
30 Mar 15 |
nicklas |
318 |
} |
6812 |
30 Mar 15 |
nicklas |
319 |
|
6812 |
30 Mar 15 |
nicklas |
320 |
// Show 'Hello world' message |
6812 |
30 Mar 15 |
nicklas |
321 |
hello.helloWorld = function(event) |
6812 |
30 Mar 15 |
nicklas |
322 |
{ |
6812 |
30 Mar 15 |
nicklas |
323 |
alert('Hello world'); |
6812 |
30 Mar 15 |
nicklas |
324 |
} |
6812 |
30 Mar 15 |
nicklas |
325 |
|
6812 |
30 Mar 15 |
nicklas |
326 |
return hello; |
6812 |
30 Mar 15 |
nicklas |
327 |
}(); |
6812 |
30 Mar 15 |
nicklas |
328 |
|
6812 |
30 Mar 15 |
nicklas |
329 |
//Register the page initializer method with the BASE core |
6812 |
30 Mar 15 |
nicklas |
330 |
Doc.onLoad(HelloWorld.initMenuItems); |
6812 |
30 Mar 15 |
nicklas |
331 |
]]> |
6812 |
30 Mar 15 |
nicklas |
332 |
</programlisting> |
6812 |
30 Mar 15 |
nicklas |
333 |
</listitem> |
4184 |
20 Mar 08 |
nicklas |
334 |
|
6812 |
30 Mar 15 |
nicklas |
335 |
<listitem> |
6812 |
30 Mar 15 |
nicklas |
336 |
<para> |
6812 |
30 Mar 15 |
nicklas |
337 |
Create a JAR package containing the two directories and files |
6812 |
30 Mar 15 |
nicklas |
338 |
you have created. It is important the the subdirectory structure |
6812 |
30 Mar 15 |
nicklas |
339 |
inside the JAR file is rooted at the first empty directory you created. |
6812 |
30 Mar 15 |
nicklas |
340 |
</para> |
6812 |
30 Mar 15 |
nicklas |
341 |
|
6812 |
30 Mar 15 |
nicklas |
342 |
<literallayout> |
6812 |
30 Mar 15 |
nicklas |
343 |
<filename class="directory">META-INF/</filename> |
6812 |
30 Mar 15 |
nicklas |
344 |
<filename>META-INF/extensions.xml</filename> |
6812 |
30 Mar 15 |
nicklas |
345 |
<filename class="directory">resources/</filename> |
6812 |
30 Mar 15 |
nicklas |
346 |
<filename>resources/hello.js</filename> |
6812 |
30 Mar 15 |
nicklas |
347 |
</literallayout> |
6812 |
30 Mar 15 |
nicklas |
348 |
|
6812 |
30 Mar 15 |
nicklas |
349 |
<para> |
6812 |
30 Mar 15 |
nicklas |
350 |
Copy the JAR file to the the <filename>plugins.dir</filename> |
6812 |
30 Mar 15 |
nicklas |
351 |
directory for your BASE installation. |
6812 |
30 Mar 15 |
nicklas |
352 |
</para> |
6812 |
30 Mar 15 |
nicklas |
353 |
</listitem> |
6812 |
30 Mar 15 |
nicklas |
354 |
|
6812 |
30 Mar 15 |
nicklas |
355 |
<listitem> |
6812 |
30 Mar 15 |
nicklas |
356 |
<para> |
6812 |
30 Mar 15 |
nicklas |
357 |
Log in to BASE and install the extension by going through the |
6812 |
30 Mar 15 |
nicklas |
358 |
installation wizard at <menuchoice> |
6812 |
30 Mar 15 |
nicklas |
359 |
<guimenu>Administrate</guimenu> |
6812 |
30 Mar 15 |
nicklas |
360 |
<guimenuitem>Plug-ins & extensions</guimenuitem> |
6812 |
30 Mar 15 |
nicklas |
361 |
<guimenuitem>Overview</guimenuitem> |
6812 |
30 Mar 15 |
nicklas |
362 |
</menuchoice>. |
6812 |
30 Mar 15 |
nicklas |
363 |
When the extension has been installed you should have a new |
6812 |
30 Mar 15 |
nicklas |
364 |
menu item: |
6812 |
30 Mar 15 |
nicklas |
365 |
<menuchoice> |
6812 |
30 Mar 15 |
nicklas |
366 |
<guimenu>Extensions</guimenu> |
6812 |
30 Mar 15 |
nicklas |
367 |
<guimenuitem>Hello world!</guimenuitem> |
6812 |
30 Mar 15 |
nicklas |
368 |
</menuchoice> |
6812 |
30 Mar 15 |
nicklas |
369 |
which pops up a message in a Javascript window. |
6812 |
30 Mar 15 |
nicklas |
370 |
|
6812 |
30 Mar 15 |
nicklas |
371 |
</para> |
6812 |
30 Mar 15 |
nicklas |
372 |
<note> |
6812 |
30 Mar 15 |
nicklas |
373 |
<para> |
6812 |
30 Mar 15 |
nicklas |
374 |
You may have to logout and login again to see the new menu item. |
6812 |
30 Mar 15 |
nicklas |
375 |
</para> |
6812 |
30 Mar 15 |
nicklas |
376 |
</note> |
6812 |
30 Mar 15 |
nicklas |
377 |
</listitem> |
6812 |
30 Mar 15 |
nicklas |
378 |
|
6812 |
30 Mar 15 |
nicklas |
379 |
</orderedlist> |
6812 |
30 Mar 15 |
nicklas |
380 |
|
6812 |
30 Mar 15 |
nicklas |
381 |
<sect2 id="extensions_developer.extensions.xml"> |
6812 |
30 Mar 15 |
nicklas |
382 |
<title>The extensions.xml file</title> |
6812 |
30 Mar 15 |
nicklas |
383 |
|
4184 |
20 Mar 08 |
nicklas |
384 |
<para> |
4184 |
20 Mar 08 |
nicklas |
385 |
The <sgmltag class="starttag">extensions</sgmltag> tag is the root |
4184 |
20 Mar 08 |
nicklas |
386 |
tag and is needed to set up the namespace and schema validation. |
4184 |
20 Mar 08 |
nicklas |
387 |
</para> |
4184 |
20 Mar 08 |
nicklas |
388 |
|
4184 |
20 Mar 08 |
nicklas |
389 |
<para> |
4184 |
20 Mar 08 |
nicklas |
390 |
The <sgmltag class="starttag">extension</sgmltag> defines a new |
4184 |
20 Mar 08 |
nicklas |
391 |
extension. It must have an <sgmltag>id</sgmltag> attribute that |
4184 |
20 Mar 08 |
nicklas |
392 |
is unique among all installed extensions and an <sgmltag>extends</sgmltag> |
4184 |
20 Mar 08 |
nicklas |
393 |
attribute which id the ID of the extension point. For the <sgmltag>id</sgmltag> |
4184 |
20 Mar 08 |
nicklas |
394 |
attribute we recommend using the same naming conventions as for java |
4184 |
20 Mar 08 |
nicklas |
395 |
packages. See <ulink |
5640 |
24 May 11 |
nicklas |
396 |
url="http://www.oracle.com/technetwork/java/codeconventions-135099.html">Java naming |
5640 |
24 May 11 |
nicklas |
397 |
conventions from Oracle</ulink>. |
4184 |
20 Mar 08 |
nicklas |
398 |
</para> |
4184 |
20 Mar 08 |
nicklas |
399 |
|
4184 |
20 Mar 08 |
nicklas |
400 |
<para> |
4184 |
20 Mar 08 |
nicklas |
401 |
The <sgmltag class="starttag">about</sgmltag> tag is optional and |
4184 |
20 Mar 08 |
nicklas |
402 |
can be used to provide meta information about the extension. We |
4184 |
20 Mar 08 |
nicklas |
403 |
recommend that all extensions are given at least a |
4184 |
20 Mar 08 |
nicklas |
404 |
<sgmltag class="starttag">name</sgmltag>. Other supported subtags are: |
4184 |
20 Mar 08 |
nicklas |
405 |
|
4184 |
20 Mar 08 |
nicklas |
406 |
<itemizedlist> |
4184 |
20 Mar 08 |
nicklas |
407 |
<listitem><sgmltag class="starttag">description</sgmltag></listitem> |
4184 |
20 Mar 08 |
nicklas |
408 |
<listitem><sgmltag class="starttag">version</sgmltag></listitem> |
4184 |
20 Mar 08 |
nicklas |
409 |
<listitem><sgmltag class="starttag">copyright</sgmltag></listitem> |
4184 |
20 Mar 08 |
nicklas |
410 |
<listitem><sgmltag class="starttag">contact</sgmltag></listitem> |
4184 |
20 Mar 08 |
nicklas |
411 |
<listitem><sgmltag class="starttag">email</sgmltag></listitem> |
4184 |
20 Mar 08 |
nicklas |
412 |
<listitem><sgmltag class="starttag">url</sgmltag></listitem> |
4184 |
20 Mar 08 |
nicklas |
413 |
</itemizedlist> |
4184 |
20 Mar 08 |
nicklas |
414 |
|
4184 |
20 Mar 08 |
nicklas |
415 |
<tip> |
4184 |
20 Mar 08 |
nicklas |
416 |
<title>Global about tag</title> |
4184 |
20 Mar 08 |
nicklas |
417 |
|
4184 |
20 Mar 08 |
nicklas |
418 |
<para> |
4184 |
20 Mar 08 |
nicklas |
419 |
<sgmltag class="starttag">about</sgmltag> tag can also be specified as a |
4184 |
20 Mar 08 |
nicklas |
420 |
first-level tag (eq. as a child to <sgmltag class="starttag">extensions</sgmltag>). |
4208 |
07 Apr 08 |
nicklas |
421 |
This can be useful when an XML file defines more than one extension |
4184 |
20 Mar 08 |
nicklas |
422 |
and you don't want to repeat the same information for every extension. |
4184 |
20 Mar 08 |
nicklas |
423 |
You can still override the information for specific extensions by including |
4184 |
20 Mar 08 |
nicklas |
424 |
new values in the extension's <sgmltag class="starttag">about</sgmltag> |
4184 |
20 Mar 08 |
nicklas |
425 |
tag. |
4184 |
20 Mar 08 |
nicklas |
426 |
</para> |
4184 |
20 Mar 08 |
nicklas |
427 |
</tip> |
6595 |
14 Nov 14 |
nicklas |
428 |
|
6595 |
14 Nov 14 |
nicklas |
429 |
<tip> |
6595 |
14 Nov 14 |
nicklas |
430 |
<title>Start out in disabled state</title> |
6595 |
14 Nov 14 |
nicklas |
431 |
|
6595 |
14 Nov 14 |
nicklas |
432 |
<para> |
6595 |
14 Nov 14 |
nicklas |
433 |
The <sgmltag class="starttag">about</sgmltag> tag can be used to specify |
6595 |
14 Nov 14 |
nicklas |
434 |
that an extension should start out in disabled state. This can be useful |
6595 |
14 Nov 14 |
nicklas |
435 |
if there are multiple variants of an extension or if some extensions |
6595 |
14 Nov 14 |
nicklas |
436 |
are considered "advanced mode" and only should be enabled after some |
6595 |
14 Nov 14 |
nicklas |
437 |
serious thinking. To use this feature, simply set <code><about disabled="1"></code> |
6595 |
14 Nov 14 |
nicklas |
438 |
in the XML file. |
6595 |
14 Nov 14 |
nicklas |
439 |
</para> |
6595 |
14 Nov 14 |
nicklas |
440 |
</tip> |
4184 |
20 Mar 08 |
nicklas |
441 |
</para> |
4184 |
20 Mar 08 |
nicklas |
442 |
|
4184 |
20 Mar 08 |
nicklas |
443 |
<para> |
4184 |
20 Mar 08 |
nicklas |
444 |
The <sgmltag class="starttag">action-factory</sgmltag> tag is required and |
4184 |
20 Mar 08 |
nicklas |
445 |
so is the <sgmltag class="starttag">factory-class</sgmltag> subtag. It tells |
4208 |
07 Apr 08 |
nicklas |
446 |
the extension system which factory to use for creating actions. The |
4184 |
20 Mar 08 |
nicklas |
447 |
<classname docapi="net.sf.basedb.clients.web.extensions.menu">FixedMenuItemFactory</classname> |
4184 |
20 Mar 08 |
nicklas |
448 |
is a very simple factory that is shipped with BASE. This factory always creates the same |
4184 |
20 Mar 08 |
nicklas |
449 |
menu item, no matter what. Another factory for menu items is the |
4184 |
20 Mar 08 |
nicklas |
450 |
<classname docapi="net.sf.basedb.clients.web.extensions.menu">PermissionMenuItemFactory</classname> |
4184 |
20 Mar 08 |
nicklas |
451 |
which can create menu items that depends on the logged in user's permissions. It is |
4184 |
20 Mar 08 |
nicklas |
452 |
for example, possible to hide or disable the menu item if the user doesn't have enough |
4184 |
20 Mar 08 |
nicklas |
453 |
permissions. If none of the supplied factories suits you it is possible to |
4184 |
20 Mar 08 |
nicklas |
454 |
supply your own implementation. More about this later. |
4184 |
20 Mar 08 |
nicklas |
455 |
</para> |
4184 |
20 Mar 08 |
nicklas |
456 |
|
4184 |
20 Mar 08 |
nicklas |
457 |
<para> |
4184 |
20 Mar 08 |
nicklas |
458 |
The <sgmltag class="starttag">parameters</sgmltag> subtag is used to |
4184 |
20 Mar 08 |
nicklas |
459 |
provide initialisation parameters to the factory. Different factories |
4184 |
20 Mar 08 |
nicklas |
460 |
supports different parameters and you will have to check the javadoc documentation |
4184 |
20 Mar 08 |
nicklas |
461 |
for each factory to get information about which parameters that are supported. |
4184 |
20 Mar 08 |
nicklas |
462 |
</para> |
4184 |
20 Mar 08 |
nicklas |
463 |
|
4184 |
20 Mar 08 |
nicklas |
464 |
<tip> |
4184 |
20 Mar 08 |
nicklas |
465 |
<para> |
4184 |
20 Mar 08 |
nicklas |
466 |
In case the factory is poorly documented you can always assume that public |
4184 |
20 Mar 08 |
nicklas |
467 |
methods the start with <code>set</code> and take a single <classname>String</classname> |
4184 |
20 Mar 08 |
nicklas |
468 |
as an argument can be used as a parameter. The parameter tag to use should |
4184 |
20 Mar 08 |
nicklas |
469 |
be the same as the method name, minus the <code>set</code> prefix and with |
4184 |
20 Mar 08 |
nicklas |
470 |
the first letter in lowercase. For example, the method |
4184 |
20 Mar 08 |
nicklas |
471 |
<methodname>setIcon(String icon)</methodname> corresponds to the |
4184 |
20 Mar 08 |
nicklas |
472 |
<sgmltag class="starttag">icon</sgmltag> parameter. |
4184 |
20 Mar 08 |
nicklas |
473 |
</para> |
4184 |
20 Mar 08 |
nicklas |
474 |
</tip> |
5519 |
23 Nov 10 |
nicklas |
475 |
|
6403 |
29 Jan 14 |
nicklas |
476 |
<note> |
6410 |
31 Jan 14 |
nicklas |
477 |
<title>Content security policy and inline javascript</title> |
6403 |
29 Jan 14 |
nicklas |
478 |
<para> |
6812 |
30 Mar 15 |
nicklas |
479 |
The Hello World example requires quite a lot of code and it |
6812 |
30 Mar 15 |
nicklas |
480 |
would have been tempting to skip the <filename>hello.js</filename> |
6812 |
30 Mar 15 |
nicklas |
481 |
file and simply add |
6812 |
30 Mar 15 |
nicklas |
482 |
|
6812 |
30 Mar 15 |
nicklas |
483 |
<code><sgmltag class="starttag">onclick</sgmltag>alert('Hello world')<sgmltag class="endtag">onclick</sgmltag></code> |
6812 |
30 Mar 15 |
nicklas |
484 |
|
6812 |
30 Mar 15 |
nicklas |
485 |
to the <sgmltag class="starttag">parameters</sgmltag> section in the |
6812 |
30 Mar 15 |
nicklas |
486 |
<filename>extensions.xml</filename> file. However, BASE is by default |
6812 |
30 Mar 15 |
nicklas |
487 |
configured to block all inline JavaScript since it opens up for |
6812 |
30 Mar 15 |
nicklas |
488 |
cross-site scripting attacks. It is possible to relax this policy |
6812 |
30 Mar 15 |
nicklas |
489 |
but it is nothing we recommend. See |
6410 |
31 Jan 14 |
nicklas |
490 |
<xref linkend="appendix.web.xml.csp-filter" /> for more information. |
6403 |
29 Jan 14 |
nicklas |
491 |
</para> |
6410 |
31 Jan 14 |
nicklas |
492 |
|
6410 |
31 Jan 14 |
nicklas |
493 |
<para> |
6410 |
31 Jan 14 |
nicklas |
494 |
The real code examples uses a different design with pure HTML that is |
6410 |
31 Jan 14 |
nicklas |
495 |
generated dynamically and a fixed javascript file that attaches event |
6410 |
31 Jan 14 |
nicklas |
496 |
handlers when the page has been loaded and should be compatible with the |
6410 |
31 Jan 14 |
nicklas |
497 |
stricter security policy. |
6410 |
31 Jan 14 |
nicklas |
498 |
</para> |
6403 |
29 Jan 14 |
nicklas |
499 |
</note> |
6403 |
29 Jan 14 |
nicklas |
500 |
|
6812 |
30 Mar 15 |
nicklas |
501 |
</sect2> |
6812 |
30 Mar 15 |
nicklas |
502 |
|
5519 |
23 Nov 10 |
nicklas |
503 |
<sect2 id="extensions_developer.extend_multiple"> |
5519 |
23 Nov 10 |
nicklas |
504 |
<title>Extending multiple extension points with a single extension</title> |
5519 |
23 Nov 10 |
nicklas |
505 |
|
5519 |
23 Nov 10 |
nicklas |
506 |
<para> |
5519 |
23 Nov 10 |
nicklas |
507 |
A single extension can extend multiple extension points as long as their |
5519 |
23 Nov 10 |
nicklas |
508 |
action classes are compatible. This is for, for example, the case when |
5519 |
23 Nov 10 |
nicklas |
509 |
you want to add a button to more than one toolbar. |
5519 |
23 Nov 10 |
nicklas |
510 |
To do this use the <sgmltag class="starttag">extends</sgmltag> |
5519 |
23 Nov 10 |
nicklas |
511 |
tag with multiple <sgmltag class="starttag">ref</sgmltag> tags. |
5519 |
23 Nov 10 |
nicklas |
512 |
You can skip the <sgmltag class="attribute">extends</sgmltag> |
5519 |
23 Nov 10 |
nicklas |
513 |
attribute in the main tag. |
5519 |
23 Nov 10 |
nicklas |
514 |
</para> |
5519 |
23 Nov 10 |
nicklas |
515 |
<programlisting language="xml"> |
5519 |
23 Nov 10 |
nicklas |
516 |
<![CDATA[ |
5519 |
23 Nov 10 |
nicklas |
517 |
<extension |
5519 |
23 Nov 10 |
nicklas |
518 |
id="net.sf.basedb.clients.web.menu.extensions.history-edit" |
5519 |
23 Nov 10 |
nicklas |
519 |
> |
5519 |
23 Nov 10 |
nicklas |
520 |
<extends> |
5519 |
23 Nov 10 |
nicklas |
521 |
<ref index="2">net.sf.basedb.clients.web.tabcontrol.edit.sample</ref> |
5519 |
23 Nov 10 |
nicklas |
522 |
<ref index="2">net.sf.basedb.clients.web.tabcontrol.edit.extract</ref> |
5519 |
23 Nov 10 |
nicklas |
523 |
</extends> |
5519 |
23 Nov 10 |
nicklas |
524 |
... |
5519 |
23 Nov 10 |
nicklas |
525 |
</extension> |
5519 |
23 Nov 10 |
nicklas |
526 |
]]> |
5519 |
23 Nov 10 |
nicklas |
527 |
</programlisting> |
5519 |
23 Nov 10 |
nicklas |
528 |
|
5519 |
23 Nov 10 |
nicklas |
529 |
<para> |
5519 |
23 Nov 10 |
nicklas |
530 |
This is a feature of the XML format only. Behind the scenes two extensions will |
5519 |
23 Nov 10 |
nicklas |
531 |
be created (one for each extension point). The extensions will share the same |
5519 |
23 Nov 10 |
nicklas |
532 |
action and renderer factory instances. Since the id for an extension must be unique |
5519 |
23 Nov 10 |
nicklas |
533 |
a new id will be generated by combining the original id with the parts of the id's from |
5519 |
23 Nov 10 |
nicklas |
534 |
the extension points. |
5519 |
23 Nov 10 |
nicklas |
535 |
</para> |
5519 |
23 Nov 10 |
nicklas |
536 |
|
5519 |
23 Nov 10 |
nicklas |
537 |
</sect2> |
4184 |
20 Mar 08 |
nicklas |
538 |
</sect1> |
4184 |
20 Mar 08 |
nicklas |
539 |
|
4184 |
20 Mar 08 |
nicklas |
540 |
|
4206 |
04 Apr 08 |
nicklas |
541 |
<sect1 id="extensions_developer.factories"> |
5782 |
04 Oct 11 |
nicklas |
542 |
<?dbhtml filename="factories.html" ?> |
4184 |
20 Mar 08 |
nicklas |
543 |
<title>Custom action factories</title> |
4184 |
20 Mar 08 |
nicklas |
544 |
|
4184 |
20 Mar 08 |
nicklas |
545 |
<para> |
4184 |
20 Mar 08 |
nicklas |
546 |
Some times the factories shipped with BASE are not enough, and you |
4184 |
20 Mar 08 |
nicklas |
547 |
may want to provide your own factory implementation. In this case you will |
4184 |
20 Mar 08 |
nicklas |
548 |
have to create a class that implements the |
4184 |
20 Mar 08 |
nicklas |
549 |
<interfacename docapi="net.sf.basedb.util.extensions">ActionFactory</interfacename> |
4208 |
07 Apr 08 |
nicklas |
550 |
interface. Here is a very simple example that does the same as the |
4208 |
07 Apr 08 |
nicklas |
551 |
previous "Hello world" example. |
4184 |
20 Mar 08 |
nicklas |
552 |
</para> |
4184 |
20 Mar 08 |
nicklas |
553 |
|
4184 |
20 Mar 08 |
nicklas |
554 |
<programlisting language="java"> |
4184 |
20 Mar 08 |
nicklas |
555 |
<![CDATA[ |
4184 |
20 Mar 08 |
nicklas |
556 |
package net.sf.basedb.examples.extensions; |
4184 |
20 Mar 08 |
nicklas |
557 |
|
4184 |
20 Mar 08 |
nicklas |
558 |
import net.sf.basedb.clients.web.extensions.JspContext; |
4184 |
20 Mar 08 |
nicklas |
559 |
import net.sf.basedb.clients.web.extensions.menu.MenuItemAction; |
4184 |
20 Mar 08 |
nicklas |
560 |
import net.sf.basedb.clients.web.extensions.menu.MenuItemBean; |
4184 |
20 Mar 08 |
nicklas |
561 |
import net.sf.basedb.util.extensions.ActionFactory; |
4208 |
07 Apr 08 |
nicklas |
562 |
import net.sf.basedb.util.extensions.InvokationContext; |
4184 |
20 Mar 08 |
nicklas |
563 |
|
4184 |
20 Mar 08 |
nicklas |
564 |
/** |
4184 |
20 Mar 08 |
nicklas |
565 |
First example of an action factory where eveything is hardcoded. |
4184 |
20 Mar 08 |
nicklas |
566 |
@author nicklas |
4184 |
20 Mar 08 |
nicklas |
567 |
*/ |
4184 |
20 Mar 08 |
nicklas |
568 |
public class HelloWorldFactory |
4184 |
20 Mar 08 |
nicklas |
569 |
implements ActionFactory<MenuItemAction> |
4184 |
20 Mar 08 |
nicklas |
570 |
{ |
4184 |
20 Mar 08 |
nicklas |
571 |
|
4184 |
20 Mar 08 |
nicklas |
572 |
private MenuItemAction[] helloWorld; |
4184 |
20 Mar 08 |
nicklas |
573 |
|
4184 |
20 Mar 08 |
nicklas |
574 |
// A public, no-argument constructor is required |
4184 |
20 Mar 08 |
nicklas |
575 |
public HelloWorldFactory() |
4184 |
20 Mar 08 |
nicklas |
576 |
{ |
4184 |
20 Mar 08 |
nicklas |
577 |
helloWorld = new MenuItemAction[1]; |
4184 |
20 Mar 08 |
nicklas |
578 |
} |
4184 |
20 Mar 08 |
nicklas |
579 |
|
4184 |
20 Mar 08 |
nicklas |
580 |
// Return true enable the extension, false to disable it |
4208 |
07 Apr 08 |
nicklas |
581 |
public boolean prepareContext( |
4208 |
07 Apr 08 |
nicklas |
582 |
InvokationContext<? super MenuItemAction> context) |
4184 |
20 Mar 08 |
nicklas |
583 |
{ |
6812 |
30 Mar 15 |
nicklas |
584 |
JspContext jspContext = (JspContext)context.getClientContext(); |
6812 |
30 Mar 15 |
nicklas |
585 |
String home = jspContext.getHome(context.getExtension()); |
6812 |
30 Mar 15 |
nicklas |
586 |
jspContext.addScript(home + "/hello.js"); |
4184 |
20 Mar 08 |
nicklas |
587 |
return true; |
4184 |
20 Mar 08 |
nicklas |
588 |
} |
4184 |
20 Mar 08 |
nicklas |
589 |
|
4184 |
20 Mar 08 |
nicklas |
590 |
// An extension may create one or more actions |
4208 |
07 Apr 08 |
nicklas |
591 |
public MenuItemAction[] getActions( |
4208 |
07 Apr 08 |
nicklas |
592 |
InvokationContext<? super MenuItemAction> context) |
4184 |
20 Mar 08 |
nicklas |
593 |
{ |
4184 |
20 Mar 08 |
nicklas |
594 |
// This cast is always safe with the web client |
4208 |
07 Apr 08 |
nicklas |
595 |
JspContext jspContext = (JspContext)context.getClientContext(); |
4184 |
20 Mar 08 |
nicklas |
596 |
if (helloWorld[0] == null) |
4184 |
20 Mar 08 |
nicklas |
597 |
{ |
4184 |
20 Mar 08 |
nicklas |
598 |
MenuItemBean bean = new MenuItemBean(); |
6812 |
30 Mar 15 |
nicklas |
599 |
bean.setId("hello-factory"); |
4184 |
20 Mar 08 |
nicklas |
600 |
bean.setTitle("Hello factory world!"); |
4184 |
20 Mar 08 |
nicklas |
601 |
bean.setIcon(jspContext.getRoot() + "/images/info.gif"); |
4184 |
20 Mar 08 |
nicklas |
602 |
helloWorld[0] = bean; |
4184 |
20 Mar 08 |
nicklas |
603 |
} |
4184 |
20 Mar 08 |
nicklas |
604 |
return helloWorld; |
4184 |
20 Mar 08 |
nicklas |
605 |
} |
4184 |
20 Mar 08 |
nicklas |
606 |
} |
4184 |
20 Mar 08 |
nicklas |
607 |
]]> |
4184 |
20 Mar 08 |
nicklas |
608 |
</programlisting> |
4184 |
20 Mar 08 |
nicklas |
609 |
|
4184 |
20 Mar 08 |
nicklas |
610 |
<para> |
6812 |
30 Mar 15 |
nicklas |
611 |
And here are the XML and JavaScript files that goes with it. |
4184 |
20 Mar 08 |
nicklas |
612 |
</para> |
4184 |
20 Mar 08 |
nicklas |
613 |
|
4184 |
20 Mar 08 |
nicklas |
614 |
<programlisting language="xml"> |
4184 |
20 Mar 08 |
nicklas |
615 |
<![CDATA[ |
4184 |
20 Mar 08 |
nicklas |
616 |
<?xml version="1.0" encoding="UTF-8" ?> |
4184 |
20 Mar 08 |
nicklas |
617 |
<extensions xmlns="http://base.thep.lu.se/extensions.xsd"> |
4184 |
20 Mar 08 |
nicklas |
618 |
<extension |
4184 |
20 Mar 08 |
nicklas |
619 |
id="net.sf.basedb.clients.web.menu.extensions.helloworldfactory" |
4184 |
20 Mar 08 |
nicklas |
620 |
extends="net.sf.basedb.clients.web.menu.extensions" |
4184 |
20 Mar 08 |
nicklas |
621 |
> |
4184 |
20 Mar 08 |
nicklas |
622 |
<index>2</index> |
4184 |
20 Mar 08 |
nicklas |
623 |
<about> |
4184 |
20 Mar 08 |
nicklas |
624 |
<name>Hello factory world</name> |
4184 |
20 Mar 08 |
nicklas |
625 |
<description> |
4184 |
20 Mar 08 |
nicklas |
626 |
A "Hello world" variant with a custom action factory. |
4184 |
20 Mar 08 |
nicklas |
627 |
Everything is hard-coded into the factory. |
4184 |
20 Mar 08 |
nicklas |
628 |
</description> |
4184 |
20 Mar 08 |
nicklas |
629 |
</about> |
4184 |
20 Mar 08 |
nicklas |
630 |
<action-factory> |
4184 |
20 Mar 08 |
nicklas |
631 |
<factory-class> |
4184 |
20 Mar 08 |
nicklas |
632 |
net.sf.basedb.examples.extensions.HelloWorldFactory |
4184 |
20 Mar 08 |
nicklas |
633 |
</factory-class> |
4184 |
20 Mar 08 |
nicklas |
634 |
</action-factory> |
4184 |
20 Mar 08 |
nicklas |
635 |
</extension> |
4184 |
20 Mar 08 |
nicklas |
636 |
</extensions> |
4184 |
20 Mar 08 |
nicklas |
637 |
]]> |
4184 |
20 Mar 08 |
nicklas |
638 |
</programlisting> |
6812 |
30 Mar 15 |
nicklas |
639 |
<programlisting language="javascript"> |
6812 |
30 Mar 15 |
nicklas |
640 |
<![CDATA[ |
6812 |
30 Mar 15 |
nicklas |
641 |
var HelloWorldFactory = function() |
6812 |
30 Mar 15 |
nicklas |
642 |
{ |
6812 |
30 Mar 15 |
nicklas |
643 |
var hello = {}; |
6812 |
30 Mar 15 |
nicklas |
644 |
|
6812 |
30 Mar 15 |
nicklas |
645 |
/** |
6812 |
30 Mar 15 |
nicklas |
646 |
Executed once when the page is loaded. Typically |
6812 |
30 Mar 15 |
nicklas |
647 |
used to bind events to fixed control elements. |
6812 |
30 Mar 15 |
nicklas |
648 |
*/ |
6812 |
30 Mar 15 |
nicklas |
649 |
hello.initMenuItems = function() |
6812 |
30 Mar 15 |
nicklas |
650 |
{ |
6812 |
30 Mar 15 |
nicklas |
651 |
// Bind event handlers the menu items. |
6812 |
30 Mar 15 |
nicklas |
652 |
// First parameter is the ID of the menu item |
6812 |
30 Mar 15 |
nicklas |
653 |
// Second parameter is the event to react to (=click) |
6812 |
30 Mar 15 |
nicklas |
654 |
// Last parameter is the function to execute |
6812 |
30 Mar 15 |
nicklas |
655 |
Events.addEventHandler('hello-factory', 'click', hello.helloFactoryWorld); |
6812 |
30 Mar 15 |
nicklas |
656 |
} |
6812 |
30 Mar 15 |
nicklas |
657 |
|
6812 |
30 Mar 15 |
nicklas |
658 |
// Show 'Hello factory world' message |
6812 |
30 Mar 15 |
nicklas |
659 |
hello.helloFactoryWorld = function(event) |
6812 |
30 Mar 15 |
nicklas |
660 |
{ |
6812 |
30 Mar 15 |
nicklas |
661 |
alert('Hello factory world'); |
6812 |
30 Mar 15 |
nicklas |
662 |
} |
6812 |
30 Mar 15 |
nicklas |
663 |
|
6812 |
30 Mar 15 |
nicklas |
664 |
return hello; |
6812 |
30 Mar 15 |
nicklas |
665 |
}(); |
6812 |
30 Mar 15 |
nicklas |
666 |
|
6812 |
30 Mar 15 |
nicklas |
667 |
//Register the page initializer method with the BASE core |
6812 |
30 Mar 15 |
nicklas |
668 |
Doc.onLoad(HelloWorldFactory.initMenuItems); |
6812 |
30 Mar 15 |
nicklas |
669 |
]]> |
6812 |
30 Mar 15 |
nicklas |
670 |
</programlisting> |
4184 |
20 Mar 08 |
nicklas |
671 |
|
4184 |
20 Mar 08 |
nicklas |
672 |
<para> |
4184 |
20 Mar 08 |
nicklas |
673 |
To install this extension you need to put the compiled |
6812 |
30 Mar 15 |
nicklas |
674 |
<filename>HelloWorldFactory.class</filename>, the XML |
6812 |
30 Mar 15 |
nicklas |
675 |
and JavaScript files inside a JAR file. The XML file must be located at |
6812 |
30 Mar 15 |
nicklas |
676 |
<filename>META-INF/extensions.xml</filename> the JavScript file |
6812 |
30 Mar 15 |
nicklas |
677 |
at <filename>resources/hello.js</filename>, and the class |
4184 |
20 Mar 08 |
nicklas |
678 |
file at <filename>net/sf/basedb/examples/extensions/HelloWorldFactory.class</filename>. |
4184 |
20 Mar 08 |
nicklas |
679 |
</para> |
4184 |
20 Mar 08 |
nicklas |
680 |
|
4184 |
20 Mar 08 |
nicklas |
681 |
<para> |
4184 |
20 Mar 08 |
nicklas |
682 |
The above example is a bit artificial and we have not gained anything. |
4184 |
20 Mar 08 |
nicklas |
683 |
Instead, we have lost the ability to easily change the menu since everything is |
4208 |
07 Apr 08 |
nicklas |
684 |
now hardcoded into the factory. To change, for example the title, requires that |
4208 |
07 Apr 08 |
nicklas |
685 |
we recompile the java code. It would be more useful if we could make the factory |
4184 |
20 Mar 08 |
nicklas |
686 |
configurable with parameters. The next example will make the icon |
4208 |
07 Apr 08 |
nicklas |
687 |
and message configurable, and also include the name |
4184 |
20 Mar 08 |
nicklas |
688 |
of the currently logged in user. For example: "Greetings <name of |
6403 |
29 Jan 14 |
nicklas |
689 |
logged in user>!". We'll also get rid of the onclick event handler |
6403 |
29 Jan 14 |
nicklas |
690 |
and use proper event binding using javascript. |
4184 |
20 Mar 08 |
nicklas |
691 |
</para> |
4184 |
20 Mar 08 |
nicklas |
692 |
|
4184 |
20 Mar 08 |
nicklas |
693 |
<programlisting language="java"> |
4184 |
20 Mar 08 |
nicklas |
694 |
<![CDATA[ |
4184 |
20 Mar 08 |
nicklas |
695 |
package net.sf.basedb.examples.extensions; |
4184 |
20 Mar 08 |
nicklas |
696 |
|
4184 |
20 Mar 08 |
nicklas |
697 |
import net.sf.basedb.clients.web.extensions.AbstractJspActionFactory; |
4184 |
20 Mar 08 |
nicklas |
698 |
import net.sf.basedb.clients.web.extensions.menu.MenuItemAction; |
4184 |
20 Mar 08 |
nicklas |
699 |
import net.sf.basedb.clients.web.extensions.menu.MenuItemBean; |
4184 |
20 Mar 08 |
nicklas |
700 |
import net.sf.basedb.core.DbControl; |
4184 |
20 Mar 08 |
nicklas |
701 |
import net.sf.basedb.core.SessionControl; |
4184 |
20 Mar 08 |
nicklas |
702 |
import net.sf.basedb.core.User; |
4208 |
07 Apr 08 |
nicklas |
703 |
import net.sf.basedb.util.extensions.ClientContext; |
4208 |
07 Apr 08 |
nicklas |
704 |
import net.sf.basedb.util.extensions.InvokationContext; |
4184 |
20 Mar 08 |
nicklas |
705 |
import net.sf.basedb.util.extensions.xml.PathSetter; |
4184 |
20 Mar 08 |
nicklas |
706 |
import net.sf.basedb.util.extensions.xml.VariableSetter; |
4184 |
20 Mar 08 |
nicklas |
707 |
|
4184 |
20 Mar 08 |
nicklas |
708 |
/** |
4184 |
20 Mar 08 |
nicklas |
709 |
Example menu item factory that creates a "Hello world" menu item |
4184 |
20 Mar 08 |
nicklas |
710 |
where the "Hello" part can be changed by the "prefix" setting in the |
4184 |
20 Mar 08 |
nicklas |
711 |
XML file, and the "world" part is dynamically replaced with the name |
4184 |
20 Mar 08 |
nicklas |
712 |
of the logged in user. |
4184 |
20 Mar 08 |
nicklas |
713 |
|
4184 |
20 Mar 08 |
nicklas |
714 |
@author nicklas |
4184 |
20 Mar 08 |
nicklas |
715 |
*/ |
4184 |
20 Mar 08 |
nicklas |
716 |
public class HelloUserFactory |
4184 |
20 Mar 08 |
nicklas |
717 |
extends AbstractJspActionFactory<MenuItemAction> |
4184 |
20 Mar 08 |
nicklas |
718 |
{ |
6403 |
29 Jan 14 |
nicklas |
719 |
// The ID attribute of the <div> tag in the final HTML |
6403 |
29 Jan 14 |
nicklas |
720 |
private String id; |
6403 |
29 Jan 14 |
nicklas |
721 |
|
4184 |
20 Mar 08 |
nicklas |
722 |
// To store the URL to the icon |
4184 |
20 Mar 08 |
nicklas |
723 |
private String icon; |
4184 |
20 Mar 08 |
nicklas |
724 |
|
4184 |
20 Mar 08 |
nicklas |
725 |
// The default prefix is Hello |
4184 |
20 Mar 08 |
nicklas |
726 |
private String prefix = "Hello"; |
4184 |
20 Mar 08 |
nicklas |
727 |
|
4184 |
20 Mar 08 |
nicklas |
728 |
// A public, no-argument constructor is required |
4184 |
20 Mar 08 |
nicklas |
729 |
public HelloUserFactory() |
4184 |
20 Mar 08 |
nicklas |
730 |
{} |
4184 |
20 Mar 08 |
nicklas |
731 |
|
4184 |
20 Mar 08 |
nicklas |
732 |
/** |
4184 |
20 Mar 08 |
nicklas |
733 |
Creates a menu item that displays: {prefix} {name of user}! |
4184 |
20 Mar 08 |
nicklas |
734 |
*/ |
4208 |
07 Apr 08 |
nicklas |
735 |
public MenuItemAction[] getActions( |
4208 |
07 Apr 08 |
nicklas |
736 |
InvokationContext<? super MenuItemAction> context) |
4184 |
20 Mar 08 |
nicklas |
737 |
{ |
4208 |
07 Apr 08 |
nicklas |
738 |
String userName = getUserName(context.getClientContext()); |
4184 |
20 Mar 08 |
nicklas |
739 |
MenuItemBean helloUser = new MenuItemBean(); |
6403 |
29 Jan 14 |
nicklas |
740 |
helloUser.setId(id); |
4184 |
20 Mar 08 |
nicklas |
741 |
helloUser.setTitle(prefix + " " + userName + "!"); |
4184 |
20 Mar 08 |
nicklas |
742 |
helloUser.setIcon(icon); |
6403 |
29 Jan 14 |
nicklas |
743 |
// Use 'dynamic' attributes for extra info that needs to be included |
6403 |
29 Jan 14 |
nicklas |
744 |
// in the HTML |
6403 |
29 Jan 14 |
nicklas |
745 |
setParameter("data-user-name", userName); |
6403 |
29 Jan 14 |
nicklas |
746 |
setParameter("data-prefix", prefix); |
6403 |
29 Jan 14 |
nicklas |
747 |
helloUser.setDynamicActionAttributesSource(this); |
4184 |
20 Mar 08 |
nicklas |
748 |
return new MenuItemAction[] { helloUser }; |
4184 |
20 Mar 08 |
nicklas |
749 |
} |
4184 |
20 Mar 08 |
nicklas |
750 |
|
4184 |
20 Mar 08 |
nicklas |
751 |
/** |
4184 |
20 Mar 08 |
nicklas |
752 |
Get the name of the logged in user. |
4184 |
20 Mar 08 |
nicklas |
753 |
*/ |
4208 |
07 Apr 08 |
nicklas |
754 |
private String getUserName(ClientContext context) |
4184 |
20 Mar 08 |
nicklas |
755 |
{ |
4237 |
18 Apr 08 |
nicklas |
756 |
SessionControl sc = context.getSessionControl(); |
4237 |
18 Apr 08 |
nicklas |
757 |
DbControl dc = context.getDbControl(); |
4237 |
18 Apr 08 |
nicklas |
758 |
User current = User.getById(dc, sc.getLoggedInUserId()); |
4237 |
18 Apr 08 |
nicklas |
759 |
return current.getName(); |
4184 |
20 Mar 08 |
nicklas |
760 |
} |
4184 |
20 Mar 08 |
nicklas |
761 |
|
6403 |
29 Jan 14 |
nicklas |
762 |
/** |
6403 |
29 Jan 14 |
nicklas |
763 |
Set the ID to use for the <div> tag. This is needed |
6403 |
29 Jan 14 |
nicklas |
764 |
so that we can attach a 'click' handler to the menu item |
6403 |
29 Jan 14 |
nicklas |
765 |
with JavaScript. |
6403 |
29 Jan 14 |
nicklas |
766 |
*/ |
6403 |
29 Jan 14 |
nicklas |
767 |
public void setId(String id) |
6403 |
29 Jan 14 |
nicklas |
768 |
{ |
6403 |
29 Jan 14 |
nicklas |
769 |
this.id = id; |
6403 |
29 Jan 14 |
nicklas |
770 |
} |
6403 |
29 Jan 14 |
nicklas |
771 |
|
4184 |
20 Mar 08 |
nicklas |
772 |
/** |
4184 |
20 Mar 08 |
nicklas |
773 |
Sets the icon to use. Path conversion is enabled. |
4184 |
20 Mar 08 |
nicklas |
774 |
*/ |
4184 |
20 Mar 08 |
nicklas |
775 |
@VariableSetter |
4184 |
20 Mar 08 |
nicklas |
776 |
@PathSetter |
4184 |
20 Mar 08 |
nicklas |
777 |
public void setIcon(String icon) |
4184 |
20 Mar 08 |
nicklas |
778 |
{ |
4184 |
20 Mar 08 |
nicklas |
779 |
this.icon = icon; |
4184 |
20 Mar 08 |
nicklas |
780 |
} |
4184 |
20 Mar 08 |
nicklas |
781 |
|
4184 |
20 Mar 08 |
nicklas |
782 |
/** |
4184 |
20 Mar 08 |
nicklas |
783 |
Sets the prefix to use. If not set, the |
4184 |
20 Mar 08 |
nicklas |
784 |
default value is "Hello". |
4184 |
20 Mar 08 |
nicklas |
785 |
*/ |
4184 |
20 Mar 08 |
nicklas |
786 |
public void setPrefix(String prefix) |
4184 |
20 Mar 08 |
nicklas |
787 |
{ |
4184 |
20 Mar 08 |
nicklas |
788 |
this.prefix = prefix == null ? "Hello" : prefix; |
4184 |
20 Mar 08 |
nicklas |
789 |
} |
4184 |
20 Mar 08 |
nicklas |
790 |
} |
4184 |
20 Mar 08 |
nicklas |
791 |
]]> |
4184 |
20 Mar 08 |
nicklas |
792 |
</programlisting> |
4184 |
20 Mar 08 |
nicklas |
793 |
|
4184 |
20 Mar 08 |
nicklas |
794 |
<para> |
6403 |
29 Jan 14 |
nicklas |
795 |
The are several new parts in this factory. The first is the <methodname>getUserName()</methodname> |
4184 |
20 Mar 08 |
nicklas |
796 |
method which is called from <methodname>getActions()</methodname>. Note |
4184 |
20 Mar 08 |
nicklas |
797 |
that the <methodname>getActions()</methodname> method always create |
4184 |
20 Mar 08 |
nicklas |
798 |
a new <classname docapi="net.sf.basedb.clients.web.extensions.menu">MenuItemBean</classname>. |
4184 |
20 Mar 08 |
nicklas |
799 |
It can no longer be cached since the title and javascript code depends on |
4184 |
20 Mar 08 |
nicklas |
800 |
which user is logged in. |
4184 |
20 Mar 08 |
nicklas |
801 |
</para> |
4184 |
20 Mar 08 |
nicklas |
802 |
|
4184 |
20 Mar 08 |
nicklas |
803 |
<para> |
6403 |
29 Jan 14 |
nicklas |
804 |
The second new part is the <methodname>setId()</methodname>, |
6403 |
29 Jan 14 |
nicklas |
805 |
<methodname>setIcon()</methodname> and |
4184 |
20 Mar 08 |
nicklas |
806 |
<methodname>setPrefix()</methodname> methods. |
4184 |
20 Mar 08 |
nicklas |
807 |
The extensions system uses java reflection to find the existance of |
6403 |
29 Jan 14 |
nicklas |
808 |
the methods if <sgmltag class="starttag">id</sgmltag>, |
6403 |
29 Jan 14 |
nicklas |
809 |
<sgmltag class="starttag">icon</sgmltag> and/or |
4184 |
20 Mar 08 |
nicklas |
810 |
<sgmltag class="starttag">prefix</sgmltag> tags are present |
4184 |
20 Mar 08 |
nicklas |
811 |
in the <sgmltag class="starttag">parameters</sgmltag> tag for a factory, |
4184 |
20 Mar 08 |
nicklas |
812 |
the methods are automatically called with the value inside the tag |
4184 |
20 Mar 08 |
nicklas |
813 |
as it's argument. |
4184 |
20 Mar 08 |
nicklas |
814 |
</para> |
4184 |
20 Mar 08 |
nicklas |
815 |
|
4184 |
20 Mar 08 |
nicklas |
816 |
<para> |
4184 |
20 Mar 08 |
nicklas |
817 |
The <classname docapi="net.sf.basedb.util.extensions.xml">VariableSetter</classname> |
4184 |
20 Mar 08 |
nicklas |
818 |
and <classname docapi="net.sf.basedb.util.extensions.xml">PathSetter</classname> |
4184 |
20 Mar 08 |
nicklas |
819 |
annotations on the <methodname>setIcon()</methodname> are used to enable |
4184 |
20 Mar 08 |
nicklas |
820 |
"smart" convertions of the value. Note that in the |
5971 |
17 Feb 12 |
nicklas |
821 |
XML file you only have to specify <filename>/images/info.png</filename> |
4184 |
20 Mar 08 |
nicklas |
822 |
as the URL to the icon, but in the hardcoded factory you have to |
5971 |
17 Feb 12 |
nicklas |
823 |
do: <code>jspContext.getRoot() + "/images/info.png"</code>. In this case, |
4184 |
20 Mar 08 |
nicklas |
824 |
it is the <classname>PathSetter</classname> which automatically adds the |
4184 |
20 Mar 08 |
nicklas |
825 |
the JSP root directory to all URL:s starting with /. The |
4184 |
20 Mar 08 |
nicklas |
826 |
<classname>VariableSetter</classname> can do the same thing but you would have to use |
5971 |
17 Feb 12 |
nicklas |
827 |
<code>$ROOT$</code> instead. Eg. <code>$ROOT$/images/info.png</code>. The |
4208 |
07 Apr 08 |
nicklas |
828 |
<classname>PathSetter</classname> only looks at the first characteer, |
4208 |
07 Apr 08 |
nicklas |
829 |
while the <classname>VariableSetter</classname> looks in the entire string. |
4184 |
20 Mar 08 |
nicklas |
830 |
</para> |
4184 |
20 Mar 08 |
nicklas |
831 |
|
4184 |
20 Mar 08 |
nicklas |
832 |
<para> |
6812 |
30 Mar 15 |
nicklas |
833 |
The third new part is the use of dynamic action attributes. These |
6812 |
30 Mar 15 |
nicklas |
834 |
are extra attributes that have not been defined by the <classname>Action</classname> |
6812 |
30 Mar 15 |
nicklas |
835 |
interface. To set a dynamic attribute we call the |
6812 |
30 Mar 15 |
nicklas |
836 |
<methodname>setParameter()</methodname> method and then |
6403 |
29 Jan 14 |
nicklas |
837 |
<methodname>MenuItemBean.setDynamicActionAttributesSource()</methodname> |
6812 |
30 Mar 15 |
nicklas |
838 |
The dynamic attributes are a simple way to output data to |
6403 |
29 Jan 14 |
nicklas |
839 |
the HTML that is later needed by scripts. In this case, the generated |
6403 |
29 Jan 14 |
nicklas |
840 |
HTML may look something like this: |
6403 |
29 Jan 14 |
nicklas |
841 |
</para> |
6403 |
29 Jan 14 |
nicklas |
842 |
|
6403 |
29 Jan 14 |
nicklas |
843 |
<programlisting language="html"> |
6403 |
29 Jan 14 |
nicklas |
844 |
<![CDATA[ |
6403 |
29 Jan 14 |
nicklas |
845 |
<div id="greetings-user" data-user-name="..." data-prefix="Greetings" ... > |
6403 |
29 Jan 14 |
nicklas |
846 |
... |
6403 |
29 Jan 14 |
nicklas |
847 |
</div> |
6403 |
29 Jan 14 |
nicklas |
848 |
]]> |
6403 |
29 Jan 14 |
nicklas |
849 |
</programlisting> |
6403 |
29 Jan 14 |
nicklas |
850 |
|
6403 |
29 Jan 14 |
nicklas |
851 |
<para> |
4184 |
20 Mar 08 |
nicklas |
852 |
Here is an example of an extension configuration that can be used |
6410 |
31 Jan 14 |
nicklas |
853 |
with the new factory. Notice that the <sgmltag class="starttag">about</sgmltag> |
6410 |
31 Jan 14 |
nicklas |
854 |
tag now include <code>safe-scripts="1"</code> attribute. This is a way |
6410 |
31 Jan 14 |
nicklas |
855 |
for the devloper to tell the extensions installation wizard that the extensions |
6410 |
31 Jan 14 |
nicklas |
856 |
doesn't use any unsafe code and no warning will be displayed when installing the |
6410 |
31 Jan 14 |
nicklas |
857 |
extensions. |
4184 |
20 Mar 08 |
nicklas |
858 |
</para> |
4184 |
20 Mar 08 |
nicklas |
859 |
|
4184 |
20 Mar 08 |
nicklas |
860 |
<programlisting language="xml"> |
4184 |
20 Mar 08 |
nicklas |
861 |
<![CDATA[ |
4184 |
20 Mar 08 |
nicklas |
862 |
<extensions xmlns="http://base.thep.lu.se/extensions.xsd"> |
4184 |
20 Mar 08 |
nicklas |
863 |
<extension |
4184 |
20 Mar 08 |
nicklas |
864 |
id="net.sf.basedb.clients.web.menu.extensions.hellouser" |
4184 |
20 Mar 08 |
nicklas |
865 |
extends="net.sf.basedb.clients.web.menu.extensions" |
4184 |
20 Mar 08 |
nicklas |
866 |
> |
4184 |
20 Mar 08 |
nicklas |
867 |
<index>3</index> |
6410 |
31 Jan 14 |
nicklas |
868 |
<about safe-scripts="1"> |
4184 |
20 Mar 08 |
nicklas |
869 |
<name>Greetings user</name> |
4184 |
20 Mar 08 |
nicklas |
870 |
<description> |
4184 |
20 Mar 08 |
nicklas |
871 |
A "Hello world" variant with a custom action factory |
4184 |
20 Mar 08 |
nicklas |
872 |
that displays "Greetings {name of user}" instead. We also |
4184 |
20 Mar 08 |
nicklas |
873 |
make the icon configurable. |
4184 |
20 Mar 08 |
nicklas |
874 |
</description> |
4184 |
20 Mar 08 |
nicklas |
875 |
</about> |
4184 |
20 Mar 08 |
nicklas |
876 |
<action-factory> |
4184 |
20 Mar 08 |
nicklas |
877 |
<factory-class> |
4184 |
20 Mar 08 |
nicklas |
878 |
net.sf.basedb.examples.extensions.HelloUserFactory |
4184 |
20 Mar 08 |
nicklas |
879 |
</factory-class> |
4184 |
20 Mar 08 |
nicklas |
880 |
<parameters> |
6403 |
29 Jan 14 |
nicklas |
881 |
<id>greetings-user</id> |
4184 |
20 Mar 08 |
nicklas |
882 |
<prefix>Greetings</prefix> |
4184 |
20 Mar 08 |
nicklas |
883 |
<icon>/images/take_ownership.png</icon> |
6403 |
29 Jan 14 |
nicklas |
884 |
<script>~/scripts/menu-items.js</script> |
4184 |
20 Mar 08 |
nicklas |
885 |
</parameters> |
4184 |
20 Mar 08 |
nicklas |
886 |
</action-factory> |
4184 |
20 Mar 08 |
nicklas |
887 |
</extension> |
4184 |
20 Mar 08 |
nicklas |
888 |
</extensions> |
4184 |
20 Mar 08 |
nicklas |
889 |
]]> |
4184 |
20 Mar 08 |
nicklas |
890 |
</programlisting> |
4184 |
20 Mar 08 |
nicklas |
891 |
|
6403 |
29 Jan 14 |
nicklas |
892 |
<para> |
6403 |
29 Jan 14 |
nicklas |
893 |
And the <filename>menu-items.js</filename> JavaScript file: |
6403 |
29 Jan 14 |
nicklas |
894 |
</para> |
6403 |
29 Jan 14 |
nicklas |
895 |
<programlisting language="javascript"> |
6403 |
29 Jan 14 |
nicklas |
896 |
<![CDATA[ |
6403 |
29 Jan 14 |
nicklas |
897 |
var HelloWorldMenu = function() |
6403 |
29 Jan 14 |
nicklas |
898 |
{ |
6403 |
29 Jan 14 |
nicklas |
899 |
var menu = {}; |
6403 |
29 Jan 14 |
nicklas |
900 |
|
6403 |
29 Jan 14 |
nicklas |
901 |
/** |
6403 |
29 Jan 14 |
nicklas |
902 |
Executed once when the page is loaded. Typically |
6403 |
29 Jan 14 |
nicklas |
903 |
used to bind events to fixed control elements. |
6403 |
29 Jan 14 |
nicklas |
904 |
*/ |
6403 |
29 Jan 14 |
nicklas |
905 |
menu.initMenuItems = function() |
6403 |
29 Jan 14 |
nicklas |
906 |
{ |
6403 |
29 Jan 14 |
nicklas |
907 |
// Bind event handlers the menu items. |
6403 |
29 Jan 14 |
nicklas |
908 |
// First parameter is the ID of the menu item |
6403 |
29 Jan 14 |
nicklas |
909 |
// Second parameter is the event to react to (=click) |
6403 |
29 Jan 14 |
nicklas |
910 |
// Last parameter is the function to execute |
6403 |
29 Jan 14 |
nicklas |
911 |
Events.addEventHandler('greetings-user', 'click', menu.greetingsUser); |
6403 |
29 Jan 14 |
nicklas |
912 |
} |
6403 |
29 Jan 14 |
nicklas |
913 |
|
6403 |
29 Jan 14 |
nicklas |
914 |
// Get the dynamic attributes defined in extensions.xml |
6403 |
29 Jan 14 |
nicklas |
915 |
// and generate an alert message |
6403 |
29 Jan 14 |
nicklas |
916 |
menu.greetingsUser = function(event) |
6403 |
29 Jan 14 |
nicklas |
917 |
{ |
6403 |
29 Jan 14 |
nicklas |
918 |
var userName = Data.get(event.currentTarget, 'user-name'); |
6403 |
29 Jan 14 |
nicklas |
919 |
var prefix = Data.get(event.currentTarget, 'prefix'); |
6403 |
29 Jan 14 |
nicklas |
920 |
alert(prefix + ' ' + userName + '!'); |
6403 |
29 Jan 14 |
nicklas |
921 |
} |
6403 |
29 Jan 14 |
nicklas |
922 |
|
6403 |
29 Jan 14 |
nicklas |
923 |
return menu; |
6403 |
29 Jan 14 |
nicklas |
924 |
}(); |
6403 |
29 Jan 14 |
nicklas |
925 |
|
6403 |
29 Jan 14 |
nicklas |
926 |
//Register the page initializer method with the BASE core |
6403 |
29 Jan 14 |
nicklas |
927 |
Doc.onLoad(HelloWorldMenu.initMenuItems); |
6403 |
29 Jan 14 |
nicklas |
928 |
]]> |
6403 |
29 Jan 14 |
nicklas |
929 |
</programlisting> |
6403 |
29 Jan 14 |
nicklas |
930 |
|
4206 |
04 Apr 08 |
nicklas |
931 |
<note> |
4206 |
04 Apr 08 |
nicklas |
932 |
<title>Be aware of multi-threading issues</title> |
4206 |
04 Apr 08 |
nicklas |
933 |
<para> |
4206 |
04 Apr 08 |
nicklas |
934 |
When you are creating custom action and renderer factories be |
4206 |
04 Apr 08 |
nicklas |
935 |
aware that multiple threads may use a single factory instance |
4206 |
04 Apr 08 |
nicklas |
936 |
at the same time. Action and renderer objects only needs to |
4206 |
04 Apr 08 |
nicklas |
937 |
be thread-safe if the factories re-use the same objects. |
4206 |
04 Apr 08 |
nicklas |
938 |
</para> |
4206 |
04 Apr 08 |
nicklas |
939 |
</note> |
4206 |
04 Apr 08 |
nicklas |
940 |
|
4184 |
20 Mar 08 |
nicklas |
941 |
</sect1> |
4184 |
20 Mar 08 |
nicklas |
942 |
|
4206 |
04 Apr 08 |
nicklas |
943 |
<sect1 id="extensions_developer.resources"> |
5782 |
04 Oct 11 |
nicklas |
944 |
<?dbhtml filename="resources.html" ?> |
4184 |
20 Mar 08 |
nicklas |
945 |
<title>Custom images, JSP files, and other resources</title> |
4184 |
20 Mar 08 |
nicklas |
946 |
|
4184 |
20 Mar 08 |
nicklas |
947 |
<para> |
4184 |
20 Mar 08 |
nicklas |
948 |
Some times your extension may need other resources. It can for |
4184 |
20 Mar 08 |
nicklas |
949 |
for example be an icon, a javascript file, a JSP file or something |
4184 |
20 Mar 08 |
nicklas |
950 |
else. Fortunately this is very easy. You need to put the extension |
4184 |
20 Mar 08 |
nicklas |
951 |
in a JAR file. As usual the extension definition XML file should be |
4184 |
20 Mar 08 |
nicklas |
952 |
at <filename>META-INF/extensions.xml</filename>. Everything you put in |
4184 |
20 Mar 08 |
nicklas |
953 |
the JAR file inside the <filename>resources/</filename> directory |
4184 |
20 Mar 08 |
nicklas |
954 |
will automatically be extracted by the extension system to a directory |
4184 |
20 Mar 08 |
nicklas |
955 |
on the web server. Here is another "Hello world" example which uses a |
4223 |
15 Apr 08 |
nicklas |
956 |
custom JSP file to display the message. There is also a custom icon. |
4184 |
20 Mar 08 |
nicklas |
957 |
</para> |
4184 |
20 Mar 08 |
nicklas |
958 |
|
4184 |
20 Mar 08 |
nicklas |
959 |
<programlisting language="xml"> |
4184 |
20 Mar 08 |
nicklas |
960 |
<![CDATA[ |
4184 |
20 Mar 08 |
nicklas |
961 |
<extensions xmlns="http://base.thep.lu.se/extensions.xsd"> |
4184 |
20 Mar 08 |
nicklas |
962 |
<extension |
4184 |
20 Mar 08 |
nicklas |
963 |
id="net.sf.basedb.clients.web.menu.extensions.hellojspworld" |
4184 |
20 Mar 08 |
nicklas |
964 |
extends="net.sf.basedb.clients.web.menu.extensions" |
4184 |
20 Mar 08 |
nicklas |
965 |
> |
4184 |
20 Mar 08 |
nicklas |
966 |
<index>4</index> |
6417 |
06 Feb 14 |
nicklas |
967 |
<about safe-scripts="1" safe-resources="1"> |
4184 |
20 Mar 08 |
nicklas |
968 |
<name>Hello JSP world</name> |
4184 |
20 Mar 08 |
nicklas |
969 |
<description> |
4223 |
15 Apr 08 |
nicklas |
970 |
This example uses a custom JSP file to display the |
4184 |
20 Mar 08 |
nicklas |
971 |
"Hello world" message instead of a javascript popup. |
4184 |
20 Mar 08 |
nicklas |
972 |
</description> |
4184 |
20 Mar 08 |
nicklas |
973 |
</about> |
4184 |
20 Mar 08 |
nicklas |
974 |
<action-factory> |
4184 |
20 Mar 08 |
nicklas |
975 |
<factory-class> |
4184 |
20 Mar 08 |
nicklas |
976 |
net.sf.basedb.clients.web.extensions.menu.FixedMenuItemFactory |
4184 |
20 Mar 08 |
nicklas |
977 |
</factory-class> |
4184 |
20 Mar 08 |
nicklas |
978 |
<parameters> |
4184 |
20 Mar 08 |
nicklas |
979 |
<title>Hello JSP world!</title> |
4223 |
15 Apr 08 |
nicklas |
980 |
<tooltip>Opens a JSP file with the message</tooltip> |
6403 |
29 Jan 14 |
nicklas |
981 |
<data-url>$HOME$/hello_world.jsp?ID=$SESSION-ID$</data-url> |
6403 |
29 Jan 14 |
nicklas |
982 |
<data-popup>HelloJspWorld, 400, 300</data-popup> |
4184 |
20 Mar 08 |
nicklas |
983 |
<icon>~/images/world.png</icon> |
4184 |
20 Mar 08 |
nicklas |
984 |
</parameters> |
4184 |
20 Mar 08 |
nicklas |
985 |
</action-factory> |
4184 |
20 Mar 08 |
nicklas |
986 |
</extension> |
4184 |
20 Mar 08 |
nicklas |
987 |
</extensions> |
4184 |
20 Mar 08 |
nicklas |
988 |
]]> |
4184 |
20 Mar 08 |
nicklas |
989 |
</programlisting> |
4184 |
20 Mar 08 |
nicklas |
990 |
|
4184 |
20 Mar 08 |
nicklas |
991 |
<para> |
4184 |
20 Mar 08 |
nicklas |
992 |
The JAR file should have have the following contents: |
4184 |
20 Mar 08 |
nicklas |
993 |
</para> |
4184 |
20 Mar 08 |
nicklas |
994 |
|
4184 |
20 Mar 08 |
nicklas |
995 |
<programlisting> |
4184 |
20 Mar 08 |
nicklas |
996 |
META-INF/extensions.XML |
4184 |
20 Mar 08 |
nicklas |
997 |
resources/hello_world.jsp |
4184 |
20 Mar 08 |
nicklas |
998 |
resources/images/world.png |
4184 |
20 Mar 08 |
nicklas |
999 |
</programlisting> |
4184 |
20 Mar 08 |
nicklas |
1000 |
|
4184 |
20 Mar 08 |
nicklas |
1001 |
<para> |
4184 |
20 Mar 08 |
nicklas |
1002 |
When this extension is installed the <filename>hello_world.jsp</filename> |
4184 |
20 Mar 08 |
nicklas |
1003 |
and <filename>world.png</filename> files are automatically extracted |
4184 |
20 Mar 08 |
nicklas |
1004 |
to the web servers file system. Each extension is given a unique |
4184 |
20 Mar 08 |
nicklas |
1005 |
<code>HOME</code> directory to make sure that extensions doesn't interfere |
4184 |
20 Mar 08 |
nicklas |
1006 |
with each other. The URL to the home directory is made available in the |
4184 |
20 Mar 08 |
nicklas |
1007 |
<varname>$HOME$</varname> variable. All factory settings that have |
4184 |
20 Mar 08 |
nicklas |
1008 |
been annotated with the <interfacename |
4184 |
20 Mar 08 |
nicklas |
1009 |
docapi="net.sf.basedb.util.extensions.xml">VariableSetter</interfacename> |
4184 |
20 Mar 08 |
nicklas |
1010 |
will have their values scanned for <code>$HOME$</code> which is replaced |
4184 |
20 Mar 08 |
nicklas |
1011 |
with the real URL. It is also possible to use the <varname>$ROOT$</varname> |
4184 |
20 Mar 08 |
nicklas |
1012 |
variable to get the root URL for the BASE web application. Never use |
4184 |
20 Mar 08 |
nicklas |
1013 |
<code>/base/...</code> since users may install BASE into another |
4184 |
20 Mar 08 |
nicklas |
1014 |
path. |
4184 |
20 Mar 08 |
nicklas |
1015 |
</para> |
4184 |
20 Mar 08 |
nicklas |
1016 |
|
4184 |
20 Mar 08 |
nicklas |
1017 |
<para> |
4184 |
20 Mar 08 |
nicklas |
1018 |
The tilde (~) in the <sgmltag class="starttag">icon</sgmltag> tag value |
4184 |
20 Mar 08 |
nicklas |
1019 |
is also replaced with the <code>HOME</code> path. Note that this kind of |
4184 |
20 Mar 08 |
nicklas |
1020 |
replacement is only done on factory settings that have been annotated |
4184 |
20 Mar 08 |
nicklas |
1021 |
with the <classname docapi="net.sf.basedb.util.extensions.xml">PathSetter</classname> |
4184 |
20 Mar 08 |
nicklas |
1022 |
annotation and is only done on the first character. |
4184 |
20 Mar 08 |
nicklas |
1023 |
</para> |
4184 |
20 Mar 08 |
nicklas |
1024 |
|
6417 |
06 Feb 14 |
nicklas |
1025 |
<para> |
6417 |
06 Feb 14 |
nicklas |
1026 |
The <code>safe-resources="1"</code> attribute in the <sgmltag class="starttag">about</sgmltag> |
6417 |
06 Feb 14 |
nicklas |
1027 |
tag is used to tell BASE that all resource files doesn't use inline scripts or event handlers. |
6417 |
06 Feb 14 |
nicklas |
1028 |
This is the default setting and don't have to be included. On the other hand, |
6417 |
06 Feb 14 |
nicklas |
1029 |
if <code>safe-resources="0"</code> is specified BASE uses a less restrictive content |
6417 |
06 Feb 14 |
nicklas |
1030 |
security policy for that extension that allows the use of inline scripts. This setting |
6417 |
06 Feb 14 |
nicklas |
1031 |
is not recommended but can be useful during a transition phase while the extensions code |
6417 |
06 Feb 14 |
nicklas |
1032 |
is being updated. |
6417 |
06 Feb 14 |
nicklas |
1033 |
</para> |
6417 |
06 Feb 14 |
nicklas |
1034 |
|
4221 |
14 Apr 08 |
nicklas |
1035 |
<note> |
4221 |
14 Apr 08 |
nicklas |
1036 |
<para> |
4223 |
15 Apr 08 |
nicklas |
1037 |
Unfortunately, the custom JSP file can't use classes that |
4221 |
14 Apr 08 |
nicklas |
1038 |
are located in the extension's JAR file. The reason is that the |
4223 |
15 Apr 08 |
nicklas |
1039 |
JAR file is not known to Tomcat and Tomcat will not look in the |
5640 |
24 May 11 |
nicklas |
1040 |
<filename>plugins.dir</filename> folder to |
4223 |
15 Apr 08 |
nicklas |
1041 |
try to find classes. There are currently two possible workarounds: |
4221 |
14 Apr 08 |
nicklas |
1042 |
</para> |
4223 |
15 Apr 08 |
nicklas |
1043 |
|
4223 |
15 Apr 08 |
nicklas |
1044 |
<itemizedlist> |
4223 |
15 Apr 08 |
nicklas |
1045 |
<listitem> |
4223 |
15 Apr 08 |
nicklas |
1046 |
<para> |
4223 |
15 Apr 08 |
nicklas |
1047 |
Place classes needed by JSP files in a separate JAR file that |
4223 |
15 Apr 08 |
nicklas |
1048 |
is installed into the <filename>WEB-INF/lib</filename> folder. |
4223 |
15 Apr 08 |
nicklas |
1049 |
The drawback is that this requires a restart of Tomcat. |
4223 |
15 Apr 08 |
nicklas |
1050 |
</para> |
4223 |
15 Apr 08 |
nicklas |
1051 |
</listitem> |
4223 |
15 Apr 08 |
nicklas |
1052 |
|
4223 |
15 Apr 08 |
nicklas |
1053 |
<listitem> |
4223 |
15 Apr 08 |
nicklas |
1054 |
<para> |
4223 |
15 Apr 08 |
nicklas |
1055 |
Use an X-JSP file instead. This is an experimental feature. See |
4223 |
15 Apr 08 |
nicklas |
1056 |
<xref linkend="extensions_developer.resources.xjsp" /> for more |
4223 |
15 Apr 08 |
nicklas |
1057 |
information. |
4223 |
15 Apr 08 |
nicklas |
1058 |
</para> |
4223 |
15 Apr 08 |
nicklas |
1059 |
</listitem> |
4223 |
15 Apr 08 |
nicklas |
1060 |
</itemizedlist> |
4221 |
14 Apr 08 |
nicklas |
1061 |
</note> |
4221 |
14 Apr 08 |
nicklas |
1062 |
|
4206 |
04 Apr 08 |
nicklas |
1063 |
<sect2 id="extensions_developer.resources.scripts"> |
4184 |
20 Mar 08 |
nicklas |
1064 |
<title>Javascript and stylesheets</title> |
4184 |
20 Mar 08 |
nicklas |
1065 |
|
4184 |
20 Mar 08 |
nicklas |
1066 |
<para> |
4184 |
20 Mar 08 |
nicklas |
1067 |
It is possible for an extension to use a custom javascript or stylesheet. |
4184 |
20 Mar 08 |
nicklas |
1068 |
However, this doesn't happen automatically and may not be enabled |
4184 |
20 Mar 08 |
nicklas |
1069 |
for all extension points. If an extension needs this functionality |
4184 |
20 Mar 08 |
nicklas |
1070 |
the action factory or renderer factory must call |
4184 |
20 Mar 08 |
nicklas |
1071 |
<methodname>JspContext.addScript()</methodname> or |
4184 |
20 Mar 08 |
nicklas |
1072 |
<methodname>JspContext.addStylesheet()</methodname> from the |
4184 |
20 Mar 08 |
nicklas |
1073 |
<methodname>prepareContext()</methodname> method. |
4184 |
20 Mar 08 |
nicklas |
1074 |
</para> |
4184 |
20 Mar 08 |
nicklas |
1075 |
|
4184 |
20 Mar 08 |
nicklas |
1076 |
<para> |
4184 |
20 Mar 08 |
nicklas |
1077 |
The <classname |
4184 |
20 Mar 08 |
nicklas |
1078 |
docapi="net.sf.basedb.clients.web.extensions">AbstractJspActionFactory</classname> |
4184 |
20 Mar 08 |
nicklas |
1079 |
and <classname |
4184 |
20 Mar 08 |
nicklas |
1080 |
docapi="net.sf.basedb.clients.web.extensions">AbstractJspRendererFactory</classname> |
4184 |
20 Mar 08 |
nicklas |
1081 |
factory can do this. All factories shipped with BASE extends one of those |
4184 |
20 Mar 08 |
nicklas |
1082 |
classes and we recommend that custom-made factories also does this. |
4184 |
20 Mar 08 |
nicklas |
1083 |
</para> |
4184 |
20 Mar 08 |
nicklas |
1084 |
|
4184 |
20 Mar 08 |
nicklas |
1085 |
<para> |
4184 |
20 Mar 08 |
nicklas |
1086 |
Factories that are extending one of those two classes can use |
4184 |
20 Mar 08 |
nicklas |
1087 |
<sgmltag class="starttag">script</sgmltag> and |
4184 |
20 Mar 08 |
nicklas |
1088 |
<sgmltag class="starttag">stylesheet</sgmltag> tags in the |
4184 |
20 Mar 08 |
nicklas |
1089 |
<sgmltag class="starttag">parameters</sgmltag> section for an |
4184 |
20 Mar 08 |
nicklas |
1090 |
extensions. Each tag may be used more than one time. The |
4184 |
20 Mar 08 |
nicklas |
1091 |
values are subject to path and variable substitution. |
4184 |
20 Mar 08 |
nicklas |
1092 |
</para> |
4184 |
20 Mar 08 |
nicklas |
1093 |
|
4184 |
20 Mar 08 |
nicklas |
1094 |
<programlisting language="xml"> |
4184 |
20 Mar 08 |
nicklas |
1095 |
<![CDATA[ |
4184 |
20 Mar 08 |
nicklas |
1096 |
<action-factory> |
4184 |
20 Mar 08 |
nicklas |
1097 |
<factory-class> |
4184 |
20 Mar 08 |
nicklas |
1098 |
... some factory class ... |
4184 |
20 Mar 08 |
nicklas |
1099 |
</factory-class> |
4184 |
20 Mar 08 |
nicklas |
1100 |
<parameters> |
4184 |
20 Mar 08 |
nicklas |
1101 |
<script>~/scripts/custom.js</script> |
4184 |
20 Mar 08 |
nicklas |
1102 |
<stylesheet>~/css/custom.css</stylesheet> |
4184 |
20 Mar 08 |
nicklas |
1103 |
... other parameters ... |
4184 |
20 Mar 08 |
nicklas |
1104 |
</parameters> |
4184 |
20 Mar 08 |
nicklas |
1105 |
</action-factory> |
4184 |
20 Mar 08 |
nicklas |
1106 |
]]> |
4184 |
20 Mar 08 |
nicklas |
1107 |
</programlisting> |
4184 |
20 Mar 08 |
nicklas |
1108 |
|
4184 |
20 Mar 08 |
nicklas |
1109 |
<para> |
4184 |
20 Mar 08 |
nicklas |
1110 |
If scripts and stylesheets has been added to the JSP context |
4184 |
20 Mar 08 |
nicklas |
1111 |
the extension system will, <emphasis>in most cases</emphasis>, |
4184 |
20 Mar 08 |
nicklas |
1112 |
include the proper HTML to link in the requested scripts and/or |
4184 |
20 Mar 08 |
nicklas |
1113 |
stylesheet. |
4184 |
20 Mar 08 |
nicklas |
1114 |
</para> |
4184 |
20 Mar 08 |
nicklas |
1115 |
|
4184 |
20 Mar 08 |
nicklas |
1116 |
<note> |
5426 |
24 Sep 10 |
nicklas |
1117 |
<title>Use UTF-8 character encoding</title> |
5426 |
24 Sep 10 |
nicklas |
1118 |
<para> |
5426 |
24 Sep 10 |
nicklas |
1119 |
The script and stylesheet files should use use UTF-8 character encoding. |
5426 |
24 Sep 10 |
nicklas |
1120 |
Otherwise they may not work as expected in BASE. |
5426 |
24 Sep 10 |
nicklas |
1121 |
</para> |
5426 |
24 Sep 10 |
nicklas |
1122 |
</note> |
5426 |
24 Sep 10 |
nicklas |
1123 |
|
5426 |
24 Sep 10 |
nicklas |
1124 |
<note> |
4184 |
20 Mar 08 |
nicklas |
1125 |
<title>All extension points doesn't support custom scripts/stylesheets</title> |
4184 |
20 Mar 08 |
nicklas |
1126 |
<para> |
4184 |
20 Mar 08 |
nicklas |
1127 |
In some cases the rendering of the HTML page has gone to far |
4184 |
20 Mar 08 |
nicklas |
1128 |
to make is possible to include custom scripts and stylesheets. |
4184 |
20 Mar 08 |
nicklas |
1129 |
This is for example the case with the extensions menu. Always |
4184 |
20 Mar 08 |
nicklas |
1130 |
check the documentation for the extension point if scripts |
4184 |
20 Mar 08 |
nicklas |
1131 |
and stylesheets are supported or not. |
4184 |
20 Mar 08 |
nicklas |
1132 |
</para> |
4184 |
20 Mar 08 |
nicklas |
1133 |
</note> |
4184 |
20 Mar 08 |
nicklas |
1134 |
</sect2> |
4223 |
15 Apr 08 |
nicklas |
1135 |
|
4223 |
15 Apr 08 |
nicklas |
1136 |
<sect2 id="extensions_developer.resources.xjsp"> |
4223 |
15 Apr 08 |
nicklas |
1137 |
<title>X-JSP files</title> |
4223 |
15 Apr 08 |
nicklas |
1138 |
|
4223 |
15 Apr 08 |
nicklas |
1139 |
<para> |
4223 |
15 Apr 08 |
nicklas |
1140 |
The drawback with a custom JSP file is that it is not possible to |
4223 |
15 Apr 08 |
nicklas |
1141 |
use classes from the extension's JAR file in the JSP code. The reason |
4223 |
15 Apr 08 |
nicklas |
1142 |
is that the JAR file is not known to Tomcat and Tomcat will not look |
5640 |
24 May 11 |
nicklas |
1143 |
in the <filename>plugins.dir</filename> folder to try to find |
4223 |
15 Apr 08 |
nicklas |
1144 |
classes. |
4223 |
15 Apr 08 |
nicklas |
1145 |
</para> |
4223 |
15 Apr 08 |
nicklas |
1146 |
|
4223 |
15 Apr 08 |
nicklas |
1147 |
<para> |
4223 |
15 Apr 08 |
nicklas |
1148 |
One workaround is to place classes that are needed by the JSP files |
4223 |
15 Apr 08 |
nicklas |
1149 |
in a separate JAR file that is placed in <filename>WEB-INF/lib</filename>. |
4223 |
15 Apr 08 |
nicklas |
1150 |
The drawback with this is that it requires a restart of Tomcat. It is |
4223 |
15 Apr 08 |
nicklas |
1151 |
also a second step that has to be performed manually by the person |
4223 |
15 Apr 08 |
nicklas |
1152 |
installing the extension and is maybe forgotten when doing an update. |
4223 |
15 Apr 08 |
nicklas |
1153 |
</para> |
4223 |
15 Apr 08 |
nicklas |
1154 |
|
4223 |
15 Apr 08 |
nicklas |
1155 |
<para> |
4223 |
15 Apr 08 |
nicklas |
1156 |
Another workaround is to use an X-JSP file. This is simply a regular |
4223 |
15 Apr 08 |
nicklas |
1157 |
JSP file that has a <code>.xjsp</code> extension instead of <code>.jsp</code>. |
4223 |
15 Apr 08 |
nicklas |
1158 |
The <code>.xjsp</code> extension will trigger the use of a different |
4223 |
15 Apr 08 |
nicklas |
1159 |
compiler that knows how to include the extension's JAR file in the class |
4223 |
15 Apr 08 |
nicklas |
1160 |
path. |
4223 |
15 Apr 08 |
nicklas |
1161 |
</para> |
4223 |
15 Apr 08 |
nicklas |
1162 |
|
4223 |
15 Apr 08 |
nicklas |
1163 |
<note> |
4223 |
15 Apr 08 |
nicklas |
1164 |
<title>X-JSP is experimental</title> |
4223 |
15 Apr 08 |
nicklas |
1165 |
<para> |
4223 |
15 Apr 08 |
nicklas |
1166 |
The X-JSP compiler depends on functionality that is internal to |
4223 |
15 Apr 08 |
nicklas |
1167 |
Tomcat. The JSP compiler is not part of any open specification |
4223 |
15 Apr 08 |
nicklas |
1168 |
and the implementation details may change at any time. This means |
4223 |
15 Apr 08 |
nicklas |
1169 |
that the X-JSP compiler may or may not work with future versions |
6864 |
15 Apr 15 |
nicklas |
1170 |
of Tomcat. We have currently tested it with Tomcat 8.0.21 only. |
4223 |
15 Apr 08 |
nicklas |
1171 |
It will most likely not work with other servlet containers. |
4223 |
15 Apr 08 |
nicklas |
1172 |
</para> |
4223 |
15 Apr 08 |
nicklas |
1173 |
|
4223 |
15 Apr 08 |
nicklas |
1174 |
<para> |
4223 |
15 Apr 08 |
nicklas |
1175 |
Adding support for X-JSP requires that a JAR file with the |
4223 |
15 Apr 08 |
nicklas |
1176 |
X-JSP compiler is installed into Tomcat's internal <filename>/lib</filename> |
4223 |
15 Apr 08 |
nicklas |
1177 |
directory. It is an optional step and not all BASE installations |
5737 |
14 Sep 11 |
nicklas |
1178 |
may have the compiler installed. See <xref linkend="plugins.installation.xjspcompiler" />. |
4223 |
15 Apr 08 |
nicklas |
1179 |
</para> |
4223 |
15 Apr 08 |
nicklas |
1180 |
</note> |
4223 |
15 Apr 08 |
nicklas |
1181 |
|
4223 |
15 Apr 08 |
nicklas |
1182 |
</sect2> |
4184 |
20 Mar 08 |
nicklas |
1183 |
</sect1> |
4184 |
20 Mar 08 |
nicklas |
1184 |
|
4206 |
04 Apr 08 |
nicklas |
1185 |
<sect1 id="extensions_developer.renderer"> |
5782 |
04 Oct 11 |
nicklas |
1186 |
<?dbhtml filename="renderer.html" ?> |
4184 |
20 Mar 08 |
nicklas |
1187 |
<title>Custom renderers and renderer factories</title> |
4184 |
20 Mar 08 |
nicklas |
1188 |
|
4184 |
20 Mar 08 |
nicklas |
1189 |
<para> |
4206 |
04 Apr 08 |
nicklas |
1190 |
It is always the responsibility of the extension point to |
4206 |
04 Apr 08 |
nicklas |
1191 |
render an action. The need for custom renderers is typically |
4206 |
04 Apr 08 |
nicklas |
1192 |
very small, at least if you want your extensions to blend into |
4206 |
04 Apr 08 |
nicklas |
1193 |
the look and feel of the BASE web client. Most customizations can |
4206 |
04 Apr 08 |
nicklas |
1194 |
be probably be handled by stylesheets and images. That said, |
4206 |
04 Apr 08 |
nicklas |
1195 |
you may still have a reason for using a custom renderer. |
4184 |
20 Mar 08 |
nicklas |
1196 |
</para> |
4206 |
04 Apr 08 |
nicklas |
1197 |
|
4206 |
04 Apr 08 |
nicklas |
1198 |
<para> |
4206 |
04 Apr 08 |
nicklas |
1199 |
Renderer factories are not very different from action factories. |
4206 |
04 Apr 08 |
nicklas |
1200 |
They are specified in the same way in the XML file and uses the |
4206 |
04 Apr 08 |
nicklas |
1201 |
same method for initialisation, including support for path |
4206 |
04 Apr 08 |
nicklas |
1202 |
conversion, etc. The difference is that you use a |
4206 |
04 Apr 08 |
nicklas |
1203 |
<sgmltag class="starttag">renderer-factory</sgmltag> tag |
4206 |
04 Apr 08 |
nicklas |
1204 |
instead of an <sgmltag class="starttag">action-factory</sgmltag> |
4206 |
04 Apr 08 |
nicklas |
1205 |
tag. |
4206 |
04 Apr 08 |
nicklas |
1206 |
</para> |
4184 |
20 Mar 08 |
nicklas |
1207 |
|
4206 |
04 Apr 08 |
nicklas |
1208 |
<programlisting language="xml"> |
4206 |
04 Apr 08 |
nicklas |
1209 |
<![CDATA[ |
4206 |
04 Apr 08 |
nicklas |
1210 |
<renderer-factory> |
4206 |
04 Apr 08 |
nicklas |
1211 |
<factory-class> |
4206 |
04 Apr 08 |
nicklas |
1212 |
... some factory class ... |
4206 |
04 Apr 08 |
nicklas |
1213 |
</factory-class> |
4206 |
04 Apr 08 |
nicklas |
1214 |
<parameters> |
4206 |
04 Apr 08 |
nicklas |
1215 |
... some parameters ... |
4206 |
04 Apr 08 |
nicklas |
1216 |
</parameters> |
4206 |
04 Apr 08 |
nicklas |
1217 |
</renderer-factory> |
4206 |
04 Apr 08 |
nicklas |
1218 |
]]> |
4206 |
04 Apr 08 |
nicklas |
1219 |
</programlisting> |
4206 |
04 Apr 08 |
nicklas |
1220 |
|
4206 |
04 Apr 08 |
nicklas |
1221 |
<para> |
4206 |
04 Apr 08 |
nicklas |
1222 |
A <interfacename docapi="net.sf.basedb.util.extensions" |
4206 |
04 Apr 08 |
nicklas |
1223 |
>RendererFactory</interfacename> also has a <methodname>prepareContext()</methodname> |
4206 |
04 Apr 08 |
nicklas |
1224 |
method that can be used to tell the web client about any scripts or stylesheets |
4206 |
04 Apr 08 |
nicklas |
1225 |
the extension needs. If your renderer factory extends the <classname |
4206 |
04 Apr 08 |
nicklas |
1226 |
docapi="net.sf.basedb.clients.web.extensions">AbstractJspRendererFactory</classname> |
4206 |
04 Apr 08 |
nicklas |
1227 |
class you will not have to worry about this since you can configure |
4206 |
04 Apr 08 |
nicklas |
1228 |
scripts and stylesheets in the XML file. |
4206 |
04 Apr 08 |
nicklas |
1229 |
</para> |
4206 |
04 Apr 08 |
nicklas |
1230 |
|
4206 |
04 Apr 08 |
nicklas |
1231 |
<para> |
4206 |
04 Apr 08 |
nicklas |
1232 |
A render factory must also implement the <methodname>getRenderer()</methodname> |
4206 |
04 Apr 08 |
nicklas |
1233 |
which should return a <interfacename docapi="net.sf.basedb.util.extensions" |
4206 |
04 Apr 08 |
nicklas |
1234 |
>Renderer</interfacename> instance. The extension system will then call |
4206 |
04 Apr 08 |
nicklas |
1235 |
the <methodname>Renderer.render()</methodname> method to render an action. |
4206 |
04 Apr 08 |
nicklas |
1236 |
This method may be called multiple times if the extension created more than |
4206 |
04 Apr 08 |
nicklas |
1237 |
one action. |
4206 |
04 Apr 08 |
nicklas |
1238 |
</para> |
4206 |
04 Apr 08 |
nicklas |
1239 |
|
4206 |
04 Apr 08 |
nicklas |
1240 |
<para> |
4206 |
04 Apr 08 |
nicklas |
1241 |
The renderers responsibility is to generate the HTML |
4206 |
04 Apr 08 |
nicklas |
1242 |
that is going to be sent to the web client. To do this it needs |
4206 |
04 Apr 08 |
nicklas |
1243 |
access to the <classname |
4206 |
04 Apr 08 |
nicklas |
1244 |
docapi="net.sf.basedb.clients.web.extensions">JspContext</classname> |
4206 |
04 Apr 08 |
nicklas |
1245 |
object that was passed to the renderer factory. Here is a simple |
4206 |
04 Apr 08 |
nicklas |
1246 |
outline of both a renderer factory and renderer. |
4206 |
04 Apr 08 |
nicklas |
1247 |
</para> |
4206 |
04 Apr 08 |
nicklas |
1248 |
|
4206 |
04 Apr 08 |
nicklas |
1249 |
<programlisting language="java"> |
4206 |
04 Apr 08 |
nicklas |
1250 |
<![CDATA[ |
4206 |
04 Apr 08 |
nicklas |
1251 |
// File: MyRendererFactory.java |
4206 |
04 Apr 08 |
nicklas |
1252 |
public class MyRendererFactory |
4206 |
04 Apr 08 |
nicklas |
1253 |
extends AbstractJspRendererFactory<MyAction> |
4206 |
04 Apr 08 |
nicklas |
1254 |
{ |
4206 |
04 Apr 08 |
nicklas |
1255 |
|
4206 |
04 Apr 08 |
nicklas |
1256 |
public MyRendererFactory() |
4206 |
04 Apr 08 |
nicklas |
1257 |
{} |
4206 |
04 Apr 08 |
nicklas |
1258 |
|
4206 |
04 Apr 08 |
nicklas |
1259 |
@Override |
4208 |
07 Apr 08 |
nicklas |
1260 |
public MyRenderer getRenderer(InvokationContext context) |
4206 |
04 Apr 08 |
nicklas |
1261 |
{ |
4208 |
07 Apr 08 |
nicklas |
1262 |
return new MyRenderer((JspContext)context.getClientContext()); |
4206 |
04 Apr 08 |
nicklas |
1263 |
} |
4206 |
04 Apr 08 |
nicklas |
1264 |
} |
4206 |
04 Apr 08 |
nicklas |
1265 |
|
4206 |
04 Apr 08 |
nicklas |
1266 |
// File: MyRenderer.java |
4206 |
04 Apr 08 |
nicklas |
1267 |
public class MyRenderer |
4206 |
04 Apr 08 |
nicklas |
1268 |
implements Renderer<MyAction> |
4206 |
04 Apr 08 |
nicklas |
1269 |
{ |
4206 |
04 Apr 08 |
nicklas |
1270 |
|
4206 |
04 Apr 08 |
nicklas |
1271 |
private final JspContext context; |
4206 |
04 Apr 08 |
nicklas |
1272 |
public MyRenderer(JspContext context) |
4206 |
04 Apr 08 |
nicklas |
1273 |
{ |
4206 |
04 Apr 08 |
nicklas |
1274 |
this.context = context; |
4206 |
04 Apr 08 |
nicklas |
1275 |
} |
4206 |
04 Apr 08 |
nicklas |
1276 |
|
4206 |
04 Apr 08 |
nicklas |
1277 |
/** |
4206 |
04 Apr 08 |
nicklas |
1278 |
Generates HTML (unless invisible): |
6403 |
29 Jan 14 |
nicklas |
1279 |
<a class="[clazz]" style="[style]" href="[href]">[title]</a> |
4206 |
04 Apr 08 |
nicklas |
1280 |
*/ |
4206 |
04 Apr 08 |
nicklas |
1281 |
public void render(MyAction action) |
4206 |
04 Apr 08 |
nicklas |
1282 |
{ |
4206 |
04 Apr 08 |
nicklas |
1283 |
if (!action.isVisible()) return; |
4206 |
04 Apr 08 |
nicklas |
1284 |
Writer out = context.getOut(); |
4206 |
04 Apr 08 |
nicklas |
1285 |
try |
4206 |
04 Apr 08 |
nicklas |
1286 |
{ |
4206 |
04 Apr 08 |
nicklas |
1287 |
out.write("<a"); |
4206 |
04 Apr 08 |
nicklas |
1288 |
if (action.getClazz() != null) |
4206 |
04 Apr 08 |
nicklas |
1289 |
{ |
4206 |
04 Apr 08 |
nicklas |
1290 |
out.write(" class=\"" + action.getClazz() + "\""); |
4206 |
04 Apr 08 |
nicklas |
1291 |
} |
4206 |
04 Apr 08 |
nicklas |
1292 |
if (action.getStyle() != null) |
4206 |
04 Apr 08 |
nicklas |
1293 |
{ |
4206 |
04 Apr 08 |
nicklas |
1294 |
out.write(" style=\"" + action.getStyle() + "\""); |
4206 |
04 Apr 08 |
nicklas |
1295 |
} |
6403 |
29 Jan 14 |
nicklas |
1296 |
if (action.getHref() != null) |
4206 |
04 Apr 08 |
nicklas |
1297 |
{ |
6403 |
29 Jan 14 |
nicklas |
1298 |
out.write(" href=\"" + action.getHref() + "\""); |
4206 |
04 Apr 08 |
nicklas |
1299 |
} |
4206 |
04 Apr 08 |
nicklas |
1300 |
out.write(">"); |
4206 |
04 Apr 08 |
nicklas |
1301 |
out.write(HTML.encodeTags(action.getTitle())); |
4206 |
04 Apr 08 |
nicklas |
1302 |
out.write("</a>\n"); |
4206 |
04 Apr 08 |
nicklas |
1303 |
} |
4206 |
04 Apr 08 |
nicklas |
1304 |
catch (IOException ex) |
4206 |
04 Apr 08 |
nicklas |
1305 |
{ |
4206 |
04 Apr 08 |
nicklas |
1306 |
throw new RuntimeException(ex); |
4206 |
04 Apr 08 |
nicklas |
1307 |
} |
4206 |
04 Apr 08 |
nicklas |
1308 |
} |
4206 |
04 Apr 08 |
nicklas |
1309 |
} |
4206 |
04 Apr 08 |
nicklas |
1310 |
]]> |
4206 |
04 Apr 08 |
nicklas |
1311 |
</programlisting> |
4184 |
20 Mar 08 |
nicklas |
1312 |
</sect1> |
4206 |
04 Apr 08 |
nicklas |
1313 |
|
4206 |
04 Apr 08 |
nicklas |
1314 |
<sect1 id="extensions_developer.extension_points"> |
5782 |
04 Oct 11 |
nicklas |
1315 |
<?dbhtml filename="extensionpoints.html" ?> |
4206 |
04 Apr 08 |
nicklas |
1316 |
<title>Extension points</title> |
4206 |
04 Apr 08 |
nicklas |
1317 |
|
4206 |
04 Apr 08 |
nicklas |
1318 |
<para> |
4206 |
04 Apr 08 |
nicklas |
1319 |
The BASE web client ships with a number of predefined extension |
4206 |
04 Apr 08 |
nicklas |
1320 |
points. Adding more extension points to the existing web client |
4223 |
15 Apr 08 |
nicklas |
1321 |
requires some minor modifications to the regular JSP files. But this |
4206 |
04 Apr 08 |
nicklas |
1322 |
is not what this chapter is about. This chapter is about defining new |
4206 |
04 Apr 08 |
nicklas |
1323 |
extension points as part of an extension. It is nothing magical about |
4206 |
04 Apr 08 |
nicklas |
1324 |
this and the process is the same as for the regular extension points in |
4206 |
04 Apr 08 |
nicklas |
1325 |
the web client. |
4206 |
04 Apr 08 |
nicklas |
1326 |
</para> |
4206 |
04 Apr 08 |
nicklas |
1327 |
|
4206 |
04 Apr 08 |
nicklas |
1328 |
<para> |
4206 |
04 Apr 08 |
nicklas |
1329 |
The first thing you need to do is to start writing the |
4206 |
04 Apr 08 |
nicklas |
1330 |
XML definition of the extension point. Here is an example |
4206 |
04 Apr 08 |
nicklas |
1331 |
from the web client: |
4206 |
04 Apr 08 |
nicklas |
1332 |
</para> |
4206 |
04 Apr 08 |
nicklas |
1333 |
|
5816 |
20 Oct 11 |
nicklas |
1334 |
<programlisting language="xml"> |
4206 |
04 Apr 08 |
nicklas |
1335 |
<![CDATA[ |
4206 |
04 Apr 08 |
nicklas |
1336 |
<extensions |
4206 |
04 Apr 08 |
nicklas |
1337 |
xmlns="http://base.thep.lu.se/extensions.xsd" |
4206 |
04 Apr 08 |
nicklas |
1338 |
> |
4206 |
04 Apr 08 |
nicklas |
1339 |
<extension-point |
4206 |
04 Apr 08 |
nicklas |
1340 |
id="net.sf.basedb.clients.web.menu.extensions" |
4206 |
04 Apr 08 |
nicklas |
1341 |
> |
4206 |
04 Apr 08 |
nicklas |
1342 |
<action-class>net.sf.basedb.clients.web.extensions.menu.MenuItemAction</action-class> |
4206 |
04 Apr 08 |
nicklas |
1343 |
<name>Menu: extensions</name> |
4206 |
04 Apr 08 |
nicklas |
1344 |
<description> |
4206 |
04 Apr 08 |
nicklas |
1345 |
Extension point for adding extensions to the 'Extensions' menu. |
4206 |
04 Apr 08 |
nicklas |
1346 |
Extensions should provide MenuItemAction instances. The rendering |
4206 |
04 Apr 08 |
nicklas |
1347 |
is internal and extensions can't use their own rendering factories. |
4206 |
04 Apr 08 |
nicklas |
1348 |
The context will only include information about the currently logged |
4206 |
04 Apr 08 |
nicklas |
1349 |
in user, not information about the current page that is displayed. |
4206 |
04 Apr 08 |
nicklas |
1350 |
The reason for this is that the rendered menu is cached as a string |
4206 |
04 Apr 08 |
nicklas |
1351 |
in the user session. The menu is not updated on every page request. |
6403 |
29 Jan 14 |
nicklas |
1352 |
As of BASE 3.3, this extension point also support custom scripts and |
6403 |
29 Jan 14 |
nicklas |
1353 |
stylesheets. |
4206 |
04 Apr 08 |
nicklas |
1354 |
</description> |
4206 |
04 Apr 08 |
nicklas |
1355 |
</extension-point> |
4206 |
04 Apr 08 |
nicklas |
1356 |
</extensions> |
4206 |
04 Apr 08 |
nicklas |
1357 |
]]> |
4206 |
04 Apr 08 |
nicklas |
1358 |
</programlisting> |
4206 |
04 Apr 08 |
nicklas |
1359 |
|
4206 |
04 Apr 08 |
nicklas |
1360 |
<para> |
4206 |
04 Apr 08 |
nicklas |
1361 |
The <sgmltag class="starttag">extensions</sgmltag> tag is the root tag and |
4206 |
04 Apr 08 |
nicklas |
1362 |
is needed to set up the namespace and schema validation. |
4206 |
04 Apr 08 |
nicklas |
1363 |
</para> |
4206 |
04 Apr 08 |
nicklas |
1364 |
|
4206 |
04 Apr 08 |
nicklas |
1365 |
<para> |
4206 |
04 Apr 08 |
nicklas |
1366 |
The <sgmltag class="starttag">extension-point</sgmltag> defines a new |
4206 |
04 Apr 08 |
nicklas |
1367 |
extension point. It must have an <sgmltag>id</sgmltag> attribute that |
4206 |
04 Apr 08 |
nicklas |
1368 |
is unique among all installed extension points. We recommend using |
4206 |
04 Apr 08 |
nicklas |
1369 |
the same naming conventions as for java packages. See <ulink |
5640 |
24 May 11 |
nicklas |
1370 |
url="http://www.oracle.com/technetwork/java/codeconventions-135099.html">Java naming |
5640 |
24 May 11 |
nicklas |
1371 |
conventions from Oracle</ulink>. |
4206 |
04 Apr 08 |
nicklas |
1372 |
</para> |
4206 |
04 Apr 08 |
nicklas |
1373 |
|
4206 |
04 Apr 08 |
nicklas |
1374 |
<note> |
4206 |
04 Apr 08 |
nicklas |
1375 |
<title>Document the extension point!</title> |
4206 |
04 Apr 08 |
nicklas |
1376 |
<para> |
4206 |
04 Apr 08 |
nicklas |
1377 |
The <sgmltag class="starttag">name</sgmltag> and |
4208 |
07 Apr 08 |
nicklas |
1378 |
<sgmltag class="starttag">description</sgmltag> tags are optional, |
4208 |
07 Apr 08 |
nicklas |
1379 |
but we strongly recommend that values are provided. |
4208 |
07 Apr 08 |
nicklas |
1380 |
The description tag should be used to document the extension |
4206 |
04 Apr 08 |
nicklas |
1381 |
point. Pay special attention to the support (or lack of |
4206 |
04 Apr 08 |
nicklas |
1382 |
support) for custom scripts, stylesheets and renderers. |
4206 |
04 Apr 08 |
nicklas |
1383 |
</para> |
4206 |
04 Apr 08 |
nicklas |
1384 |
</note> |
4206 |
04 Apr 08 |
nicklas |
1385 |
|
4206 |
04 Apr 08 |
nicklas |
1386 |
<para> |
4206 |
04 Apr 08 |
nicklas |
1387 |
The <sgmltag class="starttag">action-class</sgmltag> defines the |
4206 |
04 Apr 08 |
nicklas |
1388 |
interface or class that extensions must provide to the extension |
4206 |
04 Apr 08 |
nicklas |
1389 |
point. This must be a class or interface that is a subclass |
4206 |
04 Apr 08 |
nicklas |
1390 |
of the <interfacename |
4206 |
04 Apr 08 |
nicklas |
1391 |
docapi="net.sf.basedb.util.extensions">Action</interfacename> |
4206 |
04 Apr 08 |
nicklas |
1392 |
interface. We generally recommend that interfaces are used since |
4206 |
04 Apr 08 |
nicklas |
1393 |
this gives more implementation flexibility for action factories, but |
4206 |
04 Apr 08 |
nicklas |
1394 |
a regular class may work just as well. |
4206 |
04 Apr 08 |
nicklas |
1395 |
</para> |
4206 |
04 Apr 08 |
nicklas |
1396 |
|
4206 |
04 Apr 08 |
nicklas |
1397 |
<para> |
4206 |
04 Apr 08 |
nicklas |
1398 |
The action class is used to carry information about the action, |
6403 |
29 Jan 14 |
nicklas |
1399 |
such as a title, which icon to use, a tooltip text, etc. The action class may |
4206 |
04 Apr 08 |
nicklas |
1400 |
be as simple or complex as you like. |
4206 |
04 Apr 08 |
nicklas |
1401 |
</para> |
4206 |
04 Apr 08 |
nicklas |
1402 |
|
4206 |
04 Apr 08 |
nicklas |
1403 |
<note> |
4206 |
04 Apr 08 |
nicklas |
1404 |
<title>Web client extension points</title> |
4206 |
04 Apr 08 |
nicklas |
1405 |
<para> |
4206 |
04 Apr 08 |
nicklas |
1406 |
This is a note for the core developers. Extension points that |
4206 |
04 Apr 08 |
nicklas |
1407 |
are part of the web client should always define the action as |
4206 |
04 Apr 08 |
nicklas |
1408 |
an interface. We recommend that <code>getId()</code>, <code>getClazz()</code> |
4206 |
04 Apr 08 |
nicklas |
1409 |
and <code>getStyle()</code> attributes are always included if this makes |
4206 |
04 Apr 08 |
nicklas |
1410 |
sense. It is usually also a good idea to include <code>isVisible()</code> |
4206 |
04 Apr 08 |
nicklas |
1411 |
and <code>isEnabled()</code> attributes. |
4206 |
04 Apr 08 |
nicklas |
1412 |
</para> |
4206 |
04 Apr 08 |
nicklas |
1413 |
</note> |
4206 |
04 Apr 08 |
nicklas |
1414 |
|
4206 |
04 Apr 08 |
nicklas |
1415 |
<para> |
4206 |
04 Apr 08 |
nicklas |
1416 |
Now, if you are a good citizen you should also provide at least |
4206 |
04 Apr 08 |
nicklas |
1417 |
one implementation of an action factory that can create the |
4206 |
04 Apr 08 |
nicklas |
1418 |
objects of the desired type of action. The factory should |
4206 |
04 Apr 08 |
nicklas |
1419 |
of course be configurable from the XML file. |
4206 |
04 Apr 08 |
nicklas |
1420 |
</para> |
4206 |
04 Apr 08 |
nicklas |
1421 |
|
4206 |
04 Apr 08 |
nicklas |
1422 |
<para> |
4206 |
04 Apr 08 |
nicklas |
1423 |
If you are lazy or if you want to immediately start testing the JSP code |
4206 |
04 Apr 08 |
nicklas |
1424 |
for the extension point, it may be possible to use one of the debugger action |
4206 |
04 Apr 08 |
nicklas |
1425 |
factories in the <package>net.sf.basedb.util.extensions.debug</package> |
4206 |
04 Apr 08 |
nicklas |
1426 |
pacakge. |
4206 |
04 Apr 08 |
nicklas |
1427 |
</para> |
4206 |
04 Apr 08 |
nicklas |
1428 |
|
4206 |
04 Apr 08 |
nicklas |
1429 |
<itemizedlist> |
4206 |
04 Apr 08 |
nicklas |
1430 |
<listitem> |
4206 |
04 Apr 08 |
nicklas |
1431 |
<para> |
4206 |
04 Apr 08 |
nicklas |
1432 |
<classname |
4206 |
04 Apr 08 |
nicklas |
1433 |
docapi="net.sf.basedb.util.extensions.debug">ProxyActionFactory</classname>: |
4206 |
04 Apr 08 |
nicklas |
1434 |
This action factory can only be used if your action class is an interface |
4206 |
04 Apr 08 |
nicklas |
1435 |
and all important methods starts with <code>get</code> or <code>is</code>. |
4208 |
07 Apr 08 |
nicklas |
1436 |
The proxy action factory uses Java reflection to create a dynamic |
4208 |
07 Apr 08 |
nicklas |
1437 |
proxy class in runtime. It will map all <code>getX()</code> and <code>isY()</code> |
4206 |
04 Apr 08 |
nicklas |
1438 |
methods to retreive the values from the corresponding parameter in the XML file. |
4206 |
04 Apr 08 |
nicklas |
1439 |
For example, <methodname>getIcon()</methodname> will retrieve the value |
4206 |
04 Apr 08 |
nicklas |
1440 |
of the <sgmltag class="starttag">icon</sgmltag> tag and |
4206 |
04 Apr 08 |
nicklas |
1441 |
<methodname>isVisible()</methodname> from the <sgmltag |
4206 |
04 Apr 08 |
nicklas |
1442 |
class="starttag">visible</sgmltag>. The factory is smart enough to convert |
4206 |
04 Apr 08 |
nicklas |
1443 |
the string to the correct return value for <type>int</type>, <type>long</type>, |
4206 |
04 Apr 08 |
nicklas |
1444 |
<type>float</type>, <type>double</type> and <type>boolean</type> data types and |
4208 |
07 Apr 08 |
nicklas |
1445 |
their corresponding object wrapper types, if this is needed. |
4206 |
04 Apr 08 |
nicklas |
1446 |
</para> |
4206 |
04 Apr 08 |
nicklas |
1447 |
</listitem> |
4206 |
04 Apr 08 |
nicklas |
1448 |
|
4206 |
04 Apr 08 |
nicklas |
1449 |
<listitem> |
4206 |
04 Apr 08 |
nicklas |
1450 |
<para> |
4206 |
04 Apr 08 |
nicklas |
1451 |
<classname |
4206 |
04 Apr 08 |
nicklas |
1452 |
docapi="net.sf.basedb.util.extensions.debug">BeanActionFactory</classname>: |
4206 |
04 Apr 08 |
nicklas |
1453 |
This action factory can be used if you have created a bean-like |
4206 |
04 Apr 08 |
nicklas |
1454 |
class that implements the desired action class. The factory will |
4206 |
04 Apr 08 |
nicklas |
1455 |
create an instance of the class specified by the |
4206 |
04 Apr 08 |
nicklas |
1456 |
<sgmltag class="starttag">beanClass</sgmltag> parameter. The factory |
4206 |
04 Apr 08 |
nicklas |
1457 |
will then use Java reflection to find <code>set</code> method |
4206 |
04 Apr 08 |
nicklas |
1458 |
for the other parameters. If there is a parameter <sgmltag class="starttag">icon</sgmltag> |
4206 |
04 Apr 08 |
nicklas |
1459 |
the factory first looks for a <methodname>setIcon(String)</methodname> |
4206 |
04 Apr 08 |
nicklas |
1460 |
method. If it can't find that it will see if there is a <methodname>getIcon()</methodname> |
4206 |
04 Apr 08 |
nicklas |
1461 |
method which has a return type, T. If so, a second attempt is made to find |
4206 |
04 Apr 08 |
nicklas |
1462 |
a <methodname>setIcon(T)</methodname> method. The factory is smart enough |
4206 |
04 Apr 08 |
nicklas |
1463 |
to convert the string value from the XML file to the correct return value |
4206 |
04 Apr 08 |
nicklas |
1464 |
for <type>int</type>, <type>long</type>, <type>float</type>, |
4206 |
04 Apr 08 |
nicklas |
1465 |
<type>double</type> and <type>boolean</type> data types and their |
4208 |
07 Apr 08 |
nicklas |
1466 |
corresponding object wrapper types, if this is needed. |
4206 |
04 Apr 08 |
nicklas |
1467 |
</para> |
4206 |
04 Apr 08 |
nicklas |
1468 |
</listitem> |
4206 |
04 Apr 08 |
nicklas |
1469 |
|
4206 |
04 Apr 08 |
nicklas |
1470 |
</itemizedlist> |
4206 |
04 Apr 08 |
nicklas |
1471 |
|
4206 |
04 Apr 08 |
nicklas |
1472 |
|
4206 |
04 Apr 08 |
nicklas |
1473 |
<para> |
4206 |
04 Apr 08 |
nicklas |
1474 |
It is finally time to write the JSP code that actually uses the |
4206 |
04 Apr 08 |
nicklas |
1475 |
extension point. It is usually not very complicated. Here is |
4223 |
15 Apr 08 |
nicklas |
1476 |
an exemple which lists snippets from a JSP file: |
4206 |
04 Apr 08 |
nicklas |
1477 |
</para> |
4206 |
04 Apr 08 |
nicklas |
1478 |
|
4206 |
04 Apr 08 |
nicklas |
1479 |
<programlisting> |
4206 |
04 Apr 08 |
nicklas |
1480 |
<![CDATA[ |
4208 |
07 Apr 08 |
nicklas |
1481 |
// 1. We recommend using the extensions taglib (and the BASE core taglib) |
4206 |
04 Apr 08 |
nicklas |
1482 |
<%@ taglib prefix="ext" uri="/WEB-INF/extensions.tld" %> |
4206 |
04 Apr 08 |
nicklas |
1483 |
<%@ taglib prefix="base" uri="/WEB-INF/base.tld" %> |
4206 |
04 Apr 08 |
nicklas |
1484 |
|
4208 |
07 Apr 08 |
nicklas |
1485 |
// 2. Prepare the extension point |
4206 |
04 Apr 08 |
nicklas |
1486 |
SessionControl sc = Base.getExistingSessionControl(pageContext, true); |
4206 |
04 Apr 08 |
nicklas |
1487 |
JspContext jspContext = ExtensionsControl.createContext(sc, pageContext); |
4206 |
04 Apr 08 |
nicklas |
1488 |
ExtensionsInvoker invoker = ExtensionsControl.useExtensions(jspContext, |
4206 |
04 Apr 08 |
nicklas |
1489 |
"my.domain.name.extensionspoint"); |
4206 |
04 Apr 08 |
nicklas |
1490 |
|
4208 |
07 Apr 08 |
nicklas |
1491 |
// 3. Output scripts and stylesheets |
4206 |
04 Apr 08 |
nicklas |
1492 |
<base:page title="My new extension point"> |
4206 |
04 Apr 08 |
nicklas |
1493 |
<base:head> |
4206 |
04 Apr 08 |
nicklas |
1494 |
<ext:scripts context="<%=jspContext%>" /> |
4206 |
04 Apr 08 |
nicklas |
1495 |
<ext:stylesheets context="<%=jspContext%>" /> |
4206 |
04 Apr 08 |
nicklas |
1496 |
</base:head> |
4206 |
04 Apr 08 |
nicklas |
1497 |
<base:body> |
4206 |
04 Apr 08 |
nicklas |
1498 |
.... |
4206 |
04 Apr 08 |
nicklas |
1499 |
|
4208 |
07 Apr 08 |
nicklas |
1500 |
// 4a. Using a taglib for rendering with the default renderer |
4206 |
04 Apr 08 |
nicklas |
1501 |
<ext:render extensions="<%=invoker%>" context="<%=jspContext%>" /> |
4206 |
04 Apr 08 |
nicklas |
1502 |
|
4208 |
07 Apr 08 |
nicklas |
1503 |
// 4b. Or, use the iterator and a more hard-coded approach |
4206 |
04 Apr 08 |
nicklas |
1504 |
<% |
4206 |
04 Apr 08 |
nicklas |
1505 |
Iterator it = invoker.iterate(); |
4206 |
04 Apr 08 |
nicklas |
1506 |
while (it.hasNext()) |
4206 |
04 Apr 08 |
nicklas |
1507 |
{ |
4206 |
04 Apr 08 |
nicklas |
1508 |
MyAction action = (MyAction)it.next(); |
4208 |
07 Apr 08 |
nicklas |
1509 |
String html = action.getTitle() + |
4208 |
07 Apr 08 |
nicklas |
1510 |
.... |
4206 |
04 Apr 08 |
nicklas |
1511 |
out.write(html); |
4206 |
04 Apr 08 |
nicklas |
1512 |
} |
4206 |
04 Apr 08 |
nicklas |
1513 |
%> |
4206 |
04 Apr 08 |
nicklas |
1514 |
]]> |
4206 |
04 Apr 08 |
nicklas |
1515 |
</programlisting> |
4206 |
04 Apr 08 |
nicklas |
1516 |
|
5487 |
15 Nov 10 |
nicklas |
1517 |
<sect2 id="extensions_developer.error_handler"> |
5487 |
15 Nov 10 |
nicklas |
1518 |
<title>Error handlers</title> |
5487 |
15 Nov 10 |
nicklas |
1519 |
|
5487 |
15 Nov 10 |
nicklas |
1520 |
<para> |
5487 |
15 Nov 10 |
nicklas |
1521 |
An extension points may define a custom error handler. If not, the |
5487 |
15 Nov 10 |
nicklas |
1522 |
default error handler is used which simply writes a message to the |
5487 |
15 Nov 10 |
nicklas |
1523 |
log file. If you want to use a different error handler, create |
5487 |
15 Nov 10 |
nicklas |
1524 |
a <sgmltag class="starttag">error-handler-factory</sgmltag> tag |
5487 |
15 Nov 10 |
nicklas |
1525 |
inside the extension point definition. The <sgmltag |
5487 |
15 Nov 10 |
nicklas |
1526 |
class="starttag">factory-class</sgmltag> is a required subtag and |
5487 |
15 Nov 10 |
nicklas |
1527 |
must specify a class with a public no-argument constructor that |
5487 |
15 Nov 10 |
nicklas |
1528 |
implements the |
5487 |
15 Nov 10 |
nicklas |
1529 |
<interfacename docapi="net.sf.basedb.util.extensions">ErrorHandlerFactory</interfacename> |
5487 |
15 Nov 10 |
nicklas |
1530 |
interface. The <sgmltag class="starttag">parameters</sgmltag> subtag is |
5487 |
15 Nov 10 |
nicklas |
1531 |
optional and can be used to specify initialization parameters for the |
5487 |
15 Nov 10 |
nicklas |
1532 |
factory just as for action and renderer factories. |
5487 |
15 Nov 10 |
nicklas |
1533 |
</para> |
5487 |
15 Nov 10 |
nicklas |
1534 |
|
5816 |
20 Oct 11 |
nicklas |
1535 |
<programlisting language="xml"> |
5487 |
15 Nov 10 |
nicklas |
1536 |
<![CDATA[ |
5487 |
15 Nov 10 |
nicklas |
1537 |
<extensions |
5487 |
15 Nov 10 |
nicklas |
1538 |
xmlns="http://base.thep.lu.se/extensions.xsd" |
5487 |
15 Nov 10 |
nicklas |
1539 |
> |
5487 |
15 Nov 10 |
nicklas |
1540 |
<extension-point |
5487 |
15 Nov 10 |
nicklas |
1541 |
id="net.sf.basedb.clients.web.menu.extensions" |
5487 |
15 Nov 10 |
nicklas |
1542 |
> |
5487 |
15 Nov 10 |
nicklas |
1543 |
<action-class>net.sf.basedb.clients.web.extensions.menu.MenuItemAction</action-class> |
5487 |
15 Nov 10 |
nicklas |
1544 |
<name>Menu: extensions</name> |
5520 |
23 Nov 10 |
nicklas |
1545 |
<error-handler-factory> |
5520 |
23 Nov 10 |
nicklas |
1546 |
<factory-class> |
5520 |
23 Nov 10 |
nicklas |
1547 |
... some factory class ... |
5520 |
23 Nov 10 |
nicklas |
1548 |
</factory-class> |
5520 |
23 Nov 10 |
nicklas |
1549 |
<parameters> |
5520 |
23 Nov 10 |
nicklas |
1550 |
... initialization parameters ... |
5520 |
23 Nov 10 |
nicklas |
1551 |
</parameters> |
5520 |
23 Nov 10 |
nicklas |
1552 |
</error-handler-factory> |
5487 |
15 Nov 10 |
nicklas |
1553 |
</extension-point> |
5487 |
15 Nov 10 |
nicklas |
1554 |
</extensions> |
5487 |
15 Nov 10 |
nicklas |
1555 |
]]> |
5487 |
15 Nov 10 |
nicklas |
1556 |
</programlisting> |
5487 |
15 Nov 10 |
nicklas |
1557 |
</sect2> |
4206 |
04 Apr 08 |
nicklas |
1558 |
</sect1> |
4206 |
04 Apr 08 |
nicklas |
1559 |
|
4221 |
14 Apr 08 |
nicklas |
1560 |
<sect1 id="extensions_developer.servlets"> |
5782 |
04 Oct 11 |
nicklas |
1561 |
<?dbhtml filename="servlets.html" ?> |
4221 |
14 Apr 08 |
nicklas |
1562 |
<title>Custom servlets</title> |
4221 |
14 Apr 08 |
nicklas |
1563 |
<para> |
4221 |
14 Apr 08 |
nicklas |
1564 |
It is possible for an extension to include servlets without having |
4221 |
14 Apr 08 |
nicklas |
1565 |
to register those servlets in Tomcat's <filename>WEB-INF/web.xml</filename> |
4221 |
14 Apr 08 |
nicklas |
1566 |
file. The extension needs to be in a JAR file as usual. The servlet class |
4221 |
14 Apr 08 |
nicklas |
1567 |
should be located in the JAR file following regular Java conventions. |
4221 |
14 Apr 08 |
nicklas |
1568 |
Eg. The class <classname>my.domain.ServletClass</classname> should |
4221 |
14 Apr 08 |
nicklas |
1569 |
be located at <filename>my/domain/ServletClass.class</filename>. You |
4221 |
14 Apr 08 |
nicklas |
1570 |
also need to create a second XML file that contains the servlet |
4221 |
14 Apr 08 |
nicklas |
1571 |
definitions at <filename>META-INF/servlets.xml</filename>. The format for |
4221 |
14 Apr 08 |
nicklas |
1572 |
defining servlets in this file is very similar to how servlets are |
4221 |
14 Apr 08 |
nicklas |
1573 |
defined in the <filename>web.xml</filename> file. Here is an example: |
4221 |
14 Apr 08 |
nicklas |
1574 |
</para> |
4221 |
14 Apr 08 |
nicklas |
1575 |
|
4221 |
14 Apr 08 |
nicklas |
1576 |
<programlisting language="xml"> |
4221 |
14 Apr 08 |
nicklas |
1577 |
<![CDATA[ |
4221 |
14 Apr 08 |
nicklas |
1578 |
<?xml version="1.0" encoding="UTF-8" ?> |
4221 |
14 Apr 08 |
nicklas |
1579 |
<servlets xmlns="http://base.thep.lu.se/servlets.xsd"> |
4221 |
14 Apr 08 |
nicklas |
1580 |
<servlet> |
4221 |
14 Apr 08 |
nicklas |
1581 |
<servlet-name>HelloWorld</servlet-name> |
4221 |
14 Apr 08 |
nicklas |
1582 |
<servlet-class>net.sf.basedb.examples.extensions.HelloWorldServlet</servlet-class> |
4221 |
14 Apr 08 |
nicklas |
1583 |
<init-param> |
4221 |
14 Apr 08 |
nicklas |
1584 |
<param-name>template</param-name> |
4221 |
14 Apr 08 |
nicklas |
1585 |
<param-value>Hello {user}! Welcome to the Servlet world!</param-value> |
4221 |
14 Apr 08 |
nicklas |
1586 |
</init-param> |
4221 |
14 Apr 08 |
nicklas |
1587 |
</servlet> |
4221 |
14 Apr 08 |
nicklas |
1588 |
</servlets> |
4221 |
14 Apr 08 |
nicklas |
1589 |
]]> |
4221 |
14 Apr 08 |
nicklas |
1590 |
</programlisting> |
4221 |
14 Apr 08 |
nicklas |
1591 |
|
4221 |
14 Apr 08 |
nicklas |
1592 |
<para> |
4221 |
14 Apr 08 |
nicklas |
1593 |
The <sgmltag class="starttag">servlets</sgmltag> tag is the root tag and is |
4221 |
14 Apr 08 |
nicklas |
1594 |
needed to set up the namespace and schema validation. This may contain |
4221 |
14 Apr 08 |
nicklas |
1595 |
any number of <sgmltag class="starttag">servlet</sgmltag> tags, each one |
4221 |
14 Apr 08 |
nicklas |
1596 |
defining a single servlet. |
4221 |
14 Apr 08 |
nicklas |
1597 |
</para> |
4221 |
14 Apr 08 |
nicklas |
1598 |
|
4221 |
14 Apr 08 |
nicklas |
1599 |
<para> |
4221 |
14 Apr 08 |
nicklas |
1600 |
The <sgmltag class="starttag">servlet-name</sgmltag> tag contains the name |
4221 |
14 Apr 08 |
nicklas |
1601 |
of the servlet. This is a required tag and must be unique among the servlets |
4221 |
14 Apr 08 |
nicklas |
1602 |
defined by this extension. Other extensions may use the same name without any |
4221 |
14 Apr 08 |
nicklas |
1603 |
problems. |
4221 |
14 Apr 08 |
nicklas |
1604 |
</para> |
4221 |
14 Apr 08 |
nicklas |
1605 |
|
4221 |
14 Apr 08 |
nicklas |
1606 |
<para> |
4221 |
14 Apr 08 |
nicklas |
1607 |
The <sgmltag class="starttag">servlet-class</sgmltag> tag contains the name |
4221 |
14 Apr 08 |
nicklas |
1608 |
of implementing class. This is required and the class must implement |
4221 |
14 Apr 08 |
nicklas |
1609 |
the <interfacename>Servlet</interfacename> interface and have a public, |
4221 |
14 Apr 08 |
nicklas |
1610 |
no-argument constructor. We recommend that servlet implementations instead |
4221 |
14 Apr 08 |
nicklas |
1611 |
extends the <classname>HttpServlet</classname> class. This will make the |
4221 |
14 Apr 08 |
nicklas |
1612 |
servlet programming easier. |
4221 |
14 Apr 08 |
nicklas |
1613 |
</para> |
4221 |
14 Apr 08 |
nicklas |
1614 |
|
4221 |
14 Apr 08 |
nicklas |
1615 |
<para> |
4221 |
14 Apr 08 |
nicklas |
1616 |
A servlet may have any number <sgmltag class="starttag">init-param</sgmltag> |
4221 |
14 Apr 08 |
nicklas |
1617 |
tags, containing initialisation parameters for the servlet. Here is the |
4221 |
14 Apr 08 |
nicklas |
1618 |
code for the servlet references in the above example. |
4221 |
14 Apr 08 |
nicklas |
1619 |
</para> |
4221 |
14 Apr 08 |
nicklas |
1620 |
|
4221 |
14 Apr 08 |
nicklas |
1621 |
<programlisting language="java"> |
4221 |
14 Apr 08 |
nicklas |
1622 |
<![CDATA[ |
4221 |
14 Apr 08 |
nicklas |
1623 |
public class HelloWorldServlet |
4221 |
14 Apr 08 |
nicklas |
1624 |
extends HttpServlet |
4221 |
14 Apr 08 |
nicklas |
1625 |
{ |
4221 |
14 Apr 08 |
nicklas |
1626 |
private String template; |
4221 |
14 Apr 08 |
nicklas |
1627 |
public HelloWorldServlet() |
4221 |
14 Apr 08 |
nicklas |
1628 |
{} |
4221 |
14 Apr 08 |
nicklas |
1629 |
|
4221 |
14 Apr 08 |
nicklas |
1630 |
@Override |
4221 |
14 Apr 08 |
nicklas |
1631 |
public void init() |
4221 |
14 Apr 08 |
nicklas |
1632 |
throws ServletException |
4221 |
14 Apr 08 |
nicklas |
1633 |
{ |
4221 |
14 Apr 08 |
nicklas |
1634 |
ServletConfig cfg = getServletConfig(); |
4221 |
14 Apr 08 |
nicklas |
1635 |
template = cfg.getInitParameter("template"); |
4221 |
14 Apr 08 |
nicklas |
1636 |
if (template == null) template = "Hello {user}."; |
4221 |
14 Apr 08 |
nicklas |
1637 |
} |
4221 |
14 Apr 08 |
nicklas |
1638 |
|
4221 |
14 Apr 08 |
nicklas |
1639 |
@Override |
4221 |
14 Apr 08 |
nicklas |
1640 |
protected void doGet(HttpServletRequest request, HttpServletResponse response) |
4221 |
14 Apr 08 |
nicklas |
1641 |
throws ServletException, IOException |
4221 |
14 Apr 08 |
nicklas |
1642 |
{ |
4221 |
14 Apr 08 |
nicklas |
1643 |
final SessionControl sc = Base.getExistingSessionControl(request, true); |
4221 |
14 Apr 08 |
nicklas |
1644 |
final DbControl dc = sc.newDbControl(); |
4221 |
14 Apr 08 |
nicklas |
1645 |
try |
4221 |
14 Apr 08 |
nicklas |
1646 |
{ |
4221 |
14 Apr 08 |
nicklas |
1647 |
User current = User.getById(dc, sc.getLoggedInUserId()); |
4221 |
14 Apr 08 |
nicklas |
1648 |
PrintWriter out = response.getWriter(); |
4221 |
14 Apr 08 |
nicklas |
1649 |
out.print(template.replace("{user}", current.getName())); |
4221 |
14 Apr 08 |
nicklas |
1650 |
} |
4221 |
14 Apr 08 |
nicklas |
1651 |
finally |
4221 |
14 Apr 08 |
nicklas |
1652 |
{ |
4221 |
14 Apr 08 |
nicklas |
1653 |
if (dc != null) dc.close(); |
4221 |
14 Apr 08 |
nicklas |
1654 |
} |
4221 |
14 Apr 08 |
nicklas |
1655 |
} |
4221 |
14 Apr 08 |
nicklas |
1656 |
@Override |
4221 |
14 Apr 08 |
nicklas |
1657 |
protected void doPost(HttpServletRequest req, HttpServletResponse resp) |
4221 |
14 Apr 08 |
nicklas |
1658 |
throws ServletException, IOException |
4221 |
14 Apr 08 |
nicklas |
1659 |
{ |
4221 |
14 Apr 08 |
nicklas |
1660 |
doGet(req, resp); |
4221 |
14 Apr 08 |
nicklas |
1661 |
} |
4221 |
14 Apr 08 |
nicklas |
1662 |
} |
4221 |
14 Apr 08 |
nicklas |
1663 |
]]> |
4221 |
14 Apr 08 |
nicklas |
1664 |
</programlisting> |
4221 |
14 Apr 08 |
nicklas |
1665 |
|
4221 |
14 Apr 08 |
nicklas |
1666 |
<para> |
4221 |
14 Apr 08 |
nicklas |
1667 |
Invoking the servlet is done with a URL that is constructed like: |
4221 |
14 Apr 08 |
nicklas |
1668 |
<filename>$HOME$/[servlet-name].servlet</filename>, where <code>$HOME$</code> |
5640 |
24 May 11 |
nicklas |
1669 |
is the home directory of the extension. An alternate URL |
4975 |
15 Jun 09 |
nicklas |
1670 |
that doesn't require the <filename>.servlet</filename> extension is available: |
4975 |
15 Jun 09 |
nicklas |
1671 |
<filename>$SERVLET_HOME$/[servlet-name]</filename>, where <code>$SERVLET_HOME$</code> |
4975 |
15 Jun 09 |
nicklas |
1672 |
is the home directory of servlets for the extension. Note that this |
4975 |
15 Jun 09 |
nicklas |
1673 |
directory is on a different sub-path than the <code>$HOME$</code> directory. |
4221 |
14 Apr 08 |
nicklas |
1674 |
</para> |
4703 |
11 Dec 08 |
nicklas |
1675 |
<para> |
5640 |
24 May 11 |
nicklas |
1676 |
Extra path information is supported |
4703 |
11 Dec 08 |
nicklas |
1677 |
if it is inserted between the servlet name and the <filename>.servlet</filename> |
4975 |
15 Jun 09 |
nicklas |
1678 |
extension: <filename>$HOME$/[servlet-name][/extra/path/info].servlet</filename>, |
4975 |
15 Jun 09 |
nicklas |
1679 |
<filename>$SERVLET_HOME$/[servlet-name][/extra/path/info]</filename> |
4975 |
15 Jun 09 |
nicklas |
1680 |
|
4703 |
11 Dec 08 |
nicklas |
1681 |
</para> |
4703 |
11 Dec 08 |
nicklas |
1682 |
<para> |
4703 |
11 Dec 08 |
nicklas |
1683 |
Query parameters are supported as normal: |
4975 |
15 Jun 09 |
nicklas |
1684 |
<filename>$HOME$/[servlet-name].servlet?param1=value&param2=value</filename>, |
4975 |
15 Jun 09 |
nicklas |
1685 |
<filename>$SERVLET_HOME$/[servlet-name]?param1=value&param2=value</filename> |
4703 |
11 Dec 08 |
nicklas |
1686 |
</para> |
4703 |
11 Dec 08 |
nicklas |
1687 |
|
4221 |
14 Apr 08 |
nicklas |
1688 |
|
4221 |
14 Apr 08 |
nicklas |
1689 |
<programlisting language="xml"> |
4221 |
14 Apr 08 |
nicklas |
1690 |
<![CDATA[ |
4221 |
14 Apr 08 |
nicklas |
1691 |
<extension |
4221 |
14 Apr 08 |
nicklas |
1692 |
id="net.sf.basedb.clients.web.menu.extensions.helloservletworld" |
4221 |
14 Apr 08 |
nicklas |
1693 |
extends="net.sf.basedb.clients.web.menu.extensions" |
4221 |
14 Apr 08 |
nicklas |
1694 |
> |
4221 |
14 Apr 08 |
nicklas |
1695 |
<index>5</index> |
4221 |
14 Apr 08 |
nicklas |
1696 |
<about> |
4221 |
14 Apr 08 |
nicklas |
1697 |
<name>Hello Servlet world</name> |
4221 |
14 Apr 08 |
nicklas |
1698 |
<description> |
4221 |
14 Apr 08 |
nicklas |
1699 |
This example uses a custom Servlet page to display the |
4221 |
14 Apr 08 |
nicklas |
1700 |
"Hello world" message instead of a javascript popup. |
4221 |
14 Apr 08 |
nicklas |
1701 |
</description> |
4221 |
14 Apr 08 |
nicklas |
1702 |
</about> |
4221 |
14 Apr 08 |
nicklas |
1703 |
<action-factory> |
4221 |
14 Apr 08 |
nicklas |
1704 |
<factory-class> |
4221 |
14 Apr 08 |
nicklas |
1705 |
net.sf.basedb.clients.web.extensions.menu.FixedMenuItemFactory |
4221 |
14 Apr 08 |
nicklas |
1706 |
</factory-class> |
4221 |
14 Apr 08 |
nicklas |
1707 |
<parameters> |
4221 |
14 Apr 08 |
nicklas |
1708 |
<title>Hello Servlet world!</title> |
4221 |
14 Apr 08 |
nicklas |
1709 |
<tooltip>Opens a Servlet generated page with the message</tooltip> |
6403 |
29 Jan 14 |
nicklas |
1710 |
<data-url>$HOME$/HelloWorld.servlet?ID=$SESSION-ID$</data-url> |
6403 |
29 Jan 14 |
nicklas |
1711 |
<data-popup>HelloServletWorld, 400, 300</data-popup> |
4221 |
14 Apr 08 |
nicklas |
1712 |
<icon>~/images/servlet.png</icon> |
4221 |
14 Apr 08 |
nicklas |
1713 |
</parameters> |
4221 |
14 Apr 08 |
nicklas |
1714 |
</action-factory> |
4221 |
14 Apr 08 |
nicklas |
1715 |
</extension> |
4221 |
14 Apr 08 |
nicklas |
1716 |
]]> |
4221 |
14 Apr 08 |
nicklas |
1717 |
</programlisting> |
4221 |
14 Apr 08 |
nicklas |
1718 |
|
4221 |
14 Apr 08 |
nicklas |
1719 |
<note> |
4221 |
14 Apr 08 |
nicklas |
1720 |
<para> |
4221 |
14 Apr 08 |
nicklas |
1721 |
To keep things as simple as possible, a new instance of the servlet |
4221 |
14 Apr 08 |
nicklas |
1722 |
class is created for each request. If the servlet needs complex or |
4221 |
14 Apr 08 |
nicklas |
1723 |
expensive initialisation, that should be externalised to other |
4221 |
14 Apr 08 |
nicklas |
1724 |
classes that the servlet can use. |
4221 |
14 Apr 08 |
nicklas |
1725 |
</para> |
4221 |
14 Apr 08 |
nicklas |
1726 |
</note> |
4221 |
14 Apr 08 |
nicklas |
1727 |
|
4221 |
14 Apr 08 |
nicklas |
1728 |
</sect1> |
4221 |
14 Apr 08 |
nicklas |
1729 |
|
5640 |
24 May 11 |
nicklas |
1730 |
<sect1 id="extensions_developer.base_extension_points"> |
5782 |
04 Oct 11 |
nicklas |
1731 |
<?dbhtml filename="builtin.html" ?> |
5640 |
24 May 11 |
nicklas |
1732 |
<title>Extension points defined by BASE</title> |
5640 |
24 May 11 |
nicklas |
1733 |
|
5640 |
24 May 11 |
nicklas |
1734 |
<para> |
5640 |
24 May 11 |
nicklas |
1735 |
In this section, we will give an overview of the extension points defined |
5640 |
24 May 11 |
nicklas |
1736 |
by BASE. Most extension points are used in the web client to add |
5640 |
24 May 11 |
nicklas |
1737 |
buttons and menu items, but there are a few for the core API as well. |
5640 |
24 May 11 |
nicklas |
1738 |
</para> |
5640 |
24 May 11 |
nicklas |
1739 |
|
5640 |
24 May 11 |
nicklas |
1740 |
<sect2 id="extensions_developer.menuitems"> |
5640 |
24 May 11 |
nicklas |
1741 |
<title>Menu: extensions</title> |
5640 |
24 May 11 |
nicklas |
1742 |
|
5640 |
24 May 11 |
nicklas |
1743 |
<para> |
5640 |
24 May 11 |
nicklas |
1744 |
Menu items can be added to the top-level |
5640 |
24 May 11 |
nicklas |
1745 |
<menuchoice><guimenu>Extensions</guimenu></menuchoice> |
5640 |
24 May 11 |
nicklas |
1746 |
menu. Actions should implement the interface: <interfacename |
5654 |
15 Jun 11 |
nicklas |
1747 |
docapi="net.sf.basedb.clients.web.extensions.menu">MenuItemAction</interfacename> |
5640 |
24 May 11 |
nicklas |
1748 |
</para> |
5640 |
24 May 11 |
nicklas |
1749 |
|
5640 |
24 May 11 |
nicklas |
1750 |
<para> |
5640 |
24 May 11 |
nicklas |
1751 |
The <methodname>MenuItemAction.getMenuType()</methodname> provides support |
5640 |
24 May 11 |
nicklas |
1752 |
for <constant>MENUITEM</constant>, <constant>SUBMENU</constant> and |
5640 |
24 May 11 |
nicklas |
1753 |
<constant>SEPARATOR</constant> menus. Which of the other properties that |
5640 |
24 May 11 |
nicklas |
1754 |
are needed depend on the menu type. Read the javadoc for more information. |
6403 |
29 Jan 14 |
nicklas |
1755 |
The rendering is internal (eg. extensions can't provide their own renderers). |
5640 |
24 May 11 |
nicklas |
1756 |
</para> |
5640 |
24 May 11 |
nicklas |
1757 |
|
5640 |
24 May 11 |
nicklas |
1758 |
<para> |
5640 |
24 May 11 |
nicklas |
1759 |
BASE ships with two action factories: |
5654 |
15 Jun 11 |
nicklas |
1760 |
<classname docapi="net.sf.basedb.clients.web.extensions.menu">FixedMenuItemFactory</classname> and |
5654 |
15 Jun 11 |
nicklas |
1761 |
<classname docapi="net.sf.basedb.clients.web.extensions.menu">PermissionMenuItemFactory</classname>. |
5640 |
24 May 11 |
nicklas |
1762 |
|
5640 |
24 May 11 |
nicklas |
1763 |
The fixed factory provides a menu that is the same for all users. |
5640 |
24 May 11 |
nicklas |
1764 |
The permission factory can disable or hide a menu depending on the |
5640 |
24 May 11 |
nicklas |
1765 |
logged in user's role-based permissions. The title, icon, etc. can have |
5640 |
24 May 11 |
nicklas |
1766 |
different values depending on if the menu item is disabled or enabled. |
5640 |
24 May 11 |
nicklas |
1767 |
</para> |
6403 |
29 Jan 14 |
nicklas |
1768 |
|
6403 |
29 Jan 14 |
nicklas |
1769 |
<note> |
6812 |
30 Mar 15 |
nicklas |
1770 |
<title>onclick has been removed</title> |
6403 |
29 Jan 14 |
nicklas |
1771 |
<para> |
6812 |
30 Mar 15 |
nicklas |
1772 |
The onclick attribute has been deprecated since BASE 3.3 and was removed in BASE 3.5. Use a custom script instead to |
6403 |
29 Jan 14 |
nicklas |
1773 |
bind the click event with the menu item or <sgmltag class="starttag">data-url</sgmltag> |
6403 |
29 Jan 14 |
nicklas |
1774 |
if the menu simply navigates to another page. <sgmltag class="starttag">data-popup</sgmltag> |
6403 |
29 Jan 14 |
nicklas |
1775 |
can be used to open the page in a popup window and should contain three comma-separated |
6403 |
29 Jan 14 |
nicklas |
1776 |
values: name-of-window, width-of-window, height-of-window |
6403 |
29 Jan 14 |
nicklas |
1777 |
</para> |
6403 |
29 Jan 14 |
nicklas |
1778 |
</note> |
5640 |
24 May 11 |
nicklas |
1779 |
</sect2> |
5640 |
24 May 11 |
nicklas |
1780 |
|
5640 |
24 May 11 |
nicklas |
1781 |
<sect2 id="extensions_developer.toolbars"> |
5640 |
24 May 11 |
nicklas |
1782 |
<title>Toolbars</title> |
5640 |
24 May 11 |
nicklas |
1783 |
<para> |
5640 |
24 May 11 |
nicklas |
1784 |
Most toolbars on all list and single-item view pages can |
5640 |
24 May 11 |
nicklas |
1785 |
be extended with extra buttons. Actions should implement |
5640 |
24 May 11 |
nicklas |
1786 |
the interface: <interfacename |
5654 |
15 Jun 11 |
nicklas |
1787 |
docapi="net.sf.basedb.clients.web.extensions.toolbar">ButtonAction</interfacename>. |
5640 |
24 May 11 |
nicklas |
1788 |
Button actions are very simple and only need to provide things like |
6403 |
29 Jan 14 |
nicklas |
1789 |
a title, tooltip, icon, etc. This extension point has |
5640 |
24 May 11 |
nicklas |
1790 |
support for custom javascript, stylesheets and renderers. The |
5640 |
24 May 11 |
nicklas |
1791 |
default renderer is <classname |
5640 |
24 May 11 |
nicklas |
1792 |
docapi="net.sf.basedb.clients.web.extensions.toolbar">ToolbarButtonRendererFactory</classname>. |
5640 |
24 May 11 |
nicklas |
1793 |
</para> |
5640 |
24 May 11 |
nicklas |
1794 |
|
5640 |
24 May 11 |
nicklas |
1795 |
<para> |
5640 |
24 May 11 |
nicklas |
1796 |
BASE ships with two action factories: |
5654 |
15 Jun 11 |
nicklas |
1797 |
<classname docapi="net.sf.basedb.clients.web.extensions.toolbar">FixedButtonFactory</classname> and |
5654 |
15 Jun 11 |
nicklas |
1798 |
<classname docapi="net.sf.basedb.clients.web.extensions.toolbar">PermissionButtonFactory</classname>. |
5640 |
24 May 11 |
nicklas |
1799 |
|
5640 |
24 May 11 |
nicklas |
1800 |
The fixed factory provides a toolbar button that is the same for all users. |
5640 |
24 May 11 |
nicklas |
1801 |
The permission factory can disable or hide a buton depending on the |
5640 |
24 May 11 |
nicklas |
1802 |
logged in user's role-based permissions. The title, icon, etc. can have |
5640 |
24 May 11 |
nicklas |
1803 |
different values depending on if the menu item is disabled or enabled. |
5640 |
24 May 11 |
nicklas |
1804 |
</para> |
6403 |
29 Jan 14 |
nicklas |
1805 |
|
6403 |
29 Jan 14 |
nicklas |
1806 |
<note> |
6812 |
30 Mar 15 |
nicklas |
1807 |
<title>onclick has been removed</title> |
6403 |
29 Jan 14 |
nicklas |
1808 |
<para> |
6812 |
30 Mar 15 |
nicklas |
1809 |
The onclick attribute has been deprecated since BASE 3.3 and was removed in BASE 3.5. Use a custom script instead to |
6403 |
29 Jan 14 |
nicklas |
1810 |
bind the click event with the button. Download the example code to see it in action. |
6403 |
29 Jan 14 |
nicklas |
1811 |
</para> |
6403 |
29 Jan 14 |
nicklas |
1812 |
</note> |
6403 |
29 Jan 14 |
nicklas |
1813 |
|
5640 |
24 May 11 |
nicklas |
1814 |
</sect2> |
5640 |
24 May 11 |
nicklas |
1815 |
|
5640 |
24 May 11 |
nicklas |
1816 |
<sect2 id="extensions_developer.edit_dialogs"> |
5640 |
24 May 11 |
nicklas |
1817 |
<title>Edit dialogs</title> |
5640 |
24 May 11 |
nicklas |
1818 |
|
5640 |
24 May 11 |
nicklas |
1819 |
<para> |
5640 |
24 May 11 |
nicklas |
1820 |
Most item edit dialogs can be extended with additional tabs. |
5640 |
24 May 11 |
nicklas |
1821 |
Actions should implement the interface: <interfacename |
5654 |
15 Jun 11 |
nicklas |
1822 |
docapi="net.sf.basedb.clients.web.extensions.tabcontrol">TabAction</interfacename>. |
5640 |
24 May 11 |
nicklas |
1823 |
The actions are, in principle, simple and only need to |
5640 |
24 May 11 |
nicklas |
1824 |
provide a title and content (HTML). The action may also provide |
5640 |
24 May 11 |
nicklas |
1825 |
javascripts for validation, etc. This extension point has support |
5640 |
24 May 11 |
nicklas |
1826 |
for custom stylesheets and javascript. Rendering is fixed and can't |
5640 |
24 May 11 |
nicklas |
1827 |
be overridden. |
5640 |
24 May 11 |
nicklas |
1828 |
</para> |
5640 |
24 May 11 |
nicklas |
1829 |
|
5640 |
24 May 11 |
nicklas |
1830 |
<para> |
5640 |
24 May 11 |
nicklas |
1831 |
BASE ships with two action factories: |
5654 |
15 Jun 11 |
nicklas |
1832 |
<classname docapi="net.sf.basedb.clients.web.extensions.tabcontrol">FixedTabFactory</classname> and |
5654 |
15 Jun 11 |
nicklas |
1833 |
<classname docapi="net.sf.basedb.clients.web.extensions.tabcontrol">IncludeContentTabFactory</classname>. |
5640 |
24 May 11 |
nicklas |
1834 |
|
5816 |
20 Oct 11 |
nicklas |
1835 |
The fixed factory provides a tab with fixed content that is the same for all users |
5816 |
20 Oct 11 |
nicklas |
1836 |
and all items. This factory is not very useful in a real scenario. |
5640 |
24 May 11 |
nicklas |
1837 |
The other factory provides content by including the output from another resource, |
5640 |
24 May 11 |
nicklas |
1838 |
eg. a JSP page, a servlet, etc. The current context is stored in a request-scoped |
5640 |
24 May 11 |
nicklas |
1839 |
attribute under the key given by <code>JspContext.ATTRIBUTE_KEY</code>. |
5640 |
24 May 11 |
nicklas |
1840 |
A JSP or servlet should use this to hook into the current flow. Here is a code example: |
5640 |
24 May 11 |
nicklas |
1841 |
</para> |
5640 |
24 May 11 |
nicklas |
1842 |
|
5640 |
24 May 11 |
nicklas |
1843 |
<programlisting language="java"> |
5640 |
24 May 11 |
nicklas |
1844 |
<![CDATA[ |
5640 |
24 May 11 |
nicklas |
1845 |
// Get the JspContext that was created on the main edit page |
5640 |
24 May 11 |
nicklas |
1846 |
final JspContext jspContext = (JspContext)request.getAttribute(JspContext.ATTRIBUTE_KEY); |
5640 |
24 May 11 |
nicklas |
1847 |
|
5640 |
24 May 11 |
nicklas |
1848 |
// The current item is found in the context. NOTE! Can be null if a new item |
5640 |
24 May 11 |
nicklas |
1849 |
final BasicItem item = (BasicItem)jspContext.getCurrentItem(); |
5640 |
24 May 11 |
nicklas |
1850 |
|
5640 |
24 May 11 |
nicklas |
1851 |
// Get the DbControl and SessionControl used to handle the request (do not close!) |
5640 |
24 May 11 |
nicklas |
1852 |
final DbControl dc = jspContext.getDbControl(); |
5640 |
24 May 11 |
nicklas |
1853 |
final SessionControl sc = dc.getSessionControl(); |
5640 |
24 May 11 |
nicklas |
1854 |
]]> |
5640 |
24 May 11 |
nicklas |
1855 |
</programlisting> |
5640 |
24 May 11 |
nicklas |
1856 |
|
5640 |
24 May 11 |
nicklas |
1857 |
<para> |
5816 |
20 Oct 11 |
nicklas |
1858 |
The extra tab need to be paired with an extension that is invoked when |
5640 |
24 May 11 |
nicklas |
1859 |
the edit form is saved. Each edit-dialog extension point has a corresponding |
5640 |
24 May 11 |
nicklas |
1860 |
on-save extension point. Actions should implement the interface: <interfacename |
5654 |
15 Jun 11 |
nicklas |
1861 |
docapi="net.sf.basedb.clients.web.extensions.edit">OnSaveAction</interfacename>. |
5640 |
24 May 11 |
nicklas |
1862 |
|
5640 |
24 May 11 |
nicklas |
1863 |
This interface define three callback methods that BASE will call when |
5640 |
24 May 11 |
nicklas |
1864 |
saving an item. The <methodname>OnSaveAction.onSave()</methodname> |
5640 |
24 May 11 |
nicklas |
1865 |
method is called first, but not until all regular properties have been |
5640 |
24 May 11 |
nicklas |
1866 |
updated. If the transaction is committed the <methodname>OnSaveAction.onCommit()</methodname> |
5640 |
24 May 11 |
nicklas |
1867 |
method is also called, otherwise the <methodname>OnSaveAction.onRollback()</methodname> |
5640 |
24 May 11 |
nicklas |
1868 |
is called. The <methodname>onSave()</methodname> method can throw an exception that |
5640 |
24 May 11 |
nicklas |
1869 |
will be displayed to the user. The other callback method should not throw exceptions |
5640 |
24 May 11 |
nicklas |
1870 |
at all, since that may result in undefined behaviour and can be confusing for the user. |
5640 |
24 May 11 |
nicklas |
1871 |
</para> |
5640 |
24 May 11 |
nicklas |
1872 |
</sect2> |
5640 |
24 May 11 |
nicklas |
1873 |
|
5640 |
24 May 11 |
nicklas |
1874 |
<sect2 id="extensions_developer.bioassayset_tools"> |
5640 |
24 May 11 |
nicklas |
1875 |
<title>Bioassay set: Tools</title> |
5640 |
24 May 11 |
nicklas |
1876 |
<para> |
5640 |
24 May 11 |
nicklas |
1877 |
The bioassay set listing for an experiment has a <guilabel>Tools</guilabel> |
5640 |
24 May 11 |
nicklas |
1878 |
column which can be extended by extensions. This extension point is similar |
5640 |
24 May 11 |
nicklas |
1879 |
to the toolbar extension points and actions should implement |
5640 |
24 May 11 |
nicklas |
1880 |
the interface: <interfacename |
5654 |
15 Jun 11 |
nicklas |
1881 |
docapi="net.sf.basedb.clients.web.extensions.toolbar">ButtonAction</interfacename>. |
5640 |
24 May 11 |
nicklas |
1882 |
</para> |
5640 |
24 May 11 |
nicklas |
1883 |
|
5640 |
24 May 11 |
nicklas |
1884 |
<para> |
5640 |
24 May 11 |
nicklas |
1885 |
Note that the list can contain |
5640 |
24 May 11 |
nicklas |
1886 |
<classname docapi="net.sf.basedb.core">BioAssaySet</classname>, |
5640 |
24 May 11 |
nicklas |
1887 |
<classname docapi="net.sf.basedb.core">Transformation</classname> and |
5640 |
24 May 11 |
nicklas |
1888 |
<classname docapi="net.sf.basedb.core">ExtraValue</classname> items. |
5640 |
24 May 11 |
nicklas |
1889 |
The factory implementation need to be aware of this if it uses |
5640 |
24 May 11 |
nicklas |
1890 |
the <methodname>JspContext.getItem()</methodname> method to examine the |
5640 |
24 May 11 |
nicklas |
1891 |
current item. |
5640 |
24 May 11 |
nicklas |
1892 |
</para> |
5640 |
24 May 11 |
nicklas |
1893 |
</sect2> |
5640 |
24 May 11 |
nicklas |
1894 |
|
5640 |
24 May 11 |
nicklas |
1895 |
<sect2 id="extensions_developer.bioassayset_plots"> |
5640 |
24 May 11 |
nicklas |
1896 |
<title>Bioassay set: Overview plots</title> |
5640 |
24 May 11 |
nicklas |
1897 |
<para> |
5640 |
24 May 11 |
nicklas |
1898 |
The bioassay set page has a tab <guilabel>Overview plots</guilabel>. |
5640 |
24 May 11 |
nicklas |
1899 |
The contents of this tab is supposed to be some kind of images |
5640 |
24 May 11 |
nicklas |
1900 |
that have been generated from the data in the current bioassay set. |
5640 |
24 May 11 |
nicklas |
1901 |
What kind of plots that can be generated typically depends on the |
5640 |
24 May 11 |
nicklas |
1902 |
kind of data you have. BASE ships with an extension |
5640 |
24 May 11 |
nicklas |
1903 |
(<classname docapi="net.sf.basedb.clients.web.extensions">MAPlotFactory</classname>) |
5654 |
15 Jun 11 |
nicklas |
1904 |
that creates MA plots and Correction factor plots for 2-channel bioassays. |
5654 |
15 Jun 11 |
nicklas |
1905 |
Actions should implement the interface: |
5654 |
15 Jun 11 |
nicklas |
1906 |
<interfacename docapi="net.sf.basedb.clients.web.extensions.plot">OverviewPlotAction</interfacename>. |
5654 |
15 Jun 11 |
nicklas |
1907 |
A single action generates a sub-tab in the <guilabel>Overview plots</guilabel> tab. |
5654 |
15 Jun 11 |
nicklas |
1908 |
The sub-tab may contain one or more images. Each image is defined by a |
5640 |
24 May 11 |
nicklas |
1909 |
<interfacename docapi="net.sf.basedb.clients.web.extensions.plot">PlotGenerator</interfacename> |
5640 |
24 May 11 |
nicklas |
1910 |
which sets the size of the image and provides an URL to a servlet that generates |
5654 |
15 Jun 11 |
nicklas |
1911 |
the actual image. It is recommended that the servlet cache images since the |
5654 |
15 Jun 11 |
nicklas |
1912 |
data in a bioassay set never changes. The BASE core API provides a |
5654 |
15 Jun 11 |
nicklas |
1913 |
system-managed file cache that is suitable for this. Call |
5654 |
15 Jun 11 |
nicklas |
1914 |
<methodname>Application.getStaticCache()</methodname> to get a |
5654 |
15 Jun 11 |
nicklas |
1915 |
<classname docapi="net.sf.basedb.util">StaticCache</classname> instance. |
5654 |
15 Jun 11 |
nicklas |
1916 |
See the source code for the core |
5654 |
15 Jun 11 |
nicklas |
1917 |
<classname docapi="net.sf.basedb.clients.web.servlet">PlotServlet</classname> |
5654 |
15 Jun 11 |
nicklas |
1918 |
for details of how to use the cache. |
5640 |
24 May 11 |
nicklas |
1919 |
</para> |
5640 |
24 May 11 |
nicklas |
1920 |
|
5640 |
24 May 11 |
nicklas |
1921 |
</sect2> |
5640 |
24 May 11 |
nicklas |
1922 |
|
5640 |
24 May 11 |
nicklas |
1923 |
<sect2 id="extensions_developer.services"> |
5640 |
24 May 11 |
nicklas |
1924 |
<title>Services</title> |
5640 |
24 May 11 |
nicklas |
1925 |
<para> |
5640 |
24 May 11 |
nicklas |
1926 |
A service is a piece of code that is loaded when the BASE web |
5640 |
24 May 11 |
nicklas |
1927 |
server starts up. The service is then running as long as the BASE web |
5640 |
24 May 11 |
nicklas |
1928 |
server is running. It is possible to manually stop and start services. |
5640 |
24 May 11 |
nicklas |
1929 |
This extension point is different from most others in that it doesn't |
5640 |
24 May 11 |
nicklas |
1930 |
affects the visible interface. Since services are loaded at startup time, |
6443 |
04 Apr 14 |
nicklas |
1931 |
this also means that the context passed to <interfacename>ActionFactory</interfacename> |
6443 |
04 Apr 14 |
nicklas |
1932 |
methods will have a special <classname>ClientContext</classname> associated with it. |
6443 |
04 Apr 14 |
nicklas |
1933 |
There is no current item, and no user is logged in. However, the <classname>SessionControl</classname> |
6443 |
04 Apr 14 |
nicklas |
1934 |
returned from <methodname>ClientContext.getSessionControl()</methodname> gives |
6443 |
04 Apr 14 |
nicklas |
1935 |
permission to imporsonate another making it possible for the extension |
6443 |
04 Apr 14 |
nicklas |
1936 |
to access the BASE database almost without limitation. There is no meaning for |
6443 |
04 Apr 14 |
nicklas |
1937 |
extensions to specify a <interfacename>RendererFactory</interfacename>. Service |
6443 |
04 Apr 14 |
nicklas |
1938 |
actions should implement the interface: |
5654 |
15 Jun 11 |
nicklas |
1939 |
<interfacename docapi="net.sf.basedb.clients.web.extensions.service">ServiceControllerAction</interfacename>. |
5640 |
24 May 11 |
nicklas |
1940 |
|
5640 |
24 May 11 |
nicklas |
1941 |
The interface provides <methodname>start()</methodname> and |
5640 |
24 May 11 |
nicklas |
1942 |
<methodname>stop()</methodname> methods for controlling the service. |
5640 |
24 May 11 |
nicklas |
1943 |
BASE doesn't ship with any service, but there is an FTP service |
5640 |
24 May 11 |
nicklas |
1944 |
available at the BASE plug-ins site: <ulink |
7982 |
14 Jun 21 |
nicklas |
1945 |
url="https://baseplugins.thep.lu.se/wiki/net.sf.basedb.ftp"> |
7982 |
14 Jun 21 |
nicklas |
1946 |
https://baseplugins.thep.lu.se/wiki/net.sf.basedb.ftp</ulink> |
5640 |
24 May 11 |
nicklas |
1947 |
</para> |
5640 |
24 May 11 |
nicklas |
1948 |
</sect2> |
5640 |
24 May 11 |
nicklas |
1949 |
|
7274 |
24 Jan 17 |
nicklas |
1950 |
<sect2 id="extensions_developer.service-actions"> |
7274 |
24 Jan 17 |
nicklas |
1951 |
<title>Service actions</title> |
7274 |
24 Jan 17 |
nicklas |
1952 |
<para> |
7274 |
24 Jan 17 |
nicklas |
1953 |
The services list page has an <guilabel>Action</guilabel> column |
7274 |
24 Jan 17 |
nicklas |
1954 |
for showing the <guilabel>Start</guilabel> and <guilabel>Stop</guilabel> |
7274 |
24 Jan 17 |
nicklas |
1955 |
actions as well as any other actions extending this extension point. |
7274 |
24 Jan 17 |
nicklas |
1956 |
This extension point is similar to the toolbar extension points and actions |
7274 |
24 Jan 17 |
nicklas |
1957 |
should implement the <interfacename |
7274 |
24 Jan 17 |
nicklas |
1958 |
docapi="net.sf.basedb.clients.web.extensions.toolbar">ButtonAction</interfacename> |
7274 |
24 Jan 17 |
nicklas |
1959 |
interface. This extension point supports custom scripts and stylesheets. |
7274 |
24 Jan 17 |
nicklas |
1960 |
|
7274 |
24 Jan 17 |
nicklas |
1961 |
Note that all extensions are invoked for all services. The |
7274 |
24 Jan 17 |
nicklas |
1962 |
<methodname>ClientContext.getItem()</methodname> returns the |
7274 |
24 Jan 17 |
nicklas |
1963 |
<interfacename docapi="net.sf.basedb.clients.web.extensions.service">ServiceControllerAction</interfacename> |
7274 |
24 Jan 17 |
nicklas |
1964 |
instance for the current service. Extensions should use this to |
7274 |
24 Jan 17 |
nicklas |
1965 |
decide if an action should be created or not. |
7274 |
24 Jan 17 |
nicklas |
1966 |
</para> |
7274 |
24 Jan 17 |
nicklas |
1967 |
</sect2> |
7274 |
24 Jan 17 |
nicklas |
1968 |
|
5640 |
24 May 11 |
nicklas |
1969 |
<sect2 id="extensions_developer.connection_manager"> |
5640 |
24 May 11 |
nicklas |
1970 |
<title>Connection managers</title> |
5640 |
24 May 11 |
nicklas |
1971 |
<para> |
5640 |
24 May 11 |
nicklas |
1972 |
This extension point adds support for using external files |
5640 |
24 May 11 |
nicklas |
1973 |
in BASE. This is a core extension point and is available |
5640 |
24 May 11 |
nicklas |
1974 |
independently of the web client. Actions should implement |
5654 |
15 Jun 11 |
nicklas |
1975 |
the interface: |
5654 |
15 Jun 11 |
nicklas |
1976 |
<interfacename docapi="net.sf.basedb.util.uri">ConnectionManagerFactory</interfacename>. |
5640 |
24 May 11 |
nicklas |
1977 |
</para> |
5640 |
24 May 11 |
nicklas |
1978 |
|
5640 |
24 May 11 |
nicklas |
1979 |
<para> |
5640 |
24 May 11 |
nicklas |
1980 |
The <methodname>getDisplayName()</methodname> and <methodname>getDescription()</methodname> |
5640 |
24 May 11 |
nicklas |
1981 |
methods are used in the gui when a user manually selects which connection |
5654 |
15 Jun 11 |
nicklas |
1982 |
manager to use. The <methodname>supports(URI)</methodname> is used when auto-selecting |
5654 |
15 Jun 11 |
nicklas |
1983 |
a connection manager based on the URI of the resource. |
5640 |
24 May 11 |
nicklas |
1984 |
</para> |
5640 |
24 May 11 |
nicklas |
1985 |
|
5640 |
24 May 11 |
nicklas |
1986 |
<para> |
5640 |
24 May 11 |
nicklas |
1987 |
BASE ships with factory that supports HTTP and HTTPS file |
5640 |
24 May 11 |
nicklas |
1988 |
references: <classname |
5640 |
24 May 11 |
nicklas |
1989 |
docapi="net.sf.basedb.util.uri.http">HttpConnectionManagerFactory</classname>. |
5640 |
24 May 11 |
nicklas |
1990 |
|
5640 |
24 May 11 |
nicklas |
1991 |
The BASE plug-ins site has an connection manager that support |
7548 |
10 Dec 18 |
nicklas |
1992 |
external files via FTP and SFTP: <ulink |
7982 |
14 Jun 21 |
nicklas |
1993 |
url="https://baseplugins.thep.lu.se/wiki/net.sf.basedb.xfiles"> |
7982 |
14 Jun 21 |
nicklas |
1994 |
https://baseplugins.thep.lu.se/wiki/net.sf.basedb.xfiles</ulink> |
5640 |
24 May 11 |
nicklas |
1995 |
</para> |
5640 |
24 May 11 |
nicklas |
1996 |
|
5640 |
24 May 11 |
nicklas |
1997 |
</sect2> |
5640 |
24 May 11 |
nicklas |
1998 |
|
5640 |
24 May 11 |
nicklas |
1999 |
<sect2 id="extensions_developer.fileset_validator"> |
5640 |
24 May 11 |
nicklas |
2000 |
<title>Fileset validators</title> |
5640 |
24 May 11 |
nicklas |
2001 |
|
5654 |
15 Jun 11 |
nicklas |
2002 |
<itemizedlist> |
5654 |
15 Jun 11 |
nicklas |
2003 |
<title>See also</title> |
5654 |
15 Jun 11 |
nicklas |
2004 |
<listitem><para><xref linkend="core_api.data_in_files" /></para></listitem> |
5654 |
15 Jun 11 |
nicklas |
2005 |
<listitem><para><xref linkend="data_api.platforms" /></para></listitem> |
5654 |
15 Jun 11 |
nicklas |
2006 |
</itemizedlist> |
5654 |
15 Jun 11 |
nicklas |
2007 |
|
5640 |
24 May 11 |
nicklas |
2008 |
<para> |
5654 |
15 Jun 11 |
nicklas |
2009 |
In those cases where files are used to store data instead |
5654 |
15 Jun 11 |
nicklas |
2010 |
of importing it to the database, BASE can use extensions to |
5654 |
15 Jun 11 |
nicklas |
2011 |
check that the supplied files are valid and also to extract |
5654 |
15 Jun 11 |
nicklas |
2012 |
metadata from the files. For example, the |
5654 |
15 Jun 11 |
nicklas |
2013 |
<classname docapi="net.sf.basedb.util.affymetrix">CelValidationAction</classname> |
5654 |
15 Jun 11 |
nicklas |
2014 |
is used to check if a file is a valid Affymetrix CEL file and |
5654 |
15 Jun 11 |
nicklas |
2015 |
to extract data headers and the number of spots from it. |
5654 |
15 Jun 11 |
nicklas |
2016 |
</para> |
5640 |
24 May 11 |
nicklas |
2017 |
|
5654 |
15 Jun 11 |
nicklas |
2018 |
<para> |
5654 |
15 Jun 11 |
nicklas |
2019 |
Validation and metadata extraction actions should implement |
5654 |
15 Jun 11 |
nicklas |
2020 |
the <interfacename docapi="net.sf.basedb.util.fileset">ValidationAction</interfacename> |
5654 |
15 Jun 11 |
nicklas |
2021 |
interface. This is a core extension point and is available |
5654 |
15 Jun 11 |
nicklas |
2022 |
independently of the web client. |
5640 |
24 May 11 |
nicklas |
2023 |
</para> |
5640 |
24 May 11 |
nicklas |
2024 |
|
5654 |
15 Jun 11 |
nicklas |
2025 |
<para> |
5654 |
15 Jun 11 |
nicklas |
2026 |
This extension point is a bit more complex than most other extension |
5654 |
15 Jun 11 |
nicklas |
2027 |
points. To begin with, the factory class will be called with the |
5654 |
15 Jun 11 |
nicklas |
2028 |
owner of the file set as the current item. Eg. the |
5654 |
15 Jun 11 |
nicklas |
2029 |
<code>ClientContext.getCurrentItem()</code> should return a |
5654 |
15 Jun 11 |
nicklas |
2030 |
<interfacename docapi="net.sf.basedb.core">FileStoreEnabled</interfacename> |
5654 |
15 Jun 11 |
nicklas |
2031 |
item. It is recommended that the factory performs a pre-filtering |
5654 |
15 Jun 11 |
nicklas |
2032 |
of the items to avoid calling the actual validation code on unsupported |
5654 |
15 Jun 11 |
nicklas |
2033 |
files. For example, the <classname docapi="net.sf.basedb.util.affymetrix">CelValidationFactory</classname> |
5654 |
15 Jun 11 |
nicklas |
2034 |
will check that the item is a <classname docapi="net.sf.basedb.core">RawBioAssay</classname> |
5654 |
15 Jun 11 |
nicklas |
2035 |
item using the Affymetrix platform. |
5654 |
15 Jun 11 |
nicklas |
2036 |
</para> |
5654 |
15 Jun 11 |
nicklas |
2037 |
|
5654 |
15 Jun 11 |
nicklas |
2038 |
<para> |
5654 |
15 Jun 11 |
nicklas |
2039 |
Each file in the file set is then passed to the |
5654 |
15 Jun 11 |
nicklas |
2040 |
<methodname>ValidationAction.acceptFile(FileSetMember)</methodname> |
5654 |
15 Jun 11 |
nicklas |
2041 |
which may accept or reject the file. If the file is accepted it may |
5654 |
15 Jun 11 |
nicklas |
2042 |
be accepted for immediate validation or later validation. The latter option |
5654 |
15 Jun 11 |
nicklas |
2043 |
is useful in more complex scenarios were files need to be validated as a group. |
5654 |
15 Jun 11 |
nicklas |
2044 |
If the file is accepted the <methodname>ValidationAction.validateAndExtractMetadata()</methodname> |
5654 |
15 Jun 11 |
nicklas |
2045 |
is called, which is were the real work should happen. |
5654 |
15 Jun 11 |
nicklas |
2046 |
</para> |
5654 |
15 Jun 11 |
nicklas |
2047 |
|
5654 |
15 Jun 11 |
nicklas |
2048 |
<para> |
5654 |
15 Jun 11 |
nicklas |
2049 |
The extensions for this extension point is also called when a file is replaced |
5654 |
15 Jun 11 |
nicklas |
2050 |
or removed from the file set. The calling sequence to set up the validation is |
5654 |
15 Jun 11 |
nicklas |
2051 |
more or less the same as described above, but the last step is to |
5654 |
15 Jun 11 |
nicklas |
2052 |
call <methodname>ValidationAction.resetMetadata()</methodname> instead |
5654 |
15 Jun 11 |
nicklas |
2053 |
of <methodname>ValidationAction.validateAndExtractMetadata()</methodname>. |
5654 |
15 Jun 11 |
nicklas |
2054 |
</para> |
5654 |
15 Jun 11 |
nicklas |
2055 |
|
5654 |
15 Jun 11 |
nicklas |
2056 |
<tip> |
5654 |
15 Jun 11 |
nicklas |
2057 |
<title> |
5654 |
15 Jun 11 |
nicklas |
2058 |
Use the <classname docapi="net.sf.basedb.util.fileset">SingleFileValidationAction</classname> |
5654 |
15 Jun 11 |
nicklas |
2059 |
class. |
5654 |
15 Jun 11 |
nicklas |
2060 |
</title> |
5654 |
15 Jun 11 |
nicklas |
2061 |
<para> |
5654 |
15 Jun 11 |
nicklas |
2062 |
Most validators that work on a single file at a time may find the |
5654 |
15 Jun 11 |
nicklas |
2063 |
<classname>SingleFileValidationAction</classname> class useful. Is should |
5654 |
15 Jun 11 |
nicklas |
2064 |
simplify the task of making sure that only the desired file type is |
5654 |
15 Jun 11 |
nicklas |
2065 |
validated. See the source code of the <classname |
5654 |
15 Jun 11 |
nicklas |
2066 |
docapi="net.sf.basedb.util.affymetrix">CelValidationAction</classname> |
5654 |
15 Jun 11 |
nicklas |
2067 |
class for an example. |
5654 |
15 Jun 11 |
nicklas |
2068 |
</para> |
5654 |
15 Jun 11 |
nicklas |
2069 |
</tip> |
5654 |
15 Jun 11 |
nicklas |
2070 |
|
5640 |
24 May 11 |
nicklas |
2071 |
</sect2> |
6048 |
18 Apr 12 |
nicklas |
2072 |
|
6080 |
07 Aug 12 |
nicklas |
2073 |
<sect2 id="extensions_developer.logging"> |
6080 |
07 Aug 12 |
nicklas |
2074 |
<title>Logging managers</title> |
6080 |
07 Aug 12 |
nicklas |
2075 |
|
6080 |
07 Aug 12 |
nicklas |
2076 |
<para> |
6080 |
07 Aug 12 |
nicklas |
2077 |
This extension point makes it possible to detect changes that are made to |
6080 |
07 Aug 12 |
nicklas |
2078 |
item and generate log entries in real time. The core will send notifications |
6080 |
07 Aug 12 |
nicklas |
2079 |
for all item creations, updates and deletions to all registered logging |
6080 |
07 Aug 12 |
nicklas |
2080 |
managers. It is up to each implementation to decide if an event should be |
6080 |
07 Aug 12 |
nicklas |
2081 |
logged, where to log it and how much information that should be stored. |
6080 |
07 Aug 12 |
nicklas |
2082 |
The BASE core provides a logging implementation that save some information |
6080 |
07 Aug 12 |
nicklas |
2083 |
to the database which can also be viewed through the web interface. |
6080 |
07 Aug 12 |
nicklas |
2084 |
</para> |
6080 |
07 Aug 12 |
nicklas |
2085 |
|
6080 |
07 Aug 12 |
nicklas |
2086 |
<para> |
6080 |
07 Aug 12 |
nicklas |
2087 |
The logging mechanism works on the data layer level and hooks into |
6080 |
07 Aug 12 |
nicklas |
2088 |
callbacks provided by Hibernate. <interfacename |
6080 |
07 Aug 12 |
nicklas |
2089 |
docapi="net.sf.basedb.core.log">EntityLogger</interfacename>:s are used to |
6080 |
07 Aug 12 |
nicklas |
2090 |
extract relevant information from Hibernate and create log entries. |
6080 |
07 Aug 12 |
nicklas |
2091 |
While it is possible to have a generic logger it is usually better |
6080 |
07 Aug 12 |
nicklas |
2092 |
to have different implementations depending on the type of entity that |
6080 |
07 Aug 12 |
nicklas |
2093 |
was changed. For example, a change in a child item should, for usability |
6080 |
07 Aug 12 |
nicklas |
2094 |
reasons, be logged as a change in the parent item. Entity loggers |
6080 |
07 Aug 12 |
nicklas |
2095 |
are created by a <interfacename |
6080 |
07 Aug 12 |
nicklas |
2096 |
docapi="net.sf.basedb.core.log">LogManagerFactory</interfacename>. All changes |
6080 |
07 Aug 12 |
nicklas |
2097 |
made in a single transaction are usually collected by a <interfacename |
6080 |
07 Aug 12 |
nicklas |
2098 |
docapi="net.sf.basedb.core.log">LogManager</interfacename> which is also |
6080 |
07 Aug 12 |
nicklas |
2099 |
created by the factory. |
6080 |
07 Aug 12 |
nicklas |
2100 |
</para> |
6080 |
07 Aug 12 |
nicklas |
2101 |
|
6080 |
07 Aug 12 |
nicklas |
2102 |
<sect3 id="extensions_developer.logging.factory"> |
6080 |
07 Aug 12 |
nicklas |
2103 |
<title>The LogManagerFactory interface</title> |
6080 |
07 Aug 12 |
nicklas |
2104 |
|
6080 |
07 Aug 12 |
nicklas |
2105 |
<para> |
6080 |
07 Aug 12 |
nicklas |
2106 |
Each registered action factory shoulds create a <interfacename |
6080 |
07 Aug 12 |
nicklas |
2107 |
docapi="net.sf.basedb.core.log">LogManagerFactory</interfacename> |
6080 |
07 Aug 12 |
nicklas |
2108 |
that is used throughout a single transaction. If the factory is |
6080 |
07 Aug 12 |
nicklas |
2109 |
thread-safe, the same instance can be re-used for multiple requests |
6080 |
07 Aug 12 |
nicklas |
2110 |
at the same time. Here is a list of |
6080 |
07 Aug 12 |
nicklas |
2111 |
the methods the factory must implement: |
6080 |
07 Aug 12 |
nicklas |
2112 |
</para> |
6080 |
07 Aug 12 |
nicklas |
2113 |
|
6080 |
07 Aug 12 |
nicklas |
2114 |
<variablelist> |
6080 |
07 Aug 12 |
nicklas |
2115 |
<varlistentry> |
6080 |
07 Aug 12 |
nicklas |
2116 |
<term> |
6080 |
07 Aug 12 |
nicklas |
2117 |
<methodsynopsis language="java"> |
6080 |
07 Aug 12 |
nicklas |
2118 |
<modifier>public</modifier> |
6080 |
07 Aug 12 |
nicklas |
2119 |
<type>LogManager</type> |
6080 |
07 Aug 12 |
nicklas |
2120 |
<methodname>getLogManager</methodname> |
6080 |
07 Aug 12 |
nicklas |
2121 |
<methodparam> |
6080 |
07 Aug 12 |
nicklas |
2122 |
<type>LogControl</type> |
6080 |
07 Aug 12 |
nicklas |
2123 |
<parameter>logControl</parameter> |
6080 |
07 Aug 12 |
nicklas |
2124 |
</methodparam> |
6080 |
07 Aug 12 |
nicklas |
2125 |
</methodsynopsis> |
6080 |
07 Aug 12 |
nicklas |
2126 |
</term> |
6080 |
07 Aug 12 |
nicklas |
2127 |
<listitem> |
6080 |
07 Aug 12 |
nicklas |
2128 |
<para> |
6080 |
07 Aug 12 |
nicklas |
2129 |
Creates a log manager for a single transaction. Since a transaction |
6080 |
07 Aug 12 |
nicklas |
2130 |
is not thread-safe the log manager implementation doesn't have to |
6080 |
07 Aug 12 |
nicklas |
2131 |
be either. The factory has the possibility to create new log managers |
6080 |
07 Aug 12 |
nicklas |
2132 |
for each transaction. |
6080 |
07 Aug 12 |
nicklas |
2133 |
</para> |
6080 |
07 Aug 12 |
nicklas |
2134 |
</listitem> |
6080 |
07 Aug 12 |
nicklas |
2135 |
</varlistentry> |
6080 |
07 Aug 12 |
nicklas |
2136 |
|
6080 |
07 Aug 12 |
nicklas |
2137 |
<varlistentry> |
6080 |
07 Aug 12 |
nicklas |
2138 |
<term> |
6080 |
07 Aug 12 |
nicklas |
2139 |
<methodsynopsis language="java"> |
6080 |
07 Aug 12 |
nicklas |
2140 |
<modifier>public</modifier> |
6080 |
07 Aug 12 |
nicklas |
2141 |
<type>boolean</type> |
6080 |
07 Aug 12 |
nicklas |
2142 |
<methodname>isLoggable</methodname> |
6080 |
07 Aug 12 |
nicklas |
2143 |
<methodparam> |
6080 |
07 Aug 12 |
nicklas |
2144 |
<type>Object</type> |
6080 |
07 Aug 12 |
nicklas |
2145 |
<parameter>entity</parameter> |
6080 |
07 Aug 12 |
nicklas |
2146 |
</methodparam> |
6080 |
07 Aug 12 |
nicklas |
2147 |
</methodsynopsis> |
6080 |
07 Aug 12 |
nicklas |
2148 |
</term> |
6080 |
07 Aug 12 |
nicklas |
2149 |
<listitem> |
6080 |
07 Aug 12 |
nicklas |
2150 |
<para> |
6080 |
07 Aug 12 |
nicklas |
2151 |
Checks if changes to the given entity should be |
6080 |
07 Aug 12 |
nicklas |
2152 |
logged or not. For performance reasons, it usually makes sense to |
6080 |
07 Aug 12 |
nicklas |
2153 |
not log everything. For example, the database logger implementation |
6080 |
07 Aug 12 |
nicklas |
2154 |
only logs changes if the entity implements the <interfacename |
6080 |
07 Aug 12 |
nicklas |
2155 |
docapi="net.sf.basedb.core.data">LoggableData</interfacename> |
6080 |
07 Aug 12 |
nicklas |
2156 |
interface. The return value of this method should be consistent |
6080 |
07 Aug 12 |
nicklas |
2157 |
with <methodname>getEntityLogger()</methodname>. |
6080 |
07 Aug 12 |
nicklas |
2158 |
</para> |
6080 |
07 Aug 12 |
nicklas |
2159 |
</listitem> |
6080 |
07 Aug 12 |
nicklas |
2160 |
</varlistentry> |
6080 |
07 Aug 12 |
nicklas |
2161 |
|
6080 |
07 Aug 12 |
nicklas |
2162 |
<varlistentry> |
6080 |
07 Aug 12 |
nicklas |
2163 |
<term> |
6080 |
07 Aug 12 |
nicklas |
2164 |
<methodsynopsis language="java"> |
6080 |
07 Aug 12 |
nicklas |
2165 |
<modifier>public</modifier> |
6080 |
07 Aug 12 |
nicklas |
2166 |
<type>EntityLogger</type> |
6080 |
07 Aug 12 |
nicklas |
2167 |
<methodname>getEntityLogger</methodname> |
6080 |
07 Aug 12 |
nicklas |
2168 |
<methodparam> |
6080 |
07 Aug 12 |
nicklas |
2169 |
<type>LogManager</type> |
6080 |
07 Aug 12 |
nicklas |
2170 |
<parameter>logManager</parameter> |
6080 |
07 Aug 12 |
nicklas |
2171 |
</methodparam> |
6080 |
07 Aug 12 |
nicklas |
2172 |
<methodparam> |
6080 |
07 Aug 12 |
nicklas |
2173 |
<type>Object</type> |
6080 |
07 Aug 12 |
nicklas |
2174 |
<parameter>entity</parameter> |
6080 |
07 Aug 12 |
nicklas |
2175 |
</methodparam> |
6080 |
07 Aug 12 |
nicklas |
2176 |
</methodsynopsis> |
6080 |
07 Aug 12 |
nicklas |
2177 |
</term> |
6080 |
07 Aug 12 |
nicklas |
2178 |
<listitem> |
6080 |
07 Aug 12 |
nicklas |
2179 |
<para> |
6080 |
07 Aug 12 |
nicklas |
2180 |
Create or get an entity logger that knows how to log |
6080 |
07 Aug 12 |
nicklas |
2181 |
changes to the given entity. If the entity should not be |
6080 |
07 Aug 12 |
nicklas |
2182 |
logged, <constant>null</constant> can be returned. This method |
6080 |
07 Aug 12 |
nicklas |
2183 |
is called for each modified item in the transaction. |
6080 |
07 Aug 12 |
nicklas |
2184 |
</para> |
6080 |
07 Aug 12 |
nicklas |
2185 |
</listitem> |
6080 |
07 Aug 12 |
nicklas |
2186 |
</varlistentry> |
6080 |
07 Aug 12 |
nicklas |
2187 |
</variablelist> |
6080 |
07 Aug 12 |
nicklas |
2188 |
|
6080 |
07 Aug 12 |
nicklas |
2189 |
</sect3> |
6080 |
07 Aug 12 |
nicklas |
2190 |
|
6080 |
07 Aug 12 |
nicklas |
2191 |
<sect3 id="extensions_developer.logging.manager"> |
6080 |
07 Aug 12 |
nicklas |
2192 |
<title>The LogManager interface</title> |
6080 |
07 Aug 12 |
nicklas |
2193 |
|
6080 |
07 Aug 12 |
nicklas |
2194 |
<para> |
6080 |
07 Aug 12 |
nicklas |
2195 |
A new log manager is created for each transaction. The log manager |
6080 |
07 Aug 12 |
nicklas |
2196 |
is responsible for collecting all changes made in the transaction |
6080 |
07 Aug 12 |
nicklas |
2197 |
and store those changes in the appropriate place. The interface doesn't define |
6080 |
07 Aug 12 |
nicklas |
2198 |
any methods for this collection, since each implementation may have |
6080 |
07 Aug 12 |
nicklas |
2199 |
very different needs. |
6080 |
07 Aug 12 |
nicklas |
2200 |
</para> |
6080 |
07 Aug 12 |
nicklas |
2201 |
|
6080 |
07 Aug 12 |
nicklas |
2202 |
<variablelist> |
6080 |
07 Aug 12 |
nicklas |
2203 |
<varlistentry> |
6080 |
07 Aug 12 |
nicklas |
2204 |
<term> |
6080 |
07 Aug 12 |
nicklas |
2205 |
<methodsynopsis language="java"> |
6080 |
07 Aug 12 |
nicklas |
2206 |
<modifier>public</modifier> |
6080 |
07 Aug 12 |
nicklas |
2207 |
<type>LogControl</type> |
6080 |
07 Aug 12 |
nicklas |
2208 |
<methodname>getLogControl</methodname> |
6080 |
07 Aug 12 |
nicklas |
2209 |
</methodsynopsis> |
6080 |
07 Aug 12 |
nicklas |
2210 |
</term> |
6080 |
07 Aug 12 |
nicklas |
2211 |
<listitem> |
6080 |
07 Aug 12 |
nicklas |
2212 |
<para> |
6080 |
07 Aug 12 |
nicklas |
2213 |
Get the log control object that was supplied by the BASE core |
6080 |
07 Aug 12 |
nicklas |
2214 |
when the transaction was started. The log controller contains |
6080 |
07 Aug 12 |
nicklas |
2215 |
methods for accessing information about the transaction, such |
6080 |
07 Aug 12 |
nicklas |
2216 |
as the logged in user, executing plug-in, etc. It can also |
6080 |
07 Aug 12 |
nicklas |
2217 |
be used to execute queries against the database to get |
6080 |
07 Aug 12 |
nicklas |
2218 |
even more information. |
6080 |
07 Aug 12 |
nicklas |
2219 |
</para> |
6080 |
07 Aug 12 |
nicklas |
2220 |
|
6080 |
07 Aug 12 |
nicklas |
2221 |
<warning> |
6080 |
07 Aug 12 |
nicklas |
2222 |
<para> |
6080 |
07 Aug 12 |
nicklas |
2223 |
Be careful about the queries that are executed by the log |
6080 |
07 Aug 12 |
nicklas |
2224 |
controller. Since all logging code is executed at flush |
6080 |
07 Aug 12 |
nicklas |
2225 |
time in callbacks from Hibernate we are not allowed to |
6080 |
07 Aug 12 |
nicklas |
2226 |
use the regular session. Instead, all queries are sent |
6080 |
07 Aug 12 |
nicklas |
2227 |
through the stateless session. The stateless session has no |
6080 |
07 Aug 12 |
nicklas |
2228 |
caching functionality which means that Hibernate will use |
6080 |
07 Aug 12 |
nicklas |
2229 |
extra queries to load associations. Our recommendation is |
6080 |
07 Aug 12 |
nicklas |
2230 |
to avoid quires that return full entities, use scalar |
6080 |
07 Aug 12 |
nicklas |
2231 |
queries instead to just load the values that are needed. |
6080 |
07 Aug 12 |
nicklas |
2232 |
</para> |
6080 |
07 Aug 12 |
nicklas |
2233 |
</warning> |
6080 |
07 Aug 12 |
nicklas |
2234 |
</listitem> |
6080 |
07 Aug 12 |
nicklas |
2235 |
</varlistentry> |
6080 |
07 Aug 12 |
nicklas |
2236 |
<varlistentry> |
6080 |
07 Aug 12 |
nicklas |
2237 |
<term> |
6080 |
07 Aug 12 |
nicklas |
2238 |
<methodsynopsis language="java"> |
6080 |
07 Aug 12 |
nicklas |
2239 |
<modifier>public</modifier> |
6080 |
07 Aug 12 |
nicklas |
2240 |
<void/> |
6080 |
07 Aug 12 |
nicklas |
2241 |
<methodname>afterCommit</methodname> |
6080 |
07 Aug 12 |
nicklas |
2242 |
</methodsynopsis> |
6080 |
07 Aug 12 |
nicklas |
2243 |
</term> |
6080 |
07 Aug 12 |
nicklas |
2244 |
<term> |
6080 |
07 Aug 12 |
nicklas |
2245 |
<methodsynopsis language="java"> |
6080 |
07 Aug 12 |
nicklas |
2246 |
<modifier>public</modifier> |
6080 |
07 Aug 12 |
nicklas |
2247 |
<void/> |
6080 |
07 Aug 12 |
nicklas |
2248 |
<methodname>afterRollback</methodname> |
6080 |
07 Aug 12 |
nicklas |
2249 |
</methodsynopsis> |
6080 |
07 Aug 12 |
nicklas |
2250 |
</term> |
6080 |
07 Aug 12 |
nicklas |
2251 |
<listitem> |
6080 |
07 Aug 12 |
nicklas |
2252 |
Called after a successful commit or after a rollback. Note |
6080 |
07 Aug 12 |
nicklas |
2253 |
that the connection to the database has been closed at this |
6080 |
07 Aug 12 |
nicklas |
2254 |
time and it is not possible to save any more information to |
6080 |
07 Aug 12 |
nicklas |
2255 |
it at this time. |
6080 |
07 Aug 12 |
nicklas |
2256 |
</listitem> |
6080 |
07 Aug 12 |
nicklas |
2257 |
</varlistentry> |
6080 |
07 Aug 12 |
nicklas |
2258 |
</variablelist> |
6080 |
07 Aug 12 |
nicklas |
2259 |
</sect3> |
6080 |
07 Aug 12 |
nicklas |
2260 |
|
6080 |
07 Aug 12 |
nicklas |
2261 |
<sect3 id="extensions_developer.logging.entitylogger"> |
6080 |
07 Aug 12 |
nicklas |
2262 |
<title>The EntityLogger interface</title> |
6080 |
07 Aug 12 |
nicklas |
2263 |
|
6080 |
07 Aug 12 |
nicklas |
2264 |
<para> |
6080 |
07 Aug 12 |
nicklas |
2265 |
An entity logger is responsible for extracting the changes |
6080 |
07 Aug 12 |
nicklas |
2266 |
made to an entity and converting it to something that is useful |
6080 |
07 Aug 12 |
nicklas |
2267 |
as a log entry. In most cases, this is not very complicated, but |
6080 |
07 Aug 12 |
nicklas |
2268 |
in some cases, a change in one entity should actually be logged |
6080 |
07 Aug 12 |
nicklas |
2269 |
as a change in a different entity. For example, changes to |
6080 |
07 Aug 12 |
nicklas |
2270 |
annotations are handled by the <classname |
6080 |
07 Aug 12 |
nicklas |
2271 |
docapi="net.sf.basedb.core.log.db">AnnotationLogger</classname> which |
6080 |
07 Aug 12 |
nicklas |
2272 |
which log it as a change on the parent item. |
6080 |
07 Aug 12 |
nicklas |
2273 |
</para> |
6080 |
07 Aug 12 |
nicklas |
2274 |
|
6080 |
07 Aug 12 |
nicklas |
2275 |
<variablelist> |
6080 |
07 Aug 12 |
nicklas |
2276 |
<varlistentry> |
6080 |
07 Aug 12 |
nicklas |
2277 |
<term> |
6080 |
07 Aug 12 |
nicklas |
2278 |
<methodsynopsis language="java"> |
6080 |
07 Aug 12 |
nicklas |
2279 |
<modifier>public</modifier> |
6080 |
07 Aug 12 |
nicklas |
2280 |
<void/> |
6080 |
07 Aug 12 |
nicklas |
2281 |
<methodname>logChanges</methodname> |
6080 |
07 Aug 12 |
nicklas |
2282 |
<methodparam> |
6080 |
07 Aug 12 |
nicklas |
2283 |
<type>LogManager</type> |
6080 |
07 Aug 12 |
nicklas |
2284 |
<parameter>logManager</parameter> |
6080 |
07 Aug 12 |
nicklas |
2285 |
</methodparam> |
6080 |
07 Aug 12 |
nicklas |
2286 |
<methodparam> |
6080 |
07 Aug 12 |
nicklas |
2287 |
<type>EntityDetails</type> |
6080 |
07 Aug 12 |
nicklas |
2288 |
<parameter>details</parameter> |
6080 |
07 Aug 12 |
nicklas |
2289 |
</methodparam> |
6080 |
07 Aug 12 |
nicklas |
2290 |
</methodsynopsis> |
6080 |
07 Aug 12 |
nicklas |
2291 |
</term> |
6080 |
07 Aug 12 |
nicklas |
2292 |
<listitem> |
6080 |
07 Aug 12 |
nicklas |
2293 |
<para> |
6080 |
07 Aug 12 |
nicklas |
2294 |
This method is called whenever a change has been detected |
6080 |
07 Aug 12 |
nicklas |
2295 |
in an entity. The <varname>details</varname> variable contains |
6080 |
07 Aug 12 |
nicklas |
2296 |
information about the entity and, to a certain degree, |
6080 |
07 Aug 12 |
nicklas |
2297 |
what changes that has been made. |
6080 |
07 Aug 12 |
nicklas |
2298 |
</para> |
6080 |
07 Aug 12 |
nicklas |
2299 |
</listitem> |
6080 |
07 Aug 12 |
nicklas |
2300 |
</varlistentry> |
6080 |
07 Aug 12 |
nicklas |
2301 |
</variablelist> |
6080 |
07 Aug 12 |
nicklas |
2302 |
</sect3> |
6080 |
07 Aug 12 |
nicklas |
2303 |
|
6080 |
07 Aug 12 |
nicklas |
2304 |
</sect2> |
6080 |
07 Aug 12 |
nicklas |
2305 |
|
6080 |
07 Aug 12 |
nicklas |
2306 |
|
6048 |
18 Apr 12 |
nicklas |
2307 |
<sect2 id="extensions_developer.overview_loader"> |
6048 |
18 Apr 12 |
nicklas |
2308 |
<title>Item overview loaders</title> |
6048 |
18 Apr 12 |
nicklas |
2309 |
|
6048 |
18 Apr 12 |
nicklas |
2310 |
<para> |
6048 |
18 Apr 12 |
nicklas |
2311 |
The item overview functionality allow extensions to load more items in the tree |
6048 |
18 Apr 12 |
nicklas |
2312 |
structure. The extension point is a core extension point that is available |
6048 |
18 Apr 12 |
nicklas |
2313 |
independently of the web client. Actions should implement the |
6048 |
18 Apr 12 |
nicklas |
2314 |
<interfacename docapi="net.sf.basedb.util.overview.extensions">ChildNodeLoaderAction</interfacename> |
6048 |
18 Apr 12 |
nicklas |
2315 |
interface. We recommend that the actions also extend the |
6048 |
18 Apr 12 |
nicklas |
2316 |
<classname docapi="net.sf.basedb.util.overview.loader">BasicItemNodeLoader</classname> |
6048 |
18 Apr 12 |
nicklas |
2317 |
since this will make it easier to handle situations with missing items, permission |
6048 |
18 Apr 12 |
nicklas |
2318 |
problems and validation. Since each registered extension is checked for each item |
6048 |
18 Apr 12 |
nicklas |
2319 |
in the overview we recommend that the action factory makes a first filtering step |
6048 |
18 Apr 12 |
nicklas |
2320 |
before an action is created. This should be relatively simple since the current |
6048 |
18 Apr 12 |
nicklas |
2321 |
item in the <classname>ClientContext</classname> is the parent node. For example: |
6048 |
18 Apr 12 |
nicklas |
2322 |
</para> |
6048 |
18 Apr 12 |
nicklas |
2323 |
|
6048 |
18 Apr 12 |
nicklas |
2324 |
<programlisting language="java"> |
6048 |
18 Apr 12 |
nicklas |
2325 |
<![CDATA[ |
6048 |
18 Apr 12 |
nicklas |
2326 |
// From the ActionFactory interface |
6048 |
18 Apr 12 |
nicklas |
2327 |
public boolean prepareContext(InvokationContext<? super ChildNodeLoaderAction> context) |
6048 |
18 Apr 12 |
nicklas |
2328 |
{ |
6048 |
18 Apr 12 |
nicklas |
2329 |
Node parentNode = (Node)context.getClientContext().getCurrentItem(); |
6048 |
18 Apr 12 |
nicklas |
2330 |
if (parentNode != null) |
6048 |
18 Apr 12 |
nicklas |
2331 |
{ |
6048 |
18 Apr 12 |
nicklas |
2332 |
if (parentNode.getItem() instanceof Ownable) |
6048 |
18 Apr 12 |
nicklas |
2333 |
{ |
6048 |
18 Apr 12 |
nicklas |
2334 |
return true; |
6048 |
18 Apr 12 |
nicklas |
2335 |
} |
6048 |
18 Apr 12 |
nicklas |
2336 |
} |
6048 |
18 Apr 12 |
nicklas |
2337 |
return false; |
6048 |
18 Apr 12 |
nicklas |
2338 |
} |
6048 |
18 Apr 12 |
nicklas |
2339 |
]]> |
6048 |
18 Apr 12 |
nicklas |
2340 |
</programlisting> |
6048 |
18 Apr 12 |
nicklas |
2341 |
|
6048 |
18 Apr 12 |
nicklas |
2342 |
</sect2> |
5640 |
24 May 11 |
nicklas |
2343 |
|
6048 |
18 Apr 12 |
nicklas |
2344 |
<sect2 id="extensions_developer.overview_validator"> |
6048 |
18 Apr 12 |
nicklas |
2345 |
<title>Item overview validation</title> |
6048 |
18 Apr 12 |
nicklas |
2346 |
|
6048 |
18 Apr 12 |
nicklas |
2347 |
<para> |
6048 |
18 Apr 12 |
nicklas |
2348 |
The item overview functionality allow extensions to add validation code |
6048 |
18 Apr 12 |
nicklas |
2349 |
to any item in the tree. There are two co-existing extension points, one |
6048 |
18 Apr 12 |
nicklas |
2350 |
for the actual validation code and one for the validation rule defintions. |
6048 |
18 Apr 12 |
nicklas |
2351 |
Both extension points are core extension points that is available |
6048 |
18 Apr 12 |
nicklas |
2352 |
independently of the web client. Validation actions should implement the |
6048 |
18 Apr 12 |
nicklas |
2353 |
<interfacename docapi="net.sf.basedb.util.overview.extensions">NodeValidatorAction</interfacename> |
6048 |
18 Apr 12 |
nicklas |
2354 |
interface, which is simple the same as <interfacename docapi="net.sf.basedb.util.overview.validator">NodeValidator</interfacename> |
6048 |
18 Apr 12 |
nicklas |
2355 |
We recommend that the actions extend the |
6048 |
18 Apr 12 |
nicklas |
2356 |
<classname docapi="net.sf.basedb.util.overview.validator">NameableNodeValidator</classname> |
6048 |
18 Apr 12 |
nicklas |
2357 |
or <classname docapi="net.sf.basedb.util.overview.validator">BasicNodeValidator</classname> |
6048 |
18 Apr 12 |
nicklas |
2358 |
since this will make it easier to handle situations with missing items and permission |
6048 |
18 Apr 12 |
nicklas |
2359 |
problems. Since each registered extension is checked for each item |
6048 |
18 Apr 12 |
nicklas |
2360 |
in the overview we recommend that the action factory makes a first filtering step |
6048 |
18 Apr 12 |
nicklas |
2361 |
before an action is created. This should be relatively simple since the current |
6048 |
18 Apr 12 |
nicklas |
2362 |
item in the <classname>ClientContext</classname> is type of that should be validated. |
6048 |
18 Apr 12 |
nicklas |
2363 |
For example: |
6048 |
18 Apr 12 |
nicklas |
2364 |
</para> |
6048 |
18 Apr 12 |
nicklas |
2365 |
|
6048 |
18 Apr 12 |
nicklas |
2366 |
<programlisting language="java"> |
6048 |
18 Apr 12 |
nicklas |
2367 |
<![CDATA[ |
6048 |
18 Apr 12 |
nicklas |
2368 |
// From the ActionFactory interface |
6048 |
18 Apr 12 |
nicklas |
2369 |
public boolean prepareContext(InvokationContext<? super NodeValidatorAction> context) |
6048 |
18 Apr 12 |
nicklas |
2370 |
{ |
6048 |
18 Apr 12 |
nicklas |
2371 |
return context.getClientContext().getCurrentItem() == Item.USER; |
6048 |
18 Apr 12 |
nicklas |
2372 |
} |
6048 |
18 Apr 12 |
nicklas |
2373 |
]]> |
6048 |
18 Apr 12 |
nicklas |
2374 |
</programlisting> |
6048 |
18 Apr 12 |
nicklas |
2375 |
|
6048 |
18 Apr 12 |
nicklas |
2376 |
<para> |
6048 |
18 Apr 12 |
nicklas |
2377 |
Rule definition actions should implement the <interfacename |
6048 |
18 Apr 12 |
nicklas |
2378 |
docapi="net.sf.basedb.util.overview.extensions">ValidationRuleAction</interfacename>. |
6048 |
18 Apr 12 |
nicklas |
2379 |
This is simply a container with some information about the validation rule, such as |
6048 |
18 Apr 12 |
nicklas |
2380 |
a title, description and a default severity level. The |
6048 |
18 Apr 12 |
nicklas |
2381 |
<classname docapi="net.sf.basedb.util.overview">Validator</classname> class |
6048 |
18 Apr 12 |
nicklas |
2382 |
that ships with BASE already implements this interface. The <classname |
6048 |
18 Apr 12 |
nicklas |
2383 |
docapi="net.sf.basedb.util.overview.extensions">ReflectValidationRuleActionFactory</classname> |
6048 |
18 Apr 12 |
nicklas |
2384 |
can be used to return an existing <code>public static final</code> rule definition as an |
6048 |
18 Apr 12 |
nicklas |
2385 |
action: |
6048 |
18 Apr 12 |
nicklas |
2386 |
</para> |
6048 |
18 Apr 12 |
nicklas |
2387 |
|
6048 |
18 Apr 12 |
nicklas |
2388 |
<programlisting language="xml"> |
6048 |
18 Apr 12 |
nicklas |
2389 |
<![CDATA[ |
6048 |
18 Apr 12 |
nicklas |
2390 |
<extension |
6048 |
18 Apr 12 |
nicklas |
2391 |
id="validationrule.invalid-url" |
6048 |
18 Apr 12 |
nicklas |
2392 |
extends="net.sf.basedb.util.overview.validationrule"> |
6048 |
18 Apr 12 |
nicklas |
2393 |
<index>4</index> |
6048 |
18 Apr 12 |
nicklas |
2394 |
<about> |
6048 |
18 Apr 12 |
nicklas |
2395 |
<name>Invalid URL</name> |
6048 |
18 Apr 12 |
nicklas |
2396 |
<description>Checks if an URL has a valid syntax.</description> |
6048 |
18 Apr 12 |
nicklas |
2397 |
</about> |
6048 |
18 Apr 12 |
nicklas |
2398 |
<action-factory> |
6048 |
18 Apr 12 |
nicklas |
2399 |
<factory-class> |
6048 |
18 Apr 12 |
nicklas |
2400 |
net.sf.basedb.util.overview.extensions.ReflectValidationRuleActionFactory |
6048 |
18 Apr 12 |
nicklas |
2401 |
</factory-class> |
6048 |
18 Apr 12 |
nicklas |
2402 |
<parameters> |
6048 |
18 Apr 12 |
nicklas |
2403 |
<field>net.sf.basedb.examples.extensions.overview.OwnerValidator.INVALID_URL</field> |
6048 |
18 Apr 12 |
nicklas |
2404 |
</parameters> |
6048 |
18 Apr 12 |
nicklas |
2405 |
</action-factory> |
6048 |
18 Apr 12 |
nicklas |
2406 |
</extension> |
6048 |
18 Apr 12 |
nicklas |
2407 |
]]> |
6048 |
18 Apr 12 |
nicklas |
2408 |
</programlisting> |
6048 |
18 Apr 12 |
nicklas |
2409 |
|
6048 |
18 Apr 12 |
nicklas |
2410 |
</sect2> |
6048 |
18 Apr 12 |
nicklas |
2411 |
|
6052 |
23 Apr 12 |
nicklas |
2412 |
<sect2 id="extensions_developer.overview_information"> |
6052 |
23 Apr 12 |
nicklas |
2413 |
<title>Item overview information</title> |
6052 |
23 Apr 12 |
nicklas |
2414 |
|
6052 |
23 Apr 12 |
nicklas |
2415 |
<para> |
6052 |
23 Apr 12 |
nicklas |
2416 |
The item overview functionality allow extensions to display additional information |
6052 |
23 Apr 12 |
nicklas |
2417 |
about the currently selected node in the right pane in the web interface. |
6052 |
23 Apr 12 |
nicklas |
2418 |
Each <interfacename docapi="net.sf.basedb.clients.web.extensions.section">SectionAction</interfacename> |
6052 |
23 Apr 12 |
nicklas |
2419 |
object that is created by extensions will result in an additional section in the |
6052 |
23 Apr 12 |
nicklas |
2420 |
GUI. Note that all extension factories are called for all nodes. The |
6052 |
23 Apr 12 |
nicklas |
2421 |
<methodname>ActionFactory.prepareContext()</methodname> should be used to enable/disable |
6052 |
23 Apr 12 |
nicklas |
2422 |
the extension depending on the node that is selected. BASE ships with the |
6052 |
23 Apr 12 |
nicklas |
2423 |
<classname docapi="net.sf.basedb.clients.web.extensions.section">IncludeContentSectionFactory</classname> |
6052 |
23 Apr 12 |
nicklas |
2424 |
factory implementation which allows a resourse (eg. another JSP script) to generate |
6052 |
23 Apr 12 |
nicklas |
2425 |
the content of the section. The current context is stored in a request-scoped |
6052 |
23 Apr 12 |
nicklas |
2426 |
attribute under the key given by <code>JspContext.ATTRIBUTE_KEY</code>. |
6052 |
23 Apr 12 |
nicklas |
2427 |
A JSP or servlet should use this to hook into the current flow. Here is a code example: |
6052 |
23 Apr 12 |
nicklas |
2428 |
</para> |
6052 |
23 Apr 12 |
nicklas |
2429 |
|
6052 |
23 Apr 12 |
nicklas |
2430 |
<programlisting language="java"> |
6052 |
23 Apr 12 |
nicklas |
2431 |
<![CDATA[ |
6052 |
23 Apr 12 |
nicklas |
2432 |
// Get the JspContext that was created on the main edit page |
6052 |
23 Apr 12 |
nicklas |
2433 |
final JspContext jspContext = (JspContext)request.getAttribute(JspContext.ATTRIBUTE_KEY); |
6052 |
23 Apr 12 |
nicklas |
2434 |
|
6052 |
23 Apr 12 |
nicklas |
2435 |
// The currently selected node is found in the context. |
6052 |
23 Apr 12 |
nicklas |
2436 |
final Node node = (Node)jspContext.getCurrentItem(); |
6052 |
23 Apr 12 |
nicklas |
2437 |
|
6052 |
23 Apr 12 |
nicklas |
2438 |
// Get the DbControl and SessionControl used to handle the request (do not close!) |
6052 |
23 Apr 12 |
nicklas |
2439 |
final DbControl dc = jspContext.getDbControl(); |
6052 |
23 Apr 12 |
nicklas |
2440 |
final SessionControl sc = dc.getSessionControl(); |
6052 |
23 Apr 12 |
nicklas |
2441 |
]]> |
6052 |
23 Apr 12 |
nicklas |
2442 |
</programlisting> |
6052 |
23 Apr 12 |
nicklas |
2443 |
|
6052 |
23 Apr 12 |
nicklas |
2444 |
</sect2> |
6052 |
23 Apr 12 |
nicklas |
2445 |
|
6052 |
23 Apr 12 |
nicklas |
2446 |
|
6050 |
19 Apr 12 |
nicklas |
2447 |
<sect2 id="extensions_developer.list_column"> |
6050 |
19 Apr 12 |
nicklas |
2448 |
<title>Table list columns</title> |
6050 |
19 Apr 12 |
nicklas |
2449 |
|
6050 |
19 Apr 12 |
nicklas |
2450 |
<para> |
6050 |
19 Apr 12 |
nicklas |
2451 |
This extension point makes it possible to add more columns to most major list pages |
6050 |
19 Apr 12 |
nicklas |
2452 |
in the web interface. Actions should implement the <interfacename |
6050 |
19 Apr 12 |
nicklas |
2453 |
docapi="net.sf.basedb.clients.web.extensions.list">ListColumnAction</interfacename> interface. |
6050 |
19 Apr 12 |
nicklas |
2454 |
This interface contains several methods which can be grouped into three main types: |
6050 |
19 Apr 12 |
nicklas |
2455 |
</para> |
6050 |
19 Apr 12 |
nicklas |
2456 |
|
6050 |
19 Apr 12 |
nicklas |
2457 |
<itemizedlist> |
6050 |
19 Apr 12 |
nicklas |
2458 |
<listitem> |
6050 |
19 Apr 12 |
nicklas |
2459 |
<para> |
6050 |
19 Apr 12 |
nicklas |
2460 |
Metadata methods, for example, the id and title of the column and if the column |
6050 |
19 Apr 12 |
nicklas |
2461 |
can be sorted, filtered, etc. |
6050 |
19 Apr 12 |
nicklas |
2462 |
</para> |
6050 |
19 Apr 12 |
nicklas |
2463 |
</listitem> |
6050 |
19 Apr 12 |
nicklas |
2464 |
|
6050 |
19 Apr 12 |
nicklas |
2465 |
<listitem> |
6050 |
19 Apr 12 |
nicklas |
2466 |
<para> |
6050 |
19 Apr 12 |
nicklas |
2467 |
Rendering information, for example, CSS class and style information that is |
6050 |
19 Apr 12 |
nicklas |
2468 |
used for the column header. |
6050 |
19 Apr 12 |
nicklas |
2469 |
</para> |
6050 |
19 Apr 12 |
nicklas |
2470 |
</listitem> |
6050 |
19 Apr 12 |
nicklas |
2471 |
|
6050 |
19 Apr 12 |
nicklas |
2472 |
<listitem> |
6050 |
19 Apr 12 |
nicklas |
2473 |
<para> |
6050 |
19 Apr 12 |
nicklas |
2474 |
Worker methods, that retrieve the value from the current item and format |
6050 |
19 Apr 12 |
nicklas |
2475 |
it for proper display. Different methods are used for the web display |
6050 |
19 Apr 12 |
nicklas |
2476 |
and for exporting to a file. |
6050 |
19 Apr 12 |
nicklas |
2477 |
</para> |
6050 |
19 Apr 12 |
nicklas |
2478 |
</listitem> |
6050 |
19 Apr 12 |
nicklas |
2479 |
</itemizedlist> |
6050 |
19 Apr 12 |
nicklas |
2480 |
|
6050 |
19 Apr 12 |
nicklas |
2481 |
<para> |
6050 |
19 Apr 12 |
nicklas |
2482 |
The <classname docapi="net.sf.basedb.clients.web.extensions.list">AbstractListColumnBean</classname> |
6050 |
19 Apr 12 |
nicklas |
2483 |
class provides a bean-like implementation for all methods except the <methodname>getValue()</methodname> |
6050 |
19 Apr 12 |
nicklas |
2484 |
method. Extending from this class makes it easy to your own implementations. BASE ships with the |
6050 |
19 Apr 12 |
nicklas |
2485 |
<classname docapi="net.sf.basedb.clients.web.extensions.list">PropertyPathActionFactory</classname> |
6050 |
19 Apr 12 |
nicklas |
2486 |
factory that can be used without coding if the added column can be expressed as a property path that |
6050 |
19 Apr 12 |
nicklas |
2487 |
can be handled by the <classname docapi="net.sf.basedb.core">Metadata</classname> class. |
7982 |
14 Jun 21 |
nicklas |
2488 |
As usual, see the <ulink url="https://baseplugins.thep.lu.se/wiki/net.sf.basedb.examplecode">example code</ulink> |
6050 |
19 Apr 12 |
nicklas |
2489 |
for some examples. |
6050 |
19 Apr 12 |
nicklas |
2490 |
</para> |
6050 |
19 Apr 12 |
nicklas |
2491 |
|
6050 |
19 Apr 12 |
nicklas |
2492 |
</sect2> |
6048 |
18 Apr 12 |
nicklas |
2493 |
|
7915 |
24 Feb 21 |
nicklas |
2494 |
<sect2 id="extensions_developer.query_filters"> |
7915 |
24 Feb 21 |
nicklas |
2495 |
<title>Query filters</title> |
7915 |
24 Feb 21 |
nicklas |
2496 |
|
7915 |
24 Feb 21 |
nicklas |
2497 |
<para> |
7915 |
24 Feb 21 |
nicklas |
2498 |
This extension point makes it possible to extend filtering |
7915 |
24 Feb 21 |
nicklas |
2499 |
functionality for queries that are generated by list pages via the |
7915 |
24 Feb 21 |
nicklas |
2500 |
<methodname>ItemContext.configureQuery()</methodname> method in the |
7915 |
24 Feb 21 |
nicklas |
2501 |
<classname docapi="net.sf.basedb.core">ItemContext</classname> class. |
7915 |
24 Feb 21 |
nicklas |
2502 |
|
7915 |
24 Feb 21 |
nicklas |
2503 |
Actions should implement the <interfacename |
7915 |
24 Feb 21 |
nicklas |
2504 |
docapi="net.sf.basedb.core.query">QueryFilterAction</interfacename> |
7915 |
24 Feb 21 |
nicklas |
2505 |
interface. This interface allows an extension to filter a query based |
7915 |
24 Feb 21 |
nicklas |
2506 |
on a single column filter, a filter row or a combination of everything. |
7915 |
24 Feb 21 |
nicklas |
2507 |
</para> |
7915 |
24 Feb 21 |
nicklas |
2508 |
|
7915 |
24 Feb 21 |
nicklas |
2509 |
<para> |
7915 |
24 Feb 21 |
nicklas |
2510 |
Note that the <methodname>ActionFactory.prepareContext()</methodname> is |
7915 |
24 Feb 21 |
nicklas |
2511 |
called for all filter extensions at all times. It is recommended that |
7915 |
24 Feb 21 |
nicklas |
2512 |
the implementation checks the current context for the type of items in the |
7915 |
24 Feb 21 |
nicklas |
2513 |
list and if there is a filter in a column that the extension should handle. |
7915 |
24 Feb 21 |
nicklas |
2514 |
An extension may override the default implementation of any filter, but this |
7915 |
24 Feb 21 |
nicklas |
2515 |
is not recommended. The recommended design is to combine the filter |
7915 |
24 Feb 21 |
nicklas |
2516 |
extension with a custom column that uses the <code>!x.</code> prefix |
7915 |
24 Feb 21 |
nicklas |
2517 |
as the column id. Here is an example from the Variant Search extension |
7982 |
14 Jun 21 |
nicklas |
2518 |
(<ulink url="https://baseplugins.thep.lu.se/wiki/net.sf.basedb.varsearch" |
7982 |
14 Jun 21 |
nicklas |
2519 |
>https://baseplugins.thep.lu.se/wiki/net.sf.basedb.varsearch</ulink>): |
7915 |
24 Feb 21 |
nicklas |
2520 |
</para> |
7915 |
24 Feb 21 |
nicklas |
2521 |
|
7915 |
24 Feb 21 |
nicklas |
2522 |
<programlisting language="java"> |
7915 |
24 Feb 21 |
nicklas |
2523 |
<![CDATA[ |
7915 |
24 Feb 21 |
nicklas |
2524 |
public boolean prepareContext(InvokationContext<? super QueryFilterAction> context) |
7915 |
24 Feb 21 |
nicklas |
2525 |
{ |
7915 |
24 Feb 21 |
nicklas |
2526 |
// Enabled in the RAWBIOASSAY list page |
7915 |
24 Feb 21 |
nicklas |
2527 |
// and if the !x.lucene column is present with a filter |
7915 |
24 Feb 21 |
nicklas |
2528 |
// and if the service database is running |
7915 |
24 Feb 21 |
nicklas |
2529 |
ItemContext ctx = context.getClientContext().getCurrentItem(); |
7915 |
24 Feb 21 |
nicklas |
2530 |
return ctx.getItemType() == Item.RAWBIOASSAY && |
7915 |
24 Feb 21 |
nicklas |
2531 |
ctx.hasExtensionFilter("lucene") && |
7915 |
24 Feb 21 |
nicklas |
2532 |
VarSearchService.getInstance().isRunning(); |
7915 |
24 Feb 21 |
nicklas |
2533 |
} |
7915 |
24 Feb 21 |
nicklas |
2534 |
]]> |
7915 |
24 Feb 21 |
nicklas |
2535 |
</programlisting> |
7915 |
24 Feb 21 |
nicklas |
2536 |
|
7915 |
24 Feb 21 |
nicklas |
2537 |
|
7915 |
24 Feb 21 |
nicklas |
2538 |
</sect2> |
7915 |
24 Feb 21 |
nicklas |
2539 |
|
6429 |
10 Mar 14 |
nicklas |
2540 |
<sect2 id="extensions_developer.login-manager"> |
6429 |
10 Mar 14 |
nicklas |
2541 |
<title>Login manager</title> |
6429 |
10 Mar 14 |
nicklas |
2542 |
<para> |
6429 |
10 Mar 14 |
nicklas |
2543 |
This extension point makes it possible to authenticate users by some other means than |
6429 |
10 Mar 14 |
nicklas |
2544 |
the regular internal username+password authentication. Authentication managers should |
6429 |
10 Mar 14 |
nicklas |
2545 |
implement the <classname docapi="net.sf.basedb.core.authentication">AuthenticationManager</classname> |
7543 |
06 Dec 18 |
nicklas |
2546 |
action interface. This interface is simple and the only method that is required to implement |
7543 |
06 Dec 18 |
nicklas |
2547 |
is the parameter-less <methodname>authenticate()</methodname> method. There are three outcomes: |
6429 |
10 Mar 14 |
nicklas |
2548 |
</para> |
6429 |
10 Mar 14 |
nicklas |
2549 |
|
6429 |
10 Mar 14 |
nicklas |
2550 |
<itemizedlist> |
6429 |
10 Mar 14 |
nicklas |
2551 |
<listitem> |
6429 |
10 Mar 14 |
nicklas |
2552 |
<para>A <classname docapi="net.sf.basedb.core.authentication">AuthenticatedUser</classname> |
6429 |
10 Mar 14 |
nicklas |
2553 |
is returned with information about a user that has passed authentication. |
6429 |
10 Mar 14 |
nicklas |
2554 |
</para> |
6429 |
10 Mar 14 |
nicklas |
2555 |
</listitem> |
6429 |
10 Mar 14 |
nicklas |
2556 |
|
6429 |
10 Mar 14 |
nicklas |
2557 |
<listitem> |
6429 |
10 Mar 14 |
nicklas |
2558 |
<para>A <constant>null</constant> value is returned to indicate that the manager could |
6429 |
10 Mar 14 |
nicklas |
2559 |
not determine if the login credentials are valid or not. The BASE core may try another |
6429 |
10 Mar 14 |
nicklas |
2560 |
authentication manager or use internal authentication. |
6429 |
10 Mar 14 |
nicklas |
2561 |
</para> |
6429 |
10 Mar 14 |
nicklas |
2562 |
</listitem> |
6429 |
10 Mar 14 |
nicklas |
2563 |
|
6429 |
10 Mar 14 |
nicklas |
2564 |
<listitem> |
6429 |
10 Mar 14 |
nicklas |
2565 |
<para>An exception is thrown to indicate that the manager has determined that |
6429 |
10 Mar 14 |
nicklas |
2566 |
the login credentials are invalid. |
6429 |
10 Mar 14 |
nicklas |
2567 |
</para> |
6429 |
10 Mar 14 |
nicklas |
2568 |
</listitem> |
6429 |
10 Mar 14 |
nicklas |
2569 |
|
6429 |
10 Mar 14 |
nicklas |
2570 |
</itemizedlist> |
6429 |
10 Mar 14 |
nicklas |
2571 |
|
6429 |
10 Mar 14 |
nicklas |
2572 |
<para> |
6429 |
10 Mar 14 |
nicklas |
2573 |
Since the action interface doesn't contain any parameters that contain information about the |
6429 |
10 Mar 14 |
nicklas |
2574 |
login request, the implementation need to get this from the <classname |
6429 |
10 Mar 14 |
nicklas |
2575 |
docapi="net.sf.basedb.util.extensions">ClientContext</classname> that is passed to the |
6429 |
10 Mar 14 |
nicklas |
2576 |
action factory. The <methodname>getCurrentItem()</methodname> item is a <classname |
6429 |
10 Mar 14 |
nicklas |
2577 |
docapi="net.sf.basedb.core.authentication">LoginRequest</classname> containing the login and |
6429 |
10 Mar 14 |
nicklas |
2578 |
password the user entered on the login page. The <classname>ClientContext</classname> |
6429 |
10 Mar 14 |
nicklas |
2579 |
ojbect can be cast to <classname docapi="net.sf.basedb.core">AuthenticationContext</classname> |
6429 |
10 Mar 14 |
nicklas |
2580 |
which provide some extra services to the authentication manager. |
6429 |
10 Mar 14 |
nicklas |
2581 |
</para> |
6429 |
10 Mar 14 |
nicklas |
2582 |
|
7543 |
06 Dec 18 |
nicklas |
2583 |
<sect3 id="extensions_developer.login-manager.multiple"> |
7543 |
06 Dec 18 |
nicklas |
2584 |
<title>Supporting multiple installed login managers</title> |
7543 |
06 Dec 18 |
nicklas |
2585 |
|
7543 |
06 Dec 18 |
nicklas |
2586 |
<para> |
7543 |
06 Dec 18 |
nicklas |
2587 |
As of BASE 3.14 it should be easier to support server configurations that |
7543 |
06 Dec 18 |
nicklas |
2588 |
include multiple login manages. The <code>login-form</code> attribute in the |
7543 |
06 Dec 18 |
nicklas |
2589 |
<classname>LoginRequest</classname> parameter contains the login form |
7543 |
06 Dec 18 |
nicklas |
2590 |
that was used by the user. A login manager should check this value |
7543 |
06 Dec 18 |
nicklas |
2591 |
to decide if the login request should be handled or not. Note that |
7543 |
06 Dec 18 |
nicklas |
2592 |
the value may be missing. |
7543 |
06 Dec 18 |
nicklas |
2593 |
</para> |
7543 |
06 Dec 18 |
nicklas |
2594 |
|
7543 |
06 Dec 18 |
nicklas |
2595 |
<para> |
7543 |
06 Dec 18 |
nicklas |
2596 |
The <classname docapi="net.sf.basedb.core.authentication">AuthenticationManager</classname> |
7543 |
06 Dec 18 |
nicklas |
2597 |
interface also includes an optional method, |
7543 |
06 Dec 18 |
nicklas |
2598 |
<methodname>vetoAuthenticatedUser(UserData, AuthenticatedUser)</methodname>. This method |
7543 |
06 Dec 18 |
nicklas |
2599 |
is only called if one of the installed login manager authenticated the user successfully. |
7543 |
06 Dec 18 |
nicklas |
2600 |
Then, all other installed login managers get a chance to raise a veto by throwing an |
7543 |
06 Dec 18 |
nicklas |
2601 |
exception from this method. A responsible login manager probably need to implement this |
7543 |
06 Dec 18 |
nicklas |
2602 |
method to detect if a user that is supposed to login with a specific method is trying to |
7543 |
06 Dec 18 |
nicklas |
2603 |
login with some other method. Examples of actual implementations can be found in the |
7543 |
06 Dec 18 |
nicklas |
2604 |
the <ulink |
7982 |
14 Jun 21 |
nicklas |
2605 |
url="https://baseplugins.thep.lu.se/wiki/net.sf.basedb.yubikey">YubiKey</ulink> |
7543 |
06 Dec 18 |
nicklas |
2606 |
and <ulink |
7982 |
14 Jun 21 |
nicklas |
2607 |
url="https://baseplugins.thep.lu.se/wiki/net.sf.basedb.otp">OTP</ulink> extensions. |
7543 |
06 Dec 18 |
nicklas |
2608 |
</para> |
7543 |
06 Dec 18 |
nicklas |
2609 |
|
7543 |
06 Dec 18 |
nicklas |
2610 |
</sect3> |
7543 |
06 Dec 18 |
nicklas |
2611 |
|
6429 |
10 Mar 14 |
nicklas |
2612 |
<sect3 id="extensions_developer.login-manager.internal-vs-external"> |
6429 |
10 Mar 14 |
nicklas |
2613 |
<title>Internal vs. external authentation</title> |
6429 |
10 Mar 14 |
nicklas |
2614 |
|
6429 |
10 Mar 14 |
nicklas |
2615 |
<para> |
6685 |
20 Jan 15 |
nicklas |
2616 |
All login requests are always sent to registered authentication |
6429 |
10 Mar 14 |
nicklas |
2617 |
managers first. Internal authentication is only used if no authentication |
6429 |
10 Mar 14 |
nicklas |
2618 |
manager could validate the user. Even with external authentication it is possible to |
6429 |
10 Mar 14 |
nicklas |
2619 |
let BASE cache the logins/passwords. This makes it possible to login to |
6429 |
10 Mar 14 |
nicklas |
2620 |
BASE if the external authentication server is down. |
6429 |
10 Mar 14 |
nicklas |
2621 |
</para> |
6429 |
10 Mar 14 |
nicklas |
2622 |
|
6429 |
10 Mar 14 |
nicklas |
2623 |
<note> |
6429 |
10 Mar 14 |
nicklas |
2624 |
<para> |
6429 |
10 Mar 14 |
nicklas |
2625 |
An external authentication server can only be used to grant or deny |
6429 |
10 Mar 14 |
nicklas |
2626 |
a user access to BASE. It cannot be used to give a user permissions, |
6429 |
10 Mar 14 |
nicklas |
2627 |
or put a user into groups or different roles inside BASE. |
6429 |
10 Mar 14 |
nicklas |
2628 |
</para> |
6429 |
10 Mar 14 |
nicklas |
2629 |
</note> |
6429 |
10 Mar 14 |
nicklas |
2630 |
|
6429 |
10 Mar 14 |
nicklas |
2631 |
<para> |
6429 |
10 Mar 14 |
nicklas |
2632 |
The authentication process goes something like this: |
6429 |
10 Mar 14 |
nicklas |
2633 |
|
6429 |
10 Mar 14 |
nicklas |
2634 |
<itemizedlist> |
6429 |
10 Mar 14 |
nicklas |
2635 |
<listitem> |
6429 |
10 Mar 14 |
nicklas |
2636 |
<para> |
6429 |
10 Mar 14 |
nicklas |
2637 |
An external authentication manager determines that the login request |
6429 |
10 Mar 14 |
nicklas |
2638 |
is valid and the user is already known to BASE. |
6429 |
10 Mar 14 |
nicklas |
2639 |
If the extra information (name, email, phone, etc.) is supplied |
6429 |
10 Mar 14 |
nicklas |
2640 |
and the <property>auth.synchronize</property> setting |
6429 |
10 Mar 14 |
nicklas |
2641 |
is <constant>TRUE</constant> the extra information is copied to |
6429 |
10 Mar 14 |
nicklas |
2642 |
the BASE server. |
6429 |
10 Mar 14 |
nicklas |
2643 |
</para> |
6429 |
10 Mar 14 |
nicklas |
2644 |
</listitem> |
6429 |
10 Mar 14 |
nicklas |
2645 |
|
6429 |
10 Mar 14 |
nicklas |
2646 |
<listitem> |
6429 |
10 Mar 14 |
nicklas |
2647 |
<para> |
6429 |
10 Mar 14 |
nicklas |
2648 |
An external authentication manager determines that the login request |
6429 |
10 Mar 14 |
nicklas |
2649 |
is valid, but the user is not known to BASE. This happens |
6429 |
10 Mar 14 |
nicklas |
2650 |
the first time a user logs in. BASE will create |
6429 |
10 Mar 14 |
nicklas |
2651 |
a new user account. If the authentication manager provides extra information, it |
6429 |
10 Mar 14 |
nicklas |
2652 |
is copied to the BASE server (even if <property>auth.synchronize</property> |
6429 |
10 Mar 14 |
nicklas |
2653 |
is not set). The new user account will get the default quota |
6429 |
10 Mar 14 |
nicklas |
2654 |
and be added to the all roles and groups which has been |
6429 |
10 Mar 14 |
nicklas |
2655 |
marked as <emphasis>default</emphasis>. |
6429 |
10 Mar 14 |
nicklas |
2656 |
</para> |
6429 |
10 Mar 14 |
nicklas |
2657 |
</listitem> |
6429 |
10 Mar 14 |
nicklas |
2658 |
|
6429 |
10 Mar 14 |
nicklas |
2659 |
<listitem> |
6429 |
10 Mar 14 |
nicklas |
2660 |
<para> |
6429 |
10 Mar 14 |
nicklas |
2661 |
If password caching is enabled, the password is copied to BASE. |
6429 |
10 Mar 14 |
nicklas |
2662 |
If an expiration timeout has been set, an expiration date |
6429 |
10 Mar 14 |
nicklas |
2663 |
will be calculated and set on the user account. The expiration |
6429 |
10 Mar 14 |
nicklas |
2664 |
date is only checked when the external authentication server is |
6429 |
10 Mar 14 |
nicklas |
2665 |
down. |
6429 |
10 Mar 14 |
nicklas |
2666 |
</para> |
6429 |
10 Mar 14 |
nicklas |
2667 |
</listitem> |
6429 |
10 Mar 14 |
nicklas |
2668 |
|
6429 |
10 Mar 14 |
nicklas |
2669 |
<listitem> |
6429 |
10 Mar 14 |
nicklas |
2670 |
<para> |
6429 |
10 Mar 14 |
nicklas |
2671 |
The external authentication manager says that the login is invalid or |
6429 |
10 Mar 14 |
nicklas |
2672 |
the password is incorrect. The user will not be logged in. |
6429 |
10 Mar 14 |
nicklas |
2673 |
</para> |
6429 |
10 Mar 14 |
nicklas |
2674 |
</listitem> |
6429 |
10 Mar 14 |
nicklas |
2675 |
|
6429 |
10 Mar 14 |
nicklas |
2676 |
<listitem> |
6429 |
10 Mar 14 |
nicklas |
2677 |
<para> |
6429 |
10 Mar 14 |
nicklas |
2678 |
The authentication manager says that something else is wrong. |
6429 |
10 Mar 14 |
nicklas |
2679 |
If password caching is enabled, internal authentication will be |
6429 |
10 Mar 14 |
nicklas |
2680 |
used. Otherwise the user will not be logged in. |
6429 |
10 Mar 14 |
nicklas |
2681 |
</para> |
6429 |
10 Mar 14 |
nicklas |
2682 |
</listitem> |
6429 |
10 Mar 14 |
nicklas |
2683 |
</itemizedlist> |
6429 |
10 Mar 14 |
nicklas |
2684 |
|
6429 |
10 Mar 14 |
nicklas |
2685 |
</para> |
6429 |
10 Mar 14 |
nicklas |
2686 |
</sect3> |
6429 |
10 Mar 14 |
nicklas |
2687 |
|
8045 |
03 Jun 22 |
nicklas |
2688 |
<sect3 id="extensions_developer.login-manager.settings"> |
6429 |
10 Mar 14 |
nicklas |
2689 |
<title>Configuration settings</title> |
6429 |
10 Mar 14 |
nicklas |
2690 |
|
6429 |
10 Mar 14 |
nicklas |
2691 |
<para> |
6429 |
10 Mar 14 |
nicklas |
2692 |
The configuration settings for the authentication system are located |
6429 |
10 Mar 14 |
nicklas |
2693 |
in the <filename>base.config</filename> file. |
6429 |
10 Mar 14 |
nicklas |
2694 |
Here is an overview of the settings. For more information read |
6429 |
10 Mar 14 |
nicklas |
2695 |
<xref linkend="appendix.base.config.authentication" />. |
6429 |
10 Mar 14 |
nicklas |
2696 |
</para> |
6429 |
10 Mar 14 |
nicklas |
2697 |
|
6429 |
10 Mar 14 |
nicklas |
2698 |
<variablelist> |
6429 |
10 Mar 14 |
nicklas |
2699 |
<varlistentry> |
6429 |
10 Mar 14 |
nicklas |
2700 |
<term><property>auth.synchronize</property></term> |
6429 |
10 Mar 14 |
nicklas |
2701 |
<listitem> |
6429 |
10 Mar 14 |
nicklas |
2702 |
<para> |
6429 |
10 Mar 14 |
nicklas |
2703 |
If extra user information is synchronized at login time or not. |
6429 |
10 Mar 14 |
nicklas |
2704 |
This setting is ignored if the driver does not support extra information. |
6429 |
10 Mar 14 |
nicklas |
2705 |
</para> |
6429 |
10 Mar 14 |
nicklas |
2706 |
</listitem> |
6429 |
10 Mar 14 |
nicklas |
2707 |
</varlistentry> |
6429 |
10 Mar 14 |
nicklas |
2708 |
|
6429 |
10 Mar 14 |
nicklas |
2709 |
<varlistentry> |
6429 |
10 Mar 14 |
nicklas |
2710 |
<term><property>auth.cachepasswords</property></term> |
6429 |
10 Mar 14 |
nicklas |
2711 |
<listitem> |
6429 |
10 Mar 14 |
nicklas |
2712 |
<para> |
6429 |
10 Mar 14 |
nicklas |
2713 |
If passwords should be cached by BASE or not. If the passwords are |
6429 |
10 Mar 14 |
nicklas |
2714 |
cached a user may login to BASE even if the external authentication |
6429 |
10 Mar 14 |
nicklas |
2715 |
server is down. |
6429 |
10 Mar 14 |
nicklas |
2716 |
</para> |
6429 |
10 Mar 14 |
nicklas |
2717 |
</listitem> |
6429 |
10 Mar 14 |
nicklas |
2718 |
</varlistentry> |
6429 |
10 Mar 14 |
nicklas |
2719 |
|
6429 |
10 Mar 14 |
nicklas |
2720 |
<varlistentry> |
6429 |
10 Mar 14 |
nicklas |
2721 |
<term><property>auth.daystocache</property></term> |
6429 |
10 Mar 14 |
nicklas |
2722 |
<listitem> |
6429 |
10 Mar 14 |
nicklas |
2723 |
<para> |
6429 |
10 Mar 14 |
nicklas |
2724 |
How many days to cache the passwords if caching has been enabled. |
6429 |
10 Mar 14 |
nicklas |
2725 |
A value of 0 caches the passwords for ever. |
6429 |
10 Mar 14 |
nicklas |
2726 |
</para> |
6429 |
10 Mar 14 |
nicklas |
2727 |
</listitem> |
6429 |
10 Mar 14 |
nicklas |
2728 |
</varlistentry> |
6429 |
10 Mar 14 |
nicklas |
2729 |
</variablelist> |
6429 |
10 Mar 14 |
nicklas |
2730 |
</sect3> |
6429 |
10 Mar 14 |
nicklas |
2731 |
|
6429 |
10 Mar 14 |
nicklas |
2732 |
</sect2> |
6429 |
10 Mar 14 |
nicklas |
2733 |
|
6429 |
10 Mar 14 |
nicklas |
2734 |
<sect2 id="extensions_developer.login-form"> |
6429 |
10 Mar 14 |
nicklas |
2735 |
<title>Login form</title> |
6429 |
10 Mar 14 |
nicklas |
2736 |
|
6429 |
10 Mar 14 |
nicklas |
2737 |
<para> |
6429 |
10 Mar 14 |
nicklas |
2738 |
This extension point is typically used in combination with a login manager to provide a |
6429 |
10 Mar 14 |
nicklas |
2739 |
customized login form. Extensions should implement the <interfacename |
6429 |
10 Mar 14 |
nicklas |
2740 |
docapi="net.sf.basedb.clients.web.extensions.login">LoginFormAction</interfacename> |
6429 |
10 Mar 14 |
nicklas |
2741 |
action which is used to specify prompts, tooltips, help texts and styling information |
6429 |
10 Mar 14 |
nicklas |
2742 |
for the login and password fields. The extension point supports custom scripts and stylesheets. |
6429 |
10 Mar 14 |
nicklas |
2743 |
</para> |
6429 |
10 Mar 14 |
nicklas |
2744 |
|
6429 |
10 Mar 14 |
nicklas |
2745 |
<note> |
7543 |
06 Dec 18 |
nicklas |
2746 |
<title>As of BASE 3.14 it is possible to install multiple login managers</title> |
6429 |
10 Mar 14 |
nicklas |
2747 |
<para> |
7543 |
06 Dec 18 |
nicklas |
2748 |
All installed and enabled login forms are available in a selection list |
8045 |
03 Jun 22 |
nicklas |
2749 |
from which the user can select to switch to another login form. Since BASE 3.19.3 |
8045 |
03 Jun 22 |
nicklas |
2750 |
custom scripts and stylesheets are only loaded for the currently active form. |
8045 |
03 Jun 22 |
nicklas |
2751 |
In earlier BASE versions, custom scripts and stylesheets were loaded for all installed |
8045 |
03 Jun 22 |
nicklas |
2752 |
login forms. |
6429 |
10 Mar 14 |
nicklas |
2753 |
</para> |
7543 |
06 Dec 18 |
nicklas |
2754 |
<para> |
8045 |
03 Jun 22 |
nicklas |
2755 |
It is possible for both style sheets and scripts to verify that they are only used on |
8045 |
03 Jun 22 |
nicklas |
2756 |
the intended login form. BASE is setting two data-attributes on the |
7543 |
06 Dec 18 |
nicklas |
2757 |
<sgmltag class="starttag">body</sgmltag> tag: |
7543 |
06 Dec 18 |
nicklas |
2758 |
</para> |
7543 |
06 Dec 18 |
nicklas |
2759 |
|
7543 |
06 Dec 18 |
nicklas |
2760 |
<variablelist> |
7543 |
06 Dec 18 |
nicklas |
2761 |
<varlistentry> |
7543 |
06 Dec 18 |
nicklas |
2762 |
<term><property>data-login-form</property></term> |
7543 |
06 Dec 18 |
nicklas |
2763 |
<listitem> |
7543 |
06 Dec 18 |
nicklas |
2764 |
<para> |
7543 |
06 Dec 18 |
nicklas |
2765 |
The ID of the currently active login form. |
7543 |
06 Dec 18 |
nicklas |
2766 |
</para> |
7543 |
06 Dec 18 |
nicklas |
2767 |
</listitem> |
7543 |
06 Dec 18 |
nicklas |
2768 |
</varlistentry> |
7543 |
06 Dec 18 |
nicklas |
2769 |
<varlistentry> |
7543 |
06 Dec 18 |
nicklas |
2770 |
<term><property>data-requested-form</property></term> |
7543 |
06 Dec 18 |
nicklas |
2771 |
<listitem> |
7543 |
06 Dec 18 |
nicklas |
2772 |
<para> |
7543 |
06 Dec 18 |
nicklas |
2773 |
The ID of the login form that was requested. This may differ from the currently active |
7543 |
06 Dec 18 |
nicklas |
2774 |
if it is not installed or enabled. |
7543 |
06 Dec 18 |
nicklas |
2775 |
</para> |
7543 |
06 Dec 18 |
nicklas |
2776 |
</listitem> |
7543 |
06 Dec 18 |
nicklas |
2777 |
</varlistentry> |
7543 |
06 Dec 18 |
nicklas |
2778 |
</variablelist> |
7543 |
06 Dec 18 |
nicklas |
2779 |
|
7543 |
06 Dec 18 |
nicklas |
2780 |
<para> |
7543 |
06 Dec 18 |
nicklas |
2781 |
In CSS files, rules that are targeting elements on the login form should match |
7543 |
06 Dec 18 |
nicklas |
2782 |
against the <sgmltag class="attribute">data-login-form</sgmltag> attribute in the selector, |
7543 |
06 Dec 18 |
nicklas |
2783 |
for example: |
7543 |
06 Dec 18 |
nicklas |
2784 |
</para> |
7543 |
06 Dec 18 |
nicklas |
2785 |
|
7543 |
06 Dec 18 |
nicklas |
2786 |
<programlisting language="css"> |
7543 |
06 Dec 18 |
nicklas |
2787 |
/* Example from the YubiKey login form */ |
7543 |
06 Dec 18 |
nicklas |
2788 |
body[data-login-form="net.sf.basedb.yubikey.login-form"] |
7543 |
06 Dec 18 |
nicklas |
2789 |
#loginform #login-row th |
7543 |
06 Dec 18 |
nicklas |
2790 |
{ |
7543 |
06 Dec 18 |
nicklas |
2791 |
background-image: url('../images/yubico.png'); |
7543 |
06 Dec 18 |
nicklas |
2792 |
background-position: right center; |
7543 |
06 Dec 18 |
nicklas |
2793 |
background-repeat: no-repeat; |
7543 |
06 Dec 18 |
nicklas |
2794 |
padding-right: 20px; |
7543 |
06 Dec 18 |
nicklas |
2795 |
} |
7543 |
06 Dec 18 |
nicklas |
2796 |
</programlisting> |
7543 |
06 Dec 18 |
nicklas |
2797 |
|
7543 |
06 Dec 18 |
nicklas |
2798 |
<para> |
7543 |
06 Dec 18 |
nicklas |
2799 |
Scripts should also check the value of this attribute before doing stuff: |
7543 |
06 Dec 18 |
nicklas |
2800 |
</para> |
7543 |
06 Dec 18 |
nicklas |
2801 |
<programlisting language="javascript"> |
7543 |
06 Dec 18 |
nicklas |
2802 |
/* Examle from the OTP login form */ |
7543 |
06 Dec 18 |
nicklas |
2803 |
if (Data.get(document.body, 'login-form') != 'net.sf.basedb.otp.login-form') |
7543 |
06 Dec 18 |
nicklas |
2804 |
{ |
7543 |
06 Dec 18 |
nicklas |
2805 |
// Not the OTP login form |
7543 |
06 Dec 18 |
nicklas |
2806 |
return; |
7543 |
06 Dec 18 |
nicklas |
2807 |
} |
7543 |
06 Dec 18 |
nicklas |
2808 |
</programlisting> |
7543 |
06 Dec 18 |
nicklas |
2809 |
|
7543 |
06 Dec 18 |
nicklas |
2810 |
<para> |
7543 |
06 Dec 18 |
nicklas |
2811 |
When logging in, the ID of the selected login form is added to the |
7543 |
06 Dec 18 |
nicklas |
2812 |
<classname docapi="net.sf.basedb.core.authentication">LoginRequest</classname> |
7543 |
06 Dec 18 |
nicklas |
2813 |
with attribute name <code>login-form</code> so that login managers can |
7543 |
06 Dec 18 |
nicklas |
2814 |
pick it up and take action on it. |
7543 |
06 Dec 18 |
nicklas |
2815 |
</para> |
7543 |
06 Dec 18 |
nicklas |
2816 |
|
6429 |
10 Mar 14 |
nicklas |
2817 |
</note> |
6429 |
10 Mar 14 |
nicklas |
2818 |
|
8045 |
03 Jun 22 |
nicklas |
2819 |
<sect3 id="extensions_developer.login-form.before-login"> |
8045 |
03 Jun 22 |
nicklas |
2820 |
<title>The before-login event</title> |
8045 |
03 Jun 22 |
nicklas |
2821 |
|
8045 |
03 Jun 22 |
nicklas |
2822 |
<para> |
8045 |
03 Jun 22 |
nicklas |
2823 |
In BASE 3.19.3 the <code>before-login</code> was introduced. It is a custom event |
8045 |
03 Jun 22 |
nicklas |
2824 |
that is sent to the <sgmltag class="starttag">form</sgmltag> tag just before the |
8045 |
03 Jun 22 |
nicklas |
2825 |
login form is submitted to the server. Extensions may add event listeners for this |
8045 |
03 Jun 22 |
nicklas |
2826 |
event if they need to take some action and they have the possibility to cancel |
8045 |
03 Jun 22 |
nicklas |
2827 |
the submission by calling the <code>event.preventDefault()</code> method. |
8045 |
03 Jun 22 |
nicklas |
2828 |
</para> |
8045 |
03 Jun 22 |
nicklas |
2829 |
|
8045 |
03 Jun 22 |
nicklas |
2830 |
<para> |
8045 |
03 Jun 22 |
nicklas |
2831 |
This functionality is, for example, used by the <ulink |
8045 |
03 Jun 22 |
nicklas |
2832 |
url="https://baseplugins.thep.lu.se/wiki/net.sf.basedb.webauthn">WebAuthn</ulink> extension, |
8045 |
03 Jun 22 |
nicklas |
2833 |
which need to contact the server to get a <emphasis>challenge</emphasis>, ask the user |
8045 |
03 Jun 22 |
nicklas |
2834 |
to insert and click on the security key, and then return the signed challenge in the |
8045 |
03 Jun 22 |
nicklas |
2835 |
<code>extraField</code> before the login form is actually submitted. Since all of this |
8045 |
03 Jun 22 |
nicklas |
2836 |
is handled asynchronously the <code>before-login</code> event need to be cancelled. The login |
8045 |
03 Jun 22 |
nicklas |
2837 |
form can be submitted by calling <code>Login.submitLoginForm()</code>. |
8045 |
03 Jun 22 |
nicklas |
2838 |
</para> |
8045 |
03 Jun 22 |
nicklas |
2839 |
</sect3> |
6429 |
10 Mar 14 |
nicklas |
2840 |
</sect2> |
6628 |
26 Nov 14 |
nicklas |
2841 |
|
6628 |
26 Nov 14 |
nicklas |
2842 |
<sect2 id="extensions_developer.skins"> |
6628 |
26 Nov 14 |
nicklas |
2843 |
<title>Skins</title> |
6628 |
26 Nov 14 |
nicklas |
2844 |
|
6628 |
26 Nov 14 |
nicklas |
2845 |
<para> |
6628 |
26 Nov 14 |
nicklas |
2846 |
This extension point can be used to change the visual appearance of BASE. Contrary |
6628 |
26 Nov 14 |
nicklas |
2847 |
to other extension points, providing actions are optional. The skinning is |
6628 |
26 Nov 14 |
nicklas |
2848 |
done by having the action factory set style sheet and script files on the <classname |
6628 |
26 Nov 14 |
nicklas |
2849 |
docapi="net.sf.basedb.clients.web.extensions">JspContext</classname> instance. |
6628 |
26 Nov 14 |
nicklas |
2850 |
Typically the style sheet override or set some properties defined by the BASE |
6628 |
26 Nov 14 |
nicklas |
2851 |
core stylesheets. |
6628 |
26 Nov 14 |
nicklas |
2852 |
</para> |
6628 |
26 Nov 14 |
nicklas |
2853 |
|
6628 |
26 Nov 14 |
nicklas |
2854 |
<para> |
6628 |
26 Nov 14 |
nicklas |
2855 |
Actions may be provided and should then implement the <interfacename |
6628 |
26 Nov 14 |
nicklas |
2856 |
docapi="net.sf.basedb.clients.web.extensions.skin">SkinAction</interfacename> |
6628 |
26 Nov 14 |
nicklas |
2857 |
interface. Actions are needed if the skin extension wants to modify the |
6628 |
26 Nov 14 |
nicklas |
2858 |
fav-icon or include some data in a hidden <sgmltag class="starttag">div</sgmltag> |
6628 |
26 Nov 14 |
nicklas |
2859 |
tag. For this to work, the action must also implement the <interfacename |
6628 |
26 Nov 14 |
nicklas |
2860 |
docapi="net.sf.basedb.clients.web.extensions">DynamicActionAttributes</interfacename> |
6628 |
26 Nov 14 |
nicklas |
2861 |
interface, since only the dynamic attribute values are included in the web page. |
6628 |
26 Nov 14 |
nicklas |
2862 |
</para> |
6628 |
26 Nov 14 |
nicklas |
2863 |
|
6628 |
26 Nov 14 |
nicklas |
2864 |
<para> |
6628 |
26 Nov 14 |
nicklas |
2865 |
BASE provides a simple action factory implementation, |
6628 |
26 Nov 14 |
nicklas |
2866 |
<classname docapi="net.sf.basedb.clients.web.extensions.skin">FixedSkinActionFactory</classname>, |
6628 |
26 Nov 14 |
nicklas |
2867 |
that supports all of the above. |
6628 |
26 Nov 14 |
nicklas |
2868 |
</para> |
6628 |
26 Nov 14 |
nicklas |
2869 |
|
6628 |
26 Nov 14 |
nicklas |
2870 |
</sect2> |
7115 |
16 Mar 16 |
nicklas |
2871 |
|
7115 |
16 Mar 16 |
nicklas |
2872 |
<sect2 id="extensions_developer.start-page"> |
7115 |
16 Mar 16 |
nicklas |
2873 |
<title>Start page</title> |
7115 |
16 Mar 16 |
nicklas |
2874 |
|
7115 |
16 Mar 16 |
nicklas |
2875 |
<para> |
7115 |
16 Mar 16 |
nicklas |
2876 |
This extension point can be used to change the start page that is |
7115 |
16 Mar 16 |
nicklas |
2877 |
loaded after a use logs in to BASE. The normal start page is |
7115 |
16 Mar 16 |
nicklas |
2878 |
the <menuchoice> |
7115 |
16 Mar 16 |
nicklas |
2879 |
<guimenu>BASE</guimenu> |
7115 |
16 Mar 16 |
nicklas |
2880 |
<guimenuitem>Home</guimenuitem> |
7115 |
16 Mar 16 |
nicklas |
2881 |
</menuchoice> page. Extensions should implement the <interfacename |
7115 |
16 Mar 16 |
nicklas |
2882 |
docapi="net.sf.basedb.clients.web.extensions.startpage">StartPageAction</interfacename> |
7115 |
16 Mar 16 |
nicklas |
2883 |
interface. The current item in the <classname |
7115 |
16 Mar 16 |
nicklas |
2884 |
docapi="net.sf.basedb.clients.web.extensions">JspContext</classname> |
7115 |
16 Mar 16 |
nicklas |
2885 |
is the currently logged in user. All possible |
7115 |
16 Mar 16 |
nicklas |
2886 |
start pages will be listed as a user configuration in the |
7115 |
16 Mar 16 |
nicklas |
2887 |
<menuchoice> |
7115 |
16 Mar 16 |
nicklas |
2888 |
<guimenu>BASE</guimenu> |
7115 |
16 Mar 16 |
nicklas |
2889 |
<guimenuitem>Preferences</guimenuitem> |
7115 |
16 Mar 16 |
nicklas |
2890 |
</menuchoice> dialog. The ID of the selected start page is stored as |
7115 |
16 Mar 16 |
nicklas |
2891 |
a user setting. When the user is logging in to BASE the extension is |
7115 |
16 Mar 16 |
nicklas |
2892 |
queried for the URL to load and the browser is redirected to that page. |
7115 |
16 Mar 16 |
nicklas |
2893 |
</para> |
7115 |
16 Mar 16 |
nicklas |
2894 |
|
7115 |
16 Mar 16 |
nicklas |
2895 |
<para> |
7115 |
16 Mar 16 |
nicklas |
2896 |
BASE provides a simple action factory implementation: |
7115 |
16 Mar 16 |
nicklas |
2897 |
<classname docapi="net.sf.basedb.clients.web.extensions.startpage">FixedStartPageFactory</classname>. |
7115 |
16 Mar 16 |
nicklas |
2898 |
</para> |
7115 |
16 Mar 16 |
nicklas |
2899 |
|
7115 |
16 Mar 16 |
nicklas |
2900 |
</sect2> |
5640 |
24 May 11 |
nicklas |
2901 |
</sect1> |
5640 |
24 May 11 |
nicklas |
2902 |
|
4184 |
20 Mar 08 |
nicklas |
2903 |
</chapter> |