/* * Copyright (C) 2005-2007 Alfresco Software Limited. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU 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 General Public License for more details. * You should have received a copy of the GNU 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. * As a special exception to the terms and conditions of version 2.0 of * the GPL, you may redistribute this Program in connection with Free/Libre * and Open Source Software ("FLOSS") applications as described in Alfresco's * FLOSS exception. You should have recieved a copy of the text describing * the FLOSS exception, and it is also available here: * http://www.alfresco.com/legal/licensing" */ package org.alfresco.repo.content; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; import net.sf.ehcache.Cache; import net.sf.ehcache.CacheManager; import org.alfresco.repo.cache.EhCacheAdapter; import org.alfresco.repo.content.filestore.FileContentStore; import org.alfresco.service.cmr.repository.ContentIOException; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.util.TempFileProvider; /** * Ensures that the routing of URLs based on context is working. A combination * of fully featured and incompletely featured stores is used to ensure that * all routing scenarios are handled. * * @see AbstractRoutingContentStore * @since 2.1 * * @author Derek Hulley */ public class RoutingContentStoreTest extends AbstractWritableContentStoreTest { private ContentStore storeA; private ContentStore storeB; private ContentStore storeC; private ContentStore storeD; private ContentStore routingStore; @Override public void setUp() throws Exception { super.setUp(); File tempDir = TempFileProvider.getTempDir(); // Create a subdirectory for A File storeADir = new File(tempDir, "A"); storeA = new FileContentStore(storeADir); // Create a subdirectory for B File storeBDir = new File(tempDir, "B"); storeB = new FileContentStore(storeBDir); // Create a subdirectory for C File storeCDir = new File(tempDir, "C"); storeC = new DumbReadOnlyFileStore(new FileContentStore(storeCDir)); // No subdirectory for D storeD = new SupportsNoUrlFormatStore(); // Create the routing store routingStore = new RandomRoutingContentStore(storeA, storeB, storeC, storeD); } @Override protected ContentStore getStore() { return routingStore; } public void testSetUp() throws Exception { assertNotNull(routingStore); } private void checkForContent(String contentUrl, String content) { for (ContentStore store : new ContentStore[] {storeA, storeB}) { // Does the store have it if (store.exists(contentUrl)) { // Check it ContentReader reader = store.getReader(contentUrl); String checkContent = reader.getContentString(); assertEquals("Content found but is incorrect", content, checkContent); return; } } fail("Content not found in any of the stores: " + contentUrl); } /** * Checks that requests for missing content URLs are served. */ public void testMissingUrl() { String missingContentUrl = FileContentStore.createNewFileStoreUrl(); ContentReader reader = routingStore.getReader(missingContentUrl); assertNotNull("Missing URL should not return null", reader); assertFalse("Empty reader should say content doesn't exist.", reader.exists()); try { reader.getContentString(); fail("Empty reader cannot return content."); } catch (Throwable e) { // Expected } } public void testGeneralUse() { for (int i = 0 ; i < 20; i++) { ContentContext contentContext = new ContentContext(null, null); ContentWriter writer = routingStore.getWriter(contentContext); String content = "This was generated by " + this.getClass().getName() + "#" + getName() + " number " + i; writer.putContent(content); // Check that it exists String contentUrl = writer.getContentUrl(); checkForContent(contentUrl, content); // Now go direct to the routing store and check that it is able to find the appropriate URLs ContentReader reader = routingStore.getReader(contentUrl); assertNotNull("Null reader returned", reader); assertTrue("Reader should be onto live content", reader.exists()); } } /** * A test routing store that directs content writes to a randomly-chosen store. * Matching of content URLs back to the stores is handled by the base class. * * @author Derek Hulley */ private static class RandomRoutingContentStore extends AbstractRoutingContentStore { private List stores; public RandomRoutingContentStore(ContentStore ... stores) { this.stores = new ArrayList(5); for (ContentStore store : stores) { this.stores.add(store); } Cache ehCache = new Cache("RandomRoutingContentStore", 50, false, true, 0L, 0L); CacheManager cacheManager = new CacheManager(); cacheManager.addCache(ehCache); EhCacheAdapter cache = new EhCacheAdapter(); cache.setCache(ehCache); super.setStoresCache(cache); } @Override protected List getAllStores() { return stores; } @Override protected ContentStore selectWriteStore(ContentContext ctx) { // Shuffle the list of writable stores List shuffled = new ArrayList(stores); Collections.shuffle(shuffled); // Pick the first writable store for (ContentStore store : shuffled) { if (store.isWriteSupported()) { return store; } } // Nothing found fail("A request came for a writer when there is no writable store to choose from"); return null; } } /** * The simplest possible store. * * @author Derek Hulley */ private static class DumbReadOnlyFileStore extends AbstractContentStore { FileContentStore fileStore; public DumbReadOnlyFileStore(FileContentStore fileStore) { this.fileStore = fileStore; } public boolean isWriteSupported() { return false; } public ContentReader getReader(String contentUrl) { return fileStore.getReader(contentUrl); } @Override public void getUrls(Date createdAfter, Date createdBefore, ContentUrlHandler handler) throws ContentIOException { fileStore.getUrls(createdAfter, createdBefore, handler); } } /** * This store supports nothing. It is designed to catch the routing code out. * * @author Derek Hulley */ private static class SupportsNoUrlFormatStore extends AbstractContentStore { public SupportsNoUrlFormatStore() { } public boolean isWriteSupported() { return false; } public ContentReader getReader(String contentUrl) { throw new UnsupportedContentUrlException(this, contentUrl); } @Override public void getUrls(Date createdAfter, Date createdBefore, ContentUrlHandler handler) throws ContentIOException { throw new UnsupportedOperationException("getUrls not supported"); } } }