Statistics
| Revision:

root / branches / pilotoDWG / frameworks / _fwAndami / docs / Andami developer guide.html @ 1697

History | View | Annotate | Download (16.7 KB)

1
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2
<html>
3
<head>
4
  <meta content="text/html; charset=ISO-8859-1"
5
 http-equiv="content-type">
6
  <title>Andami developer guide</title>
7
  <link href="style.css" rel="stylesheet" type="text/css">
8
</head>
9
<body>
10
<table border="0" width="90%">
11
  <tbody>
12
    <tr>
13
      <td class="Nivel2"><a href="#Introduccion"><strong><font
14
 color="#ffffff">Introducci&oacute;n</font></strong></a></td>
15
    </tr>
16
    <tr>
17
      <td class="Nivel2"><a href="#Creacion_de_plugins"><font
18
 color="#ffffff"><strong>Creaci&oacute;n de plugins</strong></font></a></td>
19
    </tr>
20
    <tr>
21
      <td class="Nivel2"><a href="#Funcionamiento_del_class_loader"><strong><font
22
 color="#ffffff">Funcionamiento del class loader</font></strong></a></td>
23
    </tr>
24
    <tr>
25
      <td class="Nivel2"><a href="#Servicios_a_los_plugins"><font
26
 color="#ffffff"><strong>Servicios a los plugins</strong></font></a></td>
27
    </tr>
28
    <tr>
29
      <td><strong>&nbsp;&nbsp;&nbsp; <a
30
 href="#Ejecucion_en_segundo_plano">Ejecuci&oacute;n en segundo plano</a></strong></td>
31
    </tr>
32
    <tr>
33
      <td><strong>&nbsp;&nbsp;&nbsp; <a
34
 href="#Acceso_a_las_extensiones">Acceso a las extensiones</a></strong></td>
35
    </tr>
36
    <tr>
37
      <td class="urbanismo"><strong>&nbsp;&nbsp;&nbsp; <a
38
 href="#Consola">Consola</a></strong></td>
39
    </tr>
40
    <tr>
41
      <td class="urbanismo"><strong>&nbsp;&nbsp;&nbsp; <a
42
 href="#Persistencia_de_los_plugins">Persistencia de los plugins</a></strong></td>
43
    </tr>
44
    <tr>
45
      <td><strong>&nbsp;&nbsp;&nbsp; <a href="#popupmenus">Pop-up menus</a></strong></td>
46
    </tr>
47
    <tr>
48
      <td><strong>&nbsp;&nbsp;&nbsp; <a href="#Vistas">Vistas</a></strong></td>
49
    </tr>
50
    <tr>
51
      <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a
52
 href="#SingletonView">SingletonView's</a></td>
53
    </tr>
54
  </tbody>
