IndexServiceImpl implements IndexService { private void updateMediaPackageMetadata(MediaPackage mp, MetadataList metadataList) { String oldSeriesId = mp.getSeries(); for (EventCatalogUIAdapter catalogUIAdapter : getEventCatalogUIAdapters()) { final DublinCoreMetadataCollection metadata = metadataList.getMetadataByAdapter(catalogUIAdapter); if (metadata != null && metadata.isUpdated()) { catalogUIAdapter.storeFields(mp, metadata); } } if (!StringUtils.equals(oldSeriesId, mp.getSeries())) { List<String> seriesDcTags = new ArrayList<>(); List<String> seriesAclTags = new ArrayList<>(); Map<String, List<String>> seriesExtDcTags = new HashMap<>(); if (StringUtils.isNotBlank(oldSeriesId)) { for (MediaPackageElement mpe : mp.getElementsByFlavor(MediaPackageElements.SERIES)) { mp.remove(mpe); for (String tag : mpe.getTags()) { seriesDcTags.add(tag); } } for (MediaPackageElement mpe : mp.getElementsByFlavor(MediaPackageElements.XACML_POLICY_SERIES)) { mp.remove(mpe); for (String tag : mpe.getTags()) { seriesAclTags.add(tag); } } try { Opt<Map<String, byte[]>> oldSeriesElementsOpt = seriesService.getSeriesElements(oldSeriesId); for (Map<String, byte[]> oldSeriesElements : oldSeriesElementsOpt) { for (String oldSeriesElementType : oldSeriesElements.keySet()) { for (MediaPackageElement mpe : mp .getElementsByFlavor(MediaPackageElementFlavor.flavor(oldSeriesElementType, "series"))) { mp.remove(mpe); String elementType = mpe.getFlavor().getType(); if (StringUtils.isNotBlank(elementType)) { if (!seriesExtDcTags.containsKey(elementType)) { seriesExtDcTags.put(elementType, new ArrayList<>()); } for (String tag : mpe.getTags()) { seriesExtDcTags.get(elementType).add(tag); } } } } } } catch (SeriesException e) { logger.info("Unable to retrieve series element types from series service for the series {}", oldSeriesId, e); } } if (StringUtils.isNotBlank(mp.getSeries())) { try { DublinCoreCatalog seriesDC = seriesService.getSeries(mp.getSeries()); if (seriesDC != null) { mp.setSeriesTitle(seriesDC.getFirst(DublinCore.PROPERTY_TITLE)); try (InputStream in = IOUtils.toInputStream(seriesDC.toXmlString(), "UTF-8")) { String elementId = UUID.randomUUID().toString(); URI catalogUrl = workspace.put(mp.getIdentifier().toString(), elementId, "dublincore.xml", in); MediaPackageElement mpe = mp.add(catalogUrl, MediaPackageElement.Type.Catalog, MediaPackageElements.SERIES); mpe.setIdentifier(elementId); mpe.setChecksum(Checksum.create(ChecksumType.DEFAULT_TYPE, workspace.read(catalogUrl))); if (StringUtils.isNotBlank(oldSeriesId)) { for (String tag : seriesDcTags) { mpe.addTag(tag); } } else { mpe.addTag("archive"); } } catch (IOException e) { throw new IllegalStateException("Unable to add the series dublincore to the media package " + mp.getIdentifier(), e); } } } catch (SeriesException e) { throw new IllegalStateException("Unable to retrieve series dublincore catalog for the series " + mp.getSeries(), e); } catch (NotFoundException | UnauthorizedException e) { throw new IllegalArgumentException("Unable to retrieve series dublincore catalog for the series " + mp.getSeries(), e); } try { AccessControlList seriesAccessControl = seriesService.getSeriesAccessControl(mp.getSeries()); if (seriesAccessControl != null) { mp = authorizationService.setAcl(mp, AclScope.Series, seriesAccessControl).getA(); for (MediaPackageElement seriesAclMpe : mp.getElementsByFlavor(MediaPackageElements.XACML_POLICY_SERIES)) { if (StringUtils.isNotBlank(oldSeriesId)) { for (String tag : seriesAclTags) { seriesAclMpe.addTag(tag); } } else { seriesAclMpe.addTag("archive"); } } } } catch (SeriesException | MediaPackageException e) { throw new IllegalStateException("Unable to retrieve series ACL for series " + oldSeriesId, e); } catch (NotFoundException e) { logger.debug("There is no ACL set for the series {}", mp.getSeries()); } try { Opt<Map<String, byte[]>> seriesElementsOpt = seriesService.getSeriesElements(mp.getSeries()); for (Map<String, byte[]> seriesElements : seriesElementsOpt) { for (String seriesElementType : seriesElements.keySet()) { try (InputStream in = new ByteArrayInputStream(seriesElements.get(seriesElementType))) { String elementId = UUID.randomUUID().toString(); URI catalogUrl = workspace.put(mp.getIdentifier().toString(), elementId, "dublincore.xml", in); MediaPackageElement mpe = mp.add(catalogUrl, MediaPackageElement.Type.Catalog, MediaPackageElementFlavor.flavor(seriesElementType, "series")); mpe.setIdentifier(elementId); mpe.setChecksum(Checksum.create(ChecksumType.DEFAULT_TYPE, workspace.read(catalogUrl))); if (StringUtils.isNotBlank(oldSeriesId)) { if (seriesExtDcTags.containsKey(seriesElementType)) { for (String tag : seriesExtDcTags.get(seriesElementType)) { mpe.addTag(tag); } } } else { mpe.addTag("archive"); } } catch (IOException e) { throw new IllegalStateException(String.format("Unable to serialize series element %s for the series %s", seriesElementType, mp.getSeries()), e); } catch (NotFoundException e) { throw new IllegalArgumentException("Unable to retrieve series element dublincore catalog for the series " + mp.getSeries(), e); } } } } catch (SeriesException e) { throw new IllegalStateException("Unable to retrieve series elements for the series " + mp.getSeries(), e); } } } }  void setAclServiceFactory(AclServiceFactory aclServiceFactory); void setAuthorizationService(AuthorizationService authorizationService); void setCaptureAgentStateService(CaptureAgentStateService captureAgentStateService); void setEventCommentService(EventCommentService eventCommentService); void setCommonEventCatalogUIAdapter(CommonEventCatalogUIAdapter eventCatalogUIAdapter); void setCommonSeriesCatalogUIAdapter(CommonSeriesCatalogUIAdapter seriesCatalogUIAdapter); void addCatalogUIAdapter(EventCatalogUIAdapter catalogUIAdapter); void removeCatalogUIAdapter(EventCatalogUIAdapter catalogUIAdapter); void addCatalogUIAdapter(SeriesCatalogUIAdapter catalogUIAdapter); void removeCatalogUIAdapter(SeriesCatalogUIAdapter catalogUIAdapter); void setIngestService(IngestService ingestService); void setListProvidersService(ListProvidersService listProvidersService); void setAssetManager(AssetManager assetManager); void setSchedulerService(SchedulerService schedulerService); void setSecurityService(SecurityService securityService); void setSeriesService(SeriesService seriesService); void setWorkflowService(WorkflowService workflowService); void setWorkspace(Workspace workspace); void setUserDirectoryService(UserDirectoryService userDirectoryService); void setGroupRoleProvider(JpaGroupRoleProvider jpaGroupRoleProvider); AclService getAclService(); List<EventCatalogUIAdapter> getEventCatalogUIAdapters(String organization); List<SeriesCatalogUIAdapter> getSeriesCatalogUIAdapters(String organization); @Override List<EventCatalogUIAdapter> getEventCatalogUIAdapters(); @Override List<SeriesCatalogUIAdapter> getSeriesCatalogUIAdapters(); @Override EventCatalogUIAdapter getCommonEventCatalogUIAdapter(); @Override SeriesCatalogUIAdapter getCommonSeriesCatalogUIAdapter(); void activate(ComponentContext cc); void deactivate(ComponentContext cc); @Override String createEvent(HttpServletRequest request); @Override String updateEventAssets(MediaPackage mp, HttpServletRequest request); String createEvent(JSONObject metadataJson, MediaPackage mp); @Override String createEvent(EventHttpServletRequest eventHttpServletRequest); @Override MetadataList updateAllEventMetadata(
          final String id, final String metadataJSON, final AbstractSearchIndex index); @Override void removeCatalogByFlavor(Event event, MediaPackageElementFlavor flavor); @Override void removeCatalogByFlavor(Series series, MediaPackageElementFlavor flavor); @Override MetadataList updateEventMetadata(String id, MetadataList metadataList, AbstractSearchIndex index); @Override AccessControlList updateEventAcl(String id, AccessControlList acl, AbstractSearchIndex index); @Override Map<String, Map<String, String>> getEventWorkflowProperties(final List<String> eventIds); @Override SearchResult<Group> getGroups(String filter, Opt<Integer> optLimit, Opt<Integer> optOffset,
          Opt<String> optSort, AbstractSearchIndex index); @Override Opt<Group> getGroup(String id, AbstractSearchIndex index); @Override void removeGroup(String id); @Override void updateGroup(String id, String name, String description, String roles, String members); @Override void createGroup(String name, String description, String roles, String members); @Override Opt<Event> getEvent(String id, AbstractSearchIndex index); @Override EventRemovalResult removeEvent(Event event, Runnable doOnNotFound, String retractWorkflowId); @Override boolean removeEvent(String id); @Override MediaPackage getEventMediapackage(Event event); @Override Source getEventSource(Event event); @Override String createSeries(MetadataList metadataList, Map<String, String> options, Opt<AccessControlList> optAcl,
          Opt<Long> optThemeId); @Override String createSeries(String metadata); @Override Opt<Series> getSeries(String seriesId, AbstractSearchIndex searchIndex); @Override void removeSeries(String id); @Override MetadataList updateAllSeriesMetadata(String id, String metadataJSON, AbstractSearchIndex index); @Override MetadataList updateAllSeriesMetadata(String id, MetadataList metadataList, AbstractSearchIndex index); @Override void updateCommentCatalog(final Event event, final List<EventComment> comments); @Override MetadataList getMetadataListWithAllSeriesCatalogUIAdapters(); @Override MetadataList getMetadataListWithAllEventCatalogUIAdapters(); boolean isWorkflowActive(String workflowState); static final String THEME_PROPERTY_NAME; }
