< Indietro | Avanti >

Visualizzazione di un record

In questa lezione, si acquisiscono informazioni su come visualizzare tutti i campi di un record restituito da una query utilizzando l'interfaccia PropertyRequest.
L'esempio di codice estende l'esempio nel modulo precedente (per l'esecuzione di una query) aggiungendo la possibilità di visualizzare tutti i campi di un record restituito da una query, non solo quelli nei campi di visualizzazione della query.

ExecuteQuery.run viene richiamato in modo che l'utente possa selezionare ed eseguire una query. In questo esempio, al metodo ExecuteQuerty.run viene fornita un'istanza effettiva di ExeuteQuerty.Viewer denominata ViewRecord.Viewer. Questa operazione comporta la comparsa di un pulsante Apri nella visualizzazione della serie di risultati, che, quando selezionato, richiama il metodo Viewer.view. Al metodo Viewer.view (definito di seguito) viene inoltrato un proxy per la risorsa associata alla riga selezionata della serie di risultati. Il proxy viene ottenuto utilizzando il metodo CqRowData.getRecord().

Il contenuto di questo esempio viene, quindi, incorporato nel metodo Viewer.view:

static class Viewer implements ExecuteQuery.Viewer {
    Viewer(CqProvider provider) {  m_provider = provider;  }
    
    /**
     * @see com.ibm.rational.stp.client.samples.ExecuteQuery.Viewer#view(com.ibm.rational.wvcm.stp.cq.CqRecord)
     */
    public JFrame view(CqRecord record)
    {
        if (record != null) try {
            record = (CqRecord)record.doReadProperties(RECORD_PROPERTIES);
            return showRecord("View: ", record, null);
        } catch (WvcmException ex){
            ex.printStackTrace();
        }
        
        return null;
    }
    
    /**
     * Visualizza il contenuto di una risorsa Allegato in una finestra di testo.
     * 
     * @param attachment Un proxy Allegati per l'allegato da
     *            visualizzare.
     */
    public void view(CqAttachment attachment)
    {
        if (attachment != null) try{
            File file = File.createTempFile("attach", "tmp");
            
            attachment.doReadContent(file.getAbsolutePath(), null);
            BrowserDataModel.showFile(attachment.getDisplayName(), file);
        } catch(Throwable ex) {
            Utilities.exception(null, "View Attachment", ex);
        }
    }
    
    /**
     * Visualizza la proprietà ALL_FIELD_VALUES di una risorsa record in una
     * tabella. Le colonne della tabella sono determinate dal contenuto
     * dell'array {@link #fieldMetaProperties}. La visualizzazione della maggior parte degli oggetti viene
     * implementata dal metodo toString() dell'oggetto.
     * 
     * @param title La stringa del titolo per la finestra che contiene la tabella
     * @param record Il proxy Record per il record da visualizzare. È necessario
     *            definire la proprietà ALL_FIELD_VALUES e FieldValues
     *            in tale proprietà deve definire le metaproprietà elencate
     *            nell'array {@link #fieldMetaProperties}.
     * @param future I componenti aggiuntivi della finestra da visualizzare con la
     *            tabella delle proprietà. (Utilizzati dalle estensioni per questo esempio).
     * @return Una struttura RecordFrame che contiene i componenti GUI creati
     *         da questo metodo.
     * @throws WvcmException
     */
    RecordFrame showRecord(String title, 
                           CqRecord record, 
                           JComponent[] future) throws WvcmException 
    {
        final StpProperty.List<CqFieldValue<?>> fields = 
            record.getAllFieldValues();
        
        // Definire un modello tabella in cui ciascuna riga è una proprietà della
        // risorsa record e ciascuna colonna è una metaproprietà della
        // proprietà, come ad esempio il nome, il tipo e il valore;
        TableModel dataModel = new AbstractTableModel() {
            private static final long serialVersionUID = 1L;
            public int getColumnCount() { return fieldMetaProperties.length; }
            public int getRowCount() { return fields.size();}
            public Object getValueAt(int row, int col) 
                { 
                    try {
                        Object val = fields.get(row)
                            .getMetaProperty((MetaPropertyName<?>)
                                             fieldMetaProperties[col].getRoot());
                        
                        if (val instanceof CqRecord)
                            return ((CqRecord)val).getUserFriendlyLocation()
                                .getName();
                        else if (val instanceof CqAttachmentFolder)
                            return ((CqAttachmentFolder)val)
                                .getAttachmentList().size()
                                + " attachments";
                        else
                            return val;
                            
                    } catch(Throwable ex) {
                        if (ex instanceof StpException) {
                            return ((StpException)ex).getStpReasonCode();  
                          } else {
                              String name = ex.getClass().getName();
                              return name.substring(name.lastIndexOf(".")+1);
                          }
                    }
                }
            public String getColumnName(int col)
                { return fieldMetaProperties[col].getRoot().getName(); }
        };
        
        // Definire il layout di visualizzazione
        final JTable table = new JTable(dataModel);
        final JPanel panel = new JPanel(new BorderLayout());
        final JPanel buttons = new JPanel(new FlowLayout());
        final JButton button = new JButton("View");
        final RecordFrame frame = 
            new RecordFrame(title + record.getUserFriendlyLocation().toString(),
                            table, fields);

        // Aggiungere un pulsante per la visualizzazione di un record selezionato o di un campo allegato
        buttons.add(button, BorderLayout.SOUTH);
        button.setEnabled(false);
        button.addActionListener(new ActionListener(){
                public void actionPerformed(ActionEvent arg0)
                {
                    int[] selected = table.getSelectedRows();
                    
                    for (int i =0; i < selected.length; ++i) {
                        int row = selected[i];
                        if (isAttachmentList(fields, row)) {
                            view(selectAttachment(frame, fields, row, "View"));
                        } else {
                            view(getRecordReferencedAt(fields, row));
                        }
                    }
                }
            });
        
        // Aggiungere ulteriori pulsanti (utilizzati dagli esempi successivi)
        if (future != null)
            for(int i = 0; i < future.length; ++i) buttons.add(future[i]);

        table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

        // Richiedere la notifica delle modifiche di selezione e abilitare il pulsante di visualizzazione
        // solo se viene selezionato un campo con valori di record o un campo allegato
        ListSelectionModel rowSM = table.getSelectionModel();
        rowSM.addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                if (!e.getValueIsAdjusting()){
                    int[] selected = table.getSelectedRows();
                    button.setEnabled(false);

                    for (int i=0; i <selected.length; ++i)
                        if (getRecordReferencedAt(fields, selected[i]) != null
                            || isAttachmentList(fields, selected[i])) {
                            button.setEnabled(true);
                            break;
                        }
                }
            }
        });

        panel.add(new JScrollPane(table), BorderLayout.CENTER);
        panel.add(buttons, BorderLayout.SOUTH);
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setContentPane(panel);
        frame.setBounds(g_windowX += 10, g_windowY += 10, 600, 300);
        frame.setVisible(true);
        
        return frame;
    }

    protected CqProvider m_provider;
}

