Completed
Push — master ( f21795...e63d25 )
by Janis
02:34
created

OcrService::buildFileInfo()   A

Complexity

Conditions 4
Paths 7

Size

Total Lines 20
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 4.0466

Importance

Changes 0
Metric Value
dl 0
loc 20
ccs 12
cts 14
cp 0.8571
rs 9.2
c 0
b 0
f 0
cc 4
eloc 13
nc 7
nop 1
crap 4.0466
1
<?php
2
/**
3
 * nextCloud - ocr
4
 *
5
 * This file is licensed under the Affero General Public License version 3 or
6
 * later. See the COPYING file.
7
 *
8
 * @author Janis Koehr <[email protected]>
9
 * @copyright Janis Koehr 2016
10
 */
11
12
namespace OCA\Ocr\Service;
13
14
use Exception;
15
use OC\Files\View;
16
use OCA\Ocr\Db\FileMapper;
17
use OCA\Ocr\Db\File;
18
use OCA\Ocr\Db\OcrStatus;
19
use OCA\Ocr\Db\OcrStatusMapper;
20
use OCA\Ocr\Db\ShareMapper;
21
use OCP\AppFramework\Db\DoesNotExistException;
22
use OCP\IL10N;
23
use OCP\ILogger;
24
use OCP\ITempManager;
25
26
27
/**
28
 * Class OcrService
29
 * @package OCA\Ocr\Service
30
 */
