Aktualis HTV job allapot
authorelgekko <vasary@elgekko.net>
Fri, 24 Mar 2023 13:48:09 +0000 (14:48 +0100)
committerelgekko <vasary@elgekko.net>
Fri, 24 Mar 2023 13:48:09 +0000 (14:48 +0100)
58 files changed:
server/-product/production/HIRTV/jobs/executors.xml
server/-product/production/HIRTV/jobs/schedules-orig.json [deleted file]
server/-product/production/HIRTV/jobs/schedules.json
server/-product/production/HIRTV/jobs/steps/ArchiveListBuilderStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/ArchiveMaterialSubmitStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/BackupFileStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/BatchRetrieveForkStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/CancelableStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/CheckLOWRESIntegrity.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/CheckMORPHEUSMissingMaterialsStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/CheckTRAFFICMissingMaterialsStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/CleanupMountedLocationStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/CopyForArchiveNEXIOMaterialsStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/CopyForArchiveNEXIORecordingsStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/CreateArchiveItemStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/CreateMissingLowresStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/DeleteFileStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/DeleteNEXIOMaterialsStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/DetectMissingLengthStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/DownloadRecordingFromNexioStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/DuplicateRemoverStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/GenerateMorpheusMetadataStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/HLSProxyStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/ImportMORPHEUSMissingMaterialsStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/ImportStatisticsStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/MXFCutterStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/MediaToolStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/MetadataTransformStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/OutputPathAndNameSelectorStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/ProjectCleanupMountedLocationStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/RecordingsArchiveItemBuilderStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/SyncOCTOPUSDataStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/TSMBackupStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/TSMExtendedRetrieveStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/TSMRestoreStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/TSMRetrieveMissingMaterialStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/TSMSystemRestoreStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/TranscodeFFAStranStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/TranscodeSELENIOStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/TranscodeStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/UpdateGhostMediaDataStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/UploadRecordingToNexioStep.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/shared/Cmd.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/shared/EscortFiles.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/shared/ExternalCommand.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/shared/ExternalCommandExecutor.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/shared/ExternalProfile.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/shared/ExternalProfilesConfig.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/shared/FFMpeg.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/shared/FileSearchFilterOptions.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/shared/IExternalCallback.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/shared/ItemManagerExtensions.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/shared/MediaCubeClient.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/shared/MetadataSaver.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/shared/MetadataType.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/shared/MetadataTypeDetector.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/shared/OctopusDataMiner.java [new file with mode: 0644]
server/-product/production/HIRTV/jobs/steps/shared/PlanAirExtensions.java [new file with mode: 0644]

index 08332f195f26a400389104f2659d1e224dd3d6f9..c843940c63c81c807a72bdc2beb74067920a4a24 100644 (file)
@@ -1,49 +1,42 @@
 <?xml version="1.0" encoding="UTF-8"?>\r
 <executors>\r
-       <executor className="DummyTestStep1.java" maxConcurrent="1" isRemote="false" />\r
-       <executor className="DummyTestStep2.java" maxConcurrent="1" isRemote="false" />\r
-       <executor className="DummyTestStep3.java" maxConcurrent="1" isRemote="false" />\r
-\r
-       <executor className="TestForkCancelableStep.java" maxConcurrent="1" />\r
-       <executor className="CancelableStep.java" maxConcurrent="50" />\r
-       <executor className="ForkMissingLowresStep.java" maxConcurrent="1" />\r
-       \r
+       <executor className="BackupFileStep.java" maxConcurrent="1" />\r
+       <executor className="ArchiveListBuilderStep.java" maxConcurrent="1" />\r
+       <executor className="ArchiveMaterialSubmitStep.java" maxConcurrent="1" />\r
+       <executor className="BatchRetrieveForkStep.java" maxConcurrent="10" />\r
+       <executor className="CancelableStep.java" maxConcurrent="1" />\r
+       <executor className="CheckLOWRESIntegrity.java" maxConcurrent="1" />\r
+       <executor className="CheckMORPHEUSMissingMaterialsStep.java" maxConcurrent="1" />\r
+       <executor className="CheckTRAFFICMissingMaterialsStep.java" maxConcurrent="1" />\r
+       <executor className="CleanupMountedLocationStep.java" maxConcurrent="10" />\r
+       <executor className="ProjectCleanupMountedLocationStep.java" maxConcurrent="1" />\r
        <executor className="CopyForArchiveNEXIOMaterialsStep.java" maxConcurrent="1" />\r
+       <executor className="CopyForArchiveNEXIORecordingsStep.java" maxConcurrent="1" />\r
+       <executor className="CreateArchiveItemStep.java" maxConcurrent="1" />\r
+       <executor className="CreateMissingLowresStep.java" maxConcurrent="1" />\r
        <executor className="DeleteNEXIOMaterialsStep.java" maxConcurrent="1" />\r
-\r
-       <executor className="user.jobengine.server.steps.ArchiveListBuilderStep" maxConcurrent="1" />\r
-       <executor className="user.jobengine.server.steps.ArchiveMaterialSubmitStep" maxConcurrent="1" />\r
-       <executor className="user.jobengine.server.steps.BatchRetrieveForkStep" maxConcurrent="10" />\r
-       <executor className="user.jobengine.server.steps.CheckLOWRESIntegrity" maxConcurrent="1" />\r
-       <executor className="user.jobengine.server.steps.CheckMORPHEUSMissingMaterialsStep" maxConcurrent="1" />\r
-       <executor className="user.jobengine.server.steps.CheckTRAFFICMissingMaterialsStep" maxConcurrent="1" />\r
-       <executor className="user.jobengine.server.steps.CleanupMountedLocationStep" maxConcurrent="10" />\r
-       <executor className="ProjectCleanupMountedLocationStep.java" maxConcurrent="1" />\r
-       <executor className="user.jobengine.server.steps.CopyForArchiveNEXIORecordingsStep" maxConcurrent="1" />\r
-       <executor className="user.jobengine.server.steps.CreateArchiveItemStep" maxConcurrent="1" />\r
-       <executor className="user.jobengine.server.steps.CreateMissingLowresStep" maxConcurrent="1" />\r
-       <executor className="user.jobengine.server.steps.DetectMissingLengthStep" maxConcurrent="1" />\r
-       <executor className="user.jobengine.server.steps.DeleteFileStep" maxConcurrent="100" />\r
-       <executor className="user.jobengine.server.steps.DownloadRecordingFromNexioStep" maxConcurrent="1" />\r
-       <executor className="user.jobengine.server.steps.DuplicateRemoverStep" maxConcurrent="1" />\r
-       <executor className="user.jobengine.server.steps.GenerateMorpheusMetadataStep" maxConcurrent="10" />\r
-       <executor className="user.jobengine.server.steps.HLSProxyStep" maxConcurrent="2" />\r
-       <executor className="user.jobengine.server.steps.ImportMORPHEUSMissingMaterialsStep" maxConcurrent="1" />\r
-       <executor className="user.jobengine.server.steps.ImportStatisticsStep" maxConcurrent="7" />\r
-       <executor className="user.jobengine.server.steps.MXFCutterStep" maxConcurrent="7" />\r
-       <executor className="user.jobengine.server.steps.MetadataTransformStep" maxConcurrent="1" />\r
-       <executor className="user.jobengine.server.steps.OutputPathAndNameSelectorStep" maxConcurrent="1" />\r
-       <executor className="user.jobengine.server.steps.RecordingsArchiveItemBuilderStep" maxConcurrent="1" />\r
-       <executor className="user.jobengine.server.steps.SyncOCTOPUSDataStep" maxConcurrent="1" />\r
-       <executor className="user.jobengine.server.steps.TranscodeStep" maxConcurrent="2" />\r
-       <executor className="user.jobengine.server.steps.TranscodeFFAStranStep" maxConcurrent="2" />\r
-       <executor className="user.jobengine.server.steps.TranscodeSELENIOStep" maxConcurrent="2" />\r
-       <executor className="user.jobengine.server.steps.TSMBackupStep" maxConcurrent="1" />\r
-       <executor className="user.jobengine.server.steps.TSMExtendedRetrieveStep" maxConcurrent="2"  />\r
-       <executor className="user.jobengine.server.steps.TSMRestoreStep" maxConcurrent="1" />\r
-       <executor className="user.jobengine.server.steps.TSMSystemRestoreStep" maxConcurrent="1" />\r
-       <executor className="user.jobengine.server.steps.TSMRetrieveMissingMaterialStep" maxConcurrent="1" />\r
-       <executor className="user.jobengine.server.steps.UploadRecordingToNexioStep" maxConcurrent="1" />\r
-       <executor className="user.jobengine.server.steps.MediaToolStep" maxConcurrent="1" />\r
-       <executor className="user.jobengine.server.steps.UpdateGhostMediaDataStep" maxConcurrent="1" />\r
+       <executor className="DetectMissingLengthStep.java" maxConcurrent="1" />\r
+       <executor className="DeleteFileStep.java" maxConcurrent="100" />\r
+       <executor className="DownloadRecordingFromNexioStep.java" maxConcurrent="1" />\r
+       <executor className="DuplicateRemoverStep.java" maxConcurrent="1" />\r
+       <executor className="GenerateMorpheusMetadataStep.java" maxConcurrent="10" />\r
+       <executor className="HLSProxyStep.java" maxConcurrent="2" />\r
+       <executor className="ImportMORPHEUSMissingMaterialsStep.java" maxConcurrent="1" />\r
+       <executor className="ImportStatisticsStep.java" maxConcurrent="7" />\r
+       <executor className="MXFCutterStep.java" maxConcurrent="7" />\r
+       <executor className="MetadataTransformStep.java" maxConcurrent="1" />\r
+       <executor className="OutputPathAndNameSelectorStep.java" maxConcurrent="1" />\r
+       <executor className="RecordingsArchiveItemBuilderStep.java" maxConcurrent="1" />\r
+       <executor className="SyncOCTOPUSDataStep.java" maxConcurrent="1" />\r
+       <executor className="TranscodeStep.java" maxConcurrent="2" />\r
+       <executor className="TranscodeFFAStranStep.java" maxConcurrent="2" />\r
+       <executor className="TranscodeSELENIOStep.java" maxConcurrent="2" />\r
+       <executor className="TSMBackupStep.java" maxConcurrent="3" />\r
+       <executor className="TSMExtendedRetrieveStep.java" maxConcurrent="1"  />\r
+       <executor className="TSMRestoreStep.java" maxConcurrent="1" />\r
+       <executor className="TSMSystemRestoreStep.java" maxConcurrent="1" />\r
+       <executor className="TSMRetrieveMissingMaterialStep.java" maxConcurrent="1" />\r
+       <executor className="UploadRecordingToNexioStep.java" maxConcurrent="1" />\r
+       <executor className="MediaToolStep.java" maxConcurrent="1" />\r
+       <executor className="UpdateGhostMediaDataStep.java" maxConcurrent="1" />\r
 </executors>
\ No newline at end of file
diff --git a/server/-product/production/HIRTV/jobs/schedules-orig.json b/server/-product/production/HIRTV/jobs/schedules-orig.json
deleted file mode 100644 (file)
index 076b6fc..0000000
+++ /dev/null
@@ -1,318 +0,0 @@
-{"joblist":[\r
-       {\r
-      "template": "cancelable.xml"\r
-       },      \r
-       {\r
-      "active": true,\r
-      "executeimmediate": true,\r
-         "name" : "OCTOPUS adatok szinkronizálása",\r
-      "template": "sync-octopus.xml",\r
-      "cronexpression": "0/30 * * * * ?",\r
-      "parameters": [\r
-       {"name": "includeArchived", "value": false, "type": "java.lang.Boolean"},\r
-       {"name": "address", "value": "http://10.10.1.10/api/v1", "type": "java.lang.String"},\r
-       {"name": "user", "value": "mam", "type": "java.lang.String"},\r
-       {"name": "pwd", "value": "napocska", "type": "java.lang.String"}\r
-      ]\r
-       },      \r
-       {\r
-      "active": true,\r
-      "executeimmediate": false,\r
-         "name" : "Limitált archiválás az ISILON/ARCHIVE mappából",\r
-      "template": "archive-limited.xml",\r
-      "cronexpression": "0 0 6-22/2 * * ?",\r
-      "parameters": [ \r
-       {"name": "sourcePath", "value": "/mnt/ISILON/ARCHIVE", "type": "java.lang.String"},\r
-       {"name": "killDateDays", "value": 1, "type": "java.lang.Integer"},\r
-       {"name": "limit", "value": 20, "type": "java.lang.Integer"}\r
-      ]\r
-       },\r
-       {\r
-      "active": true,\r
-      "executeimmediate": false,\r
-         "name" : "Archiválás az ISILON/ARCHIVE mappából",\r
-      "template": "archive-ondemand.xml",\r
-      "cronexpression": "0 0 1 * * ?",\r
-      "parameters": [ \r
-       {"name": "sourcePath", "value": "/mnt/ISILON/ARCHIVE", "type": "java.lang.String"},\r
-       {"name": "killDateDays", "value": 1, "type": "java.lang.Integer"},\r
-       {"name": "limit", "value": 0, "type": "java.lang.Integer"}\r
-      ]\r
-       },\r
-       {\r
-         "active": true,\r
-         "executeimmediate": false,\r
-         "name" : "PROXY pótlás FFASTRANS 71",\r
-         "template": "sys-recreate-lowres-71.xml",\r
-         "cronexpression": "0 * * * * ?",\r
-         "parameters": [ \r
-               {"name": "localLowresPath", "value": "/mnt/FIXTRANSCODER-71/OUTPUT", "type": "java.lang.String" },\r
-               {"name": "transcoderAddress", "value": "http://10.10.1.71:65445/api/json/v1/", "type": "java.lang.String"},\r
-               {"name": "globalRetrievePath", "value": "file://10.10.1.30/transcode", "type": "java.lang.String"},\r
-               {"name": "localRetrievePath", "value": "/mediacube/data/lowres/www/video/IFT3/transcode", "type": "java.lang.String"},\r
-               {"name": "localHiresPath", "value": "/mediacube/data/lowres/www/video/IFT3/transcode", "type": "java.lang.String" },\r
-               {"name": "globalHiresPath", "value": "L:\\transcode", "type": "java.lang.String" },\r
-               {"name": "transcoderTemplateName", "value": "MAM_proxy", "type": "java.lang.String"}\r
-         ]\r
-       },\r
-       {\r
-         "active": false,\r
-         "executeimmediate": false,\r
-         "name" : "PROXY pótlás FFASTRANS 72",\r
-         "template": "sys-recreate-lowres-72.xml",\r
-         "cronexpression": "10 * * * * ?",\r
-         "parameters": [ \r
-               {"name": "localLowresPath", "value": "/mnt/FIXTRANSCODER-72/OUTPUT", "type": "java.lang.String" },\r
-               {"name": "transcoderAddress", "value": "http://10.10.1.72:65445/api/json/v1/", "type": "java.lang.String"},\r
-               {"name": "globalRetrievePath", "value": "file://10.10.1.30/transcode", "type": "java.lang.String"},\r
-               {"name": "localRetrievePath", "value": "/mediacube/data/lowres/www/video/IFT3/transcode", "type": "java.lang.String"},\r
-               {"name": "localHiresPath", "value": "/mediacube/data/lowres/www/video/IFT3/transcode", "type": "java.lang.String" },\r
-               {"name": "globalHiresPath", "value": "L:\\transcode", "type": "java.lang.String" },\r
-               {"name": "transcoderTemplateName", "value": "MAM_proxy", "type": "java.lang.String"}\r
-         ]\r
-       },\r
-       {\r
-         "active": false,\r
-         "executeimmediate": false,\r
-         "name" : "PROXY pótlás FFASTRANS 73",\r
-         "template": "sys-recreate-lowres-73.xml",\r
-         "cronexpression": "20 * * * * ?",\r
-         "parameters": [ \r
-               {"name": "localLowresPath", "value": "/mnt/FIXTRANSCODER-73/OUTPUT", "type": "java.lang.String" },\r
-               {"name": "transcoderAddress", "value": "http://10.10.1.73:65445/api/json/v1/", "type": "java.lang.String"},\r
-               {"name": "globalRetrievePath", "value": "file://10.10.1.30/transcode", "type": "java.lang.String"},\r
-               {"name": "localRetrievePath", "value": "/mediacube/data/lowres/www/video/IFT3/transcode", "type": "java.lang.String"},\r
-               {"name": "localHiresPath", "value": "/mediacube/data/lowres/www/video/IFT3/transcode", "type": "java.lang.String" },\r
-               {"name": "globalHiresPath", "value": "L:\\transcode", "type": "java.lang.String" },\r
-               {"name": "transcoderTemplateName", "value": "MAM_proxy", "type": "java.lang.String"}\r
-         ]\r
-       },\r
-       {\r
-         "active": false,\r
-      "executeimmediate": false,\r
-         "name" : "PROXY pótlás FFASTRANS 74",\r
-      "template": "sys-recreate-lowres-74.xml",\r
-      "cronexpression": "30 * * * * ?",\r
-      "parameters": [ \r
-       {"name": "localLowresPath", "value": "/mnt/FIXTRANSCODER-74/OUTPUT", "type": "java.lang.String" },\r
-       {"name": "transcoderAddress", "value": "http://10.10.1.74:65445/api/json/v1/", "type": "java.lang.String"},\r
-       {"name": "globalRetrievePath", "value": "file://10.10.1.30/transcode", "type": "java.lang.String"},\r
-       {"name": "localRetrievePath", "value": "/mediacube/data/lowres/www/video/IFT3/transcode", "type": "java.lang.String"},\r
-       {"name": "localHiresPath", "value": "/mediacube/data/lowres/www/video/IFT3/transcode", "type": "java.lang.String" },\r
-       {"name": "globalHiresPath", "value": "L:\\transcode", "type": "java.lang.String" },\r
-       {"name": "transcoderTemplateName", "value": "MAM_proxy", "type": "java.lang.String"}\r
-      ]\r
-       },\r
-       {\r
-         "name" : "SYS: create-lowres-ondemand",\r
-      "template": "create-lowres-ondemand.xml",\r
-      "parameters": [ \r
-       {"name": "globalRetrievePath", "value": "file://10.10.1.30/transcode", "type": "java.lang.String"},\r
-       {"name": "localRetrievePath", "value": "/mediacube/data/lowres/www/video/IFT3/transcode", "type": "java.lang.String"},\r
-       {"name": "localHiresPath", "value": "/mediacube/data/lowres/www/video/IFT3/transcode", "type": "java.lang.String" },\r
-       {"name": "globalHiresPath", "value": "L:\\transcode", "type": "java.lang.String" },\r
-       {"name": "localLowresPath", "value": "/mnt/FIXTRANSCODER/OUTPUT", "type": "java.lang.String" },\r
-       {"name": "transcoderAddress", "value": "http://10.10.1.74:65445/api/json/v1/", "type": "java.lang.String"},\r
-       {"name": "transcoderTemplateName", "value": "MAM_proxy", "type": "java.lang.String"}\r
-      ]\r
-       },\r
-       {\r
-      "active": true,\r
-      "executeimmediate": false,\r
-         "name" : "Lejárt ISISLON/ARCHIVE anyagok törlése",\r
-      "template": "delete-materials1.xml",\r
-      "cronexpression": "0 0 5 * * ?",\r
-      "parameters": [ \r
-       {"name": "sourcePath", "value": "/mnt/ISILON/ARCHIVE", "type": "java.lang.String"},\r
-       {"name": "skipArchiveCheck", "value": true, "type": "java.lang.Boolean"}\r
-      ]\r
-       },      \r
-       {\r
-      "active": true,\r
-      "executeimmediate": false,\r
-         "name" : "Lejárt ISILON/TQC/CHECK/KESZ anyagok törlése",\r
-      "template": "delete-materials2.xml",\r
-      "cronexpression": "0 0 8 * * ?",\r
-      "parameters": [ \r
-       {"name": "sourcePath", "value": "/mnt/ISILON/TQC/CHECK/KESZ", "type": "java.lang.String"},\r
-       {"name": "skipArchiveCheck", "value": true, "type": "java.lang.Boolean"}\r
-      ]\r
-       },      \r
-       {\r
-      "active": true,\r
-      "executeimmediate": false,\r
-         "name" : "Lejárt ISILON/TQC/PROMO/KESZ anyagok törlése",\r
-      "template": "delete-materials3.xml",\r
-      "cronexpression": "0 0 6 * * ?",\r
-      "parameters": [ \r
-       {"name": "sourcePath", "value": "/mnt/ISILON/TQC/PROMO/KESZ", "type": "java.lang.String"},\r
-       {"name": "skipArchiveCheck", "value": true, "type": "java.lang.Boolean"}\r
-      ]\r
-       },      \r
-       {\r
-      "active": true,\r
-      "executeimmediate": false,\r
-         "name" : "Lejárt ISILON/TQC/REKLAM/KESZ anyagok törlése",\r
-      "template": "delete-materials4.xml",\r
-      "cronexpression": "0 0 7 * * ?",\r
-      "parameters": [ \r
-       {"name": "sourcePath", "value": "/mnt/ISILON/TQC/REKLAM/KESZ", "type": "java.lang.String"},\r
-       {"name": "skipArchiveCheck", "value": true, "type": "java.lang.Boolean"}\r
-      ]\r
-       },      \r
-       {\r
-      "active": true,\r
-      "executeimmediate": false,\r
-         "name" : "Lejárt ISILON/OCTOPUS/_NAPI_MEGTEKINTO anyagok törlése",\r
-      "template": "delete-materials5.xml",\r
-      "cronexpression": "0 0 22 * * ?",\r
-      "parameters": [ \r
-       {"name": "sourcePath", "value": "/mnt/ISILON/OCTOPUS/_NAPI_MEGTEKINTO", "type": "java.lang.String"},\r
-       {"name": "skipArchiveCheck", "value": true, "type": "java.lang.Boolean"}\r
-      ]\r
-       },      \r
-       {\r
-      "active": true,\r
-      "executeimmediate": false,\r
-         "name" : "Lejárt ISISLON/PROMO_NLE mappák törlése",\r
-      "template": "delete-promo-materials.xml",\r
-      "cronexpression": "0 0 6 * * ?",\r
-      "parameters": [ \r
-       {"name": "sourcePath", "value": "/mnt/ISILON/PROMO_NLE", "type": "java.lang.String"}\r
-      ]\r
-       },      \r
-       {\r
-      "active": true,\r
-      "executeimmediate": false,\r
-         "name" : "NEXIO bejátszó anyagok másolása az ISILON/ARCHIVE mappába",\r
-      "template": "copyforarchive-nexio-materials.xml",\r
-      "cronexpression": "0 0 10 * * ?",\r
-      "parameters": [ \r
-       {"name": "nexioPort", "value": 2098, "type": "java.lang.Integer"},\r
-       {"name": "nexioUserName", "value": "administrator", "type": "java.lang.String"},\r
-       {"name": "nexioPassword", "value": "system", "type": "java.lang.String"},\r
-       {"name": "archiveFtp", "value": "ftp://10.10.1.100/ARCHIVE", "type": "java.lang.String"},\r
-       {"name": "archiveUserName", "value": "mediacube", "type": "java.lang.String"},\r
-       {"name": "archivePassword", "value": "Broadca5T", "type": "java.lang.String"},\r
-       {"name": "daysBeforeNow", "value": 1, "type": "java.lang.Integer"},\r
-       {"name": "nexioKillDateDays", "value": 21, "type": "java.lang.Integer"},\r
-       {"name": "nexioAgency", "value": "ARCHIVED", "type": "java.lang.String"}\r
-      ]\r
-       },      \r
-       {\r
-      "active": true,\r
-      "executeimmediate": false,\r
-         "name" : "NEXIO visszarögzített anyagok másolása az ISILON/ARCHIVE mappába",\r
-      "template": "copyforarchive-nexio-recordings.xml",\r
-      "cronexpression": "0 0 12 * * ? *",\r
-      "parameters": [ \r
-       {"name": "nexioPort", "value": 2098, "type": "java.lang.Integer"},\r
-       {"name": "nexioUserName", "value": "administrator", "type": "java.lang.String"},\r
-       {"name": "nexioPassword", "value": "system", "type": "java.lang.String"},\r
-       {"name": "archiveFtp", "value": "ftp://10.10.1.100/ARCHIVE", "type": "java.lang.String"},\r
-       {"name": "archiveUserName", "value": "mediacube", "type": "java.lang.String"},\r
-       {"name": "archivePassword", "value": "Broadca5T", "type": "java.lang.String"},\r
-       {"name": "filterAgencies", "value": "schedule-rec", "type": "java.lang.String"},\r
-       {"name": "limit", "value": 30, "type": "java.lang.Integer"},\r
-       {"name": "nexioKillDateDays", "value": 7, "type": "java.lang.Integer"},\r
-       {"name": "nexioAgency", "value": "HIRADO_ARCHIVED", "type": "java.lang.String"}\r
-      ]\r
-       },      \r
-       {\r
-      "active": true,\r
-      "executeimmediate": false,\r
-         "name" : "Híranyag statisztika importálása",\r
-      "template": "import-statistics.xml",\r
-      "cronexpression": "0 0 6 * * ?",\r
-      "parameters": [ \r
-       {"name": "daysBeforeNow", "value": 1, "type": "java.lang.Integer"}\r
-      ]\r
-       },\r
-       {\r
-      "active": false,\r
-      "executeimmediate": true,\r
-         "name" : "TRAFFIC anyagok visszatöltése",\r
-      "template": "retrieve-traffic-missing-materials.xml",\r
-      "cronexpression": "0 0 0/1 1/1 * ? *",\r
-      "parameters": [\r
-       {"name": "dbUrl", "value": "jdbc:sqlserver://10.10.1.45\\sql16;databaseName=PA_Echo;", "type": "java.lang.String"},\r
-       {"name": "userName", "value": "MAM", "type": "java.lang.String"},\r
-       {"name": "password", "value": "Echotv.hu", "type": "java.lang.String"},\r
-       {"name": "lookupDays", "value": 7, "type": "java.lang.Integer"},\r
-       {"name": "targetPath", "value": "/mnt/ISILON/PLAYOUT/IceGateway/Input", "type": "java.lang.String"},\r
-       {"name": "killDateDays", "value": 10, "type": "java.lang.Integer"}\r
-      ]\r
-       },      \r
-       {\r
-      "active": true,\r
-      "executeimmediate": false,\r
-         "name" : "Lejárt NEXIO anyagok törlése",\r
-      "template": "delete-nexio-materials.xml",\r
-      "cronexpression": "0 0 6 * * ?",\r
-      "parameters": [ \r
-       {"name": "port", "value": 2098, "type": "java.lang.Integer"},\r
-       {"name": "userName", "value": "administrator", "type": "java.lang.String"},\r
-       {"name": "password", "value": "system", "type": "java.lang.String"},\r
-       {"name": "filterAgencies", "value": "HIRADO_23_00,HIRADO_ARCHIVED,HIRADO_CLN", "type": "java.lang.String"},\r
-       {"name": "gracePeriodDays", "value": 1, "type": "java.lang.Integer"},\r
-       {"name": "notificationOnly", "value": false, "type": "java.lang.Boolean"}\r
-      ]\r
-       },      \r
-       {\r
-         "name" : "SYS: MORPHEUS 'missing materials' importálása",\r
-      "template": "import-morpheus-missing-materials.xml",\r
-      "parameters": [ \r
-       {"name": "csvFilePath", "value": "/mnt/MORPHEUS", "type": "java.lang.String"},\r
-       {"name": "processedFolder", "value": "DONE", "type": "java.lang.String"},\r
-       {"name": "targetPath", "value": "/mnt/ISILON/ARCHIVE_RESTORE", "type": "java.lang.String"}\r
-      ]\r
-       },\r
-       {\r
-         "name" : "SYS: batch-retrieve-ondemand",\r
-      "template": "batch-retrieve-ondemand.xml"\r
-       },\r
-       {\r
-         "name" : "SYS: retrieve-ondemand",\r
-      "template": "retrieve-ondemand.xml",\r
-      "parameters": [ \r
-       {"name": "globalRetrievePath", "value": "file://isilon.intra.echotv.hu", "type": "java.lang.String"},\r
-       {"name": "localRetrievePath", "value": "/mnt/ISILON", "type": "java.lang.String"},\r
-       {"name": "materialOutputFolder", "value": "PLAYOUT_NLE", "type": "java.lang.String"},\r
-       {"name": "promoOutputFolder", "value": "PROMO_NLE", "type": "java.lang.String"},\r
-       {"name": "advertisementOutputFolder", "value": "REKLAM_NLE", "type": "java.lang.String"},\r
-       {"name": "octopusOutputFolder", "value": "OCTOPUS", "type": "java.lang.String"},\r
-       {"name": "genericOutputFolder", "value": "ARCHIVE_RESTORE", "type": "java.lang.String"},\r
-       {"name": "onlineOutputFolder", "value": "ONLINE", "type": "java.lang.String"},\r
-       {"name": "killDateDays", "value": 7, "type": "java.lang.Integer"},\r
-       {"name": "nexioAgency", "value": "ARCHIVE_RESTORE", "type": "java.lang.String"},\r
-       {"name": "nexioPort", "value": 2098, "type": "java.lang.Integer"},\r
-       {"name": "nexioUserName", "value": "administrator", "type": "java.lang.String"},\r
-       {"name": "nexioPassword", "value": "system", "type": "java.lang.String"}\r
-      ]\r
-       },\r
-       {\r
-         "name" : "sys: MORPHEUS 'missing materials' importálása",\r
-      "template": "sys-import-morpheus-missing-materials.xml",\r
-      "parameters": [ \r
-       {"name": "csvFilePath", "value": "/mnt/MORPHEUS", "type": "java.lang.String"},\r
-       {"name": "processedFolder", "value": "DONE", "type": "java.lang.String"},\r
-       {"name": "targetPath", "value": "/mnt/ISILON/PLAYOUT/Video", "type": "java.lang.String"}\r
-      ]\r
-       },\r
-       {\r
-         "name" : "sys: MORPHEUS 'missing material' visszatöltése",\r
-      "template": "sys-retrieve-missing-material.xml",\r
-      "parameters": [ \r
-       {"name": "targetPath", "value": "/mnt/ISILON/PLAYOUT/Video", "type": "java.lang.String"},\r
-       {"name": "globalRetrievePath", "value": "\\\\10.10.1.100\\BRAAVOS\\PLAYOUT\\Video", "type": "java.lang.String"},\r
-       {"name": "morpheusDeviceID", "value": "ISILON", "type": "java.lang.String"},\r
-       {"name": "dbUrl", "value": "jdbc:sqlserver://10.10.1.45;databaseName=PA_Echo;", "type": "java.lang.String"},\r
-       {"name": "userName", "value": "MAM", "type": "java.lang.String"},\r
-       {"name": "password", "value": "Echotv.hu", "type": "java.lang.String"},\r
-       {"name": "targetMetadataPath", "value": "/mnt/ISILON/PLAYOUT/MorpheusGateway/Input", "type": "java.lang.String"}\r
-      ]\r
-       }\r
-]}\r
-\r
-\r
-\r
index 1697c76c1649ecb5665d4cdf9d5f75929f68cbf9..3c4faed192e2f8920fcd4cfdcb1c3ea07c87412b 100644 (file)
-{\r
-       "joblist": [\r
-               {\r
-                       "template": "backup-file.xml"\r
-               },\r
-               {\r
-                       "active": false,\r
-                       "cronexpression": "0/2 * * * * ?",\r
-                       "template": "cancelable.xml",\r
-                       "parameters": [\r
-                               {\r
-                                       "name": "param",\r
-                                       "value": 100,\r
-                                       "type": "java.lang.Integer"\r
-                               }\r
-                       ]\r
-               },\r
-               {\r
-                       "cronexpression": "0/2 * * * * ?",\r
-                       "template": "sys-fork-recreate-lowres.xml",\r
-                       "parameters": [\r
-                               {\r
-                                       "name": "localHiresPath",\r
-                                       "value": "c:/temp",\r
-                                       "type": "java.lang.String"\r
-                               }\r
-                       ]\r
-               }\r
-       ]\r
-}\r
+{"joblist":[\r
+       {\r
+      "template": "backup-file.xml"\r
+       },      \r
+       {\r
+      "template": "cancelable.xml"\r
+       },      \r
+       {\r
+      "active": true,\r
+      "executeimmediate": true,\r
+         "name" : "OCTOPUS adatok szinkronizálása",\r
+      "template": "sync-octopus.xml",\r
+      "cronexpression": "0/30 * * * * ?",\r
+      "parameters": [\r
+       {"name": "includeArchived", "value": false, "type": "java.lang.Boolean"},\r
+       {"name": "address", "value": "http://10.10.1.10/api/v1", "type": "java.lang.String"},\r
+       {"name": "user", "value": "mam", "type": "java.lang.String"},\r
+       {"name": "pwd", "value": "napocska", "type": "java.lang.String"}\r
+      ]\r
+       },      \r
+       {\r
+      "active": true,\r
+      "executeimmediate": false,\r
+         "name" : "Limitált archiválás az ISILON/ARCHIVE mappából",\r
+      "template": "archive-limited.xml",\r
+      "cronexpression": "0 0 6-22/1 * * ?",\r
+      "parameters": [ \r
+       {"name": "sourcePath", "value": "/mnt/ISILON/ARCHIVE", "type": "java.lang.String"},\r
+       {"name": "killDateDays", "value": 1, "type": "java.lang.Integer"},\r
+       {"name": "limit", "value": 10, "type": "java.lang.Integer"}\r
+      ]\r
+       },\r
+       {\r
+      "active": true,\r
+      "executeimmediate": false,\r
+         "name" : "Archiválás az ISILON/ARCHIVE mappából",\r
+      "template": "archive-ondemand.xml",\r
+      "cronexpression": "0 0 1 * * ?",\r
+      "parameters": [ \r
+       {"name": "sourcePath", "value": "/mnt/ISILON/ARCHIVE", "type": "java.lang.String"},\r
+       {"name": "killDateDays", "value": 1, "type": "java.lang.Integer"},\r
+       {"name": "limit", "value": 0, "type": "java.lang.Integer"}\r
+      ]\r
+       },\r
+       {\r
+         "active": true,\r
+         "executeimmediate": false,\r
+         "name" : "PROXY pótlás FFASTRANS 71",\r
+         "template": "sys-recreate-lowres-71.xml",\r
+         "cronexpression": "0 0/10 * * * ?",\r
+         "parameters": [ \r
+               {"name": "localLowresPath", "value": "/mnt/FIXTRANSCODER-71/OUTPUT", "type": "java.lang.String" },\r
+               {"name": "transcoderAddress", "value": "http://10.10.1.71:65445/api/json/v1/", "type": "java.lang.String"},\r
+               {"name": "globalRetrievePath", "value": "file://10.10.1.30/transcode", "type": "java.lang.String"},\r
+               {"name": "localRetrievePath", "value": "/mnt/IFT3/transcode", "type": "java.lang.String"},\r
+               {"name": "localHiresPath", "value": "/mnt/IFT3/transcode", "type": "java.lang.String" },\r
+               {"name": "globalHiresPath", "value": "L:\\transcode", "type": "java.lang.String" },\r
+               {"name": "transcoderTemplateName", "value": "MAM_proxy", "type": "java.lang.String"}\r
+         ]\r
+       },\r
+       {\r
+         "active": true,\r
+         "executeimmediate": false,\r
+         "name" : "PROXY pótlás FFASTRANS 72",\r
+         "template": "sys-recreate-lowres-72.xml",\r
+         "cronexpression": "0 0/10 * * * ?",\r
+         "parameters": [ \r
+               {"name": "localLowresPath", "value": "/mnt/FIXTRANSCODER-72/OUTPUT", "type": "java.lang.String" },\r
+               {"name": "transcoderAddress", "value": "http://10.10.1.72:65445/api/json/v1/", "type": "java.lang.String"},\r
+               {"name": "globalRetrievePath", "value": "file://10.10.1.30/transcode", "type": "java.lang.String"},\r
+               {"name": "localRetrievePath", "value": "/mnt/IFT3/transcode", "type": "java.lang.String"},\r
+               {"name": "localHiresPath", "value": "/mnt/IFT3/transcode", "type": "java.lang.String" },\r
+               {"name": "globalHiresPath", "value": "L:\\transcode", "type": "java.lang.String" },\r
+               {"name": "transcoderTemplateName", "value": "MAM_proxy", "type": "java.lang.String"}\r
+         ]\r
+       },\r
+       {\r
+         "active": true,\r
+         "executeimmediate": false,\r
+         "name" : "PROXY pótlás FFASTRANS 73",\r
+         "template": "sys-recreate-lowres-73.xml",\r
+         "cronexpression": "0 0/10 * * * ?",\r
+         "parameters": [ \r
+               {"name": "localLowresPath", "value": "/mnt/FIXTRANSCODER-73/OUTPUT", "type": "java.lang.String" },\r
+               {"name": "transcoderAddress", "value": "http://10.10.1.73:65445/api/json/v1/", "type": "java.lang.String"},\r
+               {"name": "globalRetrievePath", "value": "file://10.10.1.30/transcode", "type": "java.lang.String"},\r
+               {"name": "localRetrievePath", "value": "/mnt/IFT3/transcode", "type": "java.lang.String"},\r
+               {"name": "localHiresPath", "value": "/mnt/IFT3/transcode", "type": "java.lang.String" },\r
+               {"name": "globalHiresPath", "value": "L:\\transcode", "type": "java.lang.String" },\r
+               {"name": "transcoderTemplateName", "value": "MAM_proxy", "type": "java.lang.String"}\r
+         ]\r
+       },\r
+       {\r
+         "active": true,\r
+      "executeimmediate": false,\r
+         "name" : "PROXY pótlás FFASTRANS 74",\r
+      "template": "sys-recreate-lowres-74.xml",\r
+         "cronexpression": "0 0/10 * * * ?",\r
+      "parameters": [ \r
+       {"name": "localLowresPath", "value": "/mnt/FIXTRANSCODER-74/OUTPUT", "type": "java.lang.String" },\r
+       {"name": "transcoderAddress", "value": "http://10.10.1.74:65445/api/json/v1/", "type": "java.lang.String"},\r
+       {"name": "globalRetrievePath", "value": "file://10.10.1.30/transcode", "type": "java.lang.String"},\r
+               {"name": "localRetrievePath", "value": "/mnt/IFT3/transcode", "type": "java.lang.String"},\r
+               {"name": "localHiresPath", "value": "/mnt/IFT3/transcode", "type": "java.lang.String" },\r
+       {"name": "globalHiresPath", "value": "L:\\transcode", "type": "java.lang.String" },\r
+       {"name": "transcoderTemplateName", "value": "MAM_proxy", "type": "java.lang.String"}\r
+      ]\r
+       },\r
+       {\r
+         "name" : "SYS: create-lowres-ondemand",\r
+      "template": "create-lowres-ondemand.xml",\r
+         "parameters": [ \r
+               {"name": "localLowresPath", "value": "/mnt/FIXTRANSCODER-71/OUTPUT", "type": "java.lang.String" },\r
+               {"name": "transcoderAddress", "value": "http://10.10.1.71:65445/api/json/v1/", "type": "java.lang.String"},\r
+               {"name": "globalRetrievePath", "value": "file://10.10.1.30/transcode", "type": "java.lang.String"},\r
+               {"name": "localRetrievePath", "value": "/mnt/IFT3/transcode", "type": "java.lang.String"},\r
+               {"name": "localHiresPath", "value": "/mnt/IFT3/transcode", "type": "java.lang.String" },\r
+               {"name": "globalHiresPath", "value": "L:\\transcode", "type": "java.lang.String" },\r
+               {"name": "transcoderTemplateName", "value": "MAM_proxy", "type": "java.lang.String"}\r
+         ]\r
+       },\r
+       {\r
+      "active": true,\r
+      "executeimmediate": false,\r
+         "name" : "Lejárt ISISLON/ARCHIVE anyagok törlése",\r
+      "template": "delete-materials1.xml",\r
+      "cronexpression": "0 0 5 * * ?",\r
+      "parameters": [ \r
+       {"name": "sourcePath", "value": "/mnt/ISILON/ARCHIVE", "type": "java.lang.String"},\r
+       {"name": "skipArchiveCheck", "value": false, "type": "java.lang.Boolean"}\r
+      ]\r
+       },      \r
+       {\r
+      "active": true,\r
+      "executeimmediate": false,\r
+         "name" : "Lejárt ISILON/TQC/CHECK/KESZ anyagok törlése",\r
+      "template": "delete-materials2.xml",\r
+      "cronexpression": "0 0 8 * * ?",\r
+      "parameters": [ \r
+       {"name": "sourcePath", "value": "/mnt/ISILON/TQC/CHECK/KESZ", "type": "java.lang.String"},\r
+       {"name": "skipArchiveCheck", "value": true, "type": "java.lang.Boolean"}\r
+      ]\r
+       },      \r
+       {\r
+      "active": true,\r
+      "executeimmediate": false,\r
+         "name" : "Lejárt ISILON/TQC/PROMO/KESZ anyagok törlése",\r
+      "template": "delete-materials3.xml",\r
+      "cronexpression": "0 0 6 * * ?",\r
+      "parameters": [ \r
+       {"name": "sourcePath", "value": "/mnt/ISILON/TQC/PROMO/KESZ", "type": "java.lang.String"},\r
+       {"name": "skipArchiveCheck", "value": true, "type": "java.lang.Boolean"}\r
+      ]\r
+       },      \r
+       {\r
+      "active": true,\r
+      "executeimmediate": false,\r
+         "name" : "Lejárt ISILON/TQC/REKLAM/KESZ anyagok törlése",\r
+      "template": "delete-materials4.xml",\r
+      "cronexpression": "0 0 7 * * ?",\r
+      "parameters": [ \r
+       {"name": "sourcePath", "value": "/mnt/ISILON/TQC/REKLAM/KESZ", "type": "java.lang.String"},\r
+       {"name": "skipArchiveCheck", "value": true, "type": "java.lang.Boolean"}\r
+      ]\r
+       },      \r
+       {\r
+      "active": true,\r
+      "executeimmediate": false,\r
+         "name" : "Lejárt ISILON/OCTOPUS/_NAPI_MEGTEKINTO anyagok törlése",\r
+      "template": "delete-materials5.xml",\r
+      "cronexpression": "0 0 22 * * ?",\r
+      "parameters": [ \r
+       {"name": "sourcePath", "value": "/mnt/ISILON/OCTOPUS/_NAPI_MEGTEKINTO", "type": "java.lang.String"},\r
+       {"name": "skipArchiveCheck", "value": true, "type": "java.lang.Boolean"}\r
+      ]\r
+       },      \r
+       {\r
+      "active": true,\r
+      "executeimmediate": false,\r
+         "name" : "Lejárt ISISLON/PROMO_NLE mappák törlése",\r
+      "template": "delete-promo-materials.xml",\r
+      "cronexpression": "0 0 6 * * ?",\r
+      "parameters": [ \r
+       {"name": "sourcePath", "value": "/mnt/ISILON/PROMO_NLE", "type": "java.lang.String"}\r
+      ]\r
+       },      \r
+       {\r
+      "active": true,\r
+      "executeimmediate": false,\r
+         "name" : "NEXIO bejátszó anyagok másolása az ISILON/ARCHIVE mappába",\r
+      "template": "copyforarchive-nexio-materials.xml",\r
+      "cronexpression": "0 0 10 * * ?",\r
+      "parameters": [ \r
+       {"name": "nexioPort", "value": 2098, "type": "java.lang.Integer"},\r
+       {"name": "nexioUserName", "value": "administrator", "type": "java.lang.String"},\r
+       {"name": "nexioPassword", "value": "system", "type": "java.lang.String"},\r
+       {"name": "archiveFtp", "value": "ftp://10.10.1.100/ARCHIVE", "type": "java.lang.String"},\r
+       {"name": "archiveUserName", "value": "mediacube", "type": "java.lang.String"},\r
+       {"name": "archivePassword", "value": "Broadca5T", "type": "java.lang.String"},\r
+       {"name": "daysBeforeNow", "value": 1, "type": "java.lang.Integer"},\r
+       {"name": "nexioKillDateDays", "value": 21, "type": "java.lang.Integer"},\r
+       {"name": "nexioAgency", "value": "ARCHIVED", "type": "java.lang.String"}\r
+      ]\r
+       },      \r
+       {\r
+      "active": true,\r
+      "executeimmediate": false,\r
+         "name" : "NEXIO visszarögzített anyagok másolása az ISILON/ARCHIVE mappába",\r
+      "template": "copyforarchive-nexio-recordings.xml",\r
+      "cronexpression": "0 0 12 * * ? *",\r
+      "parameters": [ \r
+       {"name": "nexioPort", "value": 2098, "type": "java.lang.Integer"},\r
+       {"name": "nexioUserName", "value": "administrator", "type": "java.lang.String"},\r
+       {"name": "nexioPassword", "value": "system", "type": "java.lang.String"},\r
+       {"name": "archiveFtp", "value": "ftp://10.10.1.100/ARCHIVE", "type": "java.lang.String"},\r
+       {"name": "archiveUserName", "value": "mediacube", "type": "java.lang.String"},\r
+       {"name": "archivePassword", "value": "Broadca5T", "type": "java.lang.String"},\r
+       {"name": "filterAgencies", "value": "schedule-rec", "type": "java.lang.String"},\r
+       {"name": "limit", "value": 30, "type": "java.lang.Integer"},\r
+       {"name": "nexioKillDateDays", "value": 7, "type": "java.lang.Integer"},\r
+       {"name": "nexioAgency", "value": "HIRADO_ARCHIVED", "type": "java.lang.String"}\r
+      ]\r
+       },      \r
+       {\r
+      "active": true,\r
+      "executeimmediate": false,\r
+         "name" : "Híranyag statisztika importálása",\r
+      "template": "import-statistics.xml",\r
+      "cronexpression": "0 0 6 * * ?",\r
+      "parameters": [ \r
+       {"name": "daysBeforeNow", "value": 1, "type": "java.lang.Integer"}\r
+      ]\r
+       },\r
+       {\r
+      "active": false,\r
+      "executeimmediate": true,\r
+         "name" : "TRAFFIC anyagok visszatöltése",\r
+      "template": "retrieve-traffic-missing-materials.xml",\r
+      "cronexpression": "0 0 0/1 1/1 * ? *",\r
+      "parameters": [\r
+       {"name": "dbUrl", "value": "jdbc:sqlserver://10.10.1.45\\sql16;databaseName=PA_Echo;", "type": "java.lang.String"},\r
+       {"name": "userName", "value": "MAM", "type": "java.lang.String"},\r
+       {"name": "password", "value": "Echotv.hu", "type": "java.lang.String"},\r
+       {"name": "lookupDays", "value": 7, "type": "java.lang.Integer"},\r
+       {"name": "targetPath", "value": "/mnt/ISILON/PLAYOUT/IceGateway/Input", "type": "java.lang.String"},\r
+       {"name": "killDateDays", "value": 10, "type": "java.lang.Integer"}\r
+      ]\r
+       },      \r
+       {\r
+      "active": true,\r
+      "executeimmediate": false,\r
+         "name" : "Lejárt NEXIO anyagok törlése",\r
+      "template": "delete-nexio-materials.xml",\r
+      "cronexpression": "0 0 6 * * ?",\r
+      "parameters": [ \r
+       {"name": "port", "value": 2098, "type": "java.lang.Integer"},\r
+       {"name": "userName", "value": "administrator", "type": "java.lang.String"},\r
+       {"name": "password", "value": "system", "type": "java.lang.String"},\r
+       {"name": "filterAgencies", "value": "HIRADO_23_00,HIRADO_ARCHIVED,HIRADO_CLN", "type": "java.lang.String"},\r
+       {"name": "gracePeriodDays", "value": 1, "type": "java.lang.Integer"},\r
+       {"name": "notificationOnly", "value": false, "type": "java.lang.Boolean"}\r
+      ]\r
+       },      \r
+       {\r
+         "name" : "SYS: MORPHEUS 'missing materials' importálása",\r
+      "template": "import-morpheus-missing-materials.xml",\r
+      "parameters": [ \r
+       {"name": "csvFilePath", "value": "/mnt/MORPHEUS", "type": "java.lang.String"},\r
+       {"name": "processedFolder", "value": "DONE", "type": "java.lang.String"},\r
+       {"name": "targetPath", "value": "/mnt/ISILON/ARCHIVE_RESTORE", "type": "java.lang.String"}\r
+      ]\r
+       },\r
+       {\r
+         "name" : "SYS: batch-retrieve-ondemand",\r
+      "template": "batch-retrieve-ondemand.xml"\r
+       },\r
+       {\r
+         "name" : "SYS: retrieve-ondemand",\r
+      "template": "retrieve-ondemand.xml",\r
+      "parameters": [ \r
+       {"name": "globalRetrievePath", "value": "file://isilon.intra.echotv.hu", "type": "java.lang.String"},\r
+       {"name": "localRetrievePath", "value": "/mnt/ISILON", "type": "java.lang.String"},\r
+       {"name": "materialOutputFolder", "value": "PLAYOUT_NLE", "type": "java.lang.String"},\r
+       {"name": "promoOutputFolder", "value": "PROMO_NLE", "type": "java.lang.String"},\r
+       {"name": "advertisementOutputFolder", "value": "REKLAM_NLE", "type": "java.lang.String"},\r
+       {"name": "octopusOutputFolder", "value": "OCTOPUS", "type": "java.lang.String"},\r
+       {"name": "genericOutputFolder", "value": "ARCHIVE_RESTORE", "type": "java.lang.String"},\r
+       {"name": "onlineOutputFolder", "value": "ONLINE", "type": "java.lang.String"},\r
+       {"name": "killDateDays", "value": 7, "type": "java.lang.Integer"},\r
+       {"name": "nexioAgency", "value": "ARCHIVE_RESTORE", "type": "java.lang.String"},\r
+       {"name": "nexioPort", "value": 2098, "type": "java.lang.Integer"},\r
+       {"name": "nexioUserName", "value": "administrator", "type": "java.lang.String"},\r
+       {"name": "nexioPassword", "value": "system", "type": "java.lang.String"}\r
+      ]\r
+       },\r
+       {\r
+         "name" : "sys: MORPHEUS 'missing materials' importálása",\r
+      "template": "sys-import-morpheus-missing-materials.xml",\r
+      "parameters": [ \r
+       {"name": "csvFilePath", "value": "/mnt/MORPHEUS", "type": "java.lang.String"},\r
+       {"name": "processedFolder", "value": "DONE", "type": "java.lang.String"},\r
+       {"name": "targetPath", "value": "/mnt/ISILON/PLAYOUT/Video", "type": "java.lang.String"}\r
+      ]\r
+       },\r
+       {\r
+         "name" : "sys: MORPHEUS 'missing material' visszatöltése",\r
+      "template": "sys-retrieve-missing-material.xml",\r
+      "parameters": [ \r
+       {"name": "targetPath", "value": "/mnt/ISILON/PLAYOUT/Video", "type": "java.lang.String"},\r
+       {"name": "globalRetrievePath", "value": "\\\\10.10.1.100\\BRAAVOS\\PLAYOUT\\Video", "type": "java.lang.String"},\r
+       {"name": "morpheusDeviceID", "value": "ISILON", "type": "java.lang.String"},\r
+       {"name": "dbUrl", "value": "jdbc:sqlserver://10.10.1.45;databaseName=PA_Echo;", "type": "java.lang.String"},\r
+       {"name": "userName", "value": "MAM", "type": "java.lang.String"},\r
+       {"name": "password", "value": "Echotv.hu", "type": "java.lang.String"},\r
+       {"name": "targetMetadataPath", "value": "/mnt/ISILON/PLAYOUT/MorpheusGateway/Input", "type": "java.lang.String"}\r
+      ]\r
+       }\r
+]}\r
+\r
+\r
+\r
diff --git a/server/-product/production/HIRTV/jobs/steps/ArchiveListBuilderStep.java b/server/-product/production/HIRTV/jobs/steps/ArchiveListBuilderStep.java
new file mode 100644 (file)
index 0000000..a86d563
--- /dev/null
@@ -0,0 +1,170 @@
+package user.jobengine.server.steps;\r
+\r
+import java.io.File;\r
+import java.io.IOException;\r
+import java.nio.file.DirectoryStream;\r
+import java.nio.file.Files;\r
+import java.nio.file.Path;\r
+import java.nio.file.Paths;\r
+import java.util.LinkedList;\r
+import java.util.List;\r
+\r
+import org.apache.commons.lang.StringUtils;\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+import org.apache.logging.log4j.Marker;\r
+\r
+import user.jobengine.server.IJobEngine;\r
+import user.jobengine.server.IJobRuntime;\r
+\r
+/**\r
+ * Az archivalhato mediak listazasa MediaFileWrapper objektumokban. A listazott\r
+ * media allomanyokat megjeloli .catched signal allomannyal, hogy a legkozelebbi\r
+ * listazas figyelmen kivul hagyja.\r
+ *\r
+ * @author robi\r
+ */\r
+public class ArchiveListBuilderStep extends JobStep {\r
+       private static final Logger logger = LogManager.getLogger();\r
+       // private static final String UTF8 = "utf-8";\r
+       private static final String STATUSFOLDER = ".STATUS";\r
+       private static final String JSONEXT = ".json";\r
+       private static final String CATCHEDEXT = ".catched";\r
+\r
+       public static final String ITEM_TITLE = "itemTitle";\r
+       public static final String ITEM_HOUSEID = "itemHouseId";\r
+       public static final String ITEM_DESCRIPTION = "itemDescription";\r
+       public static final String MEDIA_HOUSEID = "mediaHouseId";\r
+       public static final String MEDIA_TITLE = "mediaTitle";\r
+       public static final String MEDIA_DESCRIPTION = "mediaDescription";\r
+       public static final String MEDIA_TYPE = "mediaType";\r
+       private static final String DURATION = "duration";\r
+       private static final String EXISTING_MEDIAID = "existingMediaId";\r
+       private static final String TAGS = "tags";\r
+\r
+       private Marker marker;\r
+\r
+       private ArchiveItem createArchiveItem(Path jsonFilePath, Path mediaFilePath, Path catchedFilePath) {\r
+               ArchiveItem result = null;\r
+               try {\r
+                       result = ArchiveItem.fromFile(jsonFilePath);\r
+                       result.setMediaFile(mediaFilePath.toString());\r
+                       result.setCatchedFile(catchedFilePath.toString());\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+               }\r
+\r
+               return result;\r
+       }\r
+\r
+       private void createCatchedFile(Path catchedFilePath) {\r
+               try {\r
+                       Files.createFile(catchedFilePath);\r
+                       // Files.write(catchedFilePath, CATCHED.getBytes(UTF8),\r
+                       // StandardOpenOption.CREATE);\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+               }\r
+       }\r
+\r
+       @StepEntry\r
+       public Object[] execute(String sourcePath, int limit, IJobEngine jobEngine, IJobRuntime jobRuntime) {\r
+               marker = jobRuntime.getSessionMarker();\r
+               List<ArchiveItem> archiveList = new LinkedList<ArchiveItem>();\r
+               DirectoryStream<Path> directoryStream = null;\r
+               try {\r
+                       DirectoryStream<Path> stream = Files.newDirectoryStream(Paths.get(sourcePath));\r
+                       for (Path p : stream) {\r
+                               processPathItem(p, archiveList);\r
+                       }\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       logger.error(marker, "Az '{}' mappa elérése sikertelen. A rendszer hibaüzenete: {}", e.getMessage());\r
+               } finally {\r
+                       if (directoryStream != null) {\r
+                               try {\r
+                                       directoryStream.close();\r
+                               } catch (IOException e) {\r
+                               }\r
+                       }\r
+               }\r
+\r
+               if (limit > 0 && archiveList.size() > limit) {\r
+                       archiveList = archiveList.subList(0, limit);\r
+                       logger.info(marker, "A folyamat alkalmazza a beállított {} limitet.", limit);\r
+               }\r
+\r
+               if (archiveList.size() == 0)\r
+                       logger.info(marker, "Nincs archiválandó anyag.");\r
+               else\r
+                       logger.info(marker, "Az archiváló folyamat {} új anyagot érzékelt.",\r
+                                       archiveList == null ? 0 : archiveList.size());\r
+\r
+               for (ArchiveItem archiveItem : archiveList) {\r
+                       createCatchedFile(Paths.get(archiveItem.getCatchedFile()));\r
+               }\r
+\r
+               return new Object[] { archiveList };\r
+       }\r
+\r
+       private boolean processPathItem(Path mediaFilePath, final List<ArchiveItem> archiveList) {\r
+               File mediaFile = mediaFilePath.toFile();\r
+\r
+               // if (mediaFile.length() > 0)\r
+               // return false;\r
+\r
+               if (mediaFile.isDirectory()) {\r
+                       return false;\r
+               }\r
+\r
+               Path dotStorePath = Paths.get(mediaFilePath.getParent().toString(), STATUSFOLDER);\r
+               Path catchedFilePath = Paths.get(dotStorePath.toString(), mediaFile.getName() + CATCHEDEXT);\r
+               File catchedFile = catchedFilePath.toFile();\r
+               if (catchedFile.exists()) {\r
+                       logger.warn("{} file is already catched.", mediaFile.getName());\r
+                       return false;\r
+               }\r
+\r
+               Path jsonFilePath = Paths.get(dotStorePath.toString(), mediaFile.getName() + JSONEXT);\r
+               File jsonFile = jsonFilePath.toFile();\r
+               if (!jsonFile.exists()) {\r
+                       logger.warn("{} has no json metadata.", mediaFile.getName());\r
+                       return false;\r
+               }\r
+\r
+               ArchiveItem archiveItem = createArchiveItem(jsonFilePath, mediaFilePath, catchedFilePath);\r
+\r
+               if (archiveItem == null) {\r
+                       logger.warn("{} has no metadata specified.", mediaFile.getName());\r
+                       return false;\r
+               }\r
+\r
+               if (StringUtils.isBlank(archiveItem.getItemHouseId())) {\r
+                       logger.warn("{} has no Item HouseID specified in metadata.", mediaFile.getName());\r
+                       return false;\r
+               }\r
+\r
+               if (StringUtils.isBlank(archiveItem.getItemTitle())) {\r
+                       logger.warn("{} has no Item Title specified in metadata.", mediaFile.getName());\r
+                       return false;\r
+               }\r
+\r
+               if (StringUtils.isBlank(archiveItem.getMediaHouseId())) {\r
+                       logger.warn("{} has no Media HouseID specified in metadata.", mediaFile.getName());\r
+                       return false;\r
+               }\r
+\r
+               if (StringUtils.isBlank(archiveItem.getMediaTitle())) {\r
+                       logger.warn("{} has no Media Title specified in metadata.", mediaFile.getName());\r
+                       return false;\r
+               }\r
+\r
+               // A tenyleges archivalast vesszuk elore\r
+               if (mediaFile.length() == 0)\r
+                       archiveList.add(archiveItem);\r
+               else\r
+                       archiveList.add(0, archiveItem);\r
+               // createCatchedFile(catchedFilePath);\r
+               return true;\r
+       }\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/ArchiveMaterialSubmitStep.java b/server/-product/production/HIRTV/jobs/steps/ArchiveMaterialSubmitStep.java
new file mode 100644 (file)
index 0000000..9a869ab
--- /dev/null
@@ -0,0 +1,55 @@
+package user.jobengine.server.steps;\r
+\r
+import java.io.File;\r
+import java.util.List;\r
+\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+import org.apache.logging.log4j.Marker;\r
+\r
+import user.commons.ListUtils;\r
+import user.jobengine.server.IJobEngine;\r
+import user.jobengine.server.IJobRuntime;\r
+\r
+public class ArchiveMaterialSubmitStep extends JobStep {\r
+       private static final Logger logger = LogManager.getLogger();\r
+       private static final String JOBTEMPLATE = "archive-material.xml";\r
+       private static final String KILL_DATE_DAYS = "killDateDays";\r
+       private static final String ARCHIVE = "Archiválás";\r
+       private static final String ARCHIVE_ITEM = "archiveItem";\r
+       private Marker marker;\r
+\r
+       @StepEntry\r
+       public Object[] execute(List<ArchiveItem> archiveList, int killDateDays, IJobEngine jobEngine,\r
+                       IJobRuntime jobRuntime) throws Exception {\r
+               marker = jobRuntime.getSessionMarker();\r
+               if (archiveList == null || archiveList.size() == 0)\r
+                       return null;\r
+\r
+               if (jobRuntime.forkPrepare()) {\r
+                       for (int i = 0; i < archiveList.size(); i++) {\r
+                               ArchiveItem archiveItem = archiveList.get(i);\r
+                               try {\r
+                                       IJobRuntime runtime = jobEngine.submit(jobRuntime, null, JOBTEMPLATE, ARCHIVE,\r
+                                                       ListUtils.asMap(ARCHIVE_ITEM, archiveItem, KILL_DATE_DAYS, killDateDays));\r
+                                       int progress = (i + 1) * 100 / archiveList.size();\r
+                                       setProgress(progress);\r
+                                       // TODO kivezetni a submit hibaüzenetet\r
+                                       if (runtime == null)\r
+                                               throw new Exception("Submit returned null runtime");\r
+                               } catch (Exception e) {\r
+                                       logger.catching(e);\r
+                                       String fileName = new File(archiveItem.getMediaFile()).getName();\r
+                                       logger.error(marker, "A(z) '{}' állomány archiválási kísérlete sikertelen. A rendszer üzenete: {}",\r
+                                                       fileName, e.getMessage());\r
+                                       if (!archiveItem.removeCatchedFile())\r
+                                               logger.error(marker, "A(z) '{}' állomány .catched jelző állománya nem törölhető.", fileName);\r
+                                       throw e;\r
+                               }\r
+                       }\r
+               }\r
+               jobRuntime.forkWaitComplete();\r
+               return null;\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/BackupFileStep.java b/server/-product/production/HIRTV/jobs/steps/BackupFileStep.java
new file mode 100644 (file)
index 0000000..396fd24
--- /dev/null
@@ -0,0 +1,122 @@
+package user.jobengine.server.steps;\r
+\r
+import java.io.IOException;\r
+import java.nio.file.DirectoryStream;\r
+import java.nio.file.Files;\r
+import java.nio.file.Path;\r
+import java.nio.file.Paths;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.apache.commons.lang.RandomStringUtils;\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+import org.apache.logging.log4j.Marker;\r
+import org.apache.logging.log4j.message.Message;\r
+import org.apache.logging.log4j.message.ParameterizedMessage;\r
+\r
+import user.commons.RemoteFile;\r
+import user.commons.StoreUri;\r
+import user.commons.configuration.SystemConfiguration;\r
+import user.commons.remotestore.RemoteStoreProtocol;\r
+import user.jobengine.db.MediaFile;\r
+import user.jobengine.db.MediaFileDAO;\r
+import user.jobengine.db.Store;\r
+import user.jobengine.server.steps.shared.EscortFiles;\r
+\r
+public class BackupFileStep extends JobStep {\r
+       private static final Logger logger = LogManager.getLogger();\r
+       private static boolean RANDOMIZE_ARCHIVES = SystemConfiguration.getInstance().value("tsm.randomize-archives");\r
+       private Marker marker;\r
+       public static final String DOT_DONE = ".DONE";\r
+       public static final String DOT_JSON = ".json";\r
+\r
+       MediaFile getMediaFile(String fileName) {\r
+               List<MediaFile> result = new ArrayList<>();\r
+               MediaFileDAO dao = (MediaFileDAO) getManager().getBaseDAO(MediaFile.class);\r
+               getManager().executeQuery("SELECT id FROM MEDIAFILE WHERE relativepath=?", rs -> {\r
+                       long id = rs.getLong("id");\r
+                       result.add((MediaFile) dao.get(id));\r
+                       return false;\r
+               }, s -> {\r
+                       s.setString(1, fileName);\r
+               });\r
+\r
+               return result.size() > 0 ? result.get(0) : null;\r
+       }\r
+\r
+       String flag(Object checkObject) {\r
+               return checkObject == null ? "-" : "X";\r
+       }\r
+\r
+       @StepEntry\r
+       public Object[] execute() throws Exception {\r
+               marker = getSessionMarker();\r
+\r
+               Path sourceFolder = Paths.get("/mnt/ISILON/ARCHIVE/.CONFLICT");\r
+               Path donePath = Paths.get(sourceFolder.toString(), DOT_DONE);\r
+               Store tsmStore = getManager().getSystemStore(false);\r
+               StoreUri tsmUri = tsmStore.getSourceStoreUri(RemoteStoreProtocol.TSM);\r
+\r
+               try (DirectoryStream<Path> stream = Files.newDirectoryStream(sourceFolder)) {\r
+                       for (Path source : stream) {\r
+                               if (Files.isDirectory(source)) {\r
+                                       continue;\r
+                               }\r
+\r
+                               String fileName = source.getFileName().toString();\r
+                               if (fileName.toLowerCase().endsWith(".mxf") || fileName.toLowerCase().endsWith(".mp4")) {\r
+\r
+                                       MediaFile mf = getMediaFile(fileName);\r
+                                       RemoteFile tsmFile = tsmUri.getRemoteFile(fileName);\r
+                                       logger.info(marker, "[{}{}] {}", flag(mf), flag(tsmFile), fileName);\r
+                                       if (getJobRuntime().isWaitingCancel())\r
+                                               break;\r
+\r
+                                       if (tsmFile == null) {\r
+                                               backup(source, tsmUri);\r
+                                               tsmFile = tsmUri.getRemoteFile(fileName);\r
+                                       }\r
+\r
+                                       if (mf != null && tsmFile != null) {\r
+                                               moveToDone(donePath, source, fileName);\r
+                                       }\r
+                               }\r
+                       }\r
+               } finally {\r
+                       tsmUri.cleanUp();\r
+               }\r
+\r
+               return null;\r
+       }\r
+\r
+       private void moveToDone(Path donePath, Path source, String fileName) throws IOException {\r
+               EscortFiles.ensureUNCFolder(donePath);\r
+               Files.move(source, Paths.get(donePath.toString(), fileName));\r
+               Path json = Paths.get(source.getParent().toString(), fileName + DOT_JSON);\r
+               Files.move(json, Paths.get(donePath.toString(), fileName + DOT_JSON));\r
+       }\r
+\r
+       private void backup(Path source, StoreUri targetUri) throws Exception {\r
+               String sourceFileName = source.getFileName().toString();\r
+               try {\r
+                       getJobRuntime().setDescription(sourceFileName);\r
+\r
+                       StoreUri sourceUri = getManager().createStoreUri(RemoteStoreProtocol.LOCAL, source.getParent().toString());\r
+                       String targetFileName;\r
+                       if (RANDOMIZE_ARCHIVES) {\r
+                               targetFileName = String.format("%s-%s", RandomStringUtils.randomAlphanumeric(8), sourceFileName);\r
+                       } else\r
+                               targetFileName = sourceFileName;\r
+\r
+                       RemoteFile remoteFile = sourceUri.transferFrom(targetUri, sourceFileName, targetFileName);\r
+\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       Message m = new ParameterizedMessage("Az '{}' állomány archiválása sikertelen. A rendszer hibaüzenete: {}", sourceFileName, e.getMessage());\r
+                       logger.error(marker, m);\r
+                       throw new Exception(m.getFormattedMessage());\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/BatchRetrieveForkStep.java b/server/-product/production/HIRTV/jobs/steps/BatchRetrieveForkStep.java
new file mode 100644 (file)
index 0000000..a531a2e
--- /dev/null
@@ -0,0 +1,78 @@
+package user.jobengine.server.steps;\r
+\r
+import java.util.List;\r
+import java.util.Map;\r
+\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+\r
+import user.commons.log4j2.marker.MediaCubeFinishMarker;\r
+import user.commons.log4j2.marker.MediaCubeMarker;\r
+import user.jobengine.db.ArchivedMedia;\r
+import user.jobengine.server.IJobEngine;\r
+import user.jobengine.server.IJobRuntime;\r
+import user.jobengine.server.scheduler.ScheduledJob;\r
+\r
+public class BatchRetrieveForkStep extends JobStep {\r
+       private static final String TARGET_PATH_TYPE = "targetPathType";\r
+       private static final Logger logger = LogManager.getLogger();\r
+       private static final String CHILD_TEMPLATE = "retrieve-ondemand.xml";\r
+       private static final String ARCHIVEDMEDIA = "archivedMedia";\r
+       private static final String RECIPIENT = "successRecipient";\r
+       private static final String HOUSEID = "houseId";\r
+       private MediaCubeMarker marker;\r
+\r
+       @StepEntry\r
+       public Object[] execute(List<ArchivedMedia> basket, String houseId, String recipient, String targetPathType,\r
+                       IJobEngine jobEngine, IJobRuntime jobRuntime) throws Exception {\r
+               marker = (MediaCubeMarker) jobRuntime.getSessionMarker();\r
+\r
+               // session szinten csak a finishMarker cimzettje az erdekes, es ezt a cimet\r
+               // pluszban hasznalja a konfigban megadott cimmel\r
+               // a finishMarker orokli a cim bellitast a sessionMarkertol\r
+               marker.setTo(recipient);\r
+\r
+               ((MediaCubeMarker) jobRuntime.getFinishMarker()).setTo(recipient);\r
+\r
+               if (basket == null || basket.size() == 0)\r
+                       return null;\r
+               setProgress(10);\r
+\r
+               MediaCubeMarker mailMarker = new MediaCubeMarker(recipient);\r
+               mailMarker.setSessionName("Archívum viszatöltés");\r
+               mailMarker.setSessionID(houseId);\r
+               logger.info(mailMarker, "A visszatöltések elindultak az alábbi állományokra:");\r
+\r
+               if (jobRuntime.forkPrepare()) {\r
+                       for (ArchivedMedia archivedMedia : basket) {\r
+                               logger.info(mailMarker, archivedMedia.getMedia().getMediaFilesName());\r
+                               submit(archivedMedia, recipient, houseId, targetPathType, jobEngine, jobRuntime);\r
+                       }\r
+               }\r
+               setProgress(50);\r
+               logger.info(new MediaCubeFinishMarker(mailMarker), "A visszatöltések végeztével megerősítő üzenetet küldünk.");\r
+               jobRuntime.forkWaitComplete();\r
+               setProgress(100);\r
+               return null;\r
+       }\r
+\r
+       public void submit(ArchivedMedia archivedMedia, String recipient, String houseId, String targetPathType,\r
+                       IJobEngine jobEngine, IJobRuntime jobRuntime) throws Exception {\r
+               try {\r
+                       ScheduledJob scheduledJob = jobEngine.getScheduledJob(CHILD_TEMPLATE);\r
+                       Map<String, Object> parameters = scheduledJob.getJobParameters();\r
+                       parameters.put(ARCHIVEDMEDIA, archivedMedia);\r
+                       parameters.put(HOUSEID, houseId);\r
+                       parameters.put(RECIPIENT, recipient);\r
+                       parameters.put(TARGET_PATH_TYPE, targetPathType);\r
+                       IJobRuntime child = jobEngine.submit(jobRuntime, null, CHILD_TEMPLATE,\r
+                                       String.format("Visszatöltés %s részére", recipient), parameters);\r
+                       ((MediaCubeMarker) child.getSessionMarker()).setTo(recipient);\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       logger.error(marker, "Hiba a kötegelt visszatöltésben. A rendszer üzenete: {}", e.getMessage());\r
+               }\r
+\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/CancelableStep.java b/server/-product/production/HIRTV/jobs/steps/CancelableStep.java
new file mode 100644 (file)
index 0000000..b830e15
--- /dev/null
@@ -0,0 +1,22 @@
+package user.jobengine.server.steps;\r
+\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+\r
+public class CancelableStep extends JobStep {\r
+       private static final Logger logger = LogManager.getLogger();\r
+\r
+       @StepEntry\r
+       public Object[] execute(int param) throws Exception {\r
+               logger.info(getMarker(), "Executing with param {}", param);\r
+               for (int i = 0; i < 10; i++) {\r
+                       if (getJobRuntime().isWaitingCancel())\r
+                               break;\r
+                       Thread.sleep(10);\r
+                       int progress = (i + 1) * 100 / 10;\r
+                       setProgress(progress);\r
+               }\r
+               return null;\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/CheckLOWRESIntegrity.java b/server/-product/production/HIRTV/jobs/steps/CheckLOWRESIntegrity.java
new file mode 100644 (file)
index 0000000..373545e
--- /dev/null
@@ -0,0 +1,66 @@
+package user.jobengine.server.steps;\r
+\r
+import java.nio.file.Path;\r
+import java.nio.file.Paths;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+import org.apache.logging.log4j.Marker;\r
+\r
+import user.jobengine.db.IItemManager;\r
+import user.jobengine.db.IResultSetConsumer;\r
+import user.jobengine.db.Media;\r
+import user.jobengine.db.MediaFile;\r
+import user.jobengine.server.IJobEngine;\r
+import user.jobengine.server.IJobRuntime;\r
+\r
+public class CheckLOWRESIntegrity extends JobStep {\r
+       private static final Logger logger = LogManager.getLogger();\r
+       private IItemManager manager;\r
+       private Marker marker;\r
+       private String webPath;\r
+\r
+       private void checkIntegrity(MediaFile mediaFile) {\r
+               Path path = Paths.get(webPath, mediaFile.getRelativePath());\r
+               if (!path.toFile().exists()) {\r
+                       logger.warn(marker, "{} {}", mediaFile.getId(), path);\r
+               }\r
+       }\r
+\r
+       @StepEntry\r
+       public Object[] execute(String webPath, IJobEngine jobEngine, IJobRuntime jobRuntime) throws Exception {\r
+               this.webPath = webPath;\r
+               marker = jobRuntime.getSessionMarker();\r
+               manager = jobEngine.getItemManager();\r
+               List<Long> mediaIdentities = getTranscodedMediaIdentities();\r
+               int allCount = mediaIdentities.size();\r
+               int currentCount = 0;\r
+               for (long id : mediaIdentities) {\r
+                       Media media = manager.getMedia(id);\r
+                       List<MediaFile> mediaFiles = media.getMediaFiles();\r
+                       for (MediaFile mediaFile : mediaFiles) {\r
+                               if (mediaFile.getStoreId() == 21)\r
+                                       checkIntegrity(mediaFile);\r
+                       }\r
+                       currentCount++;\r
+                       jobRuntime.incrementProgress(currentCount * 100 / allCount);\r
+               }\r
+               return null;\r
+       }\r
+\r
+       public List<Long> getTranscodedMediaIdentities() {\r
+               final List<Long> result = new ArrayList<>();\r
+               String query = "select mediaid from vw_mediafiles where mediafilecount = 2";\r
+\r
+               IResultSetConsumer consumer = rs -> {\r
+                       result.add(rs.getLong("mediaId"));\r
+                       return true;\r
+               };\r
+\r
+               manager.executeQuery(query, consumer, null);\r
+               return result;\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/CheckMORPHEUSMissingMaterialsStep.java b/server/-product/production/HIRTV/jobs/steps/CheckMORPHEUSMissingMaterialsStep.java
new file mode 100644 (file)
index 0000000..d28a108
--- /dev/null
@@ -0,0 +1,155 @@
+package user.jobengine.server.steps;\r
+\r
+import java.io.File;\r
+import java.io.IOException;\r
+import java.nio.charset.Charset;\r
+import java.nio.file.DirectoryStream;\r
+import java.nio.file.Files;\r
+import java.nio.file.Path;\r
+import java.nio.file.Paths;\r
+import java.util.Arrays;\r
+import java.util.List;\r
+\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+\r
+import user.commons.IEntityBase;\r
+import user.commons.ListUtils;\r
+import user.jobengine.db.IItemManager;\r
+import user.jobengine.db.MediaFile;\r
+import user.jobengine.db.MediaFileDAO;\r
+import user.jobengine.server.IJobEngine;\r
+import user.jobengine.server.IJobRuntime;\r
+\r
+public class CheckMORPHEUSMissingMaterialsStep extends JobStep {\r
+       private static final Logger logger = LogManager.getLogger();\r
+       private static final String KILLDATEDAYS = "killDateDays";\r
+       private static final String SUCCESSRECIPIENT = "successRecipient";\r
+       private static final String TARGETNAMEPATTERN = "targetNamePattern";\r
+       private static final String MATERIAL_ID = "Material ID";\r
+       private static final String RETRIEVE_MATERIAL = "Adásanyag visszatöltés";\r
+       private static final String TARGETPATH = "targetPath";\r
+       private static final String MEDIACUBEMEDIA = "mediaCubeMedia";\r
+       private static final String JOBTEMPLATE = "retrieve-material.xml";\r
+       private static final String CSV_EXT = ".csv";\r
+       private static final String MXF_EXT = ".MXF";\r
+       private String targetPath;\r
+       private MediaFileDAO dao;\r
+       private IJobEngine jobEngine;\r
+       private int killDateDays;\r
+\r
+       @StepEntry\r
+       public Object[] execute(String sourcePath, String targetPath, int killDateDays, IJobEngine jobEngine,\r
+                       IJobRuntime jobRuntime) throws Exception {\r
+               this.killDateDays = killDateDays;\r
+               setAndCheck(sourcePath, targetPath, jobEngine);\r
+               DirectoryStream<Path> directoryStream = null;\r
+               try {\r
+                       Files.newDirectoryStream(Paths.get(sourcePath)).forEach(p -> processPathItem(p));\r
+               } catch (Exception e) {\r
+                       logger.error("", e);\r
+               } finally {\r
+                       if (directoryStream != null) {\r
+                               try {\r
+                                       directoryStream.close();\r
+                               } catch (IOException e) {\r
+                               }\r
+                       }\r
+               }\r
+               return null;\r
+       }\r
+\r
+       private void processMediaId(String mediaId) throws Exception {\r
+               List<IEntityBase> medias = dao.getByHouseId(mediaId + ".MXF");\r
+               if (medias == null || medias.size() == 0) {\r
+                       logger.error(getMarker(), "A(z) {} anyag nem található az archívumban.", mediaId);\r
+                       return;\r
+               }\r
+\r
+               if (medias.size() > 1) {\r
+                       logger.error(getMarker(), "A(z) {} anyagból egynél több található az archívumban.", mediaId);\r
+                       return;\r
+               }\r
+\r
+               jobEngine.submit(JOBTEMPLATE, RETRIEVE_MATERIAL, ListUtils.asMap(MEDIACUBEMEDIA, medias.get(0), TARGETPATH, targetPath, TARGETNAMEPATTERN,\r
+                               mediaId + MXF_EXT, SUCCESSRECIPIENT, null, KILLDATEDAYS, killDateDays));\r
+       }\r
+\r
+       private void processMissingMaterialCSV(Path csvFilePath) throws Exception {\r
+               List<String> lines = Files.readAllLines(csvFilePath, Charset.forName("UTF-8"));\r
+               if (lines == null | lines.size() == 0) {\r
+                       return;\r
+               }\r
+\r
+               int mediaIdPosition = -1;\r
+               for (int i = 0; i < lines.size(); i++) {\r
+                       String line = lines.get(i);\r
+                       if (line == null)\r
+                               continue;\r
+                       String[] data = line.split(",");\r
+                       if (i == 0) {\r
+                               // Channel,Time to Air,Duration,Material ID,Title,Device ID,Reason,\r
+                               List<String> dataList = Arrays.asList(data);\r
+                               mediaIdPosition = dataList.indexOf(MATERIAL_ID);\r
+                               if (mediaIdPosition < 0) {\r
+                                       logger.error(getMarker(), "A(z) {} MORPHEUS állományban nem található a 'Material ID' mező.",\r
+                                                       csvFilePath.toFile().getName());\r
+                                       break;\r
+                               }\r
+                       } else {\r
+                               processMediaId(data[mediaIdPosition]);\r
+                       }\r
+               }\r
+       }\r
+\r
+       private void processPathItem(Path csvFilePath) {\r
+               File csvFile = csvFilePath.toFile();\r
+\r
+               if (csvFile.isDirectory() || !csvFile.getName().toLowerCase().endsWith(CSV_EXT.toLowerCase())) {\r
+                       return;\r
+               }\r
+\r
+               try {\r
+                       processMissingMaterialCSV(csvFilePath);\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       logger.error(getMarker(),\r
+                                       "A(z) {} MORPHEUS állomány feldolgozásakor hiba történt. A rendszer hibaüzenete: {}.",\r
+                                       csvFile.getName(), e.getMessage());\r
+               }\r
+\r
+               // TODO ne törölje, move\r
+               // if (!csvFile.delete())\r
+               // logger.error(getMarker(), "A {} MORPHEUS állomány nem törölhető.",\r
+               // csvFile.getName());\r
+       }\r
+\r
+       private void setAndCheck(String sourcePath, String targetPath, IJobEngine jobEngine) {\r
+               if (jobEngine == null) {\r
+                       logger.error(getMarker(), "Az folyamatkezelő réteg nem elérhető.");\r
+                       throw new NullPointerException("Internal error, missing JobEngine reference.");\r
+               }\r
+               this.jobEngine = jobEngine;\r
+\r
+               IItemManager manager = jobEngine.getItemManager();\r
+               if (manager == null) {\r
+                       logger.error(getMarker(), "Az adatbáziskezelő réteg nem elérhető.");\r
+                       throw new NullPointerException("Internal error, missing ItemManager reference.");\r
+               }\r
+               dao = (MediaFileDAO) manager.getBaseDAO(MediaFile.class);\r
+               if (dao == null) {\r
+                       logger.error(getMarker(), "Az adatbáziskezelő réteg MediaFile kezelöje nem elérhető.");\r
+                       throw new NullPointerException("Internal error, missing MediaFile DAO reference.");\r
+               }\r
+               if (sourcePath == null) {\r
+                       logger.error(getMarker(), "A folyamat 'sourcePath' bemeneti paramétere üres.");\r
+                       throw new NullPointerException("System is not configured properly, 'sourcePath' input parameter missing.");\r
+               }\r
+               if (targetPath == null) {\r
+                       logger.error(getMarker(), "A folyamat 'targetPath' bemeneti paramétere üres.");\r
+                       throw new NullPointerException("System is not configured properly, 'targetPath' input parameter missing.");\r
+               }\r
+               this.targetPath = targetPath;\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/CheckTRAFFICMissingMaterialsStep.java b/server/-product/production/HIRTV/jobs/steps/CheckTRAFFICMissingMaterialsStep.java
new file mode 100644 (file)
index 0000000..87fca79
--- /dev/null
@@ -0,0 +1,97 @@
+package user.jobengine.server.steps;\r
+\r
+import java.sql.Connection;\r
+import java.sql.DriverManager;\r
+import java.sql.PreparedStatement;\r
+import java.sql.ResultSet;\r
+import java.util.List;\r
+\r
+import org.apache.commons.lang.StringUtils;\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+\r
+import user.commons.IEntityBase;\r
+import user.commons.ListUtils;\r
+import user.jobengine.db.IItemManager;\r
+import user.jobengine.db.MediaFile;\r
+import user.jobengine.db.MediaFileDAO;\r
+import user.jobengine.server.IJobEngine;\r
+import user.jobengine.server.IJobRuntime;\r
+\r
+public class CheckTrafficMissingMaterialsStep extends JobStep {\r
+       private static final String KILLDATEDAYS = "killDateDays";\r
+       private static final Logger logger = LogManager.getLogger();\r
+       private static final String TARGET_NAME_PATTERN = "targetNamePattern";\r
+       private static final String TARGET_PATH = "targetPath";\r
+       private static final String MEDIA_CUBE_MEDIA = "mediaCubeMedia";\r
+       private static final String SQLSERVER_JDBC_SQL_SERVER_DRIVER = "com.microsoft.sqlserver.jdbc.SQLServerDriver";\r
+       private static final String SQL = "{call dbo.clIFsp_EC_MAM(1001, 32, Null,  Null, ?)}";\r
+       private static final String JOBTEMPLATE = "retrieve-material.xml";\r
+       private static final String SUCCESSRECIPIENT = "successRecipient";\r
+       private int killDateDays;\r
+\r
+       @StepEntry\r
+       public Object[] execute(String dbUrl, String userName, String password, int lookupDays, String targetPath,\r
+                       int killDateDays, IJobEngine jobEngine, IJobRuntime jobRuntime) throws Exception {\r
+\r
+               this.killDateDays = killDateDays;\r
+               try (Connection con = getConnection(dbUrl, userName, password);\r
+                               PreparedStatement stmt = con.prepareStatement(SQL)) {\r
+                       stmt.setInt(1, lookupDays);\r
+                       try (ResultSet rs = stmt.executeQuery()) {\r
+                               while (rs.next()) {\r
+                                       String trafficId = rs.getString(5);\r
+                                       if (StringUtils.isBlank(trafficId))\r
+                                               continue;\r
+\r
+                                       try {\r
+                                               processTrafficId(trafficId, targetPath, jobEngine);\r
+                                       } catch (Exception e) {\r
+                                               logger.error(getMarker(),\r
+                                                               "Hiba lépett fel az {} anyag visszatöltéskor. A rendszer hibaüzenete: {}", trafficId,\r
+                                                               e.getMessage());\r
+                                       }\r
+\r
+                               }\r
+                       }\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       throw e;\r
+               } finally {\r
+               }\r
+               return null;\r
+       }\r
+\r
+       private Connection getConnection(String dbUrl, String userName, String password) throws Exception {\r
+               Connection result = null;\r
+               try {\r
+                       Class.forName(SQLSERVER_JDBC_SQL_SERVER_DRIVER);\r
+                       result = DriverManager.getConnection(dbUrl, userName, password);\r
+               } catch (Exception e) {\r
+                       logger.error(getMarker(), "Hiba lépett fel a folyamat indításakor. A rendszer hibaüzenete: {}",\r
+                                       e.getMessage());\r
+                       throw e;\r
+               }\r
+               return result;\r
+       }\r
+\r
+       private void processTrafficId(String trafficId, String targetPath, IJobEngine jobEngine) throws Exception {\r
+               IItemManager manager = jobEngine.getItemManager();\r
+               MediaFileDAO dao = (MediaFileDAO) manager.getBaseDAO(MediaFile.class);\r
+               List<IEntityBase> medias = dao.getByHouseId(trafficId);\r
+               if (medias == null || medias.size() == 0) {\r
+                       logger.error(getMarker(), "Az {} anyag nem található az archívumban.", trafficId);\r
+                       return;\r
+               }\r
+\r
+               if (medias.size() > 1) {\r
+                       logger.error(getMarker(), "Az {} anyagból egynél több található az archívumban.", trafficId);\r
+                       return;\r
+               }\r
+\r
+               String title = "Traffic adásanyag visszatöltés: " + trafficId;\r
+               jobEngine.submit(JOBTEMPLATE, title, ListUtils.asMap(MEDIA_CUBE_MEDIA, medias.get(0), TARGET_PATH, targetPath, TARGET_NAME_PATTERN, "%s",\r
+                               SUCCESSRECIPIENT, null, KILLDATEDAYS, killDateDays));\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/CleanupMountedLocationStep.java b/server/-product/production/HIRTV/jobs/steps/CleanupMountedLocationStep.java
new file mode 100644 (file)
index 0000000..d674c61
--- /dev/null
@@ -0,0 +1,296 @@
+package user.jobengine.server.steps;\r
+\r
+import java.io.File;\r
+import java.io.IOException;\r
+import java.nio.file.DirectoryStream;\r
+import java.nio.file.FileVisitResult;\r
+import java.nio.file.FileVisitor;\r
+import java.nio.file.Files;\r
+import java.nio.file.Path;\r
+import java.nio.file.Paths;\r
+import java.nio.file.SimpleFileVisitor;\r
+import java.nio.file.attribute.BasicFileAttributes;\r
+import java.text.ParseException;\r
+import java.text.SimpleDateFormat;\r
+import java.util.ArrayList;\r
+import java.util.Collections;\r
+import java.util.Date;\r
+import java.util.List;\r
+\r
+import org.apache.commons.io.FileUtils;\r
+import org.apache.commons.lang.StringUtils;\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+import org.apache.logging.log4j.Marker;\r
+\r
+import user.jobengine.server.steps.shared.ItemManagerExtensions;\r
+\r
+public class CleanupMountedLocationStep extends JobStep implements FileVisitor<Path> {\r
+\r
+       private static final Logger logger = LogManager.getLogger();\r
+       private static final String PROJECTFOLDER = "PROJECT";\r
+       private static final String DATEFORMAT = "yyyyMMdd";\r
+       private static final String DOT = ".";\r
+       private static final String STATUSFOLDER = ".STATUS";\r
+       private static final String EWC2EXT = ".ewc2";\r
+       private static final String XMPEXT = ".xmp";\r
+       private static final String CATCHEDEXT = ".catched";\r
+       private static final String KILLDATEEXT = ".killdate";\r
+       private static final String JSONEXT = ".json";\r
+\r
+       private static boolean isEmpty(final Path directory) throws IOException {\r
+               try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(directory)) {\r
+                       final int[] count = new int[] { 0 };\r
+                       final int[] specialCount = new int[] { 0 };\r
+                       dirStream.forEach(p -> {\r
+                               count[0]++;\r
+                               // if\r
+                               // (p.getFileName().toString().toLowerCase().equals(PROJECTFOLDER.toLowerCase()))\r
+                               // specialCount[0]++;\r
+                               if (p.getFileName().toString().toLowerCase().equals(STATUSFOLDER.toLowerCase()))\r
+                                       specialCount[0]++;\r
+\r
+                       });\r
+                       if (specialCount[0] == count[0])\r
+                               return true;\r
+               }\r
+               return false;\r
+       }\r
+\r
+       private Marker marker;\r
+\r
+       final int[] allCount = new int[] { 0 };\r
+       final int[] currentCount = new int[] { 0 };\r
+\r
+       private Path sourcePath;\r
+       private SimpleDateFormat dateFormat;\r
+       private boolean skipArchiveCheck;\r
+\r
+       private Date checkExpiration(List<Path> killDateFiles) {\r
+               Date killDate = null;\r
+               for (Path killDateFile : killDateFiles) {\r
+                       Date currentKillDate = getKillDate(killDateFile);\r
+                       if (currentKillDate == null)\r
+                               continue;\r
+                       if ((killDate != null && currentKillDate.after(killDate)) || killDate == null)\r
+                               killDate = currentKillDate;\r
+               }\r
+               return new Date().after(killDate) ? killDate : null;\r
+       }\r
+\r
+       @StepEntry\r
+       public Object[] execute(String sourceFolder, boolean skipArchiveCheck) throws Exception {\r
+               this.skipArchiveCheck = skipArchiveCheck;\r
+               marker = getSessionMarker();\r
+               sourcePath = Paths.get(sourceFolder);\r
+               DirectoryStream<Path> directoryStream = null;\r
+               if (StringUtils.isBlank(sourcePath.toString())) {\r
+                       logger.error(marker, "A folyamat 'sourcePath' bemeneti paramétere üres.");\r
+                       throw new NullPointerException(\r
+                                       "System is not configured properly, 'sourceFolder' input parameter missing.");\r
+               }\r
+\r
+               if (!sourcePath.toFile().exists() || !sourcePath.toFile().isDirectory()) {\r
+                       logger.error(marker, "A(z) {} mappa nem létezik.", sourceFolder);\r
+                       throw new NullPointerException(String.format("Directory %s does not exist.", sourceFolder));\r
+               }\r
+\r
+               try {\r
+                       setProgress(1);\r
+                       dateFormat = new SimpleDateFormat(DATEFORMAT);\r
+\r
+                       Files.walkFileTree(sourcePath, new SimpleFileVisitor<Path>() {\r
+                               @Override\r
+                               public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {\r
+                                       allCount[0]++;\r
+                                       return super.visitFile(file, attrs);\r
+                               }\r
+                       });\r
+                       Files.walkFileTree(sourcePath, this);\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       logger.error(marker, "Hiba a '{}' mappa feldolgozásában. A rendszer hibaüzenete: {}", sourcePath,\r
+                                       e.getMessage());\r
+                       throw e;\r
+               } finally {\r
+                       if (directoryStream != null) {\r
+                               try {\r
+                                       directoryStream.close();\r
+                               } catch (IOException e) {\r
+                               }\r
+                       }\r
+               }\r
+               return null;\r
+       }\r
+\r
+       private Date getKillDate(Path killDateFile) {\r
+               String fileName = killDateFile.getFileName().toString();\r
+               int end = fileName.lastIndexOf(DOT);\r
+               if (end < 1)\r
+                       return null;\r
+               int start = fileName.lastIndexOf(DOT, end - 1);\r
+               if (start < 0)\r
+                       return null;\r
+               String strKillDate = fileName.substring(start + 1, end);\r
+               Date result = null;\r
+               if (StringUtils.isNumeric(strKillDate)) {\r
+                       try {\r
+                               result = dateFormat.parse(strKillDate);\r
+                       } catch (ParseException e) {\r
+                               logger.error(marker,\r
+                                               "A {} fájl 'killdate' állománya hibás formátumú, a {} karaktersorozat nem konvertálható dátummá.",\r
+                                               fileName, strKillDate);\r
+                               return null;\r
+                       }\r
+               } else\r
+                       logger.error(marker, "A {} fájl 'killdate' állománya hibás formátumú, az dátum helyett ez áll: '{}'.",\r
+                                       fileName, strKillDate);\r
+               return result;\r
+       }\r
+\r
+       private List<Path> getKillDateFiles(Path filePath) {\r
+               String killDateFilePattern = String.format("%s.*%s", filePath.getFileName().toString(), KILLDATEEXT);\r
+               List<Path> result = new ArrayList<>();\r
+               Path statusPath = null;\r
+               try {\r
+                       statusPath = Paths.get(filePath.getParent().toString(), STATUSFOLDER);\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       return null;\r
+               }\r
+               File statusPathFile = statusPath.toFile();\r
+               if (statusPathFile.exists() && statusPathFile.isDirectory()) {\r
+                       try (DirectoryStream<Path> stream = Files.newDirectoryStream(statusPath, killDateFilePattern)) {\r
+                               stream.forEach(p -> result.add(p));\r
+                       } catch (Exception e) {\r
+                               logger.catching(e);\r
+                       }\r
+               }\r
+               Collections.sort(result);\r
+               return result;\r
+       }\r
+\r
+       @Override\r
+       public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {\r
+               if (!dir.equals(sourcePath) && isEmpty(dir)) {\r
+                       if (!removeExistingSpecialDirectory(dir, PROJECTFOLDER))\r
+                               return FileVisitResult.CONTINUE;\r
+                       if (!removeExistingSpecialDirectory(dir, STATUSFOLDER))\r
+                               return FileVisitResult.CONTINUE;\r
+                       if (removeFile(dir))\r
+                               logger.info(marker, "A {} üres mappa törlése sikeres.", dir);\r
+\r
+               }\r
+               return FileVisitResult.CONTINUE;\r
+       }\r
+\r
+       @Override\r
+       public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {\r
+\r
+               // A .-al kezdodo mappakat kihagyjuk\r
+               if (dir.getFileName().toString().startsWith("."))\r
+                       return FileVisitResult.SKIP_SUBTREE;\r
+\r
+               return FileVisitResult.CONTINUE;\r
+       }\r
+\r
+       private void processPathItem(Path filePath) {\r
+               currentCount[0]++;\r
+\r
+               if (filePath.getFileName().toString().startsWith("."))\r
+                       return;\r
+\r
+               int progress = currentCount[0] * 100 / allCount[0];\r
+               setProgress(progress);\r
+\r
+               logger.info("Checking {}", filePath);\r
+               List<Path> killDateFiles = getKillDateFiles(filePath);\r
+               if (killDateFiles == null || killDateFiles.size() == 0) {\r
+                       logger.warn(marker, "A {} fájlhoz nem található 'killdate' állomány.", filePath);\r
+                       return;\r
+               }\r
+\r
+               if (killDateFiles.size() != 1)\r
+                       logger.warn(marker,\r
+                                       "A {} fájlhoz több 'killdate' állomány található, a legújabb dátum határozza meg a törlés időpontját.",\r
+                                       filePath);\r
+\r
+               Date killDate = checkExpiration(killDateFiles);\r
+               if (killDate == null)\r
+                       return;\r
+\r
+               if (!skipArchiveCheck && filePath.toFile().length() > 0) {\r
+                       if (!ItemManagerExtensions.isArchived(getManager(), filePath)) {\r
+                               logger.error(marker, "A(z) {} anyag törlésre van kijelölve, de nem található az archívumban.",\r
+                                               filePath);\r
+                               return;\r
+                       }\r
+               }\r
+\r
+               if (removeFiles(filePath, killDateFiles))\r
+                       logger.info(marker,\r
+                                       "A {} fájl és kapcsolódó állományai a {} killdate bejegyzés alapján sikeresen törlődtek.",\r
+                                       filePath.getFileName(), dateFormat.format(killDate));\r
+               else\r
+                       logger.warn(marker,\r
+                                       "A {} fájl és kapcsolódó állományai a {} killdate bejegyzés alapján csak részlegesen vagy egyáltalán nem törlődtek.",\r
+                                       filePath.getFileName(), dateFormat.format(killDate));\r
+       }\r
+\r
+       private boolean removeExistingSpecialDirectory(Path dir, String folderName) throws IOException {\r
+               File projectPath = Paths.get(dir.toString(), folderName).toFile();\r
+               if (projectPath.exists() && projectPath.isDirectory()) {\r
+                       FileUtils.deleteDirectory(projectPath);\r
+                       if (projectPath.exists()) {\r
+                               logger.warn(marker, "A {} alatti {} mappa törlése nem sikerült.", dir, folderName);\r
+                               return false;\r
+                       }\r
+               }\r
+               return true;\r
+       }\r
+\r
+       private boolean removeFile(Path filePath) {\r
+               boolean result = false;\r
+               try {\r
+                       // logger.error("REMOVE {}", filePath);\r
+                       File file = filePath.toFile();\r
+                       if (file.exists())\r
+                               result = file.delete();\r
+               } catch (Exception e) {\r
+                       logger.error(marker, "A {} fájl nem törölhető. A rendszer hibaüzenete: {}", filePath, e.getMessage());\r
+               }\r
+               return result;\r
+       }\r
+\r
+       private boolean removeFiles(Path filePath, List<Path> killDateFiles) {\r
+               if (!removeFile(filePath))\r
+                       return false;\r
+\r
+               removeFile(Paths.get(filePath.toString() + EWC2EXT));\r
+               removeFile(Paths.get(filePath.toString() + XMPEXT));\r
+               removeFile(Paths.get(filePath.getParent().toString(), STATUSFOLDER,\r
+                               filePath.getFileName().toString() + CATCHEDEXT));\r
+               removeFile(\r
+                               Paths.get(filePath.getParent().toString(), STATUSFOLDER, filePath.getFileName().toString() + JSONEXT));\r
+\r
+               boolean result = true;\r
+               for (Path killDateFile : killDateFiles) {\r
+                       if (!removeFile(killDateFile))\r
+                               result = false;\r
+               }\r
+\r
+               return result;\r
+       }\r
+\r
+       @Override\r
+       public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {\r
+               processPathItem(file);\r
+               return FileVisitResult.CONTINUE;\r
+       }\r
+\r
+       @Override\r
+       public FileVisitResult visitFileFailed(Path file, IOException e) throws IOException {\r
+               logger.error(marker, "A {} fájl nem érhető el. A rendszer hibaüzenete: {}", file.toString(), e.getMessage());\r
+               return FileVisitResult.CONTINUE;\r
+       }\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/CopyForArchiveNEXIOMaterialsStep.java b/server/-product/production/HIRTV/jobs/steps/CopyForArchiveNEXIOMaterialsStep.java
new file mode 100644 (file)
index 0000000..0637fb3
--- /dev/null
@@ -0,0 +1,561 @@
+package user.jobengine.server.steps;\r
+\r
+import java.io.OutputStream;\r
+import java.net.InetAddress;\r
+import java.net.URI;\r
+import java.util.ArrayList;\r
+import java.util.Arrays;\r
+import java.util.Calendar;\r
+import java.util.Date;\r
+import java.util.List;\r
+\r
+import org.apache.commons.lang.StringUtils;\r
+import org.apache.commons.net.ftp.FTP;\r
+import org.apache.commons.net.ftp.FTPClient;\r
+import org.apache.commons.net.ftp.FTPReply;\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+import org.apache.logging.log4j.Marker;\r
+\r
+import com.ibm.nosql.json.api.BasicDBObject;\r
+import com.ibm.nosql.json.api.DB;\r
+import com.ibm.nosql.json.api.DBCollection;\r
+import com.ibm.nosql.json.api.DBCursor;\r
+import com.ibm.nosql.json.api.DBObject;\r
+\r
+import user.commons.CalendarUtils;\r
+import user.commons.ListUtils;\r
+import user.commons.StoreUri;\r
+import user.commons.configuration.SystemConfiguration;\r
+import user.commons.nosql.NoSQLUtils;\r
+import user.commons.octopus.IOctopusAPI;\r
+import user.commons.octopus.OctopusAPI;\r
+import user.commons.remotestore.FtpDirectoryLister;\r
+import user.commons.remotestore.RemoteStoreProtocol;\r
+import user.jobengine.db.IItemManager;\r
+import user.jobengine.server.IJobEngine;\r
+import user.jobengine.server.IJobRuntime;\r
+import user.jobengine.server.steps.shared.EscortFiles;\r
+import user.jobengine.server.steps.shared.ItemManagerExtensions;\r
+import user.jobengine.server.steps.shared.MetadataType;\r
+import user.jobengine.server.steps.shared.MetadataTypeDetector;\r
+\r
+public class CopyForArchiveNEXIOMaterialsStep extends JobStep {\r
+       private static final String SCHEDULED_FORMAT = "yyyy.MM.dd HH:mm";\r
+       private static final Logger logger = LogManager.getLogger("CopyForArchiveNEXIOMaterialsStep");\r
+       private static final String UTF_8 = "utf-8";\r
+       private static final String JSON_EXT = ".json";\r
+       private static final String XML_EXT = ".xml";\r
+       private static final String DURATION = "duration";\r
+       private static final String MXFEXT = ".MXF";\r
+       private static final String NEXIOCLIPS = SystemConfiguration.getInstance().value("services.nexio.collection-name",\r
+                       "nexioclips");\r
+       private static final String LONGNAMEID = "longnameid";\r
+       private static final String ARCHIVEDRUNDOWNS = "archivedrundowns";\r
+       private static final String ID = "id";\r
+       private static final String MEDIATYPE = "Hír bejátszó";\r
+       private static String NEXIO_HOST = SystemConfiguration.getInstance().value("services.nexio.host");\r
+       private OctopusAPI octopusAPI;\r
+       private IItemManager manager;\r
+\r
+       private DB db;\r
+       private FTPClient sourceFtp;\r
+       private FTPClient targetFtp;\r
+       private StoreUri sourceUri;\r
+       private StoreUri targetUri;\r
+       private int nexioKillDateDays;\r
+       private String nexioAgency;\r
+       private Marker systemMarker;\r
+       private List<String> transferredFileNames = null;\r
+       private boolean demo = false;\r
+\r
+       private int check(int value, String name) {\r
+               if (value == 0) {\r
+                       logger.error(systemMarker, "A folyamat '{}' bemeneti paramétere 0.", name);\r
+                       throw new NullPointerException(\r
+                                       String.format("System is not configured properly, missing '%s' input parameter.", name));\r
+               }\r
+               return value;\r
+       }\r
+\r
+       private String check(String value, String name) {\r
+               if (value == null) {\r
+                       logger.error(systemMarker, "A folyamat '{}' bemeneti paramétere üres.", name);\r
+                       throw new NullPointerException(\r
+                                       String.format("System is not configured properly, missing '%s' input parameter.", name));\r
+               }\r
+               return value;\r
+       }\r
+\r
+       private void copy(RundownArchive rundownArchive) throws Exception {\r
+               for (StoryArchive storyArchive : rundownArchive.getStoryArchives()) {\r
+                       for (FileArchive fileArchive : storyArchive.getFileArchives()) {\r
+                               try {\r
+                                       copyFile(fileArchive, rundownArchive, storyArchive);\r
+                               } catch (Exception e) {\r
+                                       logger.error(systemMarker, "A '{}' clip archiválása sikertelen. A rendszer üzenete: {}",\r
+                                                       fileArchive.getFileName(), e.getMessage());\r
+                                       throw e;\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       private void copyFile(FileArchive fileArchive, RundownArchive rundownArchive, StoryArchive storyArchive)\r
+                       throws Exception {\r
+               String origFileName = fileArchive.getFileName();\r
+               String fileName = String.format("%s-%s", origFileName, rundownArchive.getItemHouseId());\r
+               String videoFileName = fileName + MXFEXT;\r
+\r
+               if (transferredFileNames == null)\r
+                       transferredFileNames = new ArrayList<>();\r
+\r
+               // A mar letezo mozikat nem archivaljuk le ujra, csak a metaadatot\r
+               long existingMediaId = 0;\r
+               boolean transferDone = false;\r
+               if (transferredFileNames.contains(origFileName)) {\r
+                       logger.info(systemMarker,\r
+                                       "A '{}' file archiválásra felkészítése egy másik story kapcsán már megtörtént, ezért csak metaadat archiválás szükséges.",\r
+                                       origFileName);\r
+                       if (!demo)\r
+                               transferDone = transferChunk(videoFileName);\r
+               } else {\r
+                       existingMediaId = ItemManagerExtensions.getExistingRundownMedia(manager, origFileName);\r
+                       if (existingMediaId == 0) {\r
+                               transferredFileNames.add(origFileName);\r
+                               if (!demo)\r
+                                       transferDone = transferFile(origFileName + MXFEXT, videoFileName);\r
+                               logger.info(systemMarker, "A '{}' file archiválásra felkészítése sikeres volt.", origFileName);\r
+                       } else {\r
+\r
+                               logger.info(systemMarker,\r
+                                               "A '{}' file archiválása már megtörtént, ezért csak metaadat archiválás szükséges.",\r
+                                               origFileName);\r
+                               if (!demo)\r
+                                       transferDone = transferChunk(videoFileName);\r
+                       }\r
+               }\r
+\r
+               if (!demo && transferDone) {\r
+                       BasicDBObject metadata = createMetadata(rundownArchive, storyArchive, fileArchive, existingMediaId);\r
+                       transferMetadata(videoFileName, metadata);\r
+                       createSourceKillDateFile(rundownArchive, origFileName);\r
+               }\r
+       }\r
+\r
+       private BasicDBObject createMetadata(RundownArchive rundownArchive, StoryArchive storyArchive,\r
+                       FileArchive fileArchive, long existingMediaId) {\r
+               BasicDBObject result = new BasicDBObject();\r
+               result.put("itemHouseId", rundownArchive.getItemHouseId());\r
+               result.put("itemTitle", rundownArchive.getItemTitle());\r
+               result.put("itemDescription", rundownArchive.getItemDesc());\r
+               result.put("userName", "mediacube");\r
+               result.put("mediaHouseId", storyArchive.getMediaHouseId());\r
+               result.put("mediaTitle", storyArchive.getMediaTitle());\r
+               result.put("mediaDescription", storyArchive.getMediaDesc());\r
+               result.put("mediaType", MEDIATYPE);\r
+               result.put("duration", fileArchive.getDuration());\r
+               result.put("existingMediaId", existingMediaId);\r
+               return result;\r
+       }\r
+\r
+       private void createSourceKillDateFile(RundownArchive rundownArchive, String fileName) throws Exception {\r
+               logger.info("Create killdate/agency for {}", fileName);\r
+               OutputStream outStream = null;\r
+               try {\r
+                       sourceFtp = ((FtpDirectoryLister) sourceUri.getLister()).connect();\r
+                       Calendar killDate = CalendarUtils.createCalendar(rundownArchive.getScheduleDate());\r
+                       killDate.add(Calendar.DAY_OF_YEAR, nexioKillDateDays);\r
+                       byte[] killDateFile = EscortFiles.createNEXIOKillDateFile(fileName, killDate.getTime(), null, nexioAgency);\r
+                       outStream = sourceFtp.storeFileStream(fileName + XML_EXT);\r
+                       if (outStream == null) {\r
+                               throw new NullPointerException(\r
+                                               "Can not open: " + fileName + XML_EXT + " Reply:" + sourceFtp.getReplyString());\r
+                       }\r
+                       outStream.write(killDateFile);\r
+                       outStream.flush();\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       throw e;\r
+               } finally {\r
+                       if (outStream != null)\r
+                               outStream.close();\r
+                       sourceUri.cleanUp();\r
+               }\r
+       }\r
+\r
+       @StepEntry\r
+       public Object[] execute(int nexioPort, String nexioUserName, String nexioPassword, String archiveFtp,\r
+                       String archiveUserName, String archivePassword, int daysBeforeNow, int nexioKillDateDays,\r
+                       String nexioAgency, IJobEngine jobEngine, IJobRuntime jobRuntime) throws Exception {\r
+               systemMarker = getMarker();\r
+               logger.debug(systemMarker, "debug test");\r
+               setAndCheck(nexioPort, nexioUserName, nexioPassword, archiveFtp, archiveUserName, archivePassword,\r
+                               nexioKillDateDays, nexioAgency, jobEngine);\r
+               octopusAPI = new OctopusAPI();\r
+               Calendar scheduledDate = Calendar.getInstance();\r
+               scheduledDate.add(Calendar.DAY_OF_YEAR, -1 * daysBeforeNow);\r
+               List<DBObject> rundowns = octopusAPI.getRundowns(scheduledDate.getTime());\r
+               if (rundowns == null) {\r
+                       logger.warn(systemMarker, "Nem található adástükör a {} napra.", CalendarUtils.toDateString(scheduledDate));\r
+                       return null;\r
+               }\r
+\r
+               processRundowns(rundowns);\r
+               return null;\r
+       }\r
+\r
+       // private String getVersionedFileName(String fileName, String extension) throws\r
+       // Exception {\r
+       // String result = fileName;\r
+       // try {\r
+       // targetFtp = ((FtpDirectoryLister) targetUri.getLister()).connect();\r
+       // FTPFile[] listFiles = targetFtp.listFiles();\r
+       // List<String> fileNames = new ArrayList<>();\r
+       // for (FTPFile ftpFile : listFiles) {\r
+       // fileNames.add(ftpFile.getName());\r
+       // }\r
+       // while (fileNames.contains(result + extension)) {\r
+       //\r
+       // }\r
+       //\r
+       // } catch (Exception e) {\r
+       // logger.catching(e);\r
+       // throw e;\r
+       // } finally {\r
+       // targetUri.cleanUp();\r
+       // }\r
+       // return result;\r
+       // }\r
+\r
+       private FileArchive processMosObject(BasicDBObject rundown, BasicDBObject story, BasicDBObject mosObject)\r
+                       throws Exception {\r
+               String mosID = mosObject.getString(IOctopusAPI.OBJ_ID);\r
+               if (MetadataTypeDetector.GuessMetadataType(mosID) != MetadataType.OctopusPlaceholder) {\r
+                       logger.info(systemMarker, "Skipping MOS object {}", mosID);\r
+                       return null;\r
+               }\r
+               DBCollection clips = db.getCollection(NEXIOCLIPS);\r
+               BasicDBObject clip = (BasicDBObject) clips.findOne(new BasicDBObject(LONGNAMEID, mosID));\r
+               if (clip == null) {\r
+                       logger.info(systemMarker, "File {} does NOT exist", mosID);\r
+                       return null;\r
+                       // throw new Exception(String.format("File does NOT exist %s", mosID));\r
+               } else {\r
+                       logger.debug(systemMarker, "File {} exists", mosID);\r
+               }\r
+               long duration = NoSQLUtils.asLong(clip, DURATION);\r
+\r
+               if (duration == 0) {\r
+                       logger.info(systemMarker, "File {} exists with 0 frame length", mosID);\r
+                       return null;\r
+               }\r
+               if (duration == 1) {\r
+                       logger.info(systemMarker, "File {} exists with 1 frame length", mosID);\r
+                       return null;\r
+               }\r
+               return new FileArchive(mosID, duration);\r
+       }\r
+\r
+       private RundownArchive processRundow(DBObject r) throws Exception {\r
+               BasicDBObject rundown = (BasicDBObject) r;\r
+               long rundownID = rundown.getLong(ID);\r
+               if (!demo)\r
+                       logger.info(systemMarker, "Processing rundown {} {}", rundownID, rundown.getString(IOctopusAPI.NAME));\r
+               List<DBObject> stories = octopusAPI.getRundownFullStories(rundownID);\r
+               if (stories == null) {\r
+                       logger.info(systemMarker, "Rundown {} {} is empty", rundownID, rundown.getString(IOctopusAPI.NAME));\r
+                       return null;\r
+               }\r
+               RundownArchive result = new RundownArchive();\r
+\r
+               long id = NoSQLUtils.asLong(rundown, IOctopusAPI.ID);\r
+               if (id == 0)\r
+                       return null;\r
+               String name = NoSQLUtils.asString(NoSQLUtils.asDBObject(rundown, IOctopusAPI.RUNDOWN_TYPE), IOctopusAPI.NAME);\r
+               if (StringUtils.isBlank(name)) {\r
+                       logger.info(systemMarker, "Rundown {} {} type is empty", rundownID, rundown.getString(IOctopusAPI.NAME));\r
+                       return null;\r
+               }\r
+               String channel = NoSQLUtils.asString(NoSQLUtils.asDBObject(rundown, IOctopusAPI.CHANNEL), IOctopusAPI.NAME);\r
+               Date scheduledStart = rundown.getDate(IOctopusAPI.SCHEDULED_START);\r
+               if (scheduledStart == null) {\r
+                       logger.info(systemMarker, "Rundown {} {} schedule is empty", rundownID,\r
+                                       rundown.getString(IOctopusAPI.NAME));\r
+                       return null;\r
+               }\r
+               String start = CalendarUtils.toString(CalendarUtils.createCalendar(scheduledStart), SCHEDULED_FORMAT);\r
+               result.setScheduleDate(scheduledStart);\r
+               result.setItemHouseId(String.valueOf(id));\r
+               result.setItemTitle(String.format("%s %s %s", start, name, channel));\r
+\r
+               logger.info(systemMarker, "Processing stories in rundown {} {}", rundownID,\r
+                               rundown.getString(IOctopusAPI.NAME));\r
+               for (DBObject s : stories) {\r
+                       StoryArchive storyArchive = processStory(rundown, s);\r
+                       if (storyArchive == null)\r
+                               continue;\r
+                       result.addStoryArchive(storyArchive);\r
+               }\r
+               return result;\r
+       }\r
+\r
+       private void processRundowns(List<DBObject> rundowns) {\r
+\r
+               // TODO kiveni publikálás előtt\r
+               // db.getCollection(v).drop();\r
+               List<BasicDBObject> archivedRundowns = queryArchivedRundowns();\r
+\r
+               logger.info(systemMarker, "Found {} rundowns to archive", archivedRundowns.size());\r
+               int index = 1;\r
+\r
+               for (DBObject r : rundowns) {\r
+                       BasicDBObject rundown = (BasicDBObject) r;\r
+                       int progress = index * 100 / rundowns.size();\r
+                       setProgress(progress);\r
+                       long rundownID = NoSQLUtils.asLong(rundown, IOctopusAPI.ID);\r
+                       String rundownName = NoSQLUtils.asString(rundown, IOctopusAPI.NAME);\r
+                       try {\r
+                               BasicDBObject currentRundownID = new BasicDBObject(IOctopusAPI.ID, rundownID);\r
+                               if (!demo && archivedRundowns != null && archivedRundowns.contains(currentRundownID)) {\r
+                                       logger.info(systemMarker, "Skipping archived rundown {} {}", rundownID, rundownName);\r
+                                       continue;\r
+                               }\r
+\r
+                               RundownArchive rundownArchive = processRundow(r);\r
+                               if (rundownArchive == null || rundownArchive.isEmpty()) {\r
+                                       if (!demo)\r
+                                               logger.info(systemMarker, "Skipping rundown {} {}", rundownID, rundownName);\r
+                                       continue;\r
+                               }\r
+\r
+                               if (!demo)\r
+                                       logger.info(systemMarker, "Saving rundown {} {}", rundownID, rundownName);\r
+                               copy(rundownArchive);\r
+                               if (!demo)\r
+                                       logger.info(systemMarker, "A '{}' tükör {}db bejátszójának archiválása sikeres volt",\r
+                                                       rundownArchive.getItemTitle(), rundownArchive.getStoryArchives().size());\r
+\r
+                               if (!demo)\r
+                                       db.getCollection(ARCHIVEDRUNDOWNS).save(currentRundownID);\r
+                       } catch (Exception e) {\r
+                               logger.catching(e);\r
+                               logger.error(systemMarker, String.format(\r
+                                               "A %s %s tükör archiválása nem lehetséges, mert a annak ellenőrzése hibát jelzett. A rendszer üzenete: %s",\r
+                                               rundownID, rundownName, e.getMessage()));\r
+                       }\r
+                       index++;\r
+               }\r
+\r
+       }\r
+\r
+       private StoryArchive processStory(BasicDBObject rundown, DBObject s) throws Exception {\r
+               BasicDBObject story = (BasicDBObject) s;\r
+               String parentStoryID = story.getString(IOctopusAPI.PARENT_STORY_ID);\r
+               String storyID = story.getString(IOctopusAPI.ID);\r
+\r
+               if (StringUtils.isBlank(parentStoryID)) {\r
+                       logger.warn(systemMarker, "Story parentStoryID is null: {}", story.toPrettyString(null));\r
+                       return null;\r
+               } else {\r
+                       if ("475048225".equals(storyID))\r
+                               logger.info(systemMarker, "Processing story {}", story.toPrettyString(null));\r
+               }\r
+               List<BasicDBObject> mosObjects = NoSQLUtils.asList(story, IOctopusAPI.MOS_OBJECTS);\r
+               if (mosObjects == null) {\r
+                       logger.debug(systemMarker, "No MOS in story {}", storyID);\r
+                       return null;\r
+               }\r
+               StoryArchive storyArchive = null;\r
+               for (BasicDBObject mosObject : mosObjects) {\r
+                       FileArchive fileArchive = processMosObject(rundown, story, mosObject);\r
+                       if (fileArchive == null)\r
+                               continue;\r
+                       if (storyArchive == null) {\r
+                               storyArchive = new StoryArchive();\r
+                               storyArchive.setMediaHouseId(parentStoryID);\r
+                               storyArchive.setMediaTitle(story.getString(IOctopusAPI.NAME));\r
+                               storyArchive.setMediaDesc(story.getString(IOctopusAPI.SCRIPT_CONTENT));\r
+\r
+                       }\r
+                       storyArchive.addFileArchive(fileArchive);\r
+               }\r
+               return storyArchive;\r
+\r
+       }\r
+\r
+       private List<BasicDBObject> queryArchivedRundowns() {\r
+               List<BasicDBObject> result = null;\r
+               DBCollection collection = db.getCollection(ARCHIVEDRUNDOWNS);\r
+               DBCursor find = collection.find(new BasicDBObject(),\r
+                               new BasicDBObject(IOctopusAPI._ID, 0).append(IOctopusAPI.ID, 1));\r
+               if (find.hasNext())\r
+                       result = ListUtils.cast(find.toArray());\r
+               return result;\r
+       }\r
+\r
+       private void setAndCheck(int nexioPort, String nexioUserName, String nexioPassword, String archiveFtp,\r
+                       String archiveUserName, String archivePassword, int nexioKillDateDays, String nexioAgency,\r
+                       IJobEngine jobEngine) throws Exception {\r
+               db = NoSQLUtils.getNoSQLDB();\r
+               if (db == null) {\r
+                       logger.error(systemMarker, "Az NoSQL adatkezelő réteg nem elérhető.");\r
+                       throw new NullPointerException("Internal error, missing NoSQL DB reference.");\r
+               }\r
+\r
+               if (jobEngine == null) {\r
+                       logger.error(systemMarker, "Az folyamatkezelő réteg nem elérhető.");\r
+                       throw new NullPointerException("Internal error, missing JobEngine reference.");\r
+               }\r
+               manager = jobEngine.getItemManager();\r
+               if (manager == null) {\r
+                       logger.error(systemMarker, "Az adatbáziskezelő réteg nem elérhető.");\r
+                       throw new NullPointerException("Internal error, missing ItemManager reference.");\r
+               }\r
+\r
+               if (StringUtils.isBlank(NEXIO_HOST)) {\r
+                       logger.error(systemMarker, "A 'nexio.host' rendszer paraméter nem található.");\r
+                       throw new NullPointerException(\r
+                                       "System is not configured properly, 'jobengine.selenio.address' startup parameter missing.");\r
+               }\r
+               check(nexioPort, "nexioPort");\r
+               check(nexioUserName, "nexioUserName");\r
+               check(nexioPassword, "nexioPassword");\r
+\r
+               check(nexioKillDateDays, "nexioKillDateDays");\r
+               this.nexioKillDateDays = nexioKillDateDays;\r
+               check(nexioAgency, "nexioAgency");\r
+               this.nexioAgency = nexioAgency;\r
+\r
+               sourceUri = manager.createStoreUri(RemoteStoreProtocol.FTP, NEXIO_HOST);\r
+               sourceUri.setPortNumber(nexioPort);\r
+               sourceUri.setUserName(nexioUserName);\r
+               sourceUri.setPassword(nexioPassword);\r
+               if (sourceUri == null) {\r
+                       logger.error(systemMarker, "A forrás nem elérhető.");\r
+                       throw new NullPointerException("Internal error, missing 'sourceUri'.");\r
+               }\r
+\r
+               check(archiveFtp, "archiveFtp");\r
+               check(archiveUserName, "archiveUserName");\r
+               check(archivePassword, "archivePassword");\r
+\r
+               targetUri = manager.createStoreUri(new URI(archiveFtp));\r
+               targetUri.setUserName(archiveUserName);\r
+               targetUri.setPassword(archivePassword);\r
+               if (targetUri == null) {\r
+                       logger.error(systemMarker, "A cél nem elérhető.");\r
+                       throw new NullPointerException("Internal error, missing 'targetUri'.");\r
+               }\r
+\r
+       }\r
+\r
+       private boolean transferChunk(String fileName) throws Exception {\r
+               logger.info("Transfer chunk {}", fileName);\r
+               OutputStream outStream = null;\r
+               try {\r
+                       targetFtp = ((FtpDirectoryLister) targetUri.getLister()).connect();\r
+\r
+                       // ha ugyan abban a tukorben szerepel meg 1x a mozi, akkor a chunk felulirja a\r
+                       // tenyleges file-t, es az sosem archivalodik\r
+                       String[] names = targetFtp.listNames();\r
+                       if (names != null) {\r
+                               if (Arrays.asList(names).contains(fileName))\r
+                                       return false;\r
+                       }\r
+\r
+                       outStream = targetFtp.storeFileStream(fileName);\r
+                       if (outStream == null) {\r
+                               throw new NullPointerException("Can not open: " + fileName + " Reply:" + targetFtp.getReplyString());\r
+                       }\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       throw e;\r
+               } finally {\r
+                       if (outStream != null)\r
+                               outStream.close();\r
+                       targetUri.cleanUp();\r
+               }\r
+               return true;\r
+       }\r
+\r
+       private boolean transferFile(String sourceFileName, String targetFileName) throws Exception {\r
+               boolean result = true;\r
+               int reply = 0;\r
+               logger.info("Transfer clip {}", sourceFileName);\r
+               try {\r
+                       sourceFtp = ((FtpDirectoryLister) sourceUri.getLister()).connect();\r
+                       targetFtp = ((FtpDirectoryLister) targetUri.getLister()).connect();\r
+                       if (!targetFtp.enterRemotePassiveMode())\r
+                               throw new Exception("!PASV");\r
+\r
+                       reply = sourceFtp.port(InetAddress.getByName(targetFtp.getPassiveHost()), targetFtp.getPassivePort());\r
+                       if (!FTPReply.isPositiveCompletion(reply))\r
+                               throw new Exception("PORT parancs válasza: " + sourceFtp.getReplyString());\r
+\r
+                       if (!sourceFtp.setFileType(FTP.BINARY_FILE_TYPE))\r
+                               throw new Exception("!SOURCE TYPE");\r
+\r
+                       reply = sourceFtp.retr(sourceFileName);\r
+                       if (!FTPReply.isPositivePreliminary(reply))\r
+                               throw new Exception("RETR parancs válasza: " + sourceFtp.getReplyString());\r
+\r
+                       if (!targetFtp.setFileType(FTP.BINARY_FILE_TYPE))\r
+                               throw new Exception("!TARGET TYPE");\r
+\r
+                       reply = targetFtp.stor(targetFileName);\r
+                       if (!FTPReply.isPositivePreliminary(reply))\r
+                               throw new Exception("STOR parancs válasza: " + sourceFtp.getReplyString());\r
+\r
+                       while (true) {\r
+                               reply = sourceFtp.stat();\r
+                               if (!FTPReply.isPositiveCompletion(reply))\r
+                                       throw new Exception("STAT parancs válasza: " + sourceFtp.getReplyString());\r
+\r
+                               logger.info("Status: {}", sourceFtp.getReplyString());\r
+                               if (reply == 226) {\r
+                                       break;\r
+                               }\r
+                               Thread.sleep(1000);\r
+                       }\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       result = false;\r
+               } finally {\r
+                       sourceUri.cleanUp();\r
+                       targetUri.cleanUp();\r
+               }\r
+\r
+               return result;\r
+       }\r
+\r
+       private void transferMetadata(String fileName, BasicDBObject metadata) throws Exception {\r
+               logger.info("Transfer metadata {}", fileName);\r
+               OutputStream outStream = null;\r
+               try {\r
+                       targetFtp = ((FtpDirectoryLister) targetUri.getLister()).connect();\r
+                       if (!targetFtp.changeWorkingDirectory(EscortFiles.STATUSFOLDER)) {\r
+                               targetFtp.makeDirectory(EscortFiles.STATUSFOLDER);\r
+                               if (!targetFtp.changeWorkingDirectory(EscortFiles.STATUSFOLDER))\r
+                                       throw new Exception("!STATUSFOLDER");\r
+                       }\r
+\r
+                       outStream = targetFtp.storeFileStream(fileName + JSON_EXT);\r
+                       if (outStream == null) {\r
+                               throw new NullPointerException(\r
+                                               "Can not open: " + fileName + JSON_EXT + " Reply:" + targetFtp.getReplyString());\r
+                       }\r
+                       outStream.write(metadata.toString().getBytes(UTF_8));\r
+                       outStream.flush();\r
+                       // targetFtp.changeToParentDirectory();\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       throw e;\r
+               } finally {\r
+                       if (outStream != null)\r
+                               outStream.close();\r
+                       targetUri.cleanUp();\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/CopyForArchiveNEXIORecordingsStep.java b/server/-product/production/HIRTV/jobs/steps/CopyForArchiveNEXIORecordingsStep.java
new file mode 100644 (file)
index 0000000..941b65c
--- /dev/null
@@ -0,0 +1,455 @@
+package user.jobengine.server.steps;\r
+\r
+import java.io.OutputStream;\r
+import java.net.InetAddress;\r
+import java.net.URI;\r
+import java.text.ParseException;\r
+import java.text.SimpleDateFormat;\r
+import java.util.Calendar;\r
+import java.util.Date;\r
+import java.util.List;\r
+import java.util.TimeZone;\r
+\r
+import org.apache.commons.lang.StringUtils;\r
+import org.apache.commons.net.ftp.FTP;\r
+import org.apache.commons.net.ftp.FTPClient;\r
+import org.apache.commons.net.ftp.FTPReply;\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+import org.apache.logging.log4j.Marker;\r
+\r
+import com.ibm.nosql.json.api.BasicDBList;\r
+import com.ibm.nosql.json.api.BasicDBObject;\r
+import com.ibm.nosql.json.api.DB;\r
+import com.ibm.nosql.json.api.DBCollection;\r
+import com.ibm.nosql.json.api.DBCursor;\r
+import com.ibm.nosql.json.api.DBObject;\r
+import com.ibm.nosql.json.api.QueryBuilder;\r
+\r
+import user.commons.CalendarUtils;\r
+import user.commons.ListUtils;\r
+import user.commons.StoreUri;\r
+import user.commons.configuration.SystemConfiguration;\r
+import user.commons.nexio.NexioDispatcher;\r
+import user.commons.nosql.NoSQLUtils;\r
+import user.commons.octopus.IOctopusAPI;\r
+import user.commons.octopus.OctopusAPI;\r
+import user.commons.remotestore.FtpDirectoryLister;\r
+import user.commons.remotestore.RemoteStoreProtocol;\r
+import user.jobengine.db.IItemManager;\r
+import user.jobengine.server.IJobEngine;\r
+import user.jobengine.server.IJobRuntime;\r
+import user.jobengine.server.steps.shared.EscortFiles;\r
+\r
+public class CopyForArchiveNEXIORecordingsStep extends JobStep {\r
+       private static final String MEDIATYPE = "Visszarögzített";\r
+       private static final String SCHEDULED_FORMAT = "yyyy.MM.dd HH:mm";\r
+       private static final String STARTTIME_FORMAT = "HHmm";\r
+       private static final String RUNDOWNDATE_FORMAT = "yyyyMMdd";\r
+       private static final Logger logger = LogManager.getLogger();\r
+       private static final String UTF_8 = "utf-8";\r
+       private static final String JSON_EXT = ".json";\r
+       private static final String XML_EXT = ".xml";\r
+       private static final String DURATION = "duration";\r
+       private static final String MXFEXT = ".MXF";\r
+       private static final String NEXIOCLIPS = NexioDispatcher.CLIP_COLLECTION_NAME;\r
+       private static final String LONGNAMEID = "longnameid";\r
+       private static final String EXTAGENCY = "extagency";\r
+       private static final String RECORDDATE = "recorddate";\r
+       private static final SimpleDateFormat startTimeformat = new SimpleDateFormat(STARTTIME_FORMAT);\r
+       private static final SimpleDateFormat rundownDateformat = new SimpleDateFormat(RUNDOWNDATE_FORMAT);\r
+       private static String NEXIO_HOST = SystemConfiguration.getInstance().value("services.nexio.host");\r
+\r
+       private OctopusAPI octopusAPI;\r
+       private IItemManager manager;\r
+\r
+       private DB db;\r
+       private FTPClient sourceFtp;\r
+       private FTPClient targetFtp;\r
+       private StoreUri sourceUri;\r
+       private StoreUri targetUri;\r
+       private int nexioKillDateDays;\r
+       private String nexioAgency;\r
+       private Object[] filterAgencies;\r
+       private Marker systemMarker;\r
+\r
+       private int check(int value, String name) {\r
+               if (value == 0) {\r
+                       logger.error(systemMarker, "A folyamat '{}' bemeneti paramétere 0.", name);\r
+                       throw new NullPointerException(String.format("System is not configured properly, missing '%s' input parameter.", name));\r
+               }\r
+               return value;\r
+       }\r
+\r
+       private String check(String value, String name) {\r
+               if (StringUtils.isBlank(value)) {\r
+                       logger.error(systemMarker, "A folyamat '{}' bemeneti paramétere üres.", name);\r
+                       throw new NullPointerException(String.format("System is not configured properly, missing '%s' input parameter.", name));\r
+               }\r
+               return value;\r
+       }\r
+\r
+       private void copy(RundownArchive rundownArchive) {\r
+               for (StoryArchive storyArchive : rundownArchive.getStoryArchives()) {\r
+                       for (FileArchive fileArchive : storyArchive.getFileArchives()) {\r
+                               try {\r
+                                       copyFile(fileArchive, rundownArchive, storyArchive);\r
+                                       logger.info(systemMarker, "Sikeres fájl archiválás a '{}' tükörhöz: '{}'.", rundownArchive.getItemTitle(), fileArchive.getFileName());\r
+                               } catch (Exception e) {\r
+                                       logger.error(systemMarker, "Az '{}' fájl archiválása sikertelen. A rendszer üzenete: {}", fileArchive.getFileName(), e.getMessage());\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       private void copyFile(FileArchive fileArchive, RundownArchive rundownArchive, StoryArchive storyArchive) throws Exception {\r
+               String sourceFileName = fileArchive.getFileName();\r
+               String targetFileName = getTargetFileName(rundownArchive, sourceFileName);\r
+               transferFile(sourceFileName, targetFileName);\r
+               BasicDBObject metadata = createMetadata(rundownArchive, storyArchive, fileArchive);\r
+               transferMetadata(targetFileName, metadata);\r
+               createSourceKillDateFile(rundownArchive, sourceFileName);\r
+       }\r
+\r
+       private BasicDBObject createMetadata(RundownArchive rundownArchive, StoryArchive storyArchive, FileArchive fileArchive) {\r
+               BasicDBObject result = new BasicDBObject();\r
+               result.put("itemHouseId", rundownArchive.getItemHouseId());\r
+               result.put("itemTitle", rundownArchive.getItemTitle());\r
+               result.put("itemDescription", rundownArchive.getItemDesc());\r
+               result.put("userName", "mediacube");\r
+\r
+               result.put("mediaHouseId", storyArchive.getMediaHouseId());\r
+               result.put("mediaTitle", storyArchive.getMediaTitle());\r
+               result.put("mediaDescription", storyArchive.getMediaDesc());\r
+\r
+               result.put("duration", fileArchive.getDuration());\r
+               result.put("mediaType", MEDIATYPE);\r
+               return result;\r
+       }\r
+\r
+       private void createSourceKillDateFile(RundownArchive rundownArchive, String fileName) throws Exception {\r
+               logger.info("Create killdate/agency for {}", fileName);\r
+               OutputStream outStream = null;\r
+               try {\r
+                       sourceFtp = ((FtpDirectoryLister) sourceUri.getLister()).connect();\r
+                       Calendar killDate = CalendarUtils.createCalendar(rundownArchive.getScheduleDate());\r
+                       killDate.add(Calendar.DAY_OF_YEAR, nexioKillDateDays);\r
+                       byte[] killDateFile = EscortFiles.createNEXIOKillDateFile(fileName, killDate.getTime(), null, nexioAgency);\r
+                       outStream = sourceFtp.storeFileStream(fileName + XML_EXT);\r
+                       if (outStream == null) {\r
+                               throw new NullPointerException("Can not open: " + fileName + XML_EXT + " Reply:" + sourceFtp.getReplyString());\r
+                       }\r
+                       outStream.write(killDateFile);\r
+                       outStream.flush();\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       throw e;\r
+               } finally {\r
+                       if (outStream != null)\r
+                               outStream.close();\r
+                       sourceUri.cleanUp();\r
+               }\r
+       }\r
+\r
+       @StepEntry\r
+       public Object[] execute(int nexioPort, String nexioUserName, String nexioPassword, String archiveFtp, String archiveUserName, String archivePassword,\r
+                       String filterAgencies, int limit, int nexioKillDateDays, String targetAgency, IJobEngine jobEngine, IJobRuntime jobRuntime) throws Exception {\r
+               systemMarker = jobRuntime.getSessionMarker();\r
+               setAndCheck(nexioPort, nexioUserName, nexioPassword, archiveFtp, archiveUserName, archivePassword, filterAgencies, limit, nexioKillDateDays,\r
+                               targetAgency, jobEngine);\r
+               octopusAPI = new OctopusAPI();\r
+               List<BasicDBObject> clips = queryClips();\r
+               processClips(clips, limit);\r
+               return null;\r
+       }\r
+\r
+       private Date getScheduledStart(String clipName, Date recordDate) {\r
+               if (StringUtils.isBlank(clipName)) {\r
+                       logger.warn(systemMarker, "A fájlnak nincs neve, ezért nem archiválható.");\r
+                       return null;\r
+               }\r
+               if (recordDate == null) {\r
+                       logger.warn(systemMarker, "Az '{}' fájl rögzítésének ideje nem meghatározható, ezért nem archiválható.", clipName);\r
+                       return null;\r
+               }\r
+\r
+               Date timePart = null;\r
+               try {\r
+                       String clipNameTime = clipName.split("_")[0];\r
+                       timePart = startTimeformat.parse(clipNameTime);\r
+               } catch (ParseException e) {\r
+                       logger.warn(systemMarker, "A '{}' fájl neve nem időbélyeggel kezdődik, ezért nem archiválható.", clipName);\r
+                       return null;\r
+               }\r
+               Calendar dateCal = CalendarUtils.createCalendar(recordDate);\r
+               dateCal.setTimeZone(TimeZone.getTimeZone("Europe/Budapest"));\r
+               Calendar wholeCal = CalendarUtils.createCalendar(CalendarUtils.createCalendar(recordDate), timePart);\r
+               wholeCal.setTimeZone(TimeZone.getTimeZone("Europe/Budapest"));\r
+               return wholeCal.getTime();\r
+       }\r
+\r
+       private String getTargetFileName(RundownArchive rundownArchive, String sourceFileName) {\r
+               String date = rundownDateformat.format(rundownArchive.getScheduleDate());\r
+               return String.format("%s-%s%s", date, sourceFileName, MXFEXT);\r
+       }\r
+\r
+       private RundownArchive processClip(BasicDBObject clip) {\r
+               RundownArchive result = null;\r
+               String clipName = NoSQLUtils.asString(clip, LONGNAMEID);\r
+               Date recordDate = clip.getDate(RECORDDATE);\r
+               long duration = NoSQLUtils.asLong(clip, DURATION);\r
+               logger.info("Processing {} {}", clipName, recordDate);\r
+               Date scheduledStart = getScheduledStart(clipName, recordDate);\r
+               if (scheduledStart == null)\r
+                       return null;\r
+               DBObject rundown = octopusAPI.getRundown(scheduledStart);\r
+               if (rundown == null) {\r
+                       logger.error(systemMarker, "A '{}' anyaghoz nem található tükör '{}' kezdéssel, ezért nem archiválható.", clipName, scheduledStart);\r
+                       return null;\r
+               }\r
+\r
+               try {\r
+                       result = processRundow(rundown, clipName, duration);\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       logger.error(systemMarker, "A '{}' anyag metaadatainak transzformálása sikertelen, ezért az nem archiválható. A rendszer hibaüzenete: {}",\r
+                                       e.getMessage());\r
+                       return null;\r
+               }\r
+               /*\r
+                               if (clipName.startsWith("1900_")) {\r
+                                       String clipNameNext = clipName.replace("1900_", "1908_");\r
+                                       scheduledStart = getScheduledStart(clipNameNext, recordDate);\r
+                                       rundown = octopusAPI.getRundown(scheduledStart);\r
+                                       if (rundown == null) {\r
+                                               Calendar calendar = CalendarUtils.createCalendar(scheduledStart);\r
+                                               int dow = calendar.get(Calendar.DAY_OF_WEEK);\r
+                                               if (dow == Calendar.SATURDAY || dow == Calendar.SUNDAY) {\r
+                                                       logger.info(systemMarker, "A '{}' anyaghoz nem található tükör '{}' kezdéssel, de a hétvégi kivétel miatt archiválható.", clipName,\r
+                                                                       scheduledStart);\r
+                                                       return result;\r
+                                               } else {\r
+                                                       logger.error(systemMarker, "A '{}' anyaghoz nem található tükör '{}' kezdéssel, ezért nem archiválható.", clipName, scheduledStart);\r
+                                                       return null;\r
+                                               }\r
+                                       }\r
+               \r
+                                       RundownArchive item2 = null;\r
+               \r
+                                       try {\r
+                                               item2 = processRundow(rundown, clipName, duration);\r
+                                       } catch (Exception e) {\r
+                                               logger.catching(e);\r
+                                               logger.error(systemMarker, "A '{}' anyag metaadatainak transzformálása sikertelen, ezért az nem archiválható. A rendszer hibaüzenete: {}",\r
+                                                               e.getMessage());\r
+                                               return null;\r
+                                       }\r
+               \r
+                                       result.setItemTitle(result.getItemTitle() + " + NAPIAKT");\r
+                                       StoryArchive storyArchive = result.getStoryArchives().get(0);\r
+                                       StoryArchive storyArchive2 = item2.getStoryArchives().get(0);\r
+                                       storyArchive.setMediaDesc(storyArchive.getMediaDesc() + "\r\n\r\n****** NAPIAKT ******\r\n\r\n" + storyArchive2.getMediaDesc());\r
+                               }\r
+               */\r
+               return result;\r
+       }\r
+\r
+       private void processClips(List<BasicDBObject> clips, int limit) {\r
+               logger.info(systemMarker, "A folyamat {} archiválható anyagot érzékelt.", clips.size());\r
+               int current = 0;\r
+               for (BasicDBObject clip : clips) {\r
+                       RundownArchive rundownArchive = processClip(clip);\r
+                       if (rundownArchive == null)\r
+                               continue;\r
+\r
+                       copy(rundownArchive);\r
+\r
+                       current++;\r
+                       if (current == limit)\r
+                               break;\r
+                       int progress = current * 100 / limit;\r
+                       setProgress(progress);\r
+               }\r
+       }\r
+\r
+       private RundownArchive processRundow(DBObject r, String clipName, long duration) throws Exception {\r
+               BasicDBObject rundown = (BasicDBObject) r;\r
+               long rundownID = rundown.getLong(IOctopusAPI.ID);\r
+               logger.info("Processing rundown {} {}", rundownID, rundown.getString(IOctopusAPI.NAME));\r
+\r
+               List<DBObject> stories = octopusAPI.getRundownFullStories(rundownID);\r
+               if (stories == null)\r
+                       return null;\r
+               RundownArchive result = new RundownArchive();\r
+\r
+               String name = NoSQLUtils.asString(NoSQLUtils.asDBObject(rundown, IOctopusAPI.RUNDOWN_TYPE), IOctopusAPI.NAME);\r
+               if (StringUtils.isBlank(name))\r
+                       return null;\r
+               String channel = NoSQLUtils.asString(NoSQLUtils.asDBObject(rundown, IOctopusAPI.CHANNEL), IOctopusAPI.NAME);\r
+               Date scheduledStart = rundown.getDate(IOctopusAPI.SCHEDULED_START);\r
+               if (scheduledStart == null)\r
+                       return null;\r
+               String start = CalendarUtils.toString(CalendarUtils.createCalendar(scheduledStart), SCHEDULED_FORMAT);\r
+               result.setScheduleDate(scheduledStart);\r
+               result.setItemHouseId(String.valueOf(rundownID));\r
+               result.setItemTitle(String.format("%s %s %s", start, name, channel));\r
+\r
+               StoryArchive storyArchive = new StoryArchive();\r
+               storyArchive.setMediaHouseId(result.getItemHouseId());\r
+               storyArchive.setMediaTitle(clipName);\r
+               storyArchive.setMediaDesc(octopusAPI.getRundownContent(stories));\r
+               result.addStoryArchive(storyArchive);\r
+               storyArchive.addFileArchive(new FileArchive(clipName, duration));\r
+               return result;\r
+       }\r
+\r
+       private List<BasicDBObject> queryClips() {\r
+               DBCollection collection = db.getCollection(NEXIOCLIPS);\r
+               BasicDBList agencies = new BasicDBList(filterAgencies);\r
+\r
+               Calendar now = CalendarUtils.createZeroCalendar();\r
+               QueryBuilder dateQueryBuilder = QueryBuilder.start(RECORDDATE).lessThan(now.getTime());\r
+               QueryBuilder queryBuilder = QueryBuilder.start(EXTAGENCY).in(agencies).and(dateQueryBuilder.get());\r
+               DBCursor cursor = collection.find(queryBuilder.get()).sort(RECORDDATE, -1);\r
+               if (!cursor.hasNext())\r
+                       return null;\r
+               return ListUtils.cast(cursor.toArray());\r
+       }\r
+\r
+       private void setAndCheck(int nexioPort, String nexioUserName, String nexioPassword, String archiveFtp, String archiveUserName, String archivePassword,\r
+                       String agencies, int limit, int nexioKillDateDays, String nexioAgency, IJobEngine jobEngine) throws Exception {\r
+               db = NoSQLUtils.getNoSQLDB();\r
+               if (db == null) {\r
+                       logger.error(systemMarker, "Az NoSQL adatkezelő réteg nem elérhető.");\r
+                       throw new NullPointerException("Internal error, missing NoSQL DB reference.");\r
+               }\r
+\r
+               if (jobEngine == null) {\r
+                       logger.error(systemMarker, "Az folyamatkezelő réteg nem elérhető.");\r
+                       throw new NullPointerException("Internal error, missing JobEngine reference.");\r
+               }\r
+               manager = jobEngine.getItemManager();\r
+               if (manager == null) {\r
+                       logger.error(systemMarker, "Az adatbáziskezelő réteg nem elérhető.");\r
+                       throw new NullPointerException("Internal error, missing ItemManager reference.");\r
+               }\r
+\r
+               if (StringUtils.isBlank(NEXIO_HOST)) {\r
+                       logger.error(systemMarker, "A 'nexio.host' rendszer paraméter nem található.");\r
+                       throw new NullPointerException("System is not configured properly, 'jobengine.selenio.address' startup parameter missing.");\r
+               }\r
+               check(nexioPort, "nexioPort");\r
+               check(nexioUserName, "nexioUserName");\r
+               check(nexioPassword, "nexioPassword");\r
+\r
+               check(agencies, "filterAgencies");\r
+               filterAgencies = agencies.split(",");\r
+\r
+               check(limit, "limit");\r
+\r
+               check(nexioKillDateDays, "nexioKillDateDays");\r
+               this.nexioKillDateDays = nexioKillDateDays;\r
+               check(nexioAgency, "nexioAgency");\r
+               this.nexioAgency = nexioAgency;\r
+\r
+               sourceUri = manager.createStoreUri(RemoteStoreProtocol.FTP, NEXIO_HOST);\r
+               sourceUri.setPortNumber(nexioPort);\r
+               sourceUri.setUserName(nexioUserName);\r
+               sourceUri.setPassword(nexioPassword);\r
+               if (sourceUri == null) {\r
+                       logger.error(systemMarker, "A forrás nem elérhető.");\r
+                       throw new NullPointerException("Internal error, missing 'sourceUri'.");\r
+               }\r
+\r
+               check(archiveFtp, "archiveFtp");\r
+               check(archiveUserName, "archiveUserName");\r
+               check(archivePassword, "archivePassword");\r
+\r
+               targetUri = manager.createStoreUri(new URI(archiveFtp));\r
+               targetUri.setUserName(archiveUserName);\r
+               targetUri.setPassword(archivePassword);\r
+               if (targetUri == null) {\r
+                       logger.error(systemMarker, "A cél nem elérhető.");\r
+                       throw new NullPointerException("Internal error, missing 'targetUri'.");\r
+               }\r
+\r
+       }\r
+\r
+       private void transferFile(String sourceFileName, String targetFileName) throws Exception {\r
+               int reply = 0;\r
+               logger.info("Transfer clip {}", sourceFileName);\r
+               try {\r
+                       sourceFtp = ((FtpDirectoryLister) sourceUri.getLister()).connect();\r
+                       targetFtp = ((FtpDirectoryLister) targetUri.getLister()).connect();\r
+\r
+                       if (!targetFtp.enterRemotePassiveMode())\r
+                               throw new Exception("!PASV");\r
+\r
+                       reply = sourceFtp.port(InetAddress.getByName(targetFtp.getPassiveHost()), targetFtp.getPassivePort());\r
+                       if (!FTPReply.isPositiveCompletion(reply))\r
+                               throw new Exception("PORT parancs válasza: " + sourceFtp.getReplyString());\r
+\r
+                       if (!sourceFtp.setFileType(FTP.BINARY_FILE_TYPE))\r
+                               throw new Exception("!SOURCE TYPE");\r
+\r
+                       reply = sourceFtp.retr(sourceFileName);\r
+                       if (!FTPReply.isPositivePreliminary(reply))\r
+                               throw new Exception("RETR parancs válasza: " + sourceFtp.getReplyString());\r
+\r
+                       if (!targetFtp.setFileType(FTP.BINARY_FILE_TYPE))\r
+                               throw new Exception("!TARGET TYPE");\r
+\r
+                       reply = targetFtp.stor(targetFileName);\r
+                       if (!FTPReply.isPositivePreliminary(reply))\r
+                               throw new Exception("STOR parancs válasza: " + sourceFtp.getReplyString());\r
+\r
+                       while (true) {\r
+                               reply = sourceFtp.stat();\r
+                               if (!FTPReply.isPositiveCompletion(reply))\r
+                                       throw new Exception("STAT parancs válasza: " + sourceFtp.getReplyString());\r
+\r
+                               //logger.info("Status: {}", sourceFtp.getReplyString());\r
+                               if (reply == 226) {\r
+                                       break;\r
+                               }\r
+                               Thread.sleep(1000);\r
+                       }\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       throw e;\r
+               } finally {\r
+                       sourceUri.cleanUp();\r
+                       targetUri.cleanUp();\r
+               }\r
+\r
+       }\r
+\r
+       private void transferMetadata(String fileName, BasicDBObject metadata) throws Exception {\r
+               logger.info("Transfer metadata {}", fileName);\r
+               OutputStream outStream = null;\r
+               try {\r
+                       targetFtp = ((FtpDirectoryLister) targetUri.getLister()).connect();\r
+                       if (!targetFtp.changeWorkingDirectory(EscortFiles.STATUSFOLDER)) {\r
+                               targetFtp.makeDirectory(EscortFiles.STATUSFOLDER);\r
+                               if (!targetFtp.changeWorkingDirectory(EscortFiles.STATUSFOLDER))\r
+                                       throw new Exception("!STATUSFOLDER");\r
+                       }\r
+\r
+                       outStream = targetFtp.storeFileStream(fileName + JSON_EXT);\r
+                       if (outStream == null) {\r
+                               throw new NullPointerException("Can not open: " + fileName + JSON_EXT + " Reply:" + targetFtp.getReplyString());\r
+                       }\r
+                       outStream.write(metadata.toString().getBytes(UTF_8));\r
+                       outStream.flush();\r
+                       //targetFtp.changeToParentDirectory();\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       throw e;\r
+               } finally {\r
+                       if (outStream != null)\r
+                               outStream.close();\r
+                       targetUri.cleanUp();\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/CreateArchiveItemStep.java b/server/-product/production/HIRTV/jobs/steps/CreateArchiveItemStep.java
new file mode 100644 (file)
index 0000000..b169edf
--- /dev/null
@@ -0,0 +1,45 @@
+package user.jobengine.server.steps;\r
+\r
+import java.nio.file.Paths;\r
+\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+\r
+import com.ibm.nosql.json.api.BasicDBObject;\r
+import com.ibm.nosql.json.api.DB;\r
+import com.ibm.nosql.json.api.DBCollection;\r
+\r
+import user.commons.nosql.NoSQLUtils;\r
+import user.jobengine.db.Media;\r
+import user.jobengine.db.Store;\r
+\r
+public class CreateArchiveItemStep extends JobStep {\r
+       private static final Logger logger = LogManager.getLogger();\r
+\r
+       @StepEntry\r
+       public Object[] execute(Media mediaCubeMedia, String localHiresPath) throws Exception {\r
+               DB db = NoSQLUtils.getNoSQLDB();\r
+               DBCollection collection = db.getCollection("missing_lowres");\r
+               Store highResStore = getManager().getSystemStore(false);\r
+\r
+               ArchiveItem archiveItem = null;\r
+               try {\r
+                       if (mediaCubeMedia.getMediaFilesCount() != 1)\r
+                               throw new Exception("Expected media count is 1, found " + mediaCubeMedia.getMediaFilesCount());\r
+                       if (mediaCubeMedia.getMediaFiles().get(0).getStoreId() != highResStore.getId())\r
+                               throw new Exception("Expected media store is a high-res store");\r
+\r
+                       String name = mediaCubeMedia.getMediaFileRealName();\r
+                       archiveItem = new ArchiveItem();\r
+                       archiveItem.setMediaFile(Paths.get(localHiresPath, name).toString());\r
+                       collection.save(new BasicDBObject("name", name));\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       logger.info(getMarker(), e.getMessage());\r
+                       throw e;\r
+               } finally {\r
+                       setProgress(100);\r
+               }\r
+               return new Object[] { archiveItem };\r
+       }\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/CreateMissingLowresStep.java b/server/-product/production/HIRTV/jobs/steps/CreateMissingLowresStep.java
new file mode 100644 (file)
index 0000000..519b28a
--- /dev/null
@@ -0,0 +1,92 @@
+package user.jobengine.server.steps;\r
+\r
+import java.nio.file.Paths;\r
+\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+\r
+import com.ibm.nosql.json.api.BasicDBObject;\r
+import com.ibm.nosql.json.api.DB;\r
+import com.ibm.nosql.json.api.DBCollection;\r
+\r
+import user.commons.log4j2.marker.MediaCubeUndoMarker;\r
+import user.commons.nosql.NoSQLUtils;\r
+import user.jobengine.db.IItemManager;\r
+import user.jobengine.db.Media;\r
+import user.jobengine.db.MediaFile;\r
+import user.jobengine.server.IJobEngine;\r
+import user.jobengine.server.IJobRuntime;\r
+\r
+public class CreateMissingLowresStep extends JobStep {\r
+       private static final Logger logger = LogManager.getLogger();\r
+\r
+       @StepEntry\r
+       public Object[] execute(String localHiresPath, IJobEngine jobEngine, IJobRuntime jobRuntime) throws Exception {\r
+               Object[] result = new Object[] { null, null, "%s", null, 0, true };\r
+\r
+               DB db = NoSQLUtils.getNoSQLDB();\r
+               DBCollection collection = db.getCollection("missing_lowres");\r
+               IItemManager manager = jobEngine.getItemManager();\r
+               Media media = getFirstUntranscodedMedia(manager, collection);\r
+\r
+               try {\r
+                       if (media == null) {\r
+                               logger.info(new MediaCubeUndoMarker(getSessionMarker().getSessionID()), "Nincs feldolgozandó hiány.");\r
+                               // throw new Exception("Nincs feldolgozandó hiány.");\r
+                               cancel();\r
+                               return null;\r
+                       }\r
+\r
+                       String name = media.getMediaFileRealName();\r
+                       result[0] = media;\r
+                       ArchiveItem archiveItem = new ArchiveItem();\r
+                       archiveItem.setMediaFile(Paths.get(localHiresPath, name).toString());\r
+                       result[1] = archiveItem;\r
+                       collection.save(new BasicDBObject("name", name));\r
+                       logger.info(getSessionMarker(), "Processing mediaID: {}", media.getId());\r
+\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       logger.error(getSessionMarker(), e.getMessage());\r
+                       throw e;\r
+               } finally {\r
+                       setProgress(100);\r
+               }\r
+               return result;\r
+       }\r
+\r
+       private Media getFirstUntranscodedMedia(IItemManager manager, DBCollection collection) {\r
+               Media[] result = new Media[] { null };\r
+               // MV\r
+               String query = "SELECT mediaid FROM VW_MISSING_PROXY_IDS WHERE HOUSEID like 'M%' or HOUSEID like 'P%' or HOUSEID like 'R%' ORDER BY modified DESC";\r
+\r
+               // HTV\r
+               // String query = "SELECT mediaid FROM VW_MISSING_PROXY_IDS";\r
+               manager.executeQuery(query, rs -> {\r
+                       try {\r
+                               long mediaId = rs.getLong(1);\r
+                               Media media = manager.getMedia(mediaId);\r
+                               // a nevgeneralas miatt az eredeti MediaFilesName nem jo, a pontos nev kell\r
+                               // nekunk\r
+                               String name = media.getMediaFileRealName();\r
+                               logger.info(getSessionMarker(), "Checking {}", name);\r
+                               long existing = collection.find(new BasicDBObject("name", name)).count();\r
+                               if (existing > 0) {\r
+                                       // logger.info(getSessionMarker(), "{} is on missing_lowres list", name);\r
+                                       return true;\r
+                               }\r
+\r
+                               // 210617 proxy keszites tiltasa\r
+                               MediaFile mf = manager.getSystemMediaFile(media);\r
+                               if (mf.isDisableProxy())\r
+                                       return true;\r
+\r
+                               result[0] = media;\r
+                       } catch (Exception e) {\r
+                               logger.error(e);\r
+                       }\r
+                       return false;\r
+               }, null);\r
+               return result[0];\r
+       }\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/DeleteFileStep.java b/server/-product/production/HIRTV/jobs/steps/DeleteFileStep.java
new file mode 100644 (file)
index 0000000..79734f5
--- /dev/null
@@ -0,0 +1,36 @@
+package user.jobengine.server.steps;\r
+\r
+import java.io.File;\r
+import java.nio.file.Path;\r
+import java.nio.file.Paths;\r
+\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+import org.apache.logging.log4j.Marker;\r
+\r
+public class DeleteFileStep extends JobStep {\r
+       private static final Logger logger = LogManager.getLogger();\r
+       private Marker marker;\r
+\r
+       @StepEntry\r
+       public Object[] execute(ArchiveItem archiveItem, boolean isDelete) throws Exception {\r
+               marker = getJobRuntime().getSessionMarker();\r
+               if (isDelete) {\r
+                       Path filePath = Paths.get(archiveItem.getMediaFile());\r
+                       File file = filePath.toFile();\r
+                       if (file.exists()) {\r
+                               if (!file.isDirectory()) {\r
+                                       try {\r
+                                               file.delete();\r
+                                       } catch (Exception e) {\r
+                                               logger.error(marker, "A '{}' fájl nem törölhető. A rendszer üzenete: {}", filePath, e.getMessage());\r
+                                       }\r
+\r
+                               } else\r
+                                       logger.warn(marker, "A '{}' elérés egy mappa.", filePath);\r
+                       } else\r
+                               logger.warn(marker, "A '{}' fájl nem található.", filePath);\r
+               }\r
+               return null;\r
+       }\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/DeleteNEXIOMaterialsStep.java b/server/-product/production/HIRTV/jobs/steps/DeleteNEXIOMaterialsStep.java
new file mode 100644 (file)
index 0000000..d13b3af
--- /dev/null
@@ -0,0 +1,121 @@
+package user.jobengine.server.steps;\r
+\r
+import java.text.SimpleDateFormat;\r
+import java.util.Calendar;\r
+import java.util.List;\r
+\r
+import org.apache.commons.lang.StringUtils;\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+\r
+import com.ibm.nosql.json.api.BasicDBList;\r
+import com.ibm.nosql.json.api.BasicDBObject;\r
+import com.ibm.nosql.json.api.DB;\r
+import com.ibm.nosql.json.api.DBCollection;\r
+import com.ibm.nosql.json.api.DBCursor;\r
+import com.ibm.nosql.json.api.QueryBuilder;\r
+\r
+import user.commons.ListUtils;\r
+import user.commons.RemoteFile;\r
+import user.commons.StoreUri;\r
+import user.commons.configuration.SystemConfiguration;\r
+import user.commons.nosql.NoSQLUtils;\r
+import user.commons.remotestore.RemoteStoreProtocol;\r
+import user.jobengine.db.IItemManager;\r
+import user.jobengine.server.IJobEngine;\r
+import user.jobengine.server.IJobRuntime;\r
+\r
+public class DeleteNEXIOMaterialsStep extends JobStep {\r
+       private static final Logger logger = LogManager.getLogger(DeleteNEXIOMaterialsStep.class);\r
+       //"nexioclips"\r
+       private static final String NEXIOCLIPS = SystemConfiguration.getInstance().value("services.nexio.collection-name");\r
+       private static final String KILLDATE = "killdate";\r
+       private static final String RECORDDATE = "recorddate";\r
+       private static final String LONGNAMEID = "longnameid";\r
+       private static final String EXTAGENCY = "extagency";\r
+       private static String NEXIO_HOST = SystemConfiguration.getInstance().value("services.nexio.host");\r
+       private StoreUri sourceUri;\r
+       private IJobRuntime jobRuntime;\r
+\r
+       private void delete(String name) {\r
+               RemoteFile remoteFile = null;\r
+               try {\r
+                       remoteFile = sourceUri.getRemoteFile(name);\r
+                       if (remoteFile == null) {\r
+                               logger.warn(jobRuntime.getSessionMarker(), "A '{}' fájl már nem található meg a NEXIO szerveren", name);\r
+                               logger.warn(getMarker(), "A '{}' fájl már nem található meg a NEXIO szerveren", name);\r
+                               return;\r
+                       }\r
+                       sourceUri.delete(remoteFile);\r
+                       logger.info(jobRuntime.getSessionMarker(), "A '{}' fájl törlése sikeres volt.", name);\r
+                       logger.info(getMarker(), "A '{}' fájl törlése sikeres volt.", name);\r
+               } catch (Exception e) {\r
+                       logger.error(jobRuntime.getSessionMarker(), "A '{}' fájl nem törölhető. A rendszer hibaüzenete: {}", name,\r
+                                       e.getMessage());\r
+                       logger.error(getMarker(), "A '{}' fájl nem törölhető. A rendszer hibaüzenete: {}", name, e.getMessage());\r
+               }\r
+       }\r
+\r
+       @StepEntry\r
+       public Object[] execute(int port, String userName, String password, String filterAgencies, int gracePeriodDays,\r
+                       boolean notificationOnly, IJobEngine jobEngine, IJobRuntime jobRuntime) throws Exception {\r
+               this.jobRuntime = jobRuntime;\r
+               logger.info(getMarker(), "TESZT");\r
+               if (StringUtils.isBlank(NEXIO_HOST)) {\r
+                       logger.error(jobRuntime.getSessionMarker(), "A 'nexio.host' rendszer paraméter nem található.");\r
+                       throw new NullPointerException(\r
+                                       "System is not configured properly, 'nexio.host' startup parameter missing.");\r
+               }\r
+\r
+               if (StringUtils.isBlank(filterAgencies)) {\r
+                       logger.error(jobRuntime.getSessionMarker(), "A 'nexioAgencies' folyamat paraméter nem található.");\r
+                       throw new NullPointerException("System is not configured properly, 'nexioAgencies' job parameter missing.");\r
+               }\r
+\r
+               DB db = NoSQLUtils.getNoSQLDB();\r
+               DBCollection collection = db.getCollection(NEXIOCLIPS);\r
+               //https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html\r
+               //http://www.vogella.com/tutorials/JavaRegularExpressions/article.html\r
+               //              if (StringUtils.isNotBlank(fileNameRegex))\r
+               //                      queryBuilder.and(QueryBuilder.start(LONGNAMEID).regex(Pattern.compile(fileNameRegex)).get());\r
+               Calendar now = Calendar.getInstance();\r
+               now.add(Calendar.DAY_OF_YEAR, gracePeriodDays * -1);\r
+               BasicDBList agencies = new BasicDBList((Object[]) filterAgencies.split(","));\r
+\r
+               QueryBuilder dateQueryBuilder = QueryBuilder.start(KILLDATE).lessThan(now.getTime());\r
+               QueryBuilder queryBuilder = QueryBuilder.start(EXTAGENCY).in(agencies).and(dateQueryBuilder.get());\r
+               DBCursor cursor = collection.find(queryBuilder.get()).sort(KILLDATE, -1);\r
+\r
+               if (!cursor.hasNext())\r
+                       return null;\r
+\r
+               IItemManager manager = jobEngine.getItemManager();\r
+               sourceUri = manager.createStoreUri(RemoteStoreProtocol.FTP, NEXIO_HOST);\r
+               sourceUri.setPortNumber(port);\r
+               sourceUri.setUserName(userName);\r
+               sourceUri.setPassword(password);\r
+\r
+               List<BasicDBObject> clips = ListUtils.cast(cursor.toArray());\r
+               SimpleDateFormat dffull = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");\r
+               logger.info(getMarker(), "{} fájl vizsgálata elindul a {} lista alapján", clips.size(), NEXIOCLIPS);\r
+               int i = 0;\r
+               for (BasicDBObject clip : clips) {\r
+                       String name = String.valueOf(clip.get(LONGNAMEID));\r
+                       //logger.info(getMarker(), name);\r
+                       String agency = String.valueOf(clip.get(EXTAGENCY));\r
+\r
+                       logger.info(getMarker(), "Az {} fájl törölhető. Rögzítve: {}, Lejárt: {}, Agency: {} ", name,\r
+                                       dffull.format(clip.getDate(RECORDDATE)), dffull.format(clip.getDate(KILLDATE)), agency);\r
+\r
+                       if (!notificationOnly)\r
+                               delete(name);\r
+\r
+                       i++;\r
+                       int progress = i * 100 / clips.size();\r
+                       setProgress(progress);\r
+               }\r
+\r
+               return null;\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/DetectMissingLengthStep.java b/server/-product/production/HIRTV/jobs/steps/DetectMissingLengthStep.java
new file mode 100644 (file)
index 0000000..830e41f
--- /dev/null
@@ -0,0 +1,68 @@
+package user.jobengine.server.steps;\r
+\r
+import java.nio.file.Paths;\r
+\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+import org.apache.logging.log4j.Marker;\r
+\r
+import com.ibm.nosql.json.api.BasicDBObject;\r
+import com.ibm.nosql.json.api.DB;\r
+import com.ibm.nosql.json.api.DBCollection;\r
+import com.ibm.nosql.json.api.DBObject;\r
+\r
+import user.commons.nosql.NoSQLUtils;\r
+import user.jobengine.db.IItemManager;\r
+import user.jobengine.db.IResultSetConsumer;\r
+import user.jobengine.db.Media;\r
+import user.jobengine.server.IJobEngine;\r
+import user.jobengine.server.IJobRuntime;\r
+\r
+public class DetectMissingLengthStep extends JobStep {\r
+       private static final Logger logger = LogManager.getLogger();\r
+       private Marker marker;\r
+\r
+       @StepEntry\r
+       public Object[] execute(String localHiresPath, IJobEngine jobEngine, IJobRuntime jobRuntime) throws Exception {\r
+               Object[] result = new Object[] { null, null, "%s", null, 0, true };\r
+               marker = jobRuntime.getSessionMarker();\r
+\r
+               DB db = NoSQLUtils.getNoSQLDB();\r
+               DBCollection collection = db.getCollection("missing_length");\r
+               IItemManager manager = jobEngine.getItemManager();\r
+\r
+               try {\r
+                       String query = "select id from media where length=0 order by archived desc";\r
+                       IResultSetConsumer consumer = rs -> {\r
+                               Media media = manager.getMedia(rs.getLong("id"));\r
+                               media.setPersister(manager);\r
+                               return process(collection, result, localHiresPath, media);\r
+                       };\r
+                       manager.executeQuery(query.toString(), consumer, null);\r
+                       if (result[0] == null)\r
+                               throw new Exception("Nincs feldolgozandó hiány.");\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       logger.error(marker, e.getMessage());\r
+               } finally {\r
+                       setProgress(100);\r
+               }\r
+               return result;\r
+       }\r
+\r
+       public boolean process(DBCollection collection, Object[] result, String localHiresPath, Media media) {\r
+               String name = media.getMediaFilesName();\r
+               if (name == null)\r
+                       return true;\r
+               DBObject existing = collection.findOne(new BasicDBObject("name", name));\r
+               if (existing != null)\r
+                       return true;\r
+\r
+               result[0] = media;\r
+               ArchiveItem archiveItem = new ArchiveItem();\r
+               archiveItem.setMediaFile(Paths.get(localHiresPath, name).toString());\r
+               result[1] = archiveItem;\r
+               collection.save(new BasicDBObject("name", name));\r
+               return false;\r
+       }\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/DownloadRecordingFromNexioStep.java b/server/-product/production/HIRTV/jobs/steps/DownloadRecordingFromNexioStep.java
new file mode 100644 (file)
index 0000000..c65ab01
--- /dev/null
@@ -0,0 +1,182 @@
+package user.jobengine.server.steps;\r
+\r
+import java.io.File;\r
+import java.nio.file.Paths;\r
+\r
+import org.apache.commons.lang.StringUtils;\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+import org.apache.logging.log4j.Marker;\r
+import org.apache.logging.log4j.message.Message;\r
+import org.apache.logging.log4j.message.ParameterizedMessage;\r
+\r
+import com.ibm.nosql.json.api.BasicDBObject;\r
+import com.ibm.nosql.json.api.DB;\r
+import com.ibm.nosql.json.api.DBCollection;\r
+\r
+import user.commons.RemoteFile;\r
+import user.commons.StoreUri;\r
+import user.commons.configuration.SystemConfiguration;\r
+import user.commons.nosql.NoSQLUtils;\r
+import user.commons.remotestore.IProgressEventListener;\r
+import user.commons.remotestore.IStatusEventListener;\r
+import user.commons.remotestore.ProgressEvent;\r
+import user.commons.remotestore.RemoteStoreProtocol;\r
+import user.commons.remotestore.StatusEvent;\r
+import user.jobengine.db.IItemManager;\r
+import user.jobengine.server.IJobEngine;\r
+import user.jobengine.server.IJobRuntime;\r
+\r
+public class DownloadRecordingFromNexioStep extends JobStep {\r
+       private static final String MXFEXT = ".MXF";\r
+       private static final String NEXIOCLIPS = "nexioclips";\r
+       private static final String LONGNAMEID = "longnameid";\r
+       private static final String DURATION = "duration";\r
+       private static final Logger logger = LogManager.getLogger();\r
+\r
+       private String NEXIO_HOST = SystemConfiguration.getInstance().value("services.nexio.host");\r
+\r
+       private IItemManager manager;\r
+       private StoreUri targetUri;\r
+       private StoreUri sourceUri;\r
+       private Marker marker;\r
+       private DBCollection clipsCollection;\r
+\r
+       private int check(int value, String name) {\r
+               if (value == 0) {\r
+                       logger.error(marker, "A folyamat '{}' bemeneti paramétere 0.", name);\r
+                       throw new NullPointerException(\r
+                                       String.format("System is not configured properly, missing '%s' input parameter.", name));\r
+               }\r
+               return value;\r
+       }\r
+\r
+       private String check(String value, String name) {\r
+               if (StringUtils.isBlank(value)) {\r
+                       logger.error(marker, "A folyamat '{}' bemeneti paramétere üres.", name);\r
+                       throw new NullPointerException(\r
+                                       String.format("System is not configured properly, missing '%s' input parameter.", name));\r
+               }\r
+               return value;\r
+       }\r
+\r
+       @StepEntry\r
+       public Object[] execute(ArchiveItem archiveItem, String targetPath, String targetFileName, int nexioPort,\r
+                       String nexioUserName, String nexioPassword, IJobEngine jobEngine, IJobRuntime jobRuntime) throws Exception {\r
+               marker = jobRuntime.getSessionMarker();\r
+               manager = jobEngine.getItemManager();\r
+               setAndCheck(archiveItem, targetPath, targetFileName, nexioPort, nexioUserName, nexioPassword);\r
+               String sourceFileName = targetFileName;\r
+               try {\r
+                       final IJobRuntime runtime = jobRuntime;\r
+\r
+                       RemoteFile sourceFile = null;\r
+                       while (sourceFile == null) {\r
+                               try {\r
+                                       sourceFile = sourceUri.getRemoteFile(sourceFileName);\r
+                                       Thread.sleep(1000);\r
+                               } catch (Exception e) {\r
+                                       logger.warn(e.getMessage());\r
+                               }\r
+                       }\r
+\r
+                       targetUri.addProgressListener(new IProgressEventListener() {\r
+                               @Override\r
+                               public void progressChanged(ProgressEvent evt) {\r
+                                       runtime.incrementProgress(evt.getProgress());\r
+                               }\r
+                       });\r
+                       targetUri.addStatusListener(new IStatusEventListener() {\r
+                               @Override\r
+                               public void statusChanged(StatusEvent evt) {\r
+                                       evt.setCancel(!canContinue());\r
+                               }\r
+                       });\r
+\r
+                       String targetName = targetFileName + MXFEXT;\r
+\r
+                       File targetFile = Paths.get(targetPath, targetName).toFile();\r
+                       if (targetFile.exists())\r
+                               throw new Exception("Exists!");\r
+\r
+                       RemoteFile remoteFile = sourceUri.transferFrom(targetUri, sourceFileName, targetName);\r
+\r
+                       logger.info(marker, "Az '{}' állomány letöltése sikeres volt '{}' néven.", sourceFileName, targetFile);\r
+\r
+                       BasicDBObject clip = (BasicDBObject) clipsCollection.findOne(new BasicDBObject(LONGNAMEID, sourceFileName));\r
+                       if (clip == null)\r
+                               throw new Exception("Clip does not exist in NEXIO");\r
+\r
+                       long duration = NoSQLUtils.asLong(clip, DURATION);\r
+                       if (duration == 0)\r
+                               throw new Exception("Clip duration is 0");\r
+\r
+                       archiveItem.setDuration(duration);\r
+                       archiveItem.setMediaFile(targetFile.toString());\r
+\r
+                       RemoteFile sourceRemoteFile = sourceUri.getRemoteFile(sourceFileName);\r
+                       sourceUri.delete(sourceRemoteFile);\r
+\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       if (!archiveItem.removeCatchedFile())\r
+                               logger.error(getMarker(), "A {} állomány .catched jelző állománya nem törölhető.",\r
+                                               new File(archiveItem.getMediaFile()).getName());\r
+                       Message m = new ParameterizedMessage("Az '{}' állomány feldolgozása sikertelen. A rendszer hibaüzenete: {}",\r
+                                       sourceFileName, e.getMessage());\r
+                       logger.error(marker, m);\r
+                       throw new Exception(m.getFormattedMessage());\r
+               }\r
+               return new Object[] { 0 };\r
+       }\r
+\r
+       private void setAndCheck(ArchiveItem archiveItem, String targetPath, String targetFileName, int nexioPort,\r
+                       String nexioUserName, String nexioPassword) throws Exception {\r
+               DB db = NoSQLUtils.getNoSQLDB();\r
+               if (db == null) {\r
+                       logger.error(marker, "Az NoSQL adatkezelő réteg nem elérhető.");\r
+                       throw new NullPointerException("Internal error, missing NoSQL DB reference.");\r
+               }\r
+\r
+               clipsCollection = db.getCollection(NEXIOCLIPS);\r
+\r
+               if (archiveItem == null) {\r
+                       logger.error(marker, "A folyamat 'archiveItem' bemeneti paramétere üres.");\r
+                       throw new NullPointerException("Internal error, missing 'archiveItem'.");\r
+               }\r
+\r
+               if (archiveItem.getMediaFile() == null) {\r
+                       logger.error(marker, "A folyamat 'archiveItem.mediaFile' paramétere üres.");\r
+                       throw new NullPointerException("Internal error, missing 'archiveItem.mediaFile'.");\r
+               }\r
+\r
+               check(targetFileName, "targetFileName");\r
+               check(targetPath, "targetPath");\r
+\r
+               if (StringUtils.isBlank(NEXIO_HOST)) {\r
+                       logger.error(marker, "A 'nexio.host' rendszer paraméter nem található.");\r
+                       throw new NullPointerException(\r
+                                       "System is not configured properly, 'jobengine.selenio.address' startup parameter missing.");\r
+               }\r
+               check(nexioPort, "nexioPort");\r
+               check(nexioUserName, "nexioUserName");\r
+               check(nexioPassword, "nexioPassword");\r
+\r
+               sourceUri = manager.createStoreUri(RemoteStoreProtocol.FTP, NEXIO_HOST);\r
+               sourceUri.setPortNumber(nexioPort);\r
+               sourceUri.setUserName(nexioUserName);\r
+               sourceUri.setPassword(nexioPassword);\r
+               if (sourceUri == null) {\r
+                       logger.error(marker, "A forrás nem elérhető.");\r
+                       throw new NullPointerException("Internal error, missing 'sourceUri'.");\r
+               }\r
+\r
+               targetUri = manager.createStoreUri(RemoteStoreProtocol.LOCAL, targetPath);\r
+               if (targetUri == null) {\r
+                       logger.error(marker, "A cél nem elérhető.");\r
+                       throw new NullPointerException("Internal error, missing 'targetUri'.");\r
+               }\r
+\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/DuplicateRemoverStep.java b/server/-product/production/HIRTV/jobs/steps/DuplicateRemoverStep.java
new file mode 100644 (file)
index 0000000..5e407eb
--- /dev/null
@@ -0,0 +1,102 @@
+package user.jobengine.server.steps;\r
+\r
+import java.nio.file.Files;\r
+import java.nio.file.Path;\r
+import java.nio.file.Paths;\r
+\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+import org.apache.logging.log4j.Marker;\r
+\r
+import user.jobengine.db.IItemManager;\r
+import user.jobengine.db.IResultSetConsumer;\r
+import user.jobengine.db.IStatementDecorator;\r
+import user.jobengine.db.MediaFile;\r
+import user.jobengine.server.IJobEngine;\r
+import user.jobengine.server.IJobRuntime;\r
+import user.jobengine.server.steps.shared.EscortFiles;\r
+\r
+public class DuplicateRemoverStep extends JobStep {\r
+       private static final Logger logger = LogManager.getLogger();\r
+       private static final String LOWRES_ROOT = "/mediacube/data/lowres/www/video";\r
+       private static final String DUPLICATES_ROOT = "/mediacube/data/lowres/www";\r
+\r
+       private Marker marker;\r
+       private IItemManager manager;\r
+\r
+       @StepEntry\r
+       public Object[] execute(int limit, IJobEngine jobEngine, IJobRuntime jobRuntime) throws Exception {\r
+               marker = jobRuntime.getSessionMarker();\r
+               manager = jobEngine.getItemManager();\r
+               processLowresDuplicates(limit);\r
+               return null;\r
+       }\r
+\r
+       public void processLowresDuplicates(int limit) {\r
+               long count[] = new long[] { 0, 0 };\r
+\r
+               manager.executeQuery("select count(filecount) from vw_items_rd_dup", rs -> {\r
+                       count[0] = rs.getLong(1);\r
+                       return false;\r
+               }, null);\r
+\r
+               if (count[0] == 0) {\r
+                       setProgress(100);\r
+                       return;\r
+               }\r
+\r
+               if (limit > 0)\r
+                       count[0] = limit;\r
+\r
+               manager.executeQuery("select filename from vw_items_rd_dup order by filecount desc", rs -> {\r
+                       String fileName = rs.getString("filename");\r
+                       innerProcessLowresDuplicates(fileName);\r
+                       count[1]++;\r
+                       int progress = (int) ((double) count[1] * 100 / count[0]);\r
+                       setProgress(progress);\r
+                       if (count[0] == count[1])\r
+                               return false;\r
+                       else\r
+                               return true;\r
+               }, null);\r
+       }\r
+\r
+       private void innerProcessLowresDuplicates(String fileName) {\r
+               String query = "select mediafileid, mediafilehouseid, relativepath from vw_items_rd_lh where filename = ?";\r
+               IStatementDecorator decorator = st -> {\r
+                       st.setString(1, fileName);\r
+               };\r
+\r
+               MediaFile[] masterMediaFile = { null };\r
+\r
+               IResultSetConsumer consumer = rs -> {\r
+                       long mediaFileId = rs.getLong("mediafileid");\r
+                       MediaFile mediaFile = (MediaFile) manager.get(MediaFile.class, mediaFileId);\r
+                       if (masterMediaFile[0] == null) {\r
+                               masterMediaFile[0] = mediaFile;\r
+                               return true;\r
+                       }\r
+\r
+                       String path = rs.getString("relativepath");\r
+                       boolean moved = false;\r
+                       try {\r
+                               Path target = Paths.get(DUPLICATES_ROOT, path);\r
+                               EscortFiles.ensureUNCFolder(target.getParent());\r
+                               Files.move(Paths.get(LOWRES_ROOT, path), target);\r
+                               moved = true;\r
+                       } catch (Exception e) {\r
+                               logger.catching(e);\r
+                       }\r
+\r
+                       if (moved) {\r
+                               logger.info(marker, "{} {} {}", mediaFile.getMediaId(), mediaFile.getRelativePath(),\r
+                                               masterMediaFile[0].getRelativePath());\r
+                               mediaFile.setRelativePath(masterMediaFile[0].getRelativePath());\r
+                               manager.modify(mediaFile);\r
+                       }\r
+                       return true;\r
+               };\r
+               manager.executeQuery(query, consumer, decorator);\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/GenerateMorpheusMetadataStep.java b/server/-product/production/HIRTV/jobs/steps/GenerateMorpheusMetadataStep.java
new file mode 100644 (file)
index 0000000..f27dd07
--- /dev/null
@@ -0,0 +1,32 @@
+package user.jobengine.server.steps;\r
+\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+\r
+import com.ibm.nosql.json.api.BasicDBObject;\r
+\r
+import user.commons.morpheus.MorpheusStrings;\r
+import user.jobengine.server.IJobEngine;\r
+import user.jobengine.server.IJobRuntime;\r
+import user.jobengine.server.steps.shared.EscortFiles;\r
+import user.jobengine.server.steps.shared.PlanAirExtensions;\r
+\r
+public class GenerateMorpheusMetadataStep extends JobStep {\r
+       private static final Logger logger = LogManager.getLogger();\r
+\r
+       @StepEntry\r
+       public Object[] execute(BasicDBObject material, String morpheusDeviceID, String dbUrl, String userName, String password, String targetMetadataPath,\r
+                       IJobEngine jobEngine, IJobRuntime jobRuntime) throws Exception {\r
+               try {\r
+                       String name = material.getString(MorpheusStrings.MATERIALID);\r
+                       String content = PlanAirExtensions.getMorpeusXML(jobEngine.getItemManager(), dbUrl, userName, password, name, morpheusDeviceID);\r
+                       EscortFiles.createMorpheusXML(targetMetadataPath, name + ".xml", content);\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       logger.error(jobRuntime.getSessionMarker(), "Hiba a Morpheus kísérő XML létrehozásakor. A rendszer üzenete: {}", e.getMessage());\r
+                       throw e;\r
+               }\r
+               return null;\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/HLSProxyStep.java b/server/-product/production/HIRTV/jobs/steps/HLSProxyStep.java
new file mode 100644 (file)
index 0000000..7d2704c
--- /dev/null
@@ -0,0 +1,77 @@
+package user.jobengine.server.steps;\r
+\r
+import java.nio.file.Path;\r
+import java.nio.file.Paths;\r
+\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+import org.apache.logging.log4j.Marker;\r
+\r
+import user.commons.StoreUri;\r
+import user.commons.remotestore.RemoteStoreProtocol;\r
+import user.jobengine.db.Media;\r
+import user.jobengine.db.MediaFile;\r
+import user.jobengine.db.Store;\r
+import user.jobengine.server.steps.shared.EscortFiles;\r
+import user.jobengine.server.steps.shared.FFMpeg;\r
+\r
+public class HLSProxyStep extends JobStep {\r
+       private static final Logger logger = LogManager.getLogger();\r
+       private static final String LOWRES_FILETYPE = "Low-res";\r
+       private Marker marker;\r
+\r
+       @StepEntry\r
+       public Object[] execute(ArchiveItem archiveItem, Media mediaCubeMedia) throws Exception {\r
+               marker = getSessionMarker();\r
+\r
+               Path sourceFilePath = Paths.get(archiveItem.getMediaFile());\r
+               try {\r
+                       String fileName = sourceFilePath.getFileName().toString();\r
+                       String proxyName = fileName.substring(0, fileName.lastIndexOf(".")) + "S01" + fileName.substring(fileName.lastIndexOf("."));\r
+                       Path lowresSourcePath = Paths.get(sourceFilePath.getParent().toString(), EscortFiles.STATUSFOLDER, proxyName);\r
+                       if (!lowresSourcePath.toFile().exists()) {\r
+                               logger.info(marker, "HLS proxy not found for {}", archiveItem.getMediaFile());\r
+                               return null;\r
+                       }\r
+\r
+                       Store lowresStore = getManager().getCurrentLowresStore();\r
+                       StoreUri lowresStoreUri = lowresStore.getTargetStoreUri(RemoteStoreProtocol.LOCAL);\r
+                       String webPath = lowresStoreUri.toString(true);\r
+\r
+                       Path subdirPath = null;\r
+                       if (proxyName.indexOf(".") > 2) {\r
+                               subdirPath = Paths.get(proxyName.substring(0, 1), proxyName.substring(1, 2), proxyName.substring(2, 3), proxyName);\r
+                       } else {\r
+                               subdirPath = Paths.get(proxyName);\r
+                       }\r
+\r
+                       String subDir = subdirPath.toString();\r
+                       Path lowresTargetPath = Paths.get(webPath, subDir);\r
+\r
+                       int version = 1;\r
+                       while (lowresTargetPath.toFile().exists()) {\r
+                               subDir = subDir + version;\r
+                               lowresTargetPath = Paths.get(webPath, subDir);\r
+                               version++;\r
+                       }\r
+\r
+                       EscortFiles.ensureUNCFolder(webPath, subDir);\r
+                       lowresTargetPath = Paths.get(webPath, subDir);\r
+                       // Files.move(lowresSourcePath, lowresTargetPath);\r
+\r
+                       FFMpeg.hls_audio4ch(lowresSourcePath.toAbsolutePath().toString(), lowresTargetPath.toAbsolutePath().toString(), p -> {\r
+                               setProgress((int) p);\r
+                       });\r
+\r
+                       Path lowresHTTPPath = Paths.get(subDir, "index.m3u8");\r
+                       MediaFile mediaFile = getManager().createMediaFile(lowresHTTPPath.toString(), LOWRES_FILETYPE, lowresStore.getName());\r
+                       mediaFile.setMediaId(mediaCubeMedia.getId());\r
+                       getManager().add(mediaFile);\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       logger.error(marker, "A HLS proxy létrehozása sikertelen a '{}' fájlból. A rendszer üzenete: {}", sourceFilePath, e.getMessage());\r
+               }\r
+               return null;\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/ImportMORPHEUSMissingMaterialsStep.java b/server/-product/production/HIRTV/jobs/steps/ImportMORPHEUSMissingMaterialsStep.java
new file mode 100644 (file)
index 0000000..f2216a3
--- /dev/null
@@ -0,0 +1,255 @@
+package user.jobengine.server.steps;\r
+\r
+import java.io.File;\r
+import java.io.IOException;\r
+import java.nio.charset.Charset;\r
+import java.nio.file.DirectoryStream;\r
+import java.nio.file.Files;\r
+import java.nio.file.Path;\r
+import java.nio.file.Paths;\r
+import java.text.SimpleDateFormat;\r
+import java.util.ArrayList;\r
+import java.util.Arrays;\r
+import java.util.Date;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Locale;\r
+import java.util.Map;\r
+import java.util.Set;\r
+\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+\r
+import com.ibm.nosql.json.api.BasicDBObject;\r
+import com.ibm.nosql.json.api.DB;\r
+import com.ibm.nosql.json.api.DBCollection;\r
+import com.ibm.nosql.json.api.DBObject;\r
+import com.ibm.nosql.json.api.QueryBuilder;\r
+\r
+import user.commons.IEntityBase;\r
+import user.commons.morpheus.MorpheusStrings;\r
+import user.commons.nosql.NoSQLUtils;\r
+import user.jobengine.db.IItemManager;\r
+import user.jobengine.db.MediaFile;\r
+import user.jobengine.db.MediaFileDAO;\r
+import user.jobengine.server.IJobEngine;\r
+import user.jobengine.server.IJobRuntime;\r
+import user.jobengine.server.steps.shared.EscortFiles;\r
+\r
+public class ImportMORPHEUSMissingMaterialsStep extends JobStep {\r
+       private static final Logger logger = LogManager.getLogger();\r
+\r
+       private static final String CSV_EXT = ".csv";\r
+       private static final String MXF_EXT = ".MXF";\r
+       private MediaFileDAO dao;\r
+       private String processedFolder;\r
+       private DB db;\r
+       private String targetPath;\r
+       private IJobRuntime jobRuntime;\r
+       private int overall;\r
+       private int current;\r
+       private final SimpleDateFormat enDateFormat = new SimpleDateFormat(MorpheusStrings.FORMAT_TIME_TO_AIR, Locale.ENGLISH);\r
+\r
+       private Map<String, Integer> buildMetadataMap(Path csvFilePath, String[] data) throws Exception {\r
+               Map<String, Integer> result = new HashMap<>();\r
+               List<String> dataList = Arrays.asList(data);\r
+               storeMetadataPosition(csvFilePath, dataList, MorpheusStrings.MATERIAL_ID, result);\r
+               storeMetadataPosition(csvFilePath, dataList, MorpheusStrings.CHANNEL, result);\r
+               storeMetadataPosition(csvFilePath, dataList, MorpheusStrings.TIME_TO_AIR, result);\r
+               storeMetadataPosition(csvFilePath, dataList, MorpheusStrings.DURATION, result);\r
+               storeMetadataPosition(csvFilePath, dataList, MorpheusStrings.TITLE, result);\r
+               // storeMetadataPosition(csvFilePath, dataList, MorpheusStrings.DEVICE_ID,\r
+               // result);\r
+               // storeMetadataPosition(csvFilePath, dataList, MorpheusStrings.REASON, result);\r
+               return result;\r
+       }\r
+\r
+       @StepEntry\r
+       public Object[] execute(String sourceCSVPath, String processedFolder, String targetPath, IJobEngine jobEngine, IJobRuntime jobRuntime) throws Exception {\r
+               this.jobRuntime = jobRuntime;\r
+               setAndCheck(sourceCSVPath, processedFolder, targetPath, jobEngine);\r
+\r
+               List<Path> filePaths = new ArrayList<>();\r
+               try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(Paths.get(sourceCSVPath))) {\r
+                       for (Path path : directoryStream) {\r
+                               filePaths.add(path);\r
+                       }\r
+\r
+                       processPathItems(filePaths);\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       logger.error(getSessionMarker(), "Hiba a végrehajtás során. A rendszer üzenete: {}", e.getMessage());\r
+               }\r
+               return null;\r
+       }\r
+\r
+       private void moveProcessedCSV(Path csvFilePath) throws IOException {\r
+               EscortFiles.ensureUNCFolder(csvFilePath.getParent().toString(), processedFolder);\r
+               String fileName = csvFilePath.getFileName().toString() + "." + EscortFiles.composeKillDate(0);\r
+               Path targetPath = Paths.get(csvFilePath.getParent().toString(), processedFolder, fileName);\r
+               Files.move(csvFilePath, targetPath);\r
+       }\r
+\r
+       private void processLine(String[] data, Map<String, Integer> metadatas) throws Exception {\r
+               String channel = data[metadatas.get(MorpheusStrings.CHANNEL)];\r
+               String timeToAir = data[metadatas.get(MorpheusStrings.TIME_TO_AIR)];\r
+               String duration = data[metadatas.get(MorpheusStrings.DURATION)];\r
+               String materialID = data[metadatas.get(MorpheusStrings.MATERIAL_ID)];\r
+               String title = data[metadatas.get(MorpheusStrings.TITLE)];\r
+               // String deviceID = data[metadatas.get(MorpheusStrings.DEVICE_ID)];\r
+               // String reason = data[metadatas.get(MorpheusStrings.REASON)];\r
+\r
+               DBObject query = QueryBuilder.start()\r
+                               .and(QueryBuilder.start(MorpheusStrings.MATERIALID).is(materialID).get(), QueryBuilder.start(MorpheusStrings.TIMETOAIR).is(timeToAir).get())\r
+                               .get();\r
+               DBCollection collection = db.getCollection(MorpheusStrings.COLLECTION_NAME);\r
+               BasicDBObject existingObject = (BasicDBObject) collection.findOne(query);\r
+               if (existingObject != null) {\r
+                       logger.warn(getSessionMarker(), "Az '{}' anyag már feldolgozásra került az {} időpontban.", materialID,\r
+                                       existingObject.getDate(MorpheusStrings.IMPORTED));\r
+                       return;\r
+               }\r
+\r
+               BasicDBObject dbObject = new BasicDBObject(MorpheusStrings.IMPORTED, new Date());\r
+               dbObject.put(MorpheusStrings.CHANNEL, channel);\r
+               dbObject.put(MorpheusStrings.TIMETOAIR, enDateFormat.parse(timeToAir));\r
+               dbObject.put(MorpheusStrings.DURATION, duration);\r
+               dbObject.put(MorpheusStrings.MATERIALID, materialID);\r
+               dbObject.put(MorpheusStrings.TITLE, title);\r
+               // dbObject.put(MorpheusStrings.DEVICEID, deviceID);\r
+               // dbObject.put(MorpheusStrings.REASON, reason);\r
+\r
+               String fileName = materialID + MXF_EXT;\r
+\r
+               Path targetFilePath = Paths.get(targetPath, fileName);\r
+               boolean exists = Files.exists(targetFilePath);\r
+               if (exists && targetFilePath.toFile().length() > 0) {\r
+                       logger.warn(getSessionMarker(), "Az '{}' anyag már be van töltve.", materialID);\r
+                       dbObject.put(MorpheusStrings.STATUS, MorpheusStrings.STATUS_SKIPPED);\r
+               } else {\r
+                       List<IEntityBase> medias = dao.getByHouseId(fileName);\r
+                       if (medias == null || medias.size() == 0) {\r
+                               logger.warn(getSessionMarker(), "Az '{}' anyag nem található az archívumban.", materialID);\r
+                               dbObject.put(MorpheusStrings.STATUS, MorpheusStrings.STATUS_UNAVAILABLE);\r
+                       } else if (medias.size() > 1) {\r
+                               logger.warn(getSessionMarker(), "Az '{}' anyagból egynél több található az archívumban.", materialID);\r
+                               dbObject.put(MorpheusStrings.STATUS, MorpheusStrings.STATUS_MULTIPLE);\r
+                       } else {\r
+                               logger.info(getSessionMarker(), "Az '{}' anyag megtalálható az archívumban.", materialID);\r
+                               dbObject.put(MorpheusStrings.STATUS, MorpheusStrings.STATUS_RESTORABLE);\r
+\r
+                               MediaFile mf = (MediaFile) medias.get(0);\r
+                               dbObject.put(MorpheusStrings.MEDIAID, mf.getMediaId());\r
+                       }\r
+\r
+               }\r
+\r
+               collection.insert(dbObject);\r
+       }\r
+\r
+       // Channel,Time to Air,Duration,Material ID,Title,Device ID,Reason,\r
+       // TX02,10-JAN-2018 13:25:21:08,00:05:00:00,M009572A,Tiéd a pálya/26. - 1. seg -\r
+       // Eredeti ** mc ,ICELE-02,On Domain (ISILON, ICELE-01, ICELE-05) ,\r
+       private void processMissingMaterialCSV(Path csvFilePath, List<String> lines) throws Exception {\r
+               if (lines == null | lines.size() == 0) {\r
+                       return;\r
+               }\r
+\r
+               Map<String, Integer> metadatas = null;\r
+               for (int i = 0; i < lines.size(); i++) {\r
+                       String line = lines.get(i);\r
+                       if (line == null)\r
+                               continue;\r
+                       String[] data = line.split(",");\r
+                       if (i == 0)\r
+                               metadatas = buildMetadataMap(csvFilePath, data);\r
+                       else\r
+                               processLine(data, metadatas);\r
+\r
+                       current++;\r
+                       int progress = current * 100 / overall;\r
+                       setProgress(progress);\r
+               }\r
+\r
+       }\r
+\r
+       private void processPathItem(Path csvFilePath, List<String> lines) {\r
+               File csvFile = csvFilePath.toFile();\r
+\r
+               try {\r
+                       processMissingMaterialCSV(csvFilePath, lines);\r
+                       moveProcessedCSV(csvFilePath);\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       logger.error(getSessionMarker(), "A {} MORPHEUS állomány mozgatásakor hiba történt. A rendszer hibaüzenete: {}.", csvFile.getName(),\r
+                                       e.getMessage());\r
+               }\r
+       }\r
+\r
+       private void processPathItems(List<Path> filePaths) throws IOException {\r
+               overall = 0;\r
+               Map<Path, List<String>> contents = new HashMap<>();\r
+               for (Path filePath : filePaths) {\r
+                       File csvFile = filePath.toFile();\r
+                       if (csvFile.isDirectory() || !csvFile.getName().toLowerCase().endsWith(CSV_EXT.toLowerCase()))\r
+                               continue;\r
+                       logger.info(getSessionMarker(), "Processing {}", filePath);\r
+                       List<String> lines = Files.readAllLines(filePath, Charset.forName("UTF-8"));\r
+                       overall += lines.size();\r
+                       contents.put(filePath, lines);\r
+               }\r
+\r
+               Set<Path> csvPaths = contents.keySet();\r
+               for (Path csvPath : csvPaths) {\r
+                       processPathItem(csvPath, contents.get(csvPath));\r
+               }\r
+       }\r
+\r
+       private void setAndCheck(String sourcePath, String processedFolder, String targetPath, IJobEngine jobEngine) {\r
+               if (jobEngine == null) {\r
+                       logger.error(getSessionMarker(), "Az folyamatkezelő réteg nem elérhető.");\r
+                       throw new NullPointerException("Internal error, missing JobEngine reference.");\r
+               }\r
+\r
+               IItemManager manager = jobEngine.getItemManager();\r
+               if (manager == null) {\r
+                       logger.error(getSessionMarker(), "Az adatbáziskezelő réteg nem elérhető.");\r
+                       throw new NullPointerException("Internal error, missing ItemManager reference.");\r
+               }\r
+               dao = (MediaFileDAO) manager.getBaseDAO(MediaFile.class);\r
+               if (dao == null) {\r
+                       logger.error(getSessionMarker(), "Az adatbáziskezelő réteg MediaFile kezelöje nem elérhető.");\r
+                       throw new NullPointerException("Internal error, missing MediaFile DAO reference.");\r
+               }\r
+               if (sourcePath == null) {\r
+                       logger.error(getSessionMarker(), "A folyamat 'sourcePath' bemeneti paramétere üres.");\r
+                       throw new NullPointerException("System is not configured properly, 'sourcePath' input parameter missing.");\r
+               }\r
+               if (processedFolder == null) {\r
+                       logger.error(getSessionMarker(), "A folyamat 'processedFolder' bemeneti paramétere üres.");\r
+                       throw new NullPointerException("System is not configured properly, 'processedFolder' input parameter missing.");\r
+               }\r
+               this.processedFolder = processedFolder;\r
+\r
+               if (targetPath == null) {\r
+                       logger.error(getSessionMarker(), "A folyamat 'targetPath' bemeneti paramétere üres.");\r
+                       throw new NullPointerException("System is not configured properly, 'targetPath' input parameter missing.");\r
+               }\r
+               this.targetPath = targetPath;\r
+\r
+               db = NoSQLUtils.getNoSQLDB();\r
+               if (db == null) {\r
+                       logger.error(getSessionMarker(), "Sikertelen kapcsolódás a NoSQL adatbázishoz.");\r
+                       throw new NullPointerException("Can not connect to NoSQL database.");\r
+               }\r
+\r
+       }\r
+\r
+       private void storeMetadataPosition(Path csvFilePath, List<String> dataList, String name, Map<String, Integer> metadatas) throws Exception {\r
+               int pos = dataList.indexOf(name);\r
+               if (pos < 0)\r
+                       throw new Exception(String.format("A '%s' MORPHEUS állományban nem található a '%s' mező.", csvFilePath.getFileName(), name));\r
+               metadatas.put(name, pos);\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/ImportStatisticsStep.java b/server/-product/production/HIRTV/jobs/steps/ImportStatisticsStep.java
new file mode 100644 (file)
index 0000000..7a34a4d
--- /dev/null
@@ -0,0 +1,365 @@
+package user.jobengine.server.steps;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Calendar;\r
+import java.util.Date;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.TimeZone;\r
+\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+import org.apache.logging.log4j.Marker;\r
+\r
+import com.ibm.nosql.json.api.BasicDBList;\r
+import com.ibm.nosql.json.api.BasicDBObject;\r
+import com.ibm.nosql.json.api.DB;\r
+import com.ibm.nosql.json.api.DBCollection;\r
+import com.ibm.nosql.json.api.DBObject;\r
+\r
+import user.commons.CalendarUtils;\r
+import user.commons.nosql.NoSQLUtils;\r
+import user.commons.octopus.IOctopusAPI;\r
+import user.commons.octopus.OctopusAPI;\r
+import user.jobengine.db.IItemManager;\r
+import user.jobengine.server.IJobEngine;\r
+import user.jobengine.server.IJobRuntime;\r
+import user.jobengine.server.steps.shared.ItemManagerExtensions;\r
+\r
+public class ImportStatisticsStep extends JobStep {\r
+       private static final Logger logger = LogManager.getLogger();\r
+       private static final String SCHEDULED_FORMAT = "yyyy.MM.dd HH:mm";\r
+       private static final String NEXIOCLIPS = "nexioclips";\r
+       private static final String LONGNAMEID = "longnameid";\r
+       private static final String DURATION = "duration";\r
+       private IOctopusAPI octopusAPI;\r
+       private Marker marker;\r
+       private int overall;\r
+       private int current;\r
+       private DB db;\r
+       private DBCollection clipCollection;\r
+       private IItemManager manager;\r
+\r
+       private void createAPI(IJobRuntime jobRuntime) throws Exception {\r
+               try {\r
+                       octopusAPI = new OctopusAPI();\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       logger.error(jobRuntime.getSessionMarker(), "Az Octopus adatbázis nem érhető el. A rendszer üzenete: {}", e.getMessage());\r
+                       throw e;\r
+               }\r
+       }\r
+\r
+       private BasicDBObject createFieldsObject() {\r
+               BasicDBObject result = new BasicDBObject();\r
+               result.put(IOctopusAPI._ID, 0);\r
+               result.put(IOctopusAPI.ID, 1);\r
+               result.put(IOctopusAPI.NAME, 1);\r
+               result.put(IOctopusAPI.REF_RUNDOWN, 1);\r
+               result.put(IOctopusAPI.REF_STORYFOLDER, 1);\r
+               result.put(IOctopusAPI.MOS_OBJECTS, 1);\r
+               result.put(IOctopusAPI.PARENT_STORY_ID, 1);\r
+               result.put(IOctopusAPI.SCHEDULEFROM, 1);\r
+               result.put(IOctopusAPI.REPORTERS, 1);\r
+               return result;\r
+       }\r
+\r
+       private BasicDBObject createStory(BasicDBObject story, String label, String objId, long duration, long rdCount, long sfCount, long parentStoryId,\r
+                       String reporters) {\r
+               BasicDBObject raw = new BasicDBObject();\r
+               raw.put(IOctopusAPI.ID, NoSQLUtils.asLong(story, IOctopusAPI.ID));\r
+               raw.put(IOctopusAPI.NAME, NoSQLUtils.asString(story, IOctopusAPI.NAME));\r
+               raw.put(IOctopusAPI.PARENT_STORY_ID, parentStoryId);\r
+               raw.put(IOctopusAPI.REPORTERS, reporters);\r
+               raw.put(IOctopusAPI.OBJ_ID, objId);\r
+               raw.put(IOctopusAPI.LABEL, label);\r
+               raw.put("duration", duration);\r
+               raw.put(IOctopusAPI.REF_RUNDOWN, rdCount);\r
+               raw.put(IOctopusAPI.REF_STORYFOLDER, sfCount);\r
+               return raw;\r
+       }\r
+\r
+       @StepEntry\r
+       public Object[] execute(int daysBeforeNow, IJobEngine jobEngine, IJobRuntime jobRuntime) throws Exception {\r
+               marker = jobRuntime.getSessionMarker();\r
+               manager = jobEngine.getItemManager();\r
+               db = NoSQLUtils.getNoSQLDB();\r
+               clipCollection = db.getCollection(NEXIOCLIPS);\r
+\r
+               createAPI(jobRuntime);\r
+\r
+               Calendar scheduledDate = CalendarUtils.createZeroCalendar(Calendar.getInstance());\r
+               scheduledDate.setTimeZone(TimeZone.getTimeZone("Europe/Budapest"));\r
+               scheduledDate.add(Calendar.DAY_OF_YEAR, -1 * daysBeforeNow);\r
+               List<DBObject> rundowns = octopusAPI.getRundowns(scheduledDate.getTime());\r
+               if (rundowns == null)\r
+                       logger.warn(marker, "Nincs adástükör a {} napra.", CalendarUtils.toDateString(scheduledDate));\r
+               else\r
+                       overall += rundowns.size();\r
+\r
+               List<DBObject> folders = octopusAPI.getStoryFolders();\r
+               if (folders == null)\r
+                       logger.warn(marker, "Nincs gyűjtőmappa.");\r
+               else\r
+                       overall += folders.size();\r
+\r
+               Map<Long, BasicDBObject> stories = processRundowns(rundowns);\r
+               logger.info(jobRuntime.getSessionMarker(), "Adástükörben megtalálható anyagok száma {}", stories.size());\r
+               Map<Long, BasicDBObject> folderStories = processFolders(folders, scheduledDate);\r
+               stories.putAll(folderStories);\r
+               logger.info(jobRuntime.getSessionMarker(), "Gyűjtőkben megtalálható anyagok száma {}", stories.size());\r
+\r
+               storeStories(scheduledDate, stories);\r
+               return null;\r
+       }\r
+\r
+       private Map<Long, BasicDBObject> processFolders(List<DBObject> folders, Calendar scheduledDate) {\r
+               Map<Long, BasicDBObject> result = new HashMap<>();\r
+               for (DBObject f : folders) {\r
+                       BasicDBObject folder = (BasicDBObject) f;\r
+                       String folderName = null;\r
+                       long folderID = 0;\r
+                       try {\r
+                               folderID = NoSQLUtils.asLong(folder, IOctopusAPI.ID);\r
+                               folderName = folder.getString(IOctopusAPI.NAME);\r
+                               List<DBObject> folderStories = octopusAPI.getStoryFolderStories(folderID, createFieldsObject());\r
+                               if (folderStories != null) {\r
+\r
+                                       Map<Long, BasicDBObject> stories = processStories(folderStories, scheduledDate);\r
+                                       result.putAll(stories);\r
+                               }\r
+                       } catch (Exception e) {\r
+                               logger.catching(e);\r
+                               logger.error(marker, String.format("A %s %s mappa feldolgozása nem lehetséges. A rendszer üzenete: %s", folderID, folderName, e.getMessage()));\r
+                               throw e;\r
+                       }\r
+                       current++;\r
+                       int progress = current * 100 / overall;\r
+                       setProgress(progress);\r
+               }\r
+               return result;\r
+       }\r
+\r
+       private Map<Long, BasicDBObject> processRundowns(List<DBObject> rundowns) {\r
+               Map<Long, BasicDBObject> result = new HashMap<>();\r
+               for (DBObject r : rundowns) {\r
+                       BasicDBObject rundown = (BasicDBObject) r;\r
+                       String rundownName = null;\r
+                       long rundownID = 0;\r
+                       try {\r
+                               rundownID = NoSQLUtils.asLong(rundown, IOctopusAPI.ID);\r
+                               String name = NoSQLUtils.asString(NoSQLUtils.asDBObject(rundown, IOctopusAPI.RUNDOWN_TYPE), IOctopusAPI.NAME);\r
+                               String channel = NoSQLUtils.asString(NoSQLUtils.asDBObject(rundown, IOctopusAPI.CHANNEL), IOctopusAPI.NAME);\r
+                               Date scheduledStart = rundown.getDate(IOctopusAPI.SCHEDULED_START);\r
+                               String start = CalendarUtils.toString(CalendarUtils.createCalendar(scheduledStart), SCHEDULED_FORMAT);\r
+                               // String rundownName = NoSQLUtils.asString(rundown, IOctopusAPI.NAME);\r
+                               rundownName = String.format("%s %s %s", start, name, channel);\r
+                               List<DBObject> stories = octopusAPI.getRundownStories(rundownID, createFieldsObject());\r
+                               if (stories != null)\r
+                                       result.putAll(processStories(stories, null));\r
+                       } catch (Exception e) {\r
+                               logger.catching(e);\r
+                               logger.error(marker,\r
+                                               String.format("A %s %s tükör feldolgozása nem lehetséges. A rendszer üzenete: %s", rundownID, rundownName, e.getMessage()));\r
+                               throw e;\r
+                       }\r
+                       current++;\r
+                       int progress = current * 100 / overall;\r
+                       setProgress(progress);\r
+               }\r
+               return result;\r
+       }\r
+\r
+       private Map<Long, BasicDBObject> processStories(List<DBObject> stories, Calendar scheduledDate) {\r
+               Map<Long, BasicDBObject> result = new HashMap<>();\r
+               for (DBObject storyObject : stories) {\r
+                       BasicDBObject story = (BasicDBObject) storyObject;\r
+\r
+                       long storyID = NoSQLUtils.asLong(story, IOctopusAPI.ID);\r
+                       if (storyID == 0)\r
+                               continue;\r
+                       if (result.containsKey(storyID))\r
+                               continue;\r
+\r
+                       if (scheduledDate != null) {\r
+                               Date scheduleFrom = story.getDate(IOctopusAPI.SCHEDULEFROM);\r
+                               if (scheduleFrom == null)\r
+                                       continue;\r
+                               if (scheduleFrom.getTime() != scheduledDate.getTime().getTime())\r
+                                       continue;\r
+                       }\r
+\r
+                       List<BasicDBObject> mosObjects = NoSQLUtils.asList(story, IOctopusAPI.MOS_OBJECTS);\r
+                       if (mosObjects == null || mosObjects.isEmpty())\r
+                               continue;\r
+\r
+                       boolean foundAnyClip = false;\r
+                       for (BasicDBObject mosObject : mosObjects) {\r
+                               String clipName = NoSQLUtils.asString(mosObject, IOctopusAPI.OBJ_ID);\r
+                               if (clipName != null && clipName.length() > 0) {\r
+                                       BasicDBObject clip = (BasicDBObject) clipCollection.findOne(new BasicDBObject(LONGNAMEID, clipName));\r
+                                       if (clip != null) {\r
+                                               long duration = NoSQLUtils.asLong(clip, DURATION);\r
+                                               // az ures klipp 1 kocka hosszu\r
+                                               if (duration > 1) {\r
+                                                       mosObject.put("duration", duration);\r
+                                                       foundAnyClip = true;\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+                       if (!foundAnyClip)\r
+                               continue;\r
+\r
+                       List<BasicDBObject> rdList = NoSQLUtils.asList(story, IOctopusAPI.REF_RUNDOWN);\r
+                       story.put(IOctopusAPI.REF_RUNDOWN, rdList == null ? 0 : rdList.size());\r
+                       List<BasicDBObject> sfList = NoSQLUtils.asList(story, IOctopusAPI.REF_STORYFOLDER);\r
+                       story.put(IOctopusAPI.REF_STORYFOLDER, sfList == null ? 0 : sfList.size());\r
+\r
+                       List<BasicDBObject> reporters = NoSQLUtils.asList(story, IOctopusAPI.REPORTERS);\r
+                       String reporterNames = "";\r
+                       if (reporters != null && reporters.size() > 0) {\r
+                               for (BasicDBObject reporter : reporters) {\r
+                                       String userName = NoSQLUtils.asString(reporter, "longName");\r
+                                       if (userName != null) {\r
+                                               if (reporterNames.length() > 0)\r
+                                                       reporterNames += ", ";\r
+                                               reporterNames += userName;\r
+                                       }\r
+                               }\r
+                       }\r
+                       story.put(IOctopusAPI.REPORTERS, reporterNames);\r
+\r
+                       result.put(storyID, story);\r
+               }\r
+               return result;\r
+       }\r
+\r
+       private void store(Calendar scheduledDate, List<BasicDBObject> stories, BasicDBObject typeStat, BasicDBObject planStat, BasicDBObject reporterStat) {\r
+               try {\r
+                       BasicDBObject dailyHistory = new BasicDBObject();\r
+                       dailyHistory.put("dateTime", scheduledDate.getTime());\r
+                       BasicDBList list = new BasicDBList();\r
+                       dailyHistory.put("rawData", list);\r
+                       for (BasicDBObject story : stories) {\r
+                               list.add(story);\r
+                       }\r
+                       dailyHistory.put("typeStat", typeStat);\r
+                       dailyHistory.put("planStat", planStat);\r
+                       dailyHistory.put("reporterStat", reporterStat);\r
+\r
+                       DBCollection collection = db.getCollection("daily_news_history");\r
+                       collection.remove(new BasicDBObject("dateTime", scheduledDate.getTime()));\r
+                       collection.save(dailyHistory);\r
+\r
+               } catch (Exception e) {\r
+                       logger.error(e);\r
+                       throw e;\r
+               }\r
+       }\r
+\r
+       private void storeStories(Calendar scheduledDate, Map<Long, BasicDBObject> stories) {\r
+               BasicDBObject planStat = new BasicDBObject();\r
+               BasicDBObject typeStat = new BasicDBObject();\r
+               BasicDBObject reporterStat = new BasicDBObject();\r
+\r
+               List<BasicDBObject> rawData = new ArrayList<>();\r
+               List<String> processed = new ArrayList<>();\r
+\r
+               for (BasicDBObject story : stories.values()) {\r
+                       List<BasicDBObject> mosObjects = NoSQLUtils.asList(story, IOctopusAPI.MOS_OBJECTS);\r
+                       for (BasicDBObject mos : mosObjects) {\r
+                               String objId = NoSQLUtils.asString(mos, IOctopusAPI.OBJ_ID);\r
+                               if (!mos.containsKey("duration"))\r
+                                       continue;\r
+\r
+                               long parentStoryId = NoSQLUtils.asLong(story, IOctopusAPI.PARENT_STORY_ID);\r
+                               logger.info("Processing parentStoryId {}", parentStoryId);\r
+\r
+                               String key = String.format("%d-%s", parentStoryId, objId);\r
+                               if (processed.contains(key))\r
+                                       continue;\r
+                               processed.add(key);\r
+\r
+                               String label = NoSQLUtils.asString(mos, IOctopusAPI.LABEL);\r
+                               if (label == null) {\r
+                                       logger.error(marker, "Az anyag MOS objektuma nem tartalmaz formátum meghatározást, feldolgozása nem lehetséges. Részletek:");\r
+                                       logger.error(marker, "STORY: {}", story.toString());\r
+                                       logger.error(marker, "MOS: {}", mos.toString());\r
+                                       continue;\r
+                               }\r
+                               long duration = NoSQLUtils.asLong(mos, "duration");\r
+                               long rdCount = NoSQLUtils.asLong(story, IOctopusAPI.REF_RUNDOWN);\r
+                               long sfCount = NoSQLUtils.asLong(story, IOctopusAPI.REF_STORYFOLDER);\r
+                               String reporters = NoSQLUtils.asString(story, IOctopusAPI.REPORTERS);\r
+\r
+                               BasicDBObject raw = createStory(story, label, objId, duration, rdCount, sfCount, parentStoryId, reporters);\r
+                               rawData.add(raw);\r
+\r
+                               NoSQLUtils.addLong(planStat, "all_count", 1);\r
+                               NoSQLUtils.addLong(planStat, "all_duration", duration);\r
+\r
+                               BasicDBObject perTypeStat = NoSQLUtils.asDBObjectOrCreate(typeStat, label);\r
+                               NoSQLUtils.addLong(perTypeStat, "all_count", 1);\r
+                               NoSQLUtils.addLong(perTypeStat, "all_duration", duration);\r
+\r
+                               BasicDBObject perReporterStat = NoSQLUtils.asDBObjectOrCreate(reporterStat, reporters);\r
+                               NoSQLUtils.addLong(perReporterStat, "all_count", 1);\r
+                               NoSQLUtils.addLong(perReporterStat, "all_duration", duration);\r
+\r
+                               BasicDBObject ingestInfo = manager.getIngestInfo(scheduledDate, String.valueOf(parentStoryId));\r
+                               if (ingestInfo != null) {\r
+                                       long ingestCount = ingestInfo.getLong("count");\r
+                                       long ingestDuration = ingestInfo.getLong("duration");\r
+                                       raw.put("ingest_count", ingestCount);\r
+                                       raw.put("ingest_duration", ingestDuration);\r
+                                       NoSQLUtils.addLong(planStat, "ingest_count", ingestCount);\r
+                                       NoSQLUtils.addLong(planStat, "ingest_duration", ingestDuration);\r
+                                       NoSQLUtils.addLong(perTypeStat, "ingest_count", ingestCount);\r
+                                       NoSQLUtils.addLong(perTypeStat, "ingest_duration", ingestDuration);\r
+                                       NoSQLUtils.addLong(perReporterStat, "ingest_count", ingestCount);\r
+                                       NoSQLUtils.addLong(perReporterStat, "ingest_duration", ingestDuration);\r
+                               }\r
+\r
+                               BasicDBObject archiveInfo = ItemManagerExtensions.getArchiveInfo(manager, parentStoryId);\r
+                               if (archiveInfo != null) {\r
+                                       long archiveCount = archiveInfo.getLong("count");\r
+                                       long archiveDuration = archiveInfo.getLong("duration");\r
+                                       raw.put("archive_count", archiveCount);\r
+                                       raw.put("archive_duration", archiveDuration);\r
+                                       NoSQLUtils.addLong(planStat, "archive_count", archiveCount);\r
+                                       NoSQLUtils.addLong(planStat, "archive_duration", archiveDuration);\r
+                                       NoSQLUtils.addLong(perTypeStat, "archive_count", archiveCount);\r
+                                       NoSQLUtils.addLong(perTypeStat, "archive_duration", archiveDuration);\r
+                                       NoSQLUtils.addLong(perReporterStat, "archive_count", archiveCount);\r
+                                       NoSQLUtils.addLong(perReporterStat, "archive_duration", archiveDuration);\r
+                               }\r
+\r
+                               // skipped\r
+                               if (sfCount > 0 && rdCount == 0) {\r
+                                       NoSQLUtils.addLong(planStat, "skip_count", 1);\r
+                                       NoSQLUtils.addLong(planStat, "skip_duration", duration);\r
+                                       NoSQLUtils.addLong(perTypeStat, "skip_count", 1);\r
+                                       NoSQLUtils.addLong(perTypeStat, "skip_duration", duration);\r
+                                       NoSQLUtils.addLong(perReporterStat, "skip_count", 1);\r
+                                       NoSQLUtils.addLong(perReporterStat, "skip_duration", duration);\r
+                               }\r
+\r
+                               // onair\r
+                               if (rdCount > 0) {\r
+                                       NoSQLUtils.addLong(planStat, "onair_count", 1);\r
+                                       NoSQLUtils.addLong(planStat, "onair_duration", duration);\r
+                                       NoSQLUtils.addLong(perTypeStat, "onair_count", 1);\r
+                                       NoSQLUtils.addLong(perTypeStat, "onair_duration", duration);\r
+                                       NoSQLUtils.addLong(perReporterStat, "onair_count", 1);\r
+                                       NoSQLUtils.addLong(perReporterStat, "onair_duration", duration);\r
+                               }\r
+\r
+                       }\r
+               }\r
+\r
+               store(scheduledDate, rawData, typeStat, planStat, reporterStat);\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/MXFCutterStep.java b/server/-product/production/HIRTV/jobs/steps/MXFCutterStep.java
new file mode 100644 (file)
index 0000000..f1209d9
--- /dev/null
@@ -0,0 +1,137 @@
+package user.jobengine.server.steps;\r
+\r
+import org.apache.commons.lang.StringUtils;\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+import org.apache.logging.log4j.Marker;\r
+\r
+import user.commons.StoreUri;\r
+import user.commons.configuration.SystemConfiguration;\r
+import user.commons.remotestore.RemoteStoreProtocol;\r
+//import user.jobengine.db.Media;\r
+import user.jobengine.db.ArchivedMedia;\r
+import user.jobengine.db.IItemManager;\r
+import user.jobengine.db.Store;\r
+import user.jobengine.server.IJobEngine;\r
+import user.jobengine.server.IJobRuntime;\r
+\r
+public class MXFCutterStep extends JobStep {\r
+       private static final String TARGETNAMEPATTERN = "-ARCH-%s";\r
+       private static final Logger logger = LogManager.getLogger();\r
+       private static String NEXIO_HOST = SystemConfiguration.getInstance().value("services.nexio.host");\r
+       private IItemManager manager;\r
+       private StoreUri tempTargetUri;\r
+       private StoreUri tempSourceUri;\r
+       private String sourceFileName;\r
+       private Marker marker;\r
+       private int nexioPort;\r
+       private String nexioUserName, nexioPassword;\r
+\r
+       protected void checkTargetPath(String targetPath) {\r
+               if (StringUtils.isBlank(targetPath)) {\r
+                       logger.error(marker, "A folyamat 'targetPath' bemeneti paramétere üres.");\r
+                       throw new NullPointerException("System is not configured properly, 'targetPath' input parameter missing.");\r
+               }\r
+       }\r
+\r
+       protected StoreUri createTargetUri(IItemManager manager, String targetPath) throws NullPointerException {\r
+               StoreUri result = null;\r
+               result = manager.createStoreUri(RemoteStoreProtocol.FTP, NEXIO_HOST);\r
+               result.setPortNumber(nexioPort);\r
+               result.setUserName(nexioUserName);\r
+               result.setPassword(nexioPassword);\r
+\r
+               return result;\r
+       }\r
+\r
+       @StepEntry\r
+       public Object[] execute(ArchivedMedia archivedMedia, String targetPath, String houseId, String successRecipient, int killDateDays, boolean useNexioTarget,\r
+                       String nexioAgency, int nexioPort, String nexioUserName, String nexioPassword, IJobEngine jobEngine, IJobRuntime jobRuntime) throws Exception {\r
+               this.nexioPort = nexioPort;\r
+               this.nexioUserName = nexioUserName;\r
+               this.nexioPassword = nexioPassword;\r
+               marker = jobRuntime.getSessionMarker();\r
+\r
+//             if (!useNexioTarget) {\r
+//                     String targetFileName = String.format(targetNamePattern, sourceFileName);\r
+//                     MediaArea mediaArea = new MediaArea(Paths.get(targetPath));\r
+//                     try {\r
+//                             mediaArea.process();\r
+//                             logger.info(getSessionMarker(), mediaArea.getInform().toPrettyString(""));\r
+//                     } catch (Exception e) {\r
+//                             logger.error(getSessionMarker(), "Can't analyze input {}, skipping. System message is: {}", e.getMessage());\r
+//                     }\r
+//             }\r
+\r
+//             if (useNexioTarget && archivedMedia.getTcIn() != null && archivedMedia.getTcOut() != null) {\r
+//                     setAndCheck(archivedMedia, houseId, targetPath, useNexioTarget, jobEngine);\r
+//\r
+//                     final IJobRuntime runtime = jobRuntime;\r
+//                     sourceFileName = houseId + TARGETNAMEPATTERN;\r
+//                     tempSourceUri.addProgressListener(new IProgressEventListener() {\r
+//                             @Override\r
+//                             public void progressChanged(ProgressEvent evt) {\r
+//                                     runtime.incrementProgress(evt.getProgress());\r
+//                             }\r
+//                     });\r
+//\r
+//                     RemoteFile result = tempSourceUri.transferFrom(tempTargetUri, sourceFileName, sourceFileName);\r
+//\r
+//                     EscortFiles.setNEXIOKillDate(killDateDays, houseId, nexioAgency, tempTargetUri);\r
+//\r
+//                     logger.info("A {} videó kivágva {}s - {}s", sourceFileName, archivedMedia.getTcIn(), archivedMedia.getTcOut());\r
+//             }\r
+\r
+               return null;\r
+       }\r
+\r
+       // private String getSourceFileName(ArchivedMedia archivedMedia, Store\r
+       // store) {\r
+       // List<MediaFile> mediaFiles = archivedMedia.getMedia().getMediaFiles();\r
+       // if (mediaFiles == null)\r
+       // return null;\r
+       // for (MediaFile mediaFile : mediaFiles) {\r
+       // if (mediaFile.getStore().getId() == store.getId())\r
+       // return mediaFile.getRelativePath();\r
+       // }\r
+       // return null;\r
+       // }\r
+\r
+       private void setAndCheck(ArchivedMedia archivedMedia, String houseId, String targetPath, boolean useNexioTarget, IJobEngine jobEngine) {\r
+               if (jobEngine == null) {\r
+                       logger.error(marker, "A folyamatkezelő réteg nem elérhető.");\r
+                       throw new NullPointerException("Internal error, missing JobEngine reference.");\r
+               }\r
+               manager = jobEngine.getItemManager();\r
+               if (manager == null) {\r
+                       logger.error(marker, "Az adatbáziskezelő réteg nem elérhető.");\r
+                       throw new NullPointerException("Internal error, missing ItemManager reference.");\r
+               }\r
+               if (archivedMedia == null) {\r
+                       logger.error(marker, "A folyamat 'mediaCubeMedia' bemeneti paramétere üres.");\r
+                       throw new NullPointerException("System is not configured properly, 'mediaCubeMedia' input parameter missing.");\r
+               }\r
+               checkTargetPath(targetPath);\r
+               if (StringUtils.isBlank(houseId)) {\r
+                       logger.error(marker, "A folyamat 'houseId' bemeneti paramétere üres.");\r
+                       throw new NullPointerException("System is not configured properly, 'houseId' input parameter missing.");\r
+               }\r
+               Store tsmStore = manager.getSystemStore(false);\r
+               if (tsmStore == null) {\r
+                       logger.error(marker, "A TSM rendszer beállítás nem elérhető.");\r
+                       throw new NullPointerException("System is not configured properly, missing TSM Store.");\r
+               }\r
+\r
+               tempSourceUri = manager.createStoreUri(RemoteStoreProtocol.LOCAL, targetPath);\r
+               if (tempSourceUri == null) {\r
+                       logger.error(marker, "A TSM rendszer beállítás paraméterei nem elérhetőek.");\r
+                       throw new NullPointerException("System is not configured properly, missing TSM StoreUri.");\r
+               }\r
+               tempTargetUri = createTargetUri(manager, targetPath);\r
+               // sourceFileName = getSourceFileName(archivedMedia, tsmStore);\r
+               if (sourceFileName == null) {\r
+                       logger.error(marker, "Adatbázis bejegyzés hiba, a visszatöltendő fájl neve nem található.");\r
+                       throw new NullPointerException("Database error, missing MediaFile 'relativePath'.");\r
+               }\r
+       }\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/MediaToolStep.java b/server/-product/production/HIRTV/jobs/steps/MediaToolStep.java
new file mode 100644 (file)
index 0000000..81bea7b
--- /dev/null
@@ -0,0 +1,31 @@
+package user.jobengine.server.steps;\r
+\r
+import java.nio.file.Path;\r
+import java.nio.file.Paths;\r
+\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+\r
+import user.commons.mediaarea.MediaArea;\r
+import user.jobengine.db.Media;\r
+\r
+public class MediaToolStep extends JobStep {\r
+       private static final Logger logger = LogManager.getLogger();\r
+\r
+       @StepEntry\r
+       public Object[] execute(ArchiveItem archiveItem, Media mediaCubeMedia) throws Exception {\r
+               Path filePath = Paths.get(archiveItem.getMediaFile());\r
+               if (filePath.toFile().length() != 0) {\r
+                       MediaArea ma = new MediaArea(filePath);\r
+                       ma.process();\r
+                       long frames = ma.getFrameCount();\r
+                       if (frames > 0) {\r
+                               logger.info("Media {} length is {}", filePath, frames);\r
+                               mediaCubeMedia.setLength(frames);\r
+                               getManager().modify(mediaCubeMedia);\r
+                       }\r
+               }\r
+               return null;\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/MetadataTransformStep.java b/server/-product/production/HIRTV/jobs/steps/MetadataTransformStep.java
new file mode 100644 (file)
index 0000000..72a5e5f
--- /dev/null
@@ -0,0 +1,161 @@
+package user.jobengine.server.steps;\r
+\r
+import java.io.File;\r
+import java.nio.file.Files;\r
+import java.nio.file.Path;\r
+import java.nio.file.Paths;\r
+import java.util.List;\r
+\r
+import org.apache.commons.io.FilenameUtils;\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+import org.apache.logging.log4j.Marker;\r
+\r
+import com.ibm.nosql.json.api.BasicDBList;\r
+\r
+import user.jobengine.db.Item;\r
+import user.jobengine.db.ItemType;\r
+import user.jobengine.db.Media;\r
+import user.jobengine.server.steps.shared.EscortFiles;\r
+\r
+/**\r
+ * Itemek es mediak krealasa a ArchiveItem objektum alapjan.\r
+ *\r
+ * @author robi\r
+ */\r
+public class MetadataTransformStep extends JobStep {\r
+       private static final String CONFLICT = ".CONFLICT";\r
+       private static final Logger logger = LogManager.getLogger();\r
+       public static final String DEFAULT_MEDIATYPE = "Generic";\r
+       private Marker marker;\r
+\r
+       private void addTags(ArchiveItem archiveItem, Media mediaCubeMedia) {\r
+               BasicDBList tags = archiveItem.getTags();\r
+               if (tags != null) {\r
+                       for (Object tag : tags) {\r
+\r
+                               try {\r
+                                       String tagText = String.valueOf(tag);\r
+                                       getManager().addMediaTag(tagText, mediaCubeMedia.getId());\r
+                                       System.out.println();\r
+\r
+                               } catch (Exception e) {\r
+                                       logger.catching(e);\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       private void moveToDuplicates(ArchiveItem archiveItem, String sourceFileName) {\r
+               try {\r
+                       Path sourcePath = Paths.get(archiveItem.getMediaFile());\r
+                       Path conflictPath = Paths.get(sourcePath.getParent().toString(), CONFLICT);\r
+                       EscortFiles.ensureUNCFolder(conflictPath);\r
+                       Files.move(sourcePath, Paths.get(conflictPath.toString(), sourceFileName));\r
+                       Path metadataPath = EscortFiles.constructMetadataPath(sourcePath);\r
+                       if (metadataPath.toFile().exists())\r
+                               Files.move(metadataPath, Paths.get(conflictPath.toString(), metadataPath.getFileName().toString()));\r
+               } catch (Exception e1) {\r
+                       logger.catching(e1);\r
+                       logger.error(marker, "Hiba az '{}' állomány mappába mozgatásakor. A rendszer üzenete: {}", CONFLICT,\r
+                                       e1.getMessage());\r
+               }\r
+       }\r
+\r
+       private Item createItem(ArchiveItem archiveItem) {\r
+               Item mediaCubeItem = getExistingItem(archiveItem.getItemHouseId(), archiveItem.getItemTitle());\r
+               if (mediaCubeItem == null)\r
+                       mediaCubeItem = getManager().createItem(DEFAULT_MEDIATYPE, archiveItem.getItemTitle(),\r
+                                       archiveItem.getItemDescription(), archiveItem.getItemHouseId());\r
+               return mediaCubeItem;\r
+       }\r
+\r
+       private Media createMedia(ArchiveItem archiveItem, Item mediaCubeItem, String mediaType) {\r
+               Media mediaCubeMedia;\r
+               mediaCubeMedia = getManager().createMedia(mediaType, archiveItem.getMediaTitle(),\r
+                               archiveItem.getMediaDescription(), archiveItem.getMediaHouseId());\r
+               mediaCubeMedia.setLength(archiveItem.getDuration());\r
+               mediaCubeItem.appendMedia(mediaCubeMedia);\r
+\r
+               return mediaCubeMedia;\r
+       }\r
+\r
+       @StepEntry\r
+       public Object[] execute(ArchiveItem archiveItem) throws Exception {\r
+               marker = getSessionMarker();\r
+               Media mediaCubeMedia = null;\r
+               try {\r
+                       File sourceMediaFile = new File(archiveItem.getMediaFile());\r
+                       String sourceFileName = sourceMediaFile.getName();\r
+\r
+                       getJobRuntime().setRelated(FilenameUtils.removeExtension(sourceFileName));\r
+\r
+                       if (getManager().isMediaFileExists(sourceFileName)) {\r
+                               cleanUpOnDuplicate(archiveItem, sourceFileName);\r
+                               logger.warn(marker, "Az '" + sourceFileName\r
+                                               + "' állomány már megtalálható az archívumban, archiválása nem lehetséges.");\r
+                               cancel();\r
+                               return null;\r
+                       }\r
+\r
+                       Item mediaCubeItem = createItem(archiveItem);\r
+                       setProgress(50);\r
+                       String mediaType = getCreateType(archiveItem);\r
+                       mediaCubeMedia = createMedia(archiveItem, mediaCubeItem, mediaType);\r
+                       // ha itemid 0 akkor merge, egyebkent media insert\r
+\r
+                       if (mediaCubeItem.getId() == 0)\r
+                               getManager().mergeItemStructure(mediaCubeItem);\r
+                       else {\r
+                               mediaCubeMedia.setItemId(mediaCubeItem.getId());\r
+                               mediaCubeMedia.add();\r
+                       }\r
+\r
+                       addTags(archiveItem, mediaCubeMedia);\r
+\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       String fileName = new File(archiveItem.getMediaFile()).getName();\r
+                       logger.error(marker,\r
+                                       "Az '{}' állomány nem archiválható, mert a metaadat transzformáció sikertelen. A rendszer üzenete: {}",\r
+                                       fileName, e.getMessage());\r
+                       if (!archiveItem.removeCatchedFile())\r
+                               logger.error(marker, "Az '{}' állomány .catched jelző állománya nem törölhető.", fileName);\r
+                       throw e;\r
+               } finally {\r
+                       setProgress(100);\r
+               }\r
+               return new Object[] { mediaCubeMedia };\r
+       }\r
+\r
+       private void cleanUpOnDuplicate(ArchiveItem archiveItem, String sourceFileName) {\r
+               moveToDuplicates(archiveItem, sourceFileName);\r
+               archiveItem.removeCatchedFile();\r
+               List<Path> killDateFiles = EscortFiles.getKillDateFiles(Paths.get(archiveItem.getMediaFile()));\r
+               EscortFiles.remove(killDateFiles);\r
+       }\r
+\r
+       private String getCreateType(ArchiveItem archiveItem) {\r
+               String mediaType = archiveItem.getMediaType();\r
+               if (mediaType == null || mediaType.length() == 0)\r
+                       mediaType = DEFAULT_MEDIATYPE;\r
+               else {\r
+                       ItemType mediaItemType = getManager().getItemType(mediaType);\r
+                       if (mediaItemType == null)\r
+                               getManager().createItemType(mediaType, mediaType).add();\r
+               }\r
+               return mediaType;\r
+       }\r
+\r
+       private Item getExistingItem(String itemHouseId, String itemTitle) {\r
+               Item[] result = new Item[] { null };\r
+               String sql = String.format("select id from item where houseid='%s' and title='%s'", itemHouseId, itemTitle);\r
+               getManager().executeQuery(sql, rs -> {\r
+                       long id = rs.getLong("id");\r
+                       result[0] = getManager().getItem(id);\r
+                       return true;\r
+               }, null);\r
+               return result[0];\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/OutputPathAndNameSelectorStep.java b/server/-product/production/HIRTV/jobs/steps/OutputPathAndNameSelectorStep.java
new file mode 100644 (file)
index 0000000..52e30e9
--- /dev/null
@@ -0,0 +1,161 @@
+package user.jobengine.server.steps;\r
+\r
+import java.io.IOException;\r
+import java.nio.file.FileVisitResult;\r
+import java.nio.file.FileVisitor;\r
+import java.nio.file.Files;\r
+import java.nio.file.Path;\r
+import java.nio.file.Paths;\r
+import java.nio.file.SimpleFileVisitor;\r
+import java.nio.file.attribute.BasicFileAttributes;\r
+\r
+import org.apache.commons.lang.StringUtils;\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+import org.apache.logging.log4j.Marker;\r
+\r
+import user.commons.configuration.SystemConfiguration;\r
+import user.jobengine.db.ArchivedMedia;\r
+import user.jobengine.server.IJobEngine;\r
+import user.jobengine.server.IJobRuntime;\r
+import user.jobengine.server.steps.shared.EscortFiles;\r
+import user.jobengine.server.steps.shared.MetadataType;\r
+import user.jobengine.server.steps.shared.MetadataTypeDetector;\r
+\r
+public class OutputPathAndNameSelectorStep extends JobStep {\r
+\r
+       private static final String TARGETNAMEPATTERN = "-ARCH-%s";\r
+\r
+       private static final Logger logger = LogManager.getLogger();\r
+\r
+       private Marker marker;\r
+\r
+       private String octopusAddress = SystemConfiguration.getInstance().value("services.octopus.api.address", "");\r
+\r
+       private void check(String localRetrievePath, String materialOutputFolder, String promoOutputFolder, String advertisementOutputFolder,\r
+                       String octopusOutputFolder, String genericOutputFolder, String houseId, String targetPathType) {\r
+               if (StringUtils.isBlank(localRetrievePath)) {\r
+                       logger.error(marker, "A folyamat 'localRetrievePath' bemeneti paramétere üres.");\r
+                       throw new NullPointerException("System is not configured properly, 'localRetrievePath' input parameter missing.");\r
+               }\r
+               if (StringUtils.isBlank(materialOutputFolder)) {\r
+                       logger.error(marker, "A folyamat 'materialOutputFolder' bemeneti paramétere üres.");\r
+                       throw new NullPointerException("System is not configured properly, 'materialOutputFolder' input parameter missing.");\r
+               }\r
+               if (StringUtils.isBlank(promoOutputFolder)) {\r
+                       logger.error(marker, "A folyamat 'promoOutputFolder' bemeneti paramétere üres.");\r
+                       throw new NullPointerException("System is not configured properly, 'promoOutputFolder' input parameter missing.");\r
+               }\r
+               if (StringUtils.isBlank(advertisementOutputFolder)) {\r
+                       logger.error(marker, "A folyamat 'advertisementOutputFolder' bemeneti paramétere üres.");\r
+                       throw new NullPointerException("System is not configured properly, 'advertisementOutputFolder' input parameter missing.");\r
+               }\r
+               if (StringUtils.isBlank(octopusOutputFolder)) {\r
+                       logger.error(marker, "A folyamat 'octopusOutputFolder' bemeneti paramétere üres.");\r
+                       throw new NullPointerException("System is not configured properly, 'octopusOutputFolder' input parameter missing.");\r
+               }\r
+               if (StringUtils.isBlank(genericOutputFolder)) {\r
+                       logger.error(marker, "A folyamat 'genericOutputFolder' bemeneti paramétere üres.");\r
+                       throw new NullPointerException("System is not configured properly, 'genericOutputFolder' input parameter missing.");\r
+               }\r
+               if (StringUtils.isBlank(houseId)) {\r
+                       logger.error(marker, "A folyamat 'houseId' bemeneti paramétere üres.");\r
+                       throw new NullPointerException("System is not configured properly, 'houseId' input parameter missing.");\r
+               }\r
+               if (StringUtils.isBlank(targetPathType)) {\r
+                       logger.error(marker, "A folyamat 'targetPathType' bemeneti paramétere üres.");\r
+                       throw new NullPointerException("System is not configured properly, 'targetPathType' input parameter missing.");\r
+               }\r
+       }\r
+\r
+       @StepEntry\r
+       public Object[] execute(String localRetrievePath, String materialOutputFolder, String promoOutputFolder, String advertisementOutputFolder,\r
+                       String octopusOutputFolder, String genericOutputFolder, String onlineOutputFolder, String houseId, String targetPathType,\r
+                       ArchivedMedia archivedMedia, IJobEngine jobEngine, IJobRuntime jobRuntime) throws Exception {\r
+               marker = jobRuntime.getSessionMarker();\r
+               check(localRetrievePath, materialOutputFolder, promoOutputFolder, advertisementOutputFolder, octopusOutputFolder, genericOutputFolder, houseId,\r
+                               targetPathType);\r
+               Object[] result = null;\r
+               switch (Integer.parseInt(targetPathType)) {\r
+               case 0:\r
+                       String outputFolder = getFolderById(materialOutputFolder, promoOutputFolder, advertisementOutputFolder, octopusOutputFolder, genericOutputFolder,\r
+                                       houseId, archivedMedia);\r
+                       result = localTargetInit(localRetrievePath, outputFolder, houseId, jobRuntime);\r
+                       break;\r
+               case 1:\r
+                       result = localTargetInit(localRetrievePath, onlineOutputFolder, houseId, jobRuntime);\r
+                       break;\r
+               case 2:\r
+\r
+                       if (archivedMedia.getTcIn() != null && archivedMedia.getTcOut() != null)\r
+                               result = new Object[] { genericOutputFolder, houseId, true };\r
+                       else\r
+                               result = new Object[] { null, houseId, true };\r
+                       break;\r
+               }\r
+               return result;\r
+       }\r
+\r
+       private String getFolderById(String materialOutputFolder, String promoOutputFolder, String advertisementOutputFolder, String octopusOutputFolder,\r
+                       String genericOutputFolder, String houseId, ArchivedMedia archivedMedia) throws Exception {\r
+               String id = houseId.toUpperCase();\r
+               MetadataType mdType = MetadataTypeDetector.GuessMetadataType(id);\r
+               String result = null;\r
+\r
+               // a groovy nem latja enumnak, hanem az objektum tulajdonsaganak\r
+               switch (mdType.toString()) {\r
+               case "OctopusPlaceholder":\r
+               case "OctopusStory":\r
+                       // 220429 MV-ben nincs Octopus\r
+                       if (StringUtils.isBlank(octopusAddress))\r
+                               result = genericOutputFolder;\r
+                       else\r
+                               result = octopusOutputFolder;\r
+                       break;\r
+               case "TrafficMaterial":\r
+                       result = materialOutputFolder;\r
+                       break;\r
+               case "TrafficPromo":\r
+                       result = promoOutputFolder;\r
+                       break;\r
+               case "TrafficAD":\r
+                       result = advertisementOutputFolder;\r
+                       break;\r
+               case "Generic":\r
+                       result = genericOutputFolder;\r
+                       break;\r
+               }\r
+               return result;\r
+       }\r
+\r
+       private String getPossiblePath(String id, Path targetPath) throws IOException {\r
+               String[] result = new String[] { targetPath.toString() };\r
+               FileVisitor<Path> matcherVisitor = new SimpleFileVisitor<Path>() {\r
+                       @Override\r
+                       public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {\r
+                               String dirName = dir.getFileName().toString();\r
+                               if (dirName.startsWith(id + "-") || dirName.equals(id)) {\r
+                                       result[0] = dir.toString();\r
+                                       return FileVisitResult.TERMINATE;\r
+                               }\r
+                               return FileVisitResult.CONTINUE;\r
+                       }\r
+               };\r
+               Files.walkFileTree(targetPath.getParent(), matcherVisitor);\r
+               return result[0];\r
+       }\r
+\r
+       private Object[] localTargetInit(String localRetrievePath, String outputFolder, String houseId, IJobRuntime jobRuntime) throws IOException {\r
+               String id = houseId.toUpperCase();\r
+               String targetPath = getPossiblePath(id, Paths.get(localRetrievePath, outputFolder, id)).toString();\r
+               String targetNamePattern = houseId + TARGETNAMEPATTERN;\r
+               try {\r
+                       EscortFiles.ensureUNCFolder(Paths.get(targetPath));\r
+               } catch (Exception e) {\r
+                       logger.error(jobRuntime.getSessionMarker(), "A cél mappa '{}' nem létezik és nem hozható létre. A rendszer hibaüzenete: {}", targetPath,\r
+                                       e.getMessage());\r
+                       throw e;\r
+               }\r
+               return new Object[] { targetPath, targetNamePattern, false };\r
+       }\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/ProjectCleanupMountedLocationStep.java b/server/-product/production/HIRTV/jobs/steps/ProjectCleanupMountedLocationStep.java
new file mode 100644 (file)
index 0000000..06d1cc6
--- /dev/null
@@ -0,0 +1,225 @@
+package user.jobengine.server.steps;\r
+\r
+import java.io.File;\r
+import java.io.IOException;\r
+import java.nio.file.DirectoryStream;\r
+import java.nio.file.FileVisitResult;\r
+import java.nio.file.FileVisitor;\r
+import java.nio.file.Files;\r
+import java.nio.file.Path;\r
+import java.nio.file.Paths;\r
+import java.nio.file.SimpleFileVisitor;\r
+import java.nio.file.attribute.BasicFileAttributes;\r
+import java.text.ParseException;\r
+import java.text.SimpleDateFormat;\r
+import java.util.ArrayList;\r
+import java.util.Collections;\r
+import java.util.Date;\r
+import java.util.List;\r
+\r
+import org.apache.commons.io.FileUtils;\r
+import org.apache.commons.lang.StringUtils;\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+import org.apache.logging.log4j.Marker;\r
+\r
+import user.jobengine.server.IJobEngine;\r
+import user.jobengine.server.IJobRuntime;\r
+import user.jobengine.server.steps.shared.MetadataType;\r
+import user.jobengine.server.steps.shared.MetadataTypeDetector;\r
+\r
+public class ProjectCleanupMountedLocationStep extends JobStep implements FileVisitor<Path> {\r
+\r
+       private static final Logger logger = LogManager.getLogger();\r
+       private static final String DATEFORMAT = "yyyyMMdd";\r
+       private static final String DOT = ".";\r
+       private static final String STATUSFOLDER = ".STATUS";\r
+       private static final String KILLDATEEXT = ".killdate";\r
+       private Marker marker;\r
+       final int[] allCount = new int[] { 0 };\r
+       final int[] currentCount = new int[] { 0 };\r
+       private Path sourcePath;\r
+       private SimpleDateFormat dateFormat;\r
+\r
+       private Date checkExpiration(List<Path> killDateFiles) {\r
+               Date killDate = null;\r
+               for (Path killDateFile : killDateFiles) {\r
+                       Date currentKillDate = getKillDate(killDateFile);\r
+                       if (currentKillDate == null)\r
+                               continue;\r
+                       if ((killDate != null && currentKillDate.after(killDate)) || killDate == null)\r
+                               killDate = currentKillDate;\r
+               }\r
+               return new Date().after(killDate) ? killDate : null;\r
+       }\r
+\r
+       @StepEntry\r
+       public Object[] execute(String sourceFolder, IJobEngine jobEngine, IJobRuntime jobRuntime) throws Exception {\r
+               marker = jobRuntime.getSessionMarker();\r
+               sourcePath = Paths.get(sourceFolder);\r
+               DirectoryStream<Path> directoryStream = null;\r
+               if (StringUtils.isBlank(sourcePath.toString())) {\r
+                       logger.error(marker, "A folyamat 'sourcePath' bemeneti paramétere üres.");\r
+                       throw new NullPointerException("System is not configured properly, 'sourceFolder' input parameter missing.");\r
+               }\r
+\r
+               if (!sourcePath.toFile().exists() || !sourcePath.toFile().isDirectory()) {\r
+                       logger.error(marker, "A(z) {} mappa nem létezik.", sourceFolder);\r
+                       throw new NullPointerException(String.format("Directory %s does not exist.", sourceFolder));\r
+               }\r
+               try {\r
+                       setProgress(1);\r
+                       dateFormat = new SimpleDateFormat(DATEFORMAT);\r
+                       Files.walkFileTree(sourcePath, new SimpleFileVisitor<Path>() {\r
+                               @Override\r
+                               public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {\r
+                                       allCount[0]++;\r
+                                       return super.visitFile(file, attrs);\r
+                               }\r
+                       });\r
+                       Files.walkFileTree(sourcePath, this);\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       logger.error(marker, "Az '{}' mappa elérése sikertelen. A rendszer hibaüzenete: {}", sourcePath, e.getMessage());\r
+                       throw e;\r
+               } finally {\r
+                       if (directoryStream != null) {\r
+                               try {\r
+                                       directoryStream.close();\r
+                               } catch (IOException e) {\r
+                               }\r
+                       }\r
+               }\r
+               return null;\r
+       }\r
+\r
+       private Date getKillDate(Path killDateFile) {\r
+               String fileName = killDateFile.getFileName().toString();\r
+               int end = fileName.lastIndexOf(DOT);\r
+               if (end < 1)\r
+                       return null;\r
+               int start = fileName.lastIndexOf(DOT, end - 1);\r
+               if (start < 0)\r
+                       return null;\r
+               String strKillDate = fileName.substring(start + 1, end);\r
+               Date result = null;\r
+               if (StringUtils.isNumeric(strKillDate)) {\r
+                       try {\r
+                               result = dateFormat.parse(strKillDate);\r
+                       } catch (ParseException e) {\r
+                               logger.error(marker, "A {} fájl 'killdate' állománya hibás formátumú, a {} karaktersorozat nem konvertálható dátummá.", fileName, strKillDate);\r
+                               return null;\r
+                       }\r
+               } else\r
+                       logger.error(marker, "A {} fájl 'killdate' állománya hibás formátumú, az dátum helyett ez áll: '{}'.", fileName, strKillDate);\r
+               return result;\r
+       }\r
+\r
+       private List<Path> getKillDateFiles(Path filePath) {\r
+               String killDateFilePattern = String.format("%s.*%s", filePath.getFileName().toString(), KILLDATEEXT);\r
+               List<Path> result = new ArrayList<>();\r
+               Path statusPath = null;\r
+               try {\r
+                       statusPath = Paths.get(filePath.getParent().toString(), STATUSFOLDER);\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       return null;\r
+               }\r
+               File statusPathFile = statusPath.toFile();\r
+               if (statusPathFile.exists() && statusPathFile.isDirectory()) {\r
+                       try (DirectoryStream<Path> stream = Files.newDirectoryStream(statusPath, killDateFilePattern)) {\r
+                               stream.forEach(p -> result.add(p));\r
+                       } catch (Exception e) {\r
+                               logger.catching(e);\r
+                       }\r
+               }\r
+               Collections.sort(result);\r
+               return result;\r
+       }\r
+\r
+       private Path getProjectRootPath(Path filePath) {\r
+               Path result = null;\r
+               if (filePath.getNameCount() > sourcePath.getNameCount()) {\r
+                       String dir = filePath.getName(sourcePath.getNameCount()).toString();\r
+                       String[] tokens = dir.split("-");\r
+                       if (tokens.length != 0 && MetadataTypeDetector.GuessMetadataType(tokens[0]) == MetadataType.TrafficPromo)\r
+                               result = Paths.get(sourcePath.toAbsolutePath().toString(), dir);\r
+               }\r
+               return result;\r
+       }\r
+\r
+       @Override\r
+       public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {\r
+               return FileVisitResult.CONTINUE;\r
+       }\r
+\r
+       @Override\r
+       public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {\r
+               if (dir.equals(sourcePath))\r
+                       return FileVisitResult.CONTINUE;\r
+\r
+               Path parent = getProjectRootPath(dir);\r
+               if (parent == null) {\r
+                       System.out.println("Skipping " + dir);\r
+                       return FileVisitResult.SKIP_SUBTREE;\r
+               }\r
+\r
+               return FileVisitResult.CONTINUE;\r
+       }\r
+\r
+       private boolean processPathItem(Path filePath) {\r
+               currentCount[0]++;\r
+               int progress = currentCount[0] * 100 / allCount[0];\r
+               setProgress(progress);\r
+\r
+               if (filePath.toFile().isDirectory() || !filePath.toString().toUpperCase().endsWith(".EZP"))\r
+                       return false;\r
+\r
+               // level check\r
+               if (filePath.getNameCount() != sourcePath.getNameCount() + 3) {\r
+                       // logger.warn(marker, "A {} fájl elérési útja a várttól eltérő.", filePath);\r
+                       return false;\r
+               }\r
+\r
+               List<Path> killDateFiles = getKillDateFiles(filePath);\r
+               if (killDateFiles == null || killDateFiles.size() == 0) {\r
+                       logger.warn(marker, "A {} fájlhoz nem található 'killdate' állomány.", filePath);\r
+                       return false;\r
+               }\r
+\r
+               if (killDateFiles.size() != 1)\r
+                       logger.warn(marker, "A {} fájlhoz több 'killdate' állomány található, a legújabb dátum határozza meg a törlés időpontját.", filePath);\r
+\r
+               Date killDate = checkExpiration(killDateFiles);\r
+               if (killDate == null)\r
+                       return false;\r
+\r
+               Path parent = getProjectRootPath(filePath);\r
+               if (parent != null) {\r
+                       Path pathToDelete = Paths.get(sourcePath.toAbsolutePath().toString(), filePath.getName(sourcePath.getNameCount()).toString());\r
+                       try {\r
+                               FileUtils.deleteDirectory(pathToDelete.toFile());\r
+                               logger.info(marker, "A {} mappa sikeresen törlődött. Lejárat: {}", pathToDelete, dateFormat.format(killDate));\r
+                       } catch (Exception e) {\r
+                               logger.error(marker, "A {} mappa törlése nem lehetséges, a rendszer üzenete: {}", pathToDelete, e.getMessage());\r
+                               logger.error(e);\r
+                       }\r
+               }\r
+               // else\r
+               // logger.warn(marker, "A {} fájlhoz nem határozható meg a törlendő\r
+               // szülőkönyvtár.", filePath);\r
+               return true;\r
+       }\r
+\r
+       @Override\r
+       public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {\r
+               processPathItem(file);\r
+               return FileVisitResult.CONTINUE;\r
+       }\r
+\r
+       @Override\r
+       public FileVisitResult visitFileFailed(Path file, IOException e) throws IOException {\r
+               logger.error(marker, "A {} fájl nem érhető el. A rendszer hibaüzenete: {}", file.toString(), e.getMessage());\r
+               return FileVisitResult.CONTINUE;\r
+       }\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/RecordingsArchiveItemBuilderStep.java b/server/-product/production/HIRTV/jobs/steps/RecordingsArchiveItemBuilderStep.java
new file mode 100644 (file)
index 0000000..cb3f5d5
--- /dev/null
@@ -0,0 +1,322 @@
+package user.jobengine.server.steps;\r
+\r
+import java.io.File;\r
+import java.io.IOException;\r
+import java.nio.file.FileVisitResult;\r
+import java.nio.file.Files;\r
+import java.nio.file.Path;\r
+import java.nio.file.Paths;\r
+import java.nio.file.SimpleFileVisitor;\r
+import java.nio.file.attribute.BasicFileAttributes;\r
+import java.text.ParseException;\r
+import java.text.SimpleDateFormat;\r
+import java.util.Calendar;\r
+import java.util.Date;\r
+import java.util.List;\r
+\r
+import org.apache.commons.lang.StringUtils;\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+import org.apache.logging.log4j.Marker;\r
+\r
+import com.ibm.nosql.json.api.BasicDBObject;\r
+import com.ibm.nosql.json.api.DB;\r
+import com.ibm.nosql.json.api.DBCollection;\r
+import com.ibm.nosql.json.api.DBObject;\r
+\r
+import user.commons.CalendarUtils;\r
+import user.commons.nosql.NoSQLUtils;\r
+import user.commons.octopus.IOctopusAPI;\r
+import user.commons.octopus.OctopusAPI;\r
+import user.jobengine.server.IJobEngine;\r
+import user.jobengine.server.IJobRuntime;\r
+import user.jobengine.server.steps.shared.EscortFiles;\r
+\r
+public class RecordingsArchiveItemBuilderStep extends JobStep {\r
+       private static final String MEDIATYPE = "Visszarögzített";\r
+       private static final Logger logger = LogManager.getLogger();\r
+       private static final String STATUSFOLDER = ".STATUS";\r
+       private static final String LXFEXT = ".lxf";\r
+       private static final String CATCHEDEXT = ".catched";\r
+       private static final SimpleDateFormat startTimeformat = new SimpleDateFormat("HHmm");\r
+       private static final SimpleDateFormat startDateformat = new SimpleDateFormat("yyMMdd");\r
+       private static final String SCHEDULED_FORMAT = "yyyy.MM.dd HH:mm";\r
+\r
+       private Marker marker;\r
+       private DBCollection existingRecordings;\r
+\r
+       private ArchiveItem createArchiveItem(Path mediaFilePath, Path catchedFilePath) {\r
+               ArchiveItem result = null;\r
+               try {\r
+\r
+                       Date recordDate = startDateformat.parse(mediaFilePath.getParent().toFile().getName());\r
+                       String clipName = mediaFilePath.toFile().getName();\r
+                       Date scheduledStart = getScheduledStart(clipName, recordDate);\r
+                       IOctopusAPI octopusAPI = new OctopusAPI();\r
+\r
+                       DBObject rundown = octopusAPI.getRundown(scheduledStart);\r
+                       if (rundown == null) {\r
+                               logger.error(marker, "A '{}' anyaghoz nem található tükör '{}' kezdéssel, ezért nem archiválható.",\r
+                                               clipName, scheduledStart);\r
+                               return null;\r
+                       }\r
+                       result = processRundow(octopusAPI, rundown);\r
+                       if (result == null)\r
+                               return null;\r
+\r
+                       if (clipName.startsWith("1900")) {\r
+                               Calendar cal = CalendarUtils.createCalendar(scheduledStart);\r
+                               cal.add(Calendar.MINUTE, 5);\r
+                               rundown = octopusAPI.getRundown(cal.getTime());\r
+                               if (rundown == null) {\r
+                                       logger.error(marker, "A '{}' anyaghoz nem található tükör '{}' kezdéssel, ezért nem archiválható.",\r
+                                                       clipName, scheduledStart);\r
+                                       return null;\r
+                               }\r
+                               ArchiveItem item2 = processRundow(octopusAPI, rundown);\r
+                               if (item2 == null)\r
+                                       return null;\r
+\r
+                               result.setItemTitle(result.getItemTitle() + " + NAPIAKT");\r
+                               result.setMediaDescription(result.getMediaDescription() + "\r\n\r\n****** NAPIAKT ******\r\n\r\n"\r
+                                               + item2.getMediaDescription());\r
+                       }\r
+\r
+                       result.setMediaTitle(clipName);\r
+                       result.setMediaType(MEDIATYPE);\r
+                       result.setMediaFile(mediaFilePath.toString());\r
+                       result.setCatchedFile(catchedFilePath.toString());\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       logger.error(getJobRuntime().getSessionMarker(), "A metaadat nem elérhető. A rendszer üzenete: {}",\r
+                                       e.getMessage());\r
+                       return null;\r
+               }\r
+\r
+               return result;\r
+       }\r
+\r
+       private void createCatchedFile(Path catchedFilePath) throws IOException {\r
+               try {\r
+                       EscortFiles.ensureUNCFolder(catchedFilePath.getParent());\r
+                       Files.createFile(catchedFilePath);\r
+               } catch (IOException e) {\r
+                       logger.catching(e);\r
+                       logger.error(marker, "A '{}' jelzőfájl nem hozható létre. A rendszer üzenete: {}", catchedFilePath,\r
+                                       e.getMessage());\r
+                       throw e;\r
+               }\r
+       }\r
+\r
+       @StepEntry\r
+       public Object[] execute(String sourcePath, IJobEngine jobEngine, IJobRuntime jobRuntime) throws Exception {\r
+               final ArchiveItem[] archiveItems = { null };\r
+               DB db = NoSQLUtils.getNoSQLDB();\r
+               existingRecordings = db.getCollection("tmp_existing_recordings");\r
+               marker = getJobRuntime().getSessionMarker();\r
+               try {\r
+                       Files.walkFileTree(Paths.get(sourcePath), new SimpleFileVisitor<Path>() {\r
+\r
+                               @Override\r
+                               public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {\r
+                                       FileVisitResult result = FileVisitResult.SKIP_SUBTREE;\r
+\r
+                                       if (dir.equals(Paths.get(sourcePath)) || "2017".equals(dir.toFile().getName().toUpperCase())\r
+                                                       || "2018".equals(dir.toFile().getName().toUpperCase()))\r
+                                               result = FileVisitResult.CONTINUE;\r
+                                       else {\r
+                                               if ("2017".equals(dir.getParent().toFile().getName().toUpperCase())\r
+                                                               || "2018".equals(dir.getParent().toFile().getName().toUpperCase())) {\r
+                                                       try {\r
+                                                               startDateformat.parse(dir.toFile().getName());\r
+                                                               result = FileVisitResult.CONTINUE;\r
+                                                       } catch (ParseException e) {\r
+                                                       }\r
+                                               }\r
+                                       }\r
+\r
+                                       if (result == FileVisitResult.CONTINUE)\r
+                                               logger.info(dir);\r
+                                       return result;\r
+                               }\r
+\r
+                               @Override\r
+                               public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {\r
+                                       FileVisitResult result = FileVisitResult.TERMINATE;\r
+                                       ArchiveItem item = null;\r
+                                       try {\r
+                                               item = processPathItem(file);\r
+                                       } catch (IOException e) {\r
+                                               logger.catching(e);\r
+                                               logger.error(marker, "Az '{}' állomány feldolgozása sikertelen. A rendszer hibaüzenete: {}",\r
+                                                               file, e.getMessage());\r
+                                               throw e;\r
+                                       }\r
+                                       if (item == null) {\r
+                                               result = FileVisitResult.CONTINUE;\r
+                                       } else {\r
+                                               logger.info(file);\r
+                                               archiveItems[0] = item;\r
+                                       }\r
+                                       return result;\r
+                               }\r
+\r
+                       });\r
+\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       logger.error(marker, "Az '{}' mappa elérése sikertelen. A rendszer hibaüzenete: {}", sourcePath,\r
+                                       e.getMessage());\r
+                       throw e;\r
+               } finally {\r
+               }\r
+               ArchiveItem archiveItem = archiveItems[0];\r
+               String targetFileName = null;\r
+\r
+               if (archiveItem == null || archiveItem.getMediaFile() == null) {\r
+                       logger.warn(marker, "Az archiváló folyamat nem talált új anyagot.");\r
+                       throw new Exception("No media to archive");\r
+               } else {\r
+                       String mediaFile = archiveItem.getMediaFile();\r
+                       String name = new File(mediaFile).getName();\r
+                       int extPos = name.toLowerCase().lastIndexOf(LXFEXT);\r
+                       targetFileName = String.format("20%s-%s", Paths.get(mediaFile).getParent().getFileName(),\r
+                                       name.substring(0, extPos));\r
+                       if (targetFileName.length() > 32) {\r
+                               targetFileName = targetFileName.substring(0, 28) + "_PGM";\r
+                       }\r
+                       logger.info(marker, "Az archiváló folyamat az '{}' anyagot archiválja.", mediaFile);\r
+               }\r
+\r
+               return new Object[] { archiveItem, targetFileName };\r
+       }\r
+\r
+       private Date getScheduledStart(String clipName, Date recordDate) {\r
+\r
+               if (StringUtils.isBlank(clipName)) {\r
+                       logger.warn(marker, "A fájlnak nincs neve, ezért nem archiválható.");\r
+                       return null;\r
+               }\r
+               if (recordDate == null) {\r
+                       logger.warn(marker, "Az '{}' fájl rögzítésének ideje nem meghatározható, ezért nem archiválható.",\r
+                                       clipName);\r
+                       return null;\r
+               }\r
+\r
+               Date timePart = null;\r
+               try {\r
+                       String clipNameTime = clipName.split("_")[0];\r
+                       timePart = startTimeformat.parse(clipNameTime);\r
+               } catch (ParseException e) {\r
+                       logger.warn(marker, "A '{}' fájl neve nem időbélyeggel kezdődik, ezért nem archiválható.", clipName);\r
+                       return null;\r
+               }\r
+               return CalendarUtils.createCalendar(CalendarUtils.createCalendar(recordDate), timePart).getTime();\r
+       }\r
+\r
+       private ArchiveItem processPathItem(Path mediaFilePath) throws IOException {\r
+               File mediaFile = mediaFilePath.toFile();\r
+\r
+               Path dotStorePath = Paths.get(mediaFilePath.getParent().toString(), STATUSFOLDER);\r
+               Path catchedFilePath = Paths.get(dotStorePath.toString(), mediaFile.getName() + CATCHEDEXT);\r
+               File catchedFile = catchedFilePath.toFile();\r
+               if (catchedFile.exists()) {\r
+                       // logger.info("'{}' file is already catched", mediaFilePath);\r
+                       return null;\r
+               }\r
+               createCatchedFile(catchedFilePath);\r
+               if (!catchedFile.exists()) {\r
+                       logger.warn("'{}' catchfile does not exist.", catchedFilePath);\r
+                       return null;\r
+               }\r
+\r
+               if (mediaFile.isDirectory() || !mediaFile.getName().toLowerCase().endsWith(LXFEXT.toLowerCase())\r
+                               || mediaFilePath.getParent().toFile().getName().length() != 6\r
+                               || !mediaFile.getName().toLowerCase().contains("_pgm_")) {\r
+                       logger.info("Skipping '{}'", mediaFilePath);\r
+                       return null;\r
+               }\r
+\r
+               ArchiveItem archiveItem = createArchiveItem(mediaFilePath, catchedFilePath);\r
+\r
+               if (archiveItem == null) {\r
+                       logger.warn("'{}' has no metadata specified.", mediaFilePath);\r
+                       return null;\r
+               }\r
+\r
+               DBObject existingRecording = existingRecordings\r
+                               .findOne(new BasicDBObject("title", archiveItem.getItemTitle().substring(0, 16)));\r
+\r
+               if (existingRecording != null) {\r
+                       logger.warn("'{}' already archived, skipping.", archiveItem.getItemTitle());\r
+                       return null;\r
+               }\r
+\r
+               if (StringUtils.isBlank(archiveItem.getItemHouseId())) {\r
+                       logger.warn("'{}' has no Item HouseID specified in metadata.", mediaFilePath);\r
+                       return null;\r
+               }\r
+\r
+               if (StringUtils.isBlank(archiveItem.getItemTitle())) {\r
+                       logger.warn("'{}' has no Item Title specified in metadata.", mediaFilePath);\r
+                       return null;\r
+               }\r
+\r
+               if (StringUtils.isBlank(archiveItem.getMediaHouseId())) {\r
+                       logger.warn("'{}' has no Media HouseID specified in metadata.", mediaFilePath);\r
+                       return null;\r
+               }\r
+\r
+               if (StringUtils.isBlank(archiveItem.getMediaTitle())) {\r
+                       logger.warn("'{}' has no Media Title specified in metadata.", mediaFilePath);\r
+                       return null;\r
+               }\r
+               return archiveItem;\r
+       }\r
+\r
+       private ArchiveItem processRundow(IOctopusAPI octopusAPI, DBObject r) throws Exception {\r
+               BasicDBObject rundown = (BasicDBObject) r;\r
+               long rundownID = rundown.getLong(IOctopusAPI.ID);\r
+               logger.info("Processing rundown {} {}", rundownID, rundown.getString(IOctopusAPI.NAME));\r
+\r
+               List<DBObject> stories = octopusAPI.getRundownFullStories(rundownID);\r
+               if (stories == null)\r
+                       return null;\r
+\r
+               String name = NoSQLUtils.asString(NoSQLUtils.asDBObject(rundown, IOctopusAPI.RUNDOWN_TYPE), IOctopusAPI.NAME);\r
+               if (StringUtils.isBlank(name))\r
+                       return null;\r
+               String channel = NoSQLUtils.asString(NoSQLUtils.asDBObject(rundown, IOctopusAPI.CHANNEL), IOctopusAPI.NAME);\r
+               Date scheduledStart = rundown.getDate(IOctopusAPI.SCHEDULED_START);\r
+               if (scheduledStart == null)\r
+                       return null;\r
+\r
+               ArchiveItem result = new ArchiveItem();\r
+               result.setItemHouseId(String.valueOf(rundownID));\r
+               String start = CalendarUtils.toString(CalendarUtils.createCalendar(scheduledStart), SCHEDULED_FORMAT);\r
+               result.setItemTitle(String.format("%s %s %s", start, name, channel));\r
+\r
+               StringBuilder sb = new StringBuilder();\r
+               for (DBObject s : stories) {\r
+                       BasicDBObject story = (BasicDBObject) s;\r
+\r
+                       sb.append("*** ");\r
+                       sb.append(story.getString(IOctopusAPI.PARENT_STORY_ID));\r
+                       sb.append(" [" + story.getString(IOctopusAPI.FORMAT) + "] ");\r
+                       sb.append(story.getString(IOctopusAPI.NAME));\r
+                       sb.append(" ***");\r
+                       sb.append("\r\n");\r
+                       String content = story.getString(IOctopusAPI.SCRIPT_CONTENT);\r
+                       if (content != null) {\r
+                               content = content.replace("\r\n\r\n\r\n\r\n", "\r\n");\r
+                               content = content.replace("\r\n\r\n\r\n", "\r\n");\r
+                               content = content.replace("\r\n\r\n", "\r\n");\r
+                               sb.append(content);\r
+                               sb.append("\r\n");\r
+                       }\r
+               }\r
+               result.setMediaHouseId(result.getItemHouseId());\r
+               result.setMediaDescription(sb.toString());\r
+               return result;\r
+       }\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/SyncOCTOPUSDataStep.java b/server/-product/production/HIRTV/jobs/steps/SyncOCTOPUSDataStep.java
new file mode 100644 (file)
index 0000000..9813604
--- /dev/null
@@ -0,0 +1,32 @@
+package user.jobengine.server.steps;\r
+\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+\r
+import user.commons.remotestore.IProgressEventListener;\r
+import user.jobengine.server.steps.shared.OctopusDataMiner;\r
+\r
+public class SyncOCTOPUSDataStep extends JobStep {\r
+       private static final Logger logger = LogManager.getLogger();\r
+       private IProgressEventListener progressListener;\r
+\r
+       @StepEntry\r
+       public Object[] execute(boolean includeArchived, int maxPastDays, String address, String user, String pwd) throws Exception {\r
+               OctopusDataMiner dataMiner = null;\r
+               try {\r
+                       dataMiner = new OctopusDataMiner(address, user, pwd, maxPastDays);\r
+                       dataMiner.addProgressListener(e -> {\r
+                               setProgress(e.getProgress());\r
+                       });\r
+                       dataMiner.execute(includeArchived);\r
+               } catch (Exception e) {\r
+                       logger.error(getMarker(), "Általános folyamat hiba. A rendszer hibaüzenete: {}", e.getMessage());\r
+                       throw e;\r
+               } finally {\r
+                       if (dataMiner != null)\r
+                               dataMiner.removeProgressListener(progressListener);\r
+               }\r
+               return null;\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/TSMBackupStep.java b/server/-product/production/HIRTV/jobs/steps/TSMBackupStep.java
new file mode 100644 (file)
index 0000000..a71ce5d
--- /dev/null
@@ -0,0 +1,231 @@
+package user.jobengine.server.steps;\r
+\r
+import java.io.File;\r
+import java.io.IOException;\r
+import java.sql.Timestamp;\r
+import java.util.Date;\r
+import java.util.List;\r
+\r
+import org.apache.commons.lang.RandomStringUtils;\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+import org.apache.logging.log4j.Marker;\r
+import org.apache.logging.log4j.message.Message;\r
+import org.apache.logging.log4j.message.ParameterizedMessage;\r
+\r
+import user.commons.RemoteFile;\r
+import user.commons.StoreUri;\r
+import user.commons.configuration.SystemConfiguration;\r
+import user.commons.mediatool.Timecode;\r
+import user.commons.mediatool.Timecode.Type;\r
+import user.commons.remotestore.IProgressEventListener;\r
+import user.commons.remotestore.IStatusEventListener;\r
+import user.commons.remotestore.ProgressEvent;\r
+import user.commons.remotestore.RemoteStoreProtocol;\r
+import user.commons.remotestore.StatusEvent;\r
+import user.jobengine.db.FileType;\r
+import user.jobengine.db.IItemManager;\r
+import user.jobengine.db.Media;\r
+import user.jobengine.db.MediaFile;\r
+import user.jobengine.db.Store;\r
+import user.jobengine.server.IJobEngine;\r
+import user.jobengine.server.IJobRuntime;\r
+import user.jobengine.server.JobEngineException;\r
+import user.jobengine.server.steps.shared.EscortFiles;\r
+import user.jobengine.server.steps.shared.ItemManagerExtensions;\r
+import user.jobengine.server.steps.shared.MetadataSaver;\r
+\r
+public class TSMBackupStep extends JobStep {\r
+       private static final String MXFEXT = ".MXF";\r
+       private static final Logger logger = LogManager.getLogger();\r
+       private static boolean RANDOMIZE_ARCHIVES = SystemConfiguration.getInstance().value("tsm.randomize-archives");\r
+       private IItemManager manager;\r
+       private File sourceMediaFile;\r
+       private Store tsmStore;\r
+       private StoreUri targetUri;\r
+       private FileType fileType;\r
+       private Marker marker;\r
+\r
+       @StepEntry\r
+       public Object[] execute(ArchiveItem archiveItem, Media mediaCubeMedia, int killDateDays) throws Exception {\r
+               marker = getSessionMarker();\r
+\r
+               File sourceMediaFile = new File(archiveItem.getMediaFile());\r
+               String sourceFileName = sourceMediaFile.getName();\r
+               long fileSize = sourceMediaFile.length();\r
+\r
+               try {\r
+                       Timecode timecode = new Timecode(mediaCubeMedia.getLength(), Type.PAL);\r
+                       String details = String.format("%s (%s, %d bytes)", sourceFileName, timecode.toString(), fileSize);\r
+                       logger.info(marker, details);\r
+                       getJobRuntime().setDescription(details);\r
+               } catch (Exception e) {\r
+                       String details = String.format("%s (%d bytes)", sourceFileName, fileSize);\r
+                       getJobRuntime().setDescription(details);\r
+               }\r
+               Timecode timecode = new Timecode(mediaCubeMedia.getLength(), Type.PAL);\r
+               String details = String.format("%s (%s, %d bytes)", sourceFileName, timecode.toString(), fileSize);\r
+               getJobRuntime().setDescription(details);\r
+               try {\r
+\r
+                       setAndCheck(archiveItem, mediaCubeMedia, getEngine());\r
+\r
+                       // TODO mxf helyett az osszes kiterjesztest!!!!!\r
+                       // A dupla ellenorzes a napon beluli ismetlesek miatt kell\r
+                       long existingMediaId = archiveItem.getExistingMediaId();\r
+\r
+                       if (fileSize == 0 && existingMediaId == 0) {\r
+                               existingMediaId = ItemManagerExtensions.getExistingRundownMedia(manager, sourceFileName.replace(MXFEXT, ""));\r
+                               if (existingMediaId == 0)\r
+                                       existingMediaId = -1;\r
+                       }\r
+\r
+                       if (existingMediaId == 0)\r
+                               existingMediaId = ItemManagerExtensions.getExistingRundownMedia(manager, sourceFileName.replace(MXFEXT, ""));\r
+                       String targetFileName;\r
+                       if (RANDOMIZE_ARCHIVES) {\r
+                               // a-z, A-Z, 0-9. For example: WRMcpIk7, s57JwCVA\r
+                               // veletlenszeru neveket adunk!\r
+                               targetFileName = String.format("%s-%s", RandomStringUtils.randomAlphanumeric(8), sourceFileName);\r
+                       } else\r
+                               targetFileName = sourceFileName;\r
+\r
+                       if (existingMediaId == 0) {\r
+                               StoreUri sourceUri = manager.createStoreUri(RemoteStoreProtocol.LOCAL, sourceMediaFile.getParent().toString());\r
+\r
+                               final IJobRuntime runtime = getJobRuntime();\r
+                               sourceUri.addProgressListener(new IProgressEventListener() {\r
+                                       @Override\r
+                                       public void progressChanged(ProgressEvent evt) {\r
+                                               runtime.incrementProgress(evt.getProgress());\r
+                                       }\r
+                               });\r
+                               sourceUri.addStatusListener(new IStatusEventListener() {\r
+                                       @Override\r
+                                       public void statusChanged(StatusEvent evt) {\r
+                                               evt.setCancel(!canContinue());\r
+                                       }\r
+                               });\r
+\r
+                               RemoteFile remoteFile = sourceUri.transferFrom(targetUri, sourceFileName, targetFileName);\r
+\r
+                               if (RemoteStoreProtocol.LOCAL.equals(sourceUri.getProtocol())) {\r
+                                       MetadataSaver.saveMetadata(archiveItem.getMediaFile());\r
+                               }\r
+\r
+                       }\r
+\r
+                       if (existingMediaId > 0)\r
+                               logger.info(marker, "Az '{}' TSM mentése nem szükséges, mert már megtalálható az archívumban.", sourceFileName);\r
+\r
+                       // Fel kell szabadítani, hogy a kovetkezo archivalaskor is nekifusson\r
+                       if (existingMediaId == -1) {\r
+                               logger.info(marker, "Az '{}' mentése jelenleg nem lehetséges, mert a szükséges metaadat még nem található meg az archívumban.", sourceFileName);\r
+                               if (!archiveItem.removeCatchedFile())\r
+                                       logger.error(marker,\r
+                                                       "Az '{}' állomány .catched jelző állománya nem törölhető. Az újabb archiválási kísérlethez annak kézi eltávolítása szükséges!",\r
+                                                       sourceMediaFile.getName());\r
+                               mediaCubeMedia.remove();\r
+                       } else {\r
+                               saveMetadata(mediaCubeMedia, sourceMediaFile, targetFileName, existingMediaId, fileSize, archiveItem.isDisableProxy());\r
+                               logger.info(marker, "Az '{}' archiválása sikeres.", sourceFileName);\r
+                               if (killDateDays != 0)\r
+                                       EscortFiles.createUNCKillDate(sourceMediaFile.getParent(), sourceFileName, killDateDays, marker);\r
+                       }\r
+\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       Message m = new ParameterizedMessage("Az '{}' állomány archiválása sikertelen. A rendszer hibaüzenete: {}", details, e.getMessage());\r
+                       logger.error(marker, m);\r
+                       if (!archiveItem.removeCatchedFile())\r
+                               logger.error(marker,\r
+                                               "Az '{}' állomány .catched jelző állománya nem törölhető. Az újabb archiválási kísérlethez annak kézi eltávolítása szükséges!",\r
+                                               sourceMediaFile.getName());\r
+                       throw new Exception(m.getFormattedMessage());\r
+               }\r
+               return null;\r
+       }\r
+\r
+       private void saveMetadata(Media mediaCubeMedia, File sourceFile, String targetFileName, long existingMediaId, long fileSize, boolean disableProxy) {\r
+\r
+               if (existingMediaId == 0) {\r
+                       MediaFile mf = manager.createMediaFile(targetFileName, fileType, tsmStore, mediaCubeMedia);\r
+                       mf.setHouseId(sourceFile.getName());\r
+                       mf.setFileSize(fileSize);\r
+                       // 210617 proxy keszites tiltasa\r
+                       mf.setDisableProxy(disableProxy);\r
+                       mf.add();\r
+               } else {\r
+                       Media existingMedia = manager.getMedia(existingMediaId);\r
+                       List<MediaFile> mediaFiles = existingMedia.getMediaFiles();\r
+                       if (mediaFiles != null) {\r
+                               for (MediaFile mf : mediaFiles) {\r
+                                       mf.setPersister(manager);\r
+                                       mf.setId(0);\r
+                                       mf.setMedia(mediaCubeMedia);\r
+                                       // mivel itt masolat keszul, nem allitunk at semmit\r
+                                       // mf.setFileSize(fileSize);\r
+                                       // mf.setDisableProxy(disableProxy);\r
+                                       mf.add();\r
+                               }\r
+                       }\r
+               }\r
+               mediaCubeMedia.setPersister(manager);\r
+\r
+               // 210614 megis maradjon az aktualis idopont\r
+               mediaCubeMedia.setArchived(new Timestamp(new Date().getTime()));\r
+\r
+               /*\r
+                * try { BasicFileAttributes attr = Files.readAttributes(sourceFile.toPath(),\r
+                * BasicFileAttributes.class); mediaCubeMedia.setArchived(new\r
+                * Timestamp(attr.creationTime().toMillis())); } catch (IOException e) {\r
+                * logger.catching(e); }\r
+                */\r
+               mediaCubeMedia.modify();\r
+       }\r
+\r
+       private void setAndCheck(ArchiveItem archiveItem, Media mediaCubeMedia, IJobEngine jobEngine) throws JobEngineException, IOException {\r
+               if (jobEngine == null) {\r
+                       logger.error(marker, "Az folyamatkezelő réteg nem elérhető.");\r
+                       throw new NullPointerException("Internal error, missing JobEngine reference.");\r
+               }\r
+               manager = jobEngine.getItemManager();\r
+               if (manager == null) {\r
+                       logger.error(marker, "Az adatbáziskezelő réteg nem elérhető.");\r
+                       throw new NullPointerException("Internal error, missing ItemManager reference.");\r
+               }\r
+               if (archiveItem == null) {\r
+                       logger.error(marker, "A folyamat 'archiveItem' bemeneti paramétere üres.");\r
+                       throw new NullPointerException("System is not configured properly, missing 'archiveItem' input parameter.");\r
+               }\r
+               sourceMediaFile = new File(archiveItem.getMediaFile());\r
+               if (sourceMediaFile == null) {\r
+                       logger.error(marker, "A folyamat 'archiveItem' bemeneti paraméter 'mediaFile' értéke üres.");\r
+                       throw new NullPointerException("System is not configured properly, missing 'mediaFile' value in 'archiveItem' input parameter.");\r
+               }\r
+               if (!sourceMediaFile.exists()) {\r
+                       logger.error(marker, "A(z) {} állomány nem létezik vagy nem érhető el.", sourceMediaFile.getName());\r
+                       throw new IOException(String.format("Input file {} does not exist or unreachable.", sourceMediaFile.getName()));\r
+               }\r
+               tsmStore = manager.getSystemStore(false);\r
+               if (tsmStore == null) {\r
+                       logger.error(marker, "A TSM rendszer beállítás nem elérhető.");\r
+                       throw new NullPointerException("System is not configured properly, missing TSM Store.");\r
+               }\r
+               targetUri = tsmStore.getSourceStoreUri(RemoteStoreProtocol.TSM);\r
+               if (targetUri == null) {\r
+                       logger.error(marker, "A TSM rendszer beállítás paraméterei nem elérhetőek.");\r
+                       throw new NullPointerException("System is not configured properly, missing TSM StoreUri.");\r
+               }\r
+               fileType = manager.getFileType("High-res");\r
+               if (fileType == null) {\r
+                       logger.error(marker, "Adatbázis bejegyzés hiba, a 'High-res' FileType nem található.");\r
+                       throw new NullPointerException("System is not configured properly, missing 'High-res' FileType.");\r
+               }\r
+               if (mediaCubeMedia == null) {\r
+                       logger.error(marker, "A folyamat 'mediaCubeMedia' bemeneti paramétere üres.");\r
+                       throw new NullPointerException("System is not configured properly, 'mediaCubeMedia' input parameter missing.");\r
+               }\r
+\r
+       }\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/TSMExtendedRetrieveStep.java b/server/-product/production/HIRTV/jobs/steps/TSMExtendedRetrieveStep.java
new file mode 100644 (file)
index 0000000..8f81dde
--- /dev/null
@@ -0,0 +1,92 @@
+package user.jobengine.server.steps;\r
+\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+\r
+import user.commons.StoreUri;\r
+import user.commons.remotestore.RemoteStoreProtocol;\r
+import user.jobengine.db.ArchivedMedia;\r
+import user.jobengine.db.IItemManager;\r
+import user.jobengine.server.IJobEngine;\r
+import user.jobengine.server.IJobRuntime;\r
+import user.jobengine.server.steps.shared.EscortFiles;\r
+\r
+public class TSMExtendedRetrieveStep extends TSMRestoreStep {\r
+       private static String NEXIO_HOST = System.getProperty("nexio.host");\r
+       //      private static String NEXIO_HOST = SystemConfiguration.getInstance().value("services.nexio.host");\r
+       private static final Logger logger = LogManager.getLogger();\r
+\r
+       private boolean useNexioTarget;\r
+       private int nexioPort;\r
+       private String nexioUserName, nexioPassword;\r
+       private String nexioAgency;\r
+\r
+       @Override\r
+       protected void afterRestore(StoreUri targetUri, String targetPath, int killDateDays, String targetFileName) throws Exception {\r
+               if (useNexioTarget) {\r
+                       EscortFiles.setNEXIOKillDate(killDateDays, targetFileName, nexioAgency, targetUri);\r
+               } else {\r
+                       super.afterRestore(targetUri, targetPath, killDateDays, targetFileName);\r
+               }\r
+       }\r
+\r
+       @Override\r
+       protected void beforeRestore(StoreUri targetURI, String targetName) throws Exception {\r
+               String newTargetName = targetName;\r
+               if (targetName.contains("."))\r
+                       newTargetName = targetName.substring(0, targetName.lastIndexOf('.'));\r
+               if (useNexioTarget)\r
+                       if (targetURI.fileExists(newTargetName + ".mxf"))\r
+                               throw new Exception(String.format("%s-The newly created file name is existed.", getClass().getSimpleName()));\r
+       }\r
+\r
+       @Override\r
+       protected void checkTargetPath(String targetPath) {\r
+               if (!useNexioTarget)\r
+                       super.checkTargetPath(targetPath);\r
+       }\r
+\r
+       @Override\r
+       protected StoreUri createTargetUri(IItemManager manager, String targetPath) throws NullPointerException {\r
+               StoreUri result = null;\r
+               logger.info(getSessionMarker(), "Create target uri {}", targetPath);\r
+               if (useNexioTarget) {\r
+                       if (NEXIO_HOST == null) {\r
+                               throw new NullPointerException("Missing system property on 'nexio.host' name");\r
+                       }\r
+                       result = manager.createStoreUri(RemoteStoreProtocol.FTP, NEXIO_HOST);\r
+                       result.setPortNumber(nexioPort);\r
+                       result.setUserName(nexioUserName);\r
+                       result.setPassword(nexioPassword);\r
+               } else\r
+                       result = super.createTargetUri(manager, targetPath);\r
+               return result;\r
+       }\r
+\r
+       @StepEntry\r
+       public Object[] execute(ArchivedMedia archivedMedia, String targetPath, String targetNamePattern, String successRecipient, int killDateDays,\r
+                       String localRetrievePath, String globalRetrievePath, boolean useNexioTarget, String nexioAgency, int nexioPort, String nexioUserName,\r
+                       String nexioPassword, IJobEngine jobEngine, IJobRuntime jobRuntime) throws Exception {\r
+               this.useNexioTarget = useNexioTarget;\r
+               this.nexioAgency = nexioAgency;\r
+               this.nexioPort = nexioPort;\r
+               this.nexioUserName = nexioUserName;\r
+               this.nexioPassword = nexioPassword;\r
+               if (nexioPort == 0) {\r
+                       throw new NullPointerException("System is not configured properly, 'nexioPort' input parameter missing.");\r
+               }\r
+               if (nexioUserName == null) {\r
+                       throw new NullPointerException("System is not configured properly, 'nexioUserName' input parameter missing.");\r
+               }\r
+               if (nexioPassword == null) {\r
+                       throw new NullPointerException("System is not configured properly, 'nexioPassword' input parameter missing.");\r
+               }\r
+               if (nexioAgency == null) {\r
+                       throw new NullPointerException("System is not configured properly, 'nexioAgency' input parameter missing.");\r
+               }\r
+\r
+               return super.execute(archivedMedia.getMedia(), targetPath, targetNamePattern, successRecipient, killDateDays, localRetrievePath, globalRetrievePath,\r
+                               jobEngine, jobRuntime);\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/TSMRestoreStep.java b/server/-product/production/HIRTV/jobs/steps/TSMRestoreStep.java
new file mode 100644 (file)
index 0000000..af216f4
--- /dev/null
@@ -0,0 +1,193 @@
+package user.jobengine.server.steps;\r
+\r
+import java.io.IOException;\r
+import java.nio.file.Path;\r
+import java.nio.file.Paths;\r
+import java.text.Normalizer;\r
+import java.util.List;\r
+import java.util.regex.Pattern;\r
+\r
+import org.apache.commons.lang.StringUtils;\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+import org.apache.logging.log4j.Marker;\r
+import org.apache.logging.log4j.message.Message;\r
+\r
+import user.commons.LogUtils;\r
+import user.commons.RemoteFile;\r
+import user.commons.StoreUri;\r
+import user.commons.mediatool.Timecode;\r
+import user.commons.mediatool.Timecode.Type;\r
+import user.commons.remotestore.IProgressEventListener;\r
+import user.commons.remotestore.IStatusEventListener;\r
+import user.commons.remotestore.ProgressEvent;\r
+import user.commons.remotestore.RemoteStoreProtocol;\r
+import user.commons.remotestore.StatusEvent;\r
+import user.jobengine.db.IItemManager;\r
+import user.jobengine.db.Media;\r
+import user.jobengine.db.MediaFile;\r
+import user.jobengine.db.Store;\r
+import user.jobengine.server.IJobEngine;\r
+import user.jobengine.server.IJobRuntime;\r
+import user.jobengine.server.steps.shared.EscortFiles;\r
+import user.jobengine.server.steps.shared.MetadataSaver;\r
+\r
+public class TSMRestoreStep extends JobStep {\r
+       private static final String DOT = ".";\r
+       public static final Pattern DIACRITICS_AND_FRIENDS = Pattern.compile("[\\p{InCombiningDiacriticalMarks}\\p{IsLm}\\p{IsSk}]+");\r
+       private static final Logger logger = LogManager.getLogger();\r
+       private IItemManager manager;\r
+       private StoreUri targetUri;\r
+       private StoreUri sourceUri;\r
+       private String sourceFileName;\r
+       private Marker marker;\r
+\r
+       protected void afterRestore(StoreUri targetUri, String targetPath, int killDateDays, String targetFileName) throws IOException, Exception {\r
+               if (killDateDays != 0)\r
+                       EscortFiles.createUNCKillDate(targetPath, targetFileName, killDateDays, marker);\r
+\r
+               if (RemoteStoreProtocol.LOCAL.equals(targetUri.getProtocol())) {\r
+                       Path path = Paths.get(targetPath, targetFileName);\r
+                       MetadataSaver.saveMetadata(path.toString());\r
+               }\r
+\r
+       }\r
+\r
+       protected void beforeRestore(StoreUri targetURI, String targetFileName) throws Exception {\r
+       }\r
+\r
+       protected void checkTargetPath(String targetPath) {\r
+               if (StringUtils.isBlank(targetPath)) {\r
+                       logger.error(marker, "A folyamat 'targetPath' bemeneti paramétere üres.");\r
+                       throw new NullPointerException("System is not configured properly, 'targetPath' input parameter missing.");\r
+               }\r
+       }\r
+\r
+       protected StoreUri createTargetUri(IItemManager manager, String targetPath) {\r
+               return manager.createStoreUri(RemoteStoreProtocol.LOCAL, targetPath);\r
+       }\r
+\r
+       @StepEntry\r
+       public Object[] execute(Media mediaCubeMedia, String targetPath, String targetNamePattern, String successRecipient, int killDateDays,\r
+                       String localRetrievePath, String globalRetrievePath, IJobEngine jobEngine, IJobRuntime jobRuntime) throws Exception {\r
+               marker = jobRuntime.getSessionMarker();\r
+               setAndCheck(mediaCubeMedia, targetPath, targetNamePattern, localRetrievePath, globalRetrievePath, jobEngine);\r
+               String targetFileName = String.format(targetNamePattern, sourceFileName);\r
+               // 20210129\r
+               // targetFileName = getMaximizedFileName(mediaCubeMedia, targetFileName, 120);\r
+\r
+               Timecode timecode = new Timecode(mediaCubeMedia.getLength(), Type.PAL);\r
+               try {\r
+                       String details = String.format("%s (%s)", sourceFileName, timecode.toString());\r
+                       jobRuntime.setDescription(details);\r
+                       beforeRestore(targetUri, targetNamePattern);\r
+                       final IJobRuntime runtime = jobRuntime;\r
+                       sourceUri.addProgressListener(new IProgressEventListener() {\r
+                               @Override\r
+                               public void progressChanged(ProgressEvent evt) {\r
+                                       runtime.incrementProgress(evt.getProgress());\r
+                               }\r
+                       });\r
+                       sourceUri.addStatusListener(new IStatusEventListener() {\r
+                               @Override\r
+                               public void statusChanged(StatusEvent evt) {\r
+                                       evt.setCancel(!canContinue());\r
+                               }\r
+                       });\r
+                       RemoteFile result = sourceUri.transferFrom(targetUri, sourceFileName, targetFileName);\r
+\r
+                       String globalTargetPath = Paths.get(targetPath, targetFileName).getParent().toString().replace(Paths.get(localRetrievePath).toString(),\r
+                                       globalRetrievePath);\r
+\r
+                       logger.info(marker,\r
+                                       "Az '{}' állomány visszatöltése sikeres volt '{}' néven. A célmappa a <a href='{}' target='_blank'>ide kattintva</a> nyitható meg.",\r
+                                       sourceFileName, targetFileName, globalTargetPath);\r
+                       afterRestore(targetUri, targetPath, killDateDays, targetFileName);\r
+\r
+               } catch (Exception e) {\r
+                       Message msg = LogUtils.format("Az '{}' állomány visszatöltése sikertelen. A rendszer hibaüzenete: {}", sourceFileName, e.getMessage());\r
+                       logger.error(marker, msg);\r
+                       // logger.error(jobRuntime.marker, msg);\r
+                       logger.catching(e);\r
+                       throw e;\r
+               }\r
+\r
+               return null;\r
+       }\r
+\r
+       private String getMaximizedFileName(Media mediaCubeMedia, String targetFileName, int limit) {\r
+               String name = targetFileName;\r
+               String extension = "";\r
+               if (name.contains(DOT)) {\r
+                       extension = DOT + name.substring(name.lastIndexOf(DOT) + 1);\r
+                       name = name.substring(0, name.lastIndexOf(DOT));\r
+               }\r
+               String typeName = Normalizer.normalize(mediaCubeMedia.getItemType().getName(), Normalizer.Form.NFD);\r
+               typeName = DIACRITICS_AND_FRIENDS.matcher(typeName).replaceAll("");\r
+               typeName = typeName.replace(" ", "_");\r
+\r
+               int allowedSize = limit - typeName.length() - 1 - extension.length();\r
+               if (name.length() > allowedSize)\r
+                       name = name.substring(0, allowedSize);\r
+\r
+               return String.format("%s_%s%s", name, typeName, extension);\r
+       }\r
+\r
+       private String getSourceFileName(Media mediaCubeMedia, Store store) {\r
+               List<MediaFile> mediaFiles = mediaCubeMedia.getMediaFiles();\r
+               if (mediaFiles == null)\r
+                       return null;\r
+               for (MediaFile mediaFile : mediaFiles) {\r
+                       if (mediaFile.getStore().getId() == store.getId())\r
+                               return mediaFile.getRelativePath();\r
+               }\r
+               return null;\r
+       }\r
+\r
+       private void setAndCheck(Media mediaCubeMedia, String targetPath, String targetNamePattern, String localRetrievePath, String globalRetrievePath,\r
+                       IJobEngine jobEngine) {\r
+               if (jobEngine == null) {\r
+                       logger.error(marker, "Az folyamatkezelő réteg nem elérhető.");\r
+                       throw new NullPointerException("Internal error, missing JobEngine reference.");\r
+               }\r
+               manager = jobEngine.getItemManager();\r
+               if (manager == null) {\r
+                       logger.error(marker, "Az adatbáziskezelő réteg nem elérhető.");\r
+                       throw new NullPointerException("Internal error, missing ItemManager reference.");\r
+               }\r
+               if (mediaCubeMedia == null) {\r
+                       logger.error(marker, "A folyamat 'mediaCubeMedia' bemeneti paramétere üres.");\r
+                       throw new NullPointerException("System is not configured properly, 'mediaCubeMedia' input parameter missing.");\r
+               }\r
+               checkTargetPath(targetPath);\r
+               if (StringUtils.isBlank(targetNamePattern)) {\r
+                       logger.error(marker, "A folyamat 'targetNamePattern' bemeneti paramétere üres.");\r
+                       throw new NullPointerException("System is not configured properly, 'targetNamePattern' input parameter missing.");\r
+               }\r
+               Store tsmStore = manager.getSystemStore(false);\r
+               if (tsmStore == null) {\r
+                       logger.error(marker, "A TSM rendszer beállítás nem elérhető.");\r
+                       throw new NullPointerException("System is not configured properly, missing TSM Store.");\r
+               }\r
+               sourceUri = tsmStore.getSourceStoreUri(RemoteStoreProtocol.TSM);\r
+               if (sourceUri == null) {\r
+                       logger.error(marker, "A TSM rendszer beállítás paraméterei nem elérhetőek.");\r
+                       throw new NullPointerException("System is not configured properly, missing TSM StoreUri.");\r
+               }\r
+               targetUri = createTargetUri(manager, targetPath);\r
+               sourceFileName = getSourceFileName(mediaCubeMedia, tsmStore);\r
+               if (sourceFileName == null) {\r
+                       logger.error(marker, "Adatbázis bejegyzés hiba, a visszatöltendő fájl neve nem található.");\r
+                       throw new NullPointerException("Database error, missing MediaFile 'relativePath'.");\r
+               }\r
+\r
+               if (StringUtils.isBlank(localRetrievePath)) {\r
+                       logger.error(marker, "A folyamat 'localRetrievePath' bemeneti paramétere üres.");\r
+                       throw new NullPointerException("System is not configured properly, 'localRetrievePath' input parameter missing.");\r
+               }\r
+               if (StringUtils.isBlank(globalRetrievePath)) {\r
+                       logger.error(marker, "A folyamat 'globalRetrievePath' bemeneti paramétere üres.");\r
+                       throw new NullPointerException("System is not configured properly, 'globalRetrievePath' input parameter missing.");\r
+               }\r
+       }\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/TSMRetrieveMissingMaterialStep.java b/server/-product/production/HIRTV/jobs/steps/TSMRetrieveMissingMaterialStep.java
new file mode 100644 (file)
index 0000000..4f6e6dc
--- /dev/null
@@ -0,0 +1,45 @@
+package user.jobengine.server.steps;\r
+\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+\r
+import com.ibm.nosql.json.api.BasicDBObject;\r
+import com.ibm.nosql.json.api.DB;\r
+import com.ibm.nosql.json.api.DBCollection;\r
+\r
+import user.commons.morpheus.MorpheusStrings;\r
+import user.commons.nosql.NoSQLUtils;\r
+import user.jobengine.db.IItemManager;\r
+import user.jobengine.db.Media;\r
+import user.jobengine.server.IJobEngine;\r
+import user.jobengine.server.IJobRuntime;\r
+\r
+public class TSMRetrieveMissingMaterialStep extends TSMRestoreStep {\r
+       private static final String TARGETNAMEPATTERN = "%s";\r
+       private static final Logger logger = LogManager.getLogger();\r
+\r
+       @StepEntry\r
+       public Object[] execute(BasicDBObject material, String targetPath, String globalRetrievePath, IJobEngine jobEngine, IJobRuntime jobRuntime)\r
+                       throws Exception {\r
+               try {\r
+                       IItemManager itemManager = jobEngine.getItemManager();\r
+                       Media mediaCubeMedia = itemManager.getMedia(material.getLong(MorpheusStrings.MEDIAID));\r
+\r
+                       super.execute(mediaCubeMedia, targetPath, TARGETNAMEPATTERN, null, 0, targetPath, globalRetrievePath, jobEngine, jobRuntime);\r
+                       saveMaterial(material, MorpheusStrings.STATUS_DONE);\r
+               } catch (Exception e) {\r
+                       saveMaterial(material, MorpheusStrings.STATUS_ERROR);\r
+                       logger.catching(e);\r
+                       throw e;\r
+               }\r
+               return null;\r
+       }\r
+\r
+       private void saveMaterial(BasicDBObject material, String status) throws Exception {\r
+               DB db = NoSQLUtils.getNoSQLDB();\r
+               DBCollection collection = db.getCollection(MorpheusStrings.COLLECTION_NAME);\r
+               material.put(MorpheusStrings.STATUS, MorpheusStrings.STATUS_DONE);\r
+               collection.save(material);\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/TSMSystemRestoreStep.java b/server/-product/production/HIRTV/jobs/steps/TSMSystemRestoreStep.java
new file mode 100644 (file)
index 0000000..e85b927
--- /dev/null
@@ -0,0 +1,151 @@
+package user.jobengine.server.steps;\r
+\r
+import java.io.IOException;\r
+import java.nio.file.Path;\r
+import java.nio.file.Paths;\r
+import java.util.List;\r
+\r
+import org.apache.commons.lang.StringUtils;\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+import org.apache.logging.log4j.Marker;\r
+import org.apache.logging.log4j.message.Message;\r
+\r
+import user.commons.LogUtils;\r
+import user.commons.RemoteFile;\r
+import user.commons.StoreUri;\r
+import user.commons.log4j2.marker.MediaCubeMarker;\r
+import user.commons.remotestore.IProgressEventListener;\r
+import user.commons.remotestore.IStatusEventListener;\r
+import user.commons.remotestore.ProgressEvent;\r
+import user.commons.remotestore.RemoteStoreProtocol;\r
+import user.commons.remotestore.StatusEvent;\r
+import user.jobengine.db.IItemManager;\r
+import user.jobengine.db.Media;\r
+import user.jobengine.db.MediaFile;\r
+import user.jobengine.db.Store;\r
+import user.jobengine.server.IJobEngine;\r
+import user.jobengine.server.IJobRuntime;\r
+import user.jobengine.server.steps.shared.EscortFiles;\r
+import user.jobengine.server.steps.shared.MetadataSaver;\r
+\r
+public class TSMSystemRestoreStep extends JobStep {\r
+       private static final Logger logger = LogManager.getLogger();\r
+       private IItemManager manager;\r
+       private StoreUri targetUri;\r
+       private StoreUri sourceUri;\r
+       private String sourceFileName;\r
+       private Marker marker;\r
+\r
+       protected void afterRestore(StoreUri targetUri, String targetPath, int killDateDays, String targetFileName) throws IOException, Exception {\r
+               if (killDateDays > 0)\r
+                       EscortFiles.createUNCKillDate(targetPath, targetFileName, killDateDays, marker);\r
+               if (RemoteStoreProtocol.LOCAL.equals(targetUri.getProtocol())) {\r
+                       Path path = Paths.get(targetPath, targetFileName);\r
+                       MetadataSaver.saveMetadata(path.toString());\r
+               }\r
+       }\r
+\r
+       protected void beforeRestore(StoreUri targetURI, String targetFileName) throws Exception {\r
+       }\r
+\r
+       protected void checkTargetPath(String targetPath) {\r
+               if (StringUtils.isBlank(targetPath)) {\r
+                       logger.error(marker, "A folyamat 'targetPath' bemeneti paramétere üres.");\r
+                       throw new NullPointerException("System is not configured properly, 'targetPath' input parameter missing.");\r
+               }\r
+       }\r
+\r
+       protected StoreUri createTargetUri(IItemManager manager, String targetPath) {\r
+               return manager.createStoreUri(RemoteStoreProtocol.LOCAL, targetPath);\r
+       }\r
+\r
+       @StepEntry\r
+       public Object[] execute(Media mediaCubeMedia, String targetPath, String targetNamePattern, String successRecipient, int killDateDays, IJobEngine jobEngine,\r
+                       IJobRuntime jobRuntime) throws Exception {\r
+               marker = jobRuntime.getSessionMarker();\r
+               setAndCheck(mediaCubeMedia, targetPath, targetNamePattern, jobEngine);\r
+               String targetFileName = String.format(targetNamePattern, sourceFileName);\r
+               try {\r
+                       beforeRestore(targetUri, targetNamePattern);\r
+                       final IJobRuntime runtime = jobRuntime;\r
+                       sourceUri.addProgressListener(new IProgressEventListener() {\r
+                               @Override\r
+                               public void progressChanged(ProgressEvent evt) {\r
+                                       runtime.incrementProgress(evt.getProgress());\r
+                               }\r
+                       });\r
+                       sourceUri.addStatusListener(new IStatusEventListener() {\r
+                               @Override\r
+                               public void statusChanged(StatusEvent evt) {\r
+                                       evt.setCancel(!canContinue());\r
+                               }\r
+                       });\r
+                       RemoteFile result = sourceUri.transferFrom(targetUri, sourceFileName, targetFileName);\r
+\r
+                       Message msg = LogUtils.format("Az '{}' állomány visszatöltése sikeres volt '{}' néven. ", sourceFileName, targetFileName);\r
+                       if (StringUtils.isNotBlank(successRecipient))\r
+                               logger.info(new MediaCubeMarker(successRecipient), msg);\r
+                       logger.info(marker, msg);\r
+                       afterRestore(targetUri, targetPath, killDateDays, targetFileName);\r
+\r
+               } catch (Exception e) {\r
+                       Message msg = LogUtils.format("Az '{}' állomány visszatöltése sikertelen. A rendszer hibaüzenete: {}", sourceFileName, e.getMessage());\r
+                       logger.error(marker, msg);\r
+                       // logger.error(jobRuntime.marker, msg);\r
+                       logger.catching(e);\r
+                       throw e;\r
+               }\r
+\r
+               return null;\r
+       }\r
+\r
+       private String getSourceFileName(Media mediaCubeMedia, Store store) {\r
+               List<MediaFile> mediaFiles = mediaCubeMedia.getMediaFiles();\r
+               if (mediaFiles == null)\r
+                       return null;\r
+               for (MediaFile mediaFile : mediaFiles) {\r
+                       if (mediaFile.getStore().getId() == store.getId())\r
+                               return mediaFile.getRelativePath();\r
+               }\r
+               return null;\r
+       }\r
+\r
+       private void setAndCheck(Media mediaCubeMedia, String targetPath, String targetNamePattern, IJobEngine jobEngine) {\r
+               if (jobEngine == null) {\r
+                       logger.error(marker, "Az folyamatkezelő réteg nem elérhető.");\r
+                       throw new NullPointerException("Internal error, missing JobEngine reference.");\r
+               }\r
+               manager = jobEngine.getItemManager();\r
+               if (manager == null) {\r
+                       logger.error(marker, "Az adatbáziskezelő réteg nem elérhető.");\r
+                       throw new NullPointerException("Internal error, missing ItemManager reference.");\r
+               }\r
+               if (mediaCubeMedia == null) {\r
+                       logger.error(marker, "A folyamat 'mediaCubeMedia' bemeneti paramétere üres.");\r
+                       throw new NullPointerException("System is not configured properly, 'mediaCubeMedia' input parameter missing.");\r
+               }\r
+               checkTargetPath(targetPath);\r
+               if (StringUtils.isBlank(targetNamePattern)) {\r
+                       logger.error(marker, "A folyamat 'targetNamePattern' bemeneti paramétere üres.");\r
+                       throw new NullPointerException("System is not configured properly, 'targetNamePattern' input parameter missing.");\r
+               }\r
+               Store tsmStore = manager.getSystemStore(false);\r
+               if (tsmStore == null) {\r
+                       logger.error(marker, "A TSM rendszer beállítás nem elérhető.");\r
+                       throw new NullPointerException("System is not configured properly, missing TSM Store.");\r
+               }\r
+               sourceUri = tsmStore.getSourceStoreUri(RemoteStoreProtocol.TSM);\r
+               if (sourceUri == null) {\r
+                       logger.error(marker, "A TSM rendszer beállítás paraméterei nem elérhetőek.");\r
+                       throw new NullPointerException("System is not configured properly, missing TSM StoreUri.");\r
+               }\r
+               targetUri = createTargetUri(manager, targetPath);\r
+               sourceFileName = getSourceFileName(mediaCubeMedia, tsmStore);\r
+               if (sourceFileName == null) {\r
+                       logger.error(marker, "Adatbázis bejegyzés hiba, a visszatöltendő fájl neve nem található.");\r
+                       throw new NullPointerException("Database error, missing MediaFile 'relativePath'.");\r
+               }\r
+\r
+       }\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/TranscodeFFAStranStep.java b/server/-product/production/HIRTV/jobs/steps/TranscodeFFAStranStep.java
new file mode 100644 (file)
index 0000000..99ca174
--- /dev/null
@@ -0,0 +1,157 @@
+package user.jobengine.server.steps;\r
+\r
+import java.io.File;\r
+import java.io.IOException;\r
+import java.nio.file.Files;\r
+import java.nio.file.Path;\r
+import java.nio.file.Paths;\r
+\r
+import org.apache.commons.io.FilenameUtils;\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+import org.apache.logging.log4j.Marker;\r
+import org.apache.logging.log4j.message.Message;\r
+import org.apache.logging.log4j.message.ParameterizedMessage;\r
+\r
+import user.commons.FFAStransAPI;\r
+import user.commons.IFFAStransAPI;\r
+import user.commons.StoreUri;\r
+import user.commons.mediatool.Timecode;\r
+import user.commons.mediatool.Timecode.Type;\r
+import user.commons.remotestore.RemoteStoreProtocol;\r
+import user.jobengine.db.FileType;\r
+import user.jobengine.db.IItemManager;\r
+import user.jobengine.db.Media;\r
+import user.jobengine.db.Store;\r
+import user.jobengine.server.IJobEngine;\r
+import user.jobengine.server.IJobRuntime;\r
+import user.jobengine.server.steps.shared.EscortFiles;\r
+\r
+public class TranscodeFFAStranStep extends JobStep {\r
+       private static final int POLL_INTERVALL = 3000;\r
+       private static final String MP4EXT = ".MP4";\r
+       private static final String MXFEXT = ".MXF";\r
+       private static final String LOWRES_FILETYPE = "Low-res";\r
+       private static final Logger logger = LogManager.getLogger("TranscodeFFAStranStep");\r
+       private IItemManager manager;\r
+       private Store store;\r
+       private FileType fileType;\r
+       private Media mediaCubeMedia;\r
+       private Marker marker;\r
+\r
+       @StepEntry\r
+       public Object[] execute(ArchiveItem archiveItem, Media mediaCubeMedia, String transcoderAddress,\r
+                       String transcoderTemplateName, String globalHiresSourcePath, String localLowresTargetPath,\r
+                       boolean deleteSource, IJobEngine jobEngine, IJobRuntime jobRuntime) throws Exception {\r
+\r
+               this.marker = jobRuntime.getSessionMarker();\r
+               this.manager = jobEngine.getItemManager();\r
+               this.store = check(manager.getCurrentLowresStore(), "lowres Store");\r
+               this.fileType = check(manager.getFileType(LOWRES_FILETYPE), "lowres FileType");\r
+               this.mediaCubeMedia = check(mediaCubeMedia, "mediaCubeMedia");\r
+               check(archiveItem, "archiveItem");\r
+               check(transcoderAddress, "transcoderAddress");\r
+               check(transcoderTemplateName, "transcoderTemplateName");\r
+               check(globalHiresSourcePath, "globalHiresSourcePath");\r
+               check(localLowresTargetPath, "localLowresTargetPath");\r
+\r
+               File sourceMediaFile = new File(archiveItem.getMediaFile());\r
+               logger.info("Transcoding {}", archiveItem.getMediaFile());\r
+               String sourceFileName = sourceMediaFile.getName();\r
+               Timecode timecode = new Timecode(mediaCubeMedia.getLength(), Type.PAL);\r
+\r
+               String details = String.format("%s (%s, %d bytes)", sourceFileName, timecode.toString(),\r
+                               sourceMediaFile.length());\r
+\r
+               StoreUri storeUri = store.getTargetStoreUri(RemoteStoreProtocol.LOCAL);\r
+               if (storeUri == null)\r
+                       throw new Exception("Can not detect proxy folder.");\r
+\r
+               String webPath = storeUri.toString(true);\r
+\r
+               Path targetPath = null;\r
+               try {\r
+                       String targetFileName = FilenameUtils.removeExtension(sourceFileName) + MP4EXT;\r
+                       targetPath = Paths.get(localLowresTargetPath, targetFileName);\r
+                       if (!targetPath.toFile().exists()) {\r
+                               // jobRuntime.setDescription(String.format("%s: %s",\r
+                               // jobRuntime.getDescription(), details));\r
+                               jobRuntime.setDescription(String.format("%s transzkódolása", details));\r
+                               String sourceFile = Paths.get(globalHiresSourcePath, sourceFileName).toString();\r
+                               IFFAStransAPI api = new FFAStransAPI(transcoderAddress, p -> {\r
+                                       if (p <= 100)\r
+                                               jobRuntime.incrementProgress(p);\r
+                               });\r
+\r
+                               api.submit(transcoderTemplateName, sourceFile);\r
+                               api.monitor(POLL_INTERVALL);\r
+                       }\r
+\r
+                       // a sikeres transzkod utan nem mindig van ott egybol a fajl\r
+                       long started = System.currentTimeMillis();\r
+                       while (!targetPath.toFile().exists()) {\r
+                               long current = System.currentTimeMillis();\r
+                               // max 5 perc varakozas\r
+                               if (current - started > 5 * 60 * 1000)\r
+                                       throw new Exception("Transcode job target file access timed out");\r
+                               Thread.sleep(POLL_INTERVALL);\r
+                       }\r
+\r
+                       postprocess(targetPath, webPath);\r
+\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       Message m = new ParameterizedMessage("{} átkódolás hiba: {}", sourceFileName, e.getMessage());\r
+                       logger.error(marker, m);\r
+                       throw new Exception(m.getFormattedMessage());\r
+               } finally {\r
+                       try {\r
+                               if (deleteSource && sourceMediaFile != null && sourceMediaFile.exists())\r
+                                       sourceMediaFile.delete();\r
+                       } catch (Exception e) {\r
+                               logger.catching(e);\r
+                       }\r
+                       try {\r
+                               if (deleteSource && targetPath != null && targetPath.toFile().exists())\r
+                                       Files.delete(targetPath);\r
+                       } catch (Exception e) {\r
+                               logger.catching(e);\r
+                       }\r
+               }\r
+               return null;\r
+       }\r
+\r
+       private void postprocess(Path transcodedFilePath, String webPath) throws IOException {\r
+               Path lowresPath = null;\r
+               try {\r
+                       String transcodedFileName = transcodedFilePath.getFileName().toString();\r
+                       String targetPath = null;\r
+                       if (transcodedFileName.indexOf(".") > 2) {\r
+                               Path subdir = Paths.get(transcodedFileName.substring(0, 1), transcodedFileName.substring(1, 2),\r
+                                               transcodedFileName.substring(2, 3));\r
+                               EscortFiles.ensureUNCFolder(webPath, subdir.toString());\r
+                               targetPath = Paths.get(subdir.toString(), transcodedFileName).toString();\r
+                       } else {\r
+                               targetPath = transcodedFileName;\r
+                       }\r
+                       lowresPath = Paths.get(webPath, targetPath);\r
+                       int version = 1;\r
+                       while (lowresPath.toFile().exists()) {\r
+                               String fileName = transcodedFileName + version + MP4EXT;\r
+                               lowresPath = Paths.get(lowresPath.toString().replace(transcodedFileName, fileName));\r
+                               targetPath = targetPath.replace(transcodedFileName, fileName);\r
+                               transcodedFileName = fileName;\r
+                               version++;\r
+                       }\r
+\r
+                       Files.move(transcodedFilePath, lowresPath);\r
+                       manager.createMediaFile(targetPath, fileType, store, mediaCubeMedia).add();\r
+               } catch (IOException e) {\r
+                       logger.catching(e);\r
+                       logger.error(marker, "A(z) '{}' állomány mozgatása a '{}' helyre nem sikerült.", transcodedFilePath,\r
+                                       lowresPath);\r
+                       throw e;\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/TranscodeSELENIOStep.java b/server/-product/production/HIRTV/jobs/steps/TranscodeSELENIOStep.java
new file mode 100644 (file)
index 0000000..ebe2ce9
--- /dev/null
@@ -0,0 +1,243 @@
+package user.jobengine.server.steps;\r
+\r
+import java.io.File;\r
+import java.net.URL;\r
+import java.nio.file.Files;\r
+import java.nio.file.Path;\r
+import java.nio.file.Paths;\r
+import java.nio.file.StandardCopyOption;\r
+import java.util.Arrays;\r
+import java.util.List;\r
+\r
+import javax.xml.namespace.QName;\r
+\r
+import org.apache.commons.lang.StringUtils;\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+import org.apache.logging.log4j.Marker;\r
+import org.apache.logging.log4j.message.Message;\r
+import org.apache.logging.log4j.message.ParameterizedMessage;\r
+\r
+import user.commons.StoreUri;\r
+import user.commons.configuration.SystemConfiguration;\r
+import user.commons.remotestore.RemoteStoreProtocol;\r
+import user.commons.selenio.wsclient.AudioSource;\r
+import user.commons.selenio.wsclient.Clip;\r
+import user.commons.selenio.wsclient.ClipList;\r
+import user.commons.selenio.wsclient.Exception_Exception;\r
+import user.commons.selenio.wsclient.FileSnapshot;\r
+import user.commons.selenio.wsclient.MediaFile;\r
+import user.commons.selenio.wsclient.State;\r
+import user.commons.selenio.wsclient.TranscodeMgrWS;\r
+import user.commons.selenio.wsclient.TranscodeMgrWSService;\r
+import user.commons.selenio.wsclient.TranscodeRequest;\r
+import user.commons.selenio.wsclient.TranscodeSource;\r
+import user.commons.selenio.wsclient.TranscodeTask;\r
+import user.commons.selenio.wsclient.TranscodeTask.OutputFiles;\r
+import user.commons.selenio.wsclient.VideoSource;\r
+import user.jobengine.db.FileType;\r
+import user.jobengine.db.IItemManager;\r
+import user.jobengine.db.Media;\r
+import user.jobengine.db.Store;\r
+import user.jobengine.server.IJobEngine;\r
+import user.jobengine.server.IJobRuntime;\r
+import user.jobengine.server.steps.shared.EscortFiles;\r
+import user.jobengine.server.steps.shared.ItemManagerExtensions;\r
+\r
+public class TranscodeSELENIOStep extends JobStep {\r
+\r
+       private static final String MXFEXT = ".MXF";\r
+       private static final String LOWRES_FILETYPE = "Low-res";\r
+       private static final Logger logger = LogManager.getLogger();\r
+       private static String SELENIO_API_ADDRESS = SystemConfiguration.getInstance().value("services.selnio.api.address",\r
+                       "http://10.10.1.71:44000/TranscodeMgrWS?wsdl");\r
+       private static String SELENIO_API_PROJECTFILE = SystemConfiguration.getInstance().value("services.selnio.api.projevt-file",\r
+                       "\\\\10.10.1.71\\Data\\Blueprints\\MP4_H264_AAC.zenium");\r
+       private final List<State> showStoppers = Arrays.asList(State.CANCELLED, State.COMPLETE, State.FAILED);\r
+       private TranscodeMgrWS transcoder = null;\r
+       private IItemManager manager;\r
+       private Store store;\r
+       private FileType fileType;\r
+       private String transcoderTargetPath;\r
+       private Marker marker;\r
+       private StoreUri storeUri;\r
+\r
+       private TranscodeRequest buildTranscodeRequest(String projectFilePath, String sourceFilePath) throws java.lang.Exception {\r
+               Clip clip = new Clip();\r
+               MediaFile mediaFile = new MediaFile();\r
+               mediaFile.setFile(sourceFilePath);\r
+               AudioSource audioSource = new AudioSource();\r
+               audioSource.setMediaFile(mediaFile);\r
+               clip.getAudioSource().add(audioSource);\r
+\r
+               VideoSource videoSource = new VideoSource();\r
+               videoSource.setMediaFile(mediaFile);\r
+               clip.setVideoSource(videoSource);\r
+\r
+               ClipList clipList = new ClipList();\r
+               clipList.getClip().add(clip);\r
+\r
+               TranscodeSource transcodeSource = new TranscodeSource();\r
+               transcodeSource.setClipList(clipList);\r
+\r
+               TranscodeRequest transcodeRequest = new TranscodeRequest();\r
+               FileSnapshot project = new FileSnapshot();\r
+               project.setFullPath(projectFilePath);\r
+               transcodeRequest.setProject(project);\r
+               transcodeRequest.setTranscodeSource(transcodeSource);\r
+\r
+               //              TranscodeDestination transcodeDestination = new TranscodeDestination();\r
+\r
+               //transcodeDestination.setOutputWriteDirectory(outputPath);\r
+               //              transcodeDestination.setOutputPostMoveDirectory(targetPath);\r
+               //              transcodeRequest.setTranscodeDestination(transcodeDestination);\r
+               return transcodeRequest;\r
+       }\r
+\r
+       @StepEntry\r
+       public Object[] execute(String globalSourcePath, ArchiveItem archiveItem, Media mediaCubeMedia, String transcoderTargetPath, IJobEngine jobEngine,\r
+                       IJobRuntime jobRuntime) throws Exception {\r
+               marker = jobRuntime.getSessionMarker();\r
+               String sourceFileName = null;\r
+\r
+               try {\r
+                       setAndCheck(globalSourcePath, transcoderTargetPath, jobEngine);\r
+\r
+                       File sourceMediaFile = new File(archiveItem.getMediaFile());\r
+                       sourceFileName = sourceMediaFile.getName();\r
+\r
+                       //Nincs mit transzkodolni, a TSMBackupStep csinal masolatot a mediafileokrol\r
+                       //A dupla ellenorzes a napon beluli ismetlesek miatt kell\r
+                       long existingMediaId = archiveItem.getExistingMediaId();\r
+                       if (existingMediaId == 0)\r
+                               existingMediaId = ItemManagerExtensions.getExistingRundownMedia(manager, sourceFileName.replace(MXFEXT, ""));\r
+                       if (existingMediaId != 0 || sourceMediaFile.length() == 0)\r
+                               return null;\r
+\r
+                       String details = String.format("%s (%d bytes)", sourceFileName, sourceMediaFile.length());\r
+\r
+                       Path inputPath = Paths.get(globalSourcePath, sourceFileName);\r
+                       String sourceFilePath = inputPath.toString();\r
+                       TranscodeRequest transcodeRequest = buildTranscodeRequest(SELENIO_API_PROJECTFILE, sourceFilePath);\r
+                       TranscodeTask transcodeTask = transcoder.submitTranscodeTask(transcodeRequest);\r
+\r
+                       if (transcodeTask == null)\r
+                               throw new NullPointerException("Unable to submit transcode task, server response is empty for transcode input: " + sourceFilePath);\r
+\r
+                       jobRuntime.setDescription(String.format("%s: %s", jobRuntime.getDescription(), details));\r
+\r
+                       transcodeTask = monitor(jobRuntime, sourceFilePath, transcodeTask);\r
+                       jobRuntime.incrementProgress(100);\r
+                       processState(transcodeTask, jobEngine, mediaCubeMedia);\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       Message m = new ParameterizedMessage("Az '{}' állomány átkódolása sikertelen. A rendszer hibaüzenete: {}", sourceFileName, e.getMessage());\r
+                       logger.error(marker, m);\r
+                       throw new Exception(m.getFormattedMessage());\r
+               }\r
+               return null;\r
+       }\r
+\r
+       private TranscodeTask monitor(IJobRuntime jobRuntime, String sourceFile, TranscodeTask transcodeTask) throws Exception_Exception, InterruptedException {\r
+               while (true) {\r
+                       transcodeTask = transcoder.getTranscodeTask(transcodeTask.getId());\r
+                       if (transcodeTask == null)\r
+                               throw new NullPointerException("Unable to query transcode task, server response is empty for transcode input: " + sourceFile);\r
+\r
+                       //                      Integer estimate = transcodeTask.getEstimateSecondsRemaining();\r
+                       //                      if (estimate != null)\r
+                       //                              logger.info("Estimate {}", estimate);\r
+                       Double progress = transcodeTask.getProgress();\r
+                       if (progress != null)\r
+                               jobRuntime.incrementProgress((int) Math.round(progress * 100));\r
+\r
+                       if (showStoppers.contains(transcodeTask.getState()))\r
+                               break;\r
+\r
+                       Thread.sleep(2000);\r
+               }\r
+               return transcodeTask;\r
+       }\r
+\r
+       private void onTranscodeComplete(TranscodeTask transcodeTask, IJobEngine jobEngine, Media mediaCubeMedia) {\r
+               OutputFiles of = transcodeTask.getOutputFiles();\r
+               List<user.commons.selenio.wsclient.MediaFile> outputs = of.getOutputFiles();\r
+\r
+               String outFile = null;\r
+               if (outputs.size() == 0) {\r
+                       throw new IndexOutOfBoundsException("There are 0 file in the response: " + transcodeTask.getId());\r
+               } else {\r
+                       for (int i = 0; i < outputs.size(); i++) {\r
+                               user.commons.selenio.wsclient.MediaFile selenioMediaFile = outputs.get(0);\r
+                               if (outFile != null && !outFile.equals(selenioMediaFile.getFile()))\r
+                                       throw new IndexOutOfBoundsException("There are different files in the response: " + transcodeTask.getId());\r
+                               outFile = selenioMediaFile.getFile();\r
+                       }\r
+               }\r
+\r
+               String webPath = null;\r
+               try {\r
+                       webPath = storeUri.toString(true);\r
+                       outFile = outFile.substring(outFile.lastIndexOf("\\") + 1);\r
+                       if (outFile.indexOf(".") > 2) {\r
+                               Path subdir = Paths.get(outFile.substring(0, 1), outFile.substring(1, 2), outFile.substring(2, 3));\r
+                               manager.createMediaFile(Paths.get(subdir.toString(), outFile).toString(), fileType, store, mediaCubeMedia).add();\r
+                               EscortFiles.ensureUNCFolder(webPath, subdir.toString());\r
+                               subdir = Paths.get(webPath, subdir.toString());\r
+                               //subdir.toFile().mkdirs();\r
+                               Files.move(Paths.get(transcoderTargetPath, outFile), Paths.get(subdir.toString(), outFile), StandardCopyOption.REPLACE_EXISTING);\r
+                       } else {\r
+                               manager.createMediaFile(outFile, fileType, store, mediaCubeMedia).add();\r
+                               Files.move(Paths.get(transcoderTargetPath, outFile), Paths.get(webPath, outFile), StandardCopyOption.REPLACE_EXISTING);\r
+                       }\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       logger.error(marker, "Az '{}' állomány mozgatása a '{}' mappába nem sikerült.", outFile, webPath);\r
+               }\r
+       }\r
+\r
+       @SuppressWarnings("incomplete-switch")\r
+       private void processState(TranscodeTask transcodeTask, IJobEngine jobEngine, Media mediaCubeMedia) throws Exception {\r
+               switch (transcodeTask.getState()) {\r
+               case CANCELLED:\r
+                       throw new IllegalStateException("Transcode task was CANCELLED.");\r
+               case FAILED:\r
+                       throw new IllegalStateException("Transcode task has FAILED.");\r
+               case COMPLETE:\r
+                       onTranscodeComplete(transcodeTask, jobEngine, mediaCubeMedia);\r
+                       break;\r
+               }\r
+       }\r
+\r
+       private void setAndCheck(String globalSourcePath, String transcoderTargetPath, IJobEngine jobEngine) throws Exception {\r
+               if (StringUtils.isBlank(SELENIO_API_ADDRESS))\r
+                       throw new NullPointerException("System is not configured properly, 'jobengine.selenio.address' startup parameter missing.");\r
+\r
+               if (StringUtils.isBlank(SELENIO_API_PROJECTFILE))\r
+                       throw new NullPointerException("System is not configured properly, 'jobengine.selenio.projectfilepath' startup parameter missing.");\r
+               TranscodeMgrWSService service = new TranscodeMgrWSService(new URL(SELENIO_API_ADDRESS), new QName("http://ws.server.mediamanager.digitalrapids.ca/", "TranscodeMgrWSService"));\r
+               transcoder = service.getTranscodeMgrWSPort();\r
+\r
+               if (StringUtils.isBlank(globalSourcePath))\r
+                       throw new NullPointerException("System is not configured properly, 'globalInputFolder' parameter missing.");\r
+               manager = jobEngine.getItemManager();\r
+\r
+               store = manager.getCurrentLowresStore();\r
+               if (store == null)\r
+                       throw new NullPointerException("System is not configured properly, low-res system store definition missing.");\r
+\r
+               storeUri = store.getTargetStoreUri(RemoteStoreProtocol.LOCAL);\r
+               if (storeUri == null)\r
+                       throw new Exception("Can not detect proxy folder.");\r
+\r
+               fileType = manager.getFileType(LOWRES_FILETYPE);\r
+               if (fileType == null)\r
+                       throw new NullPointerException("System is not configured properly, low-res file type definition missing.");\r
+\r
+               if (StringUtils.isBlank(transcoderTargetPath))\r
+                       throw new NullPointerException("System is not configured properly, 'transcoderTargetPath' parameter missing.");\r
+               this.transcoderTargetPath = transcoderTargetPath;\r
+\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/TranscodeStep.java b/server/-product/production/HIRTV/jobs/steps/TranscodeStep.java
new file mode 100644 (file)
index 0000000..dd1246e
--- /dev/null
@@ -0,0 +1,32 @@
+package user.jobengine.server.steps;\r
+\r
+import user.commons.configuration.SystemConfiguration;\r
+import user.jobengine.db.Media;\r
+import user.jobengine.server.IJobEngine;\r
+import user.jobengine.server.IJobRuntime;\r
+\r
+public class TranscodeStep extends JobStep {\r
+       private static int TRANSCODER_VERSION = SystemConfiguration.getInstance().value("services.transcoder.version", 0);\r
+       private static String TRANSCODER_API_ADDRESS = SystemConfiguration.getInstance().value("services.transcoder.api.address", "");\r
+       private static String TRANSCODER_API_TEMPLATE = SystemConfiguration.getInstance().value("services.transcoder.api.template", "");\r
+\r
+       @StepEntry\r
+       public Object[] execute(String globalSourcePath, ArchiveItem archiveItem, Media mediaCubeMedia, String transcoderTargetPath, IJobEngine jobEngine,\r
+                       IJobRuntime jobRuntime) throws Exception {\r
+               switch (TRANSCODER_VERSION) {\r
+               case 0: {\r
+                       TranscodeSELENIOStep selenioStep = new TranscodeSELENIOStep();\r
+                       selenioStep.execute(globalSourcePath, archiveItem, mediaCubeMedia, transcoderTargetPath, jobEngine, jobRuntime);\r
+                       break;\r
+               }\r
+               case 1: {\r
+                       TranscodeFFAStranStep ffaStransStep = new TranscodeFFAStranStep();\r
+                       ffaStransStep.execute(archiveItem, mediaCubeMedia, TRANSCODER_API_ADDRESS, TRANSCODER_API_TEMPLATE, globalSourcePath, transcoderTargetPath, false,\r
+                                       jobEngine, jobRuntime);\r
+                       break;\r
+               }\r
+               }\r
+               return null;\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/UpdateGhostMediaDataStep.java b/server/-product/production/HIRTV/jobs/steps/UpdateGhostMediaDataStep.java
new file mode 100644 (file)
index 0000000..39cb7b3
--- /dev/null
@@ -0,0 +1,89 @@
+package user.jobengine.server.steps;\r
+\r
+import java.util.List;\r
+\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+import org.apache.logging.log4j.Marker;\r
+\r
+import user.commons.remotestore.RemoteStoreProtocol;\r
+import user.jobengine.db.IItemManager;\r
+import user.jobengine.db.Media;\r
+import user.jobengine.db.MediaFile;\r
+import user.jobengine.db.Store;\r
+import user.jobengine.server.IJobEngine;\r
+import user.jobengine.server.IJobRuntime;\r
+import user.jobengine.server.steps.shared.MetadataType;\r
+import user.jobengine.server.steps.shared.MetadataTypeDetector;\r
+\r
+public class UpdateGhostMediaDataStep extends JobStep {\r
+       private static final Logger logger = LogManager.getLogger();\r
+       private Marker marker;\r
+\r
+       @StepEntry\r
+       public Object[] execute(Media mediaCubeMedia, IJobEngine jobEngine, IJobRuntime jobRuntime) throws Exception {\r
+               marker = jobRuntime.getSessionMarker();\r
+\r
+               IItemManager manager = jobEngine.getItemManager();\r
+               //Refresh from db\r
+               List<MediaFile> mediaFiles = manager.getMedia(mediaCubeMedia.getId()).getMediaFiles();\r
+               if (mediaFiles != null && mediaFiles.size() == 2) {\r
+                       MediaFile lowres = null;\r
+                       MediaFile highres = null;\r
+\r
+                       for (MediaFile mf : mediaFiles) {\r
+                               if (mf.getStore().getSourceStoreUri(RemoteStoreProtocol.HTTP) != null)\r
+                                       lowres = mf;\r
+                               else\r
+                                       highres = mf;\r
+                       }\r
+\r
+                       if (highres == null) {\r
+                               logger.info(marker, "Nincs highres mediaId: {}", mediaCubeMedia.getId());\r
+                               return null;\r
+                       }\r
+                       if (lowres == null) {\r
+                               logger.info(marker, "Nincs lowres mediaId: {}", mediaCubeMedia.getId());\r
+                               return null;\r
+                       }\r
+\r
+                       String id = MetadataTypeDetector.truncateExtension(highres.getRelativePath());\r
+                       id = MetadataTypeDetector.truncateVersion(id);\r
+                       boolean detect = MetadataTypeDetector.GuessMetadataType(id) == MetadataType.OctopusPlaceholder\r
+                                       || MetadataTypeDetector.GuessMetadataType(id) == MetadataType.OctopusStory;\r
+                       if (!detect) {\r
+                               logger.info(marker, "Nem bejátszó mediaId: {}, file: {}", mediaCubeMedia.getId(), highres.getRelativePath());\r
+                               return null;\r
+                       }\r
+\r
+                       Store highresStore = manager.getSystemStore(false);\r
+                       final long sourceMediaId = lowres.getId();\r
+                       final long highresMediaFileId = highres.getId();\r
+                       final String highresRealtivePath = highres.getRelativePath();\r
+\r
+                       manager.executeQuery("SELECT mediaid FROM mediafile WHERE relativepath=? and storeid=? and id!=?", rs -> {\r
+                               long mediaId = rs.getLong(1);\r
+                               Media media = manager.getMedia(mediaId);\r
+                               if (media.getMediaFilesCount() == 1) {\r
+                                       logger.info(marker, "Hiányzó szellem lowres hozzáadása {} alapján", media.getId());\r
+\r
+                                       MediaFile mf = (MediaFile) manager.get(MediaFile.class, sourceMediaId);\r
+                                       mf.setMedia(media);\r
+                                       mf.setId(0);\r
+                                       manager.add(mf);\r
+                                       media.setLength(mediaCubeMedia.getLength());\r
+                                       manager.modify(media);\r
+                               }\r
+                               return true;\r
+                       }, st -> {\r
+                               st.setString(1, highresRealtivePath);\r
+                               st.setLong(2, highresStore.getId());\r
+                               st.setLong(3, highresMediaFileId);\r
+                       });\r
+\r
+               }\r
+\r
+               return null;\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/UploadRecordingToNexioStep.java b/server/-product/production/HIRTV/jobs/steps/UploadRecordingToNexioStep.java
new file mode 100644 (file)
index 0000000..b1e91ba
--- /dev/null
@@ -0,0 +1,147 @@
+package user.jobengine.server.steps;\r
+\r
+import java.io.File;\r
+import java.nio.file.Paths;\r
+\r
+import org.apache.commons.lang.StringUtils;\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+import org.apache.logging.log4j.Marker;\r
+import org.apache.logging.log4j.message.Message;\r
+import org.apache.logging.log4j.message.ParameterizedMessage;\r
+\r
+import com.ibm.nosql.json.api.DB;\r
+\r
+import user.commons.RemoteFile;\r
+import user.commons.StoreUri;\r
+import user.commons.configuration.SystemConfiguration;\r
+import user.commons.nosql.NoSQLUtils;\r
+import user.commons.remotestore.IProgressEventListener;\r
+import user.commons.remotestore.IStatusEventListener;\r
+import user.commons.remotestore.ProgressEvent;\r
+import user.commons.remotestore.RemoteStoreProtocol;\r
+import user.commons.remotestore.StatusEvent;\r
+import user.jobengine.db.IItemManager;\r
+import user.jobengine.server.IJobEngine;\r
+import user.jobengine.server.IJobRuntime;\r
+\r
+public class UploadRecordingToNexioStep extends JobStep {\r
+       private static final Logger logger = LogManager.getLogger();\r
+       private static String NEXIO_HOST = SystemConfiguration.getInstance().value("services.nexio.host");\r
+\r
+       private IItemManager manager;\r
+       private DB db;\r
+       private StoreUri sourceUri;\r
+       private StoreUri targetUri;\r
+       private Marker marker;\r
+\r
+       private int check(int value, String name) {\r
+               if (value == 0) {\r
+                       logger.error(marker, "A folyamat '{}' bemeneti paramétere 0.", name);\r
+                       throw new NullPointerException(String.format("System is not configured properly, missing '%s' input parameter.", name));\r
+               }\r
+               return value;\r
+       }\r
+\r
+       private String check(String value, String name) {\r
+               if (StringUtils.isBlank(value)) {\r
+                       logger.error(marker, "A folyamat '{}' bemeneti paramétere üres.", name);\r
+                       throw new NullPointerException(String.format("System is not configured properly, missing '%s' input parameter.", name));\r
+               }\r
+               return value;\r
+       }\r
+\r
+       @StepEntry\r
+       public Object[] execute(ArchiveItem archiveItem, String targetFileName, int nexioPort, String nexioUserName, String nexioPassword, IJobEngine jobEngine,\r
+                       IJobRuntime jobRuntime) throws Exception {\r
+\r
+               marker = jobRuntime.getSessionMarker();\r
+               manager = jobEngine.getItemManager();\r
+               setAndCheck(archiveItem, targetFileName, nexioPort, nexioUserName, nexioPassword);\r
+               File sourceFile = new File(archiveItem.getMediaFile());\r
+               String sourceFileName = sourceFile.getName();\r
+               try {\r
+                       final IJobRuntime runtime = jobRuntime;\r
+                       sourceUri.addProgressListener(new IProgressEventListener() {\r
+                               @Override\r
+                               public void progressChanged(ProgressEvent evt) {\r
+                                       runtime.incrementProgress(evt.getProgress());\r
+                               }\r
+                       });\r
+                       sourceUri.addStatusListener(new IStatusEventListener() {\r
+                               @Override\r
+                               public void statusChanged(StatusEvent evt) {\r
+                                       evt.setCancel(!canContinue());\r
+                               }\r
+                       });\r
+\r
+                       RemoteFile targetFile = null;\r
+                       try {\r
+                               targetFile = targetUri.getRemoteFile(targetFileName);\r
+                       } catch (Exception e) {\r
+                               logger.catching(e);\r
+                       }\r
+                       if (targetFile != null)\r
+                               throw new Exception("Exists!");\r
+\r
+                       RemoteFile remoteFile = sourceUri.transferFrom(targetUri, sourceFileName, targetFileName);\r
+\r
+                       logger.info(marker, "Az '{}' állomány feltöltése sikeres volt '{}' néven.", sourceFile, targetFileName);\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       if (!archiveItem.removeCatchedFile())\r
+                               logger.error(getMarker(), "A {} állomány .catched jelző állománya nem törölhető.", new File(archiveItem.getMediaFile()).getName());\r
+                       Message m = new ParameterizedMessage("Az '{}' állomány feltöltése '{}' néven sikertelen. A rendszer hibaüzenete: {}", sourceFile, targetFileName, e\r
+                                       .getMessage());\r
+                       logger.error(marker, m);\r
+                       throw new Exception(m.getFormattedMessage());\r
+               }\r
+               return new Object[] {};\r
+       }\r
+\r
+       private void setAndCheck(ArchiveItem archiveItem, String targetFileName, int nexioPort, String nexioUserName, String nexioPassword) throws Exception {\r
+               db = NoSQLUtils.getNoSQLDB();\r
+               if (db == null) {\r
+                       logger.error(marker, "Az NoSQL adatkezelő réteg nem elérhető.");\r
+                       throw new NullPointerException("Internal error, missing NoSQL DB reference.");\r
+               }\r
+\r
+               if (archiveItem == null) {\r
+                       logger.error(marker, "A folyamat 'archiveItem' bemeneti paramétere üres.");\r
+                       throw new NullPointerException("Internal error, missing 'archiveItem'.");\r
+               }\r
+\r
+               if (archiveItem.getMediaFile() == null) {\r
+                       logger.error(marker, "A folyamat 'archiveItem.mediaFile' paramétere üres.");\r
+                       throw new NullPointerException("Internal error, missing 'archiveItem.mediaFile'.");\r
+               }\r
+\r
+               check(targetFileName, "targetFileName");\r
+\r
+               if (StringUtils.isBlank(NEXIO_HOST)) {\r
+                       logger.error(marker, "A 'nexio.host' rendszer paraméter nem található.");\r
+                       throw new NullPointerException("System is not configured properly, 'jobengine.selenio.address' startup parameter missing.");\r
+               }\r
+               check(nexioPort, "nexioPort");\r
+               check(nexioUserName, "nexioUserName");\r
+               check(nexioPassword, "nexioPassword");\r
+\r
+               targetUri = manager.createStoreUri(RemoteStoreProtocol.FTP, NEXIO_HOST);\r
+               targetUri.setRootPath("LXF");\r
+               targetUri.setPortNumber(nexioPort);\r
+               targetUri.setUserName(nexioUserName);\r
+               targetUri.setPassword(nexioPassword);\r
+               if (targetUri == null) {\r
+                       logger.error(marker, "A forrás nem elérhető.");\r
+                       throw new NullPointerException("Internal error, missing 'sourceUri'.");\r
+               }\r
+\r
+               sourceUri = manager.createStoreUri(RemoteStoreProtocol.LOCAL, Paths.get(archiveItem.getMediaFile()).getParent().toString());\r
+               if (sourceUri == null) {\r
+                       logger.error(marker, "A cél nem elérhető.");\r
+                       throw new NullPointerException("Internal error, missing 'targetUri'.");\r
+               }\r
+\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/shared/Cmd.java b/server/-product/production/HIRTV/jobs/steps/shared/Cmd.java
new file mode 100644 (file)
index 0000000..6aaff0e
--- /dev/null
@@ -0,0 +1,82 @@
+package user.jobengine.server.steps.shared;\r
+\r
+import java.io.BufferedReader;\r
+import java.io.InputStreamReader;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+\r
+import user.commons.configuration.SystemConfiguration;\r
+\r
+public class Cmd {\r
+       public interface IResponseCallback {\r
+               void onResponse(String line);\r
+       }\r
+\r
+       private static final String FFMPEG_EXECUTABLE = SystemConfiguration.getInstance().value("services.ffmpeg.executable-location");\r
+\r
+       private static final Logger log = LogManager.getLogger();\r
+\r
+       public static ProcessBuilder create(String... args) {\r
+               List<String> chunks = new ArrayList<>();\r
+               for (String arg : args)\r
+                       chunks.add(arg);\r
+\r
+               ProcessBuilder processBuilder = new ProcessBuilder();\r
+               processBuilder.command(chunks).redirectErrorStream(true);\r
+               return processBuilder;\r
+       }\r
+\r
+       public static ProcessBuilder create(String command, StringBuilder args) {\r
+               args.insert(0, command + "\r\n");\r
+               String[] chunks = args.toString().replace("\r\n", " ").split(" ");\r
+               return create(chunks);\r
+       }\r
+\r
+       public static String execute(ProcessBuilder processBuilder) {\r
+               return execute(processBuilder, true);\r
+       }\r
+\r
+       public static String execute(ProcessBuilder processBuilder, boolean firstResponse) {\r
+               return execute(processBuilder, firstResponse, null);\r
+       }\r
+\r
+       public static String execute(ProcessBuilder processBuilder, boolean firstResponse, IResponseCallback responseCallBack) {\r
+               String result = null;\r
+               try {\r
+                       log.debug("Executing : {}", processBuilder.command().toString().replace("[", "").replace("]", "").replace(",", ""));\r
+                       Process process = processBuilder.start();\r
+\r
+                       try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {\r
+                               String line = null;\r
+                               while ((line = reader.readLine()) != null) {\r
+                                       log.debug("Process response: {}", line);\r
+                                       if (responseCallBack != null)\r
+                                               responseCallBack.onResponse(line);\r
+                                       //System.out.println(line);\r
+                                       if (line != null && line.length() > 0) {\r
+                                               result = line;\r
+                                               if (firstResponse)\r
+                                                       break;\r
+                                       }\r
+                               }\r
+                               int exitCode = process.waitFor();\r
+                               if (exitCode != 0)\r
+                                       log.error("Exited with error code : " + exitCode);\r
+                       } catch (Exception e) {\r
+                               throw e;\r
+                       }\r
+               } catch (Exception e) {\r
+                       log.error(e);\r
+               }\r
+\r
+               return result;\r
+       }\r
+\r
+       public static String getFFMpegExecutable() {\r
+               return FFMPEG_EXECUTABLE;\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/shared/EscortFiles.java b/server/-product/production/HIRTV/jobs/steps/shared/EscortFiles.java
new file mode 100644 (file)
index 0000000..bc673f9
--- /dev/null
@@ -0,0 +1,378 @@
+package user.jobengine.server.steps.shared;\r
+\r
+import java.io.ByteArrayInputStream;\r
+import java.io.File;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.OutputStream;\r
+import java.io.StringWriter;\r
+import java.io.UnsupportedEncodingException;\r
+import java.nio.file.DirectoryStream;\r
+import java.nio.file.Files;\r
+import java.nio.file.Path;\r
+import java.nio.file.Paths;\r
+import java.nio.file.attribute.FileAttribute;\r
+import java.nio.file.attribute.PosixFilePermission;\r
+import java.nio.file.attribute.PosixFilePermissions;\r
+import java.text.SimpleDateFormat;\r
+import java.util.ArrayList;\r
+import java.util.Calendar;\r
+import java.util.Collections;\r
+import java.util.Date;\r
+import java.util.List;\r
+import java.util.Set;\r
+\r
+import javax.xml.parsers.DocumentBuilder;\r
+import javax.xml.parsers.DocumentBuilderFactory;\r
+import javax.xml.transform.OutputKeys;\r
+import javax.xml.transform.Transformer;\r
+import javax.xml.transform.TransformerConfigurationException;\r
+import javax.xml.transform.TransformerException;\r
+import javax.xml.transform.TransformerFactory;\r
+import javax.xml.transform.TransformerFactoryConfigurationError;\r
+import javax.xml.transform.dom.DOMSource;\r
+import javax.xml.transform.stream.StreamResult;\r
+\r
+import org.apache.commons.lang.StringUtils;\r
+import org.apache.commons.net.ftp.FTPClient;\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+import org.apache.logging.log4j.Marker;\r
+import org.apache.logging.log4j.message.Message;\r
+import org.w3c.dom.DOMImplementation;\r
+import org.w3c.dom.Document;\r
+import org.w3c.dom.Element;\r
+\r
+import com.ibm.nosql.json.api.BasicDBObject;\r
+import com.ibm.nosql.json.util.JSON;\r
+\r
+import user.commons.CalendarUtils;\r
+import user.commons.StoreUri;\r
+import user.commons.log4j2.marker.MediaCubeMarker;\r
+import user.commons.remotestore.FtpDirectoryLister;\r
+\r
+public class EscortFiles {\r
+       private static final String RECORDTIMESTAMP = "RecordTimeStamp";\r
+       private static final String MODIFIEDTIMESTAMP = "ModifiedTimeStamp";\r
+       public static final String DOT_CATCHED = ".catched";\r
+       public static final String DOT_JSON = ".json";\r
+       private static final Logger logger = LogManager.getLogger();\r
+       private static final String EXTENDEDAGENCY = "ExtendedAgency";\r
+       private static final String EXTENDEDDESCRIPTION = "ExtendedDescription";\r
+       private static final String KILLDATE = "KillDate";\r
+       private static final String FORMAT_KILLDATE = "MM-dd-yyyy";\r
+       private static final String EXTENDEDID = "extendedId";\r
+       private static final String ID = "ID";\r
+       private static final String KILLDATE_FILENAME = "%s.%s.killdate";\r
+       private static final String KILLDATE_EXT = ".killdate";\r
+       private static final String FORMAT_KILLDATENAME = "yyyyMMdd";\r
+       public static final String STATUSFOLDER = ".STATUS";\r
+       public static final String CONFLICTFOLDER = ".CONFLICT";\r
+\r
+       public static String composeKillDate(int days) {\r
+               Calendar killDate = Calendar.getInstance();\r
+               killDate.add(Calendar.DAY_OF_YEAR, days);\r
+               SimpleDateFormat dateFormat = new SimpleDateFormat(FORMAT_KILLDATENAME);\r
+               return dateFormat.format(killDate.getTime());\r
+       }\r
+       /*\r
+        * <?xml version="1.0" encoding="UTF-16"?> <ID extendedId="aaaaaaa">\r
+        * <KillDate>02-02-2018</KillDate> <ExtendedDescription>TEST\r
+        * TEST</ExtendedDescription> <ExtendedAgency>AGENT AGENT</ExtendedAgency> </ID>\r
+        */\r
+\r
+       private static String composeKillDateFileName(String fileName, int days) {\r
+               return String.format(KILLDATE_FILENAME, fileName, composeKillDate(days));\r
+       }\r
+\r
+       public static void createCatchedFile(Path escortFile) throws IOException {\r
+               String catchedFileName = escortFile.toString() + DOT_CATCHED;\r
+               Path catchedFilePath = Paths.get(catchedFileName);\r
+               Files.createFile(catchedFilePath);\r
+       }\r
+\r
+       public static void createFellow(String escortFile, String extension) throws IOException {\r
+               Files.copy(Paths.get(escortFile), Paths.get(escortFile + "." + extension));\r
+       }\r
+\r
+       /***\r
+        * A media elérési útján alapján a .STATUS almappában létrehozza a .catch fajlt.\r
+        *\r
+        * @param mediaFile\r
+        * @throws IOException\r
+        */\r
+       public static void createMediaCatch(Path mediaFile) throws IOException {\r
+               Path catchedFile = createMediaCatchFilePath(mediaFile);\r
+               ensureUNCFolder(catchedFile.getParent());\r
+               Files.createFile(catchedFile);\r
+       }\r
+\r
+       public static Path createMediaCatchFilePath(Path mediaFile) {\r
+               String catchFileName = mediaFile.getFileName().toString() + DOT_CATCHED;\r
+               return Paths.get(mediaFile.getParent().toString(), STATUSFOLDER, catchFileName);\r
+       }\r
+\r
+       public static void createMetadata(String filePath, String fileName, String metadata) throws IOException {\r
+               ensureUNCFolder(filePath, STATUSFOLDER);\r
+               String metadataFileName = fileName + DOT_JSON;\r
+               Path metadataPath = Paths.get(filePath, STATUSFOLDER, metadataFileName);\r
+               Files.write(metadataPath, metadata.getBytes());\r
+       }\r
+\r
+       public static Path constructMetadataPath(Path filePath) throws IOException {\r
+               String metadataFileName = filePath.getFileName().toString() + DOT_JSON;\r
+               return Paths.get(filePath.getParent().toString(), STATUSFOLDER, metadataFileName);\r
+       }\r
+       \r
+       public static boolean createMetadataIfNotExists(String filePath, String fileName, String metadata) throws IOException {\r
+               boolean result = false;\r
+               if (!EscortFiles.isMetadataExists(filePath, fileName)) {\r
+                       EscortFiles.createMetadata(filePath, fileName, metadata);\r
+                       result = true;\r
+               }\r
+               return result;\r
+       }\r
+\r
+       public static void createMorpheusXML(String filePath, String fileName, String content) throws IOException {\r
+               ensureUNCFolder(filePath, STATUSFOLDER);\r
+               Path xmlPath = Paths.get(filePath, fileName);\r
+               if (Files.exists(xmlPath))\r
+                       throw new IOException(String.format("Az '%s' állomány már létezik.", xmlPath));\r
+               Files.write(xmlPath, content.getBytes());\r
+       }\r
+\r
+       public static byte[] createNEXIODatesMeta(String fileName, Date recorded, Date modified) throws Exception {\r
+               DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();\r
+               DocumentBuilder db = dbf.newDocumentBuilder();\r
+               DOMImplementation impl = db.getDOMImplementation();\r
+               Document xmlDocument = impl.createDocument(null, null, null);\r
+\r
+               Element root = xmlDocument.createElement(ID);\r
+               root.setAttribute(EXTENDEDID, fileName);\r
+               // <ModifiedTimeStamp>07-13-2020 (19:36:52)</ModifiedTimeStamp>\r
+               // <RecordTimeStamp>05-18-2013 (18:52:24)</RecordTimeStamp>\r
+               SimpleDateFormat df = new SimpleDateFormat("MM-dd-yyyy (HH:mm:ss)");\r
+               root.appendChild(xmlDocument.createElement(MODIFIEDTIMESTAMP)).appendChild(xmlDocument.createTextNode(df.format(modified)));\r
+               root.appendChild(xmlDocument.createElement(RECORDTIMESTAMP)).appendChild(xmlDocument.createTextNode(df.format(recorded)));\r
+               xmlDocument.appendChild(root);\r
+\r
+               return xmlDocumentToString(xmlDocument);\r
+       }\r
+\r
+       public static byte[] createNEXIOKillDateFile(String fileName, Date killDate, String description, String agency) throws Exception {\r
+               DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();\r
+               DocumentBuilder db = dbf.newDocumentBuilder();\r
+               DOMImplementation impl = db.getDOMImplementation();\r
+               Document xmlDocument = impl.createDocument(null, null, null);\r
+\r
+               Element root = xmlDocument.createElement(ID);\r
+               root.setAttribute(EXTENDEDID, fileName);\r
+               if (killDate != null) {\r
+                       String sKillDate = CalendarUtils.toString(CalendarUtils.createCalendar(killDate), FORMAT_KILLDATE);\r
+                       root.appendChild(xmlDocument.createElement(KILLDATE)).appendChild(xmlDocument.createTextNode(sKillDate));\r
+               }\r
+\r
+               if (StringUtils.isNotBlank(description))\r
+                       root.appendChild(xmlDocument.createElement(EXTENDEDDESCRIPTION)).appendChild(xmlDocument.createTextNode(description));\r
+               if (StringUtils.isNotBlank(agency))\r
+                       root.appendChild(xmlDocument.createElement(EXTENDEDAGENCY)).appendChild(xmlDocument.createTextNode(agency));\r
+               xmlDocument.appendChild(root);\r
+\r
+               return xmlDocumentToString(xmlDocument);\r
+       }\r
+\r
+       public static Document createNEXIOMeta(byte[] content) throws Exception {\r
+               DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();\r
+               DocumentBuilder db = dbf.newDocumentBuilder();\r
+               DOMImplementation impl = db.getDOMImplementation();\r
+               Document xmlDocument = null;\r
+\r
+               try (InputStream is = new ByteArrayInputStream(content)) {\r
+                       xmlDocument = db.parse(is);\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+               }\r
+\r
+               return xmlDocument;\r
+       }\r
+\r
+       public static void createUNCKillDate(String filePath, String fileName, int days, Marker marker) throws IOException {\r
+               ensureUNCFolder(filePath, STATUSFOLDER);\r
+               String killDateFileName = composeKillDateFileName(fileName, days);\r
+               Path killDatePath = Paths.get(filePath, STATUSFOLDER, killDateFileName);\r
+               if (Files.exists(killDatePath))\r
+                       logger.warn(marker, "Az '{}' állomány már létezik.", killDatePath);\r
+               else\r
+                       Files.createFile(killDatePath);\r
+       }\r
+\r
+       @SuppressWarnings("unchecked")\r
+       public static <T> T decode(Path escortFile) {\r
+               T result = null;\r
+               try {\r
+                       byte[] bytes = Files.readAllBytes(escortFile);\r
+                       String content = new String(bytes);\r
+                       result = (T) JSON.parse(content);\r
+               } catch (Exception e) {\r
+                       logger.error("Decode error. System message is: ", e.getMessage());\r
+               }\r
+               return result;\r
+       }\r
+\r
+       public static void ensureUNCFolder(Path filePath) throws IOException {\r
+               File folder = filePath.toFile();\r
+               if (!folder.exists() || !folder.isDirectory()) {\r
+                       try {\r
+                               Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rwxrwxrwx");\r
+                               FileAttribute<Set<PosixFilePermission>> attr = PosixFilePermissions.asFileAttribute(perms);\r
+                               Files.createDirectories(filePath, attr);\r
+                       } catch (Exception e) {\r
+                               // logger.catching(e);\r
+                               try {\r
+                                       Files.createDirectories(filePath);\r
+                               } catch (Exception e1) {\r
+                                       logger.catching(e1);\r
+                                       throw e1;\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       public static void ensureUNCFolder(String filePath, String folderName) throws IOException {\r
+               Path statusPath = Paths.get(filePath, folderName);\r
+               ensureUNCFolder(statusPath);\r
+       }\r
+\r
+       public static boolean isCatchedFileExists(Path escortFile) {\r
+               String catchedFileName = escortFile.toString() + DOT_CATCHED;\r
+               Path catchedFilePath = Paths.get(catchedFileName);\r
+               return Files.exists(catchedFilePath);\r
+       }\r
+\r
+       /***\r
+        * A media eleresi utjan alapjan a .STATUS almappaban vizsgalja .catch fajl\r
+        * letezeset.\r
+        *\r
+        * @param mediaFile\r
+        * @return\r
+        */\r
+       public static boolean isMediaCatched(Path mediaFile) {\r
+               Path catchedFile = createMediaCatchFilePath(mediaFile);\r
+               return Files.exists(catchedFile);\r
+       }\r
+\r
+       public static boolean isMetadataExists(String filePath, String fileName) throws IOException {\r
+               boolean result = false;\r
+               String metadataFileName = fileName + DOT_JSON;\r
+               Path metadataPath = Paths.get(filePath, STATUSFOLDER, metadataFileName);\r
+               result = Files.exists(metadataPath);\r
+               return result;\r
+       }\r
+\r
+       public static void notifyRecipient(Path escortFile, Logger logger, Message msg) {\r
+               if (Files.exists(escortFile)) {\r
+                       try {\r
+                               BasicDBObject downloadable = EscortFiles.decode(escortFile);\r
+                               String recipientKey = "recipient";\r
+                               if (downloadable.containsKey(recipientKey)) {\r
+                                       String recipient = downloadable.getString(recipientKey);\r
+                                       logger.info(new MediaCubeMarker(recipient, "MediaCube rendszerüzenet"), msg);\r
+                               }\r
+                       } catch (Exception e) {\r
+                               logger.catching(e);\r
+                       }\r
+\r
+               }\r
+       }\r
+\r
+       public static void remove(Path file) {\r
+               try {\r
+                       file.toFile().delete();\r
+               } catch (Exception e) {\r
+                       logger.error("Unable to delete {}", file.toAbsolutePath().toString());\r
+               }\r
+       }\r
+\r
+       public static void remove(List<Path> files) {\r
+               if (files != null)\r
+                       files.forEach(f -> remove(f));\r
+       }\r
+\r
+       public static void removeCatchedFile(Path escortFile) {\r
+               remove(Paths.get(escortFile.toString() + DOT_CATCHED));\r
+       }\r
+\r
+       public static List<Path> getKillDateFiles(Path filePath) {\r
+               String killDateFilePattern = String.format("%s.*%s", filePath.getFileName().toString(), KILLDATE_EXT);\r
+               List<Path> result = new ArrayList<>();\r
+               try {\r
+                       Path statusPath = Paths.get(filePath.getParent().toString(), STATUSFOLDER);\r
+                       File statusPathFile = statusPath.toFile();\r
+                       if (statusPathFile.exists() && statusPathFile.isDirectory()) {\r
+                               try (DirectoryStream<Path> stream = Files.newDirectoryStream(statusPath, killDateFilePattern)) {\r
+                                       stream.forEach(p -> result.add(p));\r
+                               } catch (Exception e) {\r
+                                       logger.catching(e);\r
+                               }\r
+                       }\r
+                       Collections.sort(result);\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+               }\r
+               return result;\r
+       }\r
+\r
+       /***\r
+        * A media eleresi utjan alapjan a .STATUS almappabol torli a .catch fajlt.\r
+        *\r
+        * @param mediaFile\r
+        * @throws IOException\r
+        */\r
+       public static void removeMediaCatch(Path mediaFile) {\r
+               Path catchedFile = createMediaCatchFilePath(mediaFile);\r
+               remove(catchedFile);\r
+       }\r
+\r
+       public static void setNEXIOKillDate(int killDateDays, String targetFileName, String nexioAgency, StoreUri targetUri) throws Exception {\r
+               OutputStream outStream = null;\r
+               try {\r
+                       FTPClient targetFTP = ((FtpDirectoryLister) targetUri.getLister()).connect();\r
+                       Calendar killDate = CalendarUtils.createCalendar(new Date());\r
+                       killDate.add(Calendar.DAY_OF_YEAR, killDateDays);\r
+                       if (targetFileName.toLowerCase().contains(".mxf"))\r
+                               targetFileName = targetFileName.substring(0, targetFileName.lastIndexOf('.'));\r
+                       byte[] killDateFile = EscortFiles.createNEXIOKillDateFile(targetFileName, killDate.getTime(), null, nexioAgency);\r
+                       String xml = targetFileName + ".xml";\r
+                       outStream = targetFTP.storeFileStream(xml);\r
+                       if (outStream == null) {\r
+                               throw new NullPointerException(\r
+                                               "Can not open: " + targetFileName.substring(0, targetFileName.lastIndexOf('.')) + ".xml" + " Reply:" + targetFTP.getReplyString());\r
+                       }\r
+                       outStream.write(killDateFile);\r
+                       outStream.flush();\r
+               } catch (Exception e) {\r
+                       throw e;\r
+               } finally {\r
+                       if (outStream != null)\r
+                               outStream.close();\r
+                       targetUri.cleanUp();\r
+               }\r
+       }\r
+\r
+       private static byte[] xmlDocumentToString(Document xmlDocument)\r
+                       throws TransformerFactoryConfigurationError, TransformerConfigurationException, TransformerException, IOException, UnsupportedEncodingException {\r
+               DOMSource domSource = new DOMSource(xmlDocument);\r
+               TransformerFactory tf = TransformerFactory.newInstance();\r
+               Transformer transformer = tf.newTransformer();\r
+               transformer.setOutputProperty(OutputKeys.METHOD, "xml");\r
+               transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-16");\r
+               transformer.setOutputProperty(OutputKeys.INDENT, "yes");\r
+               StringWriter sw = new StringWriter();\r
+               StreamResult sr = new StreamResult(sw);\r
+               transformer.transform(domSource, sr);\r
+               String result = sw.toString();\r
+               sw.close();\r
+               return result.getBytes("UTF-16");\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/shared/ExternalCommand.java b/server/-product/production/HIRTV/jobs/steps/shared/ExternalCommand.java
new file mode 100644 (file)
index 0000000..307f36d
--- /dev/null
@@ -0,0 +1,79 @@
+package user.jobengine.server.steps.shared;\r
+\r
+import java.io.BufferedReader;\r
+import java.io.InputStreamReader;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+\r
+public class ExternalCommand {\r
+       private static final Logger logger = LogManager.getLogger();\r
+       private ExternalProfile profile;\r
+\r
+       public ExternalCommand(ExternalProfile profile) {\r
+               this.profile = profile;\r
+       }\r
+\r
+       public String execute(String input, String output, boolean firstResponse, IExternalCallback responseCallBack) throws Exception {\r
+               List<String> arguments = getArguments(input, output);\r
+               List<String> command = new ArrayList<>();\r
+               command.add(profile.getExecutable());\r
+               command.addAll(arguments);\r
+\r
+               ProcessBuilder processBuilder = new ProcessBuilder();\r
+               processBuilder.command(command);\r
+\r
+               String result = null;\r
+               try {\r
+                       logger.info("Executing : {}", processBuilder.command());\r
+\r
+                       Process process = processBuilder.start();\r
+                       try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {\r
+                               String line = null;\r
+                               while ((line = reader.readLine()) != null) {\r
+                                       logger.debug("Process response: {}", line);\r
+                                       if (responseCallBack != null)\r
+                                               responseCallBack.onResponse(line);\r
+                                       //System.out.println(line);\r
+                                       if (line != null && line.length() > 0) {\r
+                                               result = line;\r
+                                               if (firstResponse)\r
+                                                       break;\r
+                                       }\r
+                               }\r
+                               int exitCode = process.waitFor();\r
+                               if (exitCode != 0) {\r
+                                       StringBuilder msg = new StringBuilder();\r
+                                       try (BufferedReader errReader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {\r
+                                               String errline = null;\r
+                                               while ((errline = errReader.readLine()) != null) {\r
+                                                       msg.append(errline);\r
+                                               }\r
+                                       } catch (Exception ex) {\r
+                                       }\r
+\r
+                                       throw new Exception("Exited with error code : " + exitCode + ". " + msg);\r
+                               }\r
+                       } catch (Exception e) {\r
+                               throw e;\r
+                       }\r
+               } catch (Exception e) {\r
+                       logger.error(e);\r
+                       throw e;\r
+               }\r
+\r
+               return result;\r
+       }\r
+\r
+       private List<String> getArguments(String input, String output) {\r
+               List<String> result = new ArrayList<>();\r
+\r
+               profile.getArguments().forEach(i -> {\r
+                       result.add(i.replace("%i", input).replace("%o", output));\r
+               });\r
+               return result;\r
+       }\r
+\r
+}
\ No newline at end of file
diff --git a/server/-product/production/HIRTV/jobs/steps/shared/ExternalCommandExecutor.java b/server/-product/production/HIRTV/jobs/steps/shared/ExternalCommandExecutor.java
new file mode 100644 (file)
index 0000000..a34ff7f
--- /dev/null
@@ -0,0 +1,32 @@
+package user.jobengine.server.steps.shared;\r
+\r
+import user.commons.configuration.SystemConfiguration;\r
+\r
+public class ExternalCommandExecutor {\r
+\r
+       public void execute(String profileName, String input, String output, IExternalCallback responseCallBack) throws Exception {\r
+               ExternalCommand externalCommand = getExternalCommand(profileName);\r
+               externalCommand.execute(input, output, false, responseCallBack);\r
+       }\r
+\r
+       private ExternalCommand getExternalCommand(String profileName) throws Exception {\r
+               ExternalProfilesConfig config = SystemConfiguration.getInstance().load("settings/external-commands.yaml", ExternalProfilesConfig.class);\r
+\r
+               if (config == null)\r
+                       throw new Exception("Missing external-commands.yaml configuration");\r
+\r
+               ExternalProfile selectedProfile = null;\r
+               for (ExternalProfile profile : config.getProfiles()) {\r
+                       if (profileName.equals(profile.getName())) {\r
+                               selectedProfile = profile;\r
+                               break;\r
+                       }\r
+               }\r
+\r
+               if (selectedProfile == null)\r
+                       throw new Exception("Missing profile " + profileName + " in external-commands.yaml configuration");\r
+\r
+               return new ExternalCommand(selectedProfile);\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/shared/ExternalProfile.java b/server/-product/production/HIRTV/jobs/steps/shared/ExternalProfile.java
new file mode 100644 (file)
index 0000000..68e22f4
--- /dev/null
@@ -0,0 +1,33 @@
+package user.jobengine.server.steps.shared;\r
+\r
+import java.util.List;\r
+\r
+public class ExternalProfile {\r
+       private String executable;\r
+       private String name;\r
+       private List<String> arguments;\r
+\r
+       public List<String> getArguments() {\r
+               return arguments;\r
+       }\r
+\r
+       public String getExecutable() {\r
+               return executable;\r
+       }\r
+\r
+       public String getName() {\r
+               return name;\r
+       }\r
+\r
+       public void setArguments(List<String> arguments) {\r
+               this.arguments = arguments;\r
+       }\r
+\r
+       public void setExecutable(String executable) {\r
+               this.executable = executable;\r
+       }\r
+\r
+       public void setName(String name) {\r
+               this.name = name;\r
+       }\r
+}
\ No newline at end of file
diff --git a/server/-product/production/HIRTV/jobs/steps/shared/ExternalProfilesConfig.java b/server/-product/production/HIRTV/jobs/steps/shared/ExternalProfilesConfig.java
new file mode 100644 (file)
index 0000000..7ef7729
--- /dev/null
@@ -0,0 +1,15 @@
+package user.jobengine.server.steps.shared;\r
+\r
+import java.util.List;\r
+\r
+public class ExternalProfilesConfig {\r
+       private List<ExternalProfile> profiles;\r
+\r
+       public List<ExternalProfile> getProfiles() {\r
+               return profiles;\r
+       }\r
+\r
+       public void setProfiles(List<ExternalProfile> profiles) {\r
+               this.profiles = profiles;\r
+       }\r
+}
\ No newline at end of file
diff --git a/server/-product/production/HIRTV/jobs/steps/shared/FFMpeg.java b/server/-product/production/HIRTV/jobs/steps/shared/FFMpeg.java
new file mode 100644 (file)
index 0000000..e4c433b
--- /dev/null
@@ -0,0 +1,225 @@
+package user.jobengine.server.steps.shared;\r
+\r
+import java.io.FileNotFoundException;\r
+import java.nio.file.Files;\r
+import java.nio.file.Paths;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.apache.commons.lang.StringUtils;\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+\r
+import user.commons.mediaarea.MediaArea;\r
+\r
+public class FFMpeg {\r
+\r
+       public interface IProgressChanged {\r
+               void onProgressChanged(long progress);\r
+       }\r
+\r
+       private static final String FPS = "fps=";\r
+       private static final String FRAME = "frame=";\r
+\r
+       private static final Logger logger = LogManager.getLogger();\r
+\r
+       //@formatter:off\r
+    public static void concatenate(String chunklist, String output) {\r
+        ProcessBuilder processBuilder = Cmd.create(\r
+                Cmd.getFFMpegExecutable(),\r
+                "-f", "concat",\r
+                "-safe", "0",\r
+                "-i", chunklist,\r
+                "-vcodec", "copy", "-acodec", "libmp3lame",\r
+                "-y", "-v", "error", "-stats", output);\r
+\r
+        Cmd.execute(processBuilder, false);\r
+    }\r
+\r
+    //@formatter:off\r
+    public static void encode(String input, String output, double from, double length) {\r
+        ProcessBuilder processBuilder = Cmd.create(\r
+                Cmd.getFFMpegExecutable(),\r
+                "-ss", String.valueOf(from),\r
+                "-t", String.valueOf(length),\r
+                "-i", input,\r
+                "-vcodec", "libx264", "-acodec", "ac3",\r
+                "-movflags", "+faststart",\r
+                "-vf", "scale=-2:480,format=yuv420p",\r
+                "-y", "-v", "error", "-stats", "-f", "mp4", output);\r
+\r
+        Cmd.execute(processBuilder, false);\r
+    }\r
+\r
+    //@formatter:off\r
+    static public void hls_audio4ch(String input, String output, IProgressChanged progressCallback) throws Exception {\r
+       StringBuilder sb = new StringBuilder();\r
+       sb.append("-v panic -stats -y")\r
+       .append("\r\n")\r
+       .append(String.format("-i %s", input))\r
+       .append("\r\n")\r
+       .append("-map 0:0 -c:v h264 -an -hls_time 100000000000 -hls_list_size 0")\r
+       .append("\r\n")\r
+       .append(String.format("-f hls %s/video.m3u8", output))\r
+       .append("\r\n");\r
+\r
+       for (int i = 0; i < 4; i++) {\r
+               sb.append(String.format("-map 0:%d -f segment -segment_time 100000000000 -segment_list_size 0", i+1))\r
+               .append("\r\n")\r
+               .append(String.format("-segment_list %s/audio%d.m3u8 -segment_format mpegts %s/audio%d%%d.aac", output, i, output, i))\r
+               .append("\r\n");\r
+       }\r
+       System.out.println(sb);\r
+        ProcessBuilder processBuilder = Cmd.create(Cmd.getFFMpegExecutable(), sb);\r
+        long[] allFrames = new long[]{0};\r
+\r
+        try {\r
+               MediaArea mi = new MediaArea(Paths.get(input));\r
+               mi.process();\r
+               allFrames[0] = mi.getFrameCount();\r
+        } catch (Exception e ){\r
+               System.err.println(e);\r
+\r
+        }\r
+\r
+        Cmd.execute(processBuilder, false, l -> {\r
+               if (allFrames[0] == 0) {\r
+                       logger.debug(l);\r
+                       System.out.println(l);\r
+                       return;\r
+               }\r
+\r
+               if (progressCallback == null)\r
+                       return;\r
+               if (l.contains(FRAME) && l.contains(FPS)) {\r
+                       String p = StringUtils.substringBetween(l, FRAME, FPS);\r
+                       if (p != null) {\r
+                               p = p.trim();\r
+                               try {\r
+                                       int currentFrames = Integer.parseInt(p);\r
+                                       progressCallback.onProgressChanged((long)currentFrames * 100 / allFrames[0]);\r
+                               } catch (Exception e){}\r
+                       }\r
+               }\r
+        });\r
+\r
+//        #EXTM3U\r
+//        #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="CH1",URI="audio0.m3u8"\r
+//        #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="CH2",URI="audio1.m3u8"\r
+//        #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="CH3",URI="audio2.m3u8"\r
+//        #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="CH4",URI="audio3.m3u8"\r
+//        #EXT-X-STREAM-INF:PROGRAM-ID=1,AUDIO="audio"\r
+//        video.m3u8\r
+\r
+        if (!Paths.get(output, "video.m3u8").toFile().exists())\r
+               throw new FileNotFoundException("video.m3u8");\r
+        if (!Paths.get(output, "video0.ts").toFile().exists())\r
+               throw new FileNotFoundException("video0.ts");\r
+        for (int i = 0; i < 4; i++) {\r
+               String file = String.format("audio%d.m3u8", i);\r
+                       if (!Paths.get(output, file).toFile().exists())\r
+                       throw new FileNotFoundException(file);\r
+               file = String.format("audio%d0.aac", i);\r
+                       if (!Paths.get(output, file).toFile().exists())\r
+                       throw new FileNotFoundException(file);\r
+        }\r
+\r
+        List<String> indexLines = new ArrayList<>();\r
+        indexLines.add("#EXTM3U");\r
+        for (int i = 0; i < 4; i++) {\r
+               indexLines.add(String.format("#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"audio\",NAME=\"CH%d\",URI=\"audio%d.m3u8\"", i+1, i));\r
+        }\r
+        indexLines.add("#EXT-X-STREAM-INF:PROGRAM-ID=1,AUDIO=\"audio\"");\r
+        indexLines.add("video.m3u8");\r
+\r
+        Files.write(Paths.get(output, "index.m3u8"), indexLines);\r
+    }\r
+\r
+\r
+\r
+    static public void withProfile(String input, String output, String profile, IProgressChanged progressCallback) throws Exception {\r
+\r
+\r
+       StringBuilder sb = new StringBuilder();\r
+       sb.append("-v panic -stats -y")\r
+       .append("\r\n")\r
+       .append(String.format("-i %s", input))\r
+       .append("\r\n")\r
+       .append("-map 0:0 -c:v h264 -an -hls_time 100000000000 -hls_list_size 0")\r
+       .append("\r\n")\r
+       .append(String.format("-f hls %s/video.m3u8", output))\r
+       .append("\r\n");\r
+\r
+       for (int i = 0; i < 4; i++) {\r
+               sb.append(String.format("-map 0:%d -f segment -segment_time 100000000000 -segment_list_size 0", i+1))\r
+               .append("\r\n")\r
+               .append(String.format("-segment_list %s/audio%d.m3u8 -segment_format mpegts %s/audio%d%%d.aac", output, i, output, i))\r
+               .append("\r\n");\r
+       }\r
+       System.out.println(sb);\r
+        ProcessBuilder processBuilder = Cmd.create(Cmd.getFFMpegExecutable(), sb);\r
+        long[] allFrames = new long[]{0};\r
+\r
+        try {\r
+               MediaArea mi = new MediaArea(Paths.get(input));\r
+               mi.process();\r
+               allFrames[0] = mi.getFrameCount();\r
+        } catch (Exception e ){\r
+               System.err.println(e);\r
+\r
+        }\r
+\r
+        Cmd.execute(processBuilder, false, l -> {\r
+               if (allFrames[0] == 0) {\r
+                       logger.debug(l);\r
+                       System.out.println(l);\r
+                       return;\r
+               }\r
+\r
+               if (progressCallback == null)\r
+                       return;\r
+               if (l.contains(FRAME) && l.contains(FPS)) {\r
+                       String p = StringUtils.substringBetween(l, FRAME, FPS);\r
+                       if (p != null) {\r
+                               p = p.trim();\r
+                               try {\r
+                                       int currentFrames = Integer.parseInt(p);\r
+                                       progressCallback.onProgressChanged((long)currentFrames * 100 / allFrames[0]);\r
+                               } catch (Exception e){}\r
+                       }\r
+               }\r
+        });\r
+\r
+//        #EXTM3U\r
+//        #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="CH1",URI="audio0.m3u8"\r
+//        #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="CH2",URI="audio1.m3u8"\r
+//        #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="CH3",URI="audio2.m3u8"\r
+//        #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="CH4",URI="audio3.m3u8"\r
+//        #EXT-X-STREAM-INF:PROGRAM-ID=1,AUDIO="audio"\r
+//        video.m3u8\r
+\r
+        if (!Paths.get(output, "video.m3u8").toFile().exists())\r
+               throw new FileNotFoundException("video.m3u8");\r
+        if (!Paths.get(output, "video0.ts").toFile().exists())\r
+               throw new FileNotFoundException("video0.ts");\r
+        for (int i = 0; i < 4; i++) {\r
+               String file = String.format("audio%d.m3u8", i);\r
+                       if (!Paths.get(output, file).toFile().exists())\r
+                       throw new FileNotFoundException(file);\r
+               file = String.format("audio%d0.aac", i);\r
+                       if (!Paths.get(output, file).toFile().exists())\r
+                       throw new FileNotFoundException(file);\r
+        }\r
+\r
+        List<String> indexLines = new ArrayList<>();\r
+        indexLines.add("#EXTM3U");\r
+        for (int i = 0; i < 4; i++) {\r
+               indexLines.add(String.format("#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"audio\",NAME=\"CH%d\",URI=\"audio%d.m3u8\"", i+1, i));\r
+        }\r
+        indexLines.add("#EXT-X-STREAM-INF:PROGRAM-ID=1,AUDIO=\"audio\"");\r
+        indexLines.add("video.m3u8");\r
+\r
+        Files.write(Paths.get(output, "index.m3u8"), indexLines);\r
+    }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/shared/FileSearchFilterOptions.java b/server/-product/production/HIRTV/jobs/steps/shared/FileSearchFilterOptions.java
new file mode 100644 (file)
index 0000000..b5a8d0e
--- /dev/null
@@ -0,0 +1,41 @@
+package user.jobengine.server.steps.shared;\r
+\r
+import java.nio.file.Path;\r
+import java.util.regex.Matcher;\r
+import java.util.regex.Pattern;\r
+\r
+import com.ibm.nosql.json.api.BasicDBObject;\r
+\r
+public class FileSearchFilterOptions {\r
+\r
+       private BasicDBObject filter;\r
+\r
+       public FileSearchFilterOptions(BasicDBObject filter) {\r
+               this.filter = filter;\r
+       }\r
+\r
+       public boolean acceptFile(Path file) {\r
+               if (filter == null)\r
+                       return true;\r
+\r
+               if (filter.containsKey("fileName")) {\r
+                       //.*\.(sh|ini|conf|vhost|xml|php)$\r
+                       String fileNamePattern = filter.getString("fileName");\r
+                       if (fileNamePattern == null || fileNamePattern.trim().length() == 0)\r
+                               return true;\r
+\r
+                       Pattern pattern = Pattern.compile(fileNamePattern, Pattern.CASE_INSENSITIVE);\r
+\r
+                       Matcher matcher = pattern.matcher(file.getFileName().toString());\r
+                       if (matcher.find())\r
+                               return true;\r
+\r
+               }\r
+\r
+               return false;\r
+       }\r
+\r
+       public boolean preAcceptDirectory(Path file) {\r
+               return true;\r
+       }\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/shared/IExternalCallback.java b/server/-product/production/HIRTV/jobs/steps/shared/IExternalCallback.java
new file mode 100644 (file)
index 0000000..1e07191
--- /dev/null
@@ -0,0 +1,5 @@
+package user.jobengine.server.steps.shared;\r
+\r
+public interface IExternalCallback {\r
+       void onResponse(String data);\r
+}
\ No newline at end of file
diff --git a/server/-product/production/HIRTV/jobs/steps/shared/ItemManagerExtensions.java b/server/-product/production/HIRTV/jobs/steps/shared/ItemManagerExtensions.java
new file mode 100644 (file)
index 0000000..70ec476
--- /dev/null
@@ -0,0 +1,95 @@
+package user.jobengine.server.steps.shared;\r
+\r
+import java.nio.file.Path;\r
+\r
+import com.ibm.nosql.json.api.BasicDBObject;\r
+\r
+import user.commons.RemoteFile;\r
+import user.commons.StoreUri;\r
+import user.commons.remotestore.RemoteStoreProtocol;\r
+import user.jobengine.db.IItemManager;\r
+import user.jobengine.db.IResultSetConsumer;\r
+import user.jobengine.db.Store;\r
+\r
+public class ItemManagerExtensions {\r
+\r
+       public static BasicDBObject getArchiveInfo(IItemManager manager, long houseid) {\r
+               final BasicDBObject[] result = new BasicDBObject[] { null };\r
+               StringBuilder query = new StringBuilder();\r
+               query.append("select count(*) as count, sum(length) as duration FROM media");\r
+               query.append(" ");\r
+               query.append(String.format("where houseid='%d' and itemtypeid = 82", houseid));\r
+               query.append(" ");\r
+               query.append("group by houseid");\r
+               IResultSetConsumer consumer = rs -> {\r
+                       BasicDBObject o = new BasicDBObject();\r
+                       o.put("count", rs.getLong("count"));\r
+                       o.put("duration", rs.getLong("duration"));\r
+                       result[0] = o;\r
+                       return false;\r
+               };\r
+               manager.executeQuery(query.toString(), consumer, null);\r
+               return result[0];\r
+       }\r
+\r
+       public static long getExistingRundownMedia(IItemManager manager, String houseid) {\r
+               final long[] result = new long[] { 0 };\r
+               final String[] idToCheck = new String[] { houseid };\r
+               int pos = houseid.lastIndexOf("-");\r
+               // a hivas a CopyForArchiveNEXIOMaterialsStep-bol is johet, ott meg nincs\r
+               // idobelyegezve a nev!\r
+               if (pos > 0 && houseid.length() - pos > 4)\r
+                       idToCheck[0] = houseid.substring(0, pos);\r
+               MetadataType metadataType = MetadataTypeDetector.GuessMetadataType(idToCheck[0]);\r
+               if (metadataType == MetadataType.OctopusPlaceholder) {\r
+                       StringBuilder query = new StringBuilder();\r
+                       query.append("select mediaid, mediafilehouseid, filename");\r
+                       query.append(" ");\r
+                       query.append(String.format("from vw_rundown_items where mediafilehouseid like '%s%%'", idToCheck[0]));\r
+                       query.append(" ");\r
+                       query.append("order by filename, mediaid");\r
+                       IResultSetConsumer consumer = rs -> {\r
+                               String fileName = rs.getString("filename");\r
+                               if (idToCheck[0].equals(fileName)) {\r
+                                       result[0] = rs.getLong("mediaid");\r
+                                       return false;\r
+                               } else\r
+                                       return true;\r
+                       };\r
+                       manager.executeQuery(query.toString(), consumer, null);\r
+               }\r
+\r
+               return result[0];\r
+       }\r
+\r
+       static public boolean isArchived(IItemManager manager, Path filePath) {\r
+               boolean result = false;\r
+               String name = filePath.getFileName().toString();\r
+               String[] tsmName = new String[] { null };\r
+               String query = String.format("SELECT relativepath FROM MEDIAFILE WHERE houseid = '%s'", name);\r
+               manager.executeQuery(query, rs -> {\r
+                       tsmName[0] = rs.getString("relativepath");\r
+                       return false;\r
+               }, null);\r
+\r
+               Store tsmStore = manager.getSystemStore(false);\r
+               if (tsmStore == null)\r
+                       throw new NullPointerException("A TSM bejegyzés nem található!");\r
+\r
+               StoreUri tsmStoreUri = tsmStore.getSourceStoreUri(RemoteStoreProtocol.TSM);\r
+               if (tsmStoreUri == null)\r
+                       throw new NullPointerException("A TSM forrás elérése nem található!");\r
+\r
+               if (tsmName[0] != null) {\r
+                       try {\r
+                               RemoteFile remoteFile = tsmStoreUri.getRemoteFile(tsmName[0]);\r
+                               result = remoteFile != null;\r
+                       } catch (Exception e) {\r
+                               result = false;\r
+                       } finally {\r
+                               tsmStoreUri.cleanUp();\r
+                       }\r
+               }\r
+               return result;\r
+       }\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/shared/MediaCubeClient.java b/server/-product/production/HIRTV/jobs/steps/shared/MediaCubeClient.java
new file mode 100644 (file)
index 0000000..0915cc3
--- /dev/null
@@ -0,0 +1,77 @@
+package user.jobengine.server.steps.shared;\r
+\r
+import javax.ws.rs.client.Entity;\r
+import javax.ws.rs.client.Invocation.Builder;\r
+import javax.ws.rs.core.MediaType;\r
+import javax.ws.rs.core.MultivaluedMap;\r
+import javax.ws.rs.core.Response;\r
+import javax.ws.rs.core.Response.Status;\r
+\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+import org.jboss.resteasy.client.jaxrs.ResteasyClient;\r
+import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;\r
+import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget;\r
+import org.jboss.resteasy.specimpl.MultivaluedMapImpl;\r
+\r
+import com.ibm.nosql.json.JSONUtil;\r
+import com.ibm.nosql.json.api.BasicDBObject;\r
+\r
+public class MediaCubeClient {\r
+       private static Logger logger = LogManager.getLogger();\r
+       private ResteasyWebTarget webTarget;\r
+\r
+       public MediaCubeClient(String address) {\r
+               ResteasyClient client = new ResteasyClientBuilder().build();\r
+               webTarget = client.target(address);\r
+       }\r
+\r
+       BasicDBObject getDbObject(String json) {\r
+               BasicDBObject result = (BasicDBObject) JSONUtil.jsonToDbObject(json);\r
+\r
+               if (result == null)\r
+                       throw new NullPointerException("API Result is null!");\r
+\r
+               if (result.containsKey("exception")) {\r
+                       BasicDBObject e = (BasicDBObject) result.get("exception");\r
+                       throw new RuntimeException(e.getString("message"));\r
+               }\r
+               //{"exception":{"message":"Invalid credentials.","publicName":"AuthenticationFailedException"}}\r
+               return result;\r
+       }\r
+\r
+       public BasicDBObject getStatus(long jobId) {\r
+               MultivaluedMap<String, Object> vars = new MultivaluedMapImpl<>();\r
+               vars.add("jobId", jobId);\r
+               Response response = query("services/rest/jobengine/jobstatus", vars).get();\r
+               if (response.getStatus() != Status.OK.getStatusCode()) {\r
+                       logger.error(response.readEntity(String.class));\r
+                       System.out.println(response.readEntity(String.class));\r
+                       return null;\r
+               }\r
+               String result = response.readEntity(String.class);\r
+               return getDbObject(result);\r
+       }\r
+\r
+       private Builder query(String path, MultivaluedMap<String, Object> vars) {\r
+               ResteasyWebTarget target = webTarget.path(path).queryParams(vars);\r
+               Builder result = target.request();\r
+               return result;\r
+       }\r
+\r
+       public long startjob(String template, String name, BasicDBObject jobParams) throws Exception {\r
+               MultivaluedMap<String, Object> vars = new MultivaluedMapImpl<>();\r
+               vars.add("template", template);\r
+               vars.add("name", name);\r
+               Response response = query("services/rest/jobengine/startjob", vars).post(Entity.entity(jobParams.toString(), MediaType.APPLICATION_JSON));\r
+\r
+               if (response.getStatus() != Status.OK.getStatusCode()) {\r
+                       logger.error(response.readEntity(String.class));\r
+                       return 0;\r
+               }\r
+\r
+               String resultObject = response.readEntity(String.class);\r
+               return Long.parseLong(resultObject);\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/shared/MetadataSaver.java b/server/-product/production/HIRTV/jobs/steps/shared/MetadataSaver.java
new file mode 100644 (file)
index 0000000..fca7153
--- /dev/null
@@ -0,0 +1,44 @@
+package user.jobengine.server.steps.shared;\r
+\r
+import java.nio.file.Files;\r
+import java.nio.file.Path;\r
+import java.nio.file.Paths;\r
+\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+\r
+import com.ibm.nosql.json.api.BasicDBObject;\r
+import com.ibm.nosql.json.api.DB;\r
+import com.ibm.nosql.json.api.DBCollection;\r
+\r
+import user.commons.mediaarea.MediaArea;\r
+import user.commons.nosql.NoSQLUtils;\r
+\r
+public class MetadataSaver {\r
+\r
+       private static final Logger logger = LogManager.getLogger();\r
+\r
+       public static void saveMetadata(String file) {\r
+               try {\r
+                       Path filePath = Paths.get(file);\r
+                       logger.info("Analize: {}", filePath);\r
+                       if (!Files.exists(filePath))\r
+                               return;\r
+\r
+                       String fileName = filePath.getFileName().toString();\r
+                       DB db = NoSQLUtils.getNoSQLDB();\r
+                       DBCollection collection = db.getCollection("metadata");\r
+                       long existing = collection.find(new BasicDBObject("fileName", fileName)).count();\r
+                       if (existing > 0)\r
+                               return;\r
+\r
+                       MediaArea mediaArea = new MediaArea(filePath);\r
+                       mediaArea.process();\r
+                       BasicDBObject metadata = mediaArea.getInform();\r
+                       collection.save(metadata);\r
+                       logger.info("Metadata saved for: {}", filePath);\r
+               } catch (Exception e) {\r
+                       logger.error("Can't analyze input {}, skipping. System message is: {}", e.getMessage());\r
+               }\r
+       }\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/shared/MetadataType.java b/server/-product/production/HIRTV/jobs/steps/shared/MetadataType.java
new file mode 100644 (file)
index 0000000..0e27bf3
--- /dev/null
@@ -0,0 +1,5 @@
+package user.jobengine.server.steps.shared;\r
+\r
+public enum MetadataType {\r
+       TrafficMaterial, TrafficPromo, TrafficAD, OctopusStory, OctopusPlaceholder, Generic\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/shared/MetadataTypeDetector.java b/server/-product/production/HIRTV/jobs/steps/shared/MetadataTypeDetector.java
new file mode 100644 (file)
index 0000000..9e9e6be
--- /dev/null
@@ -0,0 +1,49 @@
+package user.jobengine.server.steps.shared;\r
+\r
+import org.apache.commons.lang.StringUtils;\r
+\r
+public class MetadataTypeDetector {\r
+\r
+       private static final String HYPHEN = "-";\r
+       private static final String DOT = ".";\r
+\r
+       private static final String REGEXP_TRAFFICMATERIALID = "^M{1}[0-9]{6}[A-Z]{1}";\r
+       private static final String REGEXP_TRAFFICADID = "^R{1}[0-9]{6}[A-Z]{1}";\r
+       private static final String REGEXP_TRAFFICPROMOID = "^P{1}[0-9]{6}[A-Z]{1}";\r
+       private static final String REGEXP_OCTOPUSSTORYID = "^[0-9]+";\r
+       private static final String REGEXP_OCTOPUSPLACEHOLDERID = "^[0-9]+_[0-9]+";\r
+       private static final String REGEXP_OCTOPUSPLACEHOLDERVERSIONEDID = "^[0-9]+_[0-9]+-[0-9]{3}";\r
+\r
+       public static MetadataType GuessMetadataType(String id) {\r
+               if (StringUtils.isBlank(id))\r
+                       return MetadataType.Generic;\r
+               if (id.matches(REGEXP_TRAFFICMATERIALID))\r
+                       return MetadataType.TrafficMaterial;\r
+               if (id.matches(REGEXP_TRAFFICPROMOID))\r
+                       return MetadataType.TrafficPromo;\r
+               if (id.matches(REGEXP_TRAFFICADID))\r
+                       return MetadataType.TrafficAD;\r
+               if (id.matches(REGEXP_OCTOPUSSTORYID))\r
+                       return MetadataType.OctopusStory;\r
+               if (id.matches(REGEXP_OCTOPUSPLACEHOLDERID))\r
+                       return MetadataType.OctopusPlaceholder;\r
+               if (id.matches(REGEXP_OCTOPUSPLACEHOLDERVERSIONEDID))\r
+                       return MetadataType.OctopusPlaceholder;\r
+               return MetadataType.Generic;\r
+       }\r
+\r
+       public static String truncateExtension(String name) {\r
+               String result = name;\r
+               if (result != null && result.contains(DOT))\r
+                       result = result.substring(0, result.lastIndexOf(DOT));\r
+               return result;\r
+       }\r
+\r
+       public static String truncateVersion(String name) {\r
+               String result = name;\r
+               if (result != null && result.contains(HYPHEN))\r
+                       result = result.split(HYPHEN)[0];\r
+               return result;\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/shared/OctopusDataMiner.java b/server/-product/production/HIRTV/jobs/steps/shared/OctopusDataMiner.java
new file mode 100644 (file)
index 0000000..368fff6
--- /dev/null
@@ -0,0 +1,759 @@
+package user.jobengine.server.steps.shared;\r
+\r
+import java.time.LocalDate;\r
+import java.time.Period;\r
+import java.time.format.DateTimeFormatter;\r
+import java.util.Calendar;\r
+import java.util.Date;\r
+import java.util.HashMap;\r
+import java.util.HashSet;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Set;\r
+\r
+import javax.swing.event.EventListenerList;\r
+import javax.ws.rs.client.Entity;\r
+import javax.ws.rs.client.Invocation.Builder;\r
+import javax.ws.rs.core.MediaType;\r
+import javax.ws.rs.core.Response;\r
+\r
+import org.apache.commons.lang.StringUtils;\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+import org.jboss.resteasy.client.jaxrs.BasicAuthentication;\r
+import org.jboss.resteasy.client.jaxrs.ResteasyClient;\r
+import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;\r
+import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget;\r
+import org.joda.time.DateTime;\r
+\r
+import com.ibm.nosql.json.JSONUtil;\r
+import com.ibm.nosql.json.api.BasicDBList;\r
+import com.ibm.nosql.json.api.BasicDBObject;\r
+import com.ibm.nosql.json.api.DB;\r
+import com.ibm.nosql.json.api.DBCollection;\r
+import com.ibm.nosql.json.api.DBCursor;\r
+\r
+import user.commons.CalendarUtils;\r
+import user.commons.ListUtils;\r
+import user.commons.nosql.NoSQLUtils;\r
+import user.commons.octopus.IOctopusAPI;\r
+import user.commons.remotestore.IProgressEventListener;\r
+import user.commons.remotestore.ProgressEvent;\r
+\r
+public class OctopusDataMiner {\r
+       private static final String MOS_ABSTRACT = "<mosAbstract>";\r
+       private static final String MOS_ABSTRACT_END = "</mosAbstract>";\r
+       private static final Logger logger = LogManager.getLogger();\r
+       private static final String ARCHIVED = "archived";\r
+       private static final String SCHEDULEDSTART = "scheduledStart";\r
+       private static final String FILTER = "filter";\r
+       private static final String LINEFEED = "\r\n";\r
+       private static final String SIMPLE_LINEFEED = "\n";\r
+       private static final String SAVING_STORY_ID = "Saving story {}";\r
+       private static final String FIELDS_STORIES = "id,name,modified,type,format,mosObjects,script,scheduleFrom,scheduleTo,customColumns,CustomColumn.label,CustomColumn.value,reporters,User.longName,User.userName,descriptions,StoryDescription.text";\r
+       private static final String FIELDS_RUNDOWN = "id,name,modified,scheduledStart,channel,Channel.name,rundownType,RundownType.name";\r
+       public static final String FIELDS_RUNDOWN_STORYIDS = "id,slugs,Slug.storyId,Slug.position";\r
+       public static final String SLUGS = "slugs";\r
+       private static final String FIELDS_STORYFOLDER = "id,name,modified";\r
+       public static final String FIELDS_STORYFOLDER_STORYIDS = "id,stories,Story.id";\r
+       private static final String RUNDOWN = "Rundown";\r
+       private static final String FIELDS = "fields";\r
+       private static final String EXIT = "Exit";\r
+       private static final String RESULT = "result";\r
+       private static final String STORY_FOLDER = "StoryFolder";\r
+       private static final String ENTER = "Enter";\r
+       private static final String FINISHED = "Finished";\r
+       private static final String STARTING = "Starting";\r
+       private static final String MOSLABEL = "MOS: ";\r
+       private static final Object STORY = "Story";\r
+\r
+       private DB db;\r
+       private ResteasyWebTarget webTarget;\r
+       private HashSet<Long> storyIDs = new HashSet<>();\r
+       private HashSet<Long> folderIDs = new HashSet<>();\r
+       private HashSet<Long> rundownIDs = new HashSet<>();\r
+       private EventListenerList progressListenerList;\r
+       private ProgressEvent progressEvent = new ProgressEvent(this, 0);\r
+       private Map<Long, BasicDBList> storyRundowns;\r
+       private Map<Long, BasicDBList> storyStoryFolders;\r
+       private Map<Long, Object> currentRundowns;\r
+       private Map<Long, Object> currentFolder;\r
+       private Map<Long, Object> currentStories;\r
+       private boolean includeArchived;\r
+       private Calendar zeroDate = CalendarUtils.createCalendar(2017, 11, 4);\r
+       private int objectCount;\r
+       private int currentObjectIndex;\r
+       private boolean disableWrite = false;\r
+       private int maxPastDays;\r
+\r
+       public OctopusDataMiner(String address, String user, String pwd) {\r
+               db = NoSQLUtils.getNoSQLDB();\r
+               ResteasyClient client = new ResteasyClientBuilder().build();\r
+               webTarget = client.target(address).register(new BasicAuthentication(user, pwd));\r
+       }\r
+\r
+       public OctopusDataMiner(String address, String user, String pwd, int maxPastDays) {\r
+               this(address, user, pwd);\r
+               this.maxPastDays = maxPastDays;\r
+       }\r
+\r
+       public void addProgressListener(IProgressEventListener listener) {\r
+               if (progressListenerList == null)\r
+                       progressListenerList = new EventListenerList();\r
+               progressListenerList.add(IProgressEventListener.class, listener);\r
+       }\r
+\r
+       private Map<Long, BasicDBList> buildFolderReferences(BasicDBList storyFolders) {\r
+               Map<Long, BasicDBList> result = new HashMap<>();\r
+               List<BasicDBObject> storyFolderList = NoSQLUtils.asList(storyFolders);\r
+               for (BasicDBObject storyFolder : storyFolderList) {\r
+                       if (storyFolder == null || !storyFolder.containsKey(IOctopusAPI.ID))\r
+                               continue;\r
+                       BasicDBObject storyFolderWithStoryIds = queryStoryFolder(storyFolder, FIELDS_STORYFOLDER_STORYIDS);\r
+                       long storyFolderId = storyFolderWithStoryIds.getLong(IOctopusAPI.ID);\r
+                       List<BasicDBObject> stories = NoSQLUtils.asList(storyFolderWithStoryIds, IOctopusAPI.STORIES);\r
+                       if (stories == null)\r
+                               continue;\r
+\r
+                       folderIDs.add(storyFolderId);\r
+\r
+                       long position = 1;\r
+                       for (BasicDBObject story : stories) {\r
+                               long storyId = story.getLong(IOctopusAPI.ID);\r
+\r
+                               storyIDs.add(storyId);\r
+\r
+                               BasicDBList references = result.get(storyId);\r
+                               if (references == null) {\r
+                                       references = new BasicDBList();\r
+                                       result.put(storyId, references);\r
+                               }\r
+                               references.add(new BasicDBObject(IOctopusAPI.ID, storyFolderId).append(IOctopusAPI.POSITION, position++));\r
+                       }\r
+               }\r
+               return result;\r
+       }\r
+\r
+       private Map<Long, BasicDBList> buildRundownReferences(BasicDBList rundowns) {\r
+               Map<Long, BasicDBList> result = new HashMap<>();\r
+               List<BasicDBObject> rundownsList = NoSQLUtils.asList(rundowns);\r
+               for (BasicDBObject rundown : rundownsList) {\r
+                       if (rundown == null || !rundown.containsKey(IOctopusAPI.ID))\r
+                               continue;\r
+\r
+                       logger.info("Processing rundown {}", rundown.get(IOctopusAPI.NAME));\r
+                       BasicDBObject rundownWithStoryids = queryRundown(rundown, FIELDS_RUNDOWN_STORYIDS);\r
+                       // TODO ez neha null?\r
+                       long rundownId = rundownWithStoryids.getLong(IOctopusAPI.ID);\r
+                       List<BasicDBObject> slugs = NoSQLUtils.asList(rundownWithStoryids, IOctopusAPI.SLUGS);\r
+                       if (slugs == null)\r
+                               continue;\r
+\r
+                       rundownIDs.add(rundownId);\r
+\r
+                       for (BasicDBObject slug : slugs) {\r
+                               if (!slug.containsKey(IOctopusAPI.STORYID))\r
+                                       continue;\r
+                               long storyId = slug.getLong(IOctopusAPI.STORYID);\r
+\r
+                               storyIDs.add(storyId);\r
+\r
+                               BasicDBList references = result.get(storyId);\r
+                               if (references == null) {\r
+                                       references = new BasicDBList();\r
+                                       result.put(storyId, references);\r
+                               }\r
+                               long position = slug.getLong(IOctopusAPI.POSITION);\r
+                               if (slug.containsKey(IOctopusAPI.POSITION))\r
+                                       position = slug.getLong(IOctopusAPI.POSITION);\r
+                               references.add(new BasicDBObject(IOctopusAPI.ID, rundownId).append(IOctopusAPI.POSITION, position));\r
+                       }\r
+                       logger.info("Actual story amount {}", storyIDs.size());\r
+               }\r
+               return result;\r
+       }\r
+\r
+       public void clear() {\r
+               db.getCollection(IOctopusAPI.RUNDOWN_COLLECTION).remove();\r
+               db.getCollection(IOctopusAPI.FOLDER_COLLECTION).remove();\r
+               db.getCollection(IOctopusAPI.STORY_COLLECTION).remove();\r
+       }\r
+\r
+       private void deleteDiff(Set<Long> oldIDs, Set<Long> newIDs, String collectionName) {\r
+               if (oldIDs == null || oldIDs.size() == 0)\r
+                       return;\r
+               if (newIDs != null && newIDs.size() > 0)\r
+                       oldIDs.removeAll(newIDs);\r
+\r
+               if (disableWrite)\r
+                       return;\r
+\r
+               DBCollection collection = db.getCollection(collectionName);\r
+               for (long id : oldIDs) {\r
+                       logger.info("Deleting {} from {}", id, collectionName);\r
+                       collection.remove(new BasicDBObject(IOctopusAPI.ID, id));\r
+               }\r
+       }\r
+\r
+       public void execute(boolean includeArchived) throws Exception {\r
+               this.includeArchived = includeArchived;\r
+               logger.trace(STARTING);\r
+               // current = korábbi szinkronizálás\r
+               currentRundowns = getCurrentIDs(IOctopusAPI.RUNDOWN_COLLECTION);\r
+               currentFolder = getCurrentIDs(IOctopusAPI.FOLDER_COLLECTION);\r
+               currentStories = getCurrentIDs(IOctopusAPI.STORY_COLLECTION);\r
+\r
+               BasicDBList rundowns = null;\r
+               BasicDBList storyFolders = null;\r
+               try {\r
+                       rundowns = queryBuildRefRundowns();\r
+                       storyFolders = queryBuildRefFolders();\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       throw e;\r
+               }\r
+\r
+               objectCount = rundownIDs.size() + folderIDs.size() + storyIDs.size();\r
+\r
+               storeStories();\r
+               storeRundowns(rundowns);\r
+               storeStoryFolders(storyFolders);\r
+\r
+               deleteDiff(currentRundowns.keySet(), rundownIDs, IOctopusAPI.RUNDOWN_COLLECTION);\r
+               deleteDiff(currentFolder.keySet(), folderIDs, IOctopusAPI.FOLDER_COLLECTION);\r
+               deleteDiff(currentStories.keySet(), storyIDs, IOctopusAPI.STORY_COLLECTION);\r
+               logger.trace(FINISHED);\r
+       }\r
+\r
+       private String extractContent(BasicDBObject content) {\r
+               String scriptContent = "";\r
+               if (!content.containsKey(IOctopusAPI.TYPE))\r
+                       return scriptContent;\r
+               String type = content.getString(IOctopusAPI.TYPE);\r
+               switch (type) {\r
+               case IOctopusAPI.TEXT: {\r
+                       if (content.containsKey(IOctopusAPI.TEXT)) {\r
+                               String text = content.getString(IOctopusAPI.TEXT);\r
+                               if (text != null)\r
+                                       scriptContent += String.format("%s%s", text.replaceAll(SIMPLE_LINEFEED, LINEFEED), LINEFEED);\r
+                       }\r
+                       break;\r
+               }\r
+               case IOctopusAPI.MOS: {\r
+                       BasicDBObject mosObject = NoSQLUtils.asDBObject(content, IOctopusAPI.OBJECT);\r
+                       if (mosObject != null && !mosObject.isEmpty()) {\r
+                               String xml = NoSQLUtils.asString(mosObject, IOctopusAPI.XML);\r
+                               if (xml != null) {\r
+                                       int pos1 = xml.indexOf(MOS_ABSTRACT) + MOS_ABSTRACT.length();\r
+                                       int pos2 = xml.indexOf(MOS_ABSTRACT_END);\r
+\r
+                                       if (pos1 > -1 && pos2 > -1) {\r
+                                               scriptContent += String.format("%s %s%s", MOSLABEL, xml.substring(pos1, pos2), LINEFEED);\r
+                                       }\r
+                               }\r
+                       }\r
+                       break;\r
+               }\r
+               default: {\r
+                       if (content.containsKey(IOctopusAPI.CONTENT)) {\r
+                               List<BasicDBObject> innerContents = NoSQLUtils.asList(content, IOctopusAPI.CONTENT);\r
+                               if (innerContents != null) {\r
+                                       for (BasicDBObject actualInnerContent : innerContents) {\r
+                                               if (actualInnerContent != null && actualInnerContent.isEmpty())\r
+                                                       scriptContent += extractContent(actualInnerContent);\r
+                                       }\r
+                               }\r
+                       }\r
+                       break;\r
+               }\r
+               }\r
+               return scriptContent;\r
+       }\r
+\r
+       /***\r
+        * Get all custom columns label/non-null-value pair as map\r
+        *\r
+        * @param story\r
+        * @return\r
+        */\r
+       private BasicDBObject getCustomColumns(BasicDBObject story) {\r
+               BasicDBObject result = new BasicDBObject();\r
+               List<BasicDBObject> customColumns = NoSQLUtils.asList(story, IOctopusAPI.CUSTOM_COLUMNS);\r
+               if (customColumns == null)\r
+                       return null;\r
+               for (BasicDBObject customColumn : customColumns) {\r
+                       String currentName = NoSQLUtils.asString(customColumn, IOctopusAPI.LABEL);\r
+                       if (currentName == null)\r
+                               continue;\r
+                       String currentValue = NoSQLUtils.asString(customColumn, IOctopusAPI.VALUE);\r
+                       if (currentValue == null)\r
+                               continue;\r
+                       result.put(currentName, currentValue);\r
+               }\r
+               return result;\r
+       }\r
+\r
+       private String getDescriptions(BasicDBObject story) {\r
+               StringBuilder result = new StringBuilder();\r
+               List<BasicDBObject> descriptions = NoSQLUtils.asList(story, IOctopusAPI.DESCRIPTIONS);\r
+               if (descriptions == null)\r
+                       return null;\r
+               for (BasicDBObject description : descriptions) {\r
+                       String currentDesc = NoSQLUtils.asString(description, IOctopusAPI.TEXT);\r
+                       if (currentDesc == null)\r
+                               continue;\r
+                       result.append(currentDesc);\r
+               }\r
+               return result.toString();\r
+       }\r
+\r
+       private BasicDBList extractRelevantMOSObjects(BasicDBObject story) {\r
+               List<BasicDBObject> mosObjects = NoSQLUtils.asList(story, IOctopusAPI.MOS_OBJECTS);\r
+               if (mosObjects == null)\r
+                       return null;\r
+\r
+               Map<String, String> mosLabels = extractScriptMosObjectIDs(story);\r
+               // logger.info(Arrays.deepToString(new ArrayList<>(mosLabels.keySet())));\r
+               BasicDBList result = null;\r
+               for (BasicDBObject mosObject : mosObjects) {\r
+                       if (!mosObject.containsKey(IOctopusAPI.MOS_ID))\r
+                               continue;\r
+                       String mosId = mosObject.getString(IOctopusAPI.MOS_ID);\r
+                       if (!IOctopusAPI.NEXIO_MOS.equals(mosId))\r
+                               continue;\r
+                       String objId = mosObject.getString(IOctopusAPI.OBJ_ID);\r
+                       if (objId == null)\r
+                               continue;\r
+\r
+                       // logger.info("MOS ID: {}", objId);\r
+\r
+                       MetadataType metadataType = MetadataTypeDetector.GuessMetadataType(objId);\r
+                       if (!MetadataType.OctopusPlaceholder.equals(metadataType) && !MetadataType.OctopusStory.equals(metadataType))\r
+                               continue;\r
+                       if (result == null)\r
+                               result = new BasicDBList();\r
+\r
+                       String label = mosLabels.get(objId);\r
+                       if (StringUtils.isNotBlank(label))\r
+                               mosObject.append(IOctopusAPI.LABEL, label);\r
+                       result.add(mosObject);\r
+               }\r
+               return result;\r
+       }\r
+\r
+       private String extractScriptContent(BasicDBObject story) {\r
+               BasicDBObject script = NoSQLUtils.asDBObject(story, IOctopusAPI.SCRIPT);\r
+               if (script == null || script.isEmpty())\r
+                       return null;\r
+\r
+               List<BasicDBObject> body = NoSQLUtils.asList(script, IOctopusAPI.BODY);\r
+               if (body == null || body.size() == 0)\r
+                       return null;\r
+\r
+               StringBuilder sb = new StringBuilder();\r
+\r
+               for (BasicDBObject bodyItem : body) {\r
+                       if (bodyItem.containsKey(IOctopusAPI.TYPE)) {\r
+                               sb.append(bodyItem.getString(IOctopusAPI.TYPE));\r
+                               sb.append(LINEFEED);\r
+                       }\r
+                       if (bodyItem.containsKey(IOctopusAPI.LABEL)) {\r
+                               sb.append(bodyItem.getString(IOctopusAPI.LABEL));\r
+                               sb.append(LINEFEED);\r
+                       }\r
+                       List<BasicDBObject> contents = NoSQLUtils.asList(bodyItem, IOctopusAPI.CONTENT);\r
+                       if (contents == null)\r
+                               continue;\r
+                       for (BasicDBObject content : contents) {\r
+                               sb.append(extractContent(content));\r
+                       }\r
+               }\r
+               return sb.length() == 0 ? null : sb.toString();\r
+       }\r
+\r
+       private Map<String, String> extractScriptMosObjectIDs(BasicDBObject story) {\r
+               BasicDBObject script = NoSQLUtils.asDBObject(story, IOctopusAPI.SCRIPT);\r
+               if (script == null || script.isEmpty())\r
+                       return null;\r
+\r
+               List<BasicDBObject> body = NoSQLUtils.asList(script, IOctopusAPI.BODY);\r
+               if (body == null || body.size() == 0)\r
+                       return null;\r
+\r
+               Map<String, String> result = new HashMap<>();\r
+\r
+               for (BasicDBObject bodyItem : body) {\r
+                       String label = bodyItem.getString(IOctopusAPI.LABEL);\r
+                       if (StringUtils.isBlank(label))\r
+                               continue;\r
+                       BasicDBObject clip = NoSQLUtils.asDBObject(bodyItem, IOctopusAPI.CLIP);\r
+                       if (clip == null)\r
+                               continue;\r
+                       BasicDBObject obj = NoSQLUtils.asDBObject(clip, IOctopusAPI.OBJECT);\r
+                       if (obj == null)\r
+                               continue;\r
+                       String mosId = obj.getString(IOctopusAPI.MOS_ID);\r
+                       if (!IOctopusAPI.NEXIO_MOS.equals(mosId))\r
+                               continue;\r
+                       String objId = obj.getString(IOctopusAPI.OBJ_ID);\r
+                       if (objId == null)\r
+                               continue;\r
+                       result.put(objId, label);\r
+\r
+               }\r
+               return result;\r
+       }\r
+\r
+       private void fireProgressEvent() {\r
+               currentObjectIndex++;\r
+               // logger.info("currentObjectIndex {}", currentObjectIndex);\r
+               int progress = currentObjectIndex * 100 / objectCount;\r
+               if (progress != progressEvent.getProgress()) {\r
+                       progressEvent.setProgress(progress);\r
+                       fireProgressEvent(progressEvent);\r
+               }\r
+       }\r
+\r
+       private void fireProgressEvent(ProgressEvent evt) {\r
+               logger.debug("Progress changed to " + evt.getProgress() + "%");\r
+               if (progressListenerList == null)\r
+                       return;\r
+               Object[] listeners = progressListenerList.getListenerList();\r
+               for (int i = 0; i < listeners.length; i += 2) {\r
+                       if (listeners[i] == IProgressEventListener.class)\r
+                               ((IProgressEventListener) listeners[i + 1]).progressChanged(evt);\r
+               }\r
+       }\r
+\r
+       public Map<Long, Object> getCurrentIDs(String name) {\r
+               Map<Long, Object> result = new HashMap<>();\r
+\r
+               DBCursor cursor = db.getCollection(name).find(new BasicDBObject(), new BasicDBObject(IOctopusAPI.ID, 1));\r
+               if (cursor.hasNext()) {\r
+                       List<BasicDBObject> objects = ListUtils.cast(cursor.toArray());\r
+                       for (BasicDBObject obj : objects) {\r
+                               if (obj == null)\r
+                                       continue;\r
+                               long id = NoSQLUtils.asLong(obj, IOctopusAPI.ID);\r
+                               if (id == 0)\r
+                                       continue;\r
+                               Object _id = obj.getID();\r
+                               if (_id == null)\r
+                                       continue;\r
+                               result.put(id, _id);\r
+                       }\r
+               }\r
+               return result;\r
+       }\r
+\r
+       BasicDBObject getDbObject(String json) {\r
+               BasicDBObject result = (BasicDBObject) JSONUtil.jsonToDbObject(json);\r
+\r
+               if (result == null)\r
+                       throw new NullPointerException("API Result is null!");\r
+\r
+               if (result.containsKey("exception")) {\r
+                       BasicDBObject e = (BasicDBObject) result.get("exception");\r
+                       // throw new RuntimeException(e.getString("message"));\r
+                       logger.error("Query error: {}", e.getString("message"));\r
+                       return null;\r
+               }\r
+               return result;\r
+       }\r
+\r
+       private Builder query(String path, String fields) {\r
+               ResteasyWebTarget target = webTarget.path(path).queryParam(FIELDS, fields);\r
+               Builder result = target.request();\r
+               return result;\r
+       }\r
+\r
+       private BasicDBList queryBuildRefFolders() {\r
+               BasicDBList storyFolders;\r
+               logger.info("Fetch story folders");\r
+               storyFolders = queryStoryFolders();\r
+               logger.info("Story folders amount {}", storyFolders.size());\r
+\r
+               logger.info("Fetch folder story references");\r
+               storyStoryFolders = buildFolderReferences(storyFolders);\r
+               logger.info("Actual stories amount {}", storyIDs.size());\r
+               return storyFolders;\r
+       }\r
+\r
+       private BasicDBList queryBuildRefRundowns() {\r
+               BasicDBList rundowns;\r
+               logger.info("Fetch rundowns");\r
+               rundowns = queryRundowns();\r
+               logger.info("Rundowns amount {}", rundowns.size());\r
+\r
+               logger.info("Fetch rundown story references");\r
+               storyRundowns = buildRundownReferences(rundowns);\r
+               logger.info("Actual stories amount {}", storyIDs.size());\r
+               return rundowns;\r
+       }\r
+\r
+       public BasicDBObject queryRundown(BasicDBObject rundown, String fields) {\r
+               logger.trace(ENTER);\r
+               BasicDBObject result = null;\r
+               long id = NoSQLUtils.asLong(rundown, IOctopusAPI.ID);\r
+               Response response = query(String.format("%s/%d", RUNDOWN, id), fields).get();\r
+               String json = response.readEntity(String.class);\r
+               BasicDBObject resultObject = getDbObject(json);\r
+               if (resultObject == null)\r
+                       logger.error("Rundown {} {} is not available", id, rundown.getString(IOctopusAPI.NAME));\r
+               else\r
+                       result = NoSQLUtils.asDBObject(resultObject, RESULT);\r
+               logger.trace(EXIT);\r
+               return result;\r
+       }\r
+\r
+       public BasicDBList queryRundowns() {\r
+               logger.trace(ENTER);\r
+               BasicDBList result = null;\r
+               Builder query = query(RUNDOWN, FIELDS_RUNDOWN);\r
+               Response response = null;\r
+               if (includeArchived) {\r
+                       response = query.post(Entity.entity(new BasicDBObject(FILTER, new BasicDBObject(ARCHIVED, true)).toString(), MediaType.APPLICATION_JSON));\r
+               } else {\r
+                       response = query.get();\r
+               }\r
+\r
+               String json = response.readEntity(String.class);\r
+               BasicDBObject resultObject = getDbObject(json);\r
+               if (resultObject != null)\r
+                       result = NoSQLUtils.asDBList(resultObject, RESULT);\r
+\r
+               if (maxPastDays > 0 && result != null) {\r
+                       logger.info("Using maxPastDays {} limit", maxPastDays);\r
+                       List<BasicDBObject> rundownList = NoSQLUtils.asList(result);\r
+                       result = new BasicDBList();\r
+                       // "2022-12-02T19:10:00.000+01:00"\r
+                       LocalDate oldestScheduleDate = LocalDate.now().minus(Period.ofDays(maxPastDays + 1));\r
+                       for (BasicDBObject rundown : rundownList) {\r
+                               String scheduledStart = rundown.getString(SCHEDULEDSTART);\r
+                               if (scheduledStart == null)\r
+                                       continue;\r
+                               LocalDate scheduleDate = LocalDate.parse(scheduledStart, DateTimeFormatter.ISO_OFFSET_DATE_TIME);\r
+                               if (scheduleDate.isAfter(oldestScheduleDate)) {\r
+                                       result.add(rundown);\r
+                               }\r
+\r
+                       }\r
+               }\r
+\r
+               logger.trace(EXIT);\r
+               return result;\r
+       }\r
+\r
+       public BasicDBObject queryStory(long storyID) {\r
+               logger.trace(ENTER);\r
+               BasicDBObject result = null;\r
+               Response response = query(String.format("%s/%d", STORY, storyID), FIELDS_STORIES).get();\r
+               String json = response.readEntity(String.class);\r
+               BasicDBObject resultObject = getDbObject(json);\r
+               if (resultObject == null)\r
+                       logger.error("Story {} is not available", storyID);\r
+               else\r
+                       result = NoSQLUtils.asDBObject(resultObject, RESULT);\r
+               logger.trace(EXIT);\r
+               return result;\r
+       }\r
+\r
+       public BasicDBObject queryStoryFolder(BasicDBObject storyFolder, String fields) {\r
+               logger.trace(ENTER);\r
+               BasicDBObject result = null;\r
+               long id = NoSQLUtils.asLong(storyFolder, IOctopusAPI.ID);\r
+               Response response = query(String.format("%s/%d", STORY_FOLDER, id), fields).get();\r
+               String json = response.readEntity(String.class);\r
+               BasicDBObject resultObject = getDbObject(json);\r
+               if (resultObject == null)\r
+                       logger.error("StoryFolder {} {} is not available", id, storyFolder.getString(IOctopusAPI.NAME));\r
+               else\r
+                       result = NoSQLUtils.asDBObject(resultObject, RESULT);\r
+               logger.trace(EXIT);\r
+               return result;\r
+       }\r
+\r
+       public BasicDBList queryStoryFolders() {\r
+               logger.trace(ENTER);\r
+               BasicDBList result = null;\r
+               Response response = query(STORY_FOLDER, FIELDS_STORYFOLDER).get();\r
+               String json = response.readEntity(String.class);\r
+               BasicDBObject resultObject = getDbObject(json);\r
+               if (resultObject != null)\r
+                       result = NoSQLUtils.asDBList(resultObject, RESULT);\r
+\r
+               // /* teszt */\r
+               // List<BasicDBObject> list = NoSQLUtils.asList(result);\r
+               // for (BasicDBObject actual : list) {\r
+               // String fullName = concatParentsToStoryFolder(actual,\r
+               // actual.getString(IOctopusAPI.NAME));\r
+               // //logger.info("Checking StoryFolder {}", fullName);\r
+               // actual.remove(IOctopusAPI.NAME);\r
+               // actual.append(IOctopusAPI.NAME, fullName);\r
+               // }\r
+               //\r
+               logger.trace(EXIT);\r
+               return result;\r
+       }\r
+\r
+       public void removeProgressListener(IProgressEventListener listener) {\r
+               progressListenerList.remove(IProgressEventListener.class, listener);\r
+       }\r
+\r
+       void setObjectID(Map<Long, Object> current, long id, BasicDBObject objectToSave) {\r
+               Object _id = current.get(id);\r
+               if (_id == null)\r
+                       return;\r
+               objectToSave.put(IOctopusAPI._ID, _id);\r
+       }\r
+\r
+       private void storeRundown(BasicDBObject rundown) {\r
+               logger.trace(ENTER);\r
+               String name = rundown.containsKey(IOctopusAPI.NAME) ? rundown.getString(IOctopusAPI.NAME) : null;\r
+               logger.debug("Storing rundown {} {}", name, rundown.get(IOctopusAPI.SCHEDULED_START));\r
+               Date scheduledStart = toDate(rundown, IOctopusAPI.SCHEDULED_START);\r
+               if (scheduledStart != null && scheduledStart.after(zeroDate.getTime())) {\r
+                       rundown.put(IOctopusAPI.SCHEDULED_START, toDate(rundown, IOctopusAPI.SCHEDULED_START));\r
+                       rundown.put(IOctopusAPI.MODIFIED, toDate(rundown, IOctopusAPI.MODIFIED));\r
+                       DBCollection collection = db.getCollection(IOctopusAPI.RUNDOWN_COLLECTION);\r
+                       long rundownID = NoSQLUtils.asLong(rundown, IOctopusAPI.ID);\r
+                       setObjectID(currentRundowns, rundownID, rundown);\r
+                       if (!disableWrite)\r
+                               collection.save(rundown);\r
+               }\r
+               logger.trace(ENTER);\r
+       }\r
+\r
+       private void storeRundowns(BasicDBList rundowns) {\r
+               logger.trace(ENTER);\r
+               List<BasicDBObject> rundownsList = NoSQLUtils.asList(rundowns);\r
+               for (BasicDBObject rundown : rundownsList) {\r
+                       try {\r
+                               storeRundown(rundown);\r
+                       } catch (Exception e) {\r
+                               logger.catching(e);\r
+                               throw e;\r
+                       }\r
+                       fireProgressEvent();\r
+               }\r
+               logger.trace(ENTER);\r
+       }\r
+\r
+       private void storeStories() {\r
+               logger.trace(ENTER);\r
+               for (long storyID : storyIDs) {\r
+                       // logger.info("Storing story {}", storyID);\r
+                       try {\r
+                               BasicDBObject story = queryStory(storyID);\r
+                               if (story != null)\r
+                                       storeStory(story);\r
+                       } catch (Exception e) {\r
+                               logger.catching(e);\r
+                               throw e;\r
+                       }\r
+                       fireProgressEvent();\r
+               }\r
+               logger.trace(ENTER);\r
+       }\r
+\r
+       private void storeStory(BasicDBObject story) {\r
+               logger.trace(ENTER);\r
+               if (!story.containsKey(IOctopusAPI.ID)) {\r
+                       logger.error("Missing id in story {}", story.toPrettyString(null));\r
+                       return;\r
+               }\r
+\r
+               normalizeStory(story);\r
+\r
+               long storyID = story.getLong(IOctopusAPI.ID);\r
+               BasicDBList rundownRef = storyRundowns.get(storyID);\r
+               BasicDBList storyFolderRef = storyStoryFolders.get(storyID);\r
+               DBCollection collection = db.getCollection(IOctopusAPI.STORY_COLLECTION);\r
+               if (rundownRef != null)\r
+                       story.put(IOctopusAPI.REF_RUNDOWN, rundownRef);\r
+               if (storyFolderRef != null)\r
+                       story.put(IOctopusAPI.REF_STORYFOLDER, storyFolderRef);\r
+\r
+               logger.debug(SAVING_STORY_ID, storyID);\r
+               setObjectID(currentStories, storyID, story);\r
+               if (!disableWrite)\r
+                       collection.save(story);\r
+               logger.trace(EXIT);\r
+       }\r
+\r
+       public void normalizeStory(BasicDBObject story) {\r
+               story.put(IOctopusAPI.MODIFIED, toDate(story, IOctopusAPI.MODIFIED));\r
+               story.put(IOctopusAPI.SCHEDULEFROM, toDate(story, IOctopusAPI.SCHEDULEFROM));\r
+               story.put(IOctopusAPI.SCHEDULETO, toDate(story, IOctopusAPI.SCHEDULETO));\r
+\r
+               String scriptContent = extractScriptContent(story);\r
+               story.put(IOctopusAPI.SCRIPT_CONTENT, scriptContent);\r
+\r
+               BasicDBList modifiedMOS = extractRelevantMOSObjects(story);\r
+               if (modifiedMOS == null || modifiedMOS.isEmpty())\r
+                       story.remove(IOctopusAPI.MOS_OBJECTS);\r
+               else\r
+                       story.put(IOctopusAPI.MOS_OBJECTS, modifiedMOS);\r
+\r
+               BasicDBObject customColumns = getCustomColumns(story);\r
+               // logger.info(customColumns.toPrettyString(""));\r
+               String parentStoryId = NoSQLUtils.asString(customColumns, "ParentStoryID");\r
+               if (parentStoryId == null) {\r
+                       parentStoryId = story.getString(IOctopusAPI.ID);\r
+               }\r
+               story.append(IOctopusAPI.PARENT_STORY_ID, parentStoryId);\r
+               String location = NoSQLUtils.asString(customColumns, IOctopusAPI.LOCATION_HU);\r
+               if (location != null && location.trim().length() > 0)\r
+                       story.append(IOctopusAPI.LOCATION, location);\r
+\r
+               String descriptions = getDescriptions(story);\r
+               if (descriptions != null && descriptions.trim().length() > 0)\r
+                       story.append(IOctopusAPI.DESCRIPTIONS, descriptions);\r
+\r
+               story.remove(IOctopusAPI.CUSTOM_COLUMNS);\r
+               story.remove(IOctopusAPI.SCRIPT);\r
+               // story.remove(IOctopusAPI.DESCRIPTIONS);\r
+       }\r
+\r
+       private void storeStoryFolder(BasicDBObject storyFolder) {\r
+               logger.trace(ENTER);\r
+               storyFolder.put(IOctopusAPI.MODIFIED, toDate(storyFolder, IOctopusAPI.MODIFIED));\r
+               DBCollection collection = db.getCollection(IOctopusAPI.FOLDER_COLLECTION);\r
+               String name = storyFolder.getString(IOctopusAPI.NAME);\r
+               logger.debug("Storing story folder {}", name);\r
+               long folderID = NoSQLUtils.asLong(storyFolder, IOctopusAPI.ID);\r
+               setObjectID(currentFolder, folderID, storyFolder);\r
+               if (!disableWrite)\r
+                       collection.save(storyFolder);\r
+               logger.trace(EXIT);\r
+       }\r
+\r
+       private void storeStoryFolders(BasicDBList storyFolders) {\r
+               logger.trace(ENTER);\r
+               List<BasicDBObject> storyFolderList = NoSQLUtils.asList(storyFolders);\r
+               for (BasicDBObject storyFolder : storyFolderList) {\r
+                       try {\r
+                               storeStoryFolder(storyFolder);\r
+                       } catch (Exception e) {\r
+                               logger.catching(e);\r
+                               throw e;\r
+                       }\r
+                       fireProgressEvent();\r
+               }\r
+               logger.trace(EXIT);\r
+       }\r
+\r
+       private Date toDate(BasicDBObject obj, String name) {\r
+               Date result = null;\r
+               if (obj.containsKey(name)) {\r
+                       String dt = obj.getString(name);\r
+                       if (dt != null) {\r
+                               // create jodatime from date\r
+                               DateTime jdt = new DateTime(dt);\r
+                               result = jdt.toDate();\r
+                       }\r
+               }\r
+               return result;\r
+       }\r
+\r
+}\r
diff --git a/server/-product/production/HIRTV/jobs/steps/shared/PlanAirExtensions.java b/server/-product/production/HIRTV/jobs/steps/shared/PlanAirExtensions.java
new file mode 100644 (file)
index 0000000..ef86f0a
--- /dev/null
@@ -0,0 +1,300 @@
+package user.jobengine.server.steps.shared;\r
+\r
+import java.io.StringWriter;\r
+import java.sql.Connection;\r
+import java.sql.DriverManager;\r
+import java.sql.ResultSetMetaData;\r
+import java.text.SimpleDateFormat;\r
+import java.util.ArrayList;\r
+import java.util.Date;\r
+import java.util.List;\r
+\r
+import javax.xml.parsers.DocumentBuilder;\r
+import javax.xml.parsers.DocumentBuilderFactory;\r
+import javax.xml.parsers.ParserConfigurationException;\r
+import javax.xml.transform.OutputKeys;\r
+import javax.xml.transform.Transformer;\r
+import javax.xml.transform.TransformerException;\r
+import javax.xml.transform.TransformerFactory;\r
+import javax.xml.transform.dom.DOMSource;\r
+import javax.xml.transform.stream.StreamResult;\r
+\r
+import org.apache.commons.lang.StringUtils;\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+import org.w3c.dom.DOMImplementation;\r
+import org.w3c.dom.Document;\r
+import org.w3c.dom.Node;\r
+\r
+import user.commons.mediatool.Timecode;\r
+import user.commons.mediatool.Timecode.Type;\r
+import user.jobengine.db.IItemManager;\r
+import user.jobengine.db.IResultSetConsumer;\r
+import user.jobengine.db.IStatementDecorator;\r
+\r
+public class PlanAirExtensions {\r
+\r
+       private static MetadataType TRAFFIC_MATERIAL;\r
+       private static MetadataType TRAFFIC_AD;\r
+       private static MetadataType TRAFFIC_PROMO;\r
+\r
+       PlanAirExtensions() {\r
+               TRAFFIC_MATERIAL = MetadataType.TrafficMaterial;\r
+               TRAFFIC_AD = MetadataType.TrafficAD;\r
+               TRAFFIC_PROMO = MetadataType.TrafficPromo;\r
+       }\r
+\r
+       private static final Logger logger = LogManager.getLogger();\r
+       // @Operation int, @@@Options int, @@ItemID int, @@IntParam1 int=Null,\r
+       // @@IntParam2 int=Null, @@IntParam3 int=Null,\r
+       // @@StrParam1 varchar(200)=Null, @@StrParam2 varchar(max)=Null, @@DateParam1\r
+       // datetime=Null, @@DateParam2 datetime=Null\r
+       private static final String MATERIAL_SQL = "{call dbo.clIFsp_EC_MAM(1002, Null, Null, Null, Null, Null, ?)}";// musorid\r
+       // item.v_ProgrammeID = (int)ReadInt(reader, ref f);\r
+       // item.v_Live = (bool)ReadBool(reader, ref f);\r
+       // item.v_EpisodeID = ReadString(reader, ref f);\r
+       // item.v_VariantID = ReadInt(reader, ref f);\r
+       // item.v_MediaID = ReadString(reader, ref f);\r
+       // item.v_VariantTypeID = ReadInt(reader, ref f);\r
+       // item.v_ProgTitle = ReadString(reader, ref f);\r
+       // item.v_EpTitle = ReadString(reader, ref f);\r
+       // item.v_Episode = ReadShort(reader, ref f);\r
+       // item.v_VariantType = ReadString(reader, ref f);\r
+       // item.v_VariantKeywords = ReadString(reader, ref f);\r
+       // item.v_VariantLengthTC = ReadString(reader, ref f);\r
+       // item.v_VariantLengthFrame = ReadInt(reader, ref f);\r
+       // item.v_VariantNrSegments = ReadInt(reader, ref f);\r
+       // item.v_FirstBroadcastDate = ReadDateTime(reader, ref f);\r
+       // item.v_NextBroadcastDate = ReadDateTime(reader, ref f);\r
+       // item.v_OkForAir = ReadBool(reader, ref f);\r
+       // item.v_ForTransm = ReadBool(reader, ref f);\r
+\r
+       private static final String MATERIAL_SEGMENTS_SQL = "{call dbo.clIFsp_EC_MAM(1010, Null, ?)}";// variantid\r
+       // item.v_SegID = (int)ReadInt(reader, ref f);\r
+       // item.v_VariantID = ReadInt(reader, ref f);\r
+       // item.v_SegTitle = ReadString(reader, ref f);\r
+       // item.v_SegKeyWords = ReadString(reader, ref f);\r
+       // item.v_SegNumber = ReadInt(reader, ref f);\r
+       // item.v_TcIn = ReadInt(reader, ref f);\r
+       // item.v_TcOut = ReadInt(reader, ref f);\r
+       // item.v_Duration = ReadInt(reader, ref f);\r
+       // item.v_TcInTC = ReadString(reader, ref f);\r
+       // item.v_TcOutTC = ReadString(reader, ref f);\r
+       // item.v_DurationTC = ReadString(reader, ref f);\r
+       // item.v_Dropable = ReadBool(reader, ref f);\r
+\r
+       private static final String PROMO_SQL = "{call dbo.clIFsp_EC_MAM(2002, Null, Null, Null, Null, Null, ?)}";\r
+       // item.t_SpotID = (int)ReadInt(reader, ref f);\r
+       // item.t_MediaID = ReadString(reader, ref f);\r
+       // item.v_Title = ReadString(reader, ref f);\r
+       // item.v_PromoType = ReadString(reader, ref f);\r
+       // item.v_ProgTitle = ReadString(reader, ref f);\r
+       // item.v_Episode = ReadShort(reader, ref f);\r
+       // item.t_PSStart = ReadDateTime(reader, ref f);\r
+       // item.t_PSEnd = ReadDateTime(reader, ref f);\r
+       // item.v_EstimatedDuration = ReadInt(reader, ref f);\r
+       // item.t_TcIn = ReadInt(reader, ref f);\r
+       // item.t_TcOut = ReadInt(reader, ref f);\r
+       // item.t_Duration = ReadInt(reader, ref f);\r
+       // item.v_TcIn = ReadString(reader, ref f);\r
+       // item.v_TcOut = ReadString(reader, ref f);\r
+       // item.v_Duration = ReadString(reader, ref f);\r
+       // item.v_Stations = ReadString(reader, ref f);\r
+       // item.t_OkForAir = ReadBool(reader, ref f);\r
+       // item.v_OkForAirs = ReadString(reader, ref f);\r
+       // item.v_IsInactive = ReadBool(reader, ref f);\r
+       private static final String AD_SQL = "{call dbo.clIFsp_EC_MAM(3002, Null, Null, Null, Null, Null, ?)}";\r
+       // item.t_SpotID = (int)ReadInt(reader, ref f);\r
+       // item.t_MediaID = ReadString(reader, ref f);\r
+       // item.v_Title = ReadString(reader, ref f);\r
+       // item.t_Advertiser = ReadString(reader, ref f);\r
+       // item.v_EstimatedDuration = ReadInt(reader, ref f);\r
+       // item.t_TcIn = ReadInt(reader, ref f);\r
+       // item.t_TcOut = ReadInt(reader, ref f);\r
+       // item.t_Duration = ReadInt(reader, ref f);\r
+       // item.v_TcIn = ReadString(reader, ref f);\r
+       // item.v_TcOut = ReadString(reader, ref f);\r
+       // item.v_Duration = ReadString(reader, ref f);\r
+       // item.t_OkForAir = ReadBool(reader, ref f);\r
+       // item.v_OkForAirs = ReadString(reader, ref f);\r
+\r
+       private static final String SQLSERVER_JDBC_SQL_SERVER_DRIVER = "com.microsoft.sqlserver.jdbc.SQLServerDriver";\r
+       private static final String HYPHEN_SPACES = " - ";\r
+       private static Connection connection;\r
+\r
+       private static void appendInstanceData(Document doc, Node node, String name, String deviceID, Timecode tcIn, Timecode tcOut) {\r
+               node.appendChild(doc.createElement("Long_File_Id")).appendChild(doc.createTextNode(name));\r
+               node.appendChild(doc.createElement("Device_Id")).appendChild(doc.createTextNode(deviceID));\r
+               node.appendChild(doc.createElement("Timecode_In")).appendChild(doc.createTextNode(tcIn.toString("")));\r
+               node.appendChild(doc.createElement("Timecode_Out")).appendChild(doc.createTextNode(tcOut.toString("")));\r
+               node.appendChild(doc.createElement("Quality_Check")).appendChild(doc.createTextNode(new SimpleDateFormat("dd/MM/yyyy").format(new Date())));\r
+       }\r
+\r
+       private static void appendItemData(Document doc, Node node, String name, String title, Timecode duration, String type) {\r
+\r
+               node.appendChild(doc.createElement("Material_Id")).appendChild(doc.createTextNode(name));\r
+               node.appendChild(doc.createElement("Title")).appendChild(doc.createTextNode(title));\r
+               node.appendChild(doc.createElement("On_Air_Duration")).appendChild(doc.createTextNode(duration.toString("")));\r
+               node.appendChild(doc.createElement("Material_Type")).appendChild(doc.createTextNode(type));\r
+       }\r
+\r
+       private static Document createXMLDocument() throws ParserConfigurationException {\r
+               DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();\r
+               DocumentBuilder db = dbf.newDocumentBuilder();\r
+               DOMImplementation impl = db.getDOMImplementation();\r
+               Document xmlDocument = impl.createDocument(null, null, null);\r
+               return xmlDocument;\r
+       }\r
+\r
+       public static long getExistingRundownMedia(IItemManager manager, String houseid) {\r
+               final long[] result = new long[] { 0 };\r
+               StringBuilder query = new StringBuilder();\r
+               query.append("select mediaid, mediafilehouseid, filename");\r
+               query.append(" ");\r
+               query.append(String.format("from vw_rundown_items where mediafilehouseid like '%s%%'", houseid));\r
+               query.append(" ");\r
+               query.append("order by filename, mediaid");\r
+               IResultSetConsumer consumer = rs -> {\r
+                       String fileName = rs.getString("filename");\r
+                       if (houseid.equals(fileName)) {\r
+                               result[0] = rs.getLong("mediaid");\r
+                               return false;\r
+                       } else\r
+                               return true;\r
+               };\r
+               manager.executeQuery(query.toString(), consumer, null);\r
+               return result[0];\r
+       }\r
+\r
+       /*\r
+        * <?xml version="1.0" encoding="UTF-8"?> <ImportItems> <ImportItem> <Item>\r
+        * <Material_Id>XMLTEST011</Material_Id> <Title>Teszt Mozi</Title>\r
+        * <On_Air_Duration>00000914</On_Air_Duration>\r
+        * <Material_Type>PROGRAMME</Material_Type> //PROGRAMME, COMMERCIAL, JUNCTION\r
+        * </Item> <Instance> <Device_Id>ISILON</Device_Id>\r
+        * <Quality_Check>09/11/2017</Quality_Check>\r
+        * <Long_File_Id>XMLTEST011</Long_File_Id> </Instance> </ImportItem>\r
+        * </ImportItems>\r
+        */\r
+       public static String getMorpeusXML(IItemManager manager, String dbUrl, String userName, String password, String name, String deviceID) throws Exception {\r
+               String result = null;\r
+               try {\r
+                       Class.forName(SQLSERVER_JDBC_SQL_SERVER_DRIVER);\r
+\r
+                       MetadataType type = MetadataTypeDetector.GuessMetadataType(name);\r
+\r
+                       Document doc = createXMLDocument();\r
+                       Node rootNode = doc.appendChild(doc.createElement("ImportItems"));\r
+                       Node importItemNode = rootNode.appendChild(doc.createElement("ImportItem"));\r
+                       Node itemNode = importItemNode.appendChild(doc.createElement("Item"));\r
+                       Node instanceNode = importItemNode.appendChild(doc.createElement("Instance"));\r
+\r
+                       connection = DriverManager.getConnection(dbUrl, userName, password);\r
+                       // TODO hiba esetén exception\r
+                       if (MetadataType.TrafficMaterial.equals(type)) {\r
+                               manager.executeQuery(connection, MATERIAL_SQL, rs -> {\r
+                                       String progTitle = rs.getString("v_ProgTitle");\r
+                                       String epTitle = rs.getString("v_EpTitle");\r
+                                       String title = progTitle;\r
+                                       if (StringUtils.isNotBlank(epTitle))\r
+                                               title += HYPHEN_SPACES + epTitle;\r
+                                       int variantID = rs.getInt("v_VariantID");\r
+                                       List<int[]> segments = new ArrayList<>();\r
+                                       manager.executeQuery(connection, MATERIAL_SEGMENTS_SQL, rs1 -> {\r
+                                               ResultSetMetaData rsmd = rs1.getMetaData();\r
+                                               for (int i = 1; i <= rsmd.getColumnCount(); i++)\r
+                                                       System.out.println(rsmd.getColumnName(i) + " " + rsmd.getColumnTypeName(i));\r
+\r
+                                               int[] segment = new int[] { rs1.getInt("v_TcIn"), rs1.getInt("v_TcOut") };\r
+                                               segments.add(segment);\r
+                                               return true;\r
+                                       }, st -> {\r
+                                               st.setInt(1, variantID);\r
+                                       });\r
+                                       int out = segments.get(segments.size() - 1)[1];\r
+                                       int in = segments.get(0)[0];\r
+                                       appendItemData(doc, itemNode, name, title, new Timecode(out - in, Type.PAL), "PROGRAMME");\r
+                                       appendInstanceData(doc, instanceNode, name, deviceID, new Timecode(in, Type.PAL), new Timecode(out, Type.PAL));\r
+                                       return false;\r
+                               }, st -> {\r
+                                       st.setString(1, name);\r
+                               });\r
+                       } else if (MetadataType.TrafficPromo.equals(type)) {\r
+                               manager.executeQuery(connection, PROMO_SQL, rs -> {\r
+                                       String title = rs.getString("v_Title");\r
+                                       int in = rs.getInt("t_TcIn");\r
+                                       int out = rs.getInt("t_TcOut");\r
+                                       appendItemData(doc, itemNode, name, title, new Timecode(out - in, Type.PAL), "COMMERCIAL");\r
+                                       appendInstanceData(doc, instanceNode, name, deviceID, new Timecode(in, Type.PAL), new Timecode(out, Type.PAL));\r
+                                       return false;\r
+                               }, st -> {\r
+                                       st.setString(1, name);\r
+                               });\r
+                       } else if (MetadataType.TrafficAD.equals(type)) {\r
+                               manager.executeQuery(connection, AD_SQL, rs -> {\r
+                                       String title = rs.getString("v_Title");\r
+                                       int in = rs.getInt("t_TcIn");\r
+                                       int out = rs.getInt("t_TcOut");\r
+                                       appendItemData(doc, itemNode, name, title, new Timecode(out - in, Type.PAL), "JUNCTION");\r
+                                       appendInstanceData(doc, instanceNode, name, deviceID, new Timecode(in, Type.PAL), new Timecode(out, Type.PAL));\r
+                                       return false;\r
+                               }, st -> {\r
+                                       st.setString(1, name);\r
+                               });\r
+                       } else {\r
+                               return null;\r
+                       }\r
+                       result = XMLtoString(doc);\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       throw e;\r
+               } finally {\r
+                       if (connection != null)\r
+                               connection.close();\r
+               }\r
+               return result;\r
+       }\r
+\r
+       public static Connection search(Connection con, MetadataType type, IItemManager manager, String dbUrl, String userName, String password,\r
+                       IResultSetConsumer consumer, IStatementDecorator decorator) throws Exception {\r
+               try {\r
+                       Class.forName(SQLSERVER_JDBC_SQL_SERVER_DRIVER);\r
+\r
+                       if (con == null)\r
+                               connection = DriverManager.getConnection(dbUrl, userName, password);\r
+                       // TODO hiba esetén exception\r
+\r
+                       if (MetadataType.TrafficMaterial.equals(type)) {\r
+                               manager.executeQuery(connection, MATERIAL_SQL, consumer, decorator);\r
+                       } else if (MetadataType.TrafficPromo.equals(type)) {\r
+                               manager.executeQuery(connection, PROMO_SQL, consumer, decorator);\r
+                       } else if (MetadataType.TrafficAD.equals(type)) {\r
+                               manager.executeQuery(connection, AD_SQL, consumer, decorator);\r
+                       }\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       throw e;\r
+               } finally {\r
+                       // if (connection != null)\r
+                       // connection.close();\r
+               }\r
+               return connection;\r
+       }\r
+\r
+       private static String XMLtoString(Document doc) throws TransformerException {\r
+               DOMSource domSource = new DOMSource(doc);\r
+               TransformerFactory tf = TransformerFactory.newInstance();\r
+               Transformer transformer = tf.newTransformer();\r
+               // transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");\r
+               transformer.setOutputProperty(OutputKeys.STANDALONE, "yes");\r
+               transformer.setOutputProperty(OutputKeys.METHOD, "xml");\r
+               transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");\r
+               transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");\r
+               transformer.setOutputProperty(OutputKeys.INDENT, "yes");\r
+               StringWriter sw = new StringWriter();\r
+               StreamResult sr = new StreamResult(sw);\r
+               transformer.transform(domSource, sr);\r
+               return sw.toString();\r
+       }\r
+\r
+}\r