tutoriales desarrollo de plugin

13
Tutorial 1: Desarrollo de un plugin En este tutorial introductorio se creará un plugin siguiendo una de las plantillas que ofrece Eclipse. Concretamente se extenderá una vista para mostrar cierta información de la plataforma. Crear el proyecto Se creará un proyecto de plugin con nombre org.example.demo y la información del plugin se introducirá como aparece en la imagen. Tras esto, se nos indicará si deseamos crear el plugin siguiendo una plantilla, escojeremos “Plugin with a view”. A continuación se nos pedirán algunos datos para generar el código que creará el asistente. Examinar la descripción del plugin y la auyda de la extensión.

Upload: buggy-buggys

Post on 16-Jan-2016

216 views

Category:

Documents


0 download

DESCRIPTION

Desarrollo de plugin

TRANSCRIPT

Page 1: Tutoriales Desarrollo de Plugin

Tutorial 1: Desarrollo de un plugin

En este tutorial introductorio se creará un plugin siguiendo una de las plantillas que ofrece Eclipse. Concretamente se extenderá una vista para mostrar cierta información de la plataforma.

Crear el proyecto Se creará un proyecto de plugin con nombre org.example.demo y la información del plugin se introducirá como aparece en la imagen.

Tras esto, se nos indicará si deseamos crear el plugin siguiendo una plantilla, escojeremos “Plugin with a view”. A continuación se nos pedirán algunos datos para generar el código que creará el asistente. Examinar la descripción del plugin y la auyda de la extensión.

Page 2: Tutoriales Desarrollo de Plugin

2

Descargar http://www.dsic.upv.es/~pginer/download/eclipse/tutorial1/tutorial1.java y completar el código de DemoView.java. Crear un fichero en text/info.txt en el proyecto. Este fichero deberá añadirse como parte de la exportación en la sección Build Configuration. Exportar como “Deployable plugins and Fragments” e indicar que se genere un fichero Ant con nombre build-demo.xml. Copiar el plugin en la carpeta plugins de eclipse y comprobar que funciona.

Page 3: Tutoriales Desarrollo de Plugin

3

Tutorial 2: Puntos de Extensión

En este tutorial se mostrará como definir puntos de extensión y cómo crear extensiones para éstos. Como ejemplo se creará un sistema extensible de funciones aritméticas. El usuario podrá aplicar distintas funciones matemáticas a un valor introducido (por simplicidad, solo se consideran funciones con un parámetro de entrada). El sistema estará formado por:

• Un plugin que proporcionará la interfaz gráfica que permita al usuario introducir los datos, visualizar los resultados y ejecutar las distintas funciones.

• Varios plugins que aportan las funciones aritméticas que se desea poder aplicar. Las funciones que se pueden añadir deberán tener un parámetro de entrada y podrán acceder a un parámetro opcional de configuración.

Page 4: Tutoriales Desarrollo de Plugin

4

Este ejemplo ha sido tomado del artículo Notes on the Eclipse Plug-in Architecture1 actualizándolo a la nueva versión de Eclipse.

Plugin base

Crear proyecto de plugin org.example.calculator.ui

Crear Interfaz IFunction La interfaz actua a modo de contrato, todo plugin que quiera extender al actual exigiremos que aporte objetos que cumplan con dicha interfaz. package org.example.calculator.ui; public interface IFunction { public long compute(long x) throws ArithmeticException; }

Fragmento 1: IFunction.java

La interfaz mostrada indica que los objetos que la implementen deberán poseer un método compute que reciba un entero de tipo long y devuelva otro.

Copiar FunctionsGrid al proyecto Descargar FunctionsGrid.java de: http://www.dsic.upv.es/~pginer/download/eclipse/tutorial2/FunctionsGrid.java FunctionsGrid es la definición de la interfaz gráfica de la aplicación. Hay algunos aspectos a destacar: El constructor de FunctionsGrid recibe como parámetro un objeto de tipo Composite sobre el que agrega los elementos de la interfaz. El método addFunction se usará para añadir nuevos botones que permitan invocar las nuevas funciones aritméticas. Recibe como parámetro el objeto IFunction a invocar así como datos de la función para presentarlos al usuario como un nombre, etiqueta y el valor de la constante de configuración usado.

