blob: fbb03b9de3db3a679e152b5f39bb33893410a378 [file] [log] [blame]
/*
* 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();
}
}
}
}