1 /*
   2  * Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.management;
  27 
  28 import java.io.Serializable;
  29 import java.util.*;
  30 import javax.management.openmbean.ArrayType;
  31 import javax.management.openmbean.CompositeData;
  32 import javax.management.openmbean.CompositeType;
  33 import javax.management.openmbean.OpenType;
  34 import javax.management.openmbean.TabularType;
  35 
  36 /**
  37  * This abstract class provides the implementation of the CompositeData
  38  * interface.  A CompositeData object will be lazily created only when
  39  * the CompositeData interface is used.
  40  *
  41  * Classes that extends this abstract class will implement the
  42  * getCompositeData() method. The object returned by the
  43  * getCompositeData() is an instance of CompositeData such that
  44  * the instance serializes itself as the type CompositeDataSupport.
  45  */
  46 public abstract class LazyCompositeData
  47         implements CompositeData, Serializable {
  48 
  49     @SuppressWarnings("serial") // Not statically typed as Serializable
  50     private CompositeData compositeData;
  51 
  52     // Implementation of the CompositeData interface
  53     @Override
  54     public boolean containsKey(String key) {
  55         return compositeData().containsKey(key);
  56     }
  57 
  58     @Override
  59     public boolean containsValue(Object value) {
  60         return compositeData().containsValue(value);
  61     }
  62 
  63     @Override
  64     public boolean equals(Object obj) {
  65         return compositeData().equals(obj);
  66     }
  67 
  68     @Override
  69     public Object get(String key) {
  70         return compositeData().get(key);
  71     }
  72 
  73     @Override
  74     public Object[] getAll(String[] keys) {
  75         return compositeData().getAll(keys);
  76     }
  77 
  78     @Override
  79     public CompositeType getCompositeType() {
  80         return compositeData().getCompositeType();
  81     }
  82 
  83     @Override
  84     public int hashCode() {
  85         return compositeData().hashCode();
  86     }
  87 
  88     @Override
  89     public String toString() {
  90         /** FIXME: What should this be?? */
  91         return compositeData().toString();
  92     }
  93 
  94     @Override
  95     public Collection<?> values() {
  96         return compositeData().values();
  97     }
  98 
  99     /* Lazy creation of a CompositeData object
 100      * only when the CompositeData interface is used.
 101      */
 102     private synchronized CompositeData compositeData() {
 103         if (compositeData != null)
 104             return compositeData;
 105         compositeData = getCompositeData();
 106         return compositeData;
 107     }
 108 
 109     /**
 110      * Designate to a CompositeData object when writing to an
 111      * output stream during serialization so that the receiver
 112      * only requires JMX 1.2 classes but not any implementation
 113      * specific class.
 114      */
 115     protected Object writeReplace() throws java.io.ObjectStreamException {
 116         return compositeData();
 117     }
 118 
 119     /**
 120      * Returns the CompositeData representing this object.
 121      * The returned CompositeData object must be an instance
 122      * of javax.management.openmbean.CompositeDataSupport class
 123      * so that no implementation specific class is required
 124      * for unmarshalling besides JMX 1.2 classes.
 125      */
 126     protected abstract CompositeData getCompositeData();
 127 
 128     // Helper methods
 129     public static String getString(CompositeData cd, String itemName) {
 130         if (cd == null)
 131             throw new IllegalArgumentException("Null CompositeData");
 132 
 133         return (String) cd.get(itemName);
 134     }
 135 
 136     public static boolean getBoolean(CompositeData cd, String itemName) {
 137         if (cd == null)
 138             throw new IllegalArgumentException("Null CompositeData");
 139 
 140         return ((Boolean) cd.get(itemName));
 141     }
 142 
 143     public static long getLong(CompositeData cd, String itemName) {
 144         if (cd == null)
 145             throw new IllegalArgumentException("Null CompositeData");
 146 
 147         return ((Long) cd.get(itemName));
 148     }
 149 
 150     public static int getInt(CompositeData cd, String itemName) {
 151         if (cd == null)
 152             throw new IllegalArgumentException("Null CompositeData");
 153 
 154         return ((Integer) cd.get(itemName));
 155     }
 156 
 157     /**
 158      * Compares two CompositeTypes and returns true if
 159      * all items in type1 exist in type2 and their item types
 160      * are the same.
 161      * @param type1 the base composite type
 162      * @param type2 the checked composite type
 163      * @return {@code true} if all items in type1 exist in type2 and their item
 164      *         types are the same.
 165      */
 166     protected static boolean isTypeMatched(CompositeType type1, CompositeType type2) {
 167         if (type1 == type2) return true;
 168 
 169         // We can't use CompositeType.isValue() since it returns false
 170         // if the type name doesn't match.
 171         Set<String> allItems = type1.keySet();
 172 
 173         // Check all items in the type1 exist in type2
 174         if (!type2.keySet().containsAll(allItems))
 175             return false;
 176 
 177         return allItems.stream().allMatch(
 178             item -> isTypeMatched(type1.getType(item), type2.getType(item))
 179         );
 180     }
 181 
 182     protected static boolean isTypeMatched(TabularType type1, TabularType type2) {
 183         if (type1 == type2) return true;
 184 
 185         List<String> list1 = type1.getIndexNames();
 186         List<String> list2 = type2.getIndexNames();
 187 
 188         // check if the list of index names are the same
 189         if (!list1.equals(list2))
 190             return false;
 191 
 192         return isTypeMatched(type1.getRowType(), type2.getRowType());
 193     }
 194 
 195     protected static boolean isTypeMatched(ArrayType<?> type1, ArrayType<?> type2) {
 196         if (type1 == type2) return true;
 197 
 198         int dim1 = type1.getDimension();
 199         int dim2 = type2.getDimension();
 200 
 201         // check if the array dimensions are the same
 202         if (dim1 != dim2)
 203             return false;
 204 
 205         return isTypeMatched(type1.getElementOpenType(), type2.getElementOpenType());
 206     }
 207 
 208     private static boolean isTypeMatched(OpenType<?> ot1, OpenType<?> ot2) {
 209         if (ot1 instanceof CompositeType) {
 210             if (! (ot2 instanceof CompositeType))
 211                 return false;
 212             if (!isTypeMatched((CompositeType) ot1, (CompositeType) ot2))
 213                 return false;
 214         } else if (ot1 instanceof TabularType) {
 215             if (! (ot2 instanceof TabularType))
 216                 return false;
 217             if (!isTypeMatched((TabularType) ot1, (TabularType) ot2))
 218                 return false;
 219         } else if (ot1 instanceof ArrayType) {
 220             if (! (ot2 instanceof ArrayType))
 221                 return false;
 222             if (!isTypeMatched((ArrayType<?>) ot1, (ArrayType<?>) ot2)) {
 223                 return false;
 224             }
 225         } else if (!ot1.equals(ot2)) {
 226             return false;
 227         }
 228         return true;
 229     }
 230 
 231     private static final long serialVersionUID = -2190411934472666714L;
 232 }