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 2006-2008 Sun Microsystems, Inc.
026 */
027 package org.opends.server.schema;
028
029
030
031 import java.util.HashSet;
032
033 import org.opends.server.admin.std.server.AttributeSyntaxCfg;
034 import org.opends.server.api.ApproximateMatchingRule;
035 import org.opends.server.api.AttributeSyntax;
036 import org.opends.server.api.EqualityMatchingRule;
037 import org.opends.server.api.OrderingMatchingRule;
038 import org.opends.server.api.SubstringMatchingRule;
039 import org.opends.server.config.ConfigException;
040 import org.opends.server.core.DirectoryServer;
041 import org.opends.server.types.ByteString;
042
043
044
045 import static org.opends.server.loggers.ErrorLogger.*;
046 import static org.opends.messages.SchemaMessages.*;
047 import org.opends.messages.MessageBuilder;
048 import static org.opends.server.schema.SchemaConstants.*;
049
050
051
052 /**
053 * This class implements the teletex terminal identifier attribute syntax, which
054 * contains a printable string (the terminal identifier) followed by zero or
055 * more parameters, which start with a dollar sign and are followed by a
056 * parameter name, a colon, and a value. The parameter value should consist of
057 * any string of bytes (the dollar sign and backslash must be escaped with a
058 * preceding backslash), and the parameter name must be one of the following
059 * strings:
060 * <UL>
061 * <LI>graphic</LI>
062 * <LI>control</LI>
063 * <LI>misc</LI>
064 * <LI>page</LI>
065 * <LI>private</LI>
066 * </UL>
067 */
068 public class TeletexTerminalIdentifierSyntax
069 extends AttributeSyntax<AttributeSyntaxCfg>
070 {
071 /**
072 * The set of allowed fax parameter values, formatted entirely in lowercase
073 * characters.
074 */
075 public static final HashSet<String> ALLOWED_TTX_PARAMETERS =
076 new HashSet<String>(5);
077
078 static
079 {
080 ALLOWED_TTX_PARAMETERS.add("graphic");
081 ALLOWED_TTX_PARAMETERS.add("control");
082 ALLOWED_TTX_PARAMETERS.add("misc");
083 ALLOWED_TTX_PARAMETERS.add("page");
084 ALLOWED_TTX_PARAMETERS.add("private");
085 }
086
087
088
089 // The default equality matching rule for this syntax.
090 private EqualityMatchingRule defaultEqualityMatchingRule;
091
092 // The default ordering matching rule for this syntax.
093 private OrderingMatchingRule defaultOrderingMatchingRule;
094
095 // The default substring matching rule for this syntax.
096 private SubstringMatchingRule defaultSubstringMatchingRule;
097
098
099
100 /**
101 * Creates a new instance of this syntax. Note that the only thing that
102 * should be done here is to invoke the default constructor for the
103 * superclass. All initialization should be performed in the
104 * <CODE>initializeSyntax</CODE> method.
105 */
106 public TeletexTerminalIdentifierSyntax()
107 {
108 super();
109 }
110
111
112
113 /**
114 * {@inheritDoc}
115 */
116 public void initializeSyntax(AttributeSyntaxCfg configuration)
117 throws ConfigException
118 {
119 defaultEqualityMatchingRule =
120 DirectoryServer.getEqualityMatchingRule(EMR_CASE_IGNORE_OID);
121 if (defaultEqualityMatchingRule == null)
122 {
123 logError(ERR_ATTR_SYNTAX_UNKNOWN_EQUALITY_MATCHING_RULE.get(
124 EMR_CASE_IGNORE_OID, SYNTAX_TELETEX_TERM_ID_NAME));
125 }
126
127 defaultOrderingMatchingRule =
128 DirectoryServer.getOrderingMatchingRule(OMR_CASE_IGNORE_OID);
129 if (defaultOrderingMatchingRule == null)
130 {
131 logError(ERR_ATTR_SYNTAX_UNKNOWN_ORDERING_MATCHING_RULE.get(
132 OMR_CASE_IGNORE_OID, SYNTAX_TELETEX_TERM_ID_NAME));
133 }
134
135 defaultSubstringMatchingRule =
136 DirectoryServer.getSubstringMatchingRule(SMR_CASE_IGNORE_OID);
137 if (defaultSubstringMatchingRule == null)
138 {
139 logError(ERR_ATTR_SYNTAX_UNKNOWN_SUBSTRING_MATCHING_RULE.get(
140 SMR_CASE_IGNORE_OID, SYNTAX_TELETEX_TERM_ID_NAME));
141 }
142 }
143
144
145
146 /**
147 * Retrieves the common name for this attribute syntax.
148 *
149 * @return The common name for this attribute syntax.
150 */
151 public String getSyntaxName()
152 {
153 return SYNTAX_TELETEX_TERM_ID_NAME;
154 }
155
156
157
158 /**
159 * Retrieves the OID for this attribute syntax.
160 *
161 * @return The OID for this attribute syntax.
162 */
163 public String getOID()
164 {
165 return SYNTAX_TELETEX_TERM_ID_OID;
166 }
167
168
169
170 /**
171 * Retrieves a description for this attribute syntax.
172 *
173 * @return A description for this attribute syntax.
174 */
175 public String getDescription()
176 {
177 return SYNTAX_TELETEX_TERM_ID_DESCRIPTION;
178 }
179
180
181
182 /**
183 * Retrieves the default equality matching rule that will be used for
184 * attributes with this syntax.
185 *
186 * @return The default equality matching rule that will be used for
187 * attributes with this syntax, or <CODE>null</CODE> if equality
188 * matches will not be allowed for this type by default.
189 */
190 public EqualityMatchingRule getEqualityMatchingRule()
191 {
192 return defaultEqualityMatchingRule;
193 }
194
195
196
197 /**
198 * Retrieves the default ordering matching rule that will be used for
199 * attributes with this syntax.
200 *
201 * @return The default ordering matching rule that will be used for
202 * attributes with this syntax, or <CODE>null</CODE> if ordering
203 * matches will not be allowed for this type by default.
204 */
205 public OrderingMatchingRule getOrderingMatchingRule()
206 {
207 return defaultOrderingMatchingRule;
208 }
209
210
211
212 /**
213 * Retrieves the default substring matching rule that will be used for
214 * attributes with this syntax.
215 *
216 * @return The default substring matching rule that will be used for
217 * attributes with this syntax, or <CODE>null</CODE> if substring
218 * matches will not be allowed for this type by default.
219 */
220 public SubstringMatchingRule getSubstringMatchingRule()
221 {
222 return defaultSubstringMatchingRule;
223 }
224
225
226
227 /**
228 * Retrieves the default approximate matching rule that will be used for
229 * attributes with this syntax.
230 *
231 * @return The default approximate matching rule that will be used for
232 * attributes with this syntax, or <CODE>null</CODE> if approximate
233 * matches will not be allowed for this type by default.
234 */
235 public ApproximateMatchingRule getApproximateMatchingRule()
236 {
237 // There is no approximate matching rule by default.
238 return null;
239 }
240
241
242
243 /**
244 * Indicates whether the provided value is acceptable for use in an attribute
245 * with this syntax. If it is not, then the reason may be appended to the
246 * provided buffer.
247 *
248 * @param value The value for which to make the determination.
249 * @param invalidReason The buffer to which the invalid reason should be
250 * appended.
251 *
252 * @return <CODE>true</CODE> if the provided value is acceptable for use with
253 * this syntax, or <CODE>false</CODE> if not.
254 */
255 public boolean valueIsAcceptable(ByteString value,
256 MessageBuilder invalidReason)
257 {
258 // Get a lowercase string representation of the value and find its length.
259 String valueString = value.stringValue();
260 int valueLength = valueString.length();
261
262
263 // The value must contain at least one character.
264 if (valueLength == 0)
265 {
266
267 invalidReason.append(ERR_ATTR_SYNTAX_TELETEXID_EMPTY.get());
268 return false;
269 }
270
271
272 // The first character must be a printable string character.
273 char c = valueString.charAt(0);
274 if (! PrintableString.isPrintableCharacter(c))
275 {
276
277 invalidReason.append(ERR_ATTR_SYNTAX_TELETEXID_NOT_PRINTABLE.get(
278 valueString, String.valueOf(c), 0));
279 return false;
280 }
281
282
283 // Continue reading until we find a dollar sign or the end of the string.
284 // Every intermediate character must be a printable string character.
285 int pos = 1;
286 for ( ; pos < valueLength; pos++)
287 {
288 c = valueString.charAt(pos);
289 if (c == '$')
290 {
291 pos++;
292 break;
293 }
294 else
295 {
296 if (! PrintableString.isPrintableCharacter(c))
297 {
298
299 invalidReason.append(ERR_ATTR_SYNTAX_TELETEXID_NOT_PRINTABLE.get(
300 valueString, String.valueOf(c), pos));
301 }
302 }
303 }
304
305 if (pos >= valueLength)
306 {
307 // We're at the end of the value, so it must be valid unless the last
308 // character was a dollar sign.
309 if (c == '$')
310 {
311
312 invalidReason.append(ERR_ATTR_SYNTAX_TELETEXID_END_WITH_DOLLAR.get(
313 valueString));
314 return false;
315 }
316 else
317 {
318 return true;
319 }
320 }
321
322
323 // Continue reading until we find the end of the string. Each substring
324 // must be a valid teletex terminal identifier parameter followed by a colon
325 // and the value. Dollar signs must be escaped
326 int paramStartPos = pos;
327 boolean escaped = false;
328 while (pos < valueLength)
329 {
330 if (escaped)
331 {
332 pos++;
333 continue;
334 }
335
336 c = valueString.charAt(pos++);
337 if (c == '\\')
338 {
339 escaped = true;
340 continue;
341 }
342 else if (c == '$')
343 {
344 String paramStr = valueString.substring(paramStartPos, pos);
345
346 int colonPos = paramStr.indexOf(':');
347 if (colonPos < 0)
348 {
349
350 invalidReason.append(ERR_ATTR_SYNTAX_TELETEXID_PARAM_NO_COLON.get(
351 valueString));
352 return false;
353 }
354
355 String paramName = paramStr.substring(0, colonPos);
356 if (! ALLOWED_TTX_PARAMETERS.contains(paramName))
357 {
358
359 invalidReason.append(ERR_ATTR_SYNTAX_TELETEXID_ILLEGAL_PARAMETER.get(
360 valueString, paramName));
361 return false;
362 }
363
364 paramStartPos = pos;
365 }
366 }
367
368
369 // We must be at the end of the value. Read the last parameter and make
370 // sure it is valid.
371 String paramStr = valueString.substring(paramStartPos);
372 int colonPos = paramStr.indexOf(':');
373 if (colonPos < 0)
374 {
375
376 invalidReason.append(ERR_ATTR_SYNTAX_TELETEXID_PARAM_NO_COLON.get(
377 valueString));
378 return false;
379 }
380
381 String paramName = paramStr.substring(0, colonPos);
382 if (! ALLOWED_TTX_PARAMETERS.contains(paramName))
383 {
384
385 invalidReason.append(ERR_ATTR_SYNTAX_TELETEXID_ILLEGAL_PARAMETER.get(
386 valueString, paramName));
387 return false;
388 }
389
390
391 // If we've gotten here, then the value must be valid.
392 return true;
393 }
394 }
395