@Test public void testUpdateMediaPackageMetadata() throws Exception { String username = "user1"; String org = "mh_default_org"; DublinCoreMetadataCollection metadataCollection = new DublinCoreMetadataCollection(); metadataCollection.addField(new MetadataField( "title", "title", "EVENTS.EVENTS.DETAILS.METADATA.TITLE", false, true, "title", null, MetadataField.Type.TEXT, null, null, null, null, null, null, null)); metadataCollection.addField(new MetadataField( "creator", "creator", "EVENTS.EVENTS.DETAILS.METADATA.PRESENTERS", false, false, null, null, MetadataField.Type.TEXT_LONG, null, null, null, null, null, null, null)); final MetadataField seriesMetadataField = new MetadataField( "isPartOf", "isPartOf", "EVENTS.EVENTS.DETAILS.METADATA.SERIES", false, false, null, null, MetadataField.Type.TEXT, null, null, null, null, null, null, null); seriesMetadataField.setValue("series-1"); metadataCollection.addField(seriesMetadataField); MetadataList metadataList = new MetadataList(); metadataList.getMetadataList().put("dublincore/episode", new MetadataList.TitledMetadataCollection("EVENTS.EVENTS.DETAILS.CATALOG.EPISODE", metadataCollection)); String eventId = "event-1"; Event event = new Event(eventId, org); event.setTitle("Test Event 1"); SearchQuery query = EasyMock.createMock(SearchQuery.class); EasyMock.expect(query.getLimit()).andReturn(100); EasyMock.expect(query.getOffset()).andReturn(0); EasyMock.replay(query); SearchResultItemImpl<Event> searchResultItem = new SearchResultItemImpl<>(1.0, event); SearchResultImpl<Event> searchResult = new SearchResultImpl<>(query, 0, 0); searchResult.addResultItem(searchResultItem); SecurityService securityService = setupSecurityService(username, org); AbstractSearchIndex index = EasyMock.createMock(AbstractSearchIndex.class); MediaPackage mp = MediaPackageBuilderFactory.newInstance().newMediaPackageBuilder() .loadFromXml(getClass().getResourceAsStream("/events/update-event-mp.xml")); EasyMock.expect(index.getByQuery(EasyMock.anyObject(EventSearchQuery.class))).andReturn(searchResult); EasyMock.replay(index); Workspace workspace = EasyMock.createMock(Workspace.class); EasyMock.expect(workspace.put(EasyMock.anyString(), EasyMock.anyString(), EasyMock.anyString(), EasyMock.anyObject())).andReturn(getClass().getResource("/dublincore.xml").toURI()).anyTimes(); EasyMock.expect(workspace.read(EasyMock.anyObject())).andAnswer( () -> getClass().getResourceAsStream("/dublincore.xml")).anyTimes(); EasyMock.replay(workspace); CommonEventCatalogUIAdapter commonEventCatalogUIAdapter = setupCommonCatalogUIAdapter(workspace).getA(); SchedulerService schedulerService = EasyMock.createMock(SchedulerService.class); EasyMock.expect(schedulerService.getMediaPackage(EasyMock.anyString())).andReturn(mp); Capture<Opt<MediaPackage>> mpCapture = Capture.newInstance(); schedulerService.updateEvent(EasyMock.anyString(), EasyMock.anyObject(Opt.class), EasyMock.anyObject(Opt.class), EasyMock.anyObject(Opt.class), EasyMock.anyObject(Opt.class), EasyMock.capture(mpCapture), EasyMock.anyObject(Opt.class), EasyMock.anyObject(Opt.class)); EasyMock.expectLastCall(); EasyMock.replay(schedulerService); SeriesService seriesService = EasyMock.createMock(SeriesService.class); DublinCoreCatalog seriesDC = DublinCores.read(getClass().getResourceAsStream("/events/update-event-series.xml")); EasyMock.expect(seriesService.getSeries(EasyMock.anyString())).andReturn(seriesDC); EasyMock.expect(seriesService.getSeriesAccessControl(EasyMock.anyString())).andReturn(null); EasyMock.expect(seriesService.getSeriesElements(EasyMock.anyString())).andReturn(Opt.none()); EasyMock.replay(seriesService); IndexServiceImpl indexService = new IndexServiceImpl(); indexService.setSecurityService(securityService); indexService.setSchedulerService(schedulerService); indexService.setCommonEventCatalogUIAdapter(commonEventCatalogUIAdapter); indexService.addCatalogUIAdapter(commonEventCatalogUIAdapter); indexService.setSeriesService(seriesService); indexService.setWorkspace(workspace); MetadataList updateEventMetadata = indexService.updateEventMetadata(org, metadataList, index); Assert.assertTrue(mpCapture.hasCaptured()); Assert.assertEquals("series-1", mp.getSeries()); Assert.assertEquals(1, mp.getCatalogs(MediaPackageElements.SERIES).length); }