From 776e1719d3999b656183b47414370c0970a8b2ae Mon Sep 17 00:00:00 2001 From: jensp Date: Thu, 27 Jul 2017 10:26:14 +0000 Subject: [PATCH] CCM NG/ccm-cms: Thumbnails for images in AssetBrowser git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@4888 8810af33-2d31-482b-a856-94f89814c4df Former-commit-id: f7d72938683ccdf86affd4ebcb673405a90c447c --- .../cms/ui/assets/AssetFolderBrowser.java | 25 ++ .../assets/AssetFolderBrowserController.java | 296 ++++++++-------- .../assets/AssetFolderBrowserTableModel.java | 9 +- .../ui/assets/AssetFolderBrowserTableRow.java | 9 + .../librecms/contentsection/rs/Images.java | 317 +++++++++++------- .../org/librecms/CmsResources.properties | 1 + .../org/librecms/CmsResources_de.properties | 1 + .../org/librecms/CmsResources_fr.properties | 1 + .../dispatcher/DispatcherHelper.java | 29 +- .../src/main/java/com/arsdigita/web/URL.java | 2 +- 10 files changed, 418 insertions(+), 272 deletions(-) diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetFolderBrowser.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetFolderBrowser.java index 8250ab6aa..312b33171 100644 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetFolderBrowser.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetFolderBrowser.java @@ -101,6 +101,8 @@ public class AssetFolderBrowser extends Table { CMS_FOLDER_BUNDLE), new GlobalizedMessage("cms.ui.folder.type", CMS_FOLDER_BUNDLE), + new GlobalizedMessage("cms.ui.asset.thumbnail", + CMS_BUNDLE), new GlobalizedMessage("cms.ui.folder.creation_date", CMS_FOLDER_BUNDLE), new GlobalizedMessage("cms.ui.folder.last_modified", @@ -120,6 +122,9 @@ public class AssetFolderBrowser extends Table { nameColumn.setCellRenderer(new NameCellRenderer()); nameColumn.setHeaderRenderer(new HeaderCellRenderer(SORT_KEY_NAME)); + getColumn(AssetFolderBrowserTableModel.COL_THUMBNAIL) + .setCellRenderer(new ThumbnailCellRenderer()); + getColumn(AssetFolderBrowserTableModel.COL_CREATION_DATE) .setHeaderRenderer( new HeaderCellRenderer(SORT_KEY_CREATION_DATE)); @@ -305,6 +310,26 @@ public class AssetFolderBrowser extends Table { } + private class ThumbnailCellRenderer implements TableCellRenderer { + + @Override + public Component getComponent(final Table table, + final PageState state, + final Object value, + final boolean isSelected, + final Object key, + final int row, + final int column) { + if (value == null) { + return new Text(""); + } else { + final Image image = new Image((String) value, ""); + return image; + } + } + + } + private class DateCellRenderer implements TableCellRenderer { @Override diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetFolderBrowserController.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetFolderBrowserController.java index f7cea3a99..b3ed0b26b 100644 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetFolderBrowserController.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetFolderBrowserController.java @@ -18,7 +18,9 @@ */ package com.arsdigita.cms.ui.assets; +import com.arsdigita.cms.CMS; import com.arsdigita.kernel.KernelConfig; +import com.arsdigita.web.CCMDispatcherServlet; import org.libreccm.categorization.Category; import org.libreccm.categorization.CategoryManager; @@ -58,8 +60,10 @@ import org.librecms.contentsection.FolderRepository; import java.util.Collections; import java.util.Optional; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.librecms.assets.Image; import static org.librecms.CmsConstants.*; @@ -71,7 +75,7 @@ import static org.librecms.CmsConstants.*; public class AssetFolderBrowserController { private static final Logger LOGGER = LogManager - .getLogger(AssetFolderBrowserController.class); + .getLogger(AssetFolderBrowserController.class); @Inject private EntityManager entityManager; @@ -111,7 +115,7 @@ public class AssetFolderBrowserController { @PostConstruct private void init() { final KernelConfig kernelConfig = confManager.findConfiguration( - KernelConfig.class); + KernelConfig.class); defaultLocale = kernelConfig.getDefaultLocale(); } @@ -128,9 +132,9 @@ public class AssetFolderBrowserController { firstResult, maxResults); final List subFolderRows = subFolders - .stream() - .map(subFolder -> buildRow(subFolder)) - .collect(Collectors.toList()); + .stream() + .map(subFolder -> buildRow(subFolder)) + .collect(Collectors.toList()); if (subFolders.size() > maxResults) { return subFolderRows; @@ -145,9 +149,9 @@ public class AssetFolderBrowserController { firstAsset, maxAssets); final List assetRows = assets - .stream() - .map(asset -> buildRow(asset)) - .collect(Collectors.toList()); + .stream() + .map(asset -> buildRow(asset)) + .collect(Collectors.toList()); final List rows = new ArrayList<>(); rows.addAll(subFolderRows); @@ -177,19 +181,19 @@ public class AssetFolderBrowserController { criteriaQuery = criteriaQuery.select(builder.count(from)); final List subFolders = findSubFolders( - folder, - filterTerm, - AssetFolderBrowser.SORT_KEY_NAME, - AssetFolderBrowser.SORT_ACTION_UP, - -1, - -1); + folder, + filterTerm, + AssetFolderBrowser.SORT_KEY_NAME, + AssetFolderBrowser.SORT_ACTION_UP, + -1, + -1); final List assets = findAssetsInFolder( - folder, - filterTerm, - AssetFolderBrowser.SORT_KEY_NAME, - AssetFolderBrowser.SORT_ACTION_UP, - -1, - -1); + folder, + filterTerm, + AssetFolderBrowser.SORT_KEY_NAME, + AssetFolderBrowser.SORT_ACTION_UP, + -1, + -1); if (subFolders.isEmpty() && assets.isEmpty()) { return 0; @@ -199,8 +203,8 @@ public class AssetFolderBrowserController { criteriaQuery = criteriaQuery.where(from.in(subFolders)); } else { criteriaQuery = criteriaQuery.where(builder.or( - from.in(subFolders), - from.in(assets))); + from.in(subFolders), + from.in(assets))); } return entityManager.createQuery(criteriaQuery).getSingleResult(); @@ -218,17 +222,17 @@ public class AssetFolderBrowserController { if (objectId.startsWith(FOLDER_BROWSER_KEY_PREFIX_FOLDER)) { copyFolder(targetFolder, Long.parseLong(objectId.substring( - FOLDER_BROWSER_KEY_PREFIX_FOLDER.length()))); + FOLDER_BROWSER_KEY_PREFIX_FOLDER.length()))); } else if (objectId.startsWith(FOLDER_BROWSER_KEY_PREFIX_ASSET)) { copyAsset(targetFolder, Long.parseLong(objectId.substring( - FOLDER_BROWSER_KEY_PREFIX_ASSET.length()))); + FOLDER_BROWSER_KEY_PREFIX_ASSET.length()))); } else { throw new IllegalArgumentException(String.format( - "ID '%s' does not start with '%s' or '%s'.", - objectId, - FOLDER_BROWSER_KEY_PREFIX_FOLDER, - FOLDER_BROWSER_KEY_PREFIX_ASSET)); + "ID '%s' does not start with '%s' or '%s'.", + objectId, + FOLDER_BROWSER_KEY_PREFIX_FOLDER, + FOLDER_BROWSER_KEY_PREFIX_ASSET)); } } @@ -240,10 +244,10 @@ public class AssetFolderBrowserController { Objects.requireNonNull(targetFolder); final Folder folder = folderRepo.findById(folderId) - .orElseThrow(() -> new IllegalArgumentException(String.format( - "No folder with ID %d in the database. " - + "Where did that ID come from?", - folderId))); + .orElseThrow(() -> new IllegalArgumentException(String.format( + "No folder with ID %d in the database. " + + "Where did that ID come from?", + folderId))); folderManager.copyFolder(folder, targetFolder); @@ -255,10 +259,10 @@ public class AssetFolderBrowserController { Objects.requireNonNull(targetFolder); final Asset asset = assetRepo - .findById(assetId) - .orElseThrow(() -> new IllegalArgumentException(String.format( - "No asset ith ID %d in the database. Where did that ID come from?", - assetId))); + .findById(assetId) + .orElseThrow(() -> new IllegalArgumentException(String.format( + "No asset ith ID %d in the database. Where did that ID come from?", + assetId))); assetManager.copy(asset, targetFolder); } @@ -274,17 +278,17 @@ public class AssetFolderBrowserController { if (objectId.startsWith(FOLDER_BROWSER_KEY_PREFIX_FOLDER)) { moveFolder(targetFolder, Long.parseLong(objectId.substring( - FOLDER_BROWSER_KEY_PREFIX_FOLDER.length()))); + FOLDER_BROWSER_KEY_PREFIX_FOLDER.length()))); } else if (objectId.startsWith(FOLDER_BROWSER_KEY_PREFIX_ASSET)) { moveAsset(targetFolder, Long.parseLong(objectId.substring( - FOLDER_BROWSER_KEY_PREFIX_ASSET.length()))); + FOLDER_BROWSER_KEY_PREFIX_ASSET.length()))); } else { throw new IllegalArgumentException(String.format( - "ID '%s' does not start with '%s' or '%s'.", - objectId, - FOLDER_BROWSER_KEY_PREFIX_FOLDER, - FOLDER_BROWSER_KEY_PREFIX_ASSET)); + "ID '%s' does not start with '%s' or '%s'.", + objectId, + FOLDER_BROWSER_KEY_PREFIX_FOLDER, + FOLDER_BROWSER_KEY_PREFIX_ASSET)); } } } @@ -294,10 +298,10 @@ public class AssetFolderBrowserController { Objects.requireNonNull(targetFolder); final Folder folder = folderRepo.findById(folderId) - .orElseThrow(() -> new IllegalArgumentException(String.format( - "No folder with ID %d in the database. " - + "Where did that ID come from?", - folderId))); + .orElseThrow(() -> new IllegalArgumentException(String.format( + "No folder with ID %d in the database. " + + "Where did that ID come from?", + folderId))); folderManager.moveFolder(folder, targetFolder); } @@ -307,10 +311,10 @@ public class AssetFolderBrowserController { Objects.requireNonNull(targetFolder); final Asset asset = assetRepo - .findById(assetId) - .orElseThrow(() -> new IllegalArgumentException(String.format( - "No asset with ID %d in the database. Where did that ID come from?", - assetId))); + .findById(assetId) + .orElseThrow(() -> new IllegalArgumentException(String.format( + "No asset with ID %d in the database. Where did that ID come from?", + assetId))); assetManager.move(asset, targetFolder); } @@ -321,20 +325,20 @@ public class AssetFolderBrowserController { Objects.requireNonNull(sources); final List sourceFolderIds = sources - .stream() - .filter(source -> source.startsWith( - FOLDER_BROWSER_KEY_PREFIX_FOLDER)) - .collect(Collectors.toList()); + .stream() + .filter(source -> source.startsWith( + FOLDER_BROWSER_KEY_PREFIX_FOLDER)) + .collect(Collectors.toList()); final List parentFolderIds = sourceFolderIds - .stream() - .map(sourceFolderId -> findParentFolderId(sourceFolderId)) - .filter(Optional::isPresent) - .map(Optional::get) - .collect(Collectors.toList()); + .stream() + .map(sourceFolderId -> findParentFolderId(sourceFolderId)) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toList()); final List> subFolderIds = sourceFolderIds - .stream() - .map(sourceFolderId -> findSubFolderIds(sourceFolderId)) - .collect(Collectors.toList()); + .stream() + .map(sourceFolderId -> findSubFolderIds(sourceFolderId)) + .collect(Collectors.toList()); final List invalidTargetIds = new ArrayList<>(); invalidTargetIds.addAll(sourceFolderIds); @@ -353,26 +357,26 @@ public class AssetFolderBrowserController { if (!folderId.startsWith(FOLDER_BROWSER_KEY_PREFIX_FOLDER)) { throw new IllegalArgumentException(String.format( - "Provided string '%s' is not an ID of a folder.", - folderId)); + "Provided string '%s' is not an ID of a folder.", + folderId)); } final long objectId = Long.parseLong(folderId.substring( - FOLDER_BROWSER_KEY_PREFIX_FOLDER.length())); + FOLDER_BROWSER_KEY_PREFIX_FOLDER.length())); final Folder folder = folderRepo.findById(objectId) - .orElseThrow(() -> new IllegalArgumentException(String.format( - "No folder with ID %d found in database. " - + "Where did that ID come form?", - objectId))); + .orElseThrow(() -> new IllegalArgumentException(String.format( + "No folder with ID %d found in database. " + + "Where did that ID come form?", + objectId))); final Optional parentFolder = folderManager.getParentFolder( - folder); + folder); if (parentFolder.isPresent()) { return Optional.empty(); } else { return Optional.ofNullable(String.format( - "%s%d", - FOLDER_BROWSER_KEY_PREFIX_FOLDER, - parentFolder.get().getObjectId())); + "%s%d", + FOLDER_BROWSER_KEY_PREFIX_FOLDER, + parentFolder.get().getObjectId())); } } @@ -382,23 +386,23 @@ public class AssetFolderBrowserController { if (!folderId.startsWith(FOLDER_BROWSER_KEY_PREFIX_FOLDER)) { throw new IllegalArgumentException(String.format( - "Provided string '%s' is not the ID of a folder.", - folderId)); + "Provided string '%s' is not the ID of a folder.", + folderId)); } final long objectId = Long.parseLong(folderId.substring( - FOLDER_BROWSER_KEY_PREFIX_FOLDER.length())); + FOLDER_BROWSER_KEY_PREFIX_FOLDER.length())); final Folder folder = folderRepo.findById(objectId) - .orElseThrow(() -> new IllegalArgumentException(String.format( - "No folder with ID %d found in database. " - + "Where did that ID come form?", - objectId))); + .orElseThrow(() -> new IllegalArgumentException(String.format( + "No folder with ID %d found in database. " + + "Where did that ID come form?", + objectId))); return findSubFolders(folder) - .stream() - .map(subFolder -> String.format("%s%d", - FOLDER_BROWSER_KEY_PREFIX_FOLDER, - subFolder.getObjectId())) - .collect(Collectors.toList()); + .stream() + .map(subFolder -> String.format("%s%d", + FOLDER_BROWSER_KEY_PREFIX_FOLDER, + subFolder.getObjectId())) + .collect(Collectors.toList()); } private List findSubFolders(final Folder folder) { @@ -406,7 +410,7 @@ public class AssetFolderBrowserController { Objects.requireNonNull(folder); if (folder.getSubFolders() == null - || folder.getSubFolders().isEmpty()) { + || folder.getSubFolders().isEmpty()) { return Collections.emptyList(); } @@ -431,21 +435,21 @@ public class AssetFolderBrowserController { if (objectId.startsWith("folder-")) { final long folderId = Long.parseLong( - objectId.substring("folder-".length())); + objectId.substring("folder-".length())); folderRepo - .findById(folderId) - .ifPresent(folderRepo::delete); + .findById(folderId) + .ifPresent(folderRepo::delete); } else if (objectId.startsWith("asset-")) { final long assetId = Long.parseLong( - objectId.substring("asset-".length())); + objectId.substring("asset-".length())); assetRepo - .findById(assetId) - .ifPresent(assetRepo::delete); + .findById(assetId) + .ifPresent(assetRepo::delete); } else { throw new IllegalArgumentException( - "The objectId is expected to start with 'folder-' or 'asset-'."); + "The objectId is expected to start with 'folder-' or 'asset-'."); } } @@ -457,15 +461,15 @@ public class AssetFolderBrowserController { row.setObjectUuid(folder.getUuid()); row.setName(folder.getName()); if (folder.getTitle().hasValue(globalizationHelper - .getNegotiatedLocale())) { + .getNegotiatedLocale())) { row.setTitle(folder.getTitle().getValue(globalizationHelper - .getNegotiatedLocale())); + .getNegotiatedLocale())); } else { row.setTitle(folder.getTitle().getValue(defaultLocale)); } row.setFolder(true); row.setDeletable(!categoryManager.hasSubCategories(folder) - && !categoryManager.hasObjects(folder)); + && !categoryManager.hasObjects(folder)); return row; } @@ -478,14 +482,22 @@ public class AssetFolderBrowserController { row.setObjectUuid(asset.getUuid()); row.setName(asset.getDisplayName()); if (asset.getTitle().hasValue(globalizationHelper - .getNegotiatedLocale())) { + .getNegotiatedLocale())) { row.setTitle(asset.getTitle().getValue(globalizationHelper - .getNegotiatedLocale())); + .getNegotiatedLocale())); } else { row.setTitle(asset.getTitle().getValue(defaultLocale)); } + if (asset instanceof Image) { + row.setThumbnailUrl(String + .format("%s/content-sections/%s/images/" + + "uuid-%s?width=150&height=100", + CCMDispatcherServlet.getContextPath(), + CMS.getContext().getContentSection().getLabel(), + asset.getUuid())); + } final AssetTypeInfo typeInfo = typesManager - .getAssetTypeInfo(asset.getClass()); + .getAssetTypeInfo(asset.getClass()); row.setTypeLabelBundle(typeInfo.getLabelBundle()); row.setTypeLabelKey(typeInfo.getLabelKey()); @@ -506,32 +518,32 @@ public class AssetFolderBrowserController { final CriteriaBuilder builder = entityManager.getCriteriaBuilder(); final CriteriaQuery criteria = builder - .createQuery(Folder.class); + .createQuery(Folder.class); final Root from = criteria.from(Folder.class); final Order order; if (AssetFolderBrowser.SORT_KEY_NAME.equals(orderBy) - && AssetFolderBrowser.SORT_ACTION_DOWN. - equals(orderDirection)) { + && AssetFolderBrowser.SORT_ACTION_DOWN. + equals(orderDirection)) { order = builder.desc(from.get("name")); } else { order = builder.asc(from.get("name")); } final TypedQuery query = entityManager - .createQuery( - criteria.where( - builder.and( - builder. - equal(from.get("parentCategory"), - folder), - builder.like(builder.lower(from.get( - "name")), - filterTerm) - ) - ) - .orderBy(order) - ); + .createQuery( + criteria.where( + builder.and( + builder. + equal(from.get("parentCategory"), + folder), + builder.like(builder.lower(from.get( + "name")), + filterTerm) + ) + ) + .orderBy(order) + ); if (firstResult >= 0) { query.setFirstResult(firstResult); @@ -582,35 +594,35 @@ public class AssetFolderBrowserController { LOGGER.debug("The database contains {} assets.", entityManager.createQuery(criteria.select(fromAsset) - .where( - builder.and( - builder.equal(join.get("category"), - folder), - builder.equal(join.get("type"), - CmsConstants.CATEGORIZATION_TYPE_FOLDER), - builder.like(builder.lower( - fromAsset.get( - "displayName")), - filterTerm) - ))).getResultList().size()); + .where( + builder.and( + builder.equal(join.get("category"), + folder), + builder.equal(join.get("type"), + CmsConstants.CATEGORIZATION_TYPE_FOLDER), + builder.like(builder.lower( + fromAsset.get( + "displayName")), + filterTerm) + ))).getResultList().size()); final TypedQuery query = entityManager - .createQuery( - criteria.select(fromAsset) - .where( - builder.and( - builder.equal(join.get( - "category"), folder), - builder.equal(join.get("type"), - CmsConstants.CATEGORIZATION_TYPE_FOLDER), - builder.like(builder.lower( - fromAsset.get( - "displayName")), - filterTerm) - ) - ) - .orderBy(order) - ); + .createQuery( + criteria.select(fromAsset) + .where( + builder.and( + builder.equal(join.get( + "category"), folder), + builder.equal(join.get("type"), + CmsConstants.CATEGORIZATION_TYPE_FOLDER), + builder.like(builder.lower( + fromAsset.get( + "displayName")), + filterTerm) + ) + ) + .orderBy(order) + ); if (firstResult >= 0) { query.setFirstResult(firstResult); diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetFolderBrowserTableModel.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetFolderBrowserTableModel.java index cf416e1dc..56b7a2d6a 100644 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetFolderBrowserTableModel.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetFolderBrowserTableModel.java @@ -35,9 +35,10 @@ class AssetFolderBrowserTableModel implements TableModel { protected static final int COL_NAME = 0; protected static final int COL_TITLE = 1; protected static final int COL_TYPE = 2; - protected static final int COL_CREATION_DATE = 3; - protected static final int COL_LAST_MODIFIED = 4; - protected static final int COL_DELETEABLE = 5; + protected static final int COL_THUMBNAIL = 3; + protected static final int COL_CREATION_DATE = 4; + protected static final int COL_LAST_MODIFIED = 5; + protected static final int COL_DELETEABLE = 6; private final Iterator iterator; private AssetFolderBrowserTableRow currentRow; @@ -79,6 +80,8 @@ class AssetFolderBrowserTableModel implements TableModel { } else { return new GlobalizedMessage(typeLabelKey, typeLabelBundle); } + case COL_THUMBNAIL: + return currentRow.getThumbnailUrl(); case COL_CREATION_DATE: return currentRow.getCreated(); case COL_LAST_MODIFIED: diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetFolderBrowserTableRow.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetFolderBrowserTableRow.java index 5e3cefaf1..045a35093 100644 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetFolderBrowserTableRow.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetFolderBrowserTableRow.java @@ -30,6 +30,7 @@ class AssetFolderBrowserTableRow { private String objectUuid; private String name; private String title; + private String thumbnailUrl; private String typeLabelBundle; private String typeLabelKey; private Date created; @@ -68,6 +69,14 @@ class AssetFolderBrowserTableRow { public void setTitle(final String title) { this.title = title; } + + public String getThumbnailUrl() { + return thumbnailUrl; + } + + public void setThumbnailUrl(final String thumbnailUrl) { + this.thumbnailUrl = thumbnailUrl; + } public String getTypeLabelBundle() { return typeLabelBundle; diff --git a/ccm-cms/src/main/java/org/librecms/contentsection/rs/Images.java b/ccm-cms/src/main/java/org/librecms/contentsection/rs/Images.java index 83ac205b5..8a8ee55ee 100644 --- a/ccm-cms/src/main/java/org/librecms/contentsection/rs/Images.java +++ b/ccm-cms/src/main/java/org/librecms/contentsection/rs/Images.java @@ -62,6 +62,76 @@ public class Images { @Inject private AssetRepository assetRepo; + @GET + @Path("/uuid-{uuid}") + public Response getImageByUuid( + @PathParam("content-section") + final String sectionName, + @PathParam("uuid") + final String uuid, + @QueryParam("width") + @DefaultValue("-1") + final String widthParam, + @QueryParam("height") + @DefaultValue("-1") + final String heightParam) { + + final Optional asset = assetRepo + .findByUuidAndType(uuid, Image.class); + + if (asset.isPresent()) { + if (asset.get() instanceof Image) { + return loadImage((Image) asset.get(), widthParam, heightParam); + } else { + return Response + .status(Response.Status.NOT_FOUND) + .entity(String + .format("The asset with the requested UUID \"%s\" " + + "is not an image.", + uuid)) + .build(); + } + } else { + return Response + .status(Response.Status.NOT_FOUND) + .entity(String + .format("The requested image \"%s\" does not exist.", + uuid)) + .build(); + } + } + + @GET + @Path("/uuid-{uuid}/properties") + public Response getImagePropertiesByUuid( + @PathParam("content-section") final String sectionName, + @PathParam("uuid") final String uuid) { + + final Optional asset = assetRepo.findByUuidAndType(uuid, + Image.class); + + if (asset.isPresent()) { + if (asset.get() instanceof Image) { + return readImageProperties((Image) asset.get()); + } else { + return Response + .status(Response.Status.NOT_FOUND) + .entity(String + .format("The asset with the requested UUID \"%s\" " + + "is not an image.", + uuid)) + .build(); + } + } else { + return Response + .status(Response.Status.NOT_FOUND) + .entity(String + .format("The requested image \"%s\" does not exist.", + uuid)) + .build(); + } + } + /** * Return the image requested by the provided content section and path. * @@ -119,80 +189,7 @@ public class Images { if (asset.isPresent()) { if (asset.get() instanceof Image) { - final Image image = (Image) asset.get(); - final byte[] data = image.getData(); - final String mimeType = image.getMimeType().toString(); - - final InputStream inputStream = new ByteArrayInputStream(data); - final BufferedImage bufferedImage; - final String imageFormat; - try { - final ImageInputStream imageInputStream = ImageIO - .createImageInputStream(inputStream); - final Iterator readers = ImageIO - .getImageReaders(imageInputStream); - final ImageReader imageReader; - if (readers.hasNext()) { - imageReader = readers.next(); - } else { - LOGGER.error("No image reader for image {} (UUID: {}) " - + "available.", - image.getDisplayName(), - image.getUuid()); - return Response.serverError().build(); - } - imageReader.setInput(imageInputStream); - bufferedImage = imageReader.read(0); - imageFormat = imageReader.getFormatName(); - } catch (IOException ex) { - LOGGER.error("Failed to load image {} (UUID: {}).", - image.getDisplayName(), - image.getUuid()); - LOGGER.error(ex); - return Response.serverError().build(); - } - - // Yes, this is correct. The parameters provided in the URL - // are expected to be integers. The private scaleImage method - // works with floats to be accurate (divisions are performed - // with the values for width and height) - final int width = parseScaleParameter(widthParam, "width"); - final int height = parseScaleParameter(heightParam, "height"); - final java.awt.Image scaledImage = scaleImage(bufferedImage, - width, - height); - - final ByteArrayOutputStream outputStream - = new ByteArrayOutputStream(); - final BufferedImage bufferedScaledImage = new BufferedImage( - scaledImage.getWidth(null), - scaledImage.getHeight(null), - bufferedImage.getType()); - bufferedScaledImage - .getGraphics() - .drawImage(scaledImage, 0, 0, null); - try { - ImageIO - .write(bufferedScaledImage, imageFormat, outputStream); - } catch (IOException ex) { - LOGGER.error("Failed to render scaled variant of image {} " - + "(UUID: {}).", - image.getDisplayName(), - image.getUuid()); - LOGGER.error(ex); - return Response.serverError().build(); - } - -// return Response - // .ok(String.format( - // "Requested image \"%s\" in content section \"%s\"", - // path, - // section.get().getLabel()), - // "text/plain") - // .build(); - return Response - .ok(outputStream.toByteArray(), mimeType) - .build(); + return loadImage((Image) asset.get(), widthParam, heightParam); } else { return Response .status(Response.Status.NOT_FOUND) @@ -210,16 +207,6 @@ public class Images { path)) .build(); } - -// final Response.ResponseBuilder builder = Response -// .ok(String.format( -// "Requested image \"%s\" from folder \"%s\" in content section \"%s\"", -// imageName, -// folderPath, -// section.get().getLabel()), -// "text/plain"); -// -// return builder.build(); } /** @@ -253,39 +240,7 @@ public class Images { if (asset.isPresent()) { if (asset.get() instanceof Image) { - final Image image = (Image) asset.get(); - final byte[] data = image.getData(); - final String mimeType = image.getMimeType().toString(); - - final InputStream inputStream = new ByteArrayInputStream(data); - final BufferedImage bufferedImage; - try { - bufferedImage = ImageIO.read(inputStream); - } catch (IOException ex) { - LOGGER.error("Failed to load image {} (UUID: {}).", - image.getDisplayName(), - image.getUuid()); - LOGGER.error(ex); - return Response.serverError().build(); - } - - final String imageProperties = String - .format("{%n" - + " \"name\": \"%s\",%n" - + " \"filename\": \"%s\",%n" - + " \"mimetype\": \"%s\",%n" - + " \"width\": %d,%n" - + " \"height\": %d%n" - + "}", - image.getDisplayName(), - image.getFileName(), - mimeType, - bufferedImage.getWidth(), - bufferedImage.getHeight()); - - return Response - .ok(imageProperties, "application/json") - .build(); + return readImageProperties((Image) asset.get()); } else { return Response .status(Response.Status.NOT_FOUND) @@ -305,6 +260,134 @@ public class Images { } } + /** + * Helper method for loading the image from the {@link Image} asset entity. + * + * This method also does the scaling of the image. + * + * @param image The image asset containing the image. + * @param widthParam The value of the width parameter. + * @param heightParam The value of the height parameter. + * + * @return The {@link Response} for sending the (scaled) image to the + * requesting user agent. + */ + private Response loadImage(final Image image, + final String widthParam, + final String heightParam) { + + final byte[] data = image.getData(); + final String mimeType = image.getMimeType().toString(); + + final InputStream inputStream = new ByteArrayInputStream(data); + final BufferedImage bufferedImage; + final String imageFormat; + try { + final ImageInputStream imageInputStream = ImageIO + .createImageInputStream(inputStream); + final Iterator readers = ImageIO + .getImageReaders(imageInputStream); + final ImageReader imageReader; + if (readers.hasNext()) { + imageReader = readers.next(); + } else { + LOGGER.error("No image reader for image {} (UUID: {}) " + + "available.", + image.getDisplayName(), + image.getUuid()); + return Response.serverError().build(); + } + imageReader.setInput(imageInputStream); + bufferedImage = imageReader.read(0); + imageFormat = imageReader.getFormatName(); + } catch (IOException ex) { + LOGGER.error("Failed to load image {} (UUID: {}).", + image.getDisplayName(), + image.getUuid()); + LOGGER.error(ex); + return Response.serverError().build(); + } + + // Yes, this is correct. The parameters provided in the URL + // are expected to be integers. The private scaleImage method + // works with floats to be accurate (divisions are performed + // with the values for width and height) + final int width = parseScaleParameter(widthParam, "width"); + final int height = parseScaleParameter(heightParam, "height"); + final java.awt.Image scaledImage = scaleImage(bufferedImage, + width, + height); + + final ByteArrayOutputStream outputStream + = new ByteArrayOutputStream(); + final BufferedImage bufferedScaledImage = new BufferedImage( + scaledImage.getWidth(null), + scaledImage.getHeight(null), + bufferedImage.getType()); + bufferedScaledImage + .getGraphics() + .drawImage(scaledImage, 0, 0, null); + try { + ImageIO + .write(bufferedScaledImage, imageFormat, outputStream); + } catch (IOException ex) { + LOGGER.error("Failed to render scaled variant of image {} " + + "(UUID: {}).", + image.getDisplayName(), + image.getUuid()); + LOGGER.error(ex); + return Response.serverError().build(); + } + + return Response + .ok(outputStream.toByteArray(), mimeType) + .build(); + } + + /** + * Helper method for reading the image properties and converting them into + * an JSON response. + * + * @param image The image which properties are read. + * + * @return A {@link Response} with the image properties as JSON. + */ + private Response readImageProperties(final Image image) { + + final byte[] data = image.getData(); + final String mimeType = image.getMimeType().toString(); + + final InputStream inputStream = new ByteArrayInputStream(data); + final BufferedImage bufferedImage; + try { + bufferedImage = ImageIO.read(inputStream); + } catch (IOException ex) { + LOGGER.error("Failed to load image {} (UUID: {}).", + image.getDisplayName(), + image.getUuid()); + LOGGER.error(ex); + return Response.serverError().build(); + } + + final String imageProperties = String + .format("{%n" + + " \"name\": \"%s\",%n" + + " \"filename\": \"%s\",%n" + + " \"mimetype\": \"%s\",%n" + + " \"width\": %d,%n" + + " \"height\": %d%n" + + "}", + image.getDisplayName(), + image.getFileName(), + mimeType, + bufferedImage.getWidth(), + bufferedImage.getHeight()); + + return Response + .ok(imageProperties, "application/json") + .build(); + } + /** * Helper method for parsing the parameters for scaling an image into * integers. diff --git a/ccm-cms/src/main/resources/org/librecms/CmsResources.properties b/ccm-cms/src/main/resources/org/librecms/CmsResources.properties index 61dd5bd32..9a4b26dff 100644 --- a/ccm-cms/src/main/resources/org/librecms/CmsResources.properties +++ b/ccm-cms/src/main/resources/org/librecms/CmsResources.properties @@ -386,3 +386,4 @@ related_info_step_description=Add related information cms.ui.authoring.file_upload.auto_detect=(Auto-Detect) cms.ui.upload_new_content=Upload new content cms.ui.asset.name=Name +cms.ui.asset.thumbnail=Preview diff --git a/ccm-cms/src/main/resources/org/librecms/CmsResources_de.properties b/ccm-cms/src/main/resources/org/librecms/CmsResources_de.properties index cf9025d60..3efb7d039 100644 --- a/ccm-cms/src/main/resources/org/librecms/CmsResources_de.properties +++ b/ccm-cms/src/main/resources/org/librecms/CmsResources_de.properties @@ -383,3 +383,4 @@ related_info_step_description=Weiterf\u00fchrende Informationen hinzuf\u00fcgen cms.ui.authoring.file_upload.auto_detect=(Automatisch erkennen) cms.ui.upload_new_content=Neuen Inhalt hochladen cms.ui.asset.name=Name +cms.ui.asset.thumbnail=Vorschau diff --git a/ccm-cms/src/main/resources/org/librecms/CmsResources_fr.properties b/ccm-cms/src/main/resources/org/librecms/CmsResources_fr.properties index 6a8a620f3..38ab5b61d 100644 --- a/ccm-cms/src/main/resources/org/librecms/CmsResources_fr.properties +++ b/ccm-cms/src/main/resources/org/librecms/CmsResources_fr.properties @@ -342,3 +342,4 @@ related_info_step_description=Add related information cms.ui.authoring.file_upload.auto_detect=(Auto-Detect) cms.ui.upload_new_content=Upload new content cms.ui.asset.name=Name +cms.ui.asset.thumbnail=Preview diff --git a/ccm-core/src/main/java/com/arsdigita/dispatcher/DispatcherHelper.java b/ccm-core/src/main/java/com/arsdigita/dispatcher/DispatcherHelper.java index 4347f86f4..327b47d90 100644 --- a/ccm-core/src/main/java/com/arsdigita/dispatcher/DispatcherHelper.java +++ b/ccm-core/src/main/java/com/arsdigita/dispatcher/DispatcherHelper.java @@ -52,9 +52,12 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.jsp.PageContext; import org.apache.logging.log4j.Logger; +import org.apache.shiro.web.servlet.ShiroHttpServletRequest; import java.net.URLEncoder; +import javax.servlet.ServletRequestWrapper; + /** * Class static helper methods for request dispatching. Contains various * generally useful procedural abstractions. @@ -70,7 +73,8 @@ public final class DispatcherHelper implements DispatcherConstants { * set com.arsdigita.dispatcher.DispatcherHelper=DEBUG by uncommenting or * adding the line. */ - private static final Logger LOGGER = LogManager.getLogger(DispatcherHelper.class); + private static final Logger LOGGER = LogManager.getLogger( + DispatcherHelper.class); private static String s_webappCtx; private static String s_staticURL; private static boolean s_cachingActive; @@ -177,7 +181,14 @@ public final class DispatcherHelper implements DispatcherConstants { } public static String getDispatcherPrefix(HttpServletRequest req) { - return (String) req.getAttribute(DISPATCHER_PREFIX_ATTR); + final HttpServletRequest request; + if (req instanceof ShiroHttpServletRequest) { + request = (HttpServletRequest) ((ServletRequestWrapper) req) + .getRequest(); + } else { + request = req; + } + return (String) request.getAttribute(DISPATCHER_PREFIX_ATTR); } public static void setDispatcherPrefix(HttpServletRequest req, @@ -541,10 +552,10 @@ public final class DispatcherHelper implements DispatcherConstants { if (previous instanceof MultipartHttpServletRequest) { LOGGER.debug("Build new multipart request from previous " - + previous + " and current " + orig); + + previous + " and current " + orig); MultipartHttpServletRequest previousmp - = (MultipartHttpServletRequest) previous; + = (MultipartHttpServletRequest) previous; sreq = new MultipartHttpServletRequest(previousmp, orig); @@ -567,7 +578,7 @@ public final class DispatcherHelper implements DispatcherConstants { } } else { LOGGER.debug("The request is not multipart; proceeding " - + "without wrapping the request"); + + "without wrapping the request"); } return sreq; } @@ -681,14 +692,14 @@ public final class DispatcherHelper implements DispatcherConstants { destination = URL.there(req, url.substring(0, sep), params); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Setting destination with map to " - + destination); + + destination); } } throw new RedirectSignal(destination, true); } else { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Redirecting to URL without using URL.there. " - + "URL is " + url); + + "URL is " + url); } throw new RedirectSignal(url, true); } @@ -875,7 +886,7 @@ public final class DispatcherHelper implements DispatcherConstants { LOGGER.warn( "webappContext changed. Expected='" + s_webappCtx + "' found='" + webappCtx - + "'.\nPerhaps the enterprise.init " + + "'.\nPerhaps the enterprise.init " + "com.arsdigita.dispatcher.Initializer webappContext " + "parameter is wrong."); // Save the webappCtx from the request for future use. @@ -1193,7 +1204,7 @@ public final class DispatcherHelper implements DispatcherConstants { // Set the preferedLocale to the default locale (first entry in the // config parameter list) Locale preferedLocale - = new Locale(kernelConfig.getDefaultLanguage(), "", ""); + = new Locale(kernelConfig.getDefaultLanguage(), "", ""); // The ACCEPTED_LANGUAGES from the client Enumeration locales = null; diff --git a/ccm-core/src/main/java/com/arsdigita/web/URL.java b/ccm-core/src/main/java/com/arsdigita/web/URL.java index 1d93e2252..54796fcc9 100644 --- a/ccm-core/src/main/java/com/arsdigita/web/URL.java +++ b/ccm-core/src/main/java/com/arsdigita/web/URL.java @@ -706,7 +706,7 @@ public class URL { @SuppressWarnings("unchecked") final Bean bean = (Bean) iterator - .next(); + .next(); final CreationalContext ctx = beanManager .createCreationalContext(bean); confManager = (ConfigurationManager) beanManager.getReference(