Java tutorial
/* * Weblounge: Web Content Management System * Copyright (c) 2003 - 2011 The Weblounge Team * http://entwinemedia.com/weblounge * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package ch.entwine.weblounge.test.harness.content; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import ch.entwine.weblounge.common.content.image.ImageStyle; import ch.entwine.weblounge.common.impl.content.image.ImageStyleImpl; import ch.entwine.weblounge.common.impl.content.image.ImageStyleUtils; import ch.entwine.weblounge.common.impl.testing.IntegrationTestBase; import ch.entwine.weblounge.common.impl.util.TestUtils; import ch.entwine.weblounge.common.site.ImageScalingMode; import ch.entwine.weblounge.common.url.UrlUtils; import ch.entwine.weblounge.test.util.TestSiteUtils; import com.sun.media.jai.codec.FileCacheSeekableStream; import com.sun.media.jai.codec.MemoryCacheSeekableStream; import com.sun.media.jai.codec.SeekableStream; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import org.apache.http.Header; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.impl.client.DefaultHttpClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Locale; import javax.media.jai.JAI; import javax.media.jai.RenderedOp; import javax.servlet.http.HttpServletResponse; /** * Integration test for image serving capabilities. */ public class ImagesTest extends IntegrationTestBase { /** The logger */ private static final Logger logger = LoggerFactory.getLogger(ImagesTest.class); /** The scaling modes to test */ private static final List<ImageStyle> styles = new ArrayList<ImageStyle>(); /** The original image's width */ private static final int originalWidth = 1000; /** The original image's height */ private static final int originalHeight = 666; /** File size of the English version */ private static final long sizeEnglish = 73642L; /** Path to the image resource */ private static final String imagePath = "/test/image"; /** Mime type of the English version */ private static final String mimetypeEnglish = "image/jpeg; charset=utf-8"; /** File name of the English version */ private static final String filenameEnglish = "porsche.jpg"; /** File size of the German version */ private static final long sizeGerman = 88723L; /** Mime type of the German version */ private static final String mimetypeGerman = "image/jpeg; charset=utf-8"; /** File name of the German version */ private static final String filenameGerman = "porsche.jpg"; /** The style's width */ private static final int BOX_WIDTH = 250; /** The style's height */ private static final int BOX_HEIGHT = 250; /** Image resource identifier */ private static final String imageId = "5bc19990-8f99-4873-a813-71b6dfac22ad"; /** Modification date parser */ private static final SimpleDateFormat lastModifiedDateFormat = new SimpleDateFormat( "EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); static { styles.add(new ImageStyleImpl("box", BOX_WIDTH, BOX_HEIGHT, ImageScalingMode.Box, false, false)); styles.add(new ImageStyleImpl("cover", BOX_WIDTH, BOX_HEIGHT, ImageScalingMode.Cover, false, false)); styles.add(new ImageStyleImpl("fill", BOX_WIDTH, BOX_HEIGHT, ImageScalingMode.Fill, false, false)); styles.add(new ImageStyleImpl("width", BOX_WIDTH, -1, ImageScalingMode.Width, false, false)); styles.add(new ImageStyleImpl("height", -1, BOX_HEIGHT, ImageScalingMode.Height, false, false)); styles.add(new ImageStyleImpl("none", -1, -1, ImageScalingMode.None, false, false)); } /** * Creates a new instance of the images test. */ public ImagesTest() { super("Images Test", WEBLOUNGE_CONTENT_TEST_GROUP); } /** * {@inheritDoc} * * @see ch.entwine.weblounge.testing.kernel.IntegrationTest#execute(java.lang.String) */ @Override public void execute(String serverUrl) throws Exception { logger.info("Preparing test of images endpoint"); String requestUrl = serverUrl; testGetOriginalImage(requestUrl); testGetOriginalImageById(requestUrl); testGetOriginalImageByIdAndName(requestUrl); testGetOriginalImageByPathLanguage(requestUrl); testGetOriginalImageByHeaderLanguage(requestUrl); testGetStyledImageById(requestUrl); testGetStyledImageByPathLanguage(requestUrl); testGetStyledImageByHeaderLanguage(requestUrl); } /** * Tests the whether the original image is returned. * * @param serverUrl * the base url * @throws Exception * if an exception occurs */ private void testGetOriginalImage(String serverUrl) throws Exception { logger.info(""); logger.info("Testing original, (header-based) localized image by path"); logger.info(""); String url = UrlUtils.concat(serverUrl, imagePath); HttpGet request = new HttpGet(url); request.setHeader("Accept-Language", "de"); testGermanOriginal(request); } /** * Tests for the special <code>/weblounge-images</code> uri prefix that is * provided by the file request handler. * * @param serverUrl * the base url * @throws Exception * if an exception occurs */ private void testGetOriginalImageById(String serverUrl) throws Exception { logger.info(""); logger.info("Testing original, (header-based) localized image by id"); logger.info(""); String url = UrlUtils.concat(serverUrl, "weblounge-images", imageId); HttpGet request = new HttpGet(url); request.setHeader("Accept-Language", "de"); testGermanOriginal(request); } /** * Tests for the special <code>/files</code> uri prefix that is provided by * the file request handler. The handler should be able to respond to these * requests: * <ul> * <li>/files/<id></li> * <li>/files/<id>/</li> * <li>/files/<id>/<filename></li> * </ul> * * @param serverUrl * the base url * @throws Exception * if an exception occurs */ private void testGetOriginalImageByIdAndName(String serverUrl) throws Exception { logger.info(""); logger.info("Testing original, (header-based) localized image by id and name"); logger.info(""); String url = UrlUtils.concat(serverUrl, "weblounge-images", imageId, filenameGerman); HttpGet request = new HttpGet(url); request.setHeader("Accept-Language", "de"); testGermanOriginal(request); } /** * Tests the <code>/{id}/{language}/styles/original</code> method of the * endpoint. * * @param serverUrl * the base url * @throws Exception * if an exception occurs */ private void testGetOriginalImageByPathLanguage(String serverUrl) throws Exception { logger.info(""); logger.info("Testing original, (path-based) localized image by path"); logger.info(""); // English String englishUrl = UrlUtils.concat(serverUrl, imagePath, "en"); HttpGet request = new HttpGet(englishUrl); testEnglishOriginal(request); // German String germanUrl = UrlUtils.concat(serverUrl, imagePath, "de"); request = new HttpGet(germanUrl); testGermanOriginal(request); } /** * Tests requests that send the required language as part of the * <code>Accept-Language</code> header. * * @param serverUrl * the base url * @throws Exception * if an exception occurs */ private void testGetOriginalImageByHeaderLanguage(String serverUrl) throws Exception { logger.info(""); logger.info("Testing original, (header-based) localized images"); logger.info(""); // English String url = UrlUtils.concat(serverUrl, imagePath); HttpGet request = new HttpGet(url); request.setHeader("Accept-Language", "en"); testEnglishOriginal(request); // German request = new HttpGet(url); request.setHeader("Accept-Language", "de"); testGermanOriginal(request); } /** * Tests for the special <code>/weblounge-images</code> uri prefix that is * provided by the file request handler. * * @param serverUrl * the base url * @throws Exception * if an exception occurs */ private void testGetStyledImageById(String serverUrl) throws Exception { logger.info(""); logger.info("Testing styled, (header-based) localized images by id"); logger.info(""); List<String> eTags = new ArrayList<String>(); HttpGet request = null; for (ImageStyle style : styles) { String url = UrlUtils.concat(serverUrl, "weblounge-images", imageId); // English request = new HttpGet(url + "?style=" + style.getIdentifier()); request.setHeader("Accept-Language", "en"); testEnglishScaled(request, style, eTags); // German request = new HttpGet(url + "?style=" + style.getIdentifier()); request.setHeader("Accept-Language", "de"); testGermanScaled(request, style, eTags); } } /** * Tests the <code>/{id}/{language}/styles/{style}</code> method of the * endpoint. * * @param serverUrl * the base url * @throws Exception * if an exception occurs */ private void testGetStyledImageByPathLanguage(String serverUrl) throws Exception { logger.info(""); logger.info("Testing styled, (path-based) localized images by path"); logger.info(""); List<String> eTags = new ArrayList<String>(); for (ImageStyle style : styles) { // English String englishUrl = UrlUtils.concat(serverUrl, imagePath, "en"); HttpGet request = new HttpGet(englishUrl + "?style=" + style.getIdentifier()); testEnglishScaled(request, style, eTags); // German String germanUrl = UrlUtils.concat(serverUrl, imagePath, "de"); request = new HttpGet(germanUrl + "?style=" + style.getIdentifier()); request.getParams().setParameter("style", style.getIdentifier()); testGermanScaled(request, style, eTags); } } /** * Tests the <code>/{id}/styles/{style}</code> method of the endpoint. * * @param serverUrl * the base url * @throws Exception * if an exception occurs */ private void testGetStyledImageByHeaderLanguage(String serverUrl) throws Exception { logger.info(""); logger.info("Testing styled, (header-based) localized images by path"); logger.info(""); List<String> eTags = new ArrayList<String>(); HttpGet request = null; for (ImageStyle style : styles) { String url = UrlUtils.concat(serverUrl, imagePath); // English request = new HttpGet(url + "?style=" + style.getIdentifier()); request.setHeader("Accept-Language", "en"); testEnglishScaled(request, style, eTags); // German request = new HttpGet(url + "?style=" + style.getIdentifier()); request.setHeader("Accept-Language", "de"); testGermanScaled(request, style, eTags); } } /** * Tests for the correctness of the English original image response. * * @param response * the http response */ private void testEnglishOriginal(HttpUriRequest request) throws Exception { logger.info("Requesting original English image at {}", request.getURI()); HttpClient httpClient = new DefaultHttpClient(); String eTagValue = null; Date modificationDate = null; try { HttpResponse response = TestUtils.request(httpClient, request, null); assertEquals(HttpServletResponse.SC_OK, response.getStatusLine().getStatusCode()); assertTrue("No content received", response.getEntity().getContentLength() > 0); // Test general headers assertEquals(1, response.getHeaders("Content-Type").length); assertEquals(mimetypeEnglish, response.getHeaders("Content-Type")[0].getValue()); assertEquals(sizeEnglish, response.getEntity().getContentLength()); assertEquals(1, response.getHeaders("Content-Disposition").length); // Test filename assertEquals("inline; filename=" + filenameEnglish, response.getHeaders("Content-Disposition")[0].getValue()); // Test ETag header Header eTagHeader = response.getFirstHeader("ETag"); assertNotNull(eTagHeader); assertNotNull(eTagHeader.getValue()); eTagValue = eTagHeader.getValue(); // Test Last-Modified header Header modifiedHeader = response.getFirstHeader("Last-Modified"); assertNotNull(modifiedHeader); modificationDate = lastModifiedDateFormat.parse(modifiedHeader.getValue()); // Consume the content response.getEntity().consumeContent(); } finally { httpClient.getConnectionManager().shutdown(); } TestSiteUtils.testETagHeader(request, eTagValue, logger, null); TestSiteUtils.testModifiedHeader(request, modificationDate, logger, null); } /** * Tests for the correctness of the German original image response. * * @param response * the http response */ private void testGermanOriginal(HttpUriRequest request) throws Exception { HttpClient httpClient = new DefaultHttpClient(); String eTagValue = null; Date modificationDate = null; try { logger.info("Requesting original German image at {}", request.getURI()); HttpResponse response = TestUtils.request(httpClient, request, null); assertEquals(HttpServletResponse.SC_OK, response.getStatusLine().getStatusCode()); assertTrue("No content received", response.getEntity().getContentLength() > 0); // Test general headers assertEquals(1, response.getHeaders("Content-Type").length); assertEquals(mimetypeGerman, response.getHeaders("Content-Type")[0].getValue()); assertEquals(sizeGerman, response.getEntity().getContentLength()); assertEquals(1, response.getHeaders("Content-Disposition").length); // Test filename assertEquals("inline; filename=" + filenameGerman, response.getHeaders("Content-Disposition")[0].getValue()); // Test ETag header Header eTagHeader = response.getFirstHeader("ETag"); assertNotNull(eTagHeader); assertNotNull(eTagHeader.getValue()); eTagValue = eTagHeader.getValue(); // Test Last-Modified header Header modifiedHeader = response.getFirstHeader("Last-Modified"); assertNotNull(modifiedHeader); modificationDate = lastModifiedDateFormat.parse(modifiedHeader.getValue()); // Consume the content response.getEntity().consumeContent(); } finally { httpClient.getConnectionManager().shutdown(); } TestSiteUtils.testETagHeader(request, eTagValue, logger, null); TestSiteUtils.testModifiedHeader(request, modificationDate, logger, null); } /** * Tests for the correctness of the English scaled image response. * * @param response * the http response * @param style * the image style */ @SuppressWarnings("cast") private void testEnglishScaled(HttpUriRequest request, ImageStyle style, List<String> eTags) throws Exception { HttpClient httpClient = new DefaultHttpClient(); String eTagValue = null; Date modificationDate = null; try { logger.info("Requesting scaled English image '{}' at {}", style.getIdentifier(), request.getURI()); HttpResponse response = TestUtils.request(httpClient, request, null); assertEquals(HttpServletResponse.SC_OK, response.getStatusLine().getStatusCode()); assertTrue("Response did not contain any content", response.getEntity().getContentLength() > 0); // Test general headers assertEquals(1, response.getHeaders("Content-Type").length); assertEquals(mimetypeEnglish, response.getHeaders("Content-Type")[0].getValue()); assertEquals(1, response.getHeaders("Content-Disposition").length); SeekableStream seekableInputStream = null; StringBuilder fileName = new StringBuilder(FilenameUtils.getBaseName(filenameEnglish)); try { // Test file size if (!ImageScalingMode.None.equals(style.getScalingMode())) { float scale = ImageStyleUtils.getScale(originalWidth, originalHeight, style); int scaledWidth = (int) Math.round(originalWidth * scale) - (int) ImageStyleUtils .getCropX(Math.round(originalWidth * scale), Math.round(originalHeight * scale), style); int scaledHeight = (int) Math.round(originalHeight * scale) - (int) ImageStyleUtils .getCropY(Math.round(originalWidth * scale), Math.round(originalHeight * scale), style); // Load the image from the given input stream seekableInputStream = new MemoryCacheSeekableStream(response.getEntity().getContent()); RenderedOp image = JAI.create("stream", seekableInputStream); if (image == null) throw new IOException("Error reading image from input stream"); // Get the actual image size int imageWidth = image.getWidth(); int imageHeight = image.getHeight(); assertEquals(scaledHeight, imageHeight, 1); assertEquals(scaledWidth, imageWidth, 1); } fileName.append("-").append(style.getIdentifier()); } finally { IOUtils.closeQuietly(seekableInputStream); } // Test filename fileName.append(".").append(FilenameUtils.getExtension(filenameEnglish)); String contentDisposition = response.getHeaders("Content-Disposition")[0].getValue(); assertTrue(contentDisposition.startsWith("inline; filename=" + fileName.toString())); // Test ETag header Header eTagHeader = response.getFirstHeader("ETag"); assertNotNull(eTagHeader); assertNotNull(eTagHeader.getValue()); eTagValue = eTagHeader.getValue(); // Make sure ETags are created in a proper way (no duplicates) assertFalse("Duplicate ETag returned", eTags.contains(eTagValue)); if (!"none".equals(style.getIdentifier())) { eTags.add(eTagValue); } // Test Last-Modified header Header modifiedHeader = response.getFirstHeader("Last-Modified"); assertNotNull(modifiedHeader); modificationDate = lastModifiedDateFormat.parse(modifiedHeader.getValue()); } finally { eTags.clear(); httpClient.getConnectionManager().shutdown(); } TestSiteUtils.testETagHeader(request, eTagValue, logger, null); TestSiteUtils.testModifiedHeader(request, modificationDate, logger, null); } /** * Tests for the correctness of the German scaled image response. * * @param response * the http response * @param style * the image style */ @SuppressWarnings("cast") private void testGermanScaled(HttpUriRequest request, ImageStyle style, List<String> eTags) throws Exception { HttpClient httpClient = new DefaultHttpClient(); String eTagValue = null; Date modificationDate = null; try { logger.info("Requesting scaled German image '{}' at {}", style.getIdentifier(), request.getURI()); HttpResponse response = TestUtils.request(httpClient, request, null); assertEquals(HttpServletResponse.SC_OK, response.getStatusLine().getStatusCode()); assertTrue("Response did not contain any content", response.getEntity().getContentLength() > 0); // Test general headers assertEquals(1, response.getHeaders("Content-Type").length); assertEquals(mimetypeGerman, response.getHeaders("Content-Type")[0].getValue()); assertEquals(1, response.getHeaders("Content-Disposition").length); SeekableStream seekableInputStream = null; StringBuilder fileName = new StringBuilder(FilenameUtils.getBaseName(filenameGerman)); try { // Test file size if (!ImageScalingMode.None.equals(style.getScalingMode())) { float scale = ImageStyleUtils.getScale(originalWidth, originalHeight, style); int scaledWidth = (int) Math.round(originalWidth * scale) - (int) ImageStyleUtils .getCropX(Math.round(originalWidth * scale), Math.round(originalHeight * scale), style); int scaledHeight = (int) Math.round(originalHeight * scale) - (int) ImageStyleUtils .getCropY(Math.round(originalWidth * scale), Math.round(originalHeight * scale), style); // Load the image from the given input stream seekableInputStream = new FileCacheSeekableStream(response.getEntity().getContent()); RenderedOp image = JAI.create("stream", seekableInputStream); if (image == null) throw new IOException("Error reading image from input stream"); // Get the original image size int imageWidth = image.getWidth(); int imageHeight = image.getHeight(); assertEquals(scaledHeight, imageHeight, 1); assertEquals(scaledWidth, imageWidth, 1); } fileName.append("-").append(style.getIdentifier()); } finally { IOUtils.closeQuietly(seekableInputStream); } // Test filename fileName.append(".").append(FilenameUtils.getExtension(filenameGerman)); String contentDisposition = response.getHeaders("Content-Disposition")[0].getValue(); assertTrue(contentDisposition.startsWith("inline; filename=" + fileName.toString())); // Test ETag header Header eTagHeader = response.getFirstHeader("ETag"); assertNotNull(eTagHeader); assertNotNull(eTagHeader.getValue()); eTagValue = eTagHeader.getValue(); // Make sure ETags are created in a proper way (no duplicates) assertFalse("Duplicate ETag returned", eTags.contains(eTagValue)); if (!"none".equals(style.getIdentifier())) { eTags.add(eTagValue); } // Test Last-Modified header Header modifiedHeader = response.getFirstHeader("Last-Modified"); assertNotNull(modifiedHeader); modificationDate = lastModifiedDateFormat.parse(modifiedHeader.getValue()); } finally { eTags.clear(); httpClient.getConnectionManager().shutdown(); } TestSiteUtils.testETagHeader(request, eTagValue, logger, null); TestSiteUtils.testModifiedHeader(request, modificationDate, logger, null); } }