31
class OcrService {
32
33
	/**
34
	 * @var ILogger
35
	 */
36
	private $logger;
37
38
	/**
39
	 * @var ITempManager
40
	 */
41
	private $tempM;
42
43
	/**
44
	 * @var QueueService
45
	 */
46
	private $queueService;
47
48
	/**
49
	 * @var OcrStatusMapper
50
	 */
51
	private $statusMapper;
52
53
	/**
54
	 * @var FileMapper
55
	 */
56
	private $fileMapper;
57
58
	/**
59
	 * @var ShareMapper
60
	 */
61
	private $shareMapper;
62
63
	/**
64
	 * @var View
65
	 */
66
	private $view;
67
68
	/**
69
	 * @var
70
	 */
71
	private $userId;
72
73
	/**
74
	 * @var IL10N
75
	 */
76
	private $l10n;
77
78
	/**
79
	 * Array of allowed mimetypes for ocr processing
80
	 */
81
	const ALLOWED_MIMETYPES = ['application/pdf', 'image/png', 'image/jpeg', 'image/tiff'];
82
83
	/**
84
	 * the correct mimetype for a pdf file
85
	 */
86
	const MIMETYPE_PDF = 'application/pdf';
87
88
	/**
89
	 * the only allowed image mimetypes by tesseract
90
	 */
91
	const MIMETYPES_IMAGE = ['image/png', 'image/jpeg', 'image/tiff'];
92
93
	/**
94
	 * OcrService constructor.
95
	 *
96
	 * @param ITempManager $tempManager
97
	 * @param QueueService $queueService
98
	 * @param OcrStatusMapper $mapper
99
	 * @param View $view
100
	 * @param $userId
101
	 * @param IL10N $l10n
102
	 * @param ILogger $logger
103
	 */
104 15
	public function __construct(ITempManager $tempManager, QueueService $queueService, OcrStatusMapper $mapper, FileMapper $fileMapper, ShareMapper $shareMapper, View $view, $userId, IL10N $l10n, ILogger $logger) {
105 15
		$this->logger = $logger;
106 15
		$this->tempM = $tempManager;
107 15
		$this->queueService = $queueService;
108 15
		$this->statusMapper = $mapper;
109 15
		$this->view = $view;
110 15
		$this->userId = $userId;
111 15
		$this->l10n = $l10n;
112 15
		$this->fileMapper = $fileMapper;
113 15
		$this->shareMapper = $shareMapper;
114 15
	}
115
116
	/**
117
	 * Gets the list of all available tesseract-ocr languages.
118
	 *
119
	 * @return string[] Languages
120
	 */
121 4
	public function listLanguages() {
122
		try {
123 4
			$success = -1;
124 4
			$this->logger->debug('Fetching languages. ', ['app' => 'ocr']);
125 4
			exec('tesseract --list-langs 2>&1', $result, $success);
126 4
			if ($success === 0 && count($result) > 0) {
127 4
				if (is_array($result)) {
128 4
					$traineddata = $result;
129 4
				} else {
130
					throw new NotFoundException($this->l10n->t('No languages found.'));
131
				}
132 4
				$languages = array();
133 4
				array_shift($traineddata); // delete the first element of the array as it is a description of tesseract
134 4
				asort($traineddata); // sort the languages alphabetically
135 4
				foreach ($traineddata as $td) {
136 4
					$tdname = trim($td); // strip whitespaces
137 4
					array_push($languages, $tdname); //add to language list
138 4
				}
139 4
				$this->logger->debug('Fetched languages: ' . json_encode($languages), ['app' => 'ocr']);
140 4
				return $languages;
141
			} else {
142
				throw new NotFoundException($this->l10n->t('No languages found.'));
143
			}
144
		} catch (Exception $e) {
145
			$this->handleException($e);
146
		}
147
	}
148
149
	/**
150
	 * Processes and prepares the files for ocr.
151
	 * Sends the stuff to the client in order to ocr async.
152
	 *
153
	 * @param string $language
154
	 * @param array $files
155
	 * @return string
156
	 */
157 5
	public function process($language, $files) {
158
		try {
159 5
			$this->logger->debug('Will now process files: ' . json_encode($files) . ' with language: ' . json_encode($language), ['app' => 'ocr']);
160
			// Check if files and language not empty
161 5
			if (!empty($files) && !empty($language) && in_array($language, $this->listLanguages())) {
162
163 3
				$fileInfo = $this->buildFileInfo($files);
164
165 2
				foreach ($fileInfo as $fInfo) {
166
					// Check if filelock existing
167
					// TODO: FileLock maybe \OC\Files\View::lockFile()
168
					// Check Shared
169 2
					$source = $fInfo->getPath();
170 2
					if ($this->checkSharedWithInitiator($fInfo)) {
171
						// Shared Item
172 1
						$source = str_replace('home::', '', $fInfo->getStoragename()) . '/' . $source;
173 1
						$target = $this->buildTargetForShared($fInfo);
174 1
					} else {
175
						// Not Shared
176 1
						$source = $this->userId . '/' . $source;
177 1
						$target = $this->buildTarget($fInfo);
178
					}
179
180
					// create a temp file for ocr processing purposes
181 2
					$tempFile = $this->tempM->getTemporaryFile();
182
183
					// set the running type
184 2
					if ($fInfo->getMimetype() === $this::MIMETYPE_PDF) {
185
						$ftype = 'mypdf';
186
					} else {
187 2
						$ftype = 'tess';
188
					}
189
					// Create status object
190 2
					$status = new OcrStatus('PENDING', $source, $target, $tempFile, $ftype, $this->userId, false);
191
					// Init client and send task / job
192
					// Feed the worker
193 2
					$this->queueService->clientSend($status, $language, \OC::$SERVERROOT);
194 2
				}
195 2
				return 'PROCESSING';
196
			} else {
197 2
				throw new NotFoundException($this->l10n->t('Empty parameters passed.'));
198
			}
199 3
		} catch (Exception $e) {
200 3
			$this->handleException($e);
201
		}
202
	}
203
204
	/**
205
	 * A function which returns the JSONResponse for all required status checks and tasks.
206
	 * It will check for already processed, pending and failed ocr tasks and return them as needed.
207
	 *
208
	 * @codeCoverageIgnore
209
	 * @return string
210
	 */
211
	public function status() {
212
		try {
213
			// TODO: release lock
214
215
			// returns user specific processed files
216
			$processed = $this->handleProcessed();
217
218
			$pending = $this->statusMapper->findAllPending($this->userId);
219
220
			// return user specific failed state and set up error
221
			$failed = $this->handleFailed();
222
223
			return ['processed' => count($processed), 'failed' => count($failed), 'pending' => count($pending)];
224
		} catch (Exception $e) {
225
			$this->handleException($e);
226
		}
227
	}
228
229
	/**
230
	 * The command ocr:complete for occ will call this function in order to set the status.
231
	 * the worker should call it automatically after each processing step.
232
	 *
233
	 * @param $statusId
234
	 * @param boolean $failed
235
	 */
236 3
	public function complete($statusId, $failed) {
237
		try {
238 3
			$status = $this->statusMapper->find($statusId);
239 2
			if (!$failed) {
240 1
				$status->setStatus('PROCESSED');
241 1
				$this->statusMapper->update($status);
242 1
			} else {
243 1
				$status->setStatus('FAILED');
244 1
				$this->statusMapper->update($status);
245
			}
246 3
		} catch (Exception $e) {
247 1
			$this->handleException($e);
248
		}
249 2
	}
250
251
	/**
252
	 * The PersonalSettingsController will have the opportunity to delete ocr status objects.
253
	 *
254
	 * @param $statusId
255
	 * @param string $userId
256
	 * @return OcrStatus
257
	 */
258 2
	public function deleteStatus($statusId, $userId) {
259
		try {
260 2
			$status = $this->statusMapper->find($statusId);
261 1
			if ($status->getUserId() !== $userId) {
262
				throw new NotFoundException($this->l10n->t('Cannot delete. Wrong owner.'));
263
			} else {
264 1
				$status = $this->statusMapper->delete($status);
265
			}
266 1
			$status->setTarget($this->removeFileExtension($status));
267 1
			$status->setSource(null);
268 1
			$status->setTempFile(null);
269 1
			$status->setType(null);
270 1
			$status->setErrorDisplayed(null);
271 1
			return $status;
272 1
		} catch (Exception $e) {
273 1
			if ($e instanceof DoesNotExistException) {
0 ignored issues
show
Bug introduced by
The class OCP\AppFramework\Db\DoesNotExistException does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
274 1
				$ex = new NotFoundException($this->l10n->t('Cannot delete. Wrong id.'));
275 1
				$this->handleException($ex);
276
			} else {
277
				$this->handleException($e);
278
			}
279
		}
280
	}
281
282
	/**
283
	 * Gets all status objects for a specific user in order to list them on the personal settings page.
284
	 *
285
	 * @param string $userId
286
	 * @return array
287
	 */
288 1
	public function getAllForPersonal($userId) {
289
		try {
290 1
			$status = $this->statusMapper->findAll($userId);
291 1
			$statusNew = array();
292 1
			for ($x = 0; $x < count($status); $x++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
293 1
				$newName = $this->removeFileExtension($status[$x]);
294 1
				$status[$x]->setTarget($newName);
295 1
				$status[$x]->setSource(null);
296 1
				$status[$x]->setTempFile(null);
297 1
				$status[$x]->setType(null);
298 1
				$status[$x]->setErrorDisplayed(null);
299 1
				array_push($statusNew, $status[$x]);
300 1
			}
301 1
			return $statusNew;
302
		} catch (Exception $e) {
303
			$this->handleException($e);
304
		}
305
	}
306
307
	/**
308
	 * Returns a not existing file name for pdf or image processing
309
	 * protected as of testing issues with static methods. (Actually
310
	 * it will be mocked partially) FIXME: Change this behaviour as soon as the buidlNotExistingFileName function is not static anymore
311
	 * @codeCoverageIgnore
312
	 *
313
	 * @param File $fileInfo
314
	 * @return string
315
	 */
316
	protected function buildTargetForShared(File $fileInfo) {
317
		try {
318
			$share = $this->shareMapper->find($fileInfo->getFileid(), $this->userId, str_replace('home::', '', $fileInfo->getStoragename()));
319
320
			// get rid of the .png or .pdf and so on
321
			$fileName = substr($share->getFileTarget(), 0, -4); // '/thedom.png' => '/thedom' || '/Test/thedom.png' => '/Test/thedom'
1 ignored issue
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
322
323
			// remove everything in front of and including of the first appearance of a slash from behind
324
			$fileName = substr(strrchr($fileName, "/"), 1); // '/thedom' => 'thedom' || '/Test/thedom' => 'thedom'
1 ignored issue
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
325
326
			// eliminate the file name from the path
327
			$filePath = dirname($share->getFileTarget()); // '/thedom.png' => '/' || '/Test/thedom.png' => '/Test'
1 ignored issue
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
328
329
			// replace the first slash
330
			$pos = strpos($filePath, '/');
331
			if ($pos !== false) {
332
				$filePath = substr_replace($filePath, '', $pos, strlen('/')); // '/' => '' || '/Test/' => 'Test'
1 ignored issue
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
333
			}
334
335 View Code Duplication
			if ($fileInfo->getMimetype() === $this::MIMETYPE_PDF) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
336
				// PDFs:
337
				return \OCP\Files::buildNotExistingFileName($filePath, $fileName . '_OCR.pdf');
338
			} else {
339
				// IMAGES:
340
				return \OCP\Files::buildNotExistingFileName($filePath, $fileName . '_OCR.txt');
341
			}
342
		} catch (Exception $e) {
343
			$this->handleException($e);
344
		}
345
	}
