001    /**
002     * Copyright 2010-2013 The Kuali Foundation
003     *
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.opensource.org/licenses/ecl2.php
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.common.jdbc.suppliers;
017    
018    import java.io.BufferedReader;
019    import java.io.IOException;
020    import java.util.Arrays;
021    import java.util.List;
022    
023    import org.apache.commons.io.IOUtils;
024    import org.kuali.common.jdbc.reader.SqlReader;
025    import org.kuali.common.jdbc.service.MetaDataUtils;
026    import org.kuali.common.jdbc.sql.model.SqlMetaData;
027    import org.kuali.common.util.Assert;
028    import org.kuali.common.util.CollectionUtils;
029    import org.kuali.common.util.ListUtils;
030    import org.kuali.common.util.LocationUtils;
031    
032    /**
033     * Supply SQL from strings that may have more than one SQL statement each
034     */
035    public final class ComplexStringSupplier extends AbstractSupplier {
036    
037            private int index = 0;
038            private BufferedReader in;
039    
040            private final List<String> strings;
041            private final SqlReader reader;
042            private final SqlMetaData metaData;
043            private boolean open = false;
044            private boolean done = false;
045    
046            public ComplexStringSupplier(String sql, SqlReader reader) {
047                    this(CollectionUtils.singletonList(sql), reader);
048            }
049    
050            public ComplexStringSupplier(List<String> strings, SqlReader reader) {
051                    Assert.noNulls(strings, reader);
052                    this.strings = ListUtils.newImmutableArrayList(strings);
053                    this.reader = reader;
054                    this.metaData = MetaDataUtils.getSqlMetaData(this);
055            }
056    
057            @Override
058            public synchronized void open() {
059                    Assert.isFalse(open, "Already open");
060                    this.open = true;
061                    this.done = false;
062    
063                    // Reset index to zero
064                    this.index = 0;
065    
066                    // Open a reader to the first string in the list
067                    this.in = getBufferedReader(strings, index);
068            }
069    
070            @Override
071            public synchronized List<String> getSql() {
072                    Assert.isTrue(open, "Not open");
073                    if (done) {
074                            return null;
075                    }
076                    try {
077                            // Have the reader produce a SQL statement
078                            String sql = reader.getSql(in);
079    
080                            if (sql != null) {
081                                    // We got SQL we are done
082                                    return Arrays.asList(sql);
083                            } else {
084                                    // We've exhausted the current string, move to the next one
085                                    this.index++;
086                            }
087    
088                            // We've exhausted all of the strings, we are done
089                            if (index == strings.size()) {
090                                    this.done = true;
091                                    return null;
092                            }
093    
094                            // Open a reader to the new string
095                            this.in = getBufferedReader(strings, index);
096    
097                            // Get SQL from the new string
098                            return getSql();
099                    } catch (IOException e) {
100                            throw new IllegalStateException(e);
101                    }
102            }
103    
104            @Override
105            public synchronized void close() {
106                    Assert.isTrue(open, "Not open");
107                    this.open = false;
108    
109                    // Make sure the BufferedReader is closed
110                    IOUtils.closeQuietly(in);
111            }
112    
113            /**
114             * Extract a String from the list and open a BufferedReader that can read from it
115             */
116            protected BufferedReader getBufferedReader(List<String> strings, int index) {
117                    String string = strings.get(index);
118                    return LocationUtils.getBufferedReaderFromString(string);
119            }
120    
121            @Override
122            public SqlMetaData getMetaData() {
123                    return metaData;
124            }
125    
126            public List<String> getStrings() {
127                    return strings;
128            }
129    
130            public SqlReader getReader() {
131                    return reader;
132            }
133    
134    }