1
2
3
4
5
6
7
8
9
10 package com.sri.emo.commandline.defaults;
11
12 import java.io.PrintWriter;
13 import java.io.StringWriter;
14 import java.util.ArrayList;
15 import java.util.Arrays;
16 import java.util.HashMap;
17 import java.util.HashSet;
18 import java.util.Iterator;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.Set;
22 import org.apache.log4j.Logger;
23 import com.jcorporate.expresso.core.db.DBException;
24 import com.jcorporate.expresso.core.dbobj.DBObject;
25 import com.jcorporate.expresso.core.dbobj.ValidValue;
26 import com.jcorporate.expresso.core.security.SuperUser;
27 import com.sri.common.util.ObjectCombinator;
28 import com.sri.emo.annotations.NodeTag;
29 import com.sri.emo.commandline.NodeTracker;
30 import com.sri.emo.commandline.SqlRowGenerator;
31 import com.sri.emo.controller.DecisionMatrix;
32 import com.sri.emo.dbobj.Node;
33 import com.sri.emo.dbobj.Part;
34 import com.sri.emo.dbobj.PartsFactory;
35 import com.sri.emo.dbobj.PickList;
36 import com.sri.emo.dbobj.StepAttributes;
37 import com.sri.emo.dbobj.WizDecisionSet;
38 import com.sri.emo.dbobj.WizDefinition;
39 import com.sri.emo.dbobj.WizStep;
40 import com.sri.emo.wizard.WizDefinitionRepository;
41 import com.sri.emo.wizard.completion.persistence.CompletionDefinition;
42 import com.sri.emo.wizard.expressoimpl.SelectionWizDefinitionRepository;
43 import com.sri.emo.wizard.selection.EmoSelectionWizard;
44 import com.sri.emo.wizard.selection.management.PromptStepType;
45
46 /***
47 * Exports wizards.
48 *
49 * @author Michael Rimov
50 */
51 public class WizardExporter extends AbstractNodeExportSupport {
52
53 /***
54 * Log4j logger.
55 */
56 private final Logger log = Logger.getLogger(WizardExporter.class);
57
58 /***
59 * Set of tag names we're looking for in exporting.
60 */
61 private final Set tags;
62
63 /***
64 * Constructs a wizard exporter with the specified services.
65 *
66 * @param nodeTracker
67 * tracker of nodes.
68 * @param generator
69 * sql row generator for export.
70 * @param tags
71 * the tags we're exporting.
72 */
73 public WizardExporter(final NodeTracker nodeTracker,
74 final SqlRowGenerator generator, String[] tags) {
75 super(nodeTracker, generator);
76
77 this.tags = new HashSet(Arrays.asList(tags));
78 }
79
80 /***
81 * Factory method to create the selection wizard repository.
82 *
83 * @return
84 */
85 protected WizDefinitionRepository getWizardRepository() {
86 return new SelectionWizDefinitionRepository();
87 }
88
89 /***
90 * Exports all wizards to the printwriter.
91 *
92 * @param writer
93 * the writer.
94 * @return number of total dbobject records exported.
95 * @throws DBException
96 */
97 public int exportAllWizards(PrintWriter writer) throws DBException {
98 int recordCount = 0;
99 int wizardCount = 0;
100 if (log.isInfoEnabled()) {
101 log.info("Exporting Wizards");
102 }
103
104 List allWizards = getWizardRepository().listAll(WizDefinition.FLD_NAME);
105 for (Iterator wizardIterator = allWizards.iterator(); wizardIterator
106 .hasNext();) {
107 WizDefinition wizardDefinition = null;
108 try {
109 wizardDefinition = (WizDefinition) wizardIterator.next();
110 recordCount += exportWizard(wizardDefinition, writer);
111 } catch (Exception ex) {
112 log.error("Error exporting wizard " + wizardDefinition, ex);
113 }
114 }
115
116 if (log.isInfoEnabled()) {
117 log.info("Processed " + wizardCount + " wizards.");
118 }
119
120 return recordCount;
121 }
122
123 /***
124 * Exports a given wizard given the wizard definition.
125 *
126 * @param wizardDefinition
127 * @param writer
128 * @return number of records exported.
129 * @throws DBException
130 */
131 private int exportWizard(final WizDefinition wizardDefinition, final PrintWriter writer) throws DBException {
132 int recordsExported = 0;
133
134 try {
135
136 if (isSelectionWizard(wizardDefinition)) {
137
138
139
140
141
142
143
144 StringWriter stringWriter = new StringWriter();
145 PrintWriter transactionalWriter = new PrintWriter(stringWriter);
146 try {
147 recordsExported += exportSelectionWizard(wizardDefinition,
148 transactionalWriter);
149 } finally {
150 transactionalWriter.close();
151 }
152
153
154 if (recordsExported > 0) {
155 writer.print(stringWriter.toString());
156 }
157 stringWriter = null;
158 transactionalWriter = null;
159 } else {
160 List recordsToExport = exportCompletionWizard(wizardDefinition);
161 for (Iterator i = recordsToExport.iterator(); i.hasNext();) {
162 DBObject eachObject = (DBObject) i.next();
163 recordsExported += this.writeDBObject(writer, eachObject);
164 }
165 }
166
167 } catch (DependentNodesNotTaggedException ex) {
168 System.err.println(ex.getMessage());
169 log.error("Error writing wizard " + wizardDefinition
170 + " missing one or more nodes", ex);
171 } catch (IncompleteDecisionMatrixException ex) {
172 System.err.println(ex.getMessage());
173 log.error("Skipping selection wizard " + wizardDefinition
174 + " due to incomplete selection matrix.", ex);
175 }
176 return recordsExported;
177 }
178
179 /***
180 * Checks to see if the given target node contains the tags necessary for
181 * export.
182 *
183 * @param targetNode
184 * @return
185 * @throws DBException
186 */
187 private boolean isNodeTaggedForExport(Node targetNode) throws DBException {
188 List targetTags = targetNode.getTags();
189 if (targetTags == null || targetTags.size() == 0) {
190 return false;
191 }
192
193 for (int i = 0; i < targetTags.size(); i++) {
194 NodeTag eachTag = (NodeTag) targetTags.get(i);
195 if (tags.contains(eachTag.getTagValue())) {
196 return true;
197 }
198 }
199
200 return false;
201 }
202
203 /***
204 * Retrieve a list of dbobjects to export for the given completion wizard.
205 *
206 * @param wizard
207 * @return list of dbobjects to export.
208 * @throws DBException
209 * @throws DependentNodesNotTaggedException
210 */
211 private List exportCompletionWizard(final WizDefinition wizard)
212 throws DBException, DependentNodesNotTaggedException {
213 List recordsToExport = new ArrayList();
214 recordsToExport.add(wizard);
215 CompletionDefinition completion = (CompletionDefinition) wizard
216 .getAdditionalInfo();
217 Node targetNode = completion.getTargetNode();
218
219 if (!isNodeTaggedForExport(targetNode)) {
220 throw new DependentNodesNotTaggedException(wizard, targetNode);
221 }
222
223 recordsToExport.add(completion);
224 List allDetails = completion.getCompletionDetails();
225 for (Iterator detailIterator = allDetails.iterator(); detailIterator.hasNext();) {
226 DBObject eachDetail = (DBObject)detailIterator.next();
227 recordsToExport.add(eachDetail);
228 }
229
230 return recordsToExport;
231 }
232
233 /***
234 * Hack -- since the wizard API provides a unified view of all wizards, we
235 * check the wizard definition running controller. If it is selection wizard
236 * controller, then we return true.
237 *
238 * @param wizardDefinition
239 * the wizard definition to examine.
240 * @return
241 * @throws DBException
242 */
243 private boolean isSelectionWizard(WizDefinition wizardDefinition)
244 throws DBException {
245 if (EmoSelectionWizard.class.getName().equals(
246 wizardDefinition.getField(WizDefinition.FLD_WIZARD))) {
247 return true;
248 }
249
250 return false;
251 }
252
253 /***
254 * Exports the selection wizard and related objects.
255 *
256 * @param wizard
257 * @param writer
258 * @return
259 * @throws DBException
260 * @throws DependentNodesNotTaggedException
261 * @throws IncompleteDecisionMatrixException
262 */
263 private int exportSelectionWizard(WizDefinition wizard, PrintWriter writer)
264 throws DBException, DependentNodesNotTaggedException,
265 IncompleteDecisionMatrixException {
266 int result = 0;
267 result += writeDBObject(writer, wizard);
268 result += writeDBObject(writer, (DBObject) wizard.getAdditionalInfo());
269
270 List pages = wizard.getPageDefinitions();
271 List notTaggedNodes = new ArrayList();
272 for (Iterator pageIterator = pages.iterator(); pageIterator.hasNext();) {
273 WizStep eachStep = (WizStep) pageIterator.next();
274 try {
275 result += writeDBObject(writer, eachStep);
276
277
278 if (eachStep.getNodeType() != null) {
279 result += exportNodeType(writer, eachStep.getNodeType()
280 .getEntityName());
281 }
282
283
284 List stepAttributes = eachStep.getStepAttributeList();
285 for (Iterator attributeIterator = stepAttributes.iterator(); attributeIterator
286 .hasNext();) {
287 StepAttributes eachAttribute = (StepAttributes) attributeIterator
288 .next();
289 result += writeDBObject(writer, eachAttribute);
290 }
291
292 switch (eachStep.getStepType()) {
293
294 case PromptStepType.CUSTOM_PICKLIST:
295 /***
296 * TODO: SelectionWizardManager.buildWizardSteps currently
297 * doesn't have an implementation for custom picklists??
298 */
299 break;
300
301 case PromptStepType.INSTANCE_PICKLIST:
302 String nodeId = eachStep
303 .getStepAttribute(StepAttributes.ATTRIBUTE_INSTANCE_ID);
304 Node n = new Node();
305 n.setNodeId(nodeId);
306 n.retrieve();
307 if (!this.isNodeTaggedForExport(n)) {
308 throw new DependentNodesNotTaggedException(wizard, n);
309 }
310
311 String attributeId = eachStep
312 .getStepAttribute(StepAttributes.ATTRIBUTE_INSTANCE_FIELD);
313 Part part = new Part();
314 part.setPartId(attributeId);
315 part.retrieve();
316 result += writeDBObject(writer, part);
317
318 break;
319
320 case PromptStepType.MODEL_PICKLIST:
321 Part picklistPart = PartsFactory
322 .getPart(eachStep
323 .getStepAttribute(StepAttributes.ATTRIBUTE_MODEL_FIELD));
324 if (picklistPart != null && picklistPart.hasPicklist()) {
325 result += writeDBObject(writer, picklistPart);
326 }
327 break;
328
329 }
330
331
332 if (WizStep.CUSTOM_PICKLIST == eachStep.getStepType()) {
333 String attribType = eachStep
334 .getStepAttribute(StepAttributes.ATTRIBUTE_PICKLIST_ID);
335
336 List list = eachStep.getPicklistMenu(attribType);
337 for (Iterator picklistIterator = list.iterator(); picklistIterator
338 .hasNext();) {
339 PickList picklist = (PickList) picklistIterator.next();
340 result += writeDBObject(writer, picklist);
341 }
342 }
343
344 } catch (DependentNodesNotTaggedException ex) {
345
346
347 assert ex.getSingleDependentNode() != null;
348 notTaggedNodes.add(ex.getSingleDependentNode());
349 }
350
351 }
352
353 if (notTaggedNodes.size() > 0) {
354 throw new DependentNodesNotTaggedException(wizard, (Node[])notTaggedNodes.toArray(new Node[notTaggedNodes.size()]));
355 }
356
357 result += exportDecisionMatrixForWizard(wizard, writer);
358
359 return result;
360 }
361
362 private void checkAllDecisionNodesPopulated(WizDefinition wizard) throws IncompleteDecisionMatrixException, DBException {
363 List pertinentSteps = wizard.getPertinentDecisionSteps();
364 DecisionMatrix decisionMatrix = new DecisionMatrix(wizard.getId());
365 ObjectCombinator combinator = buildObjectCombinator(pertinentSteps);
366 for (Iterator i = combinator.iterator(); i.hasNext();) {
367 ValidValue[] pickList = (ValidValue[]) i.next();
368
369
370 Map idToVVMap = new HashMap(pickList.length);
371 for (int index = 0; index < pickList.length; index++) {
372 ValidValue onePick = pickList[index];
373 WizStep oneStep = (WizStep) pertinentSteps.get(index);
374 idToVVMap.put(new Integer(oneStep.getFieldInt(WizStep.FLD_ID)), new Integer(onePick.getKey()));
375 }
376 WizDecisionSet decisionSet = decisionMatrix.getDecision(idToVVMap);
377 if (decisionSet == null) {
378 throw new IncompleteDecisionMatrixException(wizard);
379 }
380 }
381 }
382
383 /***
384 * Constructs an object combinator given a list of wizard steps that
385 * are pertinent to the current wizard.
386 *
387 * @param pertinentSteps List A list of WizSteps.
388 * @return ObjectCombinator constructed ObjectCombinator
389 */
390 private ObjectCombinator buildObjectCombinator(final List pertinentSteps) {
391 ValidValue[][] allPossibleValidValues = new ValidValue[pertinentSteps.size()][];
392 for (int i = 0; i < pertinentSteps.size(); i++) {
393 WizStep oneStep = (WizStep) pertinentSteps.get(i);
394 allPossibleValidValues[i] = oneStep.getMenuItems();
395 }
396
397 return new ObjectCombinator(allPossibleValidValues, ValidValue.class);
398 }
399
400
401 /***
402 * Exports the decision matrix.
403 *
404 * @param writer
405 * @param wizard
406 * @return
407 * @throws DBException
408 * @throws IncompleteDecisionMatrixException
409 */
410 private int exportDecisionMatrixForWizard(WizDefinition wizard,
411 PrintWriter printWriter) throws DBException,
412 DependentNodesNotTaggedException, IncompleteDecisionMatrixException {
413 int count = 0;
414 WizDecisionSet decisionQuery = new WizDecisionSet(SuperUser.INSTANCE);
415 decisionQuery.setWizardId(wizard.getId());
416
417 checkAllDecisionNodesPopulated(wizard);
418
419 List allDecisions = decisionQuery.searchAndRetrieveList();
420 List failedNodes = new ArrayList();
421
422 for (Iterator decisionIterator = allDecisions.iterator(); decisionIterator
423 .hasNext();) {
424
425 WizDecisionSet eachDecision = (WizDecisionSet) decisionIterator
426 .next();
427 Node decisionNode = eachDecision.getDecisionNode();
428
429
430 try {
431 if (!isNodeTaggedForExport(decisionNode)) {
432 throw new DependentNodesNotTaggedException(wizard, decisionNode);
433 }
434
435 count += writeDBObject(printWriter, eachDecision);
436
437 List allDecisionEntities = eachDecision.getDecisionEntities();
438 for (Iterator entityIterator = allDecisionEntities.iterator(); entityIterator
439 .hasNext();) {
440 DBObject eachDecisionEntity = (DBObject) entityIterator.next();
441 count += writeDBObject(printWriter, eachDecisionEntity);
442 }
443 } catch (DependentNodesNotTaggedException ex) {
444
445
446
447 failedNodes.add(decisionNode);
448 }
449 }
450
451
452 if (failedNodes.size() > 0) {
453
454 throw new DependentNodesNotTaggedException(wizard, (Node[])failedNodes.toArray(new Node[failedNodes.size()]));
455 }
456
457 return count;
458 }
459
460 }