346
347
	/**
348
	 * Returns a not existing file name for pdf or image processing
349
	 * protected as of testing issues with static methods. (Actually
350
	 * it will be mocked partially) FIXME: Change this behaviour as soon as the buidlNotExistingFileName function is not static anymore
351
	 * @codeCoverageIgnore
352
	 *
353
	 * @param File $fileInfo
354
	 * @return string
355
	 */
356
	protected function buildTarget(File $fileInfo) {
357
		try {
358
			// get rid of the .png or .pdf and so on
359
			$fileName = substr($fileInfo->getName(), 0, -4); // 'thedom.png' => 'thedom'
1 ignored issue
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
360
361
			// eliminate the file name from the path
362
			$filePath = str_replace($fileInfo->getName(), '', $fileInfo->getPath()); // 'files/Test/thedom.png' => 'files/Test/' || 'files/thedom.png' => 'files/'
1 ignored issue
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
363
364
			// and get the path on top of the files/ dir
365
			$filePath = str_replace('files', '', $filePath); // 'files/Test/' => '/Test/' || 'files/' => '/'
1 ignored issue
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
366
367
			// remove the last slash
368
			$filePath = substr_replace($filePath, '', strrpos($filePath, '/'), strlen('/')); // '/Test/' => '/Test' || '/' => ''
1 ignored issue
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
369
370
			// replace the first slash
371
			$pos = strpos($filePath, '/');
372
			if ($pos !== false) {
373
				$filePath = substr_replace($filePath, '', $pos, strlen('/')); // '/Test' => '// 'Test' || '/' => ''
374
			}
375
376 View Code Duplication
			if ($fileInfo->getMimetype() === $this::MIMETYPE_PDF) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
377
				// PDFs:
378
				return \OCP\Files::buildNotExistingFileName($filePath, $fileName . '_OCR.pdf');
379
			} else {
380
				// IMAGES:
381
				return \OCP\Files::buildNotExistingFileName($filePath, $fileName . '_OCR.txt');
382
			}
383
		} catch (Exception $e) {
384
			$this->handleException($e);
385
		}
