Friday, October 29, 2010

NetBeans Options Window Module parte 2

Continuando con el tutorial
Diseñar una Ventana

indicamos la configuración

indicamos el nombre

En la ventana Agregamos un JPanel, un JLabel y un JTextField

En el constructor agregamos
Preferences pref = NbPreferences.forModule(CoolOptionsPanel.class);
String name = pref.get("namePreference", "");
pref.addPreferenceChangeListener(new PreferenceChangeListener() {
public void preferenceChange(PreferenceChangeEvent evt) {
if (evt.getKey().equals("namePreference")) {
jTextField1.setText(evt.getNewValue());
}
}
});
jTextField1.setText(name);





Agregamos el import java.util.prefs.Preferences
Importar org.openide.util.NbPreferences

Importar java.util.prefs.PreferenceChangeListener

Importar java.utils.prefs.PreferenceChangeEvent

Instalamos el plugin y desde el menu Ventana, seleccionamos Lectura


Podemos observar el contenido en el JtextField







NetBeans Options Window Module

NetBeans Options Window Module
Basado en
http://platform.netbeans.org/tutorials/nbm-options.html
1.Crear un proyecto de tipo modulo
2. Crear un Panel de Opciones

3. Indicamos el titulo y la palabra clave

4. Se muestra la ventana de Ubicación, presionamos el botón Terminar


5. Se agrega un nuevo panel

7. En el menú Herramientas seleccionamos Opciones
8. En opciones , seleccionamos Varios


9. Agregamos un JPanel, Caja de texto y una etiqueta

10. Instalamos el plugin y verificamos las Opciones.

11. Ahora en el código fuente buscamos el método store() y agregamos la
siguiente instrucción.
NbPreferences.forModule(CoolOptionsPanel.class).put("namePreference",
jTextField1.getText());







12.Corregimos las importaciones y seleccionamos. org.openide.util.NbPreferences


12. Instalamos el plugin nuevamente y verificamos las Opciones. org.openide.util.NbPreferences

13. Escribimos netbeans y presionamos el botón aceptar.

14. Ahora para recuperar el valor, buscamos el metodo load() y escribimos




15. Instalamos nuevamente el plugin y verificamos las opciones y nos
aparece el texto netbeans, almacenado anteriormente.




Agregar el plugin a un proyecto

Creamos un proyecto basado en NetBeans Platform Application


Imdicamos el nombre del proyecto

Seleccionamos las propiedades del proyecto


En modulos dar click derecho y seleccionar Añadir existentes



Seleccionamos el modulo


Se muestra el modulo agregado

Ejecutamos el proyecto 










Thursday, October 28, 2010

Bases de Datos Relacionales.Algo del pasado o forman parte del presente.

Hace años cuando inicie en el mundo del desarrollo de software he observado la evolución de muchas tecnologías algunas con éxito otras marcadas por el fracaso debido a diversos factores, sin duda han sido los proyectos basados en Open Source y Software Libre, los que me han llamado más la atención, entre ellos claro esta NetBeans.
En esta ocasión recuerdo la primera vez que utilice alguna base de datos relacional, , y en ese entonces me preguntaba porque hay que enseñar "normalización-1, normalización-2,normalización-3", definida de multiples maneras cuando al final es el mismo concepto y el porque no iniciar con la mejor forma normal desde el principio, luego me preguntaba son las bases de datos relacionales una verdadera solución a la mayoría de los problemas o simplemente son un avance sobre el manejo tradicional de los archivos...
También me preguntaba porque debemos definir una estructura rígida para el almacenamiento de los datos, si en el mundo real esto es flexible y dinámico, y como podemos almacenar algún tipo de información sin una estructura fija y no tener que convertir el proceso natural en un proceso estructurado por obligación del modelo relacional y de la estructura rígida de las bases de datos relacionales.
Por ejemplo cual es la mejor manera de almacenar datos de un formato como marc-21, donde no existe una estructura.
Pues bien, las bases de datos relacionales más que un beneficio para este tipo de aplicaciones ofrecen un modelo complejo o no muy natural de hacerlo. Pues bien la solución a este tipo de situaciones ha llegado mediante bases de datos NOSQL, muchas orientadas a documentos como Couchdb, MongoDB, etc.
En algunas situaciones dependiendo de la necesidad tal vez las bases de datos nosql no sean una alternativa, pero están cambiando de multiples maneras la forma en que se almacenan y procesan los datos..

