View Javadoc

1   /*
2    * Copyright 2004-2007 Brian McCallister
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.skife.jdbi.v2;
18  
19  import org.skife.jdbi.v2.exceptions.UnableToCreateStatementException;
20  import org.skife.jdbi.v2.tweak.StatementLocator;
21  
22  import java.io.BufferedReader;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.io.InputStreamReader;
26  
27  /**
28   * looks for [name], then [name].sql on the classpath
29   */
30  public class ClasspathStatementLocator implements StatementLocator
31  {
32      /**
33       * Very basic sanity test to see if a string looks like it might be sql
34       */
35      public static boolean looksLikeSql(String sql) {
36          final String local = sql.substring(0, 7).toLowerCase();
37          return local.startsWith("insert ")
38                 || local.startsWith("update ")
39                 || local.startsWith("select ")
40                 || local.startsWith("call ")
41                 || local.startsWith("delete ")
42                 || local.startsWith("create ")
43                 || local.startsWith("alter ")
44                 || local.startsWith("drop ");
45      }
46  
47      /**
48       * If the passed in name doesn't look like SQL it will search the classpath for a file
49       * which looks like the provided name.
50       * <p/>
51       * The "looks like" algorithm is not very sophisticated, it basically looks for the string
52       * to begin with insert, update, select, call, delete, create, alter, or drop followed
53       * by a space.
54       * <p/>
55       * If no resource is found using the passed in string, the string s returned as-is
56       *
57       * @param name Name or statement literal
58       *
59       * @return SQL to execute (which will go to a StatementRRewrter first)
60       *
61       * @throws UnableToCreateStatementException
62       *          if an IOException occurs reading a found resource
63       */
64      public String locate(String name, StatementContext ctx) {
65          if (looksLikeSql(name)) {
66              return name;
67          }
68          final ClassLoader loader = selectClassLoader();
69          InputStream in_stream = loader.getResourceAsStream(name);
70          BufferedReader reader = null;
71          try {
72              if (in_stream == null) {
73                  in_stream = loader.getResourceAsStream(name + ".sql");
74              }
75              if (in_stream == null) {
76                  return name;
77              }
78  
79              final StringBuffer buffer = new StringBuffer();
80              reader = new BufferedReader(new InputStreamReader(in_stream));
81              String line;
82              try {
83                  while ((line = reader.readLine()) != null) {
84                      if (isComment(line)) {
85                          // comment
86                          continue;
87                      }
88                      buffer.append(line).append(" ");
89                  }
90              }
91              catch (IOException e) {
92                  throw new UnableToCreateStatementException(e.getMessage(), e, ctx);
93              }
94  
95              return buffer.toString();
96          }
97          finally {
98              try {
99                  if (reader != null) {
100                     reader.close();
101                 }
102             }
103             catch (IOException e) {
104                 // nothing we can do here :-(
105             }
106         }
107     }
108 
109     /**
110      * There *must* be a better place to put this without creating a util class just for it
111      */
112     private static ClassLoader selectClassLoader() {
113         ClassLoader loader;
114         if (Thread.currentThread().getContextClassLoader() != null) {
115             loader = Thread.currentThread().getContextClassLoader();
116         }
117         else {
118             loader = ClasspathStatementLocator.class.getClassLoader();
119         }
120         return loader;
121     }
122 
123     private static boolean isComment(final String line) {
124         return line.startsWith("#") || line.startsWith("--") || line.startsWith("//");
125     }
126 }