View Javadoc
1   /*******************************************************************************
2    * Copyright 2012 Internet2
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   ******************************************************************************/
16  /*
17   * @author mchyzer
18   * $Id: GuiSubject.java,v 1.2 2009-10-11 22:04:17 mchyzer Exp $
19   */
20  package edu.internet2.middleware.grouper.grouperUi.beans.api;
21  
22  import java.io.Serializable;
23  import java.util.HashMap;
24  import java.util.LinkedHashMap;
25  import java.util.LinkedHashSet;
26  import java.util.Map;
27  import java.util.Set;
28  
29  import org.apache.commons.lang.StringUtils;
30  
31  import edu.internet2.middleware.grouper.Group;
32  import edu.internet2.middleware.grouper.GroupFinder;
33  import edu.internet2.middleware.grouper.GrouperSession;
34  import edu.internet2.middleware.grouper.GrouperSourceAdapter;
35  import edu.internet2.middleware.grouper.Member;
36  import edu.internet2.middleware.grouper.MemberFinder;
37  import edu.internet2.middleware.grouper.SubjectFinder;
38  import edu.internet2.middleware.grouper.entity.EntitySourceAdapter;
39  import edu.internet2.middleware.grouper.exception.GrouperSessionException;
40  import edu.internet2.middleware.grouper.grouperUi.beans.ui.GrouperRequestContainer;
41  import edu.internet2.middleware.grouper.grouperUi.beans.ui.TextContainer;
42  import edu.internet2.middleware.grouper.misc.GrouperObject;
43  import edu.internet2.middleware.grouper.misc.GrouperSessionHandler;
44  import edu.internet2.middleware.grouper.subj.GrouperSubject;
45  import edu.internet2.middleware.grouper.subj.SubjectHelper;
46  import edu.internet2.middleware.grouper.subj.UnresolvableSubject;
47  import edu.internet2.middleware.grouper.ui.util.GrouperUiConfig;
48  import edu.internet2.middleware.grouper.ui.util.GrouperUiUtils;
49  import edu.internet2.middleware.grouper.util.GrouperEmailUtils;
50  import edu.internet2.middleware.grouper.util.GrouperUtil;
51  import edu.internet2.middleware.subject.Source;
52  import edu.internet2.middleware.subject.Subject;
53  import edu.internet2.middleware.subject.provider.SourceManager;
54  
55  
56  /**
57   * subject for gui has all attributes etc, and getter to be accessed from screen
58   */
59  @SuppressWarnings("serial")
60  public class GuiSubject extends GuiObjectBase implements Serializable {
61  
62    /**
63     * return source id two pipes and subject id
64     * @return the source id two pipes and subject id
65     */
66    public String getSourceIdSubjectId() {
67      if (this.subject == null) {
68        return null;
69      }
70      return this.subject.getSourceId() + "||" + this.subject.getId();
71    }
72    
73    /**
74     * 
75     * @see java.lang.Object#equals(java.lang.Object)
76     */
77    public boolean equals(Object other) {
78      if (this == other) {
79        return true;
80      }
81      if (!(other instanceof GuiSubject)) {
82        return false;
83      }
84      return SubjectHelper.eq(this.subject, ((GuiSubject)other).subject);
85    }
86  
87    /**
88     * @see java.lang.Object#hashCode()
89     */
90    public int hashCode() {
91      return SubjectHelper.hashcode(this.subject);
92    }
93  
94    /**
95     * get the member id of the subject or null if not there
96     * @return the member id if exists or null if not
97     */
98    public String getMemberId() {
99      Member theMember = this.getMember();
100     return theMember == null ? null : theMember.getId();
101   }
102   
103   /**
104    * member
105    */
106   private Member member;
107   
108   /**
109    * get the member of the subject or null if not there
110    * @return the member if exists or null if not
111    */
112   public Member getMember() {
113     
114     if (this.member == null) {
115       GrouperSession grouperSession = GrouperSession.staticGrouperSession(false);
116       
117       //when converting json this is null, so dont do a query if just doing json beans
118       if (grouperSession != null) {
119         this.member = MemberFinder.findBySubject(grouperSession, this.getSubject(), false);
120       }
121     }
122     return this.member;
123   }
124   
125   /**
126    * if the gui subject has an email address
127    * @return true if the subject has email
128    */
129   public boolean isHasEmailAttributeInSource() {
130     if (this.subject == null) {
131       return false;
132     }
133     //if there is an email attribute in the source, then this is true
134     return !StringUtils.isBlank(GrouperEmailUtils.emailAttributeNameForSource(this.subject.getSourceId()));
135   }
136 
137   /**
138    * get the email attribute value
139    * @return the email or null or blank if not there
140    */
141   public String getEmail() {
142     if (this.subject == null) {
143       return null;
144     }
145     String emailAttributeName = GrouperEmailUtils.emailAttributeNameForSource(this.subject.getSourceId());
146     if (StringUtils.isBlank(emailAttributeName)) {
147       return null;
148     }
149     return this.subject.getAttributeValue(emailAttributeName);
150   }
151   
152   /**
153    * 
154    * @param subjects
155    * @return subjects
156    */
157   public static Set<GuiSubject> convertFromSubjects(Set<Subject> subjects) {
158     return convertFromSubjects(subjects, null, -1);
159   }
160 
161 
162   /**
163    * 
164    * @param subjects
165    * @return gui subjects
166    */
167   public static Set<GuiSubject> convertFromSubjects(Set<Subject> subjects, String configMax, int defaultMax) {
168 
169     Set<GuiSubject> tempSubjects = new LinkedHashSet<GuiSubject>();
170     
171     Integer max = null;
172     
173     if (!StringUtils.isBlank(configMax)) {
174       max = GrouperUiConfig.retrieveConfig().propertyValueInt(configMax, defaultMax);
175     }
176     
177     int count = 0;
178     for (Subject subject : GrouperUtil.nonNull(subjects)) {
179       tempSubjects.add(new GuiSubject(subject));
180       if (max != null && ++count >= max) {
181         break;
182       }
183     }
184     
185     return tempSubjects;
186     
187   }
188 
189   /**
190    * see if group or not
191    * @return if group
192    */
193   public boolean isGroup() {
194     if (this.subject == null) {
195       return false;
196     }
197     return StringUtils.equals(SubjectFinder.internal_getGSA().getId(), this.subject.getSourceId());
198   }
199   
200   /** subject */
201   private Subject subject;
202 
203   /**
204    * e.g. &lt;a href="#"&gt;John Smith&lt;/a&gt;
205    * @return short link
206    */
207   public String getShortLink() {
208     this.initScreenLabels();
209     return this.screenLabelShort2html;
210   }
211   
212   /**
213    * e.g. &lt;a href="#"&gt;John Smith&lt;/a&gt;
214    * @return short link
215    */
216   public String getShortLinkWithIcon() {
217     this.initScreenLabels();
218     return this.screenLabelShort2htmlWithIcon;
219   }
220 
221   /**
222    * e.g. &lt;a href="#"&gt;John Smith&lt;/a&gt;
223    * @return short link
224    */
225   public String getScreenLabelShort2noLink() {
226     this.initScreenLabels();
227     return this.screenLabelShort2noLink;
228   }
229 
230   /**
231    * some source Id that isnt a normal grouper one
232    */
233   private static String sourceId = null;
234   
235   /**
236    * 
237    * @return a source id
238    */
239   public static String someSourceId() {
240     if (sourceId == null) {
241       synchronized (GuiSubject.class) {
242         if (sourceId == null) {
243           //pick one at random?
244           String theSourceId = "g:gsa";
245           
246           for (Source source : SourceManager.getInstance().getSources()) {
247             if (!"g:gsa".equals(source.getId())
248                 && !"grouperEntities".equals(source.getId())
249                 && !"grouperExternal".equals(source.getId())
250                 && !"g:isa".equals(source.getId())) {
251               theSourceId = source.getId();
252               break;
253             }
254           }
255           sourceId = theSourceId;
256           
257         }
258       }
259     }
260     return sourceId;
261   }
262   
263   /**
264    * init screen labels
265    */
266   private void initScreenLabels() {
267     
268     if (this.subject == null) {
269 
270       //unresolvable
271       this.subject = new UnresolvableSubject("", null, someSourceId());
272       
273     }
274     
275     if (this.screenLabelLong == null && this.screenLabelShort == null) {
276       
277       boolean convertToUnresolvableSubject = false;
278       String unresolvableSubjectString = TextContainer.retrieveFromRequest().getText().get("guiUnresolvableSubject");
279       
280       if (this.subject instanceof UnresolvableSubject) {
281         if (!StringUtils.equals(unresolvableSubjectString, ((UnresolvableSubject)this.subject).getUnresolvableString())) {
282           //we want to use the unresolvable string from the externalized text file in the UI
283           convertToUnresolvableSubject = true;
284         }
285         
286         //convert from lazy subject error to an unresolvable
287       } else if (this.subject != null && this.subject.getName() != null && this.subject.getName().contains(" entity not found")) {
288         convertToUnresolvableSubject = true;
289       }
290 
291       if (convertToUnresolvableSubject) {
292         
293         this.subject = new UnresolvableSubject(this.subject.getId(), this.subject.getTypeName(), this.subject.getSourceId(), unresolvableSubjectString);
294 
295       }
296 
297       boolean isUnresolvableGroup = false;
298       
299       
300       if (this.subject instanceof UnresolvableSubject) {
301         if (StringUtils.equals(GrouperSourceAdapter.groupSourceId(), this.subject.getSourceId())
302             || StringUtils.equals(EntitySourceAdapter.entitySourceId(), this.subject.getSourceId())) {
303           
304           isUnresolvableGroup = true;
305           
306           GrouperRequestContainer.retrieveFromRequestOrCreate().getCommonRequestContainer().setSubjectId(this.subject.getId());
307           String extensionName = null;
308           if (StringUtils.equals(GrouperSourceAdapter.groupSourceId(), this.subject.getSourceId())) {
309             extensionName = TextContainer.retrieveFromRequest().getText().get("guiGroupCantView");
310           } else {
311             extensionName = TextContainer.retrieveFromRequest().getText().get("guiEntityCantView");
312           }
313           GrouperRequestContainer.retrieveFromRequestOrCreate().getCommonRequestContainer().setSubjectId(null);
314 
315           //the user does not have view on this group or entity!
316           Map<String, Set<String>> subjectAttributes = this.subject.getAttributes();
317           subjectAttributes.put("displayExtension", GrouperUtil.toSet(StringUtils.abbreviate(extensionName, 33)));
318           subjectAttributes.put("displayName", GrouperUtil.toSet(extensionName));
319           ((UnresolvableSubject) this.subject).setDescription(extensionName);
320           ((UnresolvableSubject) this.subject).setAttributes(subjectAttributes);
321         }
322       }
323       
324       String screenLabel = GrouperUiUtils.convertSubjectToLabelLong(this.subject);
325             
326       this.screenLabelLong = screenLabel;
327       
328       screenLabel = GrouperUiUtils.convertSubjectToLabel(this.subject);
329       
330       int maxWidth = GrouperUiConfig.retrieveConfig().propertyValueInt("subject.maxChars", 100);
331       if (maxWidth == -1) {
332         this.screenLabelShort = screenLabel;
333       } else {
334         this.screenLabelShort = StringUtils.abbreviate(screenLabel, maxWidth);
335       }
336 
337       screenLabel = GrouperUiUtils.convertSubjectToLabelHtmlConfigured2(this.subject);
338       
339       maxWidth = GrouperUiConfig.retrieveConfig().propertyValueInt("subject2.maxChars", 40);
340       if (maxWidth == -1) {
341         this.screenLabelShort2 = screenLabel;
342       } else {
343         this.screenLabelShort2 = StringUtils.abbreviate(screenLabel, maxWidth);
344       }
345 
346       this.screenSubjectIcon2Html = GrouperUiUtils.convertSubjectToIconHtmlConfigured2(this.subject);
347 
348       boolean hasTooltip = this.subject != null
349         && !StringUtils.isBlank(this.subject.getDescription()) && !StringUtils.equals(this.subject.getName(), this.subject.getDescription());
350       
351       GrouperRequestContainer.retrieveFromRequestOrCreate().getCommonRequestContainer().setShowTooltip(hasTooltip);
352       GrouperRequestContainer.retrieveFromRequestOrCreate().getCommonRequestContainer().setGuiSubject(this);
353       
354       try {
355         
356         //"<a href=\"view-subject.html\" rel=\"tooltip\" data-html=\"true\" data-delay-show=\"200\" data-placement=\"right\" title=\"" + GrouperUtil.xmlEscape(subject.getDescription(), true)  + "\">" + this.screenLabelShort2 + "</a>";
357         //"<a href=\"view-subject.html\" data-html=\"true\" data-delay-show=\"200\" data-placement=\"right\">" + this.screenLabelShort2 + "</a>";
358         Group group = null;
359         
360         if (this.isGroup()) {
361           if (this.subject instanceof GrouperSubject) {
362             group = ((GrouperSubject)this.subject).internal_getGroup();
363           }
364           if (group == null) {
365             group = GroupFinder.findByUuid(GrouperSession.staticGrouperSession(), this.subject.getId(), false);
366           }
367           if (group == null) {
368             group = new Group();
369             group.setId(this.subject.getId());
370             String cantFindGroupName = this.subject.getAttributeValue("displayName");
371             String cantFindGroupExtension = this.subject.getAttributeValue("displayExtension");
372             group.setNameDb(cantFindGroupName);
373             group.setDisplayNameDb(cantFindGroupName);
374             group.setExtensionDb(cantFindGroupExtension);
375             group.setDisplayExtensionDb(cantFindGroupExtension);
376             group.setDescriptionDb(cantFindGroupName);
377           }
378         }
379         
380         if (group != null) {
381           GrouperRequestContainer.retrieveFromRequestOrCreate().getCommonRequestContainer().setGuiGroup(new GuiGroup(group));
382           this.screenLabelShort2html = TextContainer.retrieveFromRequest().getText().get("guiGroupShortLink");
383         } else {
384           
385           this.screenLabelShort2html = TextContainer.retrieveFromRequest().getText().get("guiSubjectShortLink");
386         }
387         
388         GrouperRequestContainer.retrieveFromRequestOrCreate().getCommonRequestContainer().setShowIcon(true);
389 
390         if (group != null) {
391           this.screenLabelLongWithIcon = TextContainer.retrieveFromRequest().getText().get("guiGroupLongLinkWithIcon");
392         } else {
393           this.screenLabelLongWithIcon = TextContainer.retrieveFromRequest().getText().get("guiSubjectLongLinkWithIcon");
394         }
395         
396 
397         if (group != null) {
398           this.screenLabelShort2htmlWithIcon = TextContainer.retrieveFromRequest().getText().get("guiGroupShortLink");
399         } else {
400           this.screenLabelShort2htmlWithIcon = TextContainer.retrieveFromRequest().getText().get("guiSubjectShortLink");
401         }
402         
403         if (group != null) {
404           this.screenLabelShort2noLinkWithIcon = TextContainer.retrieveFromRequest().getText().get("guiGroupShort");
405         } else {
406           this.screenLabelShort2noLinkWithIcon = TextContainer.retrieveFromRequest().getText().get("guiSubjectShort");
407         }
408         
409         GrouperRequestContainer.retrieveFromRequestOrCreate().getCommonRequestContainer().setShowIcon(false);
410 
411         if (group != null) {
412           this.screenLabelShort2noLink = TextContainer.retrieveFromRequest().getText().get("guiGroupShort");
413         } else {
414           this.screenLabelShort2noLink = TextContainer.retrieveFromRequest().getText().get("guiSubjectShort");
415         }
416 
417       } finally {
418 
419         GrouperRequestContainer.retrieveFromRequestOrCreate().getCommonRequestContainer().setGuiSubject(null);
420         GrouperRequestContainer.retrieveFromRequestOrCreate().getCommonRequestContainer().setShowTooltip(false);
421         GrouperRequestContainer.retrieveFromRequestOrCreate().getCommonRequestContainer().setShowIcon(false);
422 
423       }
424 
425     }
426   }
427 
428   /**
429    * short screen label for ui v2
430    * @return label
431    */
432   public String getScreenLabelShort2() {
433     this.initScreenLabels();
434     return this.screenLabelShort2;
435   }
436 
437   /**
438    * span for subject-specific icon for ui v2; e.g. '&lt;i class="fa fa-group"&gt;&lt;/i&gt; '
439    * @return label
440    */
441   public String getScreenSubjectIcon2Html() {
442     this.initScreenLabels();
443     return this.screenSubjectIcon2Html;
444   }
445 
446   /**
447    * construct with subject
448    * @param subject1
449    */
450   public GuiSubject(Subject subject1) {
451     this.subject = subject1;
452   }
453   
454   /**
455    * get screen label
456    * @return screen label
457    */
458   public String getScreenLabel() {
459     this.initScreenLabels();
460     return this.screenLabelShort;
461   }
462   
463   /**
464    * get screen label
465    * @return screen label
466    */
467   public String getScreenLabelLong() {
468     this.initScreenLabels();
469     return this.screenLabelLong;
470   }
471   
472   /** attributes in string - string format */
473   private Map<String, String> attributes = null;
474   /**
475    * long screen label
476    */
477   private String screenLabelLong = null;
478   /**
479    * long screen label with icon
480    */
481   private String screenLabelLongWithIcon = null;
482 
483   /**
484    * long screen label with icon
485    * @return screen label
486    */
487   public String getScreenLabelLongWithIcon() {
488     this.initScreenLabels();
489     return this.screenLabelLongWithIcon;
490   }
491 
492   /**
493    * short screen label
494    */
495   private String screenLabelShort = null;
496 
497   /**
498    * new short label in v2
499    */
500   private String screenLabelShort2 = null;
501   
502   /**
503    * new short label in v2 with html tooltip and link
504    */
505   private String screenLabelShort2html = null;
506 
507   /**
508    * new subject icon in v2
509    */
510   private String screenSubjectIcon2Html = null;
511 
512   /**
513    * new short label in v2 with html tooltip and link and icon
514    */
515   private String screenLabelShort2htmlWithIcon = null;
516   
517   /**
518    * new short label in v2 with no link, but with icon
519    */
520   private String screenLabelShort2noLinkWithIcon = null;
521 
522   /**
523    * new short label in v2 with no link or icon
524    */
525   private String screenLabelShort2noLink = null;
526 
527   
528   /**
529    * subject
530    * @return the subject
531    */
532   public Subject getSubject() {
533     return this.subject;
534   }
535   
536   /**
537    * attribute names for this subject
538    * @return the attribute names for this subject
539    */
540   public Set<String> getAttributeNamesNonInternal() {
541     Set<String> attributeNames = new LinkedHashSet<String>();
542     if (this.subject != null) {
543       String emailAttributeName = GrouperEmailUtils.emailAttributeNameForSource(this.subject.getSourceId());
544   
545       for (String attributeName : GrouperUtil.nonNull(this.getAttributes().keySet())) {
546         if (!StringUtils.equalsIgnoreCase("name", attributeName)
547             && !StringUtils.equalsIgnoreCase("description", attributeName)
548             && !StringUtils.equalsIgnoreCase("subjectId", attributeName)
549             && !StringUtils.equalsIgnoreCase(emailAttributeName, attributeName)) {
550           attributeNames.add(attributeName);
551         }
552       }
553     }
554     return attributeNames;
555   }
556   
557   /**
558    * attribute names for this subject to show in the expanded view
559    * @return the attribute names for this subject
560    */
561   public Set<String> getAttributeNamesExpandedView() {
562     Set<String> attributeNames = new LinkedHashSet<String>();
563     if (this.subject != null) {
564       String orderCommaSeparated = GrouperUiConfig.retrieveConfig().propertyValueString("subject2.attributes.order.expanded." + this.subject.getSourceId());
565       if (GrouperUtil.isBlank(orderCommaSeparated)) {
566         orderCommaSeparated = GrouperUiConfig.retrieveConfig().propertyValueString("subject2.attributes.order.expanded.default");
567       }
568       
569       // still empty, return them all to preserve previous behavior
570       if (GrouperUtil.isBlank(orderCommaSeparated)) {
571         return getAttributeNamesNonInternal();
572       }
573       
574       attributeNames.addAll(GrouperUtil.splitTrimToSet(orderCommaSeparated, ","));
575     }
576     return attributeNames;
577   }
578   
579   
580   /**
581    * attribute names for this subject to show in the non-expanded view
582    * @return the attribute names for this subject
583    */
584   public Set<String> getAttributeNamesNonExpandedView() {
585     Set<String> attributeNames = new LinkedHashSet<String>();
586     if (this.subject != null) {
587       String orderCommaSeparated = GrouperUiConfig.retrieveConfig().propertyValueString("subject2.attributes.order.nonexpanded." + this.subject.getSourceId());
588       if (GrouperUtil.isBlank(orderCommaSeparated)) {
589         orderCommaSeparated = GrouperUiConfig.retrieveConfig().propertyValueString("subject2.attributes.order.nonexpanded.default", "subjectId,email,name,description");
590       }
591       
592       if (!GrouperUtil.isBlank(orderCommaSeparated)) {
593 
594         // GRP-1558: default subject display shows "email" attribute, which source might not have
595         if (orderCommaSeparated.contains(",email,")) {
596 
597           if (!this.getAttributes().containsKey("email")) {
598             String emailAttribute = GrouperEmailUtils.emailAttributeNameForSource(this.subject.getSourceId());
599             if (!StringUtils.isBlank(emailAttribute)) {
600               orderCommaSeparated = GrouperUtil.replace(orderCommaSeparated, ",email,", "," + emailAttribute + ",");
601             } else {
602               orderCommaSeparated = GrouperUtil.replace(orderCommaSeparated, ",email,", ",");
603             }
604           }
605         }
606         
607         attributeNames.addAll(GrouperUtil.splitTrimToSet(orderCommaSeparated, ","));
608       }
609     }
610     return attributeNames;
611   }
612 
613   /**
614    * dynamic map of attribute name to attribute label
615    */
616   private Map<String, String> attributeLabelMap = new HashMap<String, String>() {
617 
618     /**
619      * @see java.util.HashMap#get(java.lang.Object)
620      */
621     @Override
622     public String get(Object attributeName) {
623       
624       String sourceId = GuiSubject.this.getSubject().getSourceId();
625       String sourceTextId = GrouperUiUtils.convertSourceIdToTextId(sourceId);
626       
627       String emailAttribute = GrouperEmailUtils.emailAttributeNameForSource(GuiSubject.this.subject.getSourceId());
628       
629       // subjectViewLabel__sourceTextId__attributeName
630       String key = "subjectViewLabel__" + sourceTextId + "__" + attributeName;
631       
632       if ("sourceId".equals(attributeName)) {
633         key = "subjectViewLabelSourceId";
634       } else if ("sourceName".equals(attributeName)) {
635         key = "subjectViewLabelSourceName";
636       } else if ("memberId".equals(attributeName)) {
637         key = "subjectViewLabelMemberId";
638       } else if ("subjectId".equals(attributeName)) {
639         key = "subjectViewLabelId";
640       } else if ("name".equals(attributeName)) {
641         key = "subjectViewLabelName";
642       } else if ("description".equals(attributeName)) {
643         key = "subjectViewLabelDescription";
644       } else if (!GrouperUtil.isBlank(emailAttribute) && emailAttribute.equals(attributeName)) {
645         key = "subjectViewLabelEmail";
646       }
647       
648       String value = TextContainer.textOrNull(key);
649       
650       if (StringUtils.isBlank(value)) {
651         return ((String)attributeName) + ":";
652       }
653       return value;
654       
655     }
656 
657   };
658 
659   
660   /**
661    * attribute label for this attribute if configured
662    * first get the text id for the source, then look in the externalized text
663    * for a label for the attribute, if not there, just use the attribute name
664    * @return the attribute label for this attribute
665    */
666   public Map<String, String> getAttributeLabel() {
667     
668     return this.attributeLabelMap;
669     
670   }
671   
672   /**
673    * Gets a map attribute names and value. The map's key
674    * contains the attribute name and the map's value
675    * contains a Set of attribute value(s).  Note, this only does single valued attributes
676    * @return the map of attributes
677    */
678   @SuppressWarnings({ "cast", "unchecked" })
679   public Map<String, String> getAttributes() {
680     if (this.attributes == null) {
681       Map<String, String> result = new LinkedHashMap<String, String>();
682       
683       if (this.subject != null) {
684         for (String key : (Set<String>)(Object)GrouperUtil.nonNull(this.subject.getAttributes()).keySet()) {
685           Object value = this.subject.getAttributes().get(key);
686           if (value instanceof String) {
687             //if a string
688             result.put(key, (String)value);
689           } else if (value instanceof Set) {
690             //if set of one string, then add it
691             if (((Set<?>)value).size() == 1) {
692               result.put(key, (String)((Set<?>)value).iterator().next());
693             } else if (((Set<?>)value).size() > 1) {
694               //put commas in between?  not sure what else to do here
695               result.put(key, GrouperUtil.setToString((Set<?>)value));
696             }
697           }
698         }
699       }
700       
701       result.put("memberId", getMemberId());
702       result.put("sourceId", this.subject.getSourceId());
703       result.put("sourceName", this.subject.getSource().getName());
704       result.put("subjectId", this.subject.getId());
705       
706       Member theMember = this.getMember();
707       
708       {
709         String name = this.subject.getName();
710         if (this.subject instanceof UnresolvableSubject && theMember != null && !StringUtils.isBlank(theMember.getName())) {
711           name = theMember.getName();
712         }
713         result.put("name",  name);
714       }
715       
716       {
717         String description = this.subject.getDescription();
718         if (this.subject instanceof UnresolvableSubject && theMember != null && !StringUtils.isBlank(theMember.getDescription())) {
719           description = theMember.getDescription();
720         }
721         result.put("description",  description);
722         
723       }
724       
725       this.attributes = result;
726     }
727     return this.attributes;
728   }
729 
730   /**
731    * 
732    * @return long label if different than the short one
733    */
734   public String getScreenLabelLongIfDifferent() {
735     this.initScreenLabels();
736     if (this.isNeedsTooltip()) {
737       return this.screenLabelLong;
738     }
739     return null;
740   }
741 
742   /**
743    * get short screen label 
744    * @return short screen label
745    */
746   public boolean isNeedsTooltip() {
747     this.initScreenLabels();
748     return !StringUtils.equals(this.screenLabelLong, this.screenLabelShort);
749   }
750 
751 
752   /**
753    * e.g. &lt;a href="#"&gt;John Smith&lt;/a&gt;
754    * @return short link
755    */
756   public String getScreenLabelShort2noLinkWithIcon() {
757     this.initScreenLabels();
758     return this.screenLabelShort2noLinkWithIcon;
759   }
760 
761 
762   /**
763    * 
764    * @param subject
765    * @param attrName
766    * @return the value
767    */
768   public static String attributeValue(Subject subject, String attrName) {
769     if (StringUtils.equalsIgnoreCase("screenLabel", attrName)) {
770       return GrouperUiUtils.convertSubjectToLabel(subject);
771     }
772     if (subject == null) { 
773       return null;
774     }
775     if (StringUtils.equalsIgnoreCase("subjectId", attrName)) {
776       return subject.getId();
777     }
778     if (StringUtils.equalsIgnoreCase("name", attrName)) {
779       return subject.getName();
780     }
781     if (StringUtils.equalsIgnoreCase("description", attrName)) {
782       return subject.getDescription();
783     }
784     if (StringUtils.equalsIgnoreCase("typeName", attrName)) {
785       return subject.getType().getName();
786     }
787     if (StringUtils.equalsIgnoreCase("sourceId", attrName)) {
788       return subject.getSource().getId();
789     }
790     if (StringUtils.equalsIgnoreCase("sourceName", attrName)) {
791       return subject.getSource().getName();
792     }
793     //TODO switch this to attribute values comma separated
794     return subject.getAttributeValue(attrName);
795   }
796 
797   /**
798    * cant get grouper object
799    */
800   @Override
801   public GrouperObject getGrouperObject() {
802     return null;
803   }
804 
805   /**
806    * if this is a subject
807    */
808   @Override
809   public boolean isSubjectType() {
810     return true;
811   }
812 
813   /**
814    * path colon separated not applicable
815    */
816   @Override
817   public String getPathColonSpaceSeparated() {
818     return "";
819   }
820 
821   /**
822    * not applicable
823    */
824   @Override
825   public String getNameColonSpaceSeparated() {
826     return this.getScreenLabelShort2noLink();
827   }
828 
829   /**
830    * not applicable
831    */
832   @Override
833   public String getTitle() {
834     return "";
835   }
836   
837   /**
838    * @return true if this is a local entity that is disabled
839    */
840   public boolean isLocalEntityDisabled() {
841     if (this.subject == null) {
842       return false;
843     }
844     
845     if (!this.subject.getSourceId().equals("grouperEntities")) {
846       return false;
847     }
848     return (Boolean)GrouperSession.internal_callbackRootGrouperSession(new GrouperSessionHandler() {
849       
850       @Override
851       public Object callback(GrouperSession grouperSession) throws GrouperSessionException {
852         Group group = GroupFinder.findByUuid(GrouperSession.staticGrouperSession(), GuiSubject.this.subject.getId(), false);
853         if (group == null) {
854           return false;
855         }
856         
857         return !group.isEnabled();
858       }
859     });
860   }
861 }