/** 
 * Proprietà da richiedere da ciascun valore campo di record, incluse
 * le ulteriori informazioni specifiche per gli allegati
 */
static final PropertyRequest VALUE_PROPERTIES =
    new PropertyRequest(StpResource.USER_FRIENDLY_LOCATION,
                        CqAttachmentFolder.ATTACHMENT_LIST
                            .nest(CqAttachment.DISPLAY_NAME,
                                  CqAttachment.FILE_NAME,
                                  CqAttachment.FILE_SIZE,
                                  CqAttachment.DESCRIPTION));

/** Le metaproprietà del campo da richiedere e visualizzare */
static final NestedPropertyName[] fieldMetaProperties = 
    new PropertyRequest(CqFieldValue.NAME, 
                        CqFieldValue.REQUIREDNESS, 
                        CqFieldValue.TYPE,
                        CqFieldValue.VALUE.nest(VALUE_PROPERTIES)).toArray();
              
/** 
 * La PropertyRequest da utilizzare durante la lettura dei dati da un record che
 * questo programma di visualizzazione deve visualizzare. Notare il livello di riferimento indiretto utilizzato per richiedere
 * le metaproprietà dei campi nell'elenco ALL_FIELD_VALUES piuttosto che
 * le metaproprietà della proprietà ALL_FIELD_VALUES stessa.
 */
final static PropertyRequest RECORD_PROPERTIES =
    new PropertyRequest(CqRecord.USER_FRIENDLY_LOCATION,
                        CqRecord.ALL_FIELD_VALUES
                        .nest(StpProperty.VALUE.nest(fieldMetaProperties)));

/**
 * Esamina il valore proprietà di un campo e, se fa riferimento a un record,
 * restituisce un proxy per il record a cui si fa riferimento. Altrimenti, restituisce un valore nullo.
 * @param fields Property.List da esaminare.
 * @param row L'indice dell'elemento nell'elenco da esaminare.
 * @return Un proxy Record se il campo fa riferimento a un record; altrimenti, un valore nullo
 */
