< Zurück | Weiter >

Datensatz anzeigen

In dieser Lerneinheit lernen Sie, wie Sie mit der Schnittstelle PropertyRequest alle Felder eines Datensatzes anzeigen, der von einer Abfrage zurückgegeben wurde.
Das Codebeispiel erweitert das Beispiel im vorherigen Modul (für die Ausführung einer Abfrage), indem es die Möglichkeit bietet, alle Felder eines von einer Abfrage zurückgegebenen Datensatzes anzuzeigen, nicht nur diejenigen, die in den Anzeigefeldern der Abfrage enthalten sind.

Die Methode ExecuteQuery.run wird aufgerufen, damit der Benutzer eine Abfrage auswählen und ausführen kann. In diesem Beispiel wird für die Methode ExecuteQuerty.run eine reale Instanz des ExeuteQuerty.Viewer mit dem Namen ViewRecord.Viewer bereitgestellt. Daraufhin erscheint die Schaltfläche Open (Öffnen) in der Anzeige der Ergebnismenge, bei deren Anklicken die Methode Viewer.view aufgerufen wird. An die (unten definierte) Methode Viewer.view wird ein Proxy für die Ressource übergeben, die mit der ausgewählten Zeile in der Ergebnismenge verknüpft ist. Der Proxy wird mit der Methode CqRowData.getRecord() abgerufen.

Der Kern dieses Beispiels wird folglich in der Methode Viewer.view repräsentiert:

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;
    }
    
    /**
     * Zeigt den Inhalt der Attachment-Ressource in einem Textfenster an.
     * 
     * @param attachment - ein Attachment-Proxy für den Anhang, der
     * angezeigt werden soll.
          */
    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);
        }
    }
    
    /**
     * Zeigt die Eigenschaft ALL_FIELD_VALUES einer Datensatzressource in einer
     * Tabelle an. Die Spalten der Tabelle werden durch den Inhalt des Arrays
     * {@link #fieldMetaProperties} bestimmt. Die Anzeige der meisten Objekte wird
     * durch die Methode toString() des Objekts implementiert.
          * 
     * @param title - Die Titelzeichenfolge für das Fenster, das die Tabelle enthält.
     * @param record - Der Datensatz-Proxy für den Datensatz, der angezeigt werden soll.
     * Der Proxy muss die Eigenschaft ALL_FIELD_VALUES definieren, und die Feldwerte
     *            in dieser Eigenschaft müssen die Meta-Eigenschaften definieren, die im
     *            Array {@link #fieldMetaProperties} aufgelistet sind.
          * @param future - Zusätzliche Fensterelemente, die zusammen mit der Eigenschaften-
     *            tabelle angezeigt werden sollen. (Wird von Erweiterungen dieses
     *            Beispiels verwendet.)
     * @return - Eine RecordFrame-Struktur, die die von dieser Methode erstellten
     *           Elemente der Benutzerschnittstelle enthält.
          * @throws WvcmException
     */
    RecordFrame showRecord(String title, 
                           CqRecord record, 
                           JComponent[] future) throws WvcmException 
    {
        final StpProperty.List<CqFieldValue<?>> fields = 
            record.getAllFieldValues();
        
        // Definition eines Tabellenmodells, in dem jede Zeile eine
        // Eigenschaft der Datensatzressource ist und jede Spalte eine
        // Meta-Eigenschaft der Eigenschaft, z. B. ihr Name, Typ oder Wert.
                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(); }
        };
        
        // Definition des Anzeigelayouts
        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);

        // Hinzufügen einer Schaltfläche zum Anzeigen eines ausgewählten
        // Datensatzes oder eines Anhangfelds
        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));
                        }
                    }
                }
            });
        
        // Hinzufügen weiterer Schaltflächen (wird in späteren Beispielen verwendet) 
        if (future != null)
            for(int i = 0; i < future.length; ++i) buttons.add(future[i]);

        table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

        // Anfordern, dass bei Auswahländerungen eine Benachrichtigung erfolgt,
        // und Anzeigeschaltfläche nur dann aktivieren, wenn ein Feld mit
        // Datensatzwerten oder ein Anhangsfeld ausgewählt wird.
                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;
}

/** 
 * Eigenschaften, die aus jedem Datensatz-Feldwert abgerufen werden sollen,
 * einschließlich spezifischer zusätzlicher Informationen für Anhänge 
  */
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));

/** Die Meta-Eigenschaften des Felds, die angefordert und angezeigt werden sollen */
static final NestedPropertyName[] fieldMetaProperties = 
    new PropertyRequest(CqFieldValue.NAME, 
                        CqFieldValue.REQUIREDNESS, 
                        CqFieldValue.TYPE,
                        CqFieldValue.VALUE.nest(VALUE_PROPERTIES)).toArray();
              
