use of org.opencastproject.series.api.SeriesException in project opencast by opencast.
the class ThemeWorkflowOperationHandler method start.
/**
* {@inheritDoc}
*
* @see org.opencastproject.workflow.api.WorkflowOperationHandler#start(org.opencastproject.workflow.api.WorkflowInstance,
* JobContext)
*/
@Override
public WorkflowOperationResult start(final WorkflowInstance workflowInstance, JobContext context) throws WorkflowOperationException {
logger.debug("Running theme workflow operation on workflow {}", workflowInstance.getId());
final MediaPackageElementFlavor bumperFlavor = getOptConfig(workflowInstance, BUMPER_FLAVOR).map(toMediaPackageElementFlavor).getOr(new MediaPackageElementFlavor("branding", "bumper"));
final MediaPackageElementFlavor trailerFlavor = getOptConfig(workflowInstance, TRAILER_FLAVOR).map(toMediaPackageElementFlavor).getOr(new MediaPackageElementFlavor("branding", "trailer"));
final MediaPackageElementFlavor titleSlideFlavor = getOptConfig(workflowInstance, TITLE_SLIDE_FLAVOR).map(toMediaPackageElementFlavor).getOr(new MediaPackageElementFlavor("branding", "title-slide"));
final MediaPackageElementFlavor licenseSlideFlavor = getOptConfig(workflowInstance, LICENSE_SLIDE_FLAVOR).map(toMediaPackageElementFlavor).getOr(new MediaPackageElementFlavor("branding", "license-slide"));
final MediaPackageElementFlavor watermarkFlavor = getOptConfig(workflowInstance, WATERMARK_FLAVOR).map(toMediaPackageElementFlavor).getOr(new MediaPackageElementFlavor("branding", "watermark"));
final List<String> bumperTags = asList(workflowInstance.getConfiguration(BUMPER_TAGS));
final List<String> trailerTags = asList(workflowInstance.getConfiguration(TRAILER_TAGS));
final List<String> titleSlideTags = asList(workflowInstance.getConfiguration(TITLE_SLIDE_TAGS));
final List<String> licenseSlideTags = asList(workflowInstance.getConfiguration(LICENSE_SLIDE_TAGS));
final List<String> watermarkTags = asList(workflowInstance.getConfiguration(WATERMARK_TAGS));
Opt<String> layoutStringOpt = getOptConfig(workflowInstance, WATERMARK_LAYOUT);
Opt<String> watermarkLayoutVariable = getOptConfig(workflowInstance, WATERMARK_LAYOUT_VARIABLE);
List<String> layoutList = new ArrayList<>(Stream.$(layoutStringOpt).bind(Strings.split(";")).toList());
try {
MediaPackage mediaPackage = workflowInstance.getMediaPackage();
String series = mediaPackage.getSeries();
if (series == null) {
logger.info("Skipping theme workflow operation, no series assigned to mediapackage {}", mediaPackage.getIdentifier());
return createResult(Action.SKIP);
}
Long themeId;
try {
themeId = Long.parseLong(seriesService.getSeriesProperty(series, THEME_PROPERTY_NAME));
} catch (NotFoundException e) {
logger.info("Skipping theme workflow operation, no theme assigned to series {} on mediapackage {}.", series, mediaPackage.getIdentifier());
return createResult(Action.SKIP);
} catch (UnauthorizedException e) {
logger.warn("Skipping theme workflow operation, user not authorized to perform operation: {}", ExceptionUtils.getStackTrace(e));
return createResult(Action.SKIP);
}
Theme theme;
try {
theme = themesServiceDatabase.getTheme(themeId);
} catch (NotFoundException e) {
logger.warn("Skipping theme workflow operation, no theme with id {} found.", themeId);
return createResult(Action.SKIP);
}
logger.info("Applying theme {} to mediapackage {}", themeId, mediaPackage.getIdentifier());
/* Make theme settings available to workflow instance */
workflowInstance.setConfiguration(THEME_ACTIVE, Boolean.toString(theme.isBumperActive() || theme.isTrailerActive() || theme.isTitleSlideActive() || theme.isWatermarkActive()));
workflowInstance.setConfiguration(THEME_BUMPER_ACTIVE, Boolean.toString(theme.isBumperActive()));
workflowInstance.setConfiguration(THEME_TRAILER_ACTIVE, Boolean.toString(theme.isTrailerActive()));
workflowInstance.setConfiguration(THEME_TITLE_SLIDE_ACTIVE, Boolean.toString(theme.isTitleSlideActive()));
workflowInstance.setConfiguration(THEME_TITLE_SLIDE_UPLOADED, Boolean.toString(StringUtils.isNotBlank(theme.getTitleSlideBackground())));
workflowInstance.setConfiguration(THEME_WATERMARK_ACTIVE, Boolean.toString(theme.isWatermarkActive()));
if (theme.isBumperActive() && StringUtils.isNotBlank(theme.getBumperFile())) {
try (InputStream bumper = staticFileService.getFile(theme.getBumperFile())) {
addElement(mediaPackage, bumperFlavor, bumperTags, bumper, staticFileService.getFileName(theme.getBumperFile()), Type.Track);
} catch (NotFoundException e) {
logger.warn("Bumper file {} not found in static file service, skip applying it", theme.getBumperFile());
}
}
if (theme.isTrailerActive() && StringUtils.isNotBlank(theme.getTrailerFile())) {
try (InputStream trailer = staticFileService.getFile(theme.getTrailerFile())) {
addElement(mediaPackage, trailerFlavor, trailerTags, trailer, staticFileService.getFileName(theme.getTrailerFile()), Type.Track);
} catch (NotFoundException e) {
logger.warn("Trailer file {} not found in static file service, skip applying it", theme.getTrailerFile());
}
}
if (theme.isTitleSlideActive()) {
if (StringUtils.isNotBlank(theme.getTitleSlideBackground())) {
try (InputStream titleSlideBackground = staticFileService.getFile(theme.getTitleSlideBackground())) {
addElement(mediaPackage, titleSlideFlavor, titleSlideTags, titleSlideBackground, staticFileService.getFileName(theme.getTitleSlideBackground()), Type.Attachment);
} catch (NotFoundException e) {
logger.warn("Title slide file {} not found in static file service, skip applying it", theme.getTitleSlideBackground());
}
}
// TODO add the title slide metadata to the workflow properties to be used by the cover-image WOH
// String titleSlideMetadata = theme.getTitleSlideMetadata();
}
if (theme.isLicenseSlideActive()) {
if (StringUtils.isNotBlank(theme.getLicenseSlideBackground())) {
try (InputStream licenseSlideBackground = staticFileService.getFile(theme.getLicenseSlideBackground())) {
addElement(mediaPackage, licenseSlideFlavor, licenseSlideTags, licenseSlideBackground, staticFileService.getFileName(theme.getLicenseSlideBackground()), Type.Attachment);
} catch (NotFoundException e) {
logger.warn("License slide file {} not found in static file service, skip applying it", theme.getLicenseSlideBackground());
}
} else {
// TODO define what to do here (maybe extract image as background)
}
// TODO add the license slide description to the workflow properties to be used by the cover-image WOH
// String licenseSlideDescription = theme.getLicenseSlideDescription();
}
if (theme.isWatermarkActive() && StringUtils.isNotBlank(theme.getWatermarkFile())) {
try (InputStream watermark = staticFileService.getFile(theme.getWatermarkFile())) {
addElement(mediaPackage, watermarkFlavor, watermarkTags, watermark, staticFileService.getFileName(theme.getWatermarkFile()), Type.Attachment);
} catch (NotFoundException e) {
logger.warn("Watermark file {} not found in static file service, skip applying it", theme.getWatermarkFile());
}
if (layoutStringOpt.isNone() || watermarkLayoutVariable.isNone())
throw new WorkflowOperationException(format("Configuration key '%s' or '%s' is either missing or empty", WATERMARK_LAYOUT, WATERMARK_LAYOUT_VARIABLE));
AbsolutePositionLayoutSpec watermarkLayout = parseLayout(theme.getWatermarkPosition());
layoutList.set(layoutList.size() - 1, Serializer.json(watermarkLayout).toJson());
layoutStringOpt = Opt.some(Stream.$(layoutList).mkString(";"));
}
if (watermarkLayoutVariable.isSome() && layoutStringOpt.isSome())
workflowInstance.setConfiguration(watermarkLayoutVariable.get(), layoutStringOpt.get());
return createResult(mediaPackage, Action.CONTINUE);
} catch (SeriesException | ThemesServiceDatabaseException | IllegalStateException | IllegalArgumentException | IOException e) {
throw new WorkflowOperationException(e);
}
}
use of org.opencastproject.series.api.SeriesException in project opencast by opencast.
the class WorkflowServiceImpl method update.
/**
* {@inheritDoc}
*
* @see org.opencastproject.workflow.api.WorkflowService#update(org.opencastproject.workflow.api.WorkflowInstance)
*/
@Override
public void update(final WorkflowInstance workflowInstance) throws WorkflowException, UnauthorizedException {
final Lock lock = updateLock.get(workflowInstance.getId());
lock.lock();
try {
WorkflowInstance originalWorkflowInstance = null;
try {
originalWorkflowInstance = getWorkflowById(workflowInstance.getId());
} catch (NotFoundException e) {
// That's fine, it's a new workflow instance
}
if (originalWorkflowInstance != null) {
try {
assertPermission(originalWorkflowInstance, Permissions.Action.WRITE.toString());
} catch (MediaPackageException e) {
throw new WorkflowParsingException(e);
}
}
MediaPackage updatedMediaPackage = null;
try {
// Before we persist this, extract the metadata
updatedMediaPackage = workflowInstance.getMediaPackage();
populateMediaPackageMetadata(updatedMediaPackage);
String seriesId = updatedMediaPackage.getSeries();
if (seriesId != null && workflowInstance.getCurrentOperation() != null) {
// If the mediapackage contains a series, find the series ACLs and add the security information to the
// mediapackage
AccessControlList acl = seriesService.getSeriesAccessControl(seriesId);
Option<AccessControlList> activeSeriesAcl = authorizationService.getAcl(updatedMediaPackage, AclScope.Series);
if (activeSeriesAcl.isNone() || !AccessControlUtil.equals(activeSeriesAcl.get(), acl))
authorizationService.setAcl(updatedMediaPackage, AclScope.Series, acl);
}
} catch (SeriesException e) {
throw new WorkflowDatabaseException(e);
} catch (NotFoundException e) {
logger.warn("Metadata for mediapackage {} could not be updated because it wasn't found", updatedMediaPackage, e);
} catch (Exception e) {
logger.error("Metadata for mediapackage {} could not be updated", updatedMediaPackage, e);
}
// Synchronize the job status with the workflow
WorkflowState workflowState = workflowInstance.getState();
String xml;
try {
xml = WorkflowParser.toXml(workflowInstance);
} catch (Exception e) {
// Can't happen, since we are converting from an in-memory object
throw new IllegalStateException("In-memory workflow instance could not be serialized", e);
}
Job job = null;
try {
job = serviceRegistry.getJob(workflowInstance.getId());
job.setPayload(xml);
// Synchronize workflow and job state
switch(workflowState) {
case FAILED:
job.setStatus(Status.FAILED);
break;
case FAILING:
break;
case INSTANTIATED:
job.setDispatchable(true);
job.setStatus(Status.QUEUED);
break;
case PAUSED:
job.setStatus(Status.PAUSED);
break;
case RUNNING:
job.setStatus(Status.RUNNING);
break;
case STOPPED:
job.setStatus(Status.CANCELED);
break;
case SUCCEEDED:
job.setStatus(Status.FINISHED);
break;
default:
throw new IllegalStateException("Found a workflow state that is not handled");
}
} catch (ServiceRegistryException e) {
logger.error(e, "Unable to read workflow job %s from service registry", workflowInstance.getId());
throw new WorkflowDatabaseException(e);
} catch (NotFoundException e) {
logger.error("Job for workflow %s not found in service registry", workflowInstance.getId());
throw new WorkflowDatabaseException(e);
}
// Update both workflow and workflow job
try {
job = serviceRegistry.updateJob(job);
messageSender.sendObjectMessage(WorkflowItem.WORKFLOW_QUEUE, MessageSender.DestinationType.Queue, WorkflowItem.updateInstance(workflowInstance));
index(workflowInstance);
} catch (ServiceRegistryException e) {
logger.error("Update of workflow job %s in the service registry failed, service registry and workflow index may be out of sync", workflowInstance.getId());
throw new WorkflowDatabaseException(e);
} catch (NotFoundException e) {
logger.error("Job for workflow %s not found in service registry", workflowInstance.getId());
throw new WorkflowDatabaseException(e);
} catch (Exception e) {
logger.error("Update of workflow job %s in the service registry failed, service registry and workflow index may be out of sync", job.getId());
throw new WorkflowException(e);
}
if (workflowStatsCollect) {
workflowsStatistics.updateWorkflow(getBeanStatistics(), getHoldWorkflows());
}
try {
WorkflowInstance clone = WorkflowParser.parseWorkflowInstance(WorkflowParser.toXml(workflowInstance));
fireListeners(originalWorkflowInstance, clone);
} catch (Exception e) {
// Can't happen, since we are converting from an in-memory object
throw new IllegalStateException("In-memory workflow instance could not be serialized", e);
}
} finally {
lock.unlock();
}
}
use of org.opencastproject.series.api.SeriesException in project opencast by opencast.
the class SeriesWorkflowOperationHandler method start.
/**
* {@inheritDoc}
*
* @see org.opencastproject.workflow.api.WorkflowOperationHandler#start(org.opencastproject.workflow.api.WorkflowInstance,
* JobContext)
*/
@Override
public WorkflowOperationResult start(final WorkflowInstance workflowInstance, JobContext context) throws WorkflowOperationException {
logger.debug("Running series workflow operation");
MediaPackage mediaPackage = workflowInstance.getMediaPackage();
Opt<String> optSeries = getOptConfig(workflowInstance.getCurrentOperation(), SERIES_PROPERTY);
Opt<String> optAttachFlavors = getOptConfig(workflowInstance.getCurrentOperation(), ATTACH_PROPERTY);
Boolean applyAcl = getOptConfig(workflowInstance.getCurrentOperation(), APPLY_ACL_PROPERTY).map(toBoolean).getOr(false);
Opt<String> optCopyMetadata = getOptConfig(workflowInstance.getCurrentOperation(), COPY_METADATA_PROPERTY);
String defaultNamespace = getOptConfig(workflowInstance.getCurrentOperation(), DEFAULT_NS_PROPERTY).getOr(DublinCore.TERMS_NS_URI);
logger.debug("Using default namespace: '{}'", defaultNamespace);
if (optSeries.isSome() && !optSeries.get().equals(mediaPackage.getSeries())) {
logger.info("Changing series id from '{}' to '{}'", StringUtils.trimToEmpty(mediaPackage.getSeries()), optSeries.get());
mediaPackage.setSeries(optSeries.get());
}
String seriesId = mediaPackage.getSeries();
if (seriesId == null) {
logger.info("No series set, skip operation");
return createResult(mediaPackage, Action.SKIP);
}
DublinCoreCatalog series;
try {
series = seriesService.getSeries(seriesId);
} catch (NotFoundException e) {
logger.info("No series with the identifier '{}' found, skip operation", seriesId);
return createResult(mediaPackage, Action.SKIP);
} catch (UnauthorizedException e) {
logger.warn("Not authorized to get series with identifier '{}' found, skip operation", seriesId);
return createResult(mediaPackage, Action.SKIP);
} catch (SeriesException e) {
logger.error("Unable to get series with identifier '{}', skip operation: {}", seriesId, ExceptionUtils.getStackTrace(e));
throw new WorkflowOperationException(e);
}
mediaPackage.setSeriesTitle(series.getFirst(DublinCore.PROPERTY_TITLE));
// Process extra metadata
HashSet<EName> extraMetadata = new HashSet<>();
if (optCopyMetadata.isSome()) {
for (String strEName : optCopyMetadata.get().split(",+\\s*")) try {
if (!strEName.isEmpty()) {
extraMetadata.add(EName.fromString(strEName, defaultNamespace));
}
} catch (IllegalArgumentException iae) {
logger.warn("Ignoring incorrect dublincore metadata property: '{}'", strEName);
}
}
// Update the episode catalog
for (Catalog episodeCatalog : mediaPackage.getCatalogs(MediaPackageElements.EPISODE)) {
DublinCoreCatalog episodeDublinCore = DublinCoreUtil.loadDublinCore(workspace, episodeCatalog);
// Make sure the MP catalog has bindings defined
episodeDublinCore.addBindings(XmlNamespaceContext.mk(XmlNamespaceBinding.mk(DublinCore.TERMS_NS_PREFIX, DublinCore.TERMS_NS_URI)));
episodeDublinCore.addBindings(XmlNamespaceContext.mk(XmlNamespaceBinding.mk(DublinCore.ELEMENTS_1_1_NS_PREFIX, DublinCore.ELEMENTS_1_1_NS_URI)));
episodeDublinCore.addBindings(XmlNamespaceContext.mk(XmlNamespaceBinding.mk(DublinCores.OC_PROPERTY_NS_PREFIX, DublinCores.OC_PROPERTY_NS_URI)));
episodeDublinCore.set(DublinCore.PROPERTY_IS_PART_OF, seriesId);
for (EName property : extraMetadata) {
if (!episodeDublinCore.hasValue(property) && series.hasValue(property)) {
episodeDublinCore.set(property, series.get(property));
}
}
try (InputStream in = IOUtils.toInputStream(episodeDublinCore.toXmlString(), "UTF-8")) {
String filename = FilenameUtils.getName(episodeCatalog.getURI().toString());
URI uri = workspace.put(mediaPackage.getIdentifier().toString(), episodeCatalog.getIdentifier(), filename, in);
episodeCatalog.setURI(uri);
// setting the URI to a new source so the checksum will most like be invalid
episodeCatalog.setChecksum(null);
} catch (Exception e) {
logger.error("Unable to update episode catalog isPartOf field: {}", ExceptionUtils.getStackTrace(e));
throw new WorkflowOperationException(e);
}
}
// Attach series catalogs
if (optAttachFlavors.isSome()) {
// Remove existing series catalogs
AbstractMediaPackageElementSelector<Catalog> catalogSelector = new CatalogSelector();
String[] seriesFlavors = StringUtils.split(optAttachFlavors.get(), ",");
for (String flavor : seriesFlavors) {
if ("*".equals(flavor)) {
catalogSelector.addFlavor("*/*");
} else {
catalogSelector.addFlavor(flavor);
}
}
for (Catalog c : catalogSelector.select(mediaPackage, false)) {
if (MediaPackageElements.SERIES.equals(c.getFlavor()) || "series".equals(c.getFlavor().getSubtype())) {
mediaPackage.remove(c);
}
}
List<SeriesCatalogUIAdapter> adapters = getSeriesCatalogUIAdapters();
for (String flavorString : seriesFlavors) {
MediaPackageElementFlavor flavor;
if ("*".equals(flavorString)) {
flavor = MediaPackageElementFlavor.parseFlavor("*/*");
} else {
flavor = MediaPackageElementFlavor.parseFlavor(flavorString);
}
for (SeriesCatalogUIAdapter a : adapters) {
MediaPackageElementFlavor adapterFlavor = MediaPackageElementFlavor.parseFlavor(a.getFlavor());
if (flavor.matches(adapterFlavor)) {
if (MediaPackageElements.SERIES.eq(a.getFlavor())) {
addDublinCoreCatalog(series, MediaPackageElements.SERIES, mediaPackage);
} else {
try {
Opt<byte[]> seriesElementData = seriesService.getSeriesElementData(seriesId, adapterFlavor.getType());
if (seriesElementData.isSome()) {
DublinCoreCatalog catalog = DublinCores.read(new ByteArrayInputStream(seriesElementData.get()));
addDublinCoreCatalog(catalog, adapterFlavor, mediaPackage);
} else {
logger.warn("No extended series catalog found for flavor '{}' and series '{}', skip adding catalog", adapterFlavor.getType(), seriesId);
}
} catch (SeriesException e) {
logger.error("Unable to load extended series metadata for flavor {}", adapterFlavor.getType());
throw new WorkflowOperationException(e);
}
}
}
}
}
}
if (applyAcl) {
try {
AccessControlList acl = seriesService.getSeriesAccessControl(seriesId);
if (acl != null)
authorizationService.setAcl(mediaPackage, AclScope.Series, acl);
} catch (Exception e) {
logger.error("Unable to update series ACL: {}", ExceptionUtils.getStackTrace(e));
throw new WorkflowOperationException(e);
}
}
return createResult(mediaPackage, Action.CONTINUE);
}
use of org.opencastproject.series.api.SeriesException in project opencast by opencast.
the class SeriesEndpoint method getSeriesAccessInformation.
@GET
@Path("{seriesId}/access.json")
@SuppressWarnings("unchecked")
@Produces(MediaType.APPLICATION_JSON)
@RestQuery(name = "getseriesaccessinformation", description = "Get the access information of a series", returnDescription = "The access information", pathParameters = { @RestParameter(name = "seriesId", isRequired = true, description = "The series identifier", type = Type.STRING) }, reponses = { @RestResponse(responseCode = SC_BAD_REQUEST, description = "The required form params were missing in the request."), @RestResponse(responseCode = SC_NOT_FOUND, description = "If the series has not been found."), @RestResponse(responseCode = SC_OK, description = "The access information ") })
public Response getSeriesAccessInformation(@PathParam("seriesId") String seriesId) throws NotFoundException {
if (StringUtils.isBlank(seriesId))
return RestUtil.R.badRequest("Path parameter series ID is missing");
boolean hasProcessingEvents = hasProcessingEvents(seriesId);
// Add all available ACLs to the response
JSONArray systemAclsJson = new JSONArray();
List<ManagedAcl> acls = getAclService().getAcls();
for (ManagedAcl acl : acls) {
systemAclsJson.add(AccessInformationUtil.serializeManagedAcl(acl));
}
final TransitionQuery q = TransitionQuery.query().withId(seriesId).withScope(AclScope.Series);
List<SeriesACLTransition> seriesTransistions;
JSONArray transitionsJson = new JSONArray();
try {
seriesTransistions = getAclService().getTransitions(q).getSeriesTransistions();
for (SeriesACLTransition trans : seriesTransistions) {
transitionsJson.add(AccessInformationUtil.serializeSeriesACLTransition(trans));
}
} catch (AclServiceException e) {
logger.error("There was an error while trying to get the ACL transitions for serie '{}' from the ACL service: {}", seriesId, e);
return RestUtil.R.serverError();
}
JSONObject seriesAccessJson = new JSONObject();
try {
AccessControlList seriesAccessControl = seriesService.getSeriesAccessControl(seriesId);
Option<ManagedAcl> currentAcl = AccessInformationUtil.matchAcls(acls, seriesAccessControl);
seriesAccessJson.put("current_acl", currentAcl.isSome() ? currentAcl.get().getId() : 0);
seriesAccessJson.put("privileges", AccessInformationUtil.serializePrivilegesByRole(seriesAccessControl));
seriesAccessJson.put("acl", AccessControlParser.toJsonSilent(seriesAccessControl));
seriesAccessJson.put("transitions", transitionsJson);
seriesAccessJson.put("locked", hasProcessingEvents);
} catch (SeriesException e) {
logger.error("Unable to get ACL from series {}: {}", seriesId, ExceptionUtils.getStackTrace(e));
return RestUtil.R.serverError();
}
JSONObject jsonReturnObj = new JSONObject();
jsonReturnObj.put("system_acls", systemAclsJson);
jsonReturnObj.put("series_access", seriesAccessJson);
return Response.ok(jsonReturnObj.toString()).build();
}
use of org.opencastproject.series.api.SeriesException in project opencast by opencast.
the class SeriesEndpoint method updateSeriesTheme.
@PUT
@Path("{seriesId}/theme")
@RestQuery(name = "updateSeriesTheme", description = "Update the series theme id", returnDescription = "Returns the id and name of the theme.", pathParameters = { @RestParameter(name = "seriesId", isRequired = true, description = "The series identifier", type = STRING) }, restParameters = { @RestParameter(name = "themeId", isRequired = true, type = RestParameter.Type.INTEGER, description = "The id of the theme for this series") }, reponses = { @RestResponse(responseCode = SC_OK, description = "The series theme has been updated and the theme id and name are returned as JSON."), @RestResponse(responseCode = SC_NOT_FOUND, description = "The series or theme has not been found"), @RestResponse(responseCode = SC_UNAUTHORIZED, description = "If the current user is not authorized to perform this action") })
public Response updateSeriesTheme(@PathParam("seriesId") String seriesID, @FormParam("themeId") long themeId) throws UnauthorizedException, NotFoundException {
try {
Opt<Theme> themeOpt = getTheme(themeId);
if (themeOpt.isNone())
return notFound("Cannot find a theme with id {}", themeId);
seriesService.updateSeriesProperty(seriesID, THEME_KEY, Long.toString(themeId));
return getSimpleThemeJsonResponse(themeOpt.get());
} catch (SeriesException e) {
logger.error("Unable to update series theme {}: {}", themeId, ExceptionUtils.getStackTrace(e));
throw new WebApplicationException(e);
} catch (SearchIndexException e) {
logger.error("Unable to get theme {}: {}", themeId, ExceptionUtils.getStackTrace(e));
throw new WebApplicationException(e);
}
}
Aggregations