001 /* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2008 Sun Microsystems, Inc. 026 */ 027 package org.opends.server.admin; 028 import org.opends.messages.Message; 029 import org.opends.messages.MessageBuilder; 030 031 032 import java.text.NumberFormat; 033 import java.util.EnumSet; 034 import java.util.Set; 035 import java.util.TreeSet; 036 037 038 039 /** 040 * A property definition visitor which can be used to generate syntax 041 * usage information. 042 */ 043 public final class PropertyDefinitionUsageBuilder { 044 045 /** 046 * Underlying implementation. 047 */ 048 private class MyPropertyDefinitionVisitor extends 049 PropertyDefinitionVisitor<Message, Void> { 050 051 // Flag indicating whether detailed syntax information will be 052 // generated. 053 private final boolean isDetailed; 054 055 // The formatter to use for numeric values. 056 private final NumberFormat numberFormat; 057 058 059 060 // Private constructor. 061 private MyPropertyDefinitionVisitor(boolean isDetailed) { 062 this.isDetailed = isDetailed; 063 064 this.numberFormat = NumberFormat.getNumberInstance(); 065 this.numberFormat.setGroupingUsed(true); 066 this.numberFormat.setMaximumFractionDigits(2); 067 } 068 069 070 071 /** 072 * {@inheritDoc} 073 */ 074 @Override 075 public <C extends ConfigurationClient, S extends Configuration> 076 Message visitAggregation(AggregationPropertyDefinition<C, S> d, Void p) { 077 return Message.raw("NAME"); 078 } 079 080 081 082 /** 083 * {@inheritDoc} 084 */ 085 @Override 086 public Message visitAttributeType(AttributeTypePropertyDefinition d, 087 Void p) { 088 return Message.raw("OID"); 089 } 090 091 /** 092 * {@inheritDoc} 093 */ 094 @Override 095 public Message visitACI(ACIPropertyDefinition d, 096 Void p) { 097 return Message.raw("ACI"); 098 } 099 100 /** 101 * {@inheritDoc} 102 */ 103 @Override 104 public Message visitBoolean(BooleanPropertyDefinition d, Void p) { 105 if (isDetailed) { 106 return Message.raw("false | true"); 107 } else { 108 return Message.raw("BOOLEAN"); 109 } 110 } 111 112 113 114 /** 115 * {@inheritDoc} 116 */ 117 @Override 118 public Message visitClass(ClassPropertyDefinition d, Void p) { 119 if (isDetailed && !d.getInstanceOfInterface().isEmpty()) { 120 return Message.raw("CLASS <= " + d.getInstanceOfInterface().get(0)); 121 } else { 122 return Message.raw("CLASS"); 123 } 124 } 125 126 127 128 /** 129 * {@inheritDoc} 130 */ 131 @Override 132 public Message visitDN(DNPropertyDefinition d, Void p) { 133 if (isDetailed && d.getBaseDN() != null) { 134 return Message.raw("DN <= " + d.getBaseDN()); 135 } else { 136 return Message.raw("DN"); 137 } 138 } 139 140 141 142 /** 143 * {@inheritDoc} 144 */ 145 @Override 146 public Message visitDuration(DurationPropertyDefinition d, Void p) { 147 MessageBuilder builder = new MessageBuilder(); 148 DurationUnit unit = d.getBaseUnit(); 149 150 if (isDetailed && d.getLowerLimit() > 0) { 151 builder.append(DurationUnit.toString(d.getLowerLimit())); 152 builder.append(" <= "); 153 } 154 155 builder.append("DURATION ("); 156 builder.append(unit.getShortName()); 157 builder.append(")"); 158 159 if (isDetailed) { 160 if (d.getUpperLimit() != null) { 161 builder.append(" <= "); 162 builder.append(DurationUnit.toString(d.getUpperLimit())); 163 } 164 165 if (d.isAllowUnlimited()) { 166 builder.append(" | unlimited"); 167 } 168 } 169 170 return builder.toMessage(); 171 } 172 173 174 175 /** 176 * {@inheritDoc} 177 */ 178 @Override 179 public <E extends Enum<E>> Message visitEnum(EnumPropertyDefinition<E> d, 180 Void p) { 181 if (!isDetailed) { 182 // Use the last word in the property name. 183 String name = d.getName(); 184 int i = name.lastIndexOf('-'); 185 if (i == -1 || i == (name.length() - 1)) { 186 return Message.raw(name.toUpperCase()); 187 } else { 188 return Message.raw(name.substring(i + 1).toUpperCase()); 189 } 190 } else { 191 Set<String> values = new TreeSet<String>(); 192 193 for (Object value : EnumSet.allOf(d.getEnumClass())) { 194 values.add(value.toString().trim().toLowerCase()); 195 } 196 197 boolean isFirst = true; 198 MessageBuilder builder = new MessageBuilder(); 199 for (String s : values) { 200 if (!isFirst) { 201 builder.append(" | "); 202 } 203 builder.append(s); 204 isFirst = false; 205 } 206 207 return builder.toMessage(); 208 } 209 } 210 211 212 213 /** 214 * {@inheritDoc} 215 */ 216 @Override 217 public Message visitInteger(IntegerPropertyDefinition d, Void p) { 218 MessageBuilder builder = new MessageBuilder(); 219 220 if (isDetailed) { 221 builder.append(String.valueOf(d.getLowerLimit())); 222 builder.append(" <= "); 223 } 224 225 builder.append("INTEGER"); 226 227 if (isDetailed) { 228 if (d.getUpperLimit() != null) { 229 builder.append(" <= "); 230 builder.append(String.valueOf(d.getUpperLimit())); 231 } else if (d.isAllowUnlimited()) { 232 builder.append(" | unlimited"); 233 } 234 } 235 236 return builder.toMessage(); 237 } 238 239 240 241 /** 242 * {@inheritDoc} 243 */ 244 @Override 245 public Message visitIPAddress(IPAddressPropertyDefinition d, Void p) { 246 return Message.raw("HOST_NAME"); 247 } 248 249 250 251 /** 252 * {@inheritDoc} 253 */ 254 @Override 255 public Message visitIPAddressMask(IPAddressMaskPropertyDefinition d, 256 Void p) { 257 return Message.raw("IP_ADDRESS_MASK"); 258 } 259 260 261 262 /** 263 * {@inheritDoc} 264 */ 265 @Override 266 public Message visitSize(SizePropertyDefinition d, Void p) { 267 MessageBuilder builder = new MessageBuilder(); 268 269 if (isDetailed && d.getLowerLimit() > 0) { 270 SizeUnit unit = SizeUnit.getBestFitUnitExact(d.getLowerLimit()); 271 builder.append(numberFormat.format(unit.fromBytes(d.getLowerLimit()))); 272 builder.append(' '); 273 builder.append(unit.getShortName()); 274 builder.append(" <= "); 275 } 276 277 builder.append("SIZE"); 278 279 if (isDetailed) { 280 if (d.getUpperLimit() != null) { 281 long upperLimit = d.getUpperLimit(); 282 SizeUnit unit = SizeUnit.getBestFitUnitExact(upperLimit); 283 284 // Quite often an upper limit is some power of 2 minus 1. In those 285 // cases lets use a "less than" relation rather than a "less than 286 // or equal to" relation. This will result in a much more readable 287 // quantity. 288 if (unit == SizeUnit.BYTES && upperLimit < Long.MAX_VALUE) { 289 unit = SizeUnit.getBestFitUnitExact(upperLimit + 1); 290 if (unit != SizeUnit.BYTES) { 291 upperLimit += 1; 292 builder.append(" < "); 293 } else { 294 builder.append(" <= "); 295 } 296 } else { 297 builder.append(" <= "); 298 } 299 300 builder.append(numberFormat.format(unit.fromBytes(upperLimit))); 301 builder.append(' '); 302 builder.append(unit.getShortName()); 303 } 304 305 if (d.isAllowUnlimited()) { 306 builder.append(" | unlimited"); 307 } 308 } 309 310 return builder.toMessage(); 311 } 312 313 314 315 /** 316 * {@inheritDoc} 317 */ 318 @Override 319 public Message visitString(StringPropertyDefinition d, Void p) { 320 if (d.getPattern() != null) { 321 if (isDetailed) { 322 MessageBuilder builder = new MessageBuilder(); 323 builder.append(d.getPatternUsage()); 324 builder.append(" - "); 325 builder.append(d.getPatternSynopsis()); 326 return builder.toMessage(); 327 } else { 328 return Message.raw(d.getPatternUsage()); 329 } 330 } else { 331 return Message.raw("STRING"); 332 } 333 } 334 335 336 337 /** 338 * {@inheritDoc} 339 */ 340 @Override 341 public <T> Message visitUnknown(PropertyDefinition<T> d, Void p) 342 throws UnknownPropertyDefinitionException { 343 return Message.raw("?"); 344 } 345 } 346 347 // Underlying implementation. 348 private final MyPropertyDefinitionVisitor pimpl; 349 350 351 352 /** 353 * Creates a new property usage builder. 354 * 355 * @param isDetailed 356 * Indicates whether or not the generated usage should 357 * contain detailed information such as constraints. 358 */ 359 public PropertyDefinitionUsageBuilder(boolean isDetailed) { 360 this.pimpl = new MyPropertyDefinitionVisitor(isDetailed); 361 } 362 363 364 365 /** 366 * Generates the usage information for the provided property 367 * definition. 368 * 369 * @param pd 370 * The property definitions. 371 * @return Returns the usage information for the provided property 372 * definition. 373 */ 374 public Message getUsage(PropertyDefinition<?> pd) { 375 return pd.accept(pimpl, null); 376 }; 377 378 }