static CqRecord getRecordReferencedAt(StpProperty.List<CqFieldValue<?>> fields, 
                                      int row)
{
    try {
        CqFieldValue field = fields.get(row);
        
        if (field.getFieldType() == ValueType.RESOURCE 
            && field.getValue() instanceof CqRecord)
            return (CqRecord)field.getValue();
    } catch (WvcmException ex) { ex.printStackTrace(); }

    return null;
}

/**
 * Indica se il campo indicato è un campo allegato.
 * @param fields Property.List da esaminare.
 * @param row L'indice dell'elemento nell'elenco da esaminare.
 * @return true Se il campo nel determinato indice è un campo allegato
 */
static boolean isAttachmentList(StpProperty.List<CqFieldValue<?>> fields, 
                                int row)

{
    if (row >= 0) try {
        CqFieldValue field = fields.get(row);
        
        return field.getFieldType() == ValueType.ATTACHMENT_LIST;
    } catch (WvcmException ex) { ex.printStackTrace(); }

    return false;
}

/**
 * Presenta all'utente un elenco di allegati associati a un
 * campo specificato di un record e consente all'utente di selezionarne uno.
 * 
 * @param frame Il frame padre per la finestra di dialogo generata da questo metodo.
 * @param fields Property.List da esaminare.
 * @param row L'indice dell'elemento nell'elenco da esaminare.
 * @param op Una stringa che identifica l'operazione da eseguire
 *            sull'allegato selezionato.
 * @return Un proxy Allegato per l'allegato selezionato; un valore nullo se l'utente
 *         sceglie di non effettuare alcuna selezione.
 */
static CqAttachment 
selectAttachment(Component frame,
                 StpProperty.List<CqFieldValue<?>> fields,
                 int row,
                 String op)
{
    CqFieldValue field = fields.get(row);
    
    try {
        CqAttachmentFolder folder = (CqAttachmentFolder)field.getValue();
        ResourceList<CqAttachment> attachments = setUserFriendlyLocation
            (folder.doReadProperties(ATTACHMENT_PROPERTIES)
                .getProperty(CqAttachmentFolder.ATTACHMENT_LIST));
        
        if (attachments.size() > 0) {
            CqAttachment attachment =
                (CqAttachment) JOptionPane
                    .showInputDialog(frame,
                                     "Choose an Attachment to " + op,
                                     op + " Attachment",
                                     JOptionPane.INFORMATION_MESSAGE,
                                     null,
                                     attachments.toArray(),
                                     attachments.get(0));
            
            return attachment;
        }
     } catch(Throwable t) { Utilities.exception(frame, op + " Attachment", t);}

    return null;
}

/**
 * Le proprietà dell'allegato da visualizzare nell'elenco di selezione degli allegati
 * generato da {@link #selectAttachment}.
 */
final static PropertyRequest ATTACHMENT_PROPERTIES =
    new PropertyRequest(CqAttachmentFolder.ATTACHMENT_LIST
                            .nest(CqAttachment.DISPLAY_NAME,
                                  CqAttachment.FILE_NAME,
                                  CqAttachment.FILE_SIZE,
                                  CqAttachment.DESCRIPTION,
                                  CqAttachment.USER_FRIENDLY_LOCATION));

/**
 * Il programma principale per l'esempio ViewRecord. Crea un'istanza di un Provider e
 * quindi, richiama l'esempio ExecuteQuery, inoltrando una versione del programma di visualizzazione
 * che visualizza i campi di un record ClearQuest.
 * @param args non utilizzato.
 */
public static void main(String[] args)
{
    try {
        CqProvider provider = Utilities.getProvider().cqProvider();
        ExecuteQuery.run("View Record", provider, new Viewer(provider));
    } catch(Throwable ex) {
        Utilities.exception(null, "View Record", ex);
        System.exit(0);
    }
}

/**
 * Un'estensione di JFrame per la visualizzazione del campo di record,
 * presentando ai client il componente JTable del frame e
 * l'elenco di campi visualizzati nella tabella.
 */
static class RecordFrame extends JFrame
{
    RecordFrame(String title,
                JTable table,
                StpProperty.List fields)
    {
        super(title);

        m_table = table;
        m_fields = fields;
    }

    JTable m_table;
    StpProperty.List m_fields;
    private static final long serialVersionUID = 1L;
}

/** Offset X per la successiva finestra da visualizzare */
private static int g_windowX = 200;