Wednesday, October 27, 2010

Capacitación virtual en NetBeans Platform

Nuestro amigo Diego Silva (uno de los mejores escritores de blogs sobre NetBeans en español) esta coordinando con Geertjan Wielenga para dictar capacitaciones para los latinoamericanos.

Información oficial en el blog de Diego Silva
http://www.apuntesdejava.com/2010/10/ultimo-minuto-capacitacion-virtual-en.html



marc-json

Ajuste el código del plugin para migrar archivos Marc21 a Couchdb, para que soporte el formato marc-json.


Parte del código fuente



Monday, October 18, 2010

NetBeans 7.0 Milestone 2 disponible

El Milestone 2 de NetBeans 7.0 esta disponible para su descarga.

En este enlace puedes descargar el M2
Las caracteristicas

  • Java
    • Support for Maven 3
    • JUnit 4.8.2 integration and various JUnit improvements
    • Remote HTTP URLs supported for Javadoc in libraries and Java platforms
    • New improved visual customizer for GridBagLayout
  • Java EE
    • Improved support for CDI, REST services and Java Persistence; new support for Bean Validation
    • Support for JSF component libraries, including bundled PrimeFaces library
    • Improved editing for Expression Language in JSF, including code completion, refactoring and hints
  • GlassFish
    • GlassFish 3.1 Support
    • Domain restart and log viewer for remote GlassFish
    • Enable and disable deployed applications
  • WebLogic Application Server
    • Streamlined and faster deployment to WebLogic
    • New server runtime node displaying deployed applications and resources
    • JSF integration with server libraries
  • Platform
    • Less intrusive checking for external changes when switching between the IDE and other programs
  • Editor
    • Word wrap
    • Show invisible characters
    • HTML 5 support
  • PHP
    • Generate PhpDoc
    • Rename refactoring, Safe Delete Refactoring

Friday, October 15, 2010

Obtener los documentos de una base de datos en Couchdb

Mostrare un pequeño código en Java que utiliza Couchdb4j para interactuar con los documentos almacenados en Couchdb.


try {
            db = dbSession.getDatabase(dbname);
            if (db == null) {
                return false;
            }
            int count = db.getDocumentCount();
            if (count == 0) {
                NotifyDescriptor d = new NotifyDescriptor.Message("No existen documentos de la base de datos " + dbname, msgType);
                DialogDisplayer.getDefault().notify(d);
                return false;
            }
            ViewResults results = db.getAllDocuments();

            //definimos el los campos para mostrar en el jtable
             Object[] filas = new Object[4]; // Hay tres columnas en la tabla


            for (Document document : results.getResults()) {
                            String id = (String) document.get("id");
                             Document full = db.getDocument(document.getId());
                String lnombre =full.getString("archivo");
                String lfecha = full.getString("fecha");
                String lprefijo = full.getString("prefijo");
                String ltipo    = full.getString("tipo");
                
            }

            return true;
        } catch (Exception ex) {

            NotifyDescriptor d = new NotifyDescriptor.Message("ObtenerRegistros()  " + ex.getLocalizedMessage().toString(), msgTypeError);
            DialogDisplayer.getDefault().notify(d);
        }
        return false;
    }

Thursday, October 14, 2010

M21Couchdb Migrador Marc21 a Couchdb

En esta ocasión realice un plugin muy básico para migrar datos desde un archivo en formato mar21 (.mrc)  a una base de datos couchdb.
El funcionamiento es sencillo, se analiza el contenido del archivo se obtienen los campos y luego estos se insertan en una base de datos documental.

Simplemente seleccionando el archivo

Este plugin utiliza la biblioteca Marc4j
Aqui podemos ver el contenido del archivo Sesion.java
package org.avbravo.m21couchdb;

/**
 *
 * @author avbravo
 */
