|
13 | 13 | * See the License for the specific language governing permissions and |
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | | -package org.utplsql.sqldev.oddgen |
17 | | - |
18 | | -import java.sql.Connection |
19 | | -import java.util.ArrayList |
20 | | -import java.util.HashMap |
21 | | -import java.util.HashSet |
22 | | -import java.util.LinkedHashMap |
23 | | -import java.util.List |
24 | | -import oracle.ide.config.Preferences |
25 | | -import org.oddgen.sqldev.generators.OddgenGenerator2 |
26 | | -import org.oddgen.sqldev.generators.model.Node |
27 | | -import org.utplsql.sqldev.dal.UtplsqlDao |
28 | | -import org.utplsql.sqldev.model.preference.PreferenceModel |
29 | | -import org.utplsql.sqldev.resources.UtplsqlResources |
30 | | - |
31 | | -class RunGenerator implements OddgenGenerator2 { |
32 | | - |
33 | | - public static val YES = "Yes" |
34 | | - public static val NO = "No" |
35 | | - |
36 | | - public static var RESET_PACKAGE = UtplsqlResources.getString("PREF_RESET_PACKAGE_LABEL") |
37 | | - public static var CLEAR_SCREEN = UtplsqlResources.getString("PREF_CLEAR_SCREEN_LABEL") |
38 | | - public static var INDENT_SPACES = UtplsqlResources.getString("PREF_INDENT_SPACES_LABEL") |
39 | | - |
40 | | - // oddgen node cache |
41 | | - var List<Node> runnables = null; |
42 | | - |
43 | | - override isSupported(Connection conn) { |
44 | | - var ret = false |
45 | | - if (conn !== null) { |
46 | | - if (conn.metaData.databaseProductName.startsWith("Oracle")) { |
47 | | - if (conn.metaData.databaseMajorVersion == 11) { |
48 | | - if (conn.metaData.databaseMinorVersion >= 2) { |
49 | | - ret = true |
50 | | - } |
51 | | - } else if (conn.metaData.databaseMajorVersion > 11) { |
52 | | - ret = true |
53 | | - } |
54 | | - } |
55 | | - } |
56 | | - return ret |
57 | | - } |
58 | | - |
59 | | - override getName(Connection conn) { |
60 | | - return "Run test" |
61 | | - } |
62 | | - |
63 | | - override getDescription(Connection conn) { |
64 | | - return "Runs utPLSQL test packages in the current user." |
65 | | - } |
66 | | - |
67 | | - override getFolders(Connection conn) { |
68 | | - val preferences = PreferenceModel.getInstance(Preferences.preferences) |
69 | | - val folders = new ArrayList<String> |
70 | | - for (f : preferences.rootFolderInOddgenView.split(",").filter[!it.empty]) { |
71 | | - folders.add(f.trim) |
72 | | - } |
73 | | - return folders |
74 | | - } |
75 | | - |
76 | | - override getHelp(Connection conn) { |
77 | | - return "<p>not yet available</p>" |
78 | | - } |
79 | | - |
80 | | - override getNodes(Connection conn, String parentNodeId) { |
81 | | - // oddgen asks for children for each parent node, regardless of load strategy (eager/lazy) |
82 | | - // oddgen does not know about the load strategy, hence caching is the responsibility of the generator |
83 | | - if (runnables === null) { |
84 | | - val preferences = PreferenceModel.getInstance(Preferences.preferences) |
85 | | - val params = new LinkedHashMap<String, String>() |
86 | | - params.put(RESET_PACKAGE, if (preferences.resetPackage) {YES} else {NO}) |
87 | | - params.put(CLEAR_SCREEN, if (preferences.clearScreen) {YES} else {NO}) |
88 | | - params.put(INDENT_SPACES, String.valueOf(preferences.indentSpaces)) |
89 | | - val UtplsqlDao dao = new UtplsqlDao(conn) |
90 | | - // load node tree eagerly (all nodes in one go) |
91 | | - runnables = dao.runnables |
92 | | - for (node : runnables) { |
93 | | - node.params = params |
94 | | - } |
95 | | - } |
96 | | - return runnables |
97 | | - } |
98 | | - |
99 | | - override getLov(Connection conn, LinkedHashMap<String, String> params, List<Node> nodes) { |
100 | | - val lov = new HashMap<String, List<String>>() |
101 | | - lov.put(RESET_PACKAGE, #[YES, NO]) |
102 | | - lov.put(CLEAR_SCREEN, #[YES, NO]) |
103 | | - lov.put(INDENT_SPACES, #["1", "2", "3", "4", "5", "6", "7", "8"]) |
104 | | - return lov |
105 | | - } |
106 | | - |
107 | | - override getParamStates(Connection conn, LinkedHashMap<String, String> params, List<Node> nodes) { |
108 | | - return new HashMap<String, Boolean> |
109 | | - } |
110 | | - |
111 | | - private def getPath(Node node, Connection conn) { |
112 | | - if (node.id == "SUITE" || node.id == "SUITEPATH") { |
113 | | - return conn.metaData.userName |
114 | | - } else { |
115 | | - return node.id |
116 | | - } |
117 | | - } |
118 | | - |
119 | | - private def replaceTabsWithSpaces(CharSequence input, int indentSpaces) { |
120 | | - val spaces = String.format("%1$"+indentSpaces+"s", "") |
121 | | - return input.toString.replace("\t", spaces) |
122 | | - } |
123 | | - |
124 | | - def dedup(List<Node> nodes) { |
125 | | - val set = new HashSet<String> |
126 | | - for (node : nodes) { |
127 | | - set.add(node.id) |
128 | | - } |
129 | | - val ret = new ArrayList<Node> |
130 | | - for (node : nodes) { |
131 | | - if (!set.contains(node.parentId)) { |
132 | | - ret.add(node) |
133 | | - } |
134 | | - } |
135 | | - return ret |
136 | | - } |
137 | | - |
138 | | - override generateProlog(Connection conn, List<Node> nodes) { |
139 | | - val dedupNodes = nodes.dedup |
140 | | - val params = dedupNodes.get(0).params |
141 | | - val ret = ''' |
142 | | - «IF params.get(RESET_PACKAGE) == YES» |
143 | | - EXECUTE dbms_session.reset_package; |
144 | | - «ENDIF» |
145 | | - SET SERVEROUTPUT ON SIZE UNLIMITED |
146 | | - «IF params.get(CLEAR_SCREEN) == YES» |
147 | | - CLEAR SCREEN |
148 | | - «ENDIF» |
149 | | - «IF dedupNodes.size == 1» |
150 | | - EXECUTE ut.run('«dedupNodes.get(0).getPath(conn)»'); |
151 | | - «ELSE» |
152 | | - BEGIN |
153 | | - ut.run( |
154 | | - ut_varchar2_list( |
155 | | - «FOR node : dedupNodes SEPARATOR ","» |
156 | | - '«node.getPath(conn)»' |
157 | | - «ENDFOR» |
158 | | - ) |
159 | | - ); |
160 | | - END; |
161 | | - / |
162 | | - «ENDIF» |
163 | | - ''' |
164 | | - return ret.replaceTabsWithSpaces(Integer.valueOf(params.get(INDENT_SPACES))) |
165 | | - } |
166 | | - |
167 | | - override generateSeparator(Connection conn) { |
168 | | - return "" |
169 | | - } |
170 | | - |
171 | | - override generateEpilog(Connection conn, List<Node> nodes) { |
172 | | - return "" |
173 | | - } |
174 | | - |
175 | | - override generate(Connection conn, Node node) { |
176 | | - return "" |
177 | | - } |
178 | | - |
| 16 | +package org.utplsql.sqldev.oddgen; |
| 17 | + |
| 18 | +import java.sql.Connection; |
| 19 | +import java.sql.SQLException; |
| 20 | +import java.util.ArrayList; |
| 21 | +import java.util.Arrays; |
| 22 | +import java.util.HashMap; |
| 23 | +import java.util.HashSet; |
| 24 | +import java.util.LinkedHashMap; |
| 25 | +import java.util.List; |
| 26 | +import java.util.logging.Logger; |
| 27 | +import java.util.stream.Collectors; |
| 28 | + |
| 29 | +import org.oddgen.sqldev.generators.OddgenGenerator2; |
| 30 | +import org.oddgen.sqldev.generators.model.Node; |
| 31 | +import org.utplsql.sqldev.dal.UtplsqlDao; |
| 32 | +import org.utplsql.sqldev.exception.GenericDatabaseAccessException; |
| 33 | +import org.utplsql.sqldev.model.StringTools; |
| 34 | +import org.utplsql.sqldev.model.preference.PreferenceModel; |
| 35 | +import org.utplsql.sqldev.resources.UtplsqlResources; |
| 36 | + |
| 37 | +import oracle.ide.config.Preferences; |
| 38 | + |
| 39 | +public class RunGenerator implements OddgenGenerator2 { |
| 40 | + private static final Logger logger = Logger.getLogger(RunGenerator.class.getName()); |
| 41 | + |
| 42 | + public static final String YES = "Yes"; |
| 43 | + public static final String NO = "No"; |
| 44 | + public static final String RESET_PACKAGE = UtplsqlResources.getString("PREF_RESET_PACKAGE_LABEL"); |
| 45 | + public static final String CLEAR_SCREEN = UtplsqlResources.getString("PREF_CLEAR_SCREEN_LABEL"); |
| 46 | + public static final String INDENT_SPACES = UtplsqlResources.getString("PREF_INDENT_SPACES_LABEL"); |
| 47 | + |
| 48 | + // oddgen node cache |
| 49 | + private List<Node> runnables = null; |
| 50 | + |
| 51 | + @Override |
| 52 | + public boolean isSupported(final Connection conn) { |
| 53 | + try { |
| 54 | + boolean ret = false; |
| 55 | + if (conn != null && conn.getMetaData().getDatabaseProductName().startsWith("Oracle") |
| 56 | + && (conn.getMetaData().getDatabaseMajorVersion() == 11 |
| 57 | + && conn.getMetaData().getDatabaseMinorVersion() >= 2 |
| 58 | + || conn.getMetaData().getDatabaseMajorVersion() > 11)) { |
| 59 | + ret = true; |
| 60 | + } |
| 61 | + return ret; |
| 62 | + } catch (SQLException e) { |
| 63 | + final String msg = "SQLException during connection check due to " + e.getMessage(); |
| 64 | + logger.severe(() -> msg); |
| 65 | + throw new GenericDatabaseAccessException(msg, e); |
| 66 | + } |
| 67 | + } |
| 68 | + |
| 69 | + @Override |
| 70 | + public String getName(final Connection conn) { |
| 71 | + return "Run test"; |
| 72 | + } |
| 73 | + |
| 74 | + @Override |
| 75 | + public String getDescription(final Connection conn) { |
| 76 | + return "Runs utPLSQL test packages in the current user."; |
| 77 | + } |
| 78 | + |
| 79 | + @Override |
| 80 | + public List<String> getFolders(final Connection conn) { |
| 81 | + final PreferenceModel preferences = PreferenceModel.getInstance(Preferences.getPreferences()); |
| 82 | + final ArrayList<String> folders = new ArrayList<>(); |
| 83 | + for (String f : preferences.getRootFolderInOddgenView().split(",")) { |
| 84 | + if (f != null) { |
| 85 | + folders.add(f.trim()); |
| 86 | + } |
| 87 | + } |
| 88 | + return folders; |
| 89 | + } |
| 90 | + |
| 91 | + @Override |
| 92 | + public String getHelp(final Connection conn) { |
| 93 | + return "<p>not yet available</p>"; |
| 94 | + } |
| 95 | + |
| 96 | + @Override |
| 97 | + public List<Node> getNodes(final Connection conn, final String parentNodeId) { |
| 98 | + // oddgen asks for children for each parent node, regardless of load strategy (eager/lazy) |
| 99 | + // oddgen does not know about the load strategy, hence caching is the responsibility of the generator |
| 100 | + if (runnables == null) { |
| 101 | + final PreferenceModel preferences = PreferenceModel.getInstance(Preferences.getPreferences()); |
| 102 | + final LinkedHashMap<String, String> params = new LinkedHashMap<>(); |
| 103 | + params.put(RESET_PACKAGE, preferences.isResetPackage() ? "YES" : "NO"); |
| 104 | + params.put(CLEAR_SCREEN, preferences.isClearScreen() ? "YES" : "NO"); |
| 105 | + params.put(INDENT_SPACES, String.valueOf(preferences.getIndentSpaces())); |
| 106 | + final UtplsqlDao dao = new UtplsqlDao(conn); |
| 107 | + // load node tree eagerly (all nodes in one go) |
| 108 | + runnables = dao.runnables(); |
| 109 | + for (final Node node : runnables) { |
| 110 | + node.setParams(params); |
| 111 | + } |
| 112 | + } |
| 113 | + return runnables; |
| 114 | + } |
| 115 | + |
| 116 | + @Override |
| 117 | + public HashMap<String, List<String>> getLov(final Connection conn, final LinkedHashMap<String, String> params, final List<Node> nodes) { |
| 118 | + final HashMap<String, List<String>> lov = new HashMap<>(); |
| 119 | + lov.put(RESET_PACKAGE, Arrays.asList(YES, NO)); |
| 120 | + lov.put(CLEAR_SCREEN, Arrays.asList(YES, NO)); |
| 121 | + lov.put(INDENT_SPACES, Arrays.asList("1", "2", "3", "4", "5", "6", "7", "8")); |
| 122 | + return lov; |
| 123 | + } |
| 124 | + |
| 125 | + @Override |
| 126 | + public HashMap<String, Boolean> getParamStates(final Connection conn, final LinkedHashMap<String, String> params, final List<Node> nodes) { |
| 127 | + return new HashMap<>(); |
| 128 | + } |
| 129 | + |
| 130 | + private String getPath(final Node node, final Connection conn) { |
| 131 | + if ("SUITE".equals(node.getId()) || "SUITEPATH".equals(node.getId())) { |
| 132 | + try { |
| 133 | + return conn.getMetaData().getUserName(); |
| 134 | + } catch (SQLException e) { |
| 135 | + final String msg = "SQLException during getUserName() due to " + e.getMessage(); |
| 136 | + logger.severe(() -> msg); |
| 137 | + throw new GenericDatabaseAccessException(msg, e); |
| 138 | + } |
| 139 | + } else { |
| 140 | + return node.getId(); |
| 141 | + } |
| 142 | + } |
| 143 | + |
| 144 | + private String replaceTabsWithSpaces(final CharSequence input, final int indentSpaces) { |
| 145 | + final String spaces = String.format((("%1$" + Integer.valueOf(indentSpaces)) + "s"), ""); |
| 146 | + return input.toString().replace("\t", spaces); |
| 147 | + } |
| 148 | + |
| 149 | + public ArrayList<Node> dedup(final List<Node> nodes) { |
| 150 | + final HashSet<String> set = new HashSet<>(); |
| 151 | + for (final Node node : nodes) { |
| 152 | + set.add(node.getId()); |
| 153 | + } |
| 154 | + final ArrayList<Node> ret = new ArrayList<>(); |
| 155 | + for (final Node node : nodes) { |
| 156 | + if (!set.contains(node.getParentId())) { |
| 157 | + ret.add(node); |
| 158 | + } |
| 159 | + } |
| 160 | + return ret; |
| 161 | + } |
| 162 | + |
| 163 | + @Override |
| 164 | + public String generateProlog(final Connection conn, final List<Node> nodes) { |
| 165 | + final ArrayList<Node> dedupNodes = dedup(nodes); |
| 166 | + final LinkedHashMap<String, String> params = dedupNodes.get(0).getParams(); |
| 167 | + final StringBuilder sb = new StringBuilder(); |
| 168 | + if ("YES".equals(params.get(RESET_PACKAGE))) { |
| 169 | + sb.append("EXECUTE dbms_session.reset_package;\n"); |
| 170 | + } |
| 171 | + sb.append("SET SERVEROUTPUT ON SIZE UNLIMITED\n"); |
| 172 | + if ("YES".equals(params.get(CLEAR_SCREEN))) { |
| 173 | + sb.append("CLEAR SCREEN\n"); |
| 174 | + } |
| 175 | + if (dedupNodes.size() == 1) { |
| 176 | + sb.append("EXECUTE ut.run('"); |
| 177 | + sb.append(getPath(dedupNodes.get(0), conn)); |
| 178 | + sb.append("');\n"); |
| 179 | + } else { |
| 180 | + final List<String> paths = nodes.stream().map(node -> getPath(node, conn)).collect(Collectors.toList()); |
| 181 | + sb.append("BEGIN\n"); |
| 182 | + sb.append("\tut.run(\n"); |
| 183 | + sb.append("\t\tut_varchar2_list(\n"); |
| 184 | + sb.append(StringTools.getCSV(paths, "\t\t\t")); |
| 185 | + sb.append("\t\t)\n"); |
| 186 | + sb.append("\t);\n"); |
| 187 | + sb.append("END;\n"); |
| 188 | + sb.append("/\n"); |
| 189 | + } |
| 190 | + final String ret = sb.toString(); |
| 191 | + return replaceTabsWithSpaces(ret, (Integer.valueOf(params.get(INDENT_SPACES)))); |
| 192 | + } |
| 193 | + |
| 194 | + @Override |
| 195 | + public String generateSeparator(final Connection conn) { |
| 196 | + return ""; |
| 197 | + } |
| 198 | + |
| 199 | + @Override |
| 200 | + public String generateEpilog(final Connection conn, final List<Node> nodes) { |
| 201 | + return ""; |
| 202 | + } |
| 203 | + |
| 204 | + @Override |
| 205 | + public String generate(final Connection conn, final Node node) { |
| 206 | + return ""; |
| 207 | + } |
179 | 208 | } |
0 commit comments