386
	}
387
388
389
	/**
390
	 * Returns the fileInfo for each file in files and checks
391
	 * if it has a allowed mimetype and some other conditions.
392
	 *
393
	 * @param array $files
394
	 * @return File[]
395
	 * @throws NotFoundException
396
	 */
397 3
	private function buildFileInfo($files) {
398
		try {
399 3
			$fileArray = array();
400 3
			foreach ($files as $file) {
401
				// Check if anything is missing and file type is correct
402 3
				if (!empty($file['id'])) {
403
404 3
					$fileInfo = $this->fileMapper->find($file['id']);
405 3
					$this->checkMimeType($fileInfo);
406
407 2
					array_push($fileArray, $fileInfo);
408 2
				} else {
409
					throw new NotFoundException($this->l10n->t('Wrong parameter.'));
410
				}
411 2
			}
412 2
			return $fileArray;
413 1
		} catch (Exception $e) {
414 1
			$this->handleException($e);
415
		}
416
	}
417
418
	/**
419
	 * Checks a Mimetype for a specific given FileInfo.
420
	 * @param File $fileInfo
421
	 */
422 3
	private function checkMimeType(File $fileInfo) {
423
		try {
424 3
			if (!$fileInfo || !in_array($fileInfo->getMimetype(), $this::ALLOWED_MIMETYPES)) {
425 1
				$this->logger->debug('Getting FileInfo did not work or not included in the ALLOWED_MIMETYPES array.', ['app' => 'ocr']);
426 1
				throw new NotFoundException($this->l10n->t('Wrong mimetype.'));
427
			}
428 3
		} catch (Exception $e) {
429 1
			$this->handleException($e);
430
		}
431 2
	}