import com.fourspaces.couchdb.Database;
import com.fourspaces.couchdb.Document;
import com.fourspaces.couchdb.Session;
import java.io.FileInputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import javax.swing.JOptionPane;
import org.marc4j.MarcReader;
import org.marc4j.MarcStreamReader;
import org.marc4j.marc.DataField;
import org.marc4j.marc.Leader;
import org.marc4j.marc.Record;
import org.marc4j.marc.Subfield;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.awt.StatusDisplayer;

/**
 *
 * @author avbravo
 */
public class Sesion {

   // private String ip = "localhost";
 //   private int puerto = 5984;

    String directorio = "";
   private static String urlArchivo;
    Record record;
    MarcReader reader;
    Leader leader;

    private static String ipCouchdb = "localhost";
    private static int puertoCouchdb = 5984;
    private static String userCouchdb;
    private static String passwordCouchdb;
    private static String prefijo;
   private static String nuevo="si";
    public static Session dbSession;
    public static Database db;
    public static Document doc;

  //  static DatabaseMetaData dmd;
    int num_columnas;
//    static List<String> ListaTablas = new ArrayList<String>();
    static List<String> ListaMensajes = new ArrayList<String>();
int msgTypeError = NotifyDescriptor.ERROR_MESSAGE;
    int msgType = NotifyDescriptor.INFORMATION_MESSAGE;
    public static String getNuevo() {
        return nuevo;
    }

    public static void setNuevo(String nuevo) {
        Sesion.nuevo = nuevo;
    }

    public static String getUrlArchivo() {
        return urlArchivo;
    }

    public static void setUrlArchivo(String urlArchivo) {
        Sesion.urlArchivo = urlArchivo;
    }

  


    
    public static List<String> getListaMensajes() {
        return ListaMensajes;
    }

    public static void setListaMensajes(List<String> ListaMensajes) {
        Sesion.ListaMensajes = ListaMensajes;
    }

   

    public static String getPrefijo() {
        return prefijo;
    }

    public static void setPrefijo(String prefijo) {
        Sesion.prefijo = prefijo;
    }

   

    public String getIpCouchdb() {
        return ipCouchdb;
    }

    public void setIpCouchdb(String ipCouchdb) {
        this.ipCouchdb = ipCouchdb;
    }

    public String getPasswordCouchdb() {
        return passwordCouchdb;
    }

    public void setPasswordCouchdb(String passwordCouchdb) {
        this.passwordCouchdb = passwordCouchdb;
    }

    public int getPuertoCouchdb() {
        return puertoCouchdb;
    }

    public void setPuertoCouchdb(int puertoCouchdb) {
        this.puertoCouchdb = puertoCouchdb;
    }

    public String getUserCouchdb() {
        return userCouchdb;
    }

    public void setUserCouchdb(String userCouchdb) {
        this.userCouchdb = userCouchdb;
    }

    
    /*
     * Agrega una tabla a la lista
     */

    

