Autopsy  4.20.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
ContactArtifactViewer.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2020-2021 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.contentviewers.artifactviewers;
20 
21 import java.awt.Component;
22 import java.awt.GridBagConstraints;
23 import java.awt.GridBagLayout;
24 import java.awt.Insets;
25 import java.awt.event.ActionListener;
26 import java.awt.image.BufferedImage;
27 import java.io.File;
28 import java.io.IOException;
29 import java.util.ArrayList;
30 import java.util.Collection;
31 import java.util.Collections;
32 import java.util.HashMap;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.Optional;
36 import java.util.concurrent.CancellationException;
37 import java.util.concurrent.ExecutionException;
38 import java.util.logging.Level;
39 import java.util.stream.Collectors;
40 import javax.imageio.ImageIO;
41 import javax.swing.ImageIcon;
42 import javax.swing.JButton;
43 import javax.swing.JLabel;
44 import javax.swing.JScrollPane;
45 import javax.swing.SwingWorker;
46 import javax.swing.border.EmptyBorder;
47 import org.apache.commons.lang.StringUtils;
48 import org.openide.util.NbBundle;
49 import org.openide.util.lookup.ServiceProvider;
63 import org.sleuthkit.datamodel.AbstractFile;
64 import org.sleuthkit.datamodel.Account;
65 import org.sleuthkit.datamodel.BlackboardArtifact;
66 import org.sleuthkit.datamodel.BlackboardAttribute;
67 import org.sleuthkit.datamodel.CommunicationsManager;
68 import org.sleuthkit.datamodel.Content;
69 import org.sleuthkit.datamodel.DataSource;
70 import org.sleuthkit.datamodel.InvalidAccountIDException;
71 import org.sleuthkit.datamodel.TskCoreException;
72 
76 @ServiceProvider(service = ArtifactContentViewer.class)
77 public class ContactArtifactViewer extends javax.swing.JPanel implements ArtifactContentViewer {
78 
79  private final static Logger logger = Logger.getLogger(ContactArtifactViewer.class.getName());
80  private static final long serialVersionUID = 1L;
81 
82  private GridBagLayout m_gridBagLayout = new GridBagLayout();
83  private GridBagConstraints m_constraints = new GridBagConstraints();
84 
85  private JLabel personaSearchStatusLabel;
86 
87  private BlackboardArtifact contactArtifact;
88  private String contactName;
89  private String datasourceName;
90  private String hostName;
91 
92  private List<BlackboardAttribute> phoneNumList = new ArrayList<>();
93  private List<BlackboardAttribute> emailList = new ArrayList<>();
94  private List<BlackboardAttribute> nameList = new ArrayList<>();
95  private List<BlackboardAttribute> otherList = new ArrayList<>();
96  private List<BlackboardAttribute> accountAttributesList = new ArrayList<>();
97 
98  private final static String DEFAULT_IMAGE_PATH = "/org/sleuthkit/autopsy/images/defaultContact.png";
99  private final ImageIcon defaultImage;
100 
101  // A list of unique accounts matching the attributes of the contact artifact.
102  private final List<CentralRepoAccount> contactUniqueAccountsList = new ArrayList<>();
103 
104  // A list of all unique personas and their account, found by searching on the
105  // account identifier attributes of the Contact artifact.
106  private final Map<Persona, ArrayList<CentralRepoAccount>> contactUniquePersonasMap = new HashMap<>();
107 
109 
114  initComponents();
115  this.setBorder(new EmptyBorder(ContentViewerDefaults.getPanelInsets()));
116  defaultImage = new ImageIcon(ContactArtifactViewer.class.getResource(DEFAULT_IMAGE_PATH));
117  }
118 
124  @SuppressWarnings("unchecked")
125  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
126  private void initComponents() {
127 
128  setToolTipText(""); // NOI18N
129  setLayout(new java.awt.GridBagLayout());
130  }// </editor-fold>//GEN-END:initComponents
131 
132  @Override
133  public void setArtifact(BlackboardArtifact artifact) {
134  // Reset the panel.
135  resetComponent();
136 
137  if (artifact != null) {
138  try {
139  extractArtifactData(artifact);
140  } catch (NoCurrentCaseException | TskCoreException ex) {
141  logger.log(Level.SEVERE, String.format("Error getting attributes for artifact (artifact_id=%d, obj_id=%d)", artifact.getArtifactID(), artifact.getObjectID()), ex);
142  return;
143  }
144  updateView();
145  }
146  this.setLayout(this.m_gridBagLayout);
147  this.revalidate();
148  this.repaint();
149  }
150 
151  @Override
152  public Component getComponent() {
153  // Slap a vertical scrollbar on the panel.
154  return new JScrollPane(this, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
155  }
156 
157  @Override
158  public boolean isSupported(BlackboardArtifact artifact) {
159  return (artifact != null)
160  && (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID());
161  }
162 
170  private void extractArtifactData(BlackboardArtifact artifact) throws NoCurrentCaseException, TskCoreException {
171 
172  this.contactArtifact = artifact;
173 
174  phoneNumList = new ArrayList<>();
175  emailList = new ArrayList<>();
176  nameList = new ArrayList<>();
177  otherList = new ArrayList<>();
178  accountAttributesList = new ArrayList<>();
179 
180  // Get all the attributes and group them by the section panels they go in
181  for (BlackboardAttribute bba : contactArtifact.getAttributes()) {
182  if (bba.getAttributeType().getTypeName().startsWith("TSK_PHONE")) {
183  phoneNumList.add(bba);
184  accountAttributesList.add(bba);
185  } else if (bba.getAttributeType().getTypeName().startsWith("TSK_EMAIL")) {
186  emailList.add(bba);
187  accountAttributesList.add(bba);
188  } else if (bba.getAttributeType().getTypeName().startsWith("TSK_NAME")) {
189  nameList.add(bba);
190  } else {
191  otherList.add(bba);
192  if (bba.getAttributeType().getTypeName().equalsIgnoreCase("TSK_ID")) {
193  accountAttributesList.add(bba);
194  }
195  }
196  }
197 
198  datasourceName = contactArtifact.getDataSource().getName();
199 
200  hostName = Optional.ofNullable(Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().getHostByDataSource((DataSource) contactArtifact.getDataSource()))
201  .map(h -> h.getName())
202  .orElse(null);
203  }
204 
208  private void updateView() {
209 
210  // Update contact name, image, phone numbers
211  updateContactDetails();
212 
213  // update artifact source panel
214  updateSource();
215 
216  // show a empty Personas panel and kick off a serch for personas
217  initiatePersonasSearch();
218 
219  }
220 
224  @NbBundle.Messages({
225  "ContactArtifactViewer_phones_header=Phone",
226  "ContactArtifactViewer_emails_header=Email",
227  "ContactArtifactViewer_others_header=Other",})
228  private void updateContactDetails() {
229 
230  // update image and name.
231  updateContactImage(m_gridBagLayout, m_constraints);
232  updateContactName(m_gridBagLayout, m_constraints);
233 
234  // update contact attributes sections
235  updateContactMethodSection(phoneNumList, Bundle.ContactArtifactViewer_phones_header(), m_gridBagLayout, m_constraints);
236  updateContactMethodSection(emailList, Bundle.ContactArtifactViewer_emails_header(), m_gridBagLayout, m_constraints);
237  updateContactMethodSection(otherList, Bundle.ContactArtifactViewer_others_header(), m_gridBagLayout, m_constraints);
238  }
239 
247  @NbBundle.Messages({
248  "ContactArtifactViewer.contactImage.text=",})
249  private void updateContactImage(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) {
250  // place the image on the top right corner
251  Insets savedInsets = contactPanelConstraints.insets;
252  contactPanelConstraints.gridy = 0;
253  contactPanelConstraints.gridx = 0;
254  contactPanelConstraints.insets = new Insets(0, 0, ContentViewerDefaults.getLineSpacing(), 0);
255  int prevGridWidth = contactPanelConstraints.gridwidth;
256  contactPanelConstraints.gridwidth = 3;
257  contactPanelConstraints.anchor = GridBagConstraints.LINE_START;
258 
259  javax.swing.JLabel contactImage = new javax.swing.JLabel();
260  contactImage.setIcon(getImageFromArtifact(contactArtifact));
261  contactImage.setText(Bundle.ContactArtifactViewer_contactImage_text());
262 
263  // add image to top left corner of the page.
264  CommunicationArtifactViewerHelper.addComponent(this, contactPanelLayout, contactPanelConstraints, contactImage);
265  CommunicationArtifactViewerHelper.addLineEndGlue(this, contactPanelLayout, contactPanelConstraints);
266  contactPanelConstraints.gridy++;
267 
268  contactPanelConstraints.gridwidth = prevGridWidth;
269  contactPanelConstraints.insets = savedInsets;
270  }
271 
279  @NbBundle.Messages({
280  "ContactArtifactViewer_contactname_unknown=Unknown",})
281  private void updateContactName(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) {
282 
283  boolean foundName = false;
284  for (BlackboardAttribute bba : this.nameList) {
285  if (StringUtils.isEmpty(bba.getValueString()) == false) {
286  contactName = bba.getDisplayString();
287 
288  CommunicationArtifactViewerHelper.addHeader(this, contactPanelLayout, contactPanelConstraints, 0, contactName);
289  foundName = true;
290  break;
291  }
292  }
293  if (foundName == false) {
294  CommunicationArtifactViewerHelper.addHeader(this, contactPanelLayout, contactPanelConstraints, ContentViewerDefaults.getSectionSpacing(), Bundle.ContactArtifactViewer_contactname_unknown());
295  }
296  }
297 
308  private void updateContactMethodSection(List<BlackboardAttribute> sectionAttributesList, String sectionHeader, GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) {
309 
310  // If there are no attributes for this section, do nothing
311  if (sectionAttributesList.isEmpty()) {
312  return;
313  }
314 
315  CommunicationArtifactViewerHelper.addHeader(this, contactPanelLayout, contactPanelConstraints, ContentViewerDefaults.getSectionSpacing(), sectionHeader);
316  for (BlackboardAttribute bba : sectionAttributesList) {
317  CommunicationArtifactViewerHelper.addKey(this, contactPanelLayout, contactPanelConstraints, bba.getAttributeType().getDisplayName());
318  CommunicationArtifactViewerHelper.addValue(this, contactPanelLayout, contactPanelConstraints, bba.getDisplayString());
319  }
320  }
321 
325  @NbBundle.Messages({
326  "ContactArtifactViewer_heading_Source=Source",
327  "ContactArtifactViewer_label_datasource=Data Source",
328  "ContactArtifactViewer_label_host=Host",})
329  private void updateSource() {
330  CommunicationArtifactViewerHelper.addHeader(this, this.m_gridBagLayout, m_constraints, ContentViewerDefaults.getSectionSpacing(), Bundle.ContactArtifactViewer_heading_Source());
331  CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_label_host());
332  CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, m_constraints, StringUtils.defaultString(hostName));
333  CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_label_datasource());
334  CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, m_constraints, datasourceName);
335  }
336 
342  @NbBundle.Messages({
343  "ContactArtifactViewer_persona_header=Persona",
344  "ContactArtifactViewer_persona_searching=Searching...",
345  "ContactArtifactViewer_cr_disabled_message=Enable Central Repository to view, create and edit personas.",
346  "ContactArtifactViewer_persona_unknown=Unknown"
347  })
348  private void initiatePersonasSearch() {
349 
350  // add a section header
351  JLabel personaHeader = CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, m_constraints, ContentViewerDefaults.getSectionSpacing(), Bundle.ContactArtifactViewer_persona_header());
352 
353  m_constraints.gridy++;
354 
355  // add a status label
356  String personaStatusLabelText = CentralRepository.isEnabled()
357  ? Bundle.ContactArtifactViewer_persona_searching()
358  : Bundle.ContactArtifactViewer_persona_unknown();
359 
360  this.personaSearchStatusLabel = new javax.swing.JLabel();
361  personaSearchStatusLabel.setText(personaStatusLabelText);
362  personaSearchStatusLabel.setFont(ContentViewerDefaults.getMessageFont());
363 
364  m_constraints.gridx = 0;
365  m_constraints.anchor = GridBagConstraints.LINE_START;
366 
367  CommunicationArtifactViewerHelper.addComponent(this, m_gridBagLayout, m_constraints, personaSearchStatusLabel);
368 
370  // Kick off a background task to serach for personas for the contact
371  personaSearchTask = new ContactPersonaSearcherTask(contactArtifact);
372  personaSearchTask.execute();
373  } else {
374  personaHeader.setEnabled(false);
375  personaSearchStatusLabel.setEnabled(false);
376 
377  Insets messageInsets = new Insets(ContentViewerDefaults.getSectionSpacing(), 0, ContentViewerDefaults.getLineSpacing(), 0);
378  CommunicationArtifactViewerHelper.addMessageRow(this, m_gridBagLayout, messageInsets, m_constraints, Bundle.ContactArtifactViewer_cr_disabled_message());
379  m_constraints.gridy++;
380 
381  CommunicationArtifactViewerHelper.addPageEndGlue(this, m_gridBagLayout, this.m_constraints);
382  }
383 
384  }
385 
389  private void updatePersonas() {
390 
391  // Remove the "Searching....." label
392  this.remove(personaSearchStatusLabel);
393 
394  m_constraints.gridx = 0;
395  if (contactUniquePersonasMap.isEmpty()) {
396  // No persona found - show a button to create one.
397  showPersona(null, 0, Collections.emptyList(), this.m_gridBagLayout, this.m_constraints);
398  } else {
399  int matchCounter = 0;
400  for (Map.Entry<Persona, ArrayList<CentralRepoAccount>> entry : contactUniquePersonasMap.entrySet()) {
401  List<CentralRepoAccount> missingAccounts = new ArrayList<>();
402  ArrayList<CentralRepoAccount> personaAccounts = entry.getValue();
403  matchCounter++;
404 
405  // create a list of accounts missing from this persona
406  for (CentralRepoAccount account : contactUniqueAccountsList) {
407  if (personaAccounts.contains(account) == false) {
408  missingAccounts.add(account);
409  }
410  }
411 
412  showPersona(entry.getKey(), matchCounter, missingAccounts, m_gridBagLayout, m_constraints);
413  m_constraints.gridy += 2;
414  }
415  }
416 
417  // add veritcal glue at the end
418  CommunicationArtifactViewerHelper.addPageEndGlue(this, m_gridBagLayout, this.m_constraints);
419 
420  // redraw the panel
421  this.setLayout(this.m_gridBagLayout);
422  this.revalidate();
423  this.repaint();
424  }
425 
438  @NbBundle.Messages({
439  "ContactArtifactViewer_persona_label=Persona ",
440  "ContactArtifactViewer_persona_no_match=No matches found",
441  "ContactArtifactViewer_persona_button_view=View",
442  "ContactArtifactViewer_persona_button_new=Create",
443  "ContactArtifactViewer_persona_match_num=Match ",
444  "ContactArtifactViewer_missing_account_label=Missing contact account",
445  "ContactArtifactViewer_found_all_accounts_label=All accounts found."
446  })
447  private void showPersona(Persona persona, int matchNumber, List<CentralRepoAccount> missingAccountsList, GridBagLayout gridBagLayout, GridBagConstraints constraints) {
448 
449  // save the original insets
450  Insets savedInsets = constraints.insets;
451 
452  // Add a Match X label in col 0.
453  constraints.gridx = 0;
454  javax.swing.JLabel matchNumberLabel = CommunicationArtifactViewerHelper.addKey(this, gridBagLayout, constraints, String.format("%s %d", Bundle.ContactArtifactViewer_persona_match_num(), matchNumber).trim());
455 
456  javax.swing.JLabel personaNameLabel = new javax.swing.JLabel();
457  javax.swing.JButton personaButton = new javax.swing.JButton();
458 
459  String personaName;
460  String personaButtonText;
461  ActionListener personaButtonListener;
462  if (persona != null) {
463  personaName = persona.getName();
464  personaButtonText = Bundle.ContactArtifactViewer_persona_button_view();
465  personaButtonListener = new ViewPersonaButtonListener(this, persona);
466  } else {
467  matchNumberLabel.setVisible(false);
468  personaName = Bundle.ContactArtifactViewer_persona_no_match();
469  personaButtonText = Bundle.ContactArtifactViewer_persona_button_new();
470  personaButtonListener = new CreatePersonaButtonListener(this, new PersonaUIComponents(personaNameLabel, personaButton));
471  }
472 
473  //constraints.gridwidth = 1; // TBD: this may not be needed if we use single panel
474  constraints.gridx++;
475  constraints.insets = new Insets(0, ContentViewerDefaults.getColumnSpacing(), ContentViewerDefaults.getLineSpacing(), 0);
476  constraints.anchor = GridBagConstraints.LINE_START;
477  personaNameLabel.setText(personaName);
478  gridBagLayout.setConstraints(personaNameLabel, constraints);
479  CommunicationArtifactViewerHelper.addComponent(this, gridBagLayout, constraints, personaNameLabel);
480  //personasPanel.add(personaNameLabel);
481 
482  // Add a Persona action button
483  constraints.gridx++;
484  //constraints.gridwidth = 1;
485  personaButton.setText(personaButtonText);
486  personaButton.addActionListener(personaButtonListener);
487 
488  // Shirnk the button height.
489  personaButton.setMargin(new Insets(0, 5, 0, 5));
490  constraints.insets = new Insets(0, ContentViewerDefaults.getColumnSpacing(), ContentViewerDefaults.getLineSpacing(), 0);
491  constraints.anchor = GridBagConstraints.LINE_START;
492  gridBagLayout.setConstraints(personaButton, constraints);
493  CommunicationArtifactViewerHelper.addComponent(this, gridBagLayout, constraints, personaButton);
494  CommunicationArtifactViewerHelper.addLineEndGlue(this, gridBagLayout, constraints);
495 
496  constraints.insets = savedInsets;
497 
498  // if we have a persona, indicate if any of the contact's accounts are missing from it.
499  if (persona != null) {
500  if (missingAccountsList.isEmpty()) {
501  constraints.gridy++;
502  constraints.gridx = 1;
503  //constraints.insets = labelInsets;
504 
505  javax.swing.JLabel accountsStatus = new javax.swing.JLabel(Bundle.ContactArtifactViewer_found_all_accounts_label());
506  constraints.insets = new Insets(0, ContentViewerDefaults.getColumnSpacing(), ContentViewerDefaults.getLineSpacing(), 0);
507  constraints.anchor = GridBagConstraints.LINE_START;
508  CommunicationArtifactViewerHelper.addComponent(this, gridBagLayout, constraints, accountsStatus);
509  constraints.insets = savedInsets;
510 
511  CommunicationArtifactViewerHelper.addLineEndGlue(this, gridBagLayout, constraints);
512  } else {
513  // show missing accounts.
514  for (CentralRepoAccount missingAccount : missingAccountsList) {
515  //constraints.weightx = 0;
516  constraints.gridx = 0;
517  constraints.gridy++;
518 
519  // this needs an extra indent
520  CommunicationArtifactViewerHelper.addKeyAtCol(this, gridBagLayout, constraints, Bundle.ContactArtifactViewer_missing_account_label(), 1);
521  constraints.insets = savedInsets;
522 
523  CommunicationArtifactViewerHelper.addValueAtCol(this, gridBagLayout, constraints, missingAccount.getIdentifier(), 2);
524  }
525  }
526  }
527 
528  // restore insets
529  constraints.insets = savedInsets;
530  }
531 
535  private void resetComponent() {
536 
537  contactArtifact = null;
538  contactName = null;
539  datasourceName = null;
540 
541  contactUniqueAccountsList.clear();
542  contactUniquePersonasMap.clear();
543 
544  phoneNumList.clear();
545  emailList.clear();
546  nameList.clear();
547  otherList.clear();
548  accountAttributesList.clear();
549 
550  if (personaSearchTask != null) {
551  personaSearchTask.cancel(Boolean.TRUE);
552  personaSearchTask = null;
553  }
554 
555  // clear the panel
556  this.removeAll();
557  this.setLayout(null);
558 
559  m_gridBagLayout = new GridBagLayout();
560  m_constraints = new GridBagConstraints();
561 
562  m_constraints.anchor = GridBagConstraints.LINE_START;
563  m_constraints.gridy = 0;
564  m_constraints.gridx = 0;
565  m_constraints.weighty = 0.0;
566  m_constraints.weightx = 0.0; // keep components fixed horizontally.
567  m_constraints.insets = new java.awt.Insets(0, ContentViewerDefaults.getSectionIndent(), 0, 0);
568  m_constraints.fill = GridBagConstraints.NONE;
569 
570  }
571 
580  private ImageIcon getImageFromArtifact(BlackboardArtifact artifact) {
581  ImageIcon imageIcon = defaultImage;
582 
583  if (artifact == null) {
584  return imageIcon;
585  }
586 
587  BlackboardArtifact.ARTIFACT_TYPE artifactType = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID());
588  if (artifactType != BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT) {
589  return imageIcon;
590  }
591 
592  try {
593  for (Content content : artifact.getChildren()) {
594  if (content instanceof AbstractFile) {
595  AbstractFile file = (AbstractFile) content;
596 
597  try {
598  BufferedImage image = ImageIO.read(new File(file.getLocalAbsPath()));
599  imageIcon = new ImageIcon(image);
600  break;
601  } catch (IOException ex) {
602  // ImageIO.read will throw an IOException if file is not an image
603  // therefore we don't need to report this exception just try
604  // the next file.
605  }
606  }
607  }
608  } catch (TskCoreException ex) {
609  logger.log(Level.WARNING, String.format("Unable to load image for contact: %d", artifact.getId()), ex);
610  }
611 
612  return imageIcon;
613  }
614 
619  private class ContactPersonaSearcherTask extends SwingWorker<Map<Persona, ArrayList<CentralRepoAccount>>, Void> {
620 
621  private final BlackboardArtifact artifact;
622  private final List<CentralRepoAccount> uniqueAccountsList = new ArrayList<>();
623 
630  ContactPersonaSearcherTask(BlackboardArtifact artifact) {
631  this.artifact = artifact;
632  }
633 
634  @Override
635  protected Map<Persona, ArrayList<CentralRepoAccount>> doInBackground() throws Exception {
636 
637  Map<Persona, ArrayList<CentralRepoAccount>> uniquePersonas = new HashMap<>();
638  CommunicationsManager commManager = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager();
639  List<Account> contactAccountsList = commManager.getAccountsRelatedToArtifact(artifact);
640 
641  for (Account account : contactAccountsList) {
642  try {
643  if (isCancelled()) {
644  return new HashMap<>();
645  }
646 
647  // make a list of all unique accounts for this contact
648  if (!account.getAccountType().equals(Account.Type.DEVICE)) {
649  Optional<CentralRepoAccount.CentralRepoAccountType> optCrAccountType = CentralRepository.getInstance().getAccountTypeByName(account.getAccountType().getTypeName());
650  if (optCrAccountType.isPresent()) {
651  CentralRepoAccount crAccount = CentralRepository.getInstance().getAccount(optCrAccountType.get(), account.getTypeSpecificID());
652 
653  if (crAccount != null && uniqueAccountsList.contains(crAccount) == false) {
654  uniqueAccountsList.add(crAccount);
655  }
656  }
657  }
658 
659  Collection<PersonaAccount> personaAccounts = PersonaAccount.getPersonaAccountsForAccount(account);
660  if (personaAccounts != null && !personaAccounts.isEmpty()) {
661  // get personas for the account
662  Collection<Persona> personas
663  = personaAccounts
664  .stream()
666  .collect(Collectors.toList());
667 
668  // make a list of unique personas, along with all their accounts
669  for (Persona persona : personas) {
670  if (uniquePersonas.containsKey(persona) == false) {
671  Collection<CentralRepoAccount> accounts = persona.getPersonaAccounts()
672  .stream()
674  .collect(Collectors.toList());
675 
676  ArrayList<CentralRepoAccount> personaAccountsList = new ArrayList<>(accounts);
677  uniquePersonas.put(persona, personaAccountsList);
678  }
679  }
680  }
681  } catch (InvalidAccountIDException ex) {
682  // Do nothing, the account has an identifier that not an
683  // acceptable format for the cr.
684  }
685  }
686 
687  return uniquePersonas;
688  }
689 
690  @Override
691  protected void done() {
692 
693  Map<Persona, ArrayList<CentralRepoAccount>> personasMap;
694  try {
695  personasMap = super.get();
696 
697  if (this.isCancelled()) {
698  return;
699  }
700 
701  contactUniquePersonasMap.clear();
702  contactUniquePersonasMap.putAll(personasMap);
703  contactUniqueAccountsList.clear();
704  contactUniqueAccountsList.addAll(uniqueAccountsList);
705 
706  updatePersonas();
707 
708  } catch (CancellationException ex) {
709  logger.log(Level.INFO, "Persona searching was canceled."); //NON-NLS
710  } catch (InterruptedException ex) {
711  logger.log(Level.INFO, "Persona searching was interrupted."); //NON-NLS
712  } catch (ExecutionException ex) {
713  logger.log(Level.SEVERE, "Fatal error during Persona search.", ex); //NON-NLS
714  }
715 
716  }
717  }
718 
723  private class PersonaUIComponents {
724 
725  private final JLabel personaNameLabel;
726  private final JButton personaActionButton;
727 
734  PersonaUIComponents(JLabel personaNameLabel, JButton personaActionButton) {
735  this.personaNameLabel = personaNameLabel;
736  this.personaActionButton = personaActionButton;
737  }
738 
744  public JLabel getPersonaNameLabel() {
745  return personaNameLabel;
746  }
747 
753  public JButton getPersonaActionButton() {
754  return personaActionButton;
755  }
756  }
757 
761  private class CreatePersonaButtonListener implements ActionListener {
762 
763  private final Component parentComponent;
765 
771  CreatePersonaButtonListener(Component parentComponent, PersonaUIComponents personaUIComponents) {
772  this.personaUIComponents = personaUIComponents;
773  this.parentComponent = parentComponent;
774  }
775 
776  @NbBundle.Messages({
777  "ContactArtifactViewer_persona_account_justification=Account found in Contact artifact",
778  "# {0} - accountIdentifer",
779  "ContactArtifactViewer_id_not_found_in_cr=Unable to find account(s) associated with contact {0} in the Central Repository."
780  })
781 
782  @Override
783  public void actionPerformed(java.awt.event.ActionEvent evt) {
784  // Launch the Persona Create dialog - do not display immediately
785  PersonaDetailsDialog createPersonaDialog = new PersonaDetailsDialog(parentComponent,
786  PersonaDetailsMode.CREATE, null, new PersonaCreateCallbackImpl(parentComponent, personaUIComponents), false);
787 
788  // Pre populate the persona name and accounts if we have them.
789  PersonaDetailsPanel personaPanel = createPersonaDialog.getDetailsPanel();
790 
791  if (contactName != null) {
792  personaPanel.setPersonaName(contactName);
793  }
794 
795  // pass the list of accounts to the dialog
796  for (CentralRepoAccount account : contactUniqueAccountsList) {
797  personaPanel.addAccount(account, Bundle.ContactArtifactViewer_persona_account_justification(), Persona.Confidence.HIGH);
798  }
799 
800  if (contactName != null && contactUniqueAccountsList.isEmpty()) {
801  createPersonaDialog.setStartupPopupMessage(Bundle.ContactArtifactViewer_id_not_found_in_cr(contactName));
802  }
803 
804  // display the dialog now
805  createPersonaDialog.display();
806  }
807  }
808 
812  private class ViewPersonaButtonListener implements ActionListener {
813 
814  private final Persona persona;
815  private final Component parentComponent;
816 
822  ViewPersonaButtonListener(Component parentComponent, Persona persona) {
823  this.persona = persona;
824  this.parentComponent = parentComponent;
825  }
826 
827  @Override
828  public void actionPerformed(java.awt.event.ActionEvent evt) {
829  new PersonaDetailsDialog(parentComponent,
830  PersonaDetailsMode.VIEW, persona, new PersonaViewCallbackImpl());
831  }
832  }
833 
837  class PersonaCreateCallbackImpl implements PersonaDetailsDialogCallback {
838 
839  private final Component parentComponent;
840  private final PersonaUIComponents personaUIComponents;
841 
847  PersonaCreateCallbackImpl(Component parentComponent, PersonaUIComponents personaUIComponents) {
848  this.parentComponent = parentComponent;
849  this.personaUIComponents = personaUIComponents;
850  }
851 
852  @Override
853  public void callback(Persona persona) {
854  JButton personaButton = personaUIComponents.getPersonaActionButton();
855  if (persona != null) {
856  // update the persona name label with newly created persona,
857  // and change the button to a "View" button
858  personaUIComponents.getPersonaNameLabel().setText(persona.getName());
859  personaUIComponents.getPersonaActionButton().setText(Bundle.ContactArtifactViewer_persona_button_view());
860 
861  // replace action listener with a View button listener
862  for (ActionListener act : personaButton.getActionListeners()) {
863  personaButton.removeActionListener(act);
864  }
865  personaButton.addActionListener(new ViewPersonaButtonListener(parentComponent, persona));
866 
867  }
868 
869  personaButton.getParent().revalidate();
870  personaButton.getParent().repaint();
871  }
872  }
873 
877  class PersonaViewCallbackImpl implements PersonaDetailsDialogCallback {
878 
879  @Override
880  public void callback(Persona persona) {
881  // nothing to do
882  }
883  }
884 
885  // Variables declaration - do not modify//GEN-BEGIN:variables
886  // End of variables declaration//GEN-END:variables
887 }
boolean addAccount(CentralRepoAccount account, String justification, Persona.Confidence confidence)
static Collection< PersonaAccount > getPersonaAccountsForAccount(long accountId)
void showPersona(Persona persona, int matchNumber, List< CentralRepoAccount > missingAccountsList, GridBagLayout gridBagLayout, GridBagConstraints constraints)
CentralRepoAccount getAccount(CentralRepoAccount.CentralRepoAccountType crAccountType, String accountUniqueID)
void updateContactName(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints)
void updateContactImage(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints)
Optional< CentralRepoAccountType > getAccountTypeByName(String accountTypeName)
void updateContactMethodSection(List< BlackboardAttribute > sectionAttributesList, String sectionHeader, GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124

Copyright © 2012-2022 Basis Technology. Generated on: Tue Aug 1 2023
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.