432
433
	/**
434
	 * @param File $fileInfo
435
	 * @return boolean|null
436
	 */
437 2
	private function checkSharedWithInitiator($fileInfo) {
438
		try {
439 2
			$owner = str_replace('home::', '', $fileInfo->getStoragename());
440 2
			if ($this->userId === $owner) {
441
				// user is owner (no shared file)
442 1
				return false;
443
			} else {
444
				// user is not owner (shared file)
445 1
				return true;
446
			}
447
		} catch (Exception $e) {
448
			$this->handleException($e);
449
		}
450
451
	}
452
453
	/**
454
	 * Finishes all Processed files by copying them to the right path and deleteing the temp files.
455
	 * Returns the number of processed files.
456
	 *
457
	 * @codeCoverageIgnore
458
	 * @return array
459
	 */
460
	private function handleProcessed() {
461
		try {
462
			$this->logger->debug('Check if files were processed by ocr and if so, put them to the right dirs.', ['app' => 'ocr']);
463
			$processed = $this->statusMapper->findAllProcessed($this->userId);
464
			foreach ($processed as $status) {
465
				if ($status->getType() === 'tess' && file_exists($status->getTempFile() . '.txt')) {
466
					//Save the tmp file with newname
467
					$this->view->file_put_contents($status->getTarget(), file_get_contents($status->getTempFile() . '.txt')); // need .txt because tesseract saves it like this
468
					// Cleaning temp files
469
					$this->statusMapper->delete($status);
470
					exec('rm ' . $status->getTempFile() . '.txt');
471
				} elseif ($status->getType() === 'mypdf' && file_exists($status->getTempFile())) {
472
					//Save the tmp file with newname
473
					$this->view->file_put_contents($status->getTarget(), file_get_contents($status->getTempFile())); // don't need to extend with .pdf / it uses the tmp file to save
474
					$this->statusMapper->delete($status);
475
					exec('rm ' . $status->getTempFile());
476
				} else {
477
					throw new NotFoundException($this->l10n->t('Temp file does not exist.'));
478
				}
479
			}
480
			return $processed;
481
		} catch (Exception $e) {
482
			$this->handleException($e);
483
		}
484
	}
485
486
	/**
487
	 * Removes ".txt" from the newName of a ocr status
488
	 *
489
	 * @param $status OcrStatus
490
	 * @return string
491
	 */
492 2
	private function removeFileExtension($status) {
493
		try {
494 2
			return substr($status->getTarget(), 0, strrpos($status->getTarget(), '_OCR'));
495
		} catch (Exception $e) {
496
			$this->handleException($e);
497
		}
498
	}
499
500
	/**
501
	 * Handles all failed orders of ocr processing queue and returns the status objects.
502
	 *
503
	 * @codeCoverageIgnore
504
	 * @return array
505
	 */
506
	private function handleFailed() {
507
		try {
508
			$failed = $this->statusMapper->findAllFailed($this->userId);
509
			foreach ($failed as $status) {
510
				// clean the tempfile
511
				exec('rm ' . $status->getTempFile());
512
				// set error displayed
513
				$status->setErrorDisplayed(true);
514
				$this->statusMapper->update($status);
515
			}
516
			$this->logger->debug('Following status objects failed: ' . json_encode($failed), ['app' => 'ocr']);
517
			return $failed;
518
		} catch (Exception $e) {
519
			$this->handleException($e);
520
		}
521
	}
522
523
	/**
524
	 * Handle the possible thrown Exceptions from all methods of this class.
525
	 *
526
	 * @param Exception $e
527
	 * @throws Exception
528
	 * @throws NotFoundException
529
	 */
530 5 View Code Duplication
	private function handleException($e) {
531 5
		$this->logger->logException($e, ['app' => 'ocr', 'message' => 'Exception during ocr service function processing']);
532 5
		if ($e instanceof NotFoundException) {
533 5
			throw new NotFoundException($e->getMessage());
534
		} else {
535
			throw $e;
536
		}
537
	}
538
}
539