1 package jp.sourceforge.ea2ddl.dao.allcommon.cbean.outsidesql;
\r
3 import org.apache.commons.logging.Log;
\r
4 import org.apache.commons.logging.LogFactory;
\r
5 import org.seasar.framework.util.InputStreamReaderUtil;
\r
6 import org.seasar.framework.util.ReaderUtil;
\r
7 import org.seasar.framework.util.ResourceUtil;
\r
9 import jp.sourceforge.ea2ddl.dao.allcommon.DBFluteConfig;
\r
10 import jp.sourceforge.ea2ddl.dao.allcommon.dbmeta.DBMeta;
\r
11 import jp.sourceforge.ea2ddl.dao.allcommon.dbmeta.DBMetaInstanceHandler;
\r
12 import jp.sourceforge.ea2ddl.dao.allcommon.jdbc.StatementConfig;
\r
13 import jp.sourceforge.ea2ddl.dao.allcommon.util.SimpleStringUtil;
\r
14 import jp.sourceforge.ea2ddl.dao.allcommon.util.SimpleSystemUtil;
\r
17 * The context of outside-SQL.
\r
18 * @author DBFlute(AutoGenerator)
\r
20 public class OutsideSqlContext {
\r
22 /** Log instance. */
\r
23 private static final Log _log = LogFactory.getLog(OutsideSqlContext.class);
\r
25 // ===================================================================================
\r
28 /** The thread-local for this. */
\r
29 private static final ThreadLocal<OutsideSqlContext> _threadLocal = new ThreadLocal<OutsideSqlContext>();
\r
32 * Get outside-SQL context on thread.
\r
33 * @return Outside-SQL context. (Nullable)
\r
35 public static OutsideSqlContext getOutsideSqlContextOnThread() {
\r
36 return (OutsideSqlContext)_threadLocal.get();
\r
40 * Set outside-SQL context on thread.
\r
41 * @param outsideSqlContext Outside-SQL context. (NotNull)
\r
43 public static void setOutsideSqlContextOnThread(OutsideSqlContext outsideSqlContext) {
\r
44 if (outsideSqlContext == null) {
\r
45 String msg = "The argument[outsideSqlContext] must not be null.";
\r
46 throw new IllegalArgumentException(msg);
\r
48 _threadLocal.set(outsideSqlContext);
\r
52 * Is existing outside-SQL context on thread?
\r
54 * @return Determination.
\r
56 public static boolean isExistOutsideSqlContextOnThread() {
\r
57 return (_threadLocal.get() != null);
\r
61 * Clear outside-SQL context on thread.
\r
63 public static void clearOutsideSqlContextOnThread() {
\r
64 _threadLocal.set(null);
\r
67 // ===================================================================================
\r
70 public static String generateSpecifiedOutsideSqlUniqueKey(String methodName, String path, Object pmb, OutsideSqlOption option, Object resultTypeSpecification) {
\r
71 final String pmbKey = (pmb != null ? pmb.getClass().getName() : "null");
\r
72 final String resultKey = (resultTypeSpecification != null ? ":" + resultTypeSpecification : "null");
\r
73 final String tableDbName = option.getTableDbName();
\r
74 final String generatedUniqueKey = option.generateUniqueKey();
\r
75 return methodName + "():" + tableDbName + ":" + path + ":" + pmbKey + ":" + generatedUniqueKey + resultKey;
\r
78 // ===================================================================================
\r
79 // Exception Handling
\r
80 // ==================
\r
81 public static void throwOutsideSqlNotFoundException(String path) {
\r
82 String msg = "Look! Read the message below." + getLineSeparator();
\r
83 msg = msg + "/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *" + getLineSeparator();
\r
84 msg = msg + "The outsideSql was Not Found!" + getLineSeparator();
\r
85 msg = msg + getLineSeparator();
\r
86 msg = msg + "[Advice]" + getLineSeparator();
\r
87 msg = msg + "Please confirm the existence of your target file of outsideSql on your classpath." + getLineSeparator();
\r
88 msg = msg + "And please confirm the file name and the file path STRICTLY!" + getLineSeparator();
\r
89 msg = msg + getLineSeparator();
\r
90 msg = msg + "[Specified OutsideSql Path]" + getLineSeparator() + path + getLineSeparator();
\r
91 msg = msg + "* * * * * * * * * */" + getLineSeparator();
\r
92 throw new jp.sourceforge.ea2ddl.dao.allcommon.exception.OutsideSqlNotFoundException(msg);
\r
95 // ===================================================================================
\r
98 // -----------------------------------------------------
\r
99 // Common of OutsideSql
\r
100 // --------------------
\r
101 protected boolean _dynamicBinding;
\r
103 protected boolean _offsetByCursorForcedly;
\r
105 protected boolean _limitByCursorForcedly;
\r
107 // -----------------------------------------------------
\r
108 // Specified OutsideSql
\r
109 // --------------------
\r
110 /** The path of outside-sql. (The mark of Specified-OutsideSql) */
\r
111 protected String _outsideSqlPath;
\r
113 protected Object _parameterBean;
\r
115 protected Object _resultTypeSpecification;
\r
117 protected String _methodName;
\r
119 /** The config of statement. (Nullable) */
\r
120 protected StatementConfig _statementConfig;
\r
122 /** The DB name of table for using behavior-SQL-path. (Nullable) */
\r
123 protected String _tableDbName;
\r
125 // ===================================================================================
\r
129 * @param sqlFileEncoding The encoding of SQL file. (NotNull)
\r
130 * @param dbmsSuffix The suffix of DBMS. (NotNull)
\r
131 * @return The filtered outside-SQL. (NotNull)
\r
132 * @exception jp.sourceforge.ea2ddl.dao.allcommon.exception.OutsideSqlNotFoundException When the SQL is not found.
\r
134 public String readFilteredOutsideSql(String sqlFileEncoding, String dbmsSuffix) {
\r
135 final String sql = readOutsideSql(sqlFileEncoding, dbmsSuffix);
\r
136 return replaceOutsideSqlBindCharacterOnLineComment(sql);
\r
139 protected String replaceOutsideSqlBindCharacterOnLineComment(String sql) {
\r
140 final String bindCharacter = "?";
\r
141 if (sql.indexOf(bindCharacter) < 0) {
\r
144 final String lineSeparator = "\n";
\r
145 if (sql.indexOf(lineSeparator) < 0) {
\r
148 final String lineCommentMark = "--";
\r
149 if (sql.indexOf(lineCommentMark) < 0) {
\r
152 final StringBuilder sb = new StringBuilder();
\r
153 final String[] lines = sql.split(lineSeparator);
\r
154 for (String line : lines) {
\r
155 final int lineCommentIndex = line.indexOf("--");
\r
156 if (lineCommentIndex < 0) {
\r
157 sb.append(line).append(lineSeparator);
\r
160 final String lineComment = line.substring(lineCommentIndex);
\r
161 if (lineComment.contains("ELSE") || !lineComment.contains(bindCharacter)) {
\r
162 sb.append(line).append(lineSeparator);
\r
166 if (_log.isDebugEnabled()) {
\r
167 _log.debug("...Replacing bind character on line comment: " + lineComment);
\r
169 final String filteredLineComment = replaceString(lineComment, bindCharacter, "Q");
\r
170 sb.append(line.substring(0, lineCommentIndex)).append(filteredLineComment).append(lineSeparator);
\r
172 return sb.toString();
\r
176 * Read outside-sql path. Required attribute is 'outsideSqlPath'.
\r
177 * @param sqlFileEncoding The encoding of SQL file. (NotNull)
\r
178 * @param dbmsSuffix The suffix of DBMS. (NotNull)
\r
179 * @return The text of SQL. (NotNull)
\r
180 * @exception jp.sourceforge.ea2ddl.dao.allcommon.exception.OutsideSqlNotFoundException When the SQL is not found.
\r
182 public String readOutsideSql(String sqlFileEncoding, String dbmsSuffix) {
\r
183 final String standardPath = _outsideSqlPath;
\r
184 final String dbmsPath = buildDbmsPath(standardPath, dbmsSuffix);
\r
186 if (isExistResource(dbmsPath)) {
\r
187 sql = readText(dbmsPath, sqlFileEncoding);
\r
188 } else if (isExistResource(standardPath)) {
\r
189 sql = readText(standardPath, sqlFileEncoding);
\r
191 throwOutsideSqlNotFoundException(standardPath);
\r
192 return null; // Non Reachable.
\r
194 return removeInitialUnicodeBomIfNeeds(sqlFileEncoding, sql);
\r
197 protected String buildDbmsPath(String standardPath, String dbmsSuffix) {
\r
198 final String dbmsPath;
\r
199 final int lastIndexOfDot = standardPath.lastIndexOf(".");
\r
200 if (lastIndexOfDot >= 0 && !standardPath.substring(lastIndexOfDot).contains("/")) {
\r
201 final String base = standardPath.substring(0, lastIndexOfDot);
\r
202 dbmsPath = base + dbmsSuffix + standardPath.substring(lastIndexOfDot);
\r
204 dbmsPath = standardPath + dbmsSuffix;
\r
209 protected String removeInitialUnicodeBomIfNeeds(String sqlFileEncoding, String sql) {
\r
210 if ("UTF-8".equalsIgnoreCase(sqlFileEncoding) && sql.length() > 0 && sql.charAt(0) == '\uFEFF') {
\r
211 sql = sql.substring(1);
\r
216 // ===================================================================================
\r
217 // Behavior Query Path
\r
218 // ===================
\r
219 public void setupBehaviorQueryPathIfNeeds() {
\r
220 if (!isBehaviorQueryPathEnabled()) {
\r
223 if (_outsideSqlPath.contains(":")) {
\r
224 final String subDirectoryValue = _outsideSqlPath.substring(0, _outsideSqlPath.lastIndexOf(":"));
\r
225 final String subDirectoryPath = replaceString(subDirectoryValue, ":", "/");
\r
226 final String behaviorQueryPath = _outsideSqlPath.substring(_outsideSqlPath.lastIndexOf(":") + ":".length());
\r
227 final String behaviorClassPath = replaceString(buildBehaviorSqlPackageName(), ".", "/");
\r
228 final String behaviorPackagePath = behaviorClassPath.substring(0, behaviorClassPath.lastIndexOf("/"));
\r
229 final String behaviorClassName = behaviorClassPath.substring(behaviorClassPath.lastIndexOf("/") + "/".length());
\r
230 _outsideSqlPath = behaviorPackagePath + "/" + subDirectoryPath + "/" + behaviorClassName + "_" + behaviorQueryPath + ".sql";
\r
232 _outsideSqlPath = replaceString(buildBehaviorSqlPackageName(), ".", "/") + "_" + _outsideSqlPath + ".sql";
\r
236 protected String buildBehaviorSqlPackageName() {
\r
237 final DBMeta dbmeta = DBMetaInstanceHandler.findDBMeta(_tableDbName);
\r
238 final String behaviorTypeName = dbmeta.getBehaviorTypeName();
\r
239 final String outsideSqlPackage = DBFluteConfig.getInstance().getOutsideSqlPackage();
\r
240 if (outsideSqlPackage != null && outsideSqlPackage.trim().length() > 0) {
\r
241 final String behaviorClassName = behaviorTypeName.substring(behaviorTypeName.lastIndexOf(".") + ".".length());
\r
242 String tmp = behaviorTypeName.substring(0, behaviorTypeName.lastIndexOf("."));
\r
243 final String exbhvName = tmp.contains(".") ? tmp.substring(tmp.lastIndexOf(".") + ".".length()) : tmp;
\r
244 return outsideSqlPackage + "." + exbhvName + "." + behaviorClassName;
\r
246 return behaviorTypeName;
\r
250 protected boolean isBehaviorQueryPathEnabled() {
\r
251 if (isProcedure()) {// [DBFlute-0.7.5]
\r
254 return _outsideSqlPath != null && !_outsideSqlPath.contains("/") && !_outsideSqlPath.contains(".") && _tableDbName != null;
\r
257 // ===================================================================================
\r
260 public boolean isSpecifiedOutsideSql() {
\r
261 return _outsideSqlPath != null;
\r
265 public boolean isProcedure() {
\r
266 return _methodName != null && _methodName.startsWith("call");
\r
269 // ===================================================================================
\r
272 protected boolean isExistResource(String path) {
\r
273 return ResourceUtil.isExist(path);
\r
276 protected String readText(final String path, String sqlFileEncoding) {
\r
277 final java.io.InputStream is = ResourceUtil.getResourceAsStream(path);
\r
278 final java.io.Reader reader = InputStreamReaderUtil.create(is, sqlFileEncoding);
\r
279 return ReaderUtil.readText(reader);
\r
282 protected static String replaceString(String text, String fromText, String toText) {
\r
283 return SimpleStringUtil.replace(text, fromText, toText);
\r
286 protected static String getLineSeparator() {
\r
287 return SimpleSystemUtil.getLineSeparator();
\r
290 // ===================================================================================
\r
293 // -----------------------------------------------------
\r
294 // Common of OutsideSql
\r
295 // --------------------
\r
296 public boolean isDynamicBinding() {
\r
297 return _dynamicBinding;
\r
300 public void setDynamicBinding(boolean dynamicBinding) {
\r
301 this._dynamicBinding = dynamicBinding;
\r
304 public boolean isOffsetByCursorForcedly() {
\r
305 return _offsetByCursorForcedly;
\r
308 public void setOffsetByCursorForcedly(boolean offsetByCursorForcedly) {
\r
309 this._offsetByCursorForcedly = offsetByCursorForcedly;
\r
312 public boolean isLimitByCursorForcedly() {
\r
313 return _limitByCursorForcedly;
\r
316 public void setLimitByCursorForcedly(boolean limitByCursorForcedly) {
\r
317 this._limitByCursorForcedly = limitByCursorForcedly;
\r
320 // -----------------------------------------------------
\r
321 // Specified OutsideSql
\r
322 // --------------------
\r
323 public String getOutsideSqlPath() {
\r
324 return _outsideSqlPath;
\r
327 public void setOutsideSqlPath(String outsideSqlPath) {
\r
328 this._outsideSqlPath = outsideSqlPath;
\r
331 public Object getParameterBean() {
\r
332 return _parameterBean;
\r
335 public void setParameterBean(Object parameterBean) {
\r
336 this._parameterBean = parameterBean;
\r
339 public Object getResultTypeSpecification() {
\r
340 return _resultTypeSpecification;
\r
343 public void setResultTypeSpecification(Object resultTypeSpecification) {
\r
344 this._resultTypeSpecification = resultTypeSpecification;
\r
347 public String getMethodName() {
\r
348 return _methodName;
\r
351 public void setMethodName(String methodName) {
\r
352 this._methodName = methodName;
\r
355 public StatementConfig getStatementConfig() {
\r
356 return _statementConfig;
\r
359 public void setStatementConfig(StatementConfig statementConfig) {
\r
360 this._statementConfig = statementConfig;
\r
363 public String getTableDbName() {
\r
364 return _tableDbName;
\r
367 public void setTableDbName(String tableDbName) {
\r
368 this._tableDbName = tableDbName;
\r