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