    /*
     *inicio
     */
    public boolean ConectarCouchDB() {
        try {
            dbSession = new Session(ipCouchdb, puertoCouchdb);
            String host = dbSession.getHost();
            //
            //  dbSession
            List<String> databasesCouchdb = dbSession.getDatabaseNames();

            StatusDisplayer.getDefault().setStatusText("host..." + dbSession.getHost());
            if (dbSession == null) {
                return false;
            }
            return true;
        } catch (Exception ex) {

            JOptionPane.showMessageDialog(null, "ConectarCouchDB()\nMensaje: " + ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
            this.ListaMensajes.add("ConectarCouchDB) " + ex.getLocalizedMessage().toString());
            StatusDisplayer.getDefault().setStatusText("ConectarCouchDB. Error " + ex.getMessage().toString());
        }
        return false;
    }

    public boolean CrearBaseDatos(String dbname) {
        try {
            db = dbSession.createDatabase(dbname);
            if (db == null) {
                return false;

            }
            return true;
        } catch (Exception ex) {
            //  JOptionPane.showMessageDialog(null, "CrearBaseDatos()\nMensaje: " + ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
            this.ListaMensajes.add("CrearBaseDatos(String dbname) " + ex.getLocalizedMessage().toString());
            StatusDisplayer.getDefault().setStatusText("CrearBaseDatos(String dbname). Error " + ex.getMessage().toString());
        }
        return false;
    }

    public boolean AbrirBaseDatos(String dbname) {
        try {
            db = dbSession.getDatabase(dbname);
            if (db == null) {
                return false;
            }
            return true;
        } catch (Exception ex) {

            //  JOptionPane.showMessageDialog(null, "AbrirBaseDatos()\nMensaje: " + ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
            this.ListaMensajes.add("AbrirBaseDatos(String dbname) " + ex.getLocalizedMessage().toString());
            StatusDisplayer.getDefault().setStatusText("AbrirBaseDatos(String dbname). Error " + ex.getMessage().toString());
        }
        return false;
    }

    public void AgregarDocumentos() {
        try {

            doc = new Document();
            doc.setId("myid");
            doc.put("nombre", "valor");

            db.saveDocument(doc);
        } catch (Exception ex) {
            this.ListaMensajes.add("AgregarDocumentos " + ex.getLocalizedMessage().toString());
            StatusDisplayer.getDefault().setStatusText("AgregarDocumentos(). Error " + ex.getMessage().toString());
        }

    }

   
    public void MigrarArchivo(){
        try {
        
CargarArchivo();

           
            
        } catch (Exception ex) {

            StatusDisplayer.getDefault().setStatusText("procesarTabla(). Error " + ex.getMessage().toString());
            this.ListaMensajes.add("MigrarArchivo() " + ex.getLocalizedMessage().toString());
        }
    }

   public boolean CargarArchivo() {
        try {

            InputStream in = new FileInputStream(urlArchivo);
            if (in != null) {
                reader = new MarcStreamReader(in);
                while (reader.hasNext()) {
// obtener el registro completo mostrando todos los campos
                    record = reader.next();
                     System.out.println(record.toString());
                    ObtenerRegistroMarc();
                    //         ObtenerValorCampos();
                    Campo856();
                    // break;
                }

            } else {
                  NotifyDescriptor d = new NotifyDescriptor.Message("No se encontro el archivo " + urlArchivo, msgTypeError);
        DialogDisplayer.getDefault().notify(d);
            }

            return true;
         } catch (Exception ex) {

            NotifyDescriptor d = new NotifyDescriptor.Message(ex.getLocalizedMessage().toString(), msgTypeError);
            DialogDisplayer.getDefault().notify(d);

        }
        return false;
    }
  public void ObtenerRegistroMarc() {
        try {
            doc = new Document();


            leader = record.getLeader();
          //  System.out.println("leader: " + leader.toString());


            //no se usa el id para que couchdb lo genere mejor
            //doc.setId(id);
            doc.put("leader", leader.toString());


            String codigo, texto;
            int largo;
            List fields = record.getControlFields();
//            System.out.println("(tags 001  a 009 size " + fields.size() + ")");
            for (int i = 0; i < fields.size(); i++) {
                //descompongo el elemento
                largo = fields.get(i).toString().length();
              //  System.out.println(fields.get(i));
                codigo = fields.get(i).toString().substring(0, 3);
                texto = fields.get(i).toString().substring(4, largo);
                //  System.out.println("-----------> " + codigo + " --> " + texto);
                doc.put(codigo, texto);
            }

            // returns fields for tags 010 through 999
            List fields2 = record.getDataFields();
  //          System.out.println("tags 010 to 999 size " + fields2.size());
            for (int i = 0; i < fields2.size(); i++) {
                largo = fields2.get(i).toString().length();
              //  System.out.println(fields2.get(i));
                codigo = fields2.get(i).toString().substring(0, 3);
                texto = fields2.get(i).toString().substring(4, largo);
                doc.put(codigo, texto);


            }
            Campo856();
            db.saveDocument(doc);
            System.out.println("--guardado----");
        } catch (Exception ex) {
              this.ListaMensajes.add("ObtenerRegistroMarc() " + ex.getLocalizedMessage().toString());
        }
    }

   public void Campo856() {
        try {
            //------------------campo 245
            DataField field = (DataField) record.getVariableField("856");
            String tag = field.getTag();
            char ind1 = field.getIndicator1();
            char ind2 = field.getIndicator2();

        //    System.out.println("Tag: " + tag + " Indicator 1: " + ind1 + " Indicator 2: " + ind2);

            List subfields = field.getSubfields();
            Iterator i = subfields.iterator();

            while (i.hasNext()) {
                Subfield subfield = (Subfield) i.next();
                char code = subfield.getCode();
                String data2 = subfield.getData();

//                System.out.println("Subfield code: " + code + " Data element: " + data2);
                String x = String.valueOf(code);


                if (x.equals("u")) {
                    doc.put("url", data2);
                }

            }
        } catch (Exception ex) {
           this.ListaMensajes.add("Campo856() " + ex.getLocalizedMessage().toString());
        }

    }
 }

Wednesday, October 13, 2010

DialogDisplayer

