1
2
3
4
5
6
7
8
9
10
11 package com.sri.emo.controller;
12
13 import com.jcorporate.expresso.core.controller.*;
14 import com.jcorporate.expresso.core.db.DBException;
15 import com.jcorporate.expresso.core.dbobj.ValidValue;
16 import com.jcorporate.expresso.core.registry.RequestRegistry;
17 import com.sri.emo.dbobj.NodeType;
18 import org.apache.log4j.Logger;
19 import org.dom4j.Document;
20 import org.dom4j.DocumentException;
21 import org.dom4j.Element;
22 import org.dom4j.io.SAXReader;
23
24 import java.io.*;
25 import java.util.ArrayList;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.Map;
29
30 /***
31 * Allows import and export of Entities and their related nodes.
32 * <p> A controller is a rough model of a finite state machine for a web application.
33 * Each state provides user interaction elements that can be rendered in a web
34 * page or other medium such as a command line app.</p>
35 *
36 * @todo Transactionize the import.
37 */
38 public class ImportExportModel extends com.sri.common.controller.
39 AbstractDBController {
40
41 /***
42 *
43 */
44 private static final long serialVersionUID = 1L;
45
46 /***
47 * The log4j logger instance for this class type. Send all logging output
48 * to this variable
49 */
50 private static final transient Logger log = Logger.getLogger(ImportExportModel.class);
51
52 /***
53 * Constant for access to state: Prompt
54 */
55 public static final String STATE_PROMPT = "prompt";
56
57
58 /***
59 * Constant for access to state: Prompt Export Model
60 */
61 public static final String STATE_PROMPT_EXPORT = "promptExportModel";
62
63 /***
64 * Constant for access to state: Export an Entire Model with Nodes
65 */
66 public static final String STATE_EXPORTMODEL = "exportModel";
67
68 /***
69 * Constant for access to state: Import an Entire Model With Nodes
70 */
71 public static final String STATE_IMPORTMODEL = "importModel";
72
73
74 /***
75 * Constant for access to state: Prompt Import
76 */
77 public static final String STATE_PROMPT_IMPORTMODEL = "promptImportModel";
78
79
80 /***
81 * Creates an instance of ImportExportModel. The Controller constructor
82 * also defines what states and parameters are officially defined by the
83 * Controller.
84 */
85 public ImportExportModel() {
86 super();
87 State s;
88
89 s = new State(STATE_PROMPT, "Prompt");
90 addState(s);
91
92 s = new State(STATE_PROMPT_EXPORT, "Prompt for Export");
93 addState(s);
94
95 s = new State(STATE_EXPORTMODEL, "Export an Entire Model with Nodes");
96 addState(s);
97
98 s = new State(STATE_IMPORTMODEL, "Import an Entire Model With Nodes");
99 addState(s);
100
101 s = new State(STATE_PROMPT_IMPORTMODEL, "Prompt for Import");
102 addState(s);
103
104 setInitialState("prompt");
105
106 }
107
108
109 /***
110 * Runs the Prompt state.
111 *
112 * @param request The <code>ExpressoRequest</code> object handed to us
113 * by the framework.
114 * The ExpressoRequest contains all the parameters such as web
115 * parameters, user
116 * security credentials and user locale
117 * @param response The <code>ExpressoResponse</code> object handed to us
118 * by the framework.
119 * The ExpressoResponse will be populated with the Inputs/Outputs
120 * /Transitions/Blocks
121 * for ths sytem.
122 * @throws ControllerException upon error
123 * @throws NonHandleableException upon fatal error
124 */
125 protected void runPromptState(ExpressoRequest request,
126 ExpressoResponse response) throws
127 ControllerException,
128 NonHandleableException {
129 Input i = new Input("fauxstate", "Choose Action");
130
131 List vv = new ArrayList(3);
132 vv.add(new ValidValue("", "choose action..."));
133 vv.add(new ValidValue(STATE_PROMPT_IMPORTMODEL, "import model"));
134 vv.add(new ValidValue(STATE_PROMPT_EXPORT, "export model"));
135 i.setValidValues(vv);
136 i.setDefaultValue("");
137 response.add(i);
138
139
140
141
142
143 Transition t = new Transition("submit", "Perform Action",
144 getClass(), STATE_PROMPT_IMPORTMODEL);
145
146 response.add(t);
147 }
148
149 /***
150 * Runs the Prompt Export.
151 *
152 * @param request The <code>ExpressoRequest</code> object handed to us by
153 * the framework.
154 * The ExpressoRequest contains all the parameters such as web
155 * parameters, user
156 * security credentials and user locale
157 * @param response The <code>ExpressoResponse</code> object handed to us
158 * by the framework.
159 * The ExpressoResponse will be populated with the Inputs/Outputs
160 * /Transitions/Blocks
161 * for ths sytem.
162 * @throws ControllerException upon error
163 * @throws NonHandleableException upon fatal error
164 */
165 protected void runPromptExportModelState(final ExpressoRequest request,
166 final ExpressoResponse response) throws ControllerException,
167 NonHandleableException {
168 try {
169 Input i = new Input("model", "Choose Model To Export");
170 NodeType nt[] = NodeType.getAllTypes();
171 List validValues = new ArrayList(nt.length + 1);
172 validValues.add(new ValidValue("", "choose a model to export..."));
173 for (int j = 0; j < nt.length; j++) {
174 validValues.add(new ValidValue(nt[j].getId(), nt[j].getDisplayName()));
175 }
176 i.setValidValues(validValues);
177 i.setDefaultValue(response);
178 response.add(i);
179
180 i = new Input("exportNodes", "Export Model Nodes As Well?");
181 i.setAttribute("checkbox", "Y");
182 i.setDefaultValue(response);
183
184 response.add(i);
185
186 Transition t = new Transition("export", "Export", getClass(),
187 STATE_EXPORTMODEL);
188 response.add(t);
189
190 } catch (DBException ex) {
191 throw new ControllerException("Error Accessing Database", ex);
192 }
193
194 }
195
196 /***
197 * Runs the Export an Entire Model with Nodes state
198 *
199 * @param request The <code>ExpressoRequest</code> object handed to us
200 * by the framework.
201 * The ExpressoRequest contains all the parameters such as web
202 * parameters, user
203 * security credentials and user locale
204 * @param response The <code>ExpressoResponse</code> object handed to us
205 * by the framework.
206 * The ExpressoResponse will be populated with the Inputs/Outputs
207 * Transitions/Blocks
208 * for ths sytem.
209 * @throws ControllerException upon error
210 * @throws NonHandleableException upon fatal error
211 * @throws IOException upon error writing the XML data.
212 */
213 protected void runExportModelState(ExpressoRequest request,
214 ExpressoResponse response) throws
215 ControllerException,
216 NonHandleableException, IOException {
217 ErrorCollection ec = request.getErrorCollection();
218 if (ec == null) {
219 ec = new ErrorCollection();
220 }
221
222 String modelString = request.getParameter("model");
223 if (modelString == null || modelString.length() == 0) {
224 ec.addError("You need to choose a model");
225 }
226
227 try {
228 NodeType model = new NodeType(RequestRegistry.getUser());
229 model.setField(NodeType.NODE_TYPE_ID, modelString);
230 model.retrieve();
231
232 if (ec.getErrorCount() > 0) {
233 if (log.isDebugEnabled()) {
234 log.debug("Errors in error collection: "
235 + ec.getErrorCount()
236 + " errors.");
237 }
238 response.saveErrors(ec);
239 response.setFormCache();
240 transition(STATE_PROMPT_EXPORT, request, response);
241 }
242
243 ModelXMLWriter writer = new ModelXMLWriter();
244 Document d = writer.renderEntityAsXml(model, request, true);
245 response.setCustomResponse(true);
246 outputXML(d, request);
247 } catch (DBException ex) {
248 throw new ControllerException("Error Accessing Database", ex);
249 }
250 }
251
252 /***
253 * Runs the Import an Entire Model With Nodes state
254 *
255 * @param request The <code>ExpressoRequest</code> object
256 * handed to us by the framework.
257 * The ExpressoRequest contains all the parameters such as
258 * web parameters, user
259 * security credentials and user locale
260 * @param response The <code>ExpressoResponse</code> object handed
261 * to us by the framework.
262 * The ExpressoResponse will be populated with the
263 * Inputs/Outputs/Transitions/Blocks
264 * for ths sytem.
265 * @throws ControllerException upon error
266 * @throws NonHandleableException upon fatal error
267 */
268 protected void runImportModelState(final ExpressoRequest request,
269 final ExpressoResponse response) throws ControllerException,
270 NonHandleableException {
271 ErrorCollection ec = request.getErrorCollection();
272 if (ec == null) {
273 ec = new ErrorCollection();
274 }
275
276 String importNodeString = request.getParameter("importNode");
277 boolean importNode;
278 if (importNodeString != null && importNodeString.equals("Y")) {
279 importNode = true;
280 } else {
281 importNode = false;
282 }
283
284 String data = getXmlData(request, ec);
285 Element docRoot = null;
286 if (data != null && ec.getErrorCount() == 0) {
287 try {
288 docRoot = parseXmlDataString(data);
289 } catch (DocumentException ex) {
290 log.error("Error parsing XML data", ex);
291 ec.addError("Error Parsing XML Data: " + ex.toString());
292 }
293
294 }
295
296 if (ec.getErrorCount() > 0) {
297 response.saveErrors(ec);
298 response.setFormCache();
299 transition(STATE_PROMPT_IMPORTMODEL, request, response);
300 return;
301 }
302
303 assert data != null;
304 assert data.length() > 0;
305 assert ec.getErrorCount() == 0;
306 assert docRoot != null;
307
308
309 try {
310 importXmlDocument(request, response, importNode, docRoot);
311
312 } catch (DBException ex1) {
313 throw new ControllerException("Database Error Importing Data", ex1);
314 } catch (Exception ex1) {
315 throw new ControllerException("Other Error Importing Data", ex1);
316 }
317 }
318
319 private void importXmlDocument(ExpressoRequest request,
320 ExpressoResponse response,
321 boolean importNode,
322 Element docRoot) throws ControllerException, DBException, NumberFormatException,
323 Exception {
324
325 ModelXMLReader reader = new ModelXMLReader();
326 NodeType nt = reader.parseEntityAndParts(docRoot);
327 response.add(new Output("Imported Entity: " + nt.getId()));
328 if (importNode) {
329 List allItems = docRoot.selectNodes("//" + ModelXMLWriter.DATA_NODES + "/*");
330
331 for (Iterator i = allItems.iterator(); i.hasNext();) {
332 Element oneElement = (Element) i.next();
333 String subselect = "//Entity/" + ModelXMLWriter.DATA_NODES + "/"
334 + oneElement.getQualifiedName();
335
336 Map createdNodes = reader.parseImportXmlAndCreateNodes(false, false, oneElement, request, subselect);
337
338 for (Iterator j = createdNodes.keySet().iterator(); j.hasNext();) {
339 String oneKey = (String) j.next();
340 response.add(new Output("Added Node: " + oneKey));
341 }
342 }
343
344 }
345 }
346
347 /***
348 * Parse the XML data from either the data parameter or the file parameter.
349 *
350 * @param request ExpressoRequest The ExpressoRequest object
351 * @param ec ErrorCollection the ErrorCollection
352 * @return String the resulting data.
353 */
354 protected String getXmlData(ExpressoRequest request, ErrorCollection ec) {
355 String data = request.getParameter("data");
356 String radioValue = request.getParameter("radiobutton");
357
358 if (data != null && data.length() > 0) {
359 String file = request.getParameter("file");
360 if (file != null && file.length() > 0 && "uploadFile".equals(radioValue)) {
361
362 data = getXmlDataFromFile(request, ec);
363 }
364 } else {
365 String file = request.getParameter("file");
366 if (file == null || file.length() == 0) {
367 ec.addError("You should define either manual data or a file to upload");
368 } else {
369 data = getXmlDataFromFile(request, ec);
370 }
371 }
372 return data;
373 }
374
375 /***
376 * Returns an element from the given data.
377 *
378 * @param data String the actual data to parse.
379 * @return Element Dom4j Element
380 * @throws DocumentException upon parsing error.
381 */
382 protected Element parseXmlDataString(String data) throws DocumentException {
383 SAXReader xmlReader = new SAXReader();
384 Document doc = xmlReader.read(new StringReader(data));
385 return doc.getRootElement();
386 }
387
388 /***
389 * Retrieve a String of the XML data.
390 *
391 * @param request ExpressoRequest
392 * @param ec ErrorCollection the ErrorCollection that we populate if
393 * things go awry.
394 * @return String
395 */
396 private String getXmlDataFromFile(ExpressoRequest request,
397 ErrorCollection ec) {
398 String fileName = request.getFileName("file");
399 if (fileName == null) {
400 ec.addError("There was an error uploading your file. Please enter the"
401 + " data manually");
402 }
403
404 String data = "";
405 try {
406 File f = new File(fileName);
407 if (f == null) {
408 ec.addError("There was an error uploading your file. "
409 + "Please enter the data manually");
410 } else {
411
412 FileReader reader = new FileReader(f);
413 char buffer[] = new char[(int) f.length()];
414 reader.read(buffer);
415 data = new String(buffer);
416 if (data.length() == 0) {
417 ec.addError("Read a zero length file");
418 }
419 }
420 } catch (FileNotFoundException ex) {
421 log.error("Error parsing file", ex);
422 ec.addError("Error reading file. The error has been logged, please"
423 + " enter the data manually");
424 } catch (IOException ex) {
425 log.error("Error reading file", ex);
426 ec.addError("Error reading file. The error has been logged, please enter"
427 + " the data manually");
428 }
429 return data;
430 }
431
432 /***
433 * Prompts for input.
434 *
435 * @param request The <code>ExpressoRequest</code> object handed
436 * to us by the framework.
437 * The ExpressoRequest contains all the parameters such as web
438 * parameters, user
439 * security credentials and user locale
440 * @param response The <code>ExpressoResponse</code> object handed to us
441 * by the framework.
442 * The ExpressoResponse will be populated with the Inputs/Outputs
443 * /Transitions/Blocks for ths sytem.
444 * @throws ControllerException upon error
445 * @throws NonHandleableException upon fatal error
446 */
447 protected void runPromptImportModelState(ExpressoRequest request,
448 ExpressoResponse response) throws ControllerException,
449 NonHandleableException {
450
451 assert request != null;
452 assert response != null;
453
454 Input i = new Input("data", "XML Data To Import");
455 i.setDefaultValue(response);
456 response.add(i);
457
458 i = new Input("importNode", "Import XML Nodes As Well?");
459 i.setAttribute("checkbox", "Y");
460 i.setDefaultValue(response);
461 response.add(i);
462
463 i = new Input("file", "File to Upload for Import");
464 i.setDefaultValue(response);
465 response.add(i);
466
467 Transition t = new Transition("import", "import", getClass(),
468 STATE_IMPORTMODEL);
469 response.add(t);
470
471 }
472
473
474 /***
475 * Override of Controller.getTitle() to provide a meaningful name to this
476 * controller.
477 *
478 * @return java.lang.String
479 */
480 public String getTitle() {
481 return "Import/Export Models";
482 }
483 }