· 6 years ago · Jul 11, 2019, 08:36 AM
1package com.glide.db.impex;
2
3import java.util.ArrayList;
4import java.util.HashMap;
5import java.util.Iterator;
6
7import org.w3c.dom.Element;
8
9import com.glide.collections.StringMap;
10import com.glide.db.CoreSystemTableChecker;
11import com.glide.db.DBUtil;
12import com.glide.db.conventions.DBColumnNamer;
13import com.glide.script.GlideElement;
14import com.glide.script.GlideRecord;
15import com.glide.script.api.GlideScriptable;
16import com.glide.sys.GlideSession;
17import com.glide.system_import_set.IImportSetConstants;
18import com.glide.ui.SysList;
19import com.glide.ui.SysMessage;
20import com.glide.update.UpdateException;
21import com.glide.update.UpdateManager2Factory;
22import com.glide.update.UpdateSaverFactory;
23import com.glide.util.Log;
24import com.glide.util.StringUtil;
25import com.glide.util.XMLDocument;
26
27/**
28 * Create a new table from the data and column headers in the import data.
29 * An XML document is created in the form expected by the Bootstrap process
30 *
31 */
32@GlideScriptable(name="GlideTableCreator")
33public class TableCreator implements IImportSetConstants {
34 public static final String DATABASE = "database";
35 private static final int DEFAULT_LIST_SIZE = 25;
36
37 protected String fTableName;
38 protected String fExtends;
39 private boolean fImplements;
40 private String fTableLabel;
41 private HashMap fColumnAttrs;
42 private ArrayList fInputAttributes;
43 private StringMap fUniqueColumnNames = new StringMap();
44 private String fScope;
45
46 @GlideScriptable
47 public TableCreator() {}
48
49 @GlideScriptable
50 public TableCreator(String tableName, String tableLabel) {
51 this(tableName, tableLabel, GlideSession.get().getCurrentApplicationId());
52 }
53
54 public TableCreator(String tableName, String tableLabel, String scope) {
55 fTableName = tableName;
56 fTableLabel = tableLabel;
57 fScope = scope;
58 }
59
60 @GlideScriptable
61 public boolean update() {
62 if (CoreSystemTableChecker.contains(fExtends)) {
63 Log.error("Cannot extend core system table " + fExtends + " aborting table update for " + fTableName);
64 return false;
65 }
66
67 XMLDocument db = createDocument();
68
69 UpdateManager2Factory.getManager().loadXML(db.toString()); // load the update like an upgrade
70 // tell the update manager to save the changes
71 return createTable(db);
72 }
73
74 public boolean create() {
75 if (CoreSystemTableChecker.contains(fExtends)) {
76 Log.error("Cannot extend core system table " + fExtends + " aborting table create for " + fTableName);
77 return false;
78 }
79
80 XMLDocument db = createDocument();
81
82 Bootstrap b = new Bootstrap(db.getDocument());
83 if (!b.bootstrap())
84 return false;
85
86 // tell the update manager to save the changes
87 return createTable(db);
88 }
89
90 private boolean createTable(XMLDocument db) {
91 try {
92 UpdateManager2Factory.getManager().createTable(fTableName, db.getDocument()); // overwrites existing dictionary update xml if necessary
93 } catch (UpdateException e) {
94 Log.error("Cannot create table from XML", e);
95 GlideSession.get().addInfoMessage(e.getMessage());
96 return false; // do not continue to create SysList
97 }
98
99 return true;
100 }
101
102 private XMLDocument createDocument() {
103 XMLDocument db = new XMLDocument(DATABASE);
104 createTableElement(db);
105 Iterator it = fColumnAttrs.keySet().iterator();
106 while (it.hasNext()) {
107 String columnName = (String)it.next();
108 createFieldElement(db, (ColumnAttributes)fColumnAttrs.get(columnName));
109 }
110 return db;
111 }
112
113 /**
114 * Create a sys_list for the table that contains the columns in the
115 * same order as the spreadsheet
116 *
117 */
118 protected void createImportSetRowSysList() {
119 ArrayList atts = fInputAttributes;
120 ArrayList fields = new ArrayList();
121
122 // special case
123 if (SYS_IMPORT_SET_ROW.equals(fExtends)) {
124 fields.add(SYS_IMPORT_ROW);
125 fields.add(SYS_IMPORT_SET);
126 fields.add(SYS_IMPORT_STATE);
127 }
128
129 createSysList(atts, fields);
130
131 // special case, add these in the end
132 if (SYS_IMPORT_SET_ROW.equals(fExtends)) {
133 fields.add(SYS_TARGET_TABLE);
134 fields.add(SYS_TARGET_SYS_ID);
135 fields.add(SYS_ROW_ERROR);
136 }
137
138 SysList l = new SysList(fTableName);
139 l.InsertListElements(fields);
140 }
141
142 public void createSysList() {
143 ArrayList fields = new ArrayList();
144 createSysList(fInputAttributes, fields);
145 SysList l = new SysList(fTableName);
146 l.InsertListElements(fields);
147 }
148
149 private void createSysList(ArrayList atts, ArrayList fields) {
150 if (atts == null)
151 return;
152
153 for (int i = 0; i < atts.size(); i++) {
154 ColumnAttributes ca = (ColumnAttributes) fColumnAttrs.get(atts.get(i));
155 if (shouldAddAttribute(ca, i))
156 addAttribute(fields, ca);
157 if (reachedMaxAttributes(i))
158 break;
159 }
160 }
161
162 void addAttribute(ArrayList fields, ColumnAttributes ca) {
163 fields.add(ca.getDBName());
164 }
165
166 boolean reachedMaxAttributes(int i) {
167 if (i == DEFAULT_LIST_SIZE-1)
168 return true;
169 return false;
170 }
171
172 boolean shouldAddAttribute(ColumnAttributes ca, int attributeNum) {
173 if (ca == null)
174 return false;
175 return true;
176 }
177
178 /**
179 * Create the table entry in the Document
180 *
181 * @param db
182 */
183 private void createTableElement(XMLDocument db) {
184 Element e = db.createElement(ELEMENT);
185 e.setAttribute(NAME, fTableName);
186 e.setAttribute(LABEL, fTableLabel);
187 e.setAttribute(TYPE, COLLECTION);
188
189 e.setAttribute(SYS_SCOPE, fScope);
190 e.setAttribute(SYS_PACKAGE, fScope);
191
192 if (!StringUtil.nil(fExtends)) {
193 if (fImplements)
194 e.setAttribute(IMPLEMENTS, fExtends);
195 else
196 e.setAttribute(EXTENDS, fExtends);
197 }
198
199 db.setCurrent(e);
200 }
201
202 /**
203 * Create an entry in the document for a column
204 *
205 * @param db
206 * @param ci
207 */
208 private void createFieldElement(XMLDocument db, ColumnAttributes ci) {
209 Element e = db.createElement(ELEMENT);
210 db.setCurrent(e);
211 String name = ci.getDBName();
212
213 // if column name already exists, give it a numeric suffix
214 name = getUniqueDBName(name, ci.getName());
215
216 db.setAttribute(NAME, name);
217
218 String label = ci.getLabel();
219 if (StringUtil.nil(label))
220 label = ci.getName();
221
222 db.setAttribute(LABEL, label);
223
224 setLength(db, ci);
225
226 if (!StringUtil.nil(ci.getReferenceTable()))
227 db.setAttribute(REFERENCE, ci.getReferenceTable());
228
229 String type = ci.getType();
230 db.setAttribute(TYPE, type);
231 db.setAttribute(ATTRIBUTES, IMPORT_ATTRIBUTE_NAME + "=" + ci.getName());
232 db.pop();
233 }
234
235 protected void setLength(XMLDocument db, ColumnAttributes ci) {
236 if (!StringUtil.nil(ci.getLength()))
237 db.setAttribute(MAX_LENGTH, ci.getLength());
238 }
239
240 private String getUniqueDBName(String dbName, String sourceName) {
241 if (!fUniqueColumnNames.containsKey(dbName)) {
242 fUniqueColumnNames.put(dbName, sourceName);
243 return dbName;
244 }
245 DBColumnNamer dbNamer = new DBColumnNamer();
246 dbName = dbNamer.getNextUniqueDBName(fUniqueColumnNames, dbName);
247 fUniqueColumnNames.put(dbName, sourceName);
248 return dbName;
249 }
250
251 public void increaseFieldSize(GlideRecord targetGR, String fieldName, int length) {
252 GlideElement targetGlideElement = targetGR.getElement(fieldName);
253 String table = targetGlideElement.getTableName();
254 GlideRecord dictionaryGR = new GlideRecord(SYS_DICTIONARY);
255 dictionaryGR.addQuery(NAME, table);
256 dictionaryGR.addQuery(ELEMENT, fieldName);
257 dictionaryGR.query();
258 if (!dictionaryGR.next())
259 return;
260
261 increaseTargetFieldSize(fieldName, length, targetGR,
262 dictionaryGR);
263 }
264
265 /*
266 * 1. update the dictionary record without running business rules or engines
267 * 2. effect the size change on the DB layer
268 * 3. manually save out the update XML
269 */
270 private void increaseTargetFieldSize(String fieldName, int length,
271 GlideRecord targetGR, GlideRecord dictionaryGR) {
272 int currentLength = dictionaryGR.getIntValue(MAX_LENGTH);
273 dictionaryGR.setValue(MAX_LENGTH, length);
274 dictionaryGR.setWorkflow(false);
275 // update the dictionary record with new length
276 // do not run the "Dictionary change length" business rule, we will do it ourselves
277 // running the business rule will incur a global cache flush
278 dictionaryGR.update();
279
280 // affect the field change
281 DBUtil.fieldChanged(targetGR.getTableName(), fieldName, currentLength);
282 try {
283 UpdateSaverFactory.getSaver(dictionaryGR).save();
284 } catch (UpdateException e) {
285 Log.warn(SysMessage.format("Failed to save update for field size increase of {0} to {1}", fieldName, String.valueOf(length)));
286 }
287 }
288
289 @GlideScriptable
290 public void setExtends(String extendsTableName) {
291 fExtends = extendsTableName;
292 }
293
294 public void setImplements(boolean b) {
295 fImplements = b;
296 }
297
298 // TODO: what's the difference between input attributes and column attributes ?
299 public void setInputAttributes(ArrayList attributes) {
300 fInputAttributes = attributes;
301 }
302
303 @GlideScriptable
304 public void setColumnAttributes(HashMap columnAttributes) {
305 fColumnAttrs = columnAttributes;
306 }
307
308 public void setLabel(String tableLabel) {
309 fTableLabel = tableLabel;
310 }
311
312 public HashMap getUniqueColumnNames() {
313 return fUniqueColumnNames;
314 }
315
316 @GlideScriptable
317 public void setOverrideUpdate(boolean b) {
318 }
319}