private AttributeList getAttributes(ObjectName objName, String[] attrNames)
     throws InstanceNotFoundException, ReflectionException, IOException {
   final NameValueMap values =
       getCachedAttributes(objName, new TreeSet<String>(Arrays.asList(attrNames)));
   final AttributeList list = new AttributeList();
   for (String attrName : attrNames) {
     final Object value = values.get(attrName);
     if (value != null || values.containsKey(attrName)) {
       list.add(new Attribute(attrName, value));
     }
   }
   return list;
 }
 private synchronized NameValueMap getCachedAttributes(ObjectName objName, Set<String> attrNames)
     throws InstanceNotFoundException, ReflectionException, IOException {
   NameValueMap values = cachedValues.get(objName);
   if (values != null && values.keySet().containsAll(attrNames)) {
     return values;
   }
   attrNames = new TreeSet<String>(attrNames);
   Set<String> oldNames = cachedNames.get(objName);
   if (oldNames != null) {
     attrNames.addAll(oldNames);
   }
   values = new NameValueMap();
   final AttributeList attrs =
       conn.getAttributes(objName, attrNames.toArray(new String[attrNames.size()]));
   for (Attribute attr : attrs.asList()) {
     values.put(attr.getName(), attr.getValue());
   }
   cachedValues.put(objName, values);
   cachedNames.put(objName, attrNames);
   return values;
 }