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 */ 020package org.apache.directory.api.converter.schema; 021 022 023import java.io.ByteArrayInputStream; 024import java.io.File; 025import java.io.FileInputStream; 026import java.io.IOException; 027import java.io.InputStream; 028import java.io.PipedInputStream; 029import java.io.PipedOutputStream; 030import java.text.ParseException; 031import java.util.List; 032 033import org.apache.commons.lang.exception.ExceptionUtils; 034import org.apache.directory.api.i18n.I18n; 035 036import antlr.RecognitionException; 037import antlr.TokenStreamException; 038 039 040/** 041 * A reusable wrapper for antlr generated schema parsers. 042 * 043 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 044 */ 045public class SchemaParser 046{ 047 /** The antlr generated parser */ 048 private antlrSchemaConverterParser parser = null; 049 050 /** A pipe into the parser */ 051 private PipedOutputStream parserIn = null; 052 053 /** A temporary buffer storing the read schema bytes */ 054 private byte[] buf = new byte[128]; 055 056 /** The inputStream mapped over the schema file to parse */ 057 private InputStream schemaIn; 058 059 /** The thread used to read the schema */ 060 private Thread producerThread; 061 062 063 /** 064 * Creates a reusable instance of an SchemaParser. 065 * 066 * @throws java.io.IOException if the pipe cannot be formed 067 */ 068 public SchemaParser() throws IOException 069 { 070 init(); 071 } 072 073 074 /** 075 * Initializes a parser and its plumbing. 076 * 077 * @throws java.io.IOException if a pipe cannot be formed. 078 */ 079 public synchronized void init() throws IOException 080 { 081 parserIn = new PipedOutputStream(); 082 PipedInputStream in = new PipedInputStream(); 083 parserIn.connect( in ); 084 antlrSchemaConverterLexer lexer = new antlrSchemaConverterLexer( in ); 085 parser = new antlrSchemaConverterParser( lexer ); 086 } 087 088 089 /** 090 * Clear the parser. 091 */ 092 public synchronized void clear() 093 { 094 parser.clear(); 095 } 096 097 098 /** 099 * Thread safe method parses an OpenLDAP schemaObject element/object. 100 * 101 * @param schemaObject the String image of a complete schema object 102 * @return The list of parsed schema elements 103 * @throws java.io.IOException If the schema file can't be processed 104 * @throws java.text.ParseException If we weren't able to parse the schema 105 */ 106 public synchronized List<SchemaElement> parse( String schemaObject ) throws IOException, ParseException 107 { 108 if ( ( schemaObject == null ) || ( schemaObject.trim().equals( "" ) ) ) 109 { 110 throw new ParseException( I18n.err( I18n.ERR_06001_EMPTY_OR_NULL_SCHEMA_OBJECT ), 0 ); 111 } 112 113 schemaIn = new ByteArrayInputStream( schemaObject.getBytes() ); 114 115 if ( producerThread == null ) 116 { 117 producerThread = new Thread( new DataProducer() ); 118 } 119 120 producerThread.start(); 121 return invokeParser( schemaObject ); 122 } 123 124 125 /** 126 * Invoke the parser 127 * @param schemaName The schema to be parsed 128 * @return A list of schema elements 129 * 130 * @throws java.io.IOException If the schema file can't be processed 131 * @throws java.text.ParseException If we weren't able to parse the schema 132 */ 133 private List<SchemaElement> invokeParser( String schemaName ) throws IOException, ParseException 134 { 135 try 136 { 137 parser.parseSchema(); 138 139 return parser.getSchemaElements(); 140 } 141 catch ( RecognitionException re ) 142 { 143 String msg = I18n.err( I18n.ERR_06002_PARSER_FAILURE, schemaName, ExceptionUtils.getFullStackTrace( re ) ); 144 init(); 145 throw new ParseException( msg, re.getColumn() ); 146 } 147 catch ( TokenStreamException tse ) 148 { 149 String msg = I18n.err( I18n.ERR_06002_PARSER_FAILURE, schemaName, ExceptionUtils.getFullStackTrace( tse ) ); 150 init(); 151 throw new ParseException( msg, 0 ); 152 } 153 } 154 155 156 /** 157 * Thread safe method parses a stream of OpenLDAP schemaObject elements/objects. 158 * 159 * @param schemaIn a stream of schema objects 160 * @return A list of schema elements 161 * @throws java.io.IOException If the schema file can't be processed 162 * @throws java.text.ParseException If we weren't able to parse the schema 163 */ 164 public synchronized List<SchemaElement> parse( InputStream schemaIn ) throws IOException, ParseException 165 { 166 this.schemaIn = schemaIn; 167 168 if ( producerThread == null ) 169 { 170 producerThread = new Thread( new DataProducer() ); 171 } 172 173 producerThread.start(); 174 175 return invokeParser( "schema input stream ==> " + schemaIn.toString() ); 176 } 177 178 179 /** 180 * Thread safe method parses a file of OpenLDAP schemaObject elements/objects. 181 * 182 * @param schemaFile a file of schema objects 183 * @throws java.io.IOException If the schema file can't be processed 184 * @throws java.text.ParseException If we weren't able to parse the schema 185 */ 186 public synchronized void parse( File schemaFile ) throws IOException, ParseException 187 { 188 this.schemaIn = new FileInputStream( schemaFile ); 189 190 if ( producerThread == null ) 191 { 192 producerThread = new Thread( new DataProducer() ); 193 } 194 195 producerThread.start(); 196 invokeParser( "schema file ==> " + schemaFile.getAbsolutePath() ); 197 } 198 199 /** 200 * The thread which read the schema files and fill the 201 * temporary buffer used by the lexical analyzer. 202 */ 203 private class DataProducer implements Runnable 204 { 205 public void run() 206 { 207 int count = -1; 208 209 try 210 { 211 while ( ( count = schemaIn.read( buf ) ) != -1 ) 212 { 213 parserIn.write( buf, 0, count ); 214 parserIn.flush(); 215 } 216 217 // using an input termination token END - need extra space to return 218 parserIn.write( "END ".getBytes() ); 219 } 220 catch ( IOException e ) 221 { 222 e.printStackTrace(); 223 } 224 } 225 } 226}