Crear una nueva vista A continuación se extenderá el mecanismo de vistas de eclipse para incluir una en la que se muestre la interfaz gráfica recién creada.

1 http://www.eclipse.org/articles/Article-Plug-in-architecture/plugin_architecture.html

Page 5: Tutoriales Desarrollo de Plugin

5

En la información del plugin ir a la sección Extensions. Añadir una nueva extensión del tipo org.eclipse.ui.views El ID y el Nombre de la extensión no son relevantes. Sobre la extensión creada mediante un click del botón secundario del ratón aparecerán los elementos que pueden crearse como extensión (view, category y sticky view). Se creará una categoría (category) y una vista nueva (view). Estos son los datos: Category id: org.example.calculator.ui.category name: Example.org Category View id: org.example.calculator.ui.view name: Calculator View class: org.example.calculator.ui.CalculatorViewPart category: org.example.calculator.ui.category Con esto creamos una nueva vista y una categoría que la contendrá. La vista indica mediante el atributo class, la clase que implementará la extensión. Mientras que category representa el identificador de la categoría a la que pertenece la vista. Únicamente falta para completar la vista crear la clase CalculatorViewPart. El código que se muestra a continuación extiende la clase ViewPart. El método createPartControl se define para que pueda crearse la interfaz gráfica. package org.example.calculator.ui; import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.part.ViewPart;

Page 6: Tutoriales Desarrollo de Plugin

6

public class CalculatorViewPart extends ViewPart { public void createPartControl(Composite parent) { new FunctionsGrid(parent); } public void dispose() { super.dispose(); } public void setFocus() { } }

Fragmento 2 CalculatorViewPart.java

Extensiones

Permtir el acceso al plugin base En la sección Runtime de las propiedades del plugin añadir a la lista de Exported Packages: org.example.calculator.ui Esto permitirá que otros plugins que lo extiendan puedan acceder a sus clases.

Crear Punto de Extensión En la sección Extension Points del descriptor del plugin, crear un Extension Point con los siguientes datos: id: functions nombre: Functions schema: schema/functions.exsd El identificador del punto de extensión es functions, sin embargo cuando requiera ser extendido se deberá hacer referencia a su nombre completo (org.example.calculator.ui.functions). El schema definirá los elementos que pueden extender el punto de extensión creado.

Page 7: Tutoriales Desarrollo de Plugin

7

El schema permite documentar la extensión. En la sección de definición. Se indicarán los elementos que podrán aparecer en una extensión. Se añadirá un nuevo elemento function y a este los siguientes atributos: name, class y constant. Al elemento extension se le añadirá un elemento compositor de tipo sequence y a este una referencia al elemento function. Con éste últmo elemento seleccionado se marcarála propiedad unbounded relativa al número máximo de elementos.

Con esto hemos especificado que la extensión consistirá en una secuencia de una o más funciones y estas funciones estarán definidas por un nombre, una clase que las implementará y una constante que se podrá indicar en tiempo de extensión parametrizando esta.

Procesar las exensiones desde el plugin base El plugin base necesita tener algún tipo de acceso a las extensiones ya que en función de estas deberá crear un número variable de botones, sin embargo estas solo se conocen en

Page 8: Tutoriales Desarrollo de Plugin

8

