| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * https://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| */ |
| package org.apache.directory.api.ldap.schema.converter; |
| |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.PipedInputStream; |
| import java.io.PipedOutputStream; |
| import java.nio.file.Files; |
| import java.nio.file.Paths; |
| import java.text.ParseException; |
| import java.util.List; |
| |
| import org.apache.commons.lang3.exception.ExceptionUtils; |
| import org.apache.directory.api.i18n.I18n; |
| import org.apache.directory.api.util.Strings; |
| |
| import antlr.RecognitionException; |
| import antlr.TokenStreamException; |
| |
| |
| /** |
| * A reusable wrapper for antlr generated schema parsers. |
| * |
| * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> |
| */ |
| public class SchemaParser |
| { |
| /** The antlr generated parser */ |
| private antlrSchemaConverterParser parser = null; |
| |
| /** A pipe into the parser */ |
| private PipedOutputStream parserIn = null; |
| |
| /** A temporary buffer storing the read schema bytes */ |
| private byte[] buf = new byte[128]; |
| |
| /** The inputStream mapped over the schema file to parse */ |
| private InputStream schemaIn; |
| |
| /** The thread used to read the schema */ |
| private Thread producerThread; |
| |
| |
| /** |
| * Creates a reusable instance of an SchemaParser. |
| * |
| * @throws java.io.IOException if the pipe cannot be formed |
| */ |
| public SchemaParser() throws IOException |
| { |
| init(); |
| } |
| |
| |
| /** |
| * Initializes a parser and its plumbing. |
| * |
| * @throws java.io.IOException if a pipe cannot be formed. |
| */ |
| public synchronized void init() throws IOException |
| { |
| parserIn = new PipedOutputStream(); |
| PipedInputStream in = new PipedInputStream(); |
| parserIn.connect( in ); |
| antlrSchemaConverterLexer lexer = new antlrSchemaConverterLexer( in ); |
| parser = new antlrSchemaConverterParser( lexer ); |
| } |
| |
| |
| /** |
| * Clear the parser. |
| */ |
| public synchronized void clear() |
| { |
| parser.clear(); |
| } |
| |
| |
| /** |
| * Thread safe method parses an OpenLDAP schemaObject element/object. |
| * |
| * @param schemaObject the String image of a complete schema object |
| * @return The list of parsed schema elements |
| * @throws java.io.IOException If the schema file can't be processed |
| * @throws java.text.ParseException If we weren't able to parse the schema |
| */ |
| public synchronized List<SchemaElement> parse( String schemaObject ) throws IOException, ParseException |
| { |
| if ( ( schemaObject == null ) || ( schemaObject.trim().equals( Strings.EMPTY_STRING ) ) ) |
| { |
| throw new ParseException( I18n.err( I18n.ERR_15002_EMPTY_OR_NULL_SCHEMA_OBJECT ), 0 ); |
| } |
| |
| schemaIn = new ByteArrayInputStream( Strings.getBytesUtf8( schemaObject ) ); |
| |
| if ( producerThread == null ) |
| { |
| producerThread = new Thread( new DataProducer() ); |
| } |
| |
| producerThread.start(); |
| |
| return invokeParser( schemaObject ); |
| } |
| |
| |
| /** |
| * Invoke the parser |
| * |
| * @param schemaName The schema to be parsed |
| * @return A list of schema elements |
| * @throws java.io.IOException If the schema file can't be processed |
| * @throws java.text.ParseException If we weren't able to parse the schema |
| */ |
| private List<SchemaElement> invokeParser( String schemaName ) throws IOException, ParseException |
| { |
| try |
| { |
| parser.parseSchema(); |
| |
| return parser.getSchemaElements(); |
| } |
| catch ( RecognitionException re ) |
| { |
| String msg = I18n.err( I18n.ERR_15003_PARSER_FAILURE, schemaName, ExceptionUtils.getStackTrace( re ) ); |
| init(); |
| throw new ParseException( msg, re.getColumn() ); |
| } |
| catch ( TokenStreamException tse ) |
| { |
| String msg = I18n.err( I18n.ERR_15003_PARSER_FAILURE, schemaName, ExceptionUtils.getStackTrace( tse ) ); |
| init(); |
| throw new ParseException( msg, 0 ); |
| } |
| } |
| |
| |
| /** |
| * Thread safe method parses a stream of OpenLDAP schemaObject elements/objects. |
| * |
| * @param schemaIn a stream of schema objects |
| * @return A list of schema elements |
| * @throws java.io.IOException If the schema file can't be processed |
| * @throws java.text.ParseException If we weren't able to parse the schema |
| */ |
| public synchronized List<SchemaElement> parse( InputStream schemaIn ) throws IOException, ParseException |
| { |
| this.schemaIn = schemaIn; |
| |
| if ( producerThread == null ) |
| { |
| producerThread = new Thread( new DataProducer() ); |
| } |
| |
| producerThread.start(); |
| |
| return invokeParser( "schema input stream ==> " + schemaIn.toString() ); |
| } |
| |
| |
| /** |
| * Thread safe method parses a file of OpenLDAP schemaObject elements/objects. |
| * |
| * @param schemaFile a file of schema objects |
| * @throws java.io.IOException If the schema file can't be processed |
| * @throws java.text.ParseException If we weren't able to parse the schema |
| */ |
| public synchronized void parse( File schemaFile ) throws IOException, ParseException |
| { |
| schemaIn = Files.newInputStream( Paths.get( schemaFile.getPath() ) ); |
| |
| if ( producerThread == null ) |
| { |
| producerThread = new Thread( new DataProducer() ); |
| } |
| |
| producerThread.start(); |
| invokeParser( "schema file ==> " + schemaFile.getAbsolutePath() ); |
| } |
| |
| |
| /** |
| * The thread which read the schema files and fill the |
| * temporary buffer used by the lexical analyzer. |
| */ |
| private class DataProducer implements Runnable |
| { |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public void run() |
| { |
| int count = -1; |
| |
| try |
| { |
| while ( ( count = schemaIn.read( buf ) ) != -1 ) |
| { |
| parserIn.write( buf, 0, count ); |
| parserIn.flush(); |
| } |
| |
| // using an input termination token END - need extra space to return |
| parserIn.write( Strings.getBytesUtf8( "END " ) ); |
| } |
| catch ( IOException e ) |
| { |
| e.printStackTrace(); |
| } |
| } |
| } |
| } |