| | |
| | | * Copyright 2008-2009 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.admin; |
| | | import org.opends.messages.Message; |
| | | import org.opends.messages.MessageBuilder; |
| | | |
| | | |
| | | import java.text.NumberFormat; |
| | | import java.util.EnumSet; |
| | | import java.util.Set; |
| | | import java.util.TreeSet; |
| | | |
| | | |
| | | import org.forgerock.i18n.LocalizableMessage; |
| | | import org.forgerock.i18n.LocalizableMessageBuilder; |
| | | |
| | | /** |
| | | * A property definition visitor which can be used to generate syntax |
| | | * usage information. |
| | | * A property definition visitor which can be used to generate syntax usage |
| | | * information. |
| | | */ |
| | | public final class PropertyDefinitionUsageBuilder { |
| | | |
| | | /** |
| | | * Underlying implementation. |
| | | */ |
| | | private class MyPropertyDefinitionVisitor extends |
| | | PropertyDefinitionVisitor<Message, Void> { |
| | | |
| | | // Flag indicating whether detailed syntax information will be |
| | | // generated. |
| | | private final boolean isDetailed; |
| | | |
| | | // The formatter to use for numeric values. |
| | | private final NumberFormat numberFormat; |
| | | |
| | | |
| | | |
| | | // Private constructor. |
| | | private MyPropertyDefinitionVisitor(boolean isDetailed) { |
| | | this.isDetailed = isDetailed; |
| | | |
| | | this.numberFormat = NumberFormat.getNumberInstance(); |
| | | this.numberFormat.setGroupingUsed(true); |
| | | this.numberFormat.setMaximumFractionDigits(2); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | * Underlying implementation. |
| | | */ |
| | | @Override |
| | | public <C extends ConfigurationClient, S extends Configuration> |
| | | Message visitAggregation(AggregationPropertyDefinition<C, S> d, Void p) { |
| | | return Message.raw("NAME"); |
| | | } |
| | | private class MyPropertyDefinitionVisitor extends PropertyDefinitionVisitor<LocalizableMessage, Void> { |
| | | |
| | | // Flag indicating whether detailed syntax information will be |
| | | // generated. |
| | | private final boolean isDetailed; |
| | | |
| | | // The formatter to use for numeric values. |
| | | private final NumberFormat numberFormat; |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public Message visitAttributeType(AttributeTypePropertyDefinition d, |
| | | Void p) { |
| | | return Message.raw("OID"); |
| | | } |
| | | // Private constructor. |
| | | private MyPropertyDefinitionVisitor(boolean isDetailed) { |
| | | this.isDetailed = isDetailed; |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public Message visitACI(ACIPropertyDefinition d, |
| | | Void p) { |
| | | return Message.raw("ACI"); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public Message visitBoolean(BooleanPropertyDefinition d, Void p) { |
| | | if (isDetailed) { |
| | | return Message.raw("false | true"); |
| | | } else { |
| | | return Message.raw("BOOLEAN"); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public Message visitClass(ClassPropertyDefinition d, Void p) { |
| | | if (isDetailed && !d.getInstanceOfInterface().isEmpty()) { |
| | | return Message.raw("CLASS <= " + d.getInstanceOfInterface().get(0)); |
| | | } else { |
| | | return Message.raw("CLASS"); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public Message visitDN(DNPropertyDefinition d, Void p) { |
| | | if (isDetailed && d.getBaseDN() != null) { |
| | | return Message.raw("DN <= " + d.getBaseDN()); |
| | | } else { |
| | | return Message.raw("DN"); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public Message visitDuration(DurationPropertyDefinition d, Void p) { |
| | | MessageBuilder builder = new MessageBuilder(); |
| | | DurationUnit unit = d.getBaseUnit(); |
| | | |
| | | if (isDetailed && d.getLowerLimit() > 0) { |
| | | builder.append(DurationUnit.toString(d.getLowerLimit())); |
| | | builder.append(" <= "); |
| | | } |
| | | |
| | | builder.append("DURATION ("); |
| | | builder.append(unit.getShortName()); |
| | | builder.append(")"); |
| | | |
| | | if (isDetailed) { |
| | | if (d.getUpperLimit() != null) { |
| | | builder.append(" <= "); |
| | | builder.append(DurationUnit.toString(d.getUpperLimit())); |
| | | this.numberFormat = NumberFormat.getNumberInstance(); |
| | | this.numberFormat.setGroupingUsed(true); |
| | | this.numberFormat.setMaximumFractionDigits(2); |
| | | } |
| | | |
| | | if (d.isAllowUnlimited()) { |
| | | builder.append(" | unlimited"); |
| | | } |
| | | } |
| | | |
| | | return builder.toMessage(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public <E extends Enum<E>> Message visitEnum(EnumPropertyDefinition<E> d, |
| | | Void p) { |
| | | if (!isDetailed) { |
| | | // Use the last word in the property name. |
| | | String name = d.getName(); |
| | | int i = name.lastIndexOf('-'); |
| | | if (i == -1 || i == (name.length() - 1)) { |
| | | return Message.raw(name.toUpperCase()); |
| | | } else { |
| | | return Message.raw(name.substring(i + 1).toUpperCase()); |
| | | } |
| | | } else { |
| | | Set<String> values = new TreeSet<String>(); |
| | | |
| | | for (Object value : EnumSet.allOf(d.getEnumClass())) { |
| | | values.add(value.toString().trim().toLowerCase()); |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public <C extends ConfigurationClient, S extends Configuration> LocalizableMessage visitAggregation( |
| | | AggregationPropertyDefinition<C, S> d, Void p) { |
| | | return LocalizableMessage.raw("NAME"); |
| | | } |
| | | |
| | | boolean isFirst = true; |
| | | MessageBuilder builder = new MessageBuilder(); |
| | | for (String s : values) { |
| | | if (!isFirst) { |
| | | builder.append(" | "); |
| | | } |
| | | builder.append(s); |
| | | isFirst = false; |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public LocalizableMessage visitAttributeType(AttributeTypePropertyDefinition d, Void p) { |
| | | return LocalizableMessage.raw("OID"); |
| | | } |
| | | |
| | | return builder.toMessage(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public Message visitInteger(IntegerPropertyDefinition d, Void p) { |
| | | MessageBuilder builder = new MessageBuilder(); |
| | | |
| | | if (isDetailed) { |
| | | builder.append(String.valueOf(d.getLowerLimit())); |
| | | builder.append(" <= "); |
| | | } |
| | | |
| | | builder.append("INTEGER"); |
| | | |
| | | if (isDetailed) { |
| | | if (d.getUpperLimit() != null) { |
| | | builder.append(" <= "); |
| | | builder.append(String.valueOf(d.getUpperLimit())); |
| | | } else if (d.isAllowUnlimited()) { |
| | | builder.append(" | unlimited"); |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public LocalizableMessage visitACI(ACIPropertyDefinition d, Void p) { |
| | | return LocalizableMessage.raw("ACI"); |
| | | } |
| | | } |
| | | |
| | | return builder.toMessage(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public Message visitIPAddress(IPAddressPropertyDefinition d, Void p) { |
| | | return Message.raw("HOST_NAME"); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public Message visitIPAddressMask(IPAddressMaskPropertyDefinition d, |
| | | Void p) { |
| | | return Message.raw("IP_ADDRESS_MASK"); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public Message visitSize(SizePropertyDefinition d, Void p) { |
| | | MessageBuilder builder = new MessageBuilder(); |
| | | |
| | | if (isDetailed && d.getLowerLimit() > 0) { |
| | | SizeUnit unit = SizeUnit.getBestFitUnitExact(d.getLowerLimit()); |
| | | builder.append(numberFormat.format(unit.fromBytes(d.getLowerLimit()))); |
| | | builder.append(' '); |
| | | builder.append(unit.getShortName()); |
| | | builder.append(" <= "); |
| | | } |
| | | |
| | | builder.append("SIZE"); |
| | | |
| | | if (isDetailed) { |
| | | if (d.getUpperLimit() != null) { |
| | | long upperLimit = d.getUpperLimit(); |
| | | SizeUnit unit = SizeUnit.getBestFitUnitExact(upperLimit); |
| | | |
| | | // Quite often an upper limit is some power of 2 minus 1. In those |
| | | // cases lets use a "less than" relation rather than a "less than |
| | | // or equal to" relation. This will result in a much more readable |
| | | // quantity. |
| | | if (unit == SizeUnit.BYTES && upperLimit < Long.MAX_VALUE) { |
| | | unit = SizeUnit.getBestFitUnitExact(upperLimit + 1); |
| | | if (unit != SizeUnit.BYTES) { |
| | | upperLimit += 1; |
| | | builder.append(" < "); |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public LocalizableMessage visitBoolean(BooleanPropertyDefinition d, Void p) { |
| | | if (isDetailed) { |
| | | return LocalizableMessage.raw("false | true"); |
| | | } else { |
| | | builder.append(" <= "); |
| | | return LocalizableMessage.raw("BOOLEAN"); |
| | | } |
| | | } else { |
| | | builder.append(" <= "); |
| | | } |
| | | |
| | | builder.append(numberFormat.format(unit.fromBytes(upperLimit))); |
| | | builder.append(' '); |
| | | builder.append(unit.getShortName()); |
| | | } |
| | | |
| | | if (d.isAllowUnlimited()) { |
| | | builder.append(" | unlimited"); |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public LocalizableMessage visitClass(ClassPropertyDefinition d, Void p) { |
| | | if (isDetailed && !d.getInstanceOfInterface().isEmpty()) { |
| | | return LocalizableMessage.raw("CLASS <= " + d.getInstanceOfInterface().get(0)); |
| | | } else { |
| | | return LocalizableMessage.raw("CLASS"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | return builder.toMessage(); |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public LocalizableMessage visitDN(DNPropertyDefinition d, Void p) { |
| | | if (isDetailed && d.getBaseDN() != null) { |
| | | return LocalizableMessage.raw("DN <= " + d.getBaseDN()); |
| | | } else { |
| | | return LocalizableMessage.raw("DN"); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public LocalizableMessage visitDuration(DurationPropertyDefinition d, Void p) { |
| | | LocalizableMessageBuilder builder = new LocalizableMessageBuilder(); |
| | | DurationUnit unit = d.getBaseUnit(); |
| | | |
| | | if (isDetailed && d.getLowerLimit() > 0) { |
| | | builder.append(DurationUnit.toString(d.getLowerLimit())); |
| | | builder.append(" <= "); |
| | | } |
| | | |
| | | builder.append("DURATION ("); |
| | | builder.append(unit.getShortName()); |
| | | builder.append(")"); |
| | | |
| | | if (isDetailed) { |
| | | if (d.getUpperLimit() != null) { |
| | | builder.append(" <= "); |
| | | builder.append(DurationUnit.toString(d.getUpperLimit())); |
| | | } |
| | | |
| | | if (d.isAllowUnlimited()) { |
| | | builder.append(" | unlimited"); |
| | | } |
| | | } |
| | | |
| | | return builder.toMessage(); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public <E extends Enum<E>> LocalizableMessage visitEnum(EnumPropertyDefinition<E> d, Void p) { |
| | | if (!isDetailed) { |
| | | // Use the last word in the property name. |
| | | String name = d.getName(); |
| | | int i = name.lastIndexOf('-'); |
| | | if (i == -1 || i == (name.length() - 1)) { |
| | | return LocalizableMessage.raw(name.toUpperCase()); |
| | | } else { |
| | | return LocalizableMessage.raw(name.substring(i + 1).toUpperCase()); |
| | | } |
| | | } else { |
| | | Set<String> values = new TreeSet<String>(); |
| | | |
| | | for (Object value : EnumSet.allOf(d.getEnumClass())) { |
| | | values.add(value.toString().trim().toLowerCase()); |
| | | } |
| | | |
| | | boolean isFirst = true; |
| | | LocalizableMessageBuilder builder = new LocalizableMessageBuilder(); |
| | | for (String s : values) { |
| | | if (!isFirst) { |
| | | builder.append(" | "); |
| | | } |
| | | builder.append(s); |
| | | isFirst = false; |
| | | } |
| | | |
| | | return builder.toMessage(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public LocalizableMessage visitInteger(IntegerPropertyDefinition d, Void p) { |
| | | LocalizableMessageBuilder builder = new LocalizableMessageBuilder(); |
| | | |
| | | if (isDetailed) { |
| | | builder.append(String.valueOf(d.getLowerLimit())); |
| | | builder.append(" <= "); |
| | | } |
| | | |
| | | builder.append("INTEGER"); |
| | | |
| | | if (isDetailed) { |
| | | if (d.getUpperLimit() != null) { |
| | | builder.append(" <= "); |
| | | builder.append(String.valueOf(d.getUpperLimit())); |
| | | } else if (d.isAllowUnlimited()) { |
| | | builder.append(" | unlimited"); |
| | | } |
| | | } |
| | | |
| | | return builder.toMessage(); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public LocalizableMessage visitIPAddress(IPAddressPropertyDefinition d, Void p) { |
| | | return LocalizableMessage.raw("HOST_NAME"); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public LocalizableMessage visitIPAddressMask(IPAddressMaskPropertyDefinition d, Void p) { |
| | | return LocalizableMessage.raw("IP_ADDRESS_MASK"); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public LocalizableMessage visitSize(SizePropertyDefinition d, Void p) { |
| | | LocalizableMessageBuilder builder = new LocalizableMessageBuilder(); |
| | | |
| | | if (isDetailed && d.getLowerLimit() > 0) { |
| | | SizeUnit unit = SizeUnit.getBestFitUnitExact(d.getLowerLimit()); |
| | | builder.append(numberFormat.format(unit.fromBytes(d.getLowerLimit()))); |
| | | builder.append(' '); |
| | | builder.append(unit.getShortName()); |
| | | builder.append(" <= "); |
| | | } |
| | | |
| | | builder.append("SIZE"); |
| | | |
| | | if (isDetailed) { |
| | | if (d.getUpperLimit() != null) { |
| | | long upperLimit = d.getUpperLimit(); |
| | | SizeUnit unit = SizeUnit.getBestFitUnitExact(upperLimit); |
| | | |
| | | // Quite often an upper limit is some power of 2 minus 1. In |
| | | // those |
| | | // cases lets use a "less than" relation rather than a "less |
| | | // than |
| | | // or equal to" relation. This will result in a much more |
| | | // readable |
| | | // quantity. |
| | | if (unit == SizeUnit.BYTES && upperLimit < Long.MAX_VALUE) { |
| | | unit = SizeUnit.getBestFitUnitExact(upperLimit + 1); |
| | | if (unit != SizeUnit.BYTES) { |
| | | upperLimit += 1; |
| | | builder.append(" < "); |
| | | } else { |
| | | builder.append(" <= "); |
| | | } |
| | | } else { |
| | | builder.append(" <= "); |
| | | } |
| | | |
| | | builder.append(numberFormat.format(unit.fromBytes(upperLimit))); |
| | | builder.append(' '); |
| | | builder.append(unit.getShortName()); |
| | | } |
| | | |
| | | if (d.isAllowUnlimited()) { |
| | | builder.append(" | unlimited"); |
| | | } |
| | | } |
| | | |
| | | return builder.toMessage(); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public LocalizableMessage visitString(StringPropertyDefinition d, Void p) { |
| | | if (d.getPattern() != null) { |
| | | if (isDetailed) { |
| | | LocalizableMessageBuilder builder = new LocalizableMessageBuilder(); |
| | | builder.append(d.getPatternUsage()); |
| | | builder.append(" - "); |
| | | builder.append(d.getPatternSynopsis()); |
| | | return builder.toMessage(); |
| | | } else { |
| | | return LocalizableMessage.raw(d.getPatternUsage()); |
| | | } |
| | | } else { |
| | | return LocalizableMessage.raw("STRING"); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public <T> LocalizableMessage visitUnknown(PropertyDefinition<T> d, Void p) |
| | | throws UnknownPropertyDefinitionException { |
| | | return LocalizableMessage.raw("?"); |
| | | } |
| | | } |
| | | |
| | | |
| | | // Underlying implementation. |
| | | private final MyPropertyDefinitionVisitor pimpl; |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | * Creates a new property usage builder. |
| | | * |
| | | * @param isDetailed |
| | | * Indicates whether or not the generated usage should contain |
| | | * detailed information such as constraints. |
| | | */ |
| | | @Override |
| | | public Message visitString(StringPropertyDefinition d, Void p) { |
| | | if (d.getPattern() != null) { |
| | | if (isDetailed) { |
| | | MessageBuilder builder = new MessageBuilder(); |
| | | builder.append(d.getPatternUsage()); |
| | | builder.append(" - "); |
| | | builder.append(d.getPatternSynopsis()); |
| | | return builder.toMessage(); |
| | | } else { |
| | | return Message.raw(d.getPatternUsage()); |
| | | } |
| | | } else { |
| | | return Message.raw("STRING"); |
| | | } |
| | | public PropertyDefinitionUsageBuilder(boolean isDetailed) { |
| | | this.pimpl = new MyPropertyDefinitionVisitor(isDetailed); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | * Generates the usage information for the provided property definition. |
| | | * |
| | | * @param pd |
| | | * The property definitions. |
| | | * @return Returns the usage information for the provided property |
| | | * definition. |
| | | */ |
| | | @Override |
| | | public <T> Message visitUnknown(PropertyDefinition<T> d, Void p) |
| | | throws UnknownPropertyDefinitionException { |
| | | return Message.raw("?"); |
| | | } |
| | | } |
| | | |
| | | // Underlying implementation. |
| | | private final MyPropertyDefinitionVisitor pimpl; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new property usage builder. |
| | | * |
| | | * @param isDetailed |
| | | * Indicates whether or not the generated usage should |
| | | * contain detailed information such as constraints. |
| | | */ |
| | | public PropertyDefinitionUsageBuilder(boolean isDetailed) { |
| | | this.pimpl = new MyPropertyDefinitionVisitor(isDetailed); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Generates the usage information for the provided property |
| | | * definition. |
| | | * |
| | | * @param pd |
| | | * The property definitions. |
| | | * @return Returns the usage information for the provided property |
| | | * definition. |
| | | */ |
| | | public Message getUsage(PropertyDefinition<?> pd) { |
| | | return pd.accept(pimpl, null); |
| | | }; |
| | | public LocalizableMessage getUsage(PropertyDefinition<?> pd) { |
| | | return pd.accept(pimpl, null); |
| | | }; |
| | | |
| | | } |