001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 *
019 */
020 package org.apache.directory.shared.ldap.schema.parsers;
021
022
023 import java.io.File;
024 import java.io.FileReader;
025 import java.io.IOException;
026 import java.io.InputStream;
027 import java.io.InputStreamReader;
028 import java.text.ParseException;
029 import java.util.ArrayList;
030 import java.util.HashMap;
031 import java.util.List;
032 import java.util.Map;
033
034 import org.apache.directory.shared.i18n.I18n;
035 import org.apache.directory.shared.ldap.schema.AttributeType;
036 import org.apache.directory.shared.ldap.schema.ObjectClass;
037 import org.apache.directory.shared.ldap.schema.SchemaObject;
038 import org.apache.directory.shared.ldap.schema.syntaxCheckers.OpenLdapObjectIdentifierMacro;
039 import org.apache.directory.shared.ldap.util.ExceptionUtils;
040
041 import antlr.RecognitionException;
042 import antlr.TokenStreamException;
043
044
045 /**
046 * A reusable wrapper for antlr generated OpenLDAP schema parsers.
047 *
048 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
049 * @version $Rev: 494164 $
050 */
051 public class OpenLdapSchemaParser extends AbstractSchemaParser
052 {
053
054 /** The list of parsed schema descriptions */
055 private List<Object> schemaDescriptions;
056
057 /** The list of attribute type, initialized by splitParsedSchemaDescriptions() */
058 private List<AttributeType> attributeTypes;
059
060 /** The list of object classes, initialized by splitParsedSchemaDescriptions()*/
061 private List<ObjectClass> objectClasses;
062
063 /** The map of object identifier macros, initialized by splitParsedSchemaDescriptions()*/
064 private Map<String, OpenLdapObjectIdentifierMacro> objectIdentifierMacros;
065
066 /** Flag whether object identifier macros should be resolved. */
067 private boolean isResolveObjectIdentifierMacros;
068
069
070 /**
071 * Creates a reusable instance of an OpenLdapSchemaParser.
072 *
073 * @throws IOException if the pipe cannot be formed
074 */
075 public OpenLdapSchemaParser() throws IOException
076 {
077 isResolveObjectIdentifierMacros = true;
078 super.setQuirksMode( true );
079 }
080
081
082 /**
083 * Reset the parser
084 */
085 public void clear()
086 {
087 }
088
089
090 /**
091 * Gets the attribute types.
092 *
093 * @return the attribute types
094 */
095 public List<AttributeType> getAttributeTypes()
096 {
097 return attributeTypes;
098 }
099
100
101 /**
102 * Gets the object class types.
103 *
104 * @return the object class types
105 */
106 public List<ObjectClass> getObjectClassTypes()
107 {
108 return objectClasses;
109 }
110
111
112 /**
113 * Gets the object identifier macros.
114 *
115 * @return the object identifier macros
116 */
117 public Map<String, OpenLdapObjectIdentifierMacro> getObjectIdentifierMacros()
118 {
119 return objectIdentifierMacros;
120 }
121
122
123 /**
124 * Splits parsed schema descriptions and resolved
125 * object identifier macros.
126 *
127 * @throws ParseException the parse exception
128 */
129 private void afterParse() throws ParseException
130 {
131 objectClasses = new ArrayList<ObjectClass>();
132 attributeTypes = new ArrayList<AttributeType>();
133 objectIdentifierMacros = new HashMap<String, OpenLdapObjectIdentifierMacro>();
134
135 // split parsed schema descriptions
136 for ( Object obj : schemaDescriptions )
137 {
138 if ( obj instanceof OpenLdapObjectIdentifierMacro )
139 {
140 OpenLdapObjectIdentifierMacro oid = ( OpenLdapObjectIdentifierMacro ) obj;
141 objectIdentifierMacros.put( oid.getName(), oid );
142 }
143 else if ( obj instanceof AttributeType )
144 {
145 AttributeType attributeType = ( AttributeType ) obj;
146
147 attributeTypes.add( attributeType );
148 }
149 else if ( obj instanceof ObjectClass )
150 {
151 ObjectClass objectClass = ( ObjectClass ) obj;
152
153 objectClasses.add( objectClass );
154 }
155 }
156
157 if ( isResolveObjectIdentifierMacros() )
158 {
159 // resolve object identifier macros
160 for ( OpenLdapObjectIdentifierMacro oid : objectIdentifierMacros.values() )
161 {
162 resolveObjectIdentifierMacro( oid );
163 }
164
165 // apply object identifier macros to object classes
166 for ( ObjectClass objectClass : objectClasses )
167 {
168 objectClass.setOid( getResolveOid( objectClass.getOid() ) );
169 }
170
171 // apply object identifier macros to attribute types
172 for ( AttributeType attributeType : attributeTypes )
173 {
174 attributeType.setOid( getResolveOid( attributeType.getOid() ) );
175 attributeType.setSyntaxOid( getResolveOid( attributeType.getSyntaxOid() ) );
176 }
177
178 }
179 }
180
181
182 private String getResolveOid( String oid )
183 {
184 if ( oid != null && oid.indexOf( ':' ) != -1 )
185 {
186 // resolve OID
187 String[] nameAndSuffix = oid.split( ":" );
188 if ( objectIdentifierMacros.containsKey( nameAndSuffix[0] ) )
189 {
190 OpenLdapObjectIdentifierMacro macro = objectIdentifierMacros.get( nameAndSuffix[0] );
191 return macro.getResolvedOid() + "." + nameAndSuffix[1];
192 }
193 }
194 return oid;
195 }
196
197
198 private void resolveObjectIdentifierMacro( OpenLdapObjectIdentifierMacro macro ) throws ParseException
199 {
200 String rawOidOrNameSuffix = macro.getRawOidOrNameSuffix();
201
202 if ( macro.isResolved() )
203 {
204 // finished
205 }
206 else if ( rawOidOrNameSuffix.indexOf( ':' ) != -1 )
207 {
208 // resolve OID
209 String[] nameAndSuffix = rawOidOrNameSuffix.split( ":" );
210 if ( objectIdentifierMacros.containsKey( nameAndSuffix[0] ) )
211 {
212 OpenLdapObjectIdentifierMacro parentMacro = objectIdentifierMacros.get( nameAndSuffix[0] );
213 resolveObjectIdentifierMacro( parentMacro );
214 macro.setResolvedOid( parentMacro.getResolvedOid() + "." + nameAndSuffix[1] );
215 }
216 else
217 {
218 throw new ParseException( I18n.err( I18n.ERR_04257, nameAndSuffix[0] ), 0 );
219 }
220
221 }
222 else
223 {
224 // no :suffix,
225 if ( objectIdentifierMacros.containsKey( rawOidOrNameSuffix ) )
226 {
227 OpenLdapObjectIdentifierMacro parentMacro = objectIdentifierMacros.get( rawOidOrNameSuffix );
228 resolveObjectIdentifierMacro( parentMacro );
229 macro.setResolvedOid( parentMacro.getResolvedOid() );
230 }
231 else
232 {
233 macro.setResolvedOid( rawOidOrNameSuffix );
234 }
235 }
236 }
237
238
239 /**
240 * Parses an OpenLDAP schemaObject element/object.
241 *
242 * @param schemaObject the String image of a complete schema object
243 * @throws IOException If the schemaObject can't be transformed to a byteArrayInputStream
244 * @throws ParseException If the schemaObject can't be parsed
245 */
246 public SchemaObject parse( String schemaObject ) throws ParseException
247 {
248 if ( schemaObject == null || schemaObject.trim().equals( "" ) )
249 {
250 throw new ParseException( I18n.err( I18n.ERR_04258 ), 0 );
251 }
252
253 reset( schemaObject ); // reset and initialize the parser / lexer pair
254 invokeParser( schemaObject );
255
256 if ( !schemaDescriptions.isEmpty() )
257 {
258 for ( Object obj : schemaDescriptions )
259 {
260 if ( obj instanceof SchemaObject )
261 {
262 return ( SchemaObject ) obj;
263 }
264 }
265 }
266 return null;
267 }
268
269
270 private void invokeParser( String subject ) throws ParseException
271 {
272 try
273 {
274 monitor.startedParse( "starting parse on:\n" + subject );
275 schemaDescriptions = parser.openLdapSchema();
276 afterParse();
277 monitor.finishedParse( "Done parsing!" );
278 }
279 catch ( RecognitionException e )
280 {
281 String msg = "Parser failure on:\n\t" + subject;
282 msg += "\nAntlr exception trace:\n" + ExceptionUtils.getFullStackTrace( e );
283 throw new ParseException( msg, e.getColumn() );
284 }
285 catch ( TokenStreamException e2 )
286 {
287 String msg = "Parser failure on:\n\t" + subject;
288 msg += "\nAntlr exception trace:\n" + ExceptionUtils.getFullStackTrace( e2 );
289 throw new ParseException( msg, 0 );
290 }
291 }
292
293
294 /**
295 * Parses a stream of OpenLDAP schemaObject elements/objects.
296 *
297 * @param schemaIn a stream of schema objects
298 * @throws IOException If the schemaObject can't be transformed to a byteArrayInputStream
299 * @throws ParseException If the schemaObject can't be parsed
300 */
301 public void parse( InputStream schemaIn ) throws IOException, ParseException
302 {
303 InputStreamReader in = new InputStreamReader( schemaIn );
304 lexer.prepareNextInput( in );
305 parser.resetState();
306
307 invokeParser( "schema input stream ==> " + schemaIn.toString() );
308 }
309
310
311 /**
312 * Parses a file of OpenLDAP schemaObject elements/objects.
313 *
314 * @param schemaFile a file of schema objects
315 * @throws IOException If the schemaObject can't be transformed to a byteArrayInputStream
316 * @throws ParseException If the schemaObject can't be parsed
317 */
318 public void parse( File schemaFile ) throws IOException, ParseException
319 {
320 FileReader in = new FileReader( schemaFile );
321 lexer.prepareNextInput( in );
322 parser.resetState();
323
324 invokeParser( "schema file ==> " + schemaFile.getAbsolutePath() );
325 }
326
327
328 /**
329 * Checks if object identifier macros should be resolved.
330 *
331 * @return true, object identifier macros should be resolved.
332 */
333 public boolean isResolveObjectIdentifierMacros()
334 {
335 return isResolveObjectIdentifierMacros;
336 }
337
338
339 /**
340 * Sets if object identifier macros should be resolved.
341 *
342 * @param isResolveObjectIdentifierMacros true if object identifier macros should be resolved
343 */
344 public void setResolveObjectIdentifierMacros( boolean isResolveObjectIdentifierMacros )
345 {
346 this.isResolveObjectIdentifierMacros = isResolveObjectIdentifierMacros;
347 }
348
349 }