/src/enoa/handler/DocumentHandler.java

http://mp-rechnungs-und-kundenverwaltung.googlecode.com/ · Java · 617 lines · 415 code · 52 blank · 150 comment · 94 complexity · ac89f902ab03e5cf3619223e91613da2 MD5 · raw file

  1. /*
  2. * This file is part of YaBS.
  3. *
  4. * YaBS is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * YaBS is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with YaBS. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. package enoa.handler;
  18. import ag.ion.bion.officelayer.document.DocumentDescriptor;
  19. import ag.ion.bion.officelayer.document.DocumentException;
  20. import ag.ion.bion.officelayer.document.IDocument;
  21. import ag.ion.bion.officelayer.filter.*;
  22. import ag.ion.bion.officelayer.form.IFormComponent;
  23. import ag.ion.bion.officelayer.text.ITextCursor;
  24. import ag.ion.bion.officelayer.text.ITextDocument;
  25. import ag.ion.bion.officelayer.text.ITextField;
  26. import ag.ion.bion.officelayer.text.ITextFieldService;
  27. import ag.ion.bion.officelayer.text.IVariableTextFieldMaster;
  28. import ag.ion.bion.officelayer.text.TextException;
  29. import ag.ion.noa.NOAException;
  30. import ag.ion.noa.filter.OpenDocumentFilter;
  31. import com.sun.star.awt.XTextComponent;
  32. import com.sun.star.beans.PropertyValue;
  33. import com.sun.star.beans.XPropertySet;
  34. import com.sun.star.form.XFormComponent;
  35. import com.sun.star.frame.XStorable;
  36. import com.sun.star.io.IOException;
  37. import com.sun.star.uno.UnoRuntime;
  38. import enoa.connection.NoaConnection;
  39. import enoa.connection.URLAdapter;
  40. import java.io.File;
  41. import java.io.FileFilter;
  42. import java.io.FileInputStream;
  43. import java.io.FileNotFoundException;
  44. import java.io.FileOutputStream;
  45. import java.io.InputStream;
  46. import java.net.MalformedURLException;
  47. import java.net.UnknownHostException;
  48. import java.util.ArrayList;
  49. import java.util.Arrays;
  50. import java.util.HashMap;
  51. import java.util.Iterator;
  52. import java.util.List;
  53. import javax.swing.table.TableModel;
  54. import mpv5.db.objects.Template;
  55. import mpv5.db.objects.User;
  56. import mpv5.globals.GlobalSettings;
  57. import mpv5.logging.Log;
  58. import org.jopendocument.util.StringInputStream;
  59. /**
  60. * This class OpenOffice Documents IO
  61. */
  62. public class DocumentHandler {
  63. /**
  64. * All known OO file extensions
  65. */
  66. public static final String EXTENSION = ".*ott$|.*sxw$|.*doc$|.*xls$|.*odt$|.*ods$|.*pps$|.*odt$|.*ppt$|.*odp$";
  67. /**
  68. * A FileFilter looking for OO files
  69. */
  70. public static FileFilter OFFICE_FILE_FILTER = new FileFilter() {
  71. @Override
  72. public boolean accept(File pathname) {
  73. return pathname.getName().matches(EXTENSION);
  74. }
  75. };
  76. private final NoaConnection connection;
  77. private final DocumentDescriptor descriptor;
  78. private IDocument document;
  79. private ITextFieldService textFieldService;
  80. private ITextField[] placeholders;
  81. private TableHandler tablehandler;
  82. private File file;
  83. /**
  84. * Creates a new (hidden) Document Handler on top of the given connection
  85. * @param connection The OO connection to use
  86. */
  87. public DocumentHandler(NoaConnection connection) {
  88. if (connection != null) {
  89. this.connection = connection;
  90. descriptor = DocumentDescriptor.DEFAULT_HIDDEN;
  91. } else {
  92. throw new NullPointerException("Connection cannot be null");
  93. }
  94. }
  95. /**
  96. * Load an existing document into the Document Handler
  97. * @param file The file to load
  98. * @param asTemplate If true, the file is treatened as template (.ott)
  99. * @throws Exception Any error thrown
  100. */
  101. public void loadDocument(File file, boolean asTemplate) throws Exception {
  102. if (!OFFICE_FILE_FILTER.accept(file)) {
  103. throw new UnsupportedOperationException("The file extension must match: " + EXTENSION);
  104. }
  105. if (asTemplate) {
  106. descriptor.setAsTemplate(asTemplate);
  107. }
  108. this.file = file;
  109. descriptor.setHidden(true);
  110. clear();
  111. }
  112. /**
  113. * Creates a new, empty text document (.odt)
  114. * @throws Exception
  115. */
  116. public void newTextDocument() throws Exception {
  117. IDocument d = connection.getDocumentService().constructNewDocument(IDocument.WRITER, descriptor);
  118. document = (ITextDocument) d;
  119. }
  120. /**
  121. * Save the given document to the physical location of the given file.
  122. * @param file
  123. * @throws DocumentException
  124. */
  125. public synchronized void saveAs(File file) throws DocumentException {
  126. if (file.exists()) {
  127. file.delete();
  128. }
  129. document.reformat();
  130. document.update();
  131. if (file.getName().split("\\.").length < 2) {
  132. throw new UnsupportedOperationException("The file must have an extension: " + file);
  133. }
  134. IFilter filter = null;
  135. String extension = file.getName().substring(file.getName().lastIndexOf("."), file.getName().length());
  136. if (extension.equalsIgnoreCase(".pdf")) {
  137. filter = PDFFilter.FILTER;
  138. } else if (extension.equalsIgnoreCase(".doc")) {
  139. filter = MSOffice97Filter.FILTER;
  140. } else if (extension.equalsIgnoreCase(".txt")) {
  141. filter = TextFilter.FILTER;
  142. } else if (extension.equalsIgnoreCase(".odt")) {
  143. filter = OpenDocumentFilter.FILTER;
  144. } else if (extension.equalsIgnoreCase(".html")) {
  145. filter = HTMLFilter.FILTER;
  146. }
  147. if (filter != null) {
  148. try {
  149. Log.Debug(this, "Exporting to: " + file);
  150. document.getPersistenceService().export(new FileOutputStream(file), filter);
  151. } catch (Exception ex) {
  152. Log.Debug(ex);
  153. }
  154. } else {
  155. throw new UnsupportedOperationException("File extension not supported: " + extension);
  156. }
  157. }
  158. /**
  159. * Close the underlying doc
  160. */
  161. public void close() {
  162. document.close();
  163. }
  164. /**
  165. * Fill the Form Fields of the template with values
  166. * @param data
  167. * @throws Exception
  168. * @throws NOAException
  169. * @deprecated slow :-/
  170. */
  171. public synchronized void fillFormFields(HashMap<String, Object> data) throws Exception, NOAException {
  172. Log.Debug(this, "Looking for form fields in: " + document);
  173. IFormComponent[] formComponents = document.getFormService().getFormComponents();
  174. Iterator<String> keys = data.keySet().iterator();
  175. String key = null;
  176. while (keys.hasNext()) {
  177. // get column name
  178. key = keys.next();
  179. // Log.Debug(this, "Found key: " + key + " [" + data.get(key) + "]");
  180. for (int i = 0; i < formComponents.length; i++) {
  181. XFormComponent xFormComponent = formComponents[i].getXFormComponent();
  182. XTextComponent xTextComponent = formComponents[i].getXTextComponent();
  183. XPropertySet propertySet = UnoRuntime.queryInterface(XPropertySet.class,
  184. xFormComponent);
  185. if (propertySet != null && propertySet.getPropertySetInfo().hasPropertyByName("Name")) {
  186. String n = propertySet.getPropertyValue("Name").toString();
  187. // Log.Debug(this, "Found form field: " + n);
  188. if (n.equalsIgnoreCase(key) || key.endsWith(n)) {
  189. Log.Debug(this, "Form field matches key: " + key + " [" + data.get(key) + "]");
  190. xTextComponent.setText(String.valueOf(data.get(key)));
  191. }
  192. }
  193. }
  194. // textDocument.getTextFieldService().refresh();
  195. }
  196. }
  197. /**
  198. * Fill the Placeholder Fields of the template with values
  199. * @param data
  200. * @throws Exception
  201. * @throws NOAException
  202. */
  203. public synchronized void fillPlaceholderFields(HashMap<String, Object> data) throws Exception, NOAException {
  204. Log.Debug(this, "Looking for placeholder fields in: " + document);
  205. Iterator<String> keys = data.keySet().iterator();
  206. String key = null;
  207. String[] placehrepr = new String[0];
  208. List<ITextField> fields = new ArrayList<ITextField>();
  209. if (textFieldService == null || placeholders == null) {
  210. textFieldService = ((ITextDocument) document).getTextFieldService();
  211. placeholders = textFieldService.getPlaceholderFields();
  212. placehrepr = new String[placeholders.length];
  213. for (int i = 0; i < placeholders.length; i++) {
  214. placehrepr[i] = placeholders[i].getDisplayText();
  215. fields.add(placeholders[i]);
  216. }
  217. Log.Debug(this, "Got: " + Arrays.asList(placehrepr));
  218. }
  219. InputStream is = null;
  220. ITextCursor cursor;
  221. while (keys.hasNext()) {
  222. key = keys.next();
  223. try {
  224. for (int i = 0; i < placehrepr.length; i++) {
  225. String placeholderDisplayText = placehrepr[i];
  226. // Log.Debug(this, "Check placeholder key: " + placeholderDisplayText);
  227. if (placeholderDisplayText.equalsIgnoreCase(key) || placeholderDisplayText.equalsIgnoreCase("<" + key + ">")
  228. || placeholderDisplayText.equalsIgnoreCase("<RTF." + key + ">")) {
  229. Log.Debug(this, "Found placeholder key: " + key + " [" + data.get(key) + "]");
  230. if (placeholderDisplayText.startsWith("<RTF.") || placeholderDisplayText.startsWith("<rtf.")) {
  231. is = new StringInputStream(((String) data.get(key)).replace("`",
  232. "'"));
  233. cursor = placeholders[i].getTextDocument().
  234. getViewCursorService().
  235. getViewCursor().
  236. getTextCursorFromStart();
  237. cursor.gotoRange(placeholders[i].getTextRange(),
  238. false);
  239. cursor.insertDocument(is,
  240. RTFFilter.FILTER);
  241. // placeholders[i].getTextRange().
  242. // setText("");
  243. } else {
  244. placeholders[i].getTextRange().setText(String.valueOf(data.get(key)));
  245. }
  246. }
  247. }
  248. } catch (java.lang.Exception ex) {
  249. Log.Debug(ex);
  250. }
  251. }
  252. if (!GlobalSettings.getBooleanProperty("org.openyabs.exportproperty.blankunusedfields.disable")) {
  253. for (int i = 0; i < fields.size(); i++) {
  254. try {
  255. ITextField xTextComponent = fields.get(i);
  256. if (xTextComponent.getXTextContent().getAnchor() != null) {
  257. if (Log.isDebugging()) {
  258. Log.Debug(this, "Filling unspecified field: " + xTextComponent.getDisplayText());
  259. }
  260. xTextComponent.getTextRange().setText("");
  261. }
  262. } catch (Throwable ex) {
  263. Log.Debug(this, ex.getLocalizedMessage());
  264. }
  265. }
  266. }
  267. }
  268. /**
  269. * Fill the Variable Text Fields of the template with values
  270. * @param data
  271. * @throws Exception
  272. * @throws NOAException
  273. * @deprecated slow :_/
  274. */
  275. public synchronized void fillTextVariableFields(HashMap<String, Object> data) throws Exception, NOAException {
  276. Log.Debug(this, "Looking for variable fields in: " + document);
  277. Iterator<String> keys = data.keySet().iterator();
  278. String key = null;
  279. IVariableTextFieldMaster x;
  280. while (keys.hasNext()) {
  281. // get column name
  282. key = keys.next();
  283. if (textFieldService == null) {
  284. textFieldService = ((ITextDocument) document).getTextFieldService();
  285. }
  286. x = textFieldService.getVariableTextFieldMaster(key);
  287. if (x != null) {
  288. ITextField[] variables = x.getVariableTextFields();
  289. for (int i = 0; i < variables.length; i++) {
  290. XPropertySet xPropertySetField = (XPropertySet) UnoRuntime.queryInterface(XPropertySet.class, variables[i].getXTextContent());
  291. if (xPropertySetField.getPropertyValue("CurrentPresentation").toString().equalsIgnoreCase(key)) {
  292. Log.Debug(this, "Found variable key: " + key + " [" + data.get(key) + "]");
  293. xPropertySetField.setPropertyValue("Content", data.get(key));
  294. }
  295. }
  296. }
  297. }
  298. }
  299. /**
  300. * Export a file to another format/file. Supported target formats:
  301. * <li>pdf (pdf/a)
  302. * <li>odt
  303. * <li>txt
  304. * @param source The file to export
  305. * @param target The target file
  306. * @return The target file
  307. * @throws DocumentException
  308. */
  309. public File export(File source, File target) throws DocumentException {
  310. if (target.getName().split("\\.").length < 2) {
  311. throw new UnsupportedOperationException("The file must have an extension: " + target);
  312. }
  313. IFilter filter = null;
  314. String extension = target.getName().substring(target.getName().lastIndexOf("."), target.getName().length());
  315. if (extension.equalsIgnoreCase(".pdf")) {
  316. if (User.getCurrentUser().getProperties().hasProperty("pdftype")
  317. && User.getCurrentUser().getProperties().getProperty("pdftype").equalsIgnoreCase("pdf/a")) {
  318. try {
  319. return exportPDFA(source, target);
  320. } catch (Exception ex) {
  321. Log.Debug(ex);
  322. }
  323. } else {
  324. filter = PDFFilter.FILTER;
  325. }
  326. } else if (extension.equalsIgnoreCase(".doc")) {
  327. filter = MSOffice97Filter.FILTER;
  328. } else if (extension.equalsIgnoreCase(".txt")) {
  329. filter = TextFilter.FILTER;
  330. } else if (extension.equalsIgnoreCase(".odt")) {
  331. filter = OpenDocumentFilter.FILTER;
  332. } else if (extension.equalsIgnoreCase(".html")) {
  333. filter = HTMLFilter.FILTER;
  334. }
  335. if (filter != null) {
  336. connection.getDocumentService().loadDocument(source.getAbsolutePath()).getPersistenceService().export(target.getPath(), filter);
  337. } else {
  338. throw new UnsupportedOperationException("File extension not supported: " + extension);
  339. }
  340. return target;
  341. }
  342. private File exportPDFA(File source, File target) throws DocumentException, MalformedURLException, FileNotFoundException, IOException, UnknownHostException {
  343. IDocument doc = connection.getDocumentService().loadDocument(new FileInputStream(source), descriptor);
  344. PDFFilter pdfFilter = (PDFFilter) PDFFilter.FILTER;
  345. /*PDFFilterProperties pdfFilterProperties = pdfFilter.getPDFFilterProperties();
  346. pdfFilterProperties.setPdfVersion(1);
  347. doc.getPersistenceService().export(url, pdfFilter);*/
  348. PropertyValue[] filterData = new PropertyValue[1];
  349. filterData[0] = new PropertyValue();
  350. filterData[0].Name = "SelectPdfVersion";
  351. filterData[0].Value = new Integer(1); //0: normal 1.4, 1: PDF/A
  352. String filterDefinition = pdfFilter.getFilterDefinition(doc);
  353. PropertyValue[] properties = new PropertyValue[2];
  354. properties[0] = new PropertyValue();
  355. properties[0].Name = "FilterName"; //$NON-NLS-1$
  356. properties[0].Value = filterDefinition;
  357. properties[1] = new PropertyValue();
  358. properties[1].Name = "FilterData";
  359. properties[1].Value = filterData;
  360. String url = URLAdapter.adaptURL(target.getPath());
  361. XStorable xStorable = (XStorable) UnoRuntime.queryInterface(XStorable.class,
  362. doc.getXComponent());
  363. xStorable.storeToURL(url, properties);
  364. return target;
  365. }
  366. /**
  367. * Print the document directly
  368. */
  369. public void print() {
  370. try {
  371. document.getPrintService().print();
  372. } catch (DocumentException ex) {
  373. Log.Debug(ex);
  374. }
  375. }
  376. /**
  377. * Fill the tables in the document
  378. * @param data
  379. */
  380. public synchronized void fillTables(HashMap<String, Object> data) {
  381. fillTables(data, null);
  382. }
  383. /**
  384. * Fills the tables in an .odt file
  385. * @param data
  386. * @param template
  387. */
  388. public void fillTables(HashMap<String, Object> data, Template template) {
  389. HashMap<String, TableModel> models = template.getTables();
  390. Log.Debug(this, "Looking for tables in: " + document);
  391. try {
  392. for (Iterator<String> it = models.keySet().iterator(); it.hasNext();) {
  393. String key = it.next();
  394. TableModel m = models.get(key);
  395. Log.Debug(this, "Table: " + key);
  396. if (tablehandler == null) {
  397. if (key.contains(".")) {
  398. key = key.substring(key.lastIndexOf(".") + 1);
  399. }
  400. Log.Debug(this, "Table identifier: " + key);
  401. tablehandler = new TableHandler((ITextDocument) document, key);
  402. }
  403. for (int j = 0; j < m.getRowCount(); j++) {
  404. String[] strings = new String[m.getColumnCount()];
  405. for (int k = 0; k < strings.length; k++) {
  406. if (m.getValueAt(j, k) != null) {
  407. strings[k] = String.valueOf(m.getValueAt(j, k));
  408. }
  409. }
  410. doRow(template, strings, j);
  411. }
  412. }
  413. } catch (Exception e) {
  414. Log.Debug(e);
  415. }
  416. try {
  417. for (Iterator<String> it = data.keySet().iterator(); it.hasNext();) {
  418. String key = it.next();
  419. if (key.contains(TableHandler.KEY_TABLE)) {//Table found
  420. Log.Debug(this, "Table: " + key);
  421. @SuppressWarnings("unchecked")
  422. List<String[]> value = (List<String[]>) data.get(key);
  423. if (tablehandler == null) {
  424. if (key.contains(".")) {
  425. key = key.substring(key.lastIndexOf(".") + 1);
  426. }
  427. Log.Debug(this, "Table identifier: " + key);
  428. tablehandler = new TableHandler((ITextDocument) document, key);
  429. }
  430. for (int i = 0; i < value.size(); i++) {
  431. String[] strings = value.get(i);
  432. doRow(template, strings, i);
  433. }
  434. }
  435. }
  436. } catch (Exception textException) {
  437. Log.Debug(this, textException);
  438. }
  439. }
  440. public static final String linkstartidentifier = "[url]";
  441. public static final String linkendidentifier = "[/url]";
  442. /**
  443. * Reset the doc
  444. * @throws DocumentException
  445. */
  446. public void clear() throws DocumentException {
  447. try {
  448. Log.Debug(this, "Trying to load: " + URLAdapter.adaptURL(file.getPath()));
  449. // document = connection.getDocumentService().loadDocument(file.getPath().replace("\\", "/"), descriptor);
  450. document = connection.getDocumentService().loadDocument(new FileInputStream(file), descriptor);
  451. } catch (Exception ex) {
  452. Log.Debug(ex);
  453. }
  454. textFieldService = null;
  455. placeholders = null;
  456. tablehandler = null;
  457. }
  458. /**
  459. * Set the images
  460. * @param data
  461. */
  462. public void setImages(HashMap<String, Object> data) {
  463. // XTextGraphicObjectsSupplier graphicObjSupplier = (XTextGraphicObjectsSupplier) UnoRuntime.queryInterface(XTextGraphicObjectsSupplier.class,
  464. // document.getXTextDocument());
  465. // XNameAccess nameAccess = graphicObjSupplier.getGraphicObjects();
  466. // String[] names = nameAccess.getElementNames();
  467. // for (int i = 0; i < names.length; i++) {
  468. // try {
  469. // Any xImageAny = (Any) nameAccess.getByName(names[i]);
  470. // Object xImageObject = xImageAny.getObject();
  471. // XTextContent xImage = (XTextContent) xImageObject;
  472. // XServiceInfo xInfo = (XServiceInfo) UnoRuntime.queryInterface(XServiceInfo.class, xImage);
  473. // if (xInfo.supportsService("com.sun.star.text.TextGraphicObject")) {
  474. // try {
  475. // XPropertySet xPropSet = (XPropertySet) UnoRuntime.queryInterface(XPropertySet.class,
  476. // xImage);
  477. // String name = xPropSet.getPropertyValue("LinkDisplayName").toString();
  478. // String graphicURL = xPropSet.getPropertyValue("GraphicURL").toString();
  479. // //only ones that are not embedded
  480. // if (graphicURL.indexOf("vnd.sun.") == -1) {
  481. // XMultiServiceFactory multiServiceFactory = (XMultiServiceFactory) UnoRuntime.queryInterface(XMultiServiceFactory.class,
  482. // textDocument.getXTextDocument());
  483. // XNameContainer xBitmapContainer = (XNameContainer) UnoRuntime.queryInterface(XNameContainer.class,
  484. // multiServiceFactory.createInstance("com.sun.star.drawing.BitmapTable"));
  485. // if (!xBitmapContainer.hasByName(name)) {
  486. // xBitmapContainer.insertByName(name, graphicURL);
  487. // String newGraphicURL = xBitmapContainer.getByName(name).toString();
  488. // xPropSet.setPropertyValue("GraphicURL", newGraphicURL);
  489. // }
  490. // }
  491. // } catch (UnknownPropertyException ex) {
  492. // Logger.getLogger(DocumentHandler.class.getName()).log(Level.SEVERE, null, ex);
  493. // } catch (WrappedTargetException ex) {
  494. // Logger.getLogger(DocumentHandler.class.getName()).log(Level.SEVERE, null, ex);
  495. // }
  496. // }
  497. // } catch (NoSuchElementException ex) {
  498. // Logger.getLogger(DocumentHandler.class.getName()).log(Level.SEVERE, null, ex);
  499. // } catch (WrappedTargetException ex) {
  500. // Logger.getLogger(DocumentHandler.class.getName()).log(Level.SEVERE, null, ex);
  501. // }
  502. // }
  503. }
  504. private String[] refactorRow(Template template, String[] possibleCols) {
  505. String format = template.__getFormat();
  506. int[] intcols;
  507. try {
  508. String[] cols = format.split(",");
  509. intcols = new int[cols.length];
  510. for (int i = 0; i < intcols.length; i++) {
  511. String string = cols[i];
  512. intcols[i] = Integer.valueOf(string).intValue();
  513. }
  514. } catch (Exception ex) {
  515. Log.Debug(this, "An error occured, using default format now. " + ex.getMessage());
  516. intcols = new int[possibleCols.length];
  517. for (int i = 0; i < intcols.length; i++) {
  518. intcols[i] = i + 1;
  519. }
  520. }
  521. String[] form = new String[intcols.length];
  522. for (int i = 0; i < intcols.length; i++) {
  523. try {
  524. form[i] = possibleCols[intcols[i] - 1];
  525. } catch (Exception e) {
  526. // Log.Debug(this, "Too much columns in the format definition: " + e);
  527. }
  528. }
  529. return form;
  530. }
  531. private void doRow(Template template, String[] strings, int row) {
  532. if (template != null) {
  533. strings = refactorRow(template, strings);
  534. }
  535. if (Log.getLoglevel() == Log.LOGLEVEL_DEBUG) {
  536. Log.Debug(this, Arrays.asList(strings).toString());
  537. }
  538. for (int j = 0; j < strings.length; j++) {
  539. String cellValue = strings[j];
  540. if (cellValue == null) {
  541. cellValue = "";
  542. }
  543. cellValue = cellValue.replaceAll("\\<.*?\\>", "");//remove html/xml tags
  544. if (!cellValue.contains("://")) {//lets say its a valid url
  545. try {
  546. tablehandler.setValueAt(cellValue, j, row);
  547. } catch (TextException ex) {
  548. Log.Debug(ex);
  549. }
  550. } else {
  551. try {
  552. String linkname = "Link";
  553. if (cellValue.contains("@")) {
  554. String link1 = cellValue.split("@")[1];
  555. linkname = cellValue.split("@")[0];
  556. cellValue = link1;
  557. }
  558. tablehandler.setHyperlinkAt(linkname, cellValue, j, row);
  559. } catch (Exception ex) {
  560. Log.Debug(ex);
  561. }
  562. }
  563. }
  564. }
  565. }