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