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 }