1/* 2 * Copyright (c) 2004, 2015, 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 26package com.sun.management.internal; 27 28import java.lang.management.MemoryUsage; 29import java.lang.reflect.Method; 30import java.lang.reflect.Field; 31import java.util.Map; 32import java.io.InvalidObjectException; 33import javax.management.openmbean.CompositeType; 34import javax.management.openmbean.CompositeData; 35import javax.management.openmbean.CompositeDataSupport; 36import javax.management.openmbean.TabularData; 37import javax.management.openmbean.SimpleType; 38import javax.management.openmbean.OpenType; 39import javax.management.openmbean.OpenDataException; 40import com.sun.management.GcInfo; 41import java.security.AccessController; 42import java.security.PrivilegedAction; 43import sun.management.LazyCompositeData; 44import static sun.management.LazyCompositeData.getLong; 45import sun.management.MappedMXBeanType; 46import sun.management.Util; 47 48/** 49 * A CompositeData for GcInfo for the local management support. 50 * This class avoids the performance penalty paid to the 51 * construction of a CompositeData use in the local case. 52 */ 53public class GcInfoCompositeData extends LazyCompositeData { 54 private final GcInfo info; 55 private final GcInfoBuilder builder; 56 private final Object[] gcExtItemValues; 57 58 public GcInfoCompositeData(GcInfo info, 59 GcInfoBuilder builder, 60 Object[] gcExtItemValues) { 61 this.info = info; 62 this.builder = builder; 63 this.gcExtItemValues = gcExtItemValues; 64 } 65 66 public GcInfo getGcInfo() { 67 return info; 68 } 69 70 public static CompositeData toCompositeData(final GcInfo info) { 71 final GcInfoBuilder builder = AccessController.doPrivileged (new PrivilegedAction<GcInfoBuilder>() { 72 public GcInfoBuilder run() { 73 try { 74 Class<?> cl = Class.forName("com.sun.management.GcInfo"); 75 Field f = cl.getDeclaredField("builder"); 76 f.setAccessible(true); 77 return (GcInfoBuilder)f.get(info); 78 } catch(ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) { 79 return null; 80 } 81 } 82 }); 83 final Object[] extAttr = AccessController.doPrivileged (new PrivilegedAction<Object[]>() { 84 public Object[] run() { 85 try { 86 Class<?> cl = Class.forName("com.sun.management.GcInfo"); 87 Field f = cl.getDeclaredField("extAttributes"); 88 f.setAccessible(true); 89 return (Object[])f.get(info); 90 } catch(ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) { 91 return null; 92 } 93 } 94 }); 95 GcInfoCompositeData gcicd = 96 new GcInfoCompositeData(info,builder,extAttr); 97 return gcicd.getCompositeData(); 98 } 99 100 protected CompositeData getCompositeData() { 101 // CONTENTS OF THIS ARRAY MUST BE SYNCHRONIZED WITH 102 // baseGcInfoItemNames! 103 final Object[] baseGcInfoItemValues; 104 105 try { 106 baseGcInfoItemValues = new Object[] { 107 info.getId(), 108 info.getStartTime(), 109 info.getEndTime(), 110 info.getDuration(), 111 memoryUsageMapType.toOpenTypeData(info.getMemoryUsageBeforeGc()), 112 memoryUsageMapType.toOpenTypeData(info.getMemoryUsageAfterGc()), 113 }; 114 } catch (OpenDataException e) { 115 // Should never reach here 116 throw new AssertionError(e); 117 } 118 119 // Get the item values for the extension attributes 120 final int gcExtItemCount = builder.getGcExtItemCount(); 121 if (gcExtItemCount == 0 && 122 gcExtItemValues != null && gcExtItemValues.length != 0) { 123 throw new AssertionError("Unexpected Gc Extension Item Values"); 124 } 125 126 if (gcExtItemCount > 0 && (gcExtItemValues == null || 127 gcExtItemCount != gcExtItemValues.length)) { 128 throw new AssertionError("Unmatched Gc Extension Item Values"); 129 } 130 131 Object[] values = new Object[baseGcInfoItemValues.length + 132 gcExtItemCount]; 133 System.arraycopy(baseGcInfoItemValues, 0, values, 0, 134 baseGcInfoItemValues.length); 135 136 if (gcExtItemCount > 0) { 137 System.arraycopy(gcExtItemValues, 0, values, 138 baseGcInfoItemValues.length, gcExtItemCount); 139 } 140 141 try { 142 return new CompositeDataSupport(builder.getGcInfoCompositeType(), 143 builder.getItemNames(), 144 values); 145 } catch (OpenDataException e) { 146 // Should never reach here 147 throw new AssertionError(e); 148 } 149 } 150 151 private static final String ID = "id"; 152 private static final String START_TIME = "startTime"; 153 private static final String END_TIME = "endTime"; 154 private static final String DURATION = "duration"; 155 private static final String MEMORY_USAGE_BEFORE_GC = "memoryUsageBeforeGc"; 156 private static final String MEMORY_USAGE_AFTER_GC = "memoryUsageAfterGc"; 157 158 private static final String[] baseGcInfoItemNames = { 159 ID, 160 START_TIME, 161 END_TIME, 162 DURATION, 163 MEMORY_USAGE_BEFORE_GC, 164 MEMORY_USAGE_AFTER_GC, 165 }; 166 167 168 private static MappedMXBeanType memoryUsageMapType; 169 static { 170 try { 171 Method m = GcInfo.class.getMethod("getMemoryUsageBeforeGc"); 172 memoryUsageMapType = 173 MappedMXBeanType.getMappedType(m.getGenericReturnType()); 174 } catch (NoSuchMethodException | OpenDataException e) { 175 // Should never reach here 176 throw new AssertionError(e); 177 } 178 } 179 180 static String[] getBaseGcInfoItemNames() { 181 return baseGcInfoItemNames; 182 } 183 184 private static OpenType<?>[] baseGcInfoItemTypes = null; 185 static synchronized OpenType<?>[] getBaseGcInfoItemTypes() { 186 if (baseGcInfoItemTypes == null) { 187 OpenType<?> memoryUsageOpenType = memoryUsageMapType.getOpenType(); 188 baseGcInfoItemTypes = new OpenType<?>[] { 189 SimpleType.LONG, 190 SimpleType.LONG, 191 SimpleType.LONG, 192 SimpleType.LONG, 193 194 memoryUsageOpenType, 195 memoryUsageOpenType, 196 }; 197 } 198 return baseGcInfoItemTypes; 199 } 200 201 public static long getId(CompositeData cd) { 202 return getLong(cd, ID); 203 } 204 public static long getStartTime(CompositeData cd) { 205 return getLong(cd, START_TIME); 206 } 207 public static long getEndTime(CompositeData cd) { 208 return getLong(cd, END_TIME); 209 } 210 211 public static Map<String, MemoryUsage> 212 getMemoryUsageBeforeGc(CompositeData cd) { 213 try { 214 TabularData td = (TabularData) cd.get(MEMORY_USAGE_BEFORE_GC); 215 return cast(memoryUsageMapType.toJavaTypeData(td)); 216 } catch (InvalidObjectException | OpenDataException e) { 217 // Should never reach here 218 throw new AssertionError(e); 219 } 220 } 221 222 @SuppressWarnings("unchecked") 223 public static Map<String, MemoryUsage> cast(Object x) { 224 return (Map<String, MemoryUsage>) x; 225 } 226 public static Map<String, MemoryUsage> 227 getMemoryUsageAfterGc(CompositeData cd) { 228 try { 229 TabularData td = (TabularData) cd.get(MEMORY_USAGE_AFTER_GC); 230 //return (Map<String,MemoryUsage>) 231 return cast(memoryUsageMapType.toJavaTypeData(td)); 232 } catch (InvalidObjectException | OpenDataException e) { 233 // Should never reach here 234 throw new AssertionError(e); 235 } 236 } 237 238 /** 239 * Returns true if the input CompositeData has the expected 240 * CompositeType (i.e. contain all attributes with expected 241 * names and types). Otherwise, return false. 242 */ 243 public static void validateCompositeData(CompositeData cd) { 244 if (cd == null) { 245 throw new NullPointerException("Null CompositeData"); 246 } 247 248 if (!isTypeMatched(getBaseGcInfoCompositeType(), 249 cd.getCompositeType())) { 250 throw new IllegalArgumentException( 251 "Unexpected composite type for GcInfo"); 252 } 253 } 254 255 // This is only used for validation. 256 private static CompositeType baseGcInfoCompositeType = null; 257 static synchronized CompositeType getBaseGcInfoCompositeType() { 258 if (baseGcInfoCompositeType == null) { 259 try { 260 baseGcInfoCompositeType = 261 new CompositeType("sun.management.BaseGcInfoCompositeType", 262 "CompositeType for Base GcInfo", 263 getBaseGcInfoItemNames(), 264 getBaseGcInfoItemNames(), 265 getBaseGcInfoItemTypes()); 266 } catch (OpenDataException e) { 267 // shouldn't reach here 268 throw new RuntimeException(e); 269 } 270 } 271 return baseGcInfoCompositeType; 272 } 273 274 private static final long serialVersionUID = -5716428894085882742L; 275} 276