git-tfs-id: [http://tfs.userrendszerhaz.hu:8080/tfs/DefaultCollection]$/MediaCube...
authorVásáry Dániel <daniel.vasary@userrendszerhaz.hu>
Mon, 18 Dec 2017 14:27:23 +0000 (14:27 +0000)
committerVásáry Dániel <daniel.vasary@userrendszerhaz.hu>
Mon, 18 Dec 2017 14:27:23 +0000 (14:27 +0000)
server/user.jobengine.executors/META-INF/MANIFEST.MF
server/user.jobengine.executors/src/user/jobengine/server/steps/CopyForArchiveNEXIOMaterialsStep.java
server/user.jobengine.executors/src/user/jobengine/server/steps/OctopusDataMiner.java [new file with mode: 0644]
server/user.jobengine.osgi.commons/src/user/commons/octopus/OctopusDataMiner.java
server/user.jobengine.osgi.server/pages/index.zul
server/user.jobengine.osgi.server/src/user/jobengine/server/steps/EscortFiles.java

index 27286a2e66e89f18e4b26d253531bf5db1e1777f..2fc6fbcc3eb896a4459617f8075a807f871924b3 100644 (file)
@@ -13,5 +13,18 @@ Require-Bundle: user.jobengine.osgi.commons;bundle-version="1.0.0",
  org.apache.logging.log4j.api;bundle-version="2.8.2"
 Bundle-ClassPath: .
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.apache.commons.io;version="2.2.0",
- org.apache.commons.net.ftp;version="3.6.0"
+Import-Package: com.fasterxml.jackson.annotation;version="2.4.5",
+ com.fasterxml.jackson.core;version="2.4.5",
+ com.fasterxml.jackson.databind;version="2.4.5",
+ com.fasterxml.jackson.databind.util;version="2.4.5",
+ com.fasterxml.jackson.datatype.joda;version="2.4.5",
+ com.fasterxml.jackson.jaxrs.json;version="2.4.5",
+ javax.ws.rs.client,
+ javax.ws.rs.core;version="2.0.1",
+ org.apache.commons.io;version="2.2.0",
+ org.apache.commons.net.ftp;version="3.6.0",
+ org.jboss.resteasy.client.jaxrs,
+ org.jboss.resteasy.plugins.providers,
+ org.jboss.resteasy.spi,
+ org.joda.time;version="2.2.0",
+ org.joda.time.base;version="2.2.0"
index b2a474c839d4a26778365123b3cf7b767996d4e7..efcbb66af3caf27aea055fdc71a4c1d55393f750 100644 (file)
@@ -37,7 +37,6 @@ import user.jobengine.server.steps.MetadataTypeDetector.MetadataType;
 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();\r
-       private static final String ARCHIVED = "ARCHIVED";\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
@@ -84,21 +83,23 @@ public class CopyForArchiveNEXIOMaterialsStep extends JobStep {
 \r
        private void copyFile(FileArchive fileArchive, RundownArchive rundownArchive, StoryArchive storyArchive) throws Exception {\r
                String fileName = fileArchive.getFileName();\r
+               //TODO file existance\r
+               //              targetFtp = ((FtpDirectoryLister) RemoteFileHandler.createLister(targetUri)).connect();\r
+               //              int version = 1;\r
+               //              while (true) {\r
+               //                      targetFtp.listNames(arg0)\r
+               //              }\r
+               //\r
+               //              if (targetUri != null)\r
+               //                      targetUri.cleanUp();\r
                String videoFileName = fileName + MXFEXT;\r
+\r
                transferFile(videoFileName);\r
                BasicDBObject metadata = createMetadata(rundownArchive, storyArchive, fileArchive);\r
-               try {\r
-                       if (!targetFtp.changeWorkingDirectory(EscortFiles.STATUSFOLDER))\r
-                               targetFtp.makeDirectory(EscortFiles.STATUSFOLDER);\r
-                       if (!targetFtp.changeWorkingDirectory(EscortFiles.STATUSFOLDER))\r
-                               throw new Exception("!STATUSFOLDER");\r
-               } catch (Exception e) {\r
-                       logger.catching(e);\r
-                       throw e;\r
-               }\r
                transferMetadata(videoFileName, metadata);\r
-               targetFtp.changeToParentDirectory();\r
+               //targetFtp.changeToParentDirectory();\r
                createSourceKillDateFile(rundownArchive, fileName);\r
+\r
        }\r
 \r
        private BasicDBObject createMetadata(RundownArchive rundownArchive, StoryArchive storyArchive, FileArchive fileArchive) {\r
@@ -127,15 +128,27 @@ public class CopyForArchiveNEXIOMaterialsStep extends JobStep {
        }\r
 \r
        private void createSourceKillDateFile(RundownArchive rundownArchive, String fileName) throws Exception {\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
-               try (OutputStream outStream = sourceFtp.storeFileStream(fileName + XML_EXT)) {\r
+               //sourceFtp = ((FtpDirectoryLister) RemoteFileHandler.createLister(sourceUri)).connect();\r
+               OutputStream outStream = null;\r
+               try {\r
+                       sourceFtp.enterLocalActiveMode();\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
+                       //                      if (sourceUri != null)\r
+                       //                              sourceUri.cleanUp();\r
                }\r
        }\r
 \r
@@ -152,6 +165,8 @@ public class CopyForArchiveNEXIOMaterialsStep extends JobStep {
                        return null;\r
                }\r
 \r
+               sourceFtp = ((FtpDirectoryLister) RemoteFileHandler.createLister(sourceUri)).connect();\r
+               targetFtp = ((FtpDirectoryLister) RemoteFileHandler.createLister(targetUri)).connect();\r
                processRundowns(rundowns);\r
                if (sourceUri != null)\r
                        sourceUri.cleanUp();\r
@@ -212,10 +227,11 @@ public class CopyForArchiveNEXIOMaterialsStep extends JobStep {
        }\r
 \r
        private void processRundowns(List<DBObject> rundowns) {\r
-               //db.getCollection(ARCHIVEDRUNDOWNS).drop();\r
+               db.getCollection(ARCHIVEDRUNDOWNS).drop();\r
                List<BasicDBObject> archivedRundowns = queryArchivedRundowns();\r
 \r
                int index = 1;\r
+\r
                for (DBObject r : rundowns) {\r
                        BasicDBObject rundown = (BasicDBObject) r;\r
                        setProgress(index * 100 / rundowns.size());\r
@@ -245,6 +261,7 @@ public class CopyForArchiveNEXIOMaterialsStep extends JobStep {
                        }\r
                        index++;\r
                }\r
+\r
        }\r
 \r
        private StoryArchive processStory(BasicDBObject rundown, DBObject s) throws Exception {\r
@@ -329,13 +346,16 @@ public class CopyForArchiveNEXIOMaterialsStep extends JobStep {
                targetUri.setUserName(archiveUserName);\r
                targetUri.setPassword(archivePassword);\r
 \r
-               sourceFtp = ((FtpDirectoryLister) RemoteFileHandler.createLister(sourceUri)).connect();\r
-               targetFtp = ((FtpDirectoryLister) RemoteFileHandler.createLister(targetUri)).connect();\r
-\r
        }\r
 \r
        private void transferFile(String fileName) throws Exception {\r
                int reply = 0;\r
+               //              sourceFtp = ((FtpDirectoryLister) RemoteFileHandler.createLister(sourceUri)).connect();\r
+               //              targetFtp = ((FtpDirectoryLister) RemoteFileHandler.createLister(targetUri)).connect();\r
+               //              if (sourceUri != null)\r
+               //                      sourceUri.cleanUp();\r
+               //              if (targetUri != null)\r
+               //                      targetUri.cleanUp();\r
 \r
                if (!targetFtp.enterRemotePassiveMode())\r
                        throw new Exception("!PASV");\r
@@ -358,20 +378,49 @@ public class CopyForArchiveNEXIOMaterialsStep extends JobStep {
                        reply = sourceFtp.stat();\r
                        if (!FTPReply.isPositiveCompletion(reply))\r
                                throw new Exception("!STAT");\r
+\r
                        String replyText = sourceFtp.getReplyString();\r
-                       if ("226 RETR Transfer Complete(TRANSACTION_SUCCESS)".equals(replyText))\r
+                       //logger.info("Status: {}", replyText);\r
+                       if (reply == 226) {\r
                                break;\r
-                       Thread.sleep(500);\r
+                       }\r
+                       Thread.sleep(100);\r
                }\r
+\r
+               //              if (sourceUri != null)\r
+               //                      sourceUri.cleanUp();\r
+               //              if (targetUri != null)\r
+               //                      targetUri.cleanUp();\r
+\r
        }\r
 \r
        private void transferMetadata(String fileName, BasicDBObject metadata) throws Exception {\r
-               try (OutputStream outStream = targetFtp.storeFileStream(fileName + JSON_EXT)) {\r
+               OutputStream outStream = null;\r
+               if (targetUri != null)\r
+                       targetUri.cleanUp();\r
+               targetFtp = ((FtpDirectoryLister) RemoteFileHandler.createLister(targetUri)).connect();\r
+               try {\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
+                       //                      if (targetUri != null)\r
+                       //                              targetUri.cleanUp();\r
                }\r
        }\r
 \r
diff --git a/server/user.jobengine.executors/src/user/jobengine/server/steps/OctopusDataMiner.java b/server/user.jobengine.executors/src/user/jobengine/server/steps/OctopusDataMiner.java
new file mode 100644 (file)
index 0000000..7bc8223
--- /dev/null
@@ -0,0 +1,907 @@
+package user.jobengine.server.steps;\r
+\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.concurrent.ConcurrentHashMap;\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.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
+import com.ibm.nosql.json.api.DBObject;\r
+import com.ibm.nosql.json.api.QueryBuilder;\r
+import com.ibm.nosql.json.api.WriteResult;\r
+\r
+import user.commons.ListUtils;\r
+import user.commons.nosql.NoSQLUtils;\r
+import user.commons.octopus.IOctopusAPI;\r
+import user.commons.octopus.OctopusAPI;\r
+import user.commons.remotestore.IProgressEventListener;\r
+import user.commons.remotestore.ProgressEvent;\r
+\r
+public class OctopusDataMiner implements Runnable {\r
+       private static final String _TMP = "_tmp";\r
+       private static final Logger logger = LogManager.getLogger();\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 SAVING_RUNDOWN = "Saving rundown : {} {}";\r
+       //      private static final String CHECKING_RUNDOWN = "Checking Rundown {} ({}/{})";\r
+       private static final String FIELDS_STORYFOLDER_STORIES = "stories,Story.modified,Story.name,Story.id,Story.mosObjects,Story.script,Story.type,Story.format,Story.customColumns,CustomColumn.label,CustomColumn.value";\r
+       private static final String FIELDS_RUNDOWN_STORIES = "slugs,Slug.story,Slug.position,Story.name,Story.id,Story.modified,Story.mosObjects,Story.script,Story.type,Story.format,Story.customColumns,CustomColumn.label,CustomColumn.value";\r
+       private static final String FIELDS_RUNDOWN_STORYIDS = "id,name,modified,scheduledStart,channel,Channel.name,rundownType,RundownType.name,slugs,Slug.storyId,Slug.position";\r
+       private static final String FIELDS_STORY_FOLDER_LIST = "id,name,modified,stories,Story.id";\r
+       private static final String RUNDOWN = "Rundown";\r
+       private static final String OCTOPUS_DEVICE_NAME = "Octopus-Device-Name";\r
+       private static final String OCTOPUS_DEVICE_ID = "Octopus-Device-Id";\r
+       private static final String FIELDS = "fields";\r
+       private static final String CHECKING_STORY_FOLDER = "Checking StoryFolder %s (%d/%d)";\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 MOSOBJECT = "Bejátszó: ";\r
+\r
+       private DB db;\r
+       private ResteasyWebTarget webTarget;\r
+       private String apiUser;\r
+       private String apiPwd;\r
+       private HashSet<Long> storyIDs = 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, BasicDBList> storedStoryRundowns;\r
+       private Map<Long, BasicDBList> storedStoryStoryFolders;\r
+       private Map<Long, BasicDBList> storedStoryMosObjects;\r
+       private String RUNDOWN_COLLECTION = IOctopusAPI.RUNDOWN_COLLECTION;\r
+       private String FOLDER_COLLECTION = IOctopusAPI.FOLDER_COLLECTION;\r
+       private String STORY_COLLECTION = IOctopusAPI.STORY_COLLECTION;\r
+\r
+       private Map<Long, BasicDBList> newRundowns = new HashMap<>();\r
+       private Map<Long, BasicDBList> newStoryFolders = new HashMap<>();\r
+       private Map<Long, BasicDBList> newStories = new HashMap<>();\r
+\r
+       public OctopusDataMiner() {\r
+               db = NoSQLUtils.getNoSQLDB();\r
+\r
+               String apiAddress = System.getProperty("jobengine.octopus.api.address");\r
+               apiUser = System.getProperty("jobengine.octopus.api.user");\r
+               apiPwd = System.getProperty("jobengine.octopus.api.password");\r
+\r
+               //              ResteasyClient client = new ResteasyClientBuilder().register(JacksonJsonProvider.class).build();\r
+               ResteasyClient client = new ResteasyClientBuilder().build();\r
+               webTarget = client.target(apiAddress).register(new BasicAuthentication(apiUser, apiPwd));\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
+                       long storyFolderId = storyFolder.getLong(IOctopusAPI.ID);\r
+                       List<BasicDBObject> stories = NoSQLUtils.asList(storyFolder, IOctopusAPI.STORIES);\r
+                       if (stories == null)\r
+                               continue;\r
+                       long position = 1;\r
+                       for (BasicDBObject story : stories) {\r
+                               long storyId = story.getLong(IOctopusAPI.ID);\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.containsKey(IOctopusAPI.ID))\r
+                               continue;\r
+                       long rundownId = rundown.getLong(IOctopusAPI.ID);\r
+                       List<BasicDBObject> slugs = NoSQLUtils.asList(rundown, IOctopusAPI.SLUGS);\r
+                       if (slugs == null)\r
+                               continue;\r
+                       for (BasicDBObject slug : slugs) {\r
+                               if (!slug.containsKey(IOctopusAPI.STORYID))\r
+                                       continue;\r
+                               long storyId = slug.getLong(IOctopusAPI.STORYID);\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
+               }\r
+               return result;\r
+       }\r
+\r
+       private void buildStoriesReferences() {\r
+               DBCollection collection = db.getCollection(STORY_COLLECTION);\r
+               DBCursor cursor = collection.find(null, new BasicDBObject(IOctopusAPI.ID, 1).append(IOctopusAPI.REF_RUNDOWN, 1).append(IOctopusAPI.REF_STORYFOLDER, 1)\r
+                               .append(IOctopusAPI.MOS_OBJECTS, 1));\r
+               //DBCursor find = collection.find(QueryBuilder.start(ID).greaterThan(0).get());\r
+               try {\r
+\r
+                       while (cursor.hasNext()) {\r
+                               BasicDBObject story = (BasicDBObject) cursor.next();\r
+                               long storyId = story.getLong(IOctopusAPI.ID);\r
+                               BasicDBList rundownRef = NoSQLUtils.asDBList(story, IOctopusAPI.REF_RUNDOWN);\r
+                               if (rundownRef != null) {\r
+                                       if (storedStoryRundowns == null)\r
+                                               storedStoryRundowns = new HashMap<>();\r
+                                       storedStoryRundowns.put(storyId, rundownRef);\r
+                               }\r
+                               BasicDBList storyFolderRef = NoSQLUtils.asDBList(story, IOctopusAPI.REF_STORYFOLDER);\r
+                               if (storyFolderRef != null) {\r
+                                       if (storedStoryStoryFolders == null)\r
+                                               storedStoryStoryFolders = new HashMap<>();\r
+                                       storedStoryStoryFolders.put(storyId, storyFolderRef);\r
+                               }\r
+\r
+                               BasicDBList storyMosObjects = NoSQLUtils.asDBList(story, IOctopusAPI.MOS_OBJECTS);\r
+                               if (storyMosObjects != null) {\r
+                                       if (storedStoryMosObjects == null)\r
+                                               storedStoryMosObjects = new HashMap<>();\r
+                                       storedStoryMosObjects.put(storyId, storyMosObjects);\r
+                               }\r
+                       }\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       throw e;\r
+               } finally {\r
+\r
+               }\r
+       }\r
+\r
+       public void clear() {\r
+               db.getCollection(RUNDOWN_COLLECTION).remove();\r
+               db.getCollection(STORY_COLLECTION).remove();\r
+               db.getCollection(FOLDER_COLLECTION).remove();\r
+               db.getCollection(IOctopusAPI.TIME_COLLECTION_NAME).remove();\r
+       }\r
+\r
+       private String concatParentsToStoryFolder(BasicDBObject actual, String name) {\r
+\r
+               String fields = "name,id,parent";\r
+               Response response = query("StoryFolder/" + actual.getLong("id"), fields).get();\r
+               String json = response.readEntity(String.class);\r
+               BasicDBObject resultObject = (BasicDBObject) JSONUtil.jsonToDbObject(json);\r
+               BasicDBObject res = (BasicDBObject) resultObject.get("result");\r
+               BasicDBObject parent = (BasicDBObject) res.get("parent");\r
+               if (parent == null || parent.isEmpty())\r
+                       return name;\r
+               String parentName = parent.getString(IOctopusAPI.NAME);\r
+               String actualName = actual.getString(IOctopusAPI.NAME);\r
+               String newName = String.format("%s/%s", parentName, actualName);\r
+               return concatParentsToStoryFolder(parent, newName);\r
+       }\r
+\r
+       private void deleteDiff(String oldCollectionName, String newCollectionName, String idFieldName) {\r
+               DBCollection oldCollection = db.getCollection(oldCollectionName);\r
+               DBCollection newCollection = db.getCollection(newCollectionName);\r
+               DBCursor oldCollectionCursor = oldCollection.find(new BasicDBObject(), new BasicDBObject(idFieldName, 1));\r
+               if (!oldCollectionCursor.hasNext()) {\r
+                       logger.error("{} collection is empty", newCollectionName);\r
+                       return;\r
+               }\r
+               List<BasicDBObject> oldItems = ListUtils.cast(oldCollectionCursor.toArray());\r
+\r
+               DBCursor newCollectionCursor = newCollection.find();\r
+               ConcurrentHashMap<Long, BasicDBObject> newItems = null;\r
+               if (newCollectionCursor.hasNext()) {\r
+                       List<BasicDBObject> newList = ListUtils.cast(newCollectionCursor.toArray());\r
+                       newItems = ListUtils.map(newList, item -> item.getLong(IOctopusAPI.ID));\r
+               }\r
+               if (newItems == null)\r
+                       newItems = new ConcurrentHashMap<>();\r
+\r
+               for (BasicDBObject oldItem : oldItems) {\r
+                       if (oldItem == null) {\r
+                               logger.error("Item is null");\r
+                               continue;\r
+                       }\r
+                       if (!oldItem.containsKey(idFieldName)) {\r
+                               logger.error("{} is null", idFieldName);\r
+                               continue;\r
+                       }\r
+                       long id = oldItem.getLong(idFieldName);\r
+                       BasicDBObject newItem = newItems.get(id);\r
+                       if (newItem == null) {\r
+                               //remove\r
+                               logger.info("Deleting {}", oldItem.toPrettyString(null));\r
+                               oldCollection.remove(new BasicDBObject(idFieldName, id));\r
+                       }\r
+               }\r
+       }\r
+\r
+       private void deleteOrphanStories() {\r
+               try {\r
+                       DBCollection collection = db.getCollection(STORY_COLLECTION);\r
+                       BasicDBObject query = (BasicDBObject) QueryBuilder.start().put("id").notIn(storyIDs.toArray()).get();\r
+                       WriteResult res = collection.remove(query);\r
+                       logger.trace(String.format("Deleted orphan stories: %d", res.getN()));\r
+               } catch (Exception e) {\r
+                       logger.error(e);\r
+               }\r
+       }\r
+\r
+       private void ensureIndexes() {\r
+               DBCollection collection = db.getCollection(FOLDER_COLLECTION);\r
+               if (collection.count() == 0)\r
+                       collection.ensureIndex(IOctopusAPI.ID);\r
+               collection = db.getCollection(RUNDOWN_COLLECTION);\r
+               if (collection.count() == 0) {\r
+                       collection.ensureIndex(IOctopusAPI.ID);\r
+                       collection.ensureIndex(IOctopusAPI.SCHEDULED_START);\r
+               }\r
+               collection = db.getCollection(STORY_COLLECTION);\r
+               if (collection.count() == 0)\r
+                       collection.ensureIndex(IOctopusAPI.ID);\r
+       }\r
+\r
+       public void execute() throws Exception {\r
+               logger.trace(STARTING);\r
+               //{"filter" :{ "archived" : true }}\r
+               Response response = query(RUNDOWN, "id,name,modified,scheduledStart,channel,Channel.name,rundownType,RundownType.name")\r
+                               .post(Entity.entity(new BasicDBObject("filter", new BasicDBObject("archived", true)).toPrettyString(null), MediaType.APPLICATION_JSON));\r
+               String json = response.readEntity(String.class);\r
+\r
+               RUNDOWN_COLLECTION = IOctopusAPI.RUNDOWN_COLLECTION + _TMP;\r
+               FOLDER_COLLECTION = IOctopusAPI.FOLDER_COLLECTION + _TMP;\r
+               STORY_COLLECTION = IOctopusAPI.STORY_COLLECTION + _TMP;\r
+\r
+               try {\r
+                       db.getCollection(RUNDOWN_COLLECTION).drop();\r
+                       db.getCollection(FOLDER_COLLECTION).drop();\r
+                       db.getCollection(STORY_COLLECTION).drop();\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       throw e;\r
+               }\r
+\r
+               BasicDBList rundowns = null;\r
+               BasicDBList storyFolders = null;\r
+\r
+               try {\r
+                       rundowns = queryBuildRefRundowns();\r
+                       storyFolders = queryBuildRefFolders();\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       throw e;\r
+               }\r
+\r
+               processRundowns(rundowns);\r
+               processStoryFolders(storyFolders);\r
+\r
+               //a sorrend fontos !\r
+               updateDiff(IOctopusAPI.STORY_COLLECTION, STORY_COLLECTION, IOctopusAPI.ID);\r
+               updateDiff(IOctopusAPI.RUNDOWN_COLLECTION, RUNDOWN_COLLECTION, IOctopusAPI.ID);\r
+               updateDiff(IOctopusAPI.FOLDER_COLLECTION, FOLDER_COLLECTION, IOctopusAPI.ID);\r
+               deleteDiff(IOctopusAPI.RUNDOWN_COLLECTION, RUNDOWN_COLLECTION, IOctopusAPI.ID);\r
+               //deleteDiff(IOctopusAPI.FOLDER_COLLECTION, FOLDER_COLLECTION, IOctopusAPI.ID);\r
+               deleteDiff(IOctopusAPI.STORY_COLLECTION, STORY_COLLECTION, IOctopusAPI.ID);\r
+\r
+               //setLastUpdateTime(new Date());\r
+               logger.info("Activate");\r
+\r
+               //              db.getCollection(RUNDOWN_COLLECTION).rename(IOctopusAPI.RUNDOWN_COLLECTION, true);\r
+               //              db.getCollection(FOLDER_COLLECTION).rename(IOctopusAPI.FOLDER_COLLECTION, true);\r
+               //              db.getCollection(STORY_COLLECTION).rename(IOctopusAPI.STORY_COLLECTION, true);\r
+               logger.trace(FINISHED);\r
+\r
+       }\r
+\r
+       public void executetest() {\r
+               //                      ResteasyWebTarget target = webTarget.path(RUNDOWN);\r
+               //                      Builder result = target.request().header(OCTOPUS_DEVICE_ID, apiUser).header(OCTOPUS_DEVICE_NAME, apiPwd);\r
+               //                      Response r = result.get();\r
+               //                      String x = r.readEntity(String.class);\r
+               //                      logger.info(x);\r
+               //                      return;\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
+                               if (mosObject.containsKey(IOctopusAPI.OBJ_ID)) {\r
+                                       String objID = mosObject.getString(IOctopusAPI.OBJ_ID);\r
+                                       scriptContent += String.format("%s %s%s", MOSOBJECT, objID, LINEFEED);\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
+       private String extractCustomColumnValue(String columnName, BasicDBObject story) {\r
+               List<BasicDBObject> customColumns = NoSQLUtils.asList(story, IOctopusAPI.CUSTOM_COLUMNS);\r
+               if (customColumns == null)\r
+                       return null;\r
+               String result = null;\r
+               for (BasicDBObject customColumn : customColumns) {\r
+                       if (!customColumn.containsKey(IOctopusAPI.LABEL))\r
+                               continue;\r
+                       String currentName = customColumn.getString(IOctopusAPI.LABEL);\r
+                       if (currentName == null)\r
+                               continue;\r
+                       if (!currentName.toLowerCase().equals(columnName.toLowerCase()))\r
+                               continue;\r
+                       if (!customColumn.containsKey(IOctopusAPI.VALUE))\r
+                               continue;\r
+                       result = customColumn.getString(IOctopusAPI.VALUE);\r
+                       break;\r
+               }\r
+               return result;\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
+               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
+                       if (result == null)\r
+                               result = new BasicDBList();\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.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 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
+       private Date getLastUpdateTime() {\r
+               Date result = null;\r
+               DBCollection collection = db.getCollection(IOctopusAPI.TIME_COLLECTION_NAME);\r
+               DBObject timeObject = collection.findOne();\r
+               if (timeObject != null)\r
+                       result = (Date) timeObject.get(IOctopusAPI.LASTUPDATE_TIME);\r
+               return result;\r
+       }\r
+\r
+       //      private boolean isModified(Date date, BasicDBObject object, String name) {\r
+       //              Date actualModifiedString = toDate(object, name);\r
+       //              if (actualModifiedString == null)\r
+       //                      logger.trace(ACTUAL_MODIFIED_STRING_IS_NULL);\r
+       //              int result = date.compareTo(actualModifiedString);\r
+       //              return result <= 0;\r
+       //      }\r
+\r
+       private boolean isModified(Date date, BasicDBObject object) {\r
+               if (date == null)\r
+                       return true;\r
+               Date modified = (Date) object.get(IOctopusAPI.MODIFIED);\r
+               int result = date.compareTo(modified);\r
+               return result <= 0;\r
+       }\r
+\r
+       private void processRundowns(BasicDBList rundowns) throws Exception {\r
+               if (rundowns == null || rundowns.size() == 0) {\r
+                       progressEvent.setProgress(50);\r
+                       fireProgressEvent(progressEvent);\r
+               } else {\r
+                       logger.info("Process rundowns");\r
+                       try {\r
+                               storeRundowns(rundowns, null);\r
+                       } catch (Exception e) {\r
+                               logger.catching(e);\r
+                               throw e;\r
+                       }\r
+               }\r
+       }\r
+\r
+       private void processStoryFolders(BasicDBList storyFolders) throws Exception {\r
+               if (storyFolders == null || storyFolders.size() == 0) {\r
+                       progressEvent.setProgress(100);\r
+                       fireProgressEvent(progressEvent);\r
+               } else {\r
+                       logger.info("Process story folders");\r
+                       try {\r
+                               storeStoryFolders(storyFolders, null);\r
+                       } catch (Exception e) {\r
+                               logger.catching(e);\r
+                               throw e;\r
+                       }\r
+               }\r
+       }\r
+\r
+       private Builder query(String path, String fields) {\r
+               //logger.info("Class loader {}", getClass().getClassLoader());\r
+               //              try {\r
+               //                      //TODO kell e?\r
+               //                      ResteasyDeployment deployment = new ResteasyDeployment();\r
+               //                      deployment.start();\r
+               //              } catch (Exception e) {\r
+               //                      logger.catching(e);\r
+               //              }\r
+               ResteasyWebTarget target = webTarget.path(path).queryParam(FIELDS, fields);\r
+               Builder result = target.request().header(OCTOPUS_DEVICE_ID, apiUser).header(OCTOPUS_DEVICE_NAME, apiPwd);\r
+               return result;\r
+       }\r
+\r
+       private BasicDBList queryBuildRefFolders() {\r
+               BasicDBList storyFolders;\r
+               logger.info("Fetch story folders");\r
+               storyFolders = queryStoryFolders();\r
+               logger.info("Fetch folder story references");\r
+               storyStoryFolders = buildFolderReferences(storyFolders);\r
+               return storyFolders;\r
+       }\r
+\r
+       private BasicDBList queryBuildRefRundowns() {\r
+               BasicDBList rundowns;\r
+               logger.info("Fetch rundowns");\r
+               rundowns = queryRundowns();\r
+               logger.info("Fetch rundown story references");\r
+               storyRundowns = buildRundownReferences(rundowns);\r
+               return rundowns;\r
+       }\r
+\r
+       private BasicDBObject queryRundown(BasicDBObject rundown) {\r
+               logger.trace(ENTER);\r
+               BasicDBObject result = null;\r
+               long id = NoSQLUtils.asLong(rundown, IOctopusAPI.ID);\r
+               Response response = query(String.format("%s/", RUNDOWN) + id, FIELDS_RUNDOWN_STORIES).get();\r
+               String json = response.readEntity(String.class);\r
+               BasicDBObject resultObject = (BasicDBObject) JSONUtil.jsonToDbObject(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
+       private BasicDBList queryRundowns() {\r
+               logger.trace(ENTER);\r
+               BasicDBList result = null;\r
+               Response response = query(RUNDOWN, FIELDS_RUNDOWN_STORYIDS).get();\r
+               String json = response.readEntity(String.class);\r
+               BasicDBObject resultObject = (BasicDBObject) JSONUtil.jsonToDbObject(json);\r
+               if (resultObject != null)\r
+                       result = NoSQLUtils.asDBList(resultObject, RESULT);\r
+               logger.trace(EXIT);\r
+               return result;\r
+       }\r
+\r
+       private BasicDBObject queryStoryFolder(BasicDBObject storyFolder) {\r
+               logger.trace(ENTER);\r
+               BasicDBObject result = null;\r
+               long id = NoSQLUtils.asLong(storyFolder, IOctopusAPI.ID);\r
+               Response response = query(String.format("%s/", STORY_FOLDER) + id, FIELDS_STORYFOLDER_STORIES).get();\r
+               String json = response.readEntity(String.class);\r
+               BasicDBObject resultObject = (BasicDBObject) JSONUtil.jsonToDbObject(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
+       private BasicDBList queryStoryFolders() {\r
+               logger.trace(ENTER);\r
+               BasicDBList result = null;\r
+               Response response = query(STORY_FOLDER, FIELDS_STORY_FOLDER_LIST).get();\r
+               String json = response.readEntity(String.class);\r
+               BasicDBObject resultObject = (BasicDBObject) JSONUtil.jsonToDbObject(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, 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
+       @Override\r
+       public void run() {\r
+               logger.trace(STARTING);\r
+               try {\r
+                       ensureIndexes();\r
+                       Date lastUpdateTime = getLastUpdateTime();\r
+\r
+                       buildStoriesReferences();\r
+\r
+                       BasicDBList rundowns = queryRundowns();\r
+                       storyRundowns = buildRundownReferences(rundowns);\r
+                       BasicDBList storyFolders = queryStoryFolders();\r
+                       storyStoryFolders = buildFolderReferences(storyFolders);\r
+\r
+                       if (rundowns == null || rundowns.size() == 0) {\r
+                               progressEvent.setProgress(50);\r
+                               fireProgressEvent(progressEvent);\r
+                       } else {\r
+                               storeRundowns(rundowns, lastUpdateTime);\r
+                       }\r
+\r
+                       if (storyFolders == null || storyFolders.size() == 0) {\r
+                               progressEvent.setProgress(100);\r
+                               fireProgressEvent(progressEvent);\r
+                       } else {\r
+                               storeStoryFolders(storyFolders, lastUpdateTime);\r
+                       }\r
+                       deleteOrphanStories();\r
+                       setLastUpdateTime(new Date());\r
+               } catch (Exception e) {\r
+                       logger.catching(e);\r
+                       throw e;\r
+               }\r
+               logger.trace(FINISHED);\r
+       }\r
+\r
+       public void run(boolean forceFull) {\r
+               if (forceFull) {\r
+                       clear();\r
+               }\r
+               run();\r
+               //              if (forceFull) {\r
+               //                      RUNDOWN_COLLECTION_NAME = "rundowns";\r
+               //                      STORY_COLLECTION_NAME = "stories";\r
+               //                      STORY_FOLDER_COLLECTION_NAME = "storyfolders";\r
+               //                      TIME_COLLECTION_NAME = "octopusSyncTime";\r
+               //                      db.getCollection("rundowns_tmp").rename(RUNDOWN_COLLECTION_NAME, true);\r
+               //                      db.getCollection("stories_tmp").rename(STORY_COLLECTION_NAME, true);\r
+               //                      db.getCollection("storyfolders_tmp").rename(STORY_FOLDER_COLLECTION_NAME, true);\r
+               //                      db.getCollection("octopusSyncTime_tmp").rename(TIME_COLLECTION_NAME, true);\r
+               //                      //clear();\r
+               //              }\r
+\r
+               //TODO reset collection names\r
+       }\r
+\r
+       public void setLastUpdateTime(Date lastUpdateTime) {\r
+               DBCollection collection = db.getCollection(OctopusAPI.TIME_COLLECTION_NAME);\r
+               DBObject timeObject = collection.findOne();\r
+               if (timeObject == null)\r
+                       timeObject = new BasicDBObject();\r
+               timeObject.put(IOctopusAPI.LASTUPDATE_TIME, lastUpdateTime);\r
+\r
+               collection.save(timeObject);\r
+       }\r
+\r
+       private void storeRundown(BasicDBObject rundown, Date lastUpdateTime) {\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
+               BasicDBObject rundownWithStories = queryRundown(rundown);\r
+               if (rundownWithStories != null) {\r
+                       BasicDBList stories = NoSQLUtils.asDBList(rundownWithStories, IOctopusAPI.SLUGS);\r
+                       if (stories != null)\r
+                               storeRundownStories(stories, lastUpdateTime);\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(RUNDOWN_COLLECTION);\r
+                       if (lastUpdateTime == null || (lastUpdateTime != null && isModified(lastUpdateTime, rundown))) {\r
+                               //logger.debug(SAVING_RUNDOWN, rundownID, name);\r
+                               collection.save(rundown);\r
+                       }\r
+               }\r
+               logger.trace(EXIT);\r
+       }\r
+\r
+       private void storeRundowns(BasicDBList rundowns, Date lastUpdateTime) {\r
+               logger.trace(ENTER);\r
+               List<BasicDBObject> rundownsList = NoSQLUtils.asList(rundowns);\r
+               int idx = 1;\r
+               for (BasicDBObject rundown : rundownsList) {\r
+                       //logger.info(CHECKING_RUNDOWN, rundown.getLong(IOctopusAPI.ID), rundownsList.size(), idx);\r
+                       storeRundown(rundown, lastUpdateTime);\r
+                       int progress = idx * 50 / rundownsList.size();\r
+                       if (progress - progressEvent.getProgress() > 0) {\r
+                               progressEvent.setProgress(progress);\r
+                               fireProgressEvent(progressEvent);\r
+                       }\r
+\r
+                       idx++;\r
+               }\r
+               logger.trace(EXIT);\r
+       }\r
+\r
+       private void storeRundownStories(BasicDBList slugs, Date lastUpdateTime) {\r
+               logger.trace(ENTER);\r
+               List<BasicDBObject> slugsList = NoSQLUtils.asList(slugs);\r
+               for (BasicDBObject slug : slugsList) {\r
+                       if (slug.containsKey(IOctopusAPI.STORY))\r
+                               storeStory((BasicDBObject) slug.get(IOctopusAPI.STORY), lastUpdateTime);\r
+               }\r
+               logger.trace(EXIT);\r
+       }\r
+\r
+       private void storeStory(BasicDBObject story, Date lastUpdateTime) {\r
+               logger.trace(ENTER);\r
+               if (!story.containsKey(IOctopusAPI.ID)) {\r
+                       logger.error("Missing id in story {}", story.toPrettyString(null));\r
+                       return;\r
+               }\r
+               long storyID = story.getLong(IOctopusAPI.ID);\r
+               boolean isContains = storyIDs.contains(storyID);\r
+               if (isContains)\r
+                       return;\r
+               storyIDs.add(storyID);\r
+               story.put(IOctopusAPI.MODIFIED, toDate(story, IOctopusAPI.MODIFIED));\r
+               BasicDBList rundownRef = storyRundowns.get(storyID);\r
+               BasicDBList storyFolderRef = storyStoryFolders.get(storyID);\r
+               BasicDBList modifiedMOS = extractRelevantMOSObjects(story);\r
+\r
+               if (lastUpdateTime != null) {\r
+                       rundownRef = (rundownRef == null) ? new BasicDBList() : rundownRef;\r
+                       storyFolderRef = (storyFolderRef == null) ? new BasicDBList() : storyFolderRef;\r
+                       modifiedMOS = (modifiedMOS == null) ? new BasicDBList() : modifiedMOS;\r
+\r
+                       boolean uptodate = true;\r
+                       if (!isModified(lastUpdateTime, story)) {\r
+                               BasicDBList storedRundownRef = storedStoryRundowns.get(storyID);\r
+                               storedRundownRef = (storedRundownRef == null) ? new BasicDBList() : storedRundownRef;\r
+                               uptodate = storedRundownRef.equals(rundownRef);\r
+\r
+                               if (uptodate) {\r
+                                       BasicDBList storedStoryFolderRef = storedStoryStoryFolders.get(storyID);\r
+                                       storedStoryFolderRef = (storedStoryFolderRef == null) ? new BasicDBList() : storedStoryFolderRef;\r
+                                       uptodate = storedStoryFolderRef.equals(storyFolderRef);\r
+                               }\r
+\r
+                               if (uptodate) {\r
+                                       BasicDBList storedMOS = storedStoryMosObjects.get(storyID);\r
+                                       storedMOS = (storedMOS == null) ? new BasicDBList() : storedMOS;\r
+                                       uptodate = storedMOS.equals(modifiedMOS);\r
+                               }\r
+\r
+                               if (uptodate)\r
+                                       return;\r
+                       }\r
+               }\r
+\r
+               DBCollection collection = db.getCollection(STORY_COLLECTION);\r
+               if (lastUpdateTime != null) {\r
+                       BasicDBObject orig = (BasicDBObject) collection.findOne(new BasicDBObject(IOctopusAPI.ID, storyID), new BasicDBObject(IOctopusAPI.ID, 1));\r
+                       if (orig != null)\r
+                               story.put("_id", orig.getID());\r
+               }\r
+               if (rundownRef != null)\r
+                       story.put(IOctopusAPI.REF_RUNDOWN, rundownRef);\r
+               if (storyFolderRef != null)\r
+                       story.put(IOctopusAPI.REF_STORYFOLDER, storyFolderRef);\r
+               String scriptContent = extractScriptContent(story);\r
+               story.put(IOctopusAPI.SCRIPT_CONTENT, scriptContent);\r
+               if (modifiedMOS == null || modifiedMOS.isEmpty()) {\r
+                       if (story.containsKey(IOctopusAPI.MOS_OBJECTS))\r
+                               story.remove(IOctopusAPI.MOS_OBJECTS);\r
+               } else\r
+                       story.put(IOctopusAPI.MOS_OBJECTS, modifiedMOS);\r
+\r
+               String parentStoryId = extractCustomColumnValue(IOctopusAPI.PARENT_STORY_ID, story);\r
+               if (parentStoryId == null) {\r
+                       logger.warn("Missing {} in story", IOctopusAPI.PARENT_STORY_ID, story.toPrettyString(null));\r
+                       story.append(IOctopusAPI.PARENT_STORY_ID, storyID);\r
+               } else\r
+                       story.append(IOctopusAPI.PARENT_STORY_ID, parentStoryId);\r
+               logger.debug(SAVING_STORY_ID, storyID);\r
+               collection.save(story);\r
+               logger.trace(EXIT);\r
+       }\r
+\r
+       private void storeStoryFolder(BasicDBObject storyFolder, Date lastUpdateTime) {\r
+               logger.trace(ENTER);\r
+               BasicDBObject storyFoldersWithStories = queryStoryFolder(storyFolder);\r
+               if (storyFoldersWithStories != null) {\r
+                       BasicDBList stories = NoSQLUtils.asDBList(storyFoldersWithStories, IOctopusAPI.STORIES);\r
+                       if (stories != null)\r
+                               storeStoryFolderStories(stories, lastUpdateTime);\r
+                       storyFolder.put(IOctopusAPI.MODIFIED, toDate(storyFolder, IOctopusAPI.MODIFIED));\r
+                       DBCollection collection = db.getCollection(FOLDER_COLLECTION);\r
+                       if (lastUpdateTime == null || (lastUpdateTime != null && isModified(lastUpdateTime, storyFolder))) {\r
+                               String name = storyFolder.getString(IOctopusAPI.NAME);\r
+                               logger.debug("Storing story folder {}", name);\r
+                               collection.save(storyFolder);\r
+                       }\r
+               }\r
+               logger.trace(EXIT);\r
+       }\r
+\r
+       private void storeStoryFolders(BasicDBList storyFolders, Date lastUpdateTime) {\r
+               logger.trace(ENTER);\r
+               List<BasicDBObject> storyFolderList = NoSQLUtils.asList(storyFolders);\r
+               int idx = 1;\r
+               for (BasicDBObject storyFolder : storyFolderList) {\r
+                       logger.debug(String.format(CHECKING_STORY_FOLDER, storyFolder.getLong(IOctopusAPI.ID), storyFolderList.size(), idx));\r
+                       storeStoryFolder(storyFolder, lastUpdateTime);\r
+                       int progress = 50 + (idx * 50 / storyFolderList.size());\r
+                       if (progress - progressEvent.getProgress() > 0) {\r
+                               progressEvent.setProgress(progress);\r
+                               fireProgressEvent(progressEvent);\r
+                       }\r
+                       idx++;\r
+               }\r
+               logger.trace(EXIT);\r
+       }\r
+\r
+       private void storeStoryFolderStories(BasicDBList stories, Date lastUpdateTime) {\r
+               logger.trace(ENTER);\r
+               List<BasicDBObject> list = NoSQLUtils.asList(stories);\r
+               for (BasicDBObject story : list)\r
+                       storeStory(story, lastUpdateTime);\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
+       private void updateDiff(String oldCollectionName, String newCollectionName, String idFieldName) {\r
+               DBCollection oldCollection = db.getCollection(oldCollectionName);\r
+               DBCollection newCollection = db.getCollection(newCollectionName);\r
+               DBCursor newCollectionCursor = newCollection.find();\r
+               if (!newCollectionCursor.hasNext()) {\r
+                       logger.error("{} collection is empty", newCollectionName);\r
+                       return;\r
+               }\r
+\r
+               List<BasicDBObject> newItems = ListUtils.cast(newCollectionCursor.toArray());\r
+\r
+               DBCursor oldCollectionCursor = oldCollection.find();\r
+               ConcurrentHashMap<Long, BasicDBObject> oldItems = null;\r
+               if (oldCollectionCursor.hasNext()) {\r
+                       List<BasicDBObject> oldList = ListUtils.cast(oldCollectionCursor.toArray());\r
+                       oldItems = ListUtils.map(oldList, item -> item.getLong(IOctopusAPI.ID));\r
+               }\r
+               if (oldItems == null)\r
+                       oldItems = new ConcurrentHashMap<>();\r
+               for (BasicDBObject newItem : newItems) {\r
+                       if (newItem == null) {\r
+                               logger.error("Item is null");\r
+                               continue;\r
+                       }\r
+                       if (!newItem.containsKey(idFieldName)) {\r
+                               logger.error("{} is null", idFieldName);\r
+                               continue;\r
+                       }\r
+                       long id = newItem.getLong(idFieldName);\r
+                       BasicDBObject oldItem = oldItems.get(id);\r
+                       boolean save = false;\r
+                       if (oldItem == null) {\r
+                               //save\r
+                               save = true;\r
+                       } else {\r
+                               //compare\r
+                               Object oldDbId = oldItem.getID();\r
+                               newItem.remove(IOctopusAPI._ID);\r
+                               oldItem.remove(IOctopusAPI._ID);\r
+\r
+                               if (!newItem.equals(oldItem)) {\r
+                                       //save\r
+                                       newItem.put(IOctopusAPI._ID, oldDbId);\r
+                                       save = true;\r
+                               }\r
+                       }\r
+\r
+                       if (save) {\r
+                               logger.info("Saving to {} item {}", oldCollectionName, id);\r
+                               oldCollection.save(newItem);\r
+                       }\r
+               }\r
+       }\r
+\r
+}\r
index 778264512f7a352d38009b74522fcd47e385e678..73dac323dedfab38ebb3fd5d6079257ce9ca4b08 100644 (file)
@@ -8,7 +8,9 @@ import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;\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.logging.log4j.LogManager;\r
@@ -40,13 +42,12 @@ public class OctopusDataMiner implements Runnable {
        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 SAVING_RUNDOWN = "Saving rundown : {} {}";\r
-       private static final String CHECKING_RUNDOWN = "Checking Rundown {} ({}/{})";\r
-       private static final String FIELDS_STORIES = "stories,Story.modified,Story.name,Story.id,Story.mosObjects,Story.script,Story.type,Story.format,Story.customColumns,CustomColumn.label,CustomColumn.value";\r
-       private static final String FIELDS_SLUGS = "slugs,Slug.story,Slug.position,Story.name,Story.id,Story.modified,Story.mosObjects,Story.script,Story.type,Story.format,Story.customColumns,CustomColumn.label,CustomColumn.value";\r
-       private static final String FIELDS_RUNDOWN_LIST = "id,name,modified,scheduledStart,channel,Channel.name,Channel.id,rundownType,RundownType.name,slugs,Slug.storyId,Slug.position";\r
+       //      private static final String SAVING_RUNDOWN = "Saving rundown : {} {}";\r
+       //      private static final String CHECKING_RUNDOWN = "Checking Rundown {} ({}/{})";\r
+       private static final String FIELDS_STORYFOLDER_STORIES = "stories,Story.modified,Story.name,Story.id,Story.mosObjects,Story.script,Story.type,Story.format,Story.customColumns,CustomColumn.label,CustomColumn.value";\r
+       private static final String FIELDS_RUNDOWN_STORIES = "slugs,Slug.story,Slug.position,Story.name,Story.id,Story.modified,Story.mosObjects,Story.script,Story.type,Story.format,Story.customColumns,CustomColumn.label,CustomColumn.value";\r
+       private static final String FIELDS_RUNDOWN_STORYIDS = "id,name,modified,scheduledStart,channel,Channel.name,rundownType,RundownType.name,slugs,Slug.storyId,Slug.position";\r
        private static final String FIELDS_STORY_FOLDER_LIST = "id,name,modified,stories,Story.id";\r
-       //private static final String FIELDS_STORY_FOLDER_LIST = "id,name,modified";\r
        private static final String RUNDOWN = "Rundown";\r
        private static final String OCTOPUS_DEVICE_NAME = "Octopus-Device-Name";\r
        private static final String OCTOPUS_DEVICE_ID = "Octopus-Device-Id";\r
@@ -212,14 +213,14 @@ public class OctopusDataMiner implements Runnable {
        private void deleteDiff(String oldCollectionName, String newCollectionName, String idFieldName) {\r
                DBCollection oldCollection = db.getCollection(oldCollectionName);\r
                DBCollection newCollection = db.getCollection(newCollectionName);\r
-               DBCursor oldCollectionCursor = newCollection.find(new BasicDBObject(), new BasicDBObject(idFieldName, 1));\r
+               DBCursor oldCollectionCursor = oldCollection.find(new BasicDBObject(), new BasicDBObject(idFieldName, 1));\r
                if (!oldCollectionCursor.hasNext()) {\r
                        logger.error("{} collection is empty", newCollectionName);\r
                        return;\r
                }\r
                List<BasicDBObject> oldItems = ListUtils.cast(oldCollectionCursor.toArray());\r
 \r
-               DBCursor newCollectionCursor = oldCollection.find();\r
+               DBCursor newCollectionCursor = newCollection.find();\r
                ConcurrentHashMap<Long, BasicDBObject> newItems = null;\r
                if (newCollectionCursor.hasNext()) {\r
                        List<BasicDBObject> newList = ListUtils.cast(newCollectionCursor.toArray());\r
@@ -274,6 +275,11 @@ public class OctopusDataMiner implements Runnable {
 \r
        public void execute() throws Exception {\r
                logger.trace(STARTING);\r
+               //{"filter" :{ "archived" : true }}\r
+               Response response = query(RUNDOWN, "id,name,modified,scheduledStart,channel,Channel.name,rundownType,RundownType.name")\r
+                               .post(Entity.entity(new BasicDBObject("filter", new BasicDBObject("archived", true)).toPrettyString(null), MediaType.APPLICATION_JSON));\r
+               String json = response.readEntity(String.class);\r
+\r
                RUNDOWN_COLLECTION = IOctopusAPI.RUNDOWN_COLLECTION + _TMP;\r
                FOLDER_COLLECTION = IOctopusAPI.FOLDER_COLLECTION + _TMP;\r
                STORY_COLLECTION = IOctopusAPI.STORY_COLLECTION + _TMP;\r
@@ -306,7 +312,7 @@ public class OctopusDataMiner implements Runnable {
                updateDiff(IOctopusAPI.RUNDOWN_COLLECTION, RUNDOWN_COLLECTION, IOctopusAPI.ID);\r
                updateDiff(IOctopusAPI.FOLDER_COLLECTION, FOLDER_COLLECTION, IOctopusAPI.ID);\r
                deleteDiff(IOctopusAPI.RUNDOWN_COLLECTION, RUNDOWN_COLLECTION, IOctopusAPI.ID);\r
-               deleteDiff(IOctopusAPI.FOLDER_COLLECTION, FOLDER_COLLECTION, IOctopusAPI.ID);\r
+               //deleteDiff(IOctopusAPI.FOLDER_COLLECTION, FOLDER_COLLECTION, IOctopusAPI.ID);\r
                deleteDiff(IOctopusAPI.STORY_COLLECTION, STORY_COLLECTION, IOctopusAPI.ID);\r
 \r
                //setLastUpdateTime(new Date());\r
@@ -535,7 +541,7 @@ public class OctopusDataMiner implements Runnable {
                logger.trace(ENTER);\r
                BasicDBObject result = null;\r
                long id = NoSQLUtils.asLong(rundown, IOctopusAPI.ID);\r
-               Response response = query(String.format("%s/", RUNDOWN) + id, FIELDS_SLUGS).get();\r
+               Response response = query(String.format("%s/", RUNDOWN) + id, FIELDS_RUNDOWN_STORIES).get();\r
                String json = response.readEntity(String.class);\r
                BasicDBObject resultObject = (BasicDBObject) JSONUtil.jsonToDbObject(json);\r
                if (resultObject == null)\r
@@ -549,7 +555,7 @@ public class OctopusDataMiner implements Runnable {
        private BasicDBList queryRundowns() {\r
                logger.trace(ENTER);\r
                BasicDBList result = null;\r
-               Response response = query(RUNDOWN, FIELDS_RUNDOWN_LIST).get();\r
+               Response response = query(RUNDOWN, FIELDS_RUNDOWN_STORYIDS).get();\r
                String json = response.readEntity(String.class);\r
                BasicDBObject resultObject = (BasicDBObject) JSONUtil.jsonToDbObject(json);\r
                if (resultObject != null)\r
@@ -562,7 +568,7 @@ public class OctopusDataMiner implements Runnable {
                logger.trace(ENTER);\r
                BasicDBObject result = null;\r
                long id = NoSQLUtils.asLong(storyFolder, IOctopusAPI.ID);\r
-               Response response = query(String.format("%s/", STORY_FOLDER) + id, FIELDS_STORIES).get();\r
+               Response response = query(String.format("%s/", STORY_FOLDER) + id, FIELDS_STORYFOLDER_STORIES).get();\r
                String json = response.readEntity(String.class);\r
                BasicDBObject resultObject = (BasicDBObject) JSONUtil.jsonToDbObject(json);\r
                if (resultObject == null)\r
index 7b98f9185bfda26c441235c04992db59e7b92247..c39b3fd1ba0669d7f300074cb06aa42362593f26 100644 (file)
@@ -57,7 +57,7 @@
                                                                <image src="/img/mediacube_logo_v2_50x50.png">\r
 <!--                                                           <custom-attributes org.zkoss.zul.image.preload="true" /> -->\r
                                                                </image>\r
-                                                               <label style="color:#e3e3e3;font-size:20px;font-weight:bold">MediaCube v2.1.8</label>\r
+                                                               <label style="color:#e3e3e3;font-size:20px;font-weight:bold">MediaCube v2.1.9</label>\r
                                                        </div>\r
                                                </west>\r
                                                <center border="0">\r
index 998d84f20f03deb3888a75a56828329373114cc2..57509664eb664edd6a677b426debb1ff0710ecd8 100644 (file)
@@ -67,12 +67,13 @@ public class EscortFiles {
                root.setAttribute("extendedId", fileName);\r
                if (killDate != null) {\r
                        String sKillDate = CalendarUtils.toString(CalendarUtils.createCalendar(killDate), "MM-dd-yyyy");\r
-                       root.appendChild(xmlDocument.createElement("KillDate")).setNodeValue(sKillDate);\r
+                       root.appendChild(xmlDocument.createElement("KillDate")).appendChild(xmlDocument.createTextNode(sKillDate));\r
                }\r
+\r
                if (StringUtils.isNotBlank(description))\r
-                       root.appendChild(xmlDocument.createElement("ExtendedDescription")).setNodeValue(description);\r
+                       root.appendChild(xmlDocument.createElement("ExtendedDescription")).appendChild(xmlDocument.createTextNode(description));\r
                if (StringUtils.isNotBlank(agency))\r
-                       root.appendChild(xmlDocument.createElement("ExtendedAgency")).setNodeValue(agency);\r
+                       root.appendChild(xmlDocument.createElement("ExtendedAgency")).appendChild(xmlDocument.createTextNode(agency));\r
                xmlDocument.appendChild(root);\r
 \r
                DOMSource domSource = new DOMSource(xmlDocument);\r