PageRenderTime 51ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/etlunit-core/src/main/java/org/bitbucket/bradleysmithllc/etlunit/feature/extend/ExtensibleFeatureModule.java

https://bitbucket.org/bradleysmithllc/etl-unit
Java | 383 lines | 298 code | 56 blank | 29 comment | 40 complexity | 9335de3d1672eef20ba3da9d55507b53 MD5 | raw file
  1. package org.bitbucket.bradleysmithllc.etlunit.feature.extend;
  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 com.github.fge.jsonschema.main.JsonSchema;
  23. import org.bitbucket.bradleysmithllc.etlunit.*;
  24. import org.bitbucket.bradleysmithllc.etlunit.context.VariableContext;
  25. import org.bitbucket.bradleysmithllc.etlunit.feature.*;
  26. import org.bitbucket.bradleysmithllc.etlunit.listener.ClassListener;
  27. import org.bitbucket.bradleysmithllc.etlunit.listener.OperationProcessor;
  28. import org.bitbucket.bradleysmithllc.etlunit.parser.*;
  29. import java.util.*;
  30. @FeatureModule
  31. public abstract class ExtensibleFeatureModule extends AbstractFeature
  32. {
  33. private final List<Extender>
  34. extenders =
  35. new ArrayList<Extender>();
  36. @Override
  37. public final ClassListener getListener()
  38. {
  39. return new ClassListener()
  40. {
  41. private final ClassListener classListener = getDelegateListener();
  42. @Override
  43. public void beginTests(VariableContext context, int executorId) throws TestExecutionError {
  44. if (classListener != null)
  45. {
  46. classListener.beginTests(context, executorId);
  47. }
  48. }
  49. @Override
  50. public void beginTests(VariableContext context) throws TestExecutionError {
  51. if (classListener != null)
  52. {
  53. classListener.beginTests(context);
  54. }
  55. }
  56. @Override
  57. public void beginPackage(ETLTestPackage name, VariableContext context, final int executor) throws TestAssertionFailure, TestExecutionError, TestWarning {
  58. if (classListener != null)
  59. {
  60. classListener.beginPackage(name, context, executor);
  61. }
  62. }
  63. @Override
  64. public void endPackage(ETLTestPackage name, VariableContext context, final int executor) throws TestAssertionFailure, TestExecutionError, TestWarning {
  65. if (classListener != null)
  66. {
  67. classListener.endPackage(name, context, executor);
  68. }
  69. }
  70. @Override
  71. public void endTests(VariableContext context, int executorId) {
  72. if (classListener != null)
  73. {
  74. classListener.endTests(context, executorId);
  75. }
  76. }
  77. @Override
  78. public void endTests(VariableContext context) {
  79. if (classListener != null)
  80. {
  81. classListener.endTests(context);
  82. }
  83. }
  84. @Override
  85. public void begin(ETLTestClass cl, final VariableContext context, final int executor)
  86. throws TestAssertionFailure, TestExecutionError, TestWarning
  87. {
  88. if (classListener != null)
  89. {
  90. classListener.begin(cl, context, executor);
  91. }
  92. }
  93. @Override
  94. public void declare(ETLTestVariable var, final VariableContext context, final int executor)
  95. {
  96. if (classListener != null)
  97. {
  98. classListener.declare(var, context, executor);
  99. }
  100. }
  101. @Override
  102. public void begin(ETLTestMethod mt, final VariableContext context, final int executor)
  103. throws TestAssertionFailure, TestExecutionError, TestWarning
  104. {
  105. if (classListener != null)
  106. {
  107. classListener.begin(mt, context, executor);
  108. }
  109. }
  110. @Override
  111. public void begin(ETLTestMethod mt, ETLTestOperation op, ETLTestValueObject parameters, VariableContext vcontext, ExecutionContext econtext, final int executor)
  112. throws TestAssertionFailure, TestExecutionError, TestWarning
  113. {
  114. if (classListener != null)
  115. {
  116. classListener.begin(mt, op, parameters, vcontext, econtext, executor);
  117. }
  118. }
  119. @Override
  120. public action_code process(ETLTestMethod mt, ETLTestOperation op, ETLTestValueObject obj, VariableContext context, ExecutionContext econtext, final int executor)
  121. throws TestAssertionFailure, TestExecutionError, TestWarning
  122. {
  123. if (classListener != null)
  124. {
  125. return classListener.process(mt, op, obj, context, econtext, executor);
  126. }
  127. // check for meta info - in case we have none we should defer to the extenders here.
  128. if (getMetaInfo().getExportedOperations() == null)
  129. {
  130. return new OperationProcessorSpammer((List) extenders).process(mt, op, obj, context, econtext, executor);
  131. }
  132. return action_code.defer;
  133. }
  134. @Override
  135. public void end(ETLTestMethod mt, ETLTestOperation op, ETLTestValueObject parameters, VariableContext vcontext, ExecutionContext econtext, final int executor)
  136. throws TestAssertionFailure, TestExecutionError, TestWarning
  137. {
  138. if (classListener != null)
  139. {
  140. classListener.end(mt, op, parameters, vcontext, econtext, executor);
  141. }
  142. }
  143. @Override
  144. public void end(ETLTestMethod mt, final VariableContext context, final int executor)
  145. throws TestAssertionFailure, TestExecutionError, TestWarning
  146. {
  147. if (classListener != null)
  148. {
  149. classListener.end(mt, context, executor);
  150. }
  151. }
  152. @Override
  153. public void end(ETLTestClass cl, final VariableContext context, final int executor)
  154. throws TestAssertionFailure, TestExecutionError, TestWarning
  155. {
  156. if (classListener != null)
  157. {
  158. classListener.end(cl, context, executor);
  159. }
  160. }
  161. };
  162. }
  163. @Override
  164. public FeatureMetaInfo getMetaInfo()
  165. {
  166. final FeatureMetaInfo meta = super.getMetaInfo();
  167. return new FeatureMetaInfo()
  168. {
  169. @Override
  170. public String getFeatureName()
  171. {
  172. return meta.getFeatureName();
  173. }
  174. @Override
  175. public String getFeatureConfiguration()
  176. {
  177. return meta.getFeatureConfiguration();
  178. }
  179. @Override
  180. public JsonSchema getFeatureConfigurationValidator()
  181. {
  182. return meta.getFeatureConfigurationValidator();
  183. }
  184. @Override
  185. public JsonNode getFeatureConfigurationValidatorNode() {
  186. return meta.getFeatureConfigurationValidatorNode();
  187. }
  188. @Override
  189. public Map<String, FeatureOperation> getExportedOperations()
  190. {
  191. Map<String, FeatureOperation> expOp = meta.getExportedOperations();
  192. if (expOp != null)
  193. {
  194. Map<String, FeatureOperation> newExpOp = new HashMap<String, FeatureOperation>();
  195. // wrap this to capture the signatures of our exported operations and expose the extender
  196. // operations
  197. for (Map.Entry<String, FeatureOperation> entry : expOp.entrySet())
  198. {
  199. String opName = entry.getKey();
  200. FeatureOperation featOp = entry.getValue();
  201. newExpOp.put(opName, new FeatureOperationWrapper(featOp, getExtenderOperations(opName)));
  202. }
  203. return newExpOp;
  204. }
  205. return null;
  206. }
  207. @Override
  208. public Map<String, FeatureAnnotation> getExportedAnnotations()
  209. {
  210. return meta.getExportedAnnotations();
  211. }
  212. @Override
  213. public boolean isInternalFeature()
  214. {
  215. return meta.isInternalFeature();
  216. }
  217. @Override
  218. public String getFeatureUsage()
  219. {
  220. return meta.getFeatureUsage();
  221. }
  222. @Override
  223. public List<RuntimeOptionDescriptor> getOptions()
  224. {
  225. return Collections.emptyList();
  226. }
  227. @Override
  228. public String getDescribingClassName()
  229. {
  230. return getDescribing().getClass().getName();
  231. }
  232. @Override
  233. public Feature getDescribing()
  234. {
  235. return ExtensibleFeatureModule.this;
  236. }
  237. };
  238. }
  239. /**
  240. * Get a list of all operations which can extend this operation. This relies on the meta info, but
  241. * the fallback is always the extender itself.
  242. *
  243. * @param opName
  244. * @return
  245. */
  246. private List<OperationProcessor> getExtenderOperations(String opName)
  247. {
  248. List<OperationProcessor> flist = new ArrayList<OperationProcessor>();
  249. for (Extender ext : extenders)
  250. {
  251. FeatureMetaInfo metaInfo = ext.getFeature().getMetaInfo();
  252. if (metaInfo != null)
  253. {
  254. Map<String, FeatureOperation> exportedOperations = metaInfo.getExportedOperations();
  255. if (exportedOperations != null)
  256. {
  257. FeatureOperation featop = exportedOperations.get(opName);
  258. if (featop != null)
  259. {
  260. flist.add(featop);
  261. }
  262. else
  263. {
  264. flist.add(ext);
  265. }
  266. }
  267. else
  268. {
  269. flist.add(ext);
  270. }
  271. }
  272. else
  273. {
  274. flist.add(ext);
  275. }
  276. }
  277. return flist;
  278. }
  279. public final void extend(Extender exe)
  280. {
  281. extenders.add(exe);
  282. }
  283. protected ClassListener getDelegateListener()
  284. {
  285. return null;
  286. }
  287. private class FeatureOperationWrapper implements FeatureOperation
  288. {
  289. private final FeatureOperation featureOperation;
  290. private final OperationProcessorSpammer operationProcessorSpammer;
  291. public FeatureOperationWrapper(FeatureOperation featOp, List<OperationProcessor> extenderOperations)
  292. {
  293. featureOperation = featOp;
  294. operationProcessorSpammer = new OperationProcessorSpammer(extenderOperations);
  295. }
  296. @Override
  297. public String getName()
  298. {
  299. return featureOperation.getName();
  300. }
  301. @Override
  302. public String getDescription()
  303. {
  304. return featureOperation.getDescription();
  305. }
  306. @Override
  307. public String getUsage()
  308. {
  309. return featureOperation.getUsage();
  310. }
  311. @Override
  312. public String getPrototype()
  313. {
  314. return featureOperation.getPrototype();
  315. }
  316. @Override
  317. public List<FeatureOperationSignature> getSignatures()
  318. {
  319. return featureOperation.getSignatures();
  320. }
  321. @Override
  322. public action_code process(ETLTestMethod mt, ETLTestOperation op, ETLTestValueObject parameters, VariableContext vcontext, ExecutionContext econtext, final int executor) throws TestAssertionFailure, TestExecutionError, TestWarning
  323. {
  324. return operationProcessorSpammer.process(mt, op, parameters, vcontext, econtext, executor);
  325. }
  326. }
  327. }