tiempo de ejecución. Para ello se ha creado la clase ProcessServiceMembers que recibirá la interfaz gráfica, recuperará la información relativa a las extensiones y ejecutará el servicio addFunction, para añadir los botones y etiquetas necesarios para ejecutar cada función. package org.example.calculator.ui; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtension; import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.Platform; import org.eclipse.ui.WorkbenchException; public class ProcessServiceMembers { private static final String EXTENSION_POINT = "org.example.calculator.ui.functions"; private static final String FUNCTION_NAME_ATTRIBUTE = "name"; private static final String CLASS_ATTRIBUTE = "class"; private static final String CONSTANT_ATTRIBUTE = "constant"; public static void process(FunctionsGrid grid) throws WorkbenchException { IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint(EXTENSION_POINT); IConfigurationElement[] members = extensionPoint.getConfigurationElements(); // For each service: for (IConfigurationElement member:members) { IExtension extension = member.getDeclaringExtension(); String pluginLabel = extension.getLabel(); if (pluginLabel == null) { pluginLabel = "[unnamed plugin]"; } String functionName = member.getAttribute(FUNCTION_NAME_ATTRIBUTE); if (functionName == null) { functionName = "[unnamed function]"; } String label = pluginLabel + "/" + functionName; Integer constant = null; String s = member.getAttribute(CONSTANT_ATTRIBUTE); if (s != null) { constant = new Integer(s); } // Add a row to support this operation to the UI grid. IFunction function; try { Object callback = member.createExecutableExtension(CLASS_ATTRIBUTE); function = (IFunction)callback; } catch (CoreException ex) { System.err.println(ex.getMessage()); ex.printStackTrace(); break; } grid.addFunction(function, functionName, label, constant); } } }

Fragmento 3 ProcessServiceMembers.java

Page 9: Tutoriales Desarrollo de Plugin

9

El código presentado define un conjunto de constantes para almacenar el identificador del punto de extensión y los nombres de los atributos que aparecerán en los elementos que forman la extensión. Estos nombres (“name”, “class” y “constant”) fueron los que se dieron al definir el elemento function del esquema de la extensión. La clase CalculatorViewPart deberá incluir una llamada para procesar los servicios y permitir a la clase ProcessServiceMembers que modifique el grid. El nuevo código de CalculatorViewPart, se muestra a continuación (los cambios respecto a la versión anterior se muestran resaltados): package org.example.calculator.ui; import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.WorkbenchException; import org.eclipse.ui.part.ViewPart; public class CalculatorViewPart extends ViewPart { public void createPartControl(Composite parent) { // Define the UI grid for invoking functions. FunctionsGrid grid = new FunctionsGrid(parent); // Do extension processing for the "functions" extension-point. try { ProcessServiceMembers.process(grid); } catch (WorkbenchException e) { e.printStackTrace(); } } public void dispose() { super.dispose(); } public void setFocus() { } }

Fragmento 4 CalculatorViewPart.java

Crear nuevos plugins El plugin creado anteriormente no aporta ninguna funcionalidad. Precisamente su función es definir un punto de extensión donde otros plugins puedan añadir nuevas funciones. A continuación se crearán dos plugins, el primero incorporará una extensión consistente en la función de copia (el valor de salida será el proporcionado como entrada). Un segundo plugin se definirá para incluir una función de multiplicación que servirá para realizar dos extensiones doble y triple que servirán para multiplicar el valor de entrada por 2 y 3 respectivamente. En vez de definir dos funciones distintas, la función multiplicar se parametrizará utilizando el valor constant de las extensiones.

Plugin Simple Crear proyecto de plugin: org.example.calculator.copia En la sección Dependencias añadir org.example.calculator.ui como dependencia. Crear una clase Copia que implemente la interfaz IFunction.

Page 10: Tutoriales Desarrollo de Plugin

10

package org.example.calculator.copia; import org.example.calculator.ui.IFunction; public class Copia implements IFunction { @Override public long compute(long x) throws ArithmeticException { return x; } }

Crear una extensión de tipo org.example.calculator.ui.functions con ID: org.example.calculator.copia y nombre “Copia Function”. Añadir un elemento function con los siguientes datos: Name: Copia Class: org.example.calculator.copia.Copia Y sin asignar valor a la constante.

Plugin Avanzado Los plugins pueden aportar múltiples extensiones a otros plugins, en este ejemplo se creará un plugin que defina dos extensiones: doble y triple. El plugin contendrá una única función, multiplicar, que hará uso el parámetro constant definido para las extensiones. Crear un proyecto de plugin con nombre org.example.calculator.multiplicar En la sección Dependencias añadir org.example.calculator.ui como dependencia. La Función a añadir se definirá en una clase. Esta deberá implementar la interfaz IFunction y IExecutableExtension.

Page 11: Tutoriales Desarrollo de Plugin

11

La interfaz IFunction exige definir el método que especificará la operación. En este caso el valor devuelto será el resultado de multiplicar el parámetro de entrada por la constante de configuración. La interfaz IExecutableExtension fuerza a implementar el método setInitializationData, que servirá para obtener precisamente el valor de la constante introducida en la definición de la extensión. package org.example.calculator.multiplicar; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExecutableExtension; import org.example.calculator.ui.IFunction; public class Multiplicar implements IFunction, IExecutableExtension { private int parametro; @Override public long compute(long x) throws ArithmeticException { return parametro*x; } @Override public void setInitializationData(IConfigurationElement config, String propertyName, Object data) throws CoreException { String s=config.getAttribute("constant"); parametro=Integer.parseInt(s); }

Page 12: Tutoriales Desarrollo de Plugin

12

}

Fragmento 5 Multiplicar.java

A continuación definiremos las dos funciones. En la sección Extensions añadir una extensión de tipo org.example.calculator.ui.functions con id org.example.calculator.multiplicar y nombre Multiplicar. Crear un elemento de tipo function con los siguientes datos: Name: Doble Class: org.example.calculator.multiplicar.Multiplicar Constant: 2 Crear un nuevo elemento function con: Name: Triple Class: org.example.calculator.multiplicar.Multiplicar Constant: 3 Ambos objetos comparten la misma clase.

Consideraciones importantes La clase ProcessServiceMembers encargada de añadir para cada extensión la parte de interfaz gráfica correspondiente. En el código presentado, el objeto que implementa la función es recuperado. Sin embargo para evitar un derroche innecesario de recursos, la estratégia habitual es crear un Proxy. Los proxies son representantes locales (más ligeros) de un objeto. De este modo el Proxy se creará a partir de la información de la extensión y solo se instanciará el objeto correspondiente cuando sea necesario utilizar el objeto. Además por brevedad se habian eliminado algunas comprobaciones relativas a la gestión de excepciones. Éste código es especialmente importante ya que permite detectar errores en la especificación de extensiones y garantizar que solo se consideren las extensiones correctas. El código completo se recoge a continuación: package org.example.calculator.ui; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtension; import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.Platform; import org.eclipse.ui.WorkbenchException; public class ProcessServiceMembers { private static final String EXTENSION_POINT = "org.example.calculator.ui.functions"; private static final String FUNCTION_NAME_ATTRIBUTE = "name"; private static final String CLASS_ATTRIBUTE = "class"; private static final String CONSTANT_ATTRIBUTE = "constant";

Page 13: Tutoriales Desarrollo de Plugin

13

public static void process(FunctionsGrid grid) throws WorkbenchException { IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint(EXTENSION_POINT); IConfigurationElement[] members = extensionPoint.getConfigurationElements(); // For each service: for (IConfigurationElement member:members) { IExtension extension = member.getDeclaringExtension(); String pluginLabel = extension.getLabel(); if (pluginLabel == null) { pluginLabel = "[unnamed plugin]";} // Get the name of the operation implemented by the service. String functionName = member.getAttribute(FUNCTION_NAME_ATTRIBUTE); if (functionName == null) { functionName = "[unnamed function]";} String label = pluginLabel + "/" + functionName; Integer constant = null; String s = member.getAttribute(CONSTANT_ATTRIBUTE); if (s != null) { constant = new Integer(s); } // Add a row to support this operation to the UI grid. IFunction function; try { Object callback = member.createExecutableExtension(CLASS_ATTRIBUTE); function = (IFunction)callback; } catch (CoreException ex) { System.err.println(ex.getMessage()); ex.printStackTrace(); break; } grid.addFunction(function, functionName, label, constant); } } }

Fragmento 6 ProcessServiceMembers