  String msg = "Mensaje de texto!";
        int msgType = NotifyDescriptor.INFORMATION_MESSAGE;
        int msgTypeError = NotifyDescriptor.ERROR_MESSAGE;
     NotifyDescriptor d = new NotifyDescriptor.Message(msg, msgType);
         DialogDisplayer.getDefault().notify(d);

Tuesday, October 12, 2010

Couchdb Explorer parte 7

Editamos la clase DemoTopComponent.java
Agregamos el objeto
Sesion sesion = new Sesion(); debajo de la declaración de la clase.
y Agregar dos atributos booleanos para controlar la activación del botón Migrar
boolean ldatabase = false;
boolean couchdb = false;

Agregamos el código para el botón Conectar Couchdb

try {
String ip = jTextFieldIpCouchdb.getText();
if (ip == null || ip.equals("")) {
JOptionPane.showMessageDialog(this, "Ingrese el ip", "Mensaje",
JOptionPane.INFORMATION_MESSAGE);
jTextFieldIpCouchdb.requestFocus();
return;
}
String spuerto = jTextFieldPuertoCouchdb.getText();
if (spuerto == null || spuerto.equals("")) {
JOptionPane.showMessageDialog(this, "Ingrese el puerto", "Mensaje",
JOptionPane.INFORMATION_MESSAGE);
jTextFieldPuertoCouchdb.requestFocus();
return;
}
int puerto = Integer.parseInt(spuerto);
String user = jTextFieldUserCouchdb.getText();
if (user == null) {
user = "";
}
String password = new String(this.jPasswordFieldCouchdb.getPassword());
if (password == null) {
password = "";
}
sesion.setIpCouchdb(ip);
sesion.setPuertoCouchdb(puerto);
sesion.setUserCouchdb(user);
sesion.setPasswordCouchdb(password);
couchdb = sesion.ConectarCouchDB();
if (couchdb == false) {
JOptionPane.showMessageDialog(this, "No se pudo establecer la conexión verifique los datos");
return;
}
StatusDisplayer.getDefault().setStatusText("Conexión exitosa a couchdb");
if (ldatabase == true) {
jButtonMigrar.setEnabled(true);
}
JOptionPane.showMessageDialog(this, "Conexión exitosa a Couchdb");
} catch (Exception ex) {
JOptionPane.showMessageDialog(this, "Error\nMensaje: " + ex.getMessage(), "Error",
JOptionPane.ERROR_MESSAGE);
}

Corregimos las importaciones

Agregamos código al botón Migrar
sesion.ListaMensajes.clear();
jTextAreaMensajes.setText("");
String prefijo = jTextFieldPrefijo.getText();
if (prefijo == null) {
prefijo = "";
}
String formatoFecha = String.valueOf(jComboBoxFormatoFecha.getSelectedItem());
sesion.setFormatoFecha(formatoFecha);
sesion.setPrefijo(prefijo);
StatusDisplayer.getDefault().setStatusText("Iniciando proceso de migración");
Thread t = new Thread(new NBRunnable());
t.start();




Agregamos un nuevo Panel para mostrar un Resumen de los mensajes
Generados
Agregamos un JscrollPane y dentro de el un JTextArea

Código del botón Ver Mensajes
// TODO add your handling code here:
for (int i = 0; i < sesion.getListaMensajes().size(); i++) {
jTextAreaMensajes.append(sesion.getListaMensajes().get(i) + "\n");
}

Plugin Terminado







Couchdb Explorer parte 6

Agregar la librería Couchdb4j
Seleccionamos Wrapped JARs

y presionamos el botón Añadir JAR
Agregamos la librería couchdb4

Agregamos los jar que están en la carpeta lib
Nos quedaría finalmente así

AGREGAR NUEVOS COMPONENTES AL DISEÑO
Agregamos etiquetas, cajas de texto , combo y botones. Para la conexión a Couchdb
Datos del jComboBoxFormatoFecha. Propiedad model:dd/MM/aaaa, MM/dd/aaaa,
aaaa/MM/dd, dd/aaaa/MM, MM/aaaa/dd, aaaa/dd/MM

Creamos la clase NBRunnable para para ejecutar múltiples hilos.
Código fuente
package org.avbravo.couchdb;
/**
*
* @author avbravo
*/
import javax.swing.JOptionPane;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.openide.awt.StatusDisplayer;
/**
*
* @author avbravo
*/
public class NBRunnable implements Runnable {
Sesion sesion = new Sesion();
@Override
public void run() {
try{
for (int i = 0; i < sesion.getListaTablas().size(); i++) {
ProgressHandle p = ProgressHandleFactory.createHandle(
"Procesando tabla: " + sesion.getListaTablas().get(i)
+ " espere....");
p.start();
sesion.procesarTabla(sesion.getListaTablas().get(i));
// break;
p.finish();
}
StatusDisplayer.getDefault().setStatusText("Migración terminada...");
// p.finish();
}catch(Exception ex){
StatusDisplayer.getDefault().setStatusText("Error "+ex.getMessage().toString());
}
}
}













Couchdb Explorer parte 5

PANEL TABLAS
Ahora en el Panel Tablas agregamos un JscrollPane1(Panel de desplazamientos). Ajustamos
un poco el tamaño.

Las propiedades horizontalScrollBarPolicy y verticalScrollBarPolicy a ALLWAYS.
Ahora en el panel Conexiones y creamos el evento para el botón Conectar
Código del botón Probar Conexión
try {
DatabaseConnection dbconn = null;
Object selected = dbconnComboBox.getSelectedItem();
if (selected instanceof DatabaseConnection) {
dbconn = (DatabaseConnection) selected;
}
sesion.conn = dbconn.getJDBCConnection(false);
if (sesion.conn == null) {
ConnectionManager.getDefault().showConnectionDialog(dbconn);
}
if (sesion.conn == null) {
JOptionPane.showMessageDialog(this, "Usuario no se ha conectado , realice la
conexión");
return;
}
//limpio la lista de tablas
sesion.ListaTablas.clear();
scene = new DBGraphScene(sesion.conn);
jScrollPane1.setViewportView(scene.createView());
JOptionPane.showMessageDialog(this, "Conectado");
jTextFieldPrefijo.setText(sesion.conn.getCatalog() + "_");
ldatabase = true;
if (couchdb == true) {
jButtonMigrar.setEnabled(true);
}
} catch (Exception ex) {
JOptionPane.showMessageDialog(this, ex.getLocalizedMessage().toString());
}

Nos envía varios errores de importación de paquetes verificar que estén estos
import java.sql.ResultSet;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
import org.netbeans.api.db.explorer.ConnectionManager;
import org.netbeans.api.db.explorer.DatabaseConnection;
import org.netbeans.api.db.explorer.support.DatabaseExplorerUIs;
import org.openide.util.NbBundle;
import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager;
//import org.openide.util.ImageUtilities;
import org.openide.util.ImageUtilities;
import java.sql.Connection;
import org.netbeans.api.settings.ConvertAsProperties;




Ahora creamos un objeto private DBGraphScene scene;

Instalamos el plugin y lo ejecutamos, seleccionamos una conexión a la base de datos y
presionamos el botón Conectar

Si no estaba conectado a la base de datos nos envía el mensaje

y damos clic en el Panel Tablas y podemos observar las tablas relacionadas.






Agregamos el API de progreso
Seleccionamos Bibliotecas

Necesitamos agregar el Api de Progreso. Para utilizar barras de progreso para los
operaciones
Seleccionamos de la lista

Debe aparecernos el Api agregado.