View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.api.converter.schema;
21  
22  
23  import java.io.ByteArrayInputStream;
24  import java.io.File;
25  import java.io.FileInputStream;
26  import java.io.IOException;
27  import java.io.InputStream;
28  import java.io.PipedInputStream;
29  import java.io.PipedOutputStream;
30  import java.text.ParseException;
31  import java.util.List;
32  
33  import org.apache.commons.lang.exception.ExceptionUtils;
34  import org.apache.directory.api.i18n.I18n;
35  
36  import antlr.RecognitionException;
37  import antlr.TokenStreamException;
38  
39  
40  /**
41   * A reusable wrapper for antlr generated schema parsers.
42   *
43   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
44   */
45  public class SchemaParser
46  {
47      /** The antlr generated parser */
48      private antlrSchemaConverterParser parser = null;
49  
50      /** A pipe into the parser */
51      private PipedOutputStream parserIn = null;
52  
53      /** A temporary buffer storing the read schema bytes */
54      private byte[] buf = new byte[128];
55  
56      /** The inputStream mapped over the schema file to parse */
57      private InputStream schemaIn;
58  
59      /** The thread used to read the schema */
60      private Thread producerThread;
61  
62  
63      /**
64       * Creates a reusable instance of an SchemaParser.
65       *
66       * @throws java.io.IOException if the pipe cannot be formed
67       */
68      public SchemaParser() throws IOException
69      {
70          init();
71      }
72  
73  
74      /**
75       * Initializes a parser and its plumbing.
76       *
77       * @throws java.io.IOException if a pipe cannot be formed.
78       */
79      public synchronized void init() throws IOException
80      {
81          parserIn = new PipedOutputStream();
82          PipedInputStream in = new PipedInputStream();
83          parserIn.connect( in );
84          antlrSchemaConverterLexer lexer = new antlrSchemaConverterLexer( in );
85          parser = new antlrSchemaConverterParser( lexer );
86      }
87  
88  
89      /**
90       * Clear the parser.
91       */
92      public synchronized void clear()
93      {
94          parser.clear();
95      }
96  
97  
98      /**
99       * 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 }