/** 
 * Die Eingeschaftsanforderung (PropertyRequest), die verwendet werden soll, wenn
 * Daten aus einem Datensatz gelesen werden, der von diesem Viewer angezeigt werden
 * soll. Beachten Sie, dass eine Zwischenstufe verwendet wurde, um die Meta-Eigenschaften
 * der Felder in der Liste ALL_FIELD_VALUES anzufordern, anstatt diese
 * Meta-Eigenschaften der Eigenschaft ALL_FIELD_VALUES selbst anzufordern.
  */
final static PropertyRequest RECORD_PROPERTIES =
    new PropertyRequest(CqRecord.USER_FRIENDLY_LOCATION,
                        CqRecord.ALL_FIELD_VALUES
                        .nest(StpProperty.VALUE.nest(fieldMetaProperties)));

/**
 * Prüft den Eigenschaftswert eines Felds und, falls dieser einen Datensatz
 * referenziert, gibt einen Proxy für den referenzierten Datensatz zurück. * Andernfalls wird null zurückgegeben.
 * @param fields - Die Property.List, die geprüft werden soll.
 * @param row - Der Index des zu prüfenden Elements in der Liste.
 * @return Ein Datensatz-Proxy, wenn das Feld einen Datensatz
 * referenziert. Andernfalls null.
 */
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;
}

/**
 * Die Angabe, ob das angegebene Feld ein Anhangsfeld ist.
 * @param fields - die Property.List, die geprüft werden soll
 * @param row - der Index des zu prüfenden Elements in der Liste
 * @return true - wenn das Feld am angegebenen Index ein Anhangsfeld ist
 */
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;
}

/**
 * Zeigt dem Benutzer eine Liste der Anhänge an, die mit einem
 * angegebenen Feld eines Datensatzes verknüpft sind, und erlaubt
 * dem Benutzer die Auswahl eines Anhangs.
  * 
 * @param frame - der übergeordnete Frame für den von dieser Methode
 * generierten Dialog
 * @param fields - die Property.List, die geprüft werden soll
 * @param row - der Index des zu prüfenden Elements in der Liste
 * @param op - eine Zeichenfolge, die die Operation identifiziert, die
 *             für den ausgewählten Anhang ausgeführt wird
  * @return - ein Anhangs-Proxy für den ausgewählten Anhang oder null, falls
 *           der Benutzer keine Auswahl getroffen hat
  */
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;
}

/**
 * Die Anhangseigenschaften, die in der von {@link #selectAttachment}
 * generierten Anhangsauswahlliste angezeigt werden sollen.
  */
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));

/**
 * Das Hauptprogramm für das Beispiel ViewRecord. Erstellt eine Instanz eines
 * Providers und ruft anschließend das Beispiel ExecuteQuery auf, wobei eine Version
 * des Viewer übergeben wird, die Felder eines ClearQuest-Datensatzes anzeigt.
  * @param args - nicht verwendet.
 */
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);
    }
}

/**
 * Eine Erweiterung von JFrame für die Anzeige des Datensatzfelds,
 * die den Clients die JTable-Komponente des Frame und die Feldliste,
 * die in der Tabelle angezeigt wird, präsentiert.
  */
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;
}

/** X-Einrückung für das nächste Fenster, das angezeigt werden soll */
private static int g_windowX = 200;

/** Y-Einrückung für das nächste Fenster, das angezeigt werden soll */
private static int g_windowY = 200;

In diesem Beispiel wird mit ViewRecord.Viewer nicht nur ein von einer Abfrage zurückgegebener Datensatz angezeigt, sondern auch ein Datensatz, der von einem ausgewählten Feld eines Datensatzes referenziert wird, sowie eine Datei, die an ein Feld des Datensatzes angehängt ist. Der Benutzer kann dieses Feature verwenden, um den Referenzen von einem Datensatz zu einem anderen zu folgen.

ViewRecord.view(CqRecord) liest alle Felder aus dem Datensatz in der Datenbank sowie die Meta-Eigenschaften jedes vom Viewer verwendeten Felds, und übergibt den gefüllten Proxy an die Methode showRecord. Der Viewer verwendet die Eigenschaft ALL_FIELD_VALUES eines ClearQuest-Datensatzes, um eine Liste aller Felder im Datensatz abzurufen. Für jedes Feld werden die Meta-Eigenschaften "NAME", "REQUIREDNESS" (Erforderlichkeit), "TYPE" (Typ) und VALUE (Wert) angefordert. Beachten Sie, dass diese Anforderungen von Meta-Eigenschaften in einer weiteren Anforderung der Meta-Eigenschaft "VALUE" verschachtelt sind, so dass diese Meta-Eigenschaften für den Wert der Eigenschaft ALL_FIELD_VALUES angefordert werden und nicht für die Eigenschaft ALL_FIELD_VALUES selbst. (Siehe die Deklaration von RECORD_PROPERTIES, VALUE_PROPERTIES und fieldMetaProperties.)