55
</table>
56
<p> <strong><font size="+1"><a name="Introduccion"></a>Introducci&oacute;n</font></strong></p>
57
<p> &nbsp;&nbsp;&nbsp; Andami es un framework orientado a plugins
58
construido sobre swing que permite la construcci&oacute;n de forma
59
r&aacute;pida y extensible de aplicaciones MDI (Multiple Document
60
Interface). Tiene ya implementadas muchas de las funcionalidades
61
requeridas para este tipo de aplicaciones tales como un men&uacute;
62
Ventana, en la que van apareciendo las ventanas que se abren, soporte
63
para el traducciones, configuraci&oacute;n personalizada para cada
64
usuario, actualizaciones autom&aacute;ticas, tanto del propio Andami
65
como de los plugins, persistencia del tama&ntilde;o y posici&oacute;n
66
de la ventana, del idioma, distintos tipos de vista, con la finalidad
67
de facilitar la programaci&oacute;n de ventanas especiales, ... Todo
68
esto adem&aacute;s de tener ya solventados los problemas t&iacute;picos
69
de la programaci&oacute;n de un entorno como &eacute;ste que no son
70
pocos.<br>
71
<br>
72
&nbsp;&nbsp;&nbsp; Adem&aacute;s, Andami est&aacute; dise&ntilde;ada de
73
forma que la propia l&oacute;gica MDI puede ser reemplazada. Si en
74
lugar de una aplicaci&oacute;n estilo arcView, se quiere que cada vista
75
que se a&ntilde;ada, se haga en una ventana de windows nueva (de las
76
que aparecen en la barra de estado) o una vista como la de Eclipse, no
77
hay m&aacute;s que desarrollar el plugin adecuado.<br>
78
<br>
79
&nbsp;&nbsp;&nbsp; Andami est&aacute; dise&ntilde;ada para ser amistosa
80
con el usuario y para ello incorpora la posibilidad de a&ntilde;adir
81
tooltips y enabletexts a los botones. El tooltip es el texto que
82
aparece cuando el rat&oacute;n se detiene sobre un bot&oacute;n o
83
men&uacute;. El enableText es el texto que aparece en el caso anterior
84
cuando el bot&oacute;n est&aacute; desactivado, permitiendo mostrar al
85
usuario qu&eacute; es lo que debe hacer para que dicho bot&oacute;n se
86
active (o cualquier otro mensaje).<br>
87
<br>
88
&nbsp;&nbsp;&nbsp; Por &uacute;ltimo, Andami tiene una gesti&oacute;n
89
de errores que agradar&aacute; a cualquier programador, ya que en casos
90
de errores graves, el propio framework avisa de dicho fallo y aconseja
91
al usuario salvar los cambios y reiniciar el programa, a parte de que
92
toda excepci&oacute;n no capturada por el usuario se redirige a un
93
fichero de log configurable en el que se escribir&aacute; su traza.<br>
94
</p>
95
<p> <strong><font size="+1"><a name="Creacion_de_plugins"></a>Creaci&oacute;n
96
de plugins</font></strong></p>
97
<p> &nbsp;&nbsp;&nbsp; Andami gira en torno al concepto de plugin.
98
Andami mantiene un directorio como directorio de los plugins, que se
99
puede cambiar en cualquier momento. Un plugin viene definido por la
100
existencia de un subdirectorio dentro del directorio de los plugins,
101
siendo el nombre del plugin el nombre de dicho directorio. Dentro de
102
dicho directorio debe haber un fichero config.xml en el que se
103
configuran los puntos de entrada y salida del plugin (men&uacute;es,
104
barras de herramientas, etiquetas de la barra de estado, men&uacute;es
105
contextuales), las librer&iacute;as que va a usar, el paquete de
106
traducciones, los plugins de los que depende, etc. El fichero
107
plugin-config.xsd contiene el esquema que ha de seguir este fichero y
108
est&aacute;n comentados todos los elementos. En el CorePlugin que viene
109
con Adami se puede ver un ejemplo de config.xml.<br>
110
<br>
111
&nbsp;&nbsp;&nbsp; Las rutas de los directorios son siempre relativas
112
al directorio del plugin y los textos de los men&uacute;es, tooltips y
113
enabletext's son claves en el fichero de traducciones en caso de que
114
haya y textos literales en caso de que no haya traducciones. El fichero
115
de traducciones es un fichero de propiedades com&uacute;n: ver
116
ResourceBundle en la API de Java.<br>
117
<br>
118
&nbsp;&nbsp;&nbsp; Dentro de los plugins aparece el concepto de
119
extensi&oacute;n. Una extensi&oacute;n es instalada por los plugins
120
mediante la implementaci&oacute;n de la interfaz
121
com.iver.andami.plugins.Extension y la instalaci&oacute;n de unos
122
controles geobernados por &eacute;sta en el fichero config.xml.
123
Mediante esta implementaci&oacute;n se le dice a Andami la
124
condici&oacute;n que se debe cumplir para que los controles sean
125
visibles o est&eacute;n activos. Adem&aacute;s se implementa la
126
acci&oacute;n a llevar a cabo cuando se selecciona uno de los
127
men&uacute;es o botones asociados a la extensi&oacute;n. Cabe resaltar
128
que Andami crea una instancia de cada extensi&oacute;n configurada en
129
config.xml, por lo que las clases que implementen la interfaz Extension
130
deben de tener un constructor sin argumentos.<br>
131
<br>
132
&nbsp;&nbsp;&nbsp; En los tag 'extension' existe un atributo class-name
133
en el que se especifica la clase que gobierna el punto de
134
extensi&oacute;n que se est&aacute; definiendo. Esta clase
135
deber&aacute; implementar la interfaz com.iver.andami.plugins.Extension
136
y ser&aacute; mediante &eacute;sta que gobernar&aacute; los
137
men&uacute;es y botones asociados a este punto de extensi&oacute;n<br>
138
<br>
139
&nbsp;&nbsp;&nbsp; Una problema com&uacute;n en este framework es no
140
ver c&oacute;mo se mantiene la informaci&oacute;n del proyecto concreto
141
que se est&aacute; desarrollando. El lugar adecuado es una de las
142
extensiones instaladas. Por ejemplo en el caso de gvSIG est&aacute; la
143
extensi&oacute;n com.iver.cit.gvsig.ProjectExtension, en la cual hay un
144
atributo Project que es la ra&iacute;z del &aacute;rbol
145
jer&aacute;rquico del cual penden las vistas, mapas, tablas, ...
146
Adem&aacute;s esta extensi&oacute;n tiene un m&eacute;todo getProject
147
que devuelve la referencia al proyecto, de manera que se puede acceder
148
desde cualquier punto de la aplicaci&oacute;n. Para ver el acceso a las
149
instancias de las extensiones ver <a href="#Acceso_a_las_extensiones">acceso
150
a las extensiones</a></p>
151
<p><br>
152
<font size="+1"><strong><a name="Funcionamiento_del_class_loader"></a>Funcionamiento
153
del class loader</strong></font></p>
154
<p> En Andami, el class loader de cada plugin delega primero en el
155
classloader del sistemaes decir, que si se ejecuta desde eclipse
156
buscar&aacute; por todos los jars que haya en el classpath del
157
proyecto, y si se ejecuta desde la linea de comandos, buscar&aacute; en
158
la variable de entorno CLASSPATH o en el argumento -classpath que se
159
pase como par&aacute;metro a java.<br>
160
<br>
161
Si el class loader del sistema no satisface la b&uacute;squeda, se
162
buscar&aacute; en los jars del directorio especificado por el
163
config.xml del plugin que intenta cargar la clase y si no se encuentra
164
en dichos jars, se buscar&aacute; en los jars de los plugins de los
165
cuales depende el plugin que intenta cargar la clase.<br>
166
<br>
167
<strong><font size="+1"><a name="Servicios_a_los_plugins"></a>Servicios
168
a los plugins</font></strong></p>
169
<p><br>
170
&nbsp;&nbsp;&nbsp; Andami ofrece a los plugins distintos servicios a
171
trav&eacute;s de la clase PluginServices en cuyo javadoc se puede
172
obtener informaci&oacute;n sobre como usarlos. Existen unos servicios
173
gen&eacute;ricos que vienen dados por m&eacute;todos est&aacute;ticos
174
de dicha clase y luego est&aacute; el m&eacute;todo getPluginServices
175
que obtiene una instancia de esta clase espec&iacute;fica del plugin,
176
mediante la cual puede acceder a servicios concretos de cada plugin,
177
traducciones, persistencia, directorio del plugin, ...<br>
178
&nbsp;<br>
179
<strong><a name="Ejecucion_en_segundo_plano"></a>Ejecuci&oacute;n en
180
segundo plano</strong><br>
181
&nbsp;&nbsp;&nbsp; Es conveniente que la interfaz gr&aacute;fica
182
est&eacute; siempre en funcionamiento, nunca bloqueada, aunque sea
183
s&oacute;lo para mostrar al usuario que el programa est&aacute;
184
procesando. Para ello hay que realizar las tareas que puedan tomar
185
demasiado tiempo en un thread a parte. La clase PluginServices
186
proporciona un m&eacute;todo est&aacute;tico backgroundExecution al
187
cual se le pasa un objeto Runnable, que es ejecutado en segundo plano,
188
dejando el thread de la interfaz libre para responder pero con sus
189
eventos bloqueados con el fin de que la interfaz responda y se
190
redibuje, pero se ignoren los eventos que produce el usuario mientras
191
se procesa la petici&oacute;n<br>
192
<br>
193
<a name="Acceso_a_las_extensiones"></a><strong>Acceso a las extensiones</strong><br>
194
&nbsp;&nbsp;&nbsp; Para acceder a la instancia de una extensi&oacute;n
195
se puede usar simplemente el m&eacute;todo de PluginServices
196
getExtension(Class) a la cual habr&aacute; que pasar como
197
par&aacute;metro la clase de la extensi&oacute;n a la que se quiere
198
acceder. Dicho m&eacute;todo retorna un objeto Extensi&oacute;n y por
199
tanto habr&aacute; que hacer casting a la clase concreta de dicha
200
extensi&oacute;n, habiendo obtenido as&iacute; la referencia a la
201
instancia de la extensi&oacute;n deseada.<br>
202
&nbsp;&nbsp;&nbsp; A la hora de desarrollar habr&aacute; que tener en
203
el build path del entorno de desarrollo que se use, el jar del plugin
204
dentro del cual est&aacute; la extensi&oacute;n que se quiere obtener,
205
para poder pasarle como par&aacute;metro a getExtension(Class) la clase
206
de la misma.<br>
207
<br>
208
<strong><a name="Consola"></a>Consola<br>
209
</strong> &nbsp;&nbsp;&nbsp; Mediante la consola del sistema, se pueden
210
introducir cadenas de texto como si de un terminal se tratara. Los
211
plugins pueden escuchar los eventos de introducci&oacute;n de texto en
212
la consola y pueden escribir informaci&oacute;n por la misma.<br>
213
</p>
214
<p> <strong><a name="Persistencia_de_los_plugins"></a>Persistencia de
215
los plugins</strong><strong></strong><br>
216
&nbsp;&nbsp;&nbsp; Uno de los servicios que ofrece Andami a los plugins
217
es la facilidad de guardar datos gen&eacute;ricos de los mismos en el
218
directorio del usuario de manera que cada usuario mantiene su propia
219
configuraci&oacute;n de los plugins. Para ello, las instancias de
220
PluginServices contienen una propiedad persistentXML que puede ser
221
obtenida y asignada y que es de tipo XMLEntity, pudiendo a&ntilde;adir
222
informaci&oacute;n de tipo b&aacute;sico (String, int, long, ...) a
223
dicha instancia y siendo esta informaci&oacute;n persistente entre
224
ejecuciones.<br>
225
<br>
226
<strong><a name="popupmenus"></a>Pop-up menus</strong><br>
227
&nbsp;&nbsp;&nbsp;&nbsp; Otro servicio proporcionado por Andami es el
228
de pop-up menu's extensibles. Mediante el XML se puede definir un
229
pop-up menu con un nombre y unas entradas al igual que cualquier otro
230
men&uacute;, con la &uacute;nica diferencia que para mostrar el popup
231
men&uacute; habr&aacute; que registrar un listener de la siguiente
232
manera:<br>
233
</p>
234
<div style="text-align: center;">
235
<pre>&lt;&gt;public void addPopupMenuListener(String name, Component c, ActionListener listener)<br></pre>
236
</div>
237
&nbsp;&nbsp;&nbsp; Lo cual har&aacute; que al pinchar con el
238
bot&oacute;n derecho sobre el componente 'c' aparezca el men&uacute;
239
'name' del fichero de configuraci&oacute;n del plugin y al seleccionar
240
cualquier entrada se ejecutar&aacute; el ActionListener que se pasa
241
como par&aacute;metro.<br>
242
<br>
243
&nbsp;&nbsp;&nbsp; Estos men&uacute;es son extensibles porque cualquier
244
otro plugin puede a&ntilde;adir entradas a dicho men&uacute; en su
245
propio fichero config.xml referenciando el men&uacute; al que quiere
246
extender mediante el nombre del plugin m&aacute;s el nombre del
247
men&uacute;. Un ejemplo. Tenemos un plugin llamado com.iver.cit.gvsig
248
que instala un men&uacute; de la siguiente manera:<br>
249
<pre>                &lt;popupMenu name="cascada"&gt;<br>                        &lt;entry text="Cascada" <br>                                tooltip="cascada_tooltip" <br>                                enableText="cascada_enable" actionCommand="CASCADA"/&gt;<br>                        &lt;entry text="Tile" <br>                                tooltip="tile_tooltip" <br>                                enableText="cascada_enable" actionCommand="CASCADA"/&gt;<br>                &lt;/popupMenu&gt;<br></pre>
250
y tenemos otro plugin que quiere a&ntilde;adir una entrada a dicho
251
men&uacute;. Para ello deber&aacute; de incluir un fragmento similar a
252
este en su fichero config.xml:<br>
253
<pre>                &lt;popupMenu name="com.iver.cit.gvsig.cascada"&gt;<br>                        &lt;entry text="Nueva entrada" actionCommand="NUEVA"/&gt;<br>                &lt;/popupMenu&gt;<br></pre>
254
y adem&aacute;s deber&aacute; de registrarse como listener de la manera
255
que se explic&oacute; anteriormente.<br>
256
<br>
257
<strong><a name="Vistas"></a>Vistas</strong><br>
258
&nbsp;&nbsp;&nbsp; El servicio m&aacute;s importante que
259
proporciona Andami es el de a&ntilde;adir vistas al marco principal.
260
Podemos calsificar las vistas por varios criterios:<br>
261
<ul>
262
  <li>Por su modalidad</li>