/** Offset Y per la successiva finestra da visualizzare */
private static int g_windowY = 200;

In questo esempio, ViewRecord.Viewer viene utilizzato non solo per visualizzare un record restituito da una query, ma anche per visualizzare un record a cui un campo selezionato di un record fa riferimento e per visualizzare un file allegato a un campo di un record. L'utente può utilizzare questa funzione per sfogliare i riferimenti da un record a un altro.

ViewRecord.view(CqRecord) legge tutti i campi dal record nel database e le metaproprietà di ciascun campo utilizzato dal programma di visualizzazione e inoltra il proxy popolato al metodo showRecord. Il programma di visualizzazione utilizza la proprietà ALL_FIELD_VALUES di un record ClearQuest per ottenere un elenco di tutti i campi nel record. Per ciascun campo, le metaproprietà NAME, REQUIREDNESS, TYPE e VALUE sono richieste. Notare che le richieste metaproprietà sono nidificate in un'altra richiesta metaproprietà VALUE in modo che queste metaproprietà vengano ottenute per il valore della proprietà ALL_FIELD_VALUES e non solo per la proprietà ALL_FIELD_VALUES. (Consultare la dichiarazione di RECORD_PROPERTIES, VALUE_PROPERTIES e fieldMetaProperties.)

Nel caso in cui il campo fosse un campo allegato, viene anche richiesta la proprietà ATTACHMENT_LIST del valore. (Se non si tratta di un campo allegato, la richiesta di questa proprietà avrà esito negativo, ma poiché a questa proprietà si accede solo se il campo è un allegato, questo errore non comporterà una eccezione.)

ViewRecord.showRecord utilizza gli stessi componenti della GUI Swing e la stessa struttura di ExecuteQuery.showResults, solo il contenuto delle righe e delle colonne della tabella varia. In questo caso, ciascuna riga è un campo del record, espresso come oggetto CqFieldValue. Ciascuna colonna è una metaproprietà del campo. L'interfaccia StpProperty.getMetaProperty generica viene utilizzata per recuperare il valore metaproprietà dalla struttura di CqFieldValue/StpProperty per ciascun campo. Con due eccezioni, per la generazione di un'immagine della metaproprietà nella vista record ci si basa sul metodo toString() per ciascun valore metaproprietà. Per le risorse record, solo il campo nome della proprietà USER_FRIENDLY_LOCATION viene visualizzato per evitare confusione nell'output. Per i campi allegato, viene visualizzato solo il numero di allegati, non il nome di ciascun allegato.

Sarebbe inoltre opportuno dare una speciale attenzione alla visualizzazione dei tipi di campo RESOURCE_LIST, JOURNAL, STRING_LIST e STRING. Questo sarà un esercizio per il lettore.

Quando viene selezionato un campo allegato e l'utente fa clic sul pulsante visualizza, viene chiamato selectAttachment e il relativo risultato vene inoltrato a ViewRecord.view(CqAttachment). Il metodo selectAttachment utilizza nuovamente JOptionPane.showInputDialog per presentare all'utente un elenco di allegati associati al campo selezionato. Il valore di un campo allegato è una risorsa della cartella allegato. Gli allegati associati al campo sono membri collegati di tale cartella allegato.

ViewRecord.view(CqAttachment) utilizza CqAttachment.doReadContent per leggere il file allegato dal database in un file temporaneo e successivamente chiama un metodo del programma di utilità (tutto codice Swing) per visualizzare il file all'utente.

ViewRecord.Viewer dovrebbe inoltre supportare la visualizzazione dei valori RESOURCE_LIST in una finestra separata. Ma anche questo verrà lasciato come esercizio per il lettore.

È possibile utilizzare Rational CM API per scrivere le applicazioni client o i programmi di utilità per la visualizzazione dei record e dei relativi campi e valori campo.

Punto di controllo della lezione

Rational CM API consente all'utente di eseguire molte operazioni specifiche per Rational ClearQuest, come ad esempio l'esecuzione di una query, l'iterazione di una serie di risultati e la visualizzazione dei record e dei relativi campi. Ora che sono state fornite informazioni su come utilizzare Rational CM API per visualizzare un record, la fase successiva è ottenere informazioni su come modificare un record.
In questa lezione, sono state fornite informazioni su quanto segue:
  • Informazioni su varie interfacce Rational CM API specifiche per le risorse Rational ClearQuest.
  • Come scrivere il codice dell'applicazione client Rational CM API per richiamare i record, richiedere le proprietà e visualizzare i valori campo.

Feedback
< Indietro | Avanti >