Für den Fall, dass es sich bei dem Feld um ein Anhangsfeld handelt, wird auch die Eigenschaft ATTACHMENT_LIST des Werts angefordert. (Falls es sich bei dem Feld nicht um ein Anhangsfeld handelt, scheitert diese Eigenschaftsanforderung. Da diese Eigenschaft jedoch nur dann aufgerufen wird, wenn dieses Feld ein Anhangsfeld ist, löst dies keine Ausnahme aus.

ViewRecord.showRecord verwendet dieselben Swing-Komponenten der grafischen Benutzerschnittstelle und dieselbe Struktur wie ExecuteQuery.showResults. Nur der Inhalt der Zeilen und Spalten in der Tabelle weicht hiervon ab. In diesem Fall, ist jede Zeile ein Feld des Datensatzes, der als CqFieldValue-Objekt ausgedrückt wird. Jede Spalte ist eine Meta-Eigenschaft des Felds. Die generische Schnittstelle StpProperty.getMetaProperty wird verwendet, um jeden Wert einer Meta-Eigenschaft aus der CqFieldValue/StpProperty-Struktur für jedes Feld abzurufen. Abgesehen von zwei Ausnahmen, wird die Methode toString() für jeden Wert einer Meta-Eigenschaft dafür verwendet, ein Image der Meta-Eigenschaft in dieser Datensatzanzeige zu generieren. Für Datensatzressourcen wird nur das Namensfeld der Eigenschaft USER_FRIENDLY_LOCATION angezeigt, um die Ausgabe übersichtlicher zu gestalten. Für Anhangsfelder wird nur die Anzahl der Anhänge angezeigt, nicht jeder Anhangsname.

Der Anzeige der Felder RESOURCE_LIST, JOURNAL, STRING_LIST und STRING könnte ebenfalls besondere Aufmerksamkeit geschenkt werden. Dies wird dem Leser als Übung überlassen.

Wurde ein Anhangsfeld ausgewählt und die Schaltfläche View angeklickt, dann wird selectAttachment aufgerufen und das Ergebnis an ViewRecord.view(CqAttachment) übergeben. Die Methode selectAttachment verwendet erneut JOptionPane.showInputDialog, um dem Benutzer eine Liste der mit dem ausgewählten Feld verknüpften Anhänge zu präsentieren. Der Wert eines Anhangsfelds ist ein Anhangsordner. Die mit dem Feld verknüpften Anhänge sind gebundene Member dieses Anhangsordners.

ViewRecord.view(CqAttachment) verwendet CqAttachment.doReadContent, um die angehängte Datei aus der Datenbank in eine temporäre Datei zu lesen, und ruft anschließend eine Dienstprogrammmethode (alles im Swing-Code) auf, um die Datei dem Benutzer anzuzeigen.

Der ViewRecord.Viewer sollte auch die Anzeige der RESOURCE_LIST-Werte in einem separaten Fenster unterstützen. Aber auch dies wird dem Leser als Übung überlassen.

Mit der ClearQuest CM-API können Sie Clientanwendungen oder Dienstprogramme zum Anzeigen von Datensätzen sowie zum Anzeigen der Felder und Feldwerte in den Datensätzen schreiben.

Prüfpunkt der Lerneinheit

Mit der ClearQuest CM-API können Sie viele Operationen ausführen, die für Rational ClearQuest spezifisch sind, beispielsweise die Ausführung einer Abfrage, die Iteration einer Ergebnismenge und die Anzeige von Datensätzen und ihren Feldern. Nachdem Sie gelernt haben, wie Sie mit der ClearQuest CM-API einen Datensatz anzeigen, lernen Sie im nächsten Schritt, wie ein Datensatz geändert wird.
In dieser Lerneinheit haben Sie folgende Kenntnisse erworben:
  • Sie haben mehrere Schnittstellen der ClearQuest CM-API kennengelernt, die für Rational ClearQuest-Ressourcen spezifisch sind.
  • Sie haben gelernt, wie Sie Clientanwendungscode für die ClearQuest CM-API schreiben, um Datensätze abzurufen, Eigenschaften anzufordern und Feldwerte anzuzeigen.
< Zurück | Weiter >

Feedback