263
  <ul>
264
    <li>Modales</li>
265
    <li>No modales</li>
266
  </ul>
267
</ul>
268
<ul>
269
  <li>Por su contenido</li>
270
  <ul>
271
    <li>Singleton (Contenido identificable)</li>
272
    <li>Normales (Contenido no identificable)</li>
273
  </ul>
274
</ul>
275
&nbsp;&nbsp;&nbsp; Para crear una vista hay que hacer una clase que
276
derive de JPanel en la que se pone toda la funcionalidad como si de un
277
di&aacute;logo normal se tratara. Adem&aacute;s esta clase ha de
278
implementar la interfaz View la cual proporciona un m&eacute;todo
279
getViewInfo que es invocado una vez en la vida de la vista. Este objeto
280
contiene las caracter&iacute;sticas que tendr&aacute; la vista:
281
maximizable, resizable, title, ... y puede ser actualizado en cualquier
282
momento, reflej&aacute;ndose estos cambios de manera autom&aacute;tica
283
en la interfaz de usuario. Una vez implementada la vista, hay que
284
a&ntilde;adirla al manger MDI, que es el encargado de manejar toda la
285
l&oacute;gica relacionada con las vistas. Para obtener una referencia
286
al manager MDI la clase PluginServices tiene un m&eacute;todo
287
getMDIManager, el cual a su vez tiene un m&eacute;todo addView mediante
288
el cual se puede a&ntilde;adir la vista.<br>
289
<br>
290
&nbsp;&nbsp;&nbsp; Si durante la ejecuci&oacute;n se quiere cambiar
291
alguna propiedad de la vista tal como el tama&ntilde;o, la
292
posici&oacute;n o el
293
t&iacute;tulo, s&oacute;lo hay que acceder al objeto ViewInfo de la
294
misma y realizar los cambios de la manera deseada. El siguiente trozo
295
de c&oacute;digo cambia el t&iacute;tulo de una ventana (se supone que
296
es ejecutado desde la clase que implementa View).<br>
297
<pre>        PluginServices.getMDIManager().getViewInfo(this).setTitle("Nuevo t&iacute;tulo");<br></pre>
298
&nbsp;&nbsp;&nbsp; Puede ser necesario que algunas vistas realicen
299
alg&uacute;n tipo de procesamiento al ser activadas pero esto no se
300
sabe cuando ocurre ya que lo que se entrega al manager MDI es un
301
JPanel. Para recibir los eventos sobre las vistas, adem&aacute;s de
302
implementar View hay que implementar ViewListener la cual
303
proporcionar&aacute; los m&eacute;todos que ser&aacute;n invocados
304
cuando sucedan los eventos oportunos en las vistas.<br>
305
<br>
306
<big><a name="SingletonView"></a>SingletonView<br>
307
</big>&nbsp;&nbsp;&nbsp; Un tipo especial de vistas son las
308
SingletonView. Su principal caracter&iacute;stica es que se les define
309
el contenido de las mismas, de manera que cuando hay una SingletonView
310
minimizada en el proyecto y se intenta a&ntilde;adir un JPanel con el
311
mismo contenido, en lugar de aparecer otra ventana en el escritorio, lo
312
que sucede es que la ventana que estaba minimizada se restaura a su
313
posici&oacute;n anterior. Para esto, el m&eacute;todo addView devuelve
314
una referencia a la vista que se muestra, sea esta la que se
315
est&aacute; a&ntilde;adiendo o la que ya est&aacute; a&ntilde;adida.
316
Adem&aacute;s, al cerrar dicha ventana se guardan las dimensiones y la
317
posici&oacute;n de las mismas, de manera que al volverla a abrir se
318
recuerdan estos datos.<br>
319
<br>
320
</body>
321
</html>