/* See LICENSE for licensing and NOTICE for copyright. */ package org.ldaptive.schema; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.ldaptive.LdapUtils; /** * Bean for an extension found in a schema element. * * @author Middleware Services */ public class Extensions { /** Pattern to match attribute type definitions. */ protected static final Pattern DEFINITION_PATTERN = Pattern.compile( "(?:(X-[^ ]+)[ ]*(?:'([^']+)'|\\(([^\\)]+)\\))?)+"); /** hash code seed. */ private static final int HASH_CODE_SEED = 1171; /** Extensions. */ private final Map<String, List<String>> extensions = new LinkedHashMap<>(); /** Creates a new extensions. */ public Extensions() {} /** * Creates a new extensions. * * @param name of a single extension * @param values for that extension */ public Extensions(final String name, final List<String> values) { addExtension(name, values); } /** * Returns the name. * * @return name */ public Set<String> getNames() { return extensions.keySet(); } /** * Returns the values for the extension with the supplied name. * * @param name of the extension * * @return values */ public List<String> getValues(final String name) { return extensions.get(name); } /** * Returns a single string value for the extension with the supplied name. See {@link #getValues(String)}. * * @param name of the extension * * @return single string extension value */ public String getValue(final String name) { final List<String> values = getValues(name); if (values == null || values.isEmpty()) { return null; } return values.iterator().next(); } /** * Returns all the values in this extensions. * * @return map of name to values for every extension */ public Map<String, List<String>> getAllValues() { return Collections.unmodifiableMap(extensions); } /** * Adds an extension. * * @param name of the extension */ public void addExtension(final String name) { extensions.put(name, new ArrayList<>(0)); } /** * Adds an extension. * * @param name of the extension * @param values in the extension */ public void addExtension(final String name, final List<String> values) { extensions.put(name, values); } /** * Parses the supplied definition string and creates an initialized extension. * * @param definition to parse * * @return extension */ public static Extensions parse(final String definition) { final Matcher m = DEFINITION_PATTERN.matcher(definition); final Extensions exts = new Extensions(); while (m.find()) { final String name = m.group(1).trim(); final List<String> values = new ArrayList<>(1); // CheckStyle:MagicNumber OFF if (m.group(2) != null) { values.add(m.group(2).trim()); } else if (m.group(3) != null) { values.addAll(Arrays.asList(SchemaUtils.parseDescriptors(m.group(3).trim()))); } // CheckStyle:MagicNumber ON exts.addExtension(name, values); } return exts; } /** * Returns this extension as formatted string per RFC 4512. * * @return formatted string */ public String format() { final StringBuilder sb = new StringBuilder(); for (Map.Entry<String, List<String>> entry : extensions.entrySet()) { sb.append(entry.getKey()).append(" "); if (entry.getValue() != null && !entry.getValue().isEmpty()) { sb.append(SchemaUtils.formatDescriptors(entry.getValue().toArray(new String[entry.getValue().size()]))); } } return sb.toString(); } @Override public boolean equals(final Object o) { if (o == this) { return true; } if (o instanceof Extensions) { final Extensions v = (Extensions) o; return LdapUtils.areEqual(extensions, v.extensions); } return false; } @Override public int hashCode() { return LdapUtils.computeHashCode(HASH_CODE_SEED, extensions); } @Override public String toString() { return String.format("[%s@%d::extensions=%s]", getClass().getName(), hashCode(), extensions); } }