PageRenderTime 41ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/etlunit-core/src/main/java/org/bitbucket/bradleysmithllc/etlunit/io/file/SchemaColumn.java

https://bitbucket.org/bradleysmithllc/etl-unit
Java | 698 lines | 570 code | 102 blank | 26 comment | 69 complexity | 2720786e53a2e3eea24deb2ef44ff711 MD5 | raw file
  1. package org.bitbucket.bradleysmithllc.etlunit.io.file;
  2. /*
  3. * #%L
  4. * etlunit-core
  5. * %%
  6. * Copyright (C) 2010 - 2014 bradleysmithllc
  7. * %%
  8. * Licensed under the Apache License, Version 2.0 (the "License");
  9. * you may not use this file except in compliance with the License.
  10. * You may obtain a copy of the License at
  11. *
  12. * http://www.apache.org/licenses/LICENSE-2.0
  13. *
  14. * Unless required by applicable law or agreed to in writing, software
  15. * distributed under the License is distributed on an "AS IS" BASIS,
  16. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17. * See the License for the specific language governing permissions and
  18. * limitations under the License.
  19. * #L%
  20. */
  21. import com.fasterxml.jackson.databind.JsonNode;
  22. import org.bitbucket.bradleysmithllc.etlunit.util.ObjectUtils;
  23. import org.bitbucket.bradleysmithllc.etlunit.util.VelocityUtil;
  24. import java.sql.Types;
  25. import java.util.Map;
  26. import java.util.regex.Pattern;
  27. public class SchemaColumn implements DataFileSchema.Column
  28. {
  29. private final String id;
  30. private String format;
  31. private boolean lenientFormatter = false;
  32. private diff_type diffType = diff_type.none;
  33. private boolean readOnly;
  34. private String type = "VARCHAR";
  35. private String typeAnnotation;
  36. private basic_type basicType = basic_type.string;
  37. private int length;
  38. private int scale;
  39. private int ordinal = Integer.MIN_VALUE;
  40. private int inferredOrdinal;
  41. private int jdbcType = -1000;
  42. private final DataFileManager dataFileManager;
  43. private int offset = -1;
  44. private Object defaultValue;
  45. public static class DefaultSequence
  46. {
  47. private int initialValue = Integer.MAX_VALUE;
  48. private int baseOffset = Integer.MAX_VALUE;
  49. private int increment = Integer.MAX_VALUE;
  50. private int modulus = Integer.MAX_VALUE;
  51. private String expression;
  52. public boolean hasInitialValue()
  53. {
  54. return initialValue != Integer.MAX_VALUE;
  55. }
  56. public boolean hasModulus()
  57. {
  58. return modulus != Integer.MAX_VALUE;
  59. }
  60. public boolean hasBaseOffset()
  61. {
  62. return baseOffset != Integer.MAX_VALUE;
  63. }
  64. public boolean hasIncrement()
  65. {
  66. return increment != Integer.MAX_VALUE;
  67. }
  68. public boolean hasExpression()
  69. {
  70. return expression != null;
  71. }
  72. public void setInitialValue(int initialValue) {
  73. this.initialValue = initialValue;
  74. }
  75. public void setBaseOffset(int baseOffset) {
  76. this.baseOffset = baseOffset;
  77. }
  78. public int getIncrement() {
  79. return increment;
  80. }
  81. public void setIncrement(int increment) {
  82. this.increment = increment;
  83. }
  84. public void setModulus(int modulus) {
  85. this.modulus = modulus;
  86. }
  87. public void setExpression(String expression) {
  88. this.expression = expression;
  89. }
  90. public int getInitialValue() {
  91. return initialValue;
  92. }
  93. public int getBaseOffset() {
  94. return baseOffset;
  95. }
  96. public int getModulus() {
  97. return modulus;
  98. }
  99. public String getExpression() {
  100. return expression;
  101. }
  102. }
  103. private DefaultSequence defaultExpression;
  104. public SchemaColumn(String id, int length, DataFileManager dataFileManager)
  105. {
  106. this(id, null, length, -1, dataFileManager);
  107. }
  108. public SchemaColumn(String id, String type, DataFileManager dataFileManager)
  109. {
  110. this(id, type, -1, -1, dataFileManager);
  111. }
  112. public SchemaColumn(String id, String type, int length, int scale, DataFileManager dataFileManager)
  113. {
  114. this.id = id;
  115. this.type = type;
  116. this.length = length;
  117. this.dataFileManager = dataFileManager;
  118. this.scale = scale;
  119. defaultExpression = null;
  120. }
  121. public SchemaColumn(JsonNode node, DataFileManager dataFileManager)
  122. {
  123. this.dataFileManager = dataFileManager;
  124. id = node.get("id").asText().toLowerCase();
  125. if (node.has("type"))
  126. {
  127. JsonNode type1 = node.get("type");
  128. if (!type1.isNull())
  129. {
  130. type = type1.asText();
  131. }
  132. }
  133. if (node.has("type-annotation"))
  134. {
  135. JsonNode type1 = node.get("type-annotation");
  136. if (!type1.isNull())
  137. {
  138. typeAnnotation = type1.asText();
  139. }
  140. else
  141. {
  142. typeAnnotation = null;
  143. }
  144. }
  145. else
  146. {
  147. typeAnnotation = null;
  148. }
  149. if (node.has("length"))
  150. {
  151. JsonNode length1 = node.get("length");
  152. if (!length1.isNull())
  153. {
  154. length = length1.asInt();
  155. }
  156. else
  157. {
  158. length = -1;
  159. }
  160. }
  161. else
  162. {
  163. length = -1;
  164. }
  165. if (node.has("scale"))
  166. {
  167. JsonNode length1 = node.get("scale");
  168. if (!length1.isNull())
  169. {
  170. scale = length1.asInt();
  171. }
  172. else
  173. {
  174. scale = -1;
  175. }
  176. }
  177. else
  178. {
  179. scale = -1;
  180. }
  181. if (node.has("ordinal"))
  182. {
  183. JsonNode length1 = node.get("ordinal");
  184. if (!length1.isNull())
  185. {
  186. ordinal = length1.asInt();
  187. }
  188. else
  189. {
  190. ordinal = Integer.MIN_VALUE;
  191. }
  192. }
  193. else
  194. {
  195. ordinal = Integer.MIN_VALUE;
  196. }
  197. if (node.has("format"))
  198. {
  199. JsonNode length1 = node.get("format");
  200. if (!length1.isNull())
  201. {
  202. format = length1.asText();
  203. }
  204. else
  205. {
  206. format = null;
  207. }
  208. }
  209. else
  210. {
  211. format = null;
  212. }
  213. if (node.has("lenient-formatter"))
  214. {
  215. JsonNode length1 = node.get("lenient-formatter");
  216. if (!length1.isNull())
  217. {
  218. if (format == null)
  219. {
  220. throw new IllegalArgumentException("Cannot specify lenient-formatter if format is not present");
  221. }
  222. lenientFormatter = length1.asBoolean();
  223. }
  224. }
  225. if (node.has("read-only"))
  226. {
  227. JsonNode length1 = node.get("read-only");
  228. if (!length1.isNull() && length1.isBoolean())
  229. {
  230. readOnly = length1.asBoolean();
  231. }
  232. else
  233. {
  234. readOnly = false;
  235. }
  236. }
  237. else
  238. {
  239. readOnly = false;
  240. }
  241. if (node.has("diff-type")) {
  242. JsonNode length1 = node.get("diff-type");
  243. if (!length1.isNull()) {
  244. diffType = diff_type.valueOf(length1.asText());
  245. if (
  246. ObjectUtils.notIn(jdbcType(), Types.VARCHAR, Types.LONGVARCHAR, Types.NVARCHAR, Types.LONGNVARCHAR)
  247. ) {
  248. throw new IllegalArgumentException("Date diff columns must be a string type. " + getId() + " " + jdbcType);
  249. }
  250. }
  251. }
  252. if (node.has("basic-type"))
  253. {
  254. JsonNode length1 = node.get("basic-type");
  255. if (!length1.isNull())
  256. {
  257. String bt = length1.asText();
  258. if (bt.equals(basic_type.integer.name()))
  259. {
  260. basicType = basic_type.integer;
  261. }
  262. else if (bt.equals(basic_type.string.name()))
  263. {
  264. basicType = basic_type.string;
  265. }
  266. else if (bt.equals(basic_type.numeric.name()))
  267. {
  268. basicType = basic_type.numeric;
  269. }
  270. }
  271. else
  272. {
  273. basicType = basic_type.string;
  274. }
  275. }
  276. else
  277. {
  278. basicType = basic_type.string;
  279. }
  280. if (node.has("default-value"))
  281. {
  282. JsonNode length1 = node.get("default-value");
  283. if (!length1.isNull())
  284. {
  285. if (!length1.isObject())
  286. {
  287. defaultExpression = null;
  288. switch (length1.getNodeType())
  289. {
  290. case STRING:
  291. defaultValue = length1.asText();
  292. break;
  293. case BOOLEAN:
  294. defaultValue = length1.asBoolean();
  295. break;
  296. case NUMBER:
  297. if (length1.isIntegralNumber())
  298. {
  299. defaultValue = length1.asInt();
  300. }
  301. else
  302. {
  303. defaultValue = length1.doubleValue();
  304. }
  305. break;
  306. case MISSING:
  307. case NULL:
  308. case ARRAY:
  309. case BINARY:
  310. case OBJECT:
  311. case POJO:
  312. break;
  313. }
  314. }
  315. else
  316. {
  317. defaultExpression = new DefaultSequence();
  318. if (length1.has("initial-value"))
  319. {
  320. defaultExpression.initialValue = length1.get("initial-value").asInt();
  321. }
  322. if (length1.has("increment"))
  323. {
  324. defaultExpression.increment = length1.get("increment").asInt();
  325. }
  326. if (length1.has("base-offset"))
  327. {
  328. defaultExpression.baseOffset = length1.get("base-offset").asInt();
  329. }
  330. if (length1.has("modulus"))
  331. {
  332. defaultExpression.modulus = length1.get("modulus").asInt();
  333. }
  334. if (length1.has("expression"))
  335. {
  336. defaultExpression.expression = length1.get("expression").asText();
  337. }
  338. }
  339. }
  340. else
  341. {
  342. defaultValue = null;
  343. defaultExpression = null;
  344. }
  345. }
  346. else
  347. {
  348. defaultValue = null;
  349. defaultExpression = null;
  350. }
  351. }
  352. public diff_type diffType() {
  353. return diffType;
  354. }
  355. public void setDiffType(diff_type type) {
  356. diffType = type;
  357. }
  358. public boolean validateText(String text)
  359. {
  360. DataConverter validator = getConverter();
  361. Pattern pattern = validator.getPattern(this);
  362. if (pattern != null)
  363. {
  364. return pattern.matcher(text).matches();
  365. }
  366. else
  367. {
  368. return true;
  369. }
  370. }
  371. public void setOffset(int offset)
  372. {
  373. this.offset = offset;
  374. }
  375. public String getId()
  376. {
  377. return id;
  378. }
  379. @Override
  380. public String getFormat() {
  381. return format;
  382. }
  383. @Override
  384. public void setFormat(String format) {
  385. this.format = format;
  386. }
  387. @Override
  388. public boolean hasTypeAnnotation()
  389. {
  390. return typeAnnotation != null;
  391. }
  392. @Override
  393. public String getTypeAnnotation()
  394. {
  395. return typeAnnotation;
  396. }
  397. public boolean hasType()
  398. {
  399. return type != null;
  400. }
  401. public String getType()
  402. {
  403. return type;
  404. }
  405. public DataConverter getConverter()
  406. {
  407. if (hasType())
  408. {
  409. return dataFileManager.resolveValidatorById(getType());
  410. }
  411. else
  412. {
  413. // default to string
  414. return dataFileManager.resolveValidatorById("VARCHAR");
  415. }
  416. }
  417. @Override
  418. public int jdbcType()
  419. {
  420. if (jdbcType == -1000)
  421. {
  422. jdbcType = JdbcTypeConverter.getTypeValue(type);
  423. }
  424. return jdbcType;
  425. }
  426. @Override
  427. public void setType(String type)
  428. {
  429. this.type = type;
  430. }
  431. @Override
  432. public void setLength(int length)
  433. {
  434. if (this.length != -1)
  435. {
  436. throw new IllegalArgumentException("Cannot change the length of a column");
  437. }
  438. this.length = length;
  439. }
  440. public int getOffset()
  441. {
  442. return offset;
  443. }
  444. public int getLength()
  445. {
  446. return length;
  447. }
  448. @Override
  449. public Object getDefaultValue() {
  450. return defaultValue;
  451. }
  452. @Override
  453. public Object generateColumnValue(Map<String, Object> columnValues, int rowSequence) {
  454. if (defaultExpression != null)
  455. {
  456. int value = rowSequence;
  457. // determine the base sequence value
  458. if (defaultExpression.hasIncrement())
  459. {
  460. columnValues.put("increment", defaultExpression.increment);
  461. value = defaultExpression.increment * rowSequence;
  462. }
  463. // any initial offset
  464. if (defaultExpression.hasInitialValue())
  465. {
  466. columnValues.put("initialValue", defaultExpression.initialValue);
  467. value += defaultExpression.initialValue;
  468. }
  469. // apply the modulo
  470. if (defaultExpression.hasModulus())
  471. {
  472. columnValues.put("modulus", defaultExpression.modulus);
  473. value %= defaultExpression.modulus;
  474. }
  475. // base offset happens last
  476. if (defaultExpression.hasBaseOffset())
  477. {
  478. columnValues.put("baseOffset", defaultExpression.baseOffset);
  479. value += defaultExpression.baseOffset;
  480. }
  481. columnValues.put("defaultValue", value);
  482. // check for an expression
  483. if (defaultExpression.hasExpression())
  484. {
  485. // this is a velocity template - process with the given data set
  486. try {
  487. return VelocityUtil.writeTemplateWithStaticSupport(defaultExpression.expression, columnValues);
  488. } catch (Exception e) {
  489. throw new RuntimeException("Error processing default value expression: " + defaultExpression.expression, e);
  490. }
  491. }
  492. return value;
  493. }
  494. return defaultValue;
  495. }
  496. @Override
  497. public boolean isReadOnly() {
  498. return readOnly;
  499. }
  500. @Override
  501. public int ordinal() {
  502. return ordinal;
  503. }
  504. @Override
  505. public int inferredOrdinal() {
  506. return inferredOrdinal;
  507. }
  508. @Override
  509. public void setInferredOrdinal(int ord) {
  510. inferredOrdinal = ord;
  511. }
  512. @Override
  513. public int actualOrdinal() {
  514. if (ordinal == Integer.MIN_VALUE) {
  515. return inferredOrdinal;
  516. } else {
  517. return ordinal;
  518. }
  519. }
  520. @Override
  521. public DataFileSchema.Column clone() {
  522. try {
  523. return (DataFileSchema.Column) super.clone();
  524. } catch (CloneNotSupportedException e) {
  525. throw new IllegalStateException(e);
  526. }
  527. }
  528. @Override
  529. public int getScale() {
  530. return scale;
  531. }
  532. @Override
  533. public void setScale(int scale) {
  534. if (this.scale != -1)
  535. {
  536. throw new IllegalArgumentException("Cannot change the scale of a column");
  537. }
  538. this.scale = scale;
  539. }
  540. @Override
  541. public void setTypeAnnotation(String typeAnnotation) {
  542. this.typeAnnotation = typeAnnotation;
  543. }
  544. public basic_type getBasicType()
  545. {
  546. return basicType;
  547. }
  548. public void setBasicType(basic_type basicType)
  549. {
  550. if (basicType == null)
  551. {
  552. throw new IllegalArgumentException("Basic type cannot be null");
  553. }
  554. this.basicType = basicType;
  555. }
  556. @Override
  557. public DefaultSequence getDefaultSequence() {
  558. return defaultExpression;
  559. }
  560. @Override
  561. public DefaultSequence populateDefaultSequence()
  562. {
  563. if (defaultExpression == null)
  564. {
  565. defaultExpression = new DefaultSequence();
  566. }
  567. return defaultExpression;
  568. }
  569. public boolean isFormatterLenient() {
  570. return lenientFormatter;
  571. }
  572. @Override
  573. public void setLenientFormatter(boolean lenient)
  574. {
  575. lenientFormatter = lenient;
  576. }
  577. @Override
  578. public String toString() {
  579. return "SchemaColumn{" +
  580. "id='" + id + '\'' +
  581. ", format='" + format + '\'' +
  582. ", lenientFormatter=" + lenientFormatter +
  583. ", readOnly=" + readOnly +
  584. ", type='" + type + '\'' +
  585. ", basicType=" + basicType +
  586. ", length=" + length +
  587. ", scale=" + scale +
  588. ", jdbcType=" + jdbcType +
  589. ", dataFileManager=" + dataFileManager +
  590. ", offset=" + offset +
  591. ", defaultExpression=" + defaultExpression +
  592. ", defaultValue=" + defaultValue +
  593. ", defaultExpression=" + defaultExpression +
  594. '}';
  595. }
  596. }