001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2016 ForgeRock AS. 015 */ 016package org.opends.server.api; 017 018import static org.opends.server.core.DirectoryServer.*; 019 020import java.lang.reflect.Method; 021import java.util.ArrayList; 022import java.util.Calendar; 023import java.util.Collection; 024import java.util.Date; 025import java.util.Iterator; 026import java.util.List; 027import java.util.UUID; 028 029import org.forgerock.opendj.ldap.ByteString; 030import org.forgerock.opendj.ldap.DN; 031import org.forgerock.opendj.ldap.GeneralizedTime; 032import org.forgerock.opendj.ldap.schema.AttributeType; 033import org.forgerock.opendj.ldap.schema.CoreSchema; 034import org.forgerock.opendj.ldap.schema.Syntax; 035import org.opends.server.types.Attribute; 036import org.opends.server.types.Attribute.RemoveOnceSwitchingAttributes; 037import org.opends.server.types.AttributeBuilder; 038import org.opends.server.types.Attributes; 039import org.opends.server.types.PublicAPI; 040import org.opends.server.types.StabilityLevel; 041 042/** 043 * This class is used to hold monitoring data, i.e. a list of attributes. It provides convenient 044 * methods to easily build such data. 045 * <p> 046 * <strong>Note:</strong> <br> 047 * Creating monitor entries may become a lot easier once we've migrated to the SDK Entry class: 048 * 049 * <pre> 050 * Entry entry = ...; 051 * entry.addAttribute("stringStat", "aString") 052 * .addAttribute("integerStat", 12345) 053 * .addAttribute("dnStat", DN.valueOf("dc=aDN"); 054 * </pre> 055 * 056 * We could also envisage an annotation based approach where we determine the monitor content from 057 * annotated fields/methods in an object. 058 */ 059@PublicAPI(stability = StabilityLevel.PRIVATE) 060public final class MonitorData implements Iterable<Attribute> 061{ 062 private final List<Attribute> attrs; 063 064 /** Constructor to use when the number of attributes to create is unknown. */ 065 public MonitorData() 066 { 067 attrs = new ArrayList<>(); 068 } 069 070 /** 071 * Constructor that accepts the number of attributes to create. 072 * 073 * @param expectedAttributesCount 074 * number of attributes that will be added 075 */ 076 public MonitorData(int expectedAttributesCount) 077 { 078 attrs = new ArrayList<>(expectedAttributesCount); 079 } 080 081 /** 082 * Adds an attribute with the provided name and value. 083 * 084 * @param attrName 085 * the attribute name 086 * @param attrValue 087 * the attribute value 088 */ 089 public void add(String attrName, Object attrValue) 090 { 091 Syntax syntax; 092 if (attrValue instanceof String 093 || attrValue instanceof ByteString 094 || attrValue instanceof Float 095 || attrValue instanceof Double) 096 { 097 // coming first because they are the most common types 098 syntax = CoreSchema.getDirectoryStringSyntax(); 099 } 100 else if (attrValue instanceof Number) 101 { 102 syntax = CoreSchema.getIntegerSyntax(); 103 } 104 else if (attrValue instanceof Boolean) 105 { 106 syntax = CoreSchema.getBooleanSyntax(); 107 } 108 else if (attrValue instanceof DN) 109 { 110 syntax = CoreSchema.getDNSyntax(); 111 } 112 else if (attrValue instanceof Date) 113 { 114 syntax = CoreSchema.getGeneralizedTimeSyntax(); 115 attrValue = GeneralizedTime.valueOf((Date) attrValue); 116 } 117 else if (attrValue instanceof Calendar) 118 { 119 syntax = CoreSchema.getGeneralizedTimeSyntax(); 120 attrValue = GeneralizedTime.valueOf((Calendar) attrValue); 121 } 122 else if (attrValue instanceof UUID) 123 { 124 syntax = CoreSchema.getUUIDSyntax(); 125 } 126 else 127 { 128 syntax = CoreSchema.getDirectoryStringSyntax(); 129 } 130 add(attrName, syntax, attrValue); 131 } 132 133 private void add(String attrName, Syntax syntax, Object attrValue) 134 { 135 AttributeType attrType = getSchema().getAttributeType(attrName, syntax); 136 attrs.add(Attributes.create(attrType, String.valueOf(attrValue))); 137 } 138 139 /** 140 * Adds an attribute with the provided name and value if the value is not null. 141 * 142 * @param attrName 143 * the attribute name 144 * @param attrValue 145 * the attribute value 146 */ 147 public void addIfNotNull(String attrName, Object attrValue) 148 { 149 if (attrValue != null) 150 { 151 add(attrName, attrValue); 152 } 153 } 154 155 /** 156 * Adds an attribute with the provided name and values. 157 * 158 * @param attrName 159 * the attribute name 160 * @param attrValues 161 * the attribute values 162 */ 163 @RemoveOnceSwitchingAttributes(comment = "once using the non immutable SDK's Attribute class, " 164 + "we can incrementally build an attribute by using the add(String attrName, Object attrValue) method") 165 public void add(String attrName, Collection<?> attrValues) 166 { 167 AttributeBuilder builder = new AttributeBuilder(attrName); 168 builder.addAllStrings(attrValues); 169 attrs.add(builder.toAttribute()); 170 } 171 172 /** 173 * Adds all the properties from the provided bean as attributes, prepending the provided prefix. 174 * 175 * @param bean 176 * the bean from which to read the properties 177 * @param attributesPrefix 178 * the prefix to prepend to the attributes read from the bean 179 * @throws ReflectiveOperationException 180 * if a problem occurs while reading the properties of the bean 181 */ 182 public void addBean(Object bean, String attributesPrefix) throws ReflectiveOperationException 183 { 184 for (Method method : bean.getClass().getMethods()) 185 { 186 if (method.getName().startsWith("get")) 187 { 188 Class<?> returnType = method.getReturnType(); 189 if (returnType.equals(int.class) || returnType.equals(long.class) || returnType.equals(String.class)) 190 { 191 addStatAttribute(attributesPrefix, bean, method, 3); 192 } 193 } 194 else if (method.getName().startsWith("is") && method.getReturnType().equals(boolean.class)) 195 { 196 addStatAttribute(attributesPrefix, bean, method, 2); 197 } 198 } 199 } 200 201 private void addStatAttribute(String attrPrefix, Object stats, Method method, int skipNameLen) 202 throws ReflectiveOperationException 203 { 204 String attrName = attrPrefix + method.getName().substring(skipNameLen); 205 add(attrName, method.invoke(stats)); 206 } 207 208 @Override 209 public Iterator<Attribute> iterator() 210 { 211 return attrs.iterator(); 212 } 213 214 /** 215 * Returns the number of attributes. 216 * 217 * @return the number of attributes 218 */ 219 public int size() 220 { 221 return attrs.size(); 222 } 223 224 @Override 225 public String toString() 226 { 227 return getClass().getName() + attrs; 228 } 229}