From e3e2711e29d44d21e5d65a26b9be4e0cd2d13446 Mon Sep 17 00:00:00 2001 From: Derek Hulley Date: Mon, 10 Sep 2007 13:09:30 +0000 Subject: [PATCH] Merged V2.1 to HEAD 6327: Drops alfresco-deployment.zip in build/dist instead of build. 6328:Set AVM file name requirements as lenient as possible. 6329: Fixed DNS name restriction to allow 1-char host labels. 6330: Setting read-only flag for start up components (AR-1621 and AR-193) 6331: Minor formatting 6332: Implementation of a read-only, HTTP-based ContentStore. 6333: AR-1619: A debug message needed changing as the FileFolderService now supports adding children onto system nodes. 6334: Build fix 6335: Fix for AWC-1447 (Office Add-In - Create Collaboration Space) 6337: Fixed AR-1622: WebService requests must be wrapped in retries git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@6721 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../messages/content-service.properties | 7 +- .../repo/admin/ConfigurationChecker.java | 2 +- .../alfresco/repo/avm/FileNameValidator.java | 2 +- .../repo/avm/FileNameValidatorTest.java | 4 +- .../content/filestore/FileContentReader.java | 2 +- .../content/filestore/FileContentStore.java | 2 +- .../http/HttpAlfrescoContentReader.java | 230 ++++++++++++++++-- .../repo/content/http/HttpAlfrescoStore.java | 159 +++++++++++- .../replication/ReplicatingContentStore.java | 18 ++ .../ReplicatingContentStoreTest.java | 15 +- .../filefolder/FileFolderServiceImpl.java | 3 +- .../node/index/AbstractReindexComponent.java | 2 +- .../AuthenticationServiceImpl.java | 10 +- .../security/authentication/userModel.xml | 4 +- 14 files changed, 406 insertions(+), 54 deletions(-) diff --git a/config/alfresco/messages/content-service.properties b/config/alfresco/messages/content-service.properties index f1b720e976..b52c90dfdb 100644 --- a/config/alfresco/messages/content-service.properties +++ b/config/alfresco/messages/content-service.properties @@ -7,4 +7,9 @@ index.recovery.out_of_date=The indexes are not synchronized with the database. index.recovery.starting=Index recovery started: {0} transactions. index.recovery.complete=Index recovery completed. index.recovery.progress=\t{0} % complete. -index.recovery.terminated=Index recovery terminated. \ No newline at end of file +index.recovery.terminated=Index recovery terminated. + +content.http_reader.err.no_connection=Unable to connect to remote Alfresco server via HTTP: {0} +content.http_reader.err.no_authentication=The HTTP reader was unable to authenticate on the remote server: {0} \n +content.http_reader.err.check_cluster=Please ensure that 'replicateUpdates' and 'replicateUpdatesViaCopy' is enabled for the cache 'org.alfresco.cache.ticketsCache'. Check that the general cluster configuration is correct and working. +content.http_reader.err.unrecognized=An unrecognized error occured when attempting to download content from remote server:\n Server: {0} \n Content: {1} \n HTTP Response: {2} diff --git a/source/java/org/alfresco/repo/admin/ConfigurationChecker.java b/source/java/org/alfresco/repo/admin/ConfigurationChecker.java index ffc1e058c6..db8abb5c65 100644 --- a/source/java/org/alfresco/repo/admin/ConfigurationChecker.java +++ b/source/java/org/alfresco/repo/admin/ConfigurationChecker.java @@ -179,7 +179,7 @@ public class ConfigurationChecker extends AbstractLifecycleBean return null; } }; - transactionService.getRetryingTransactionHelper().doInTransaction(checkWork); + transactionService.getRetryingTransactionHelper().doInTransaction(checkWork, true); } /** diff --git a/source/java/org/alfresco/repo/avm/FileNameValidator.java b/source/java/org/alfresco/repo/avm/FileNameValidator.java index 105ff48caf..669b1e43c1 100644 --- a/source/java/org/alfresco/repo/avm/FileNameValidator.java +++ b/source/java/org/alfresco/repo/avm/FileNameValidator.java @@ -34,7 +34,7 @@ public class FileNameValidator /** * The bad file name pattern. */ - private static String fgBadPattern = ".*[\"\\*\\\\><\\?/:\\|\\xA3\\xAC%&;]+.*"; + private static String fgBadPattern = ".*[\"\\*\\\\><\\?/:\\|]+.*"; /** * The compiled regex. diff --git a/source/java/org/alfresco/repo/avm/FileNameValidatorTest.java b/source/java/org/alfresco/repo/avm/FileNameValidatorTest.java index afb06c1160..e9577e48a8 100644 --- a/source/java/org/alfresco/repo/avm/FileNameValidatorTest.java +++ b/source/java/org/alfresco/repo/avm/FileNameValidatorTest.java @@ -33,8 +33,8 @@ public class FileNameValidatorTest extends TestCase { public void testValidator() { - String [] badNames = { "\"", "\\", "/", "<", ">", "?", "*", "%", "&", - ":", ";", "|" }; + String [] badNames = { "\"", "\\", "/", "<", ">", "?", "*", + ":", "|" }; for (String name : badNames) { assertFalse(FileNameValidator.IsValid(name)); diff --git a/source/java/org/alfresco/repo/content/filestore/FileContentReader.java b/source/java/org/alfresco/repo/content/filestore/FileContentReader.java index 5b2e742b2a..3fc22bc5d9 100644 --- a/source/java/org/alfresco/repo/content/filestore/FileContentReader.java +++ b/source/java/org/alfresco/repo/content/filestore/FileContentReader.java @@ -208,7 +208,7 @@ public class FileContentReader extends AbstractContentReader // the file must exist if (!file.exists()) { - throw new IOException("File does not exist"); + throw new IOException("File does not exist: " + file); } // create the channel ReadableByteChannel channel = null; diff --git a/source/java/org/alfresco/repo/content/filestore/FileContentStore.java b/source/java/org/alfresco/repo/content/filestore/FileContentStore.java index a436329f78..611152db8d 100644 --- a/source/java/org/alfresco/repo/content/filestore/FileContentStore.java +++ b/source/java/org/alfresco/repo/content/filestore/FileContentStore.java @@ -304,7 +304,7 @@ public class FileContentStore extends AbstractContentStore */ public boolean isWriteSupported() { - return true; + return !readOnly; } /** diff --git a/source/java/org/alfresco/repo/content/http/HttpAlfrescoContentReader.java b/source/java/org/alfresco/repo/content/http/HttpAlfrescoContentReader.java index 9f28b0ab1a..cf0f89830a 100644 --- a/source/java/org/alfresco/repo/content/http/HttpAlfrescoContentReader.java +++ b/source/java/org/alfresco/repo/content/http/HttpAlfrescoContentReader.java @@ -24,24 +24,34 @@ */ package org.alfresco.repo.content.http; +import java.io.IOException; +import java.io.InputStream; +import java.net.ConnectException; +import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.text.MessageFormat; +import java.util.Date; +import java.util.Locale; import javax.servlet.http.HttpServletResponse; import net.sf.acegisecurity.Authentication; import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.i18n.I18NUtil; import org.alfresco.repo.content.AbstractContentReader; -import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.repo.security.authentication.TicketComponent; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.cmr.repository.ContentIOException; import org.alfresco.service.cmr.repository.ContentReader; +import org.alfresco.service.cmr.repository.ContentStreamListener; +import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.service.transaction.TransactionService; import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; /** * The reader that does the actual communication with the Alfresco HTTP @@ -53,29 +63,45 @@ import org.apache.commons.httpclient.methods.GetMethod; */ public class HttpAlfrescoContentReader extends AbstractContentReader { - private static final String DEFAULT_URL = "{0}/dr?contentUrl={1}?ticket={2}"; - private static final String INFO_ONLY = "?infoOnly=true"; + private static final String ERR_NO_CONNECTION = "content.http_reader.err.no_connection"; + private static final String ERR_NO_AUTHENTICATION = "content.http_reader.err.no_authentication"; + private static final String ERR_CHECK_CLUSTER = "content.http_reader.err.check_cluster"; + private static final String ERR_UNRECOGNIZED = "content.http_reader.err.unrecognized"; - AuthenticationService authenticationService; - AuthenticationComponent authenticationComponent; + private static final String DEFAULT_URL = "{0}/dr?contentUrl={1}&ticket={2}"; + private static final String INFO_ONLY = "&infoOnly=true"; + + private static Log logger = LogFactory.getLog(HttpAlfrescoContentReader.class); + + private TransactionService transactionService; + private AuthenticationService authenticationService; private String baseHttpUrl; - private String contentUrl; // Helpers private HttpClient httpClient; + private PropagateTicketCallback ticketCallback; + // Cached values + private boolean isInfoCached; + private boolean cachedExists; + private long cachedLastModified; + private long cachedSize; public HttpAlfrescoContentReader( + TransactionService transactionService, AuthenticationService authenticationService, - AuthenticationComponent authenticationComponent, String baseHttpUrl, String contentUrl) { super(contentUrl); + this.transactionService = transactionService; this.authenticationService = authenticationService; - this.authenticationComponent = authenticationComponent; this.baseHttpUrl = baseHttpUrl; - this.contentUrl = contentUrl; // Helpers this.httpClient = new HttpClient(); + this.ticketCallback = new PropagateTicketCallback(); + // A trip to the remote server has not been made + cachedExists = false; + cachedSize = 0L; + cachedLastModified = 0L; } @Override @@ -88,31 +114,99 @@ public class HttpAlfrescoContentReader extends AbstractContentReader return sb.toString(); } - public boolean exists() + /** + * Helper class to wrap the ticket creation in order to force propagation of the + * authentication ticket around the cluster. + * + * @since 2.1 + * @author Derek Hulley + */ + private class PropagateTicketCallback implements RetryingTransactionCallback { + public String execute() throws Throwable + { + return authenticationService.getCurrentTicket(); + } + } + + private void getInfo() + { + String contentUrl = getContentUrl(); + // Info will be cached + isInfoCached = true; // Authenticate as the system user for the call Authentication authentication = null; GetMethod method = null; try { - authenticationComponent.setSystemUserAsCurrentUser(); - String ticket = authenticationService.getCurrentTicket(); + authentication = AuthenticationUtil.setCurrentUser(AuthenticationUtil.SYSTEM_USER_NAME); + String ticket = transactionService.getRetryingTransactionHelper().doInTransaction(ticketCallback, false, true); String url = HttpAlfrescoContentReader.generateURL(baseHttpUrl, contentUrl, ticket, true); method = new GetMethod(url); int statusCode = httpClient.executeMethod(method); - if (statusCode == HttpServletResponse.SC_NO_CONTENT) + if (statusCode == HttpServletResponse.SC_OK) { - return false; + // Get the information values from the request + String responseSize = method.getResponseHeader("alfresco.dr.size").getValue(); + String responseLastModified = method.getResponseHeader("alfresco.dr.lastModified").getValue(); + String responseMimetype = method.getResponseHeader("alfresco.dr.mimetype").getValue(); + String responseEncoding = method.getResponseHeader("alfresco.dr.encoding").getValue(); + String responseLocale = method.getResponseHeader("alfresco.dr.locale").getValue(); + // Fill in this reader's values + cachedSize = DefaultTypeConverter.INSTANCE.convert(Long.class, responseSize); + cachedLastModified = DefaultTypeConverter.INSTANCE.convert(Date.class, responseLastModified).getTime(); + setMimetype(DefaultTypeConverter.INSTANCE.convert(String.class, responseMimetype)); + setEncoding(DefaultTypeConverter.INSTANCE.convert(String.class, responseEncoding)); + setLocale(DefaultTypeConverter.INSTANCE.convert(Locale.class, responseLocale)); + // It exists + cachedExists = true; + // Done + if (logger.isDebugEnabled()) + { + logger.debug("\n" + + "HttpReader content found: \n" + + " Reader: " + this + "\n" + + " Server: " + baseHttpUrl); + } } else { - return true; + // Check the return codes + if (statusCode == HttpServletResponse.SC_NOT_FOUND) + { + // It doesn't exist, which is not an error. The defaults are fine. + } + else if (statusCode == HttpServletResponse.SC_FORBIDDEN) + { + // If the authentication fails, then the server is there, but probably not + // clustered correctly. + logger.error(I18NUtil.getMessage(ERR_NO_AUTHENTICATION, baseHttpUrl)); + logger.error(I18NUtil.getMessage(ERR_CHECK_CLUSTER)); + } + else + { + // What is this? + logger.error(I18NUtil.getMessage(ERR_UNRECOGNIZED, baseHttpUrl, contentUrl, statusCode)); + logger.error(I18NUtil.getMessage(ERR_CHECK_CLUSTER)); + } + // Done + if (logger.isDebugEnabled()) + { + logger.debug("\n" + + "HttpReader content not found: \n" + + " Reader: " + this + "\n" + + " Server: " + baseHttpUrl); + } } } + catch (ConnectException e) + { + logger.error(I18NUtil.getMessage(ERR_NO_CONNECTION, baseHttpUrl)); + } catch (Throwable e) { - throw new AlfrescoRuntimeException("Reader exists check failed: " + this); + throw new AlfrescoRuntimeException("Reader exists check failed: " + this, e); } finally { @@ -120,30 +214,114 @@ public class HttpAlfrescoContentReader extends AbstractContentReader { try { method.releaseConnection(); } catch (Throwable e) {} } - authenticationComponent.setCurrentAuthentication(authentication); + AuthenticationUtil.setCurrentAuthentication(authentication); } } - - public long getLastModified() + + public synchronized boolean exists() { - throw new UnsupportedOperationException(); + if (!isInfoCached) + { + getInfo(); + } + return cachedExists; + } + public synchronized long getLastModified() + { + if (!isInfoCached) + { + getInfo(); + } + return cachedLastModified; } - public long getSize() + public synchronized long getSize() { - throw new UnsupportedOperationException(); + if (!isInfoCached) + { + getInfo(); + } + return cachedSize; } @Override protected ContentReader createReader() throws ContentIOException { - throw new UnsupportedOperationException(); + return new HttpAlfrescoContentReader(transactionService, authenticationService, baseHttpUrl, getContentUrl()); } @Override protected ReadableByteChannel getDirectReadableChannel() throws ContentIOException { - throw new UnsupportedOperationException(); + String contentUrl = getContentUrl(); + + Authentication authentication = null; + try + { + if (!exists()) + { + throw new IOException("Content doesn't exist"); + } + authentication = AuthenticationUtil.setCurrentUser(AuthenticationUtil.SYSTEM_USER_NAME); + String ticket = transactionService.getRetryingTransactionHelper().doInTransaction(ticketCallback, false, true); + String url = HttpAlfrescoContentReader.generateURL(baseHttpUrl, contentUrl, ticket, false); + + GetMethod method = new GetMethod(url); + int statusCode = httpClient.executeMethod(method); + if (statusCode == HttpServletResponse.SC_OK) + { + // Get the stream from the request + InputStream contentStream = method.getResponseBodyAsStream(); + // Attach a listener to the stream to ensure that the HTTP request is cleaned up + this.addListener(new StreamCloseListener(method)); + // Done + if (logger.isDebugEnabled()) + { + logger.debug("\n" + + "HttpReader retrieve intput stream: \n" + + " Reader: " + this + "\n" + + " Server: " + baseHttpUrl); + } + return Channels.newChannel(contentStream); + } + else + { + // The content exists, but we failed to get it + throw new IOException("Failed to get content remote content that supposedly exists."); + } + } + catch (Throwable e) + { + throw new ContentIOException( + "Failed to open stream: \n" + + " Reader: " + this + "\n" + + " Remote server: " + baseHttpUrl, + e); + } + finally + { + AuthenticationUtil.setCurrentAuthentication(authentication); + } + } + + /** + * A listener to ensure that the HTTP method gets closed when the content stream it + * is serving to the reader is closed. + * + * @since 2.1 + * @author Derek Hulley + */ + private static class StreamCloseListener implements ContentStreamListener + { + private GetMethod getMethod; + private StreamCloseListener(GetMethod getMethod) + { + this.getMethod = getMethod; + } + public void contentStreamClosed() throws ContentIOException + { + try { getMethod.releaseConnection(); } catch (Throwable e) {} + } } /** diff --git a/source/java/org/alfresco/repo/content/http/HttpAlfrescoStore.java b/source/java/org/alfresco/repo/content/http/HttpAlfrescoStore.java index 03dc7f7a59..e6e2330ac0 100644 --- a/source/java/org/alfresco/repo/content/http/HttpAlfrescoStore.java +++ b/source/java/org/alfresco/repo/content/http/HttpAlfrescoStore.java @@ -24,10 +24,19 @@ */ package org.alfresco.repo.content.http; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; + import org.alfresco.repo.content.AbstractContentStore; -import org.alfresco.repo.security.authentication.AuthenticationComponent; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.service.transaction.TransactionService; +import org.alfresco.util.ApplicationContextHelper; +import org.springframework.context.ApplicationContext; /** * A read-only store using HTTP to access content from a remote Alfresco application. @@ -40,8 +49,8 @@ import org.alfresco.service.cmr.security.AuthenticationService; */ public class HttpAlfrescoStore extends AbstractContentStore { - AuthenticationComponent authenticationComponent; - AuthenticationService authenticationService; + private TransactionService transactionService; + private AuthenticationService authenticationService; private String baseHttpUrl; /** @@ -52,11 +61,12 @@ public class HttpAlfrescoStore extends AbstractContentStore } /** - * @param authenticationComponent the authentication compoent + * + * @param transactionService used to ensure proper ticket propagation in a cluster */ - public void setAuthenticationComponent(AuthenticationComponent authenticationComponent) + public void setTransactionService(TransactionService transactionService) { - this.authenticationComponent = authenticationComponent; + this.transactionService = transactionService; } /** @@ -68,7 +78,8 @@ public class HttpAlfrescoStore extends AbstractContentStore } /** - * Set the base HTTP URL of the remote Alfresco application. + * Set the base HTTP URL of the remote Alfresco application.
+ * For example:
http://192.168.1.66:8080/alfresco
. * * @param baseHttpUrl the remote HTTP address including the .../alfresco */ @@ -80,7 +91,7 @@ public class HttpAlfrescoStore extends AbstractContentStore } this.baseHttpUrl = baseHttpUrl; } - + /** * This is a read only store. * @@ -97,10 +108,140 @@ public class HttpAlfrescoStore extends AbstractContentStore public ContentReader getReader(String contentUrl) { ContentReader reader = new HttpAlfrescoContentReader( + transactionService, authenticationService, - authenticationComponent, baseHttpUrl, contentUrl); return reader; } + + /** + * Tests the HTTP store against a given server.
+ * Usage: + *
+     *    HttpAlfrescoStore help
+     *       Print the usage message
+     * 
+ * + * @param args the program arguments + */ + public static void main(String[] args) + { + String baseUrl = null; + String contentUrl = null; + try + { + if (args.length != 2) + { + printUsage(System.err); + System.exit(1); + } + else if (args[0].equalsIgnoreCase("help")) + { + printUsage(System.out); + System.exit(0); + } + baseUrl = args[0]; + contentUrl = args[1]; + + // Start the application to get hold of all the beans + ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); + + System.out.println( + "Starting test of " + HttpAlfrescoStore.class.getName() + " using server " + baseUrl + "."); + + // Do the test + doTest(ctx, baseUrl, contentUrl); + + System.out.println( + "Completed test of " + HttpAlfrescoStore.class.getName() + " using server " + baseUrl + "."); + + // Done + System.exit(0); + } + catch (Throwable e) + { + e.printStackTrace(); + System.err.println( + "Test of " + HttpAlfrescoStore.class.getName() + " using server " + baseUrl + " failed."); + System.exit(1); + } + finally + { + try + { + ApplicationContextHelper.closeApplicationContext(); + } + catch (Throwable e) + { + e.printStackTrace(); + } + } + } + + private static void doTest(ApplicationContext ctx, String baseUrl, String contentUrl) throws Exception + { + ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY); + TransactionService transactionService = serviceRegistry.getTransactionService(); + AuthenticationService authenticationService = serviceRegistry.getAuthenticationService(); + // Construct the store + HttpAlfrescoStore store = new HttpAlfrescoStore(); + store.setTransactionService(transactionService); + store.setAuthenticationService(authenticationService); + store.setBaseHttpUrl(baseUrl); + + // Now test + System.out.println( + " Retrieving reader for URL " + contentUrl); + ContentReader reader = store.getReader(contentUrl); + System.out.println( + " Retrieved reader for URL " + contentUrl); + // Check if the content exists + boolean exists = reader.exists(); + if (!exists) + { + System.out.println( + " Content doesn't exist: " + contentUrl); + return; + } + else + { + System.out.println( + " Content exists: " + contentUrl); + } + // Get the content data + ContentData contentData = reader.getContentData(); + System.out.println( + " Retrieved content data: " + contentData); + + // Now get the content + ByteBuffer buffer = ByteBuffer.allocate((int)reader.getSize()); + FileChannel channel = reader.getFileChannel(); + try + { + int count = channel.read(buffer); + if (count != reader.getSize()) + { + System.err.println("The number of bytes read was " + count + " but expected " + reader.getSize()); + return; + } + } + finally + { + channel.close(); + } + } + + private static void printUsage(OutputStream os) throws IOException + { + String msg = "Usage: \n" + + " HttpAlfrescoStore \n" + + " server-ip: the remote HTTP server running Alfresco \n" + + " content-url: the content URL to retrieve \n" + + " Run the test against a server. \n" + + " HttpAlfrescoStore help \n" + + " Print the usage message"; + os.write(msg.getBytes()); + os.flush(); + } } diff --git a/source/java/org/alfresco/repo/content/replication/ReplicatingContentStore.java b/source/java/org/alfresco/repo/content/replication/ReplicatingContentStore.java index 001db78b9c..558e2012b7 100644 --- a/source/java/org/alfresco/repo/content/replication/ReplicatingContentStore.java +++ b/source/java/org/alfresco/repo/content/replication/ReplicatingContentStore.java @@ -348,6 +348,11 @@ public class ReplicatingContentStore extends AbstractContentStore { for (ContentStore store : secondaryStores) { + // Ignore read-only stores + if (!store.isWriteSupported()) + { + continue; + } store.delete(contentUrl); } // log @@ -445,6 +450,19 @@ public class ReplicatingContentStore extends AbstractContentStore for (int i = 0; i < stores.size(); i++) { ContentStore store = stores.get(i); + // Bypass read-only stores + if (!store.isWriteSupported()) + { + if (logger.isDebugEnabled()) + { + logger.debug("Ignoring read-only store for content replication: \n" + + " Content: " + writer + "\n" + + " Store: " + store + "\n" + + " Number: " + i); + } + continue; + } + try { // replicate the content to the store - we know the URL that we want to write to diff --git a/source/java/org/alfresco/repo/content/replication/ReplicatingContentStoreTest.java b/source/java/org/alfresco/repo/content/replication/ReplicatingContentStoreTest.java index 4abbe7ce0e..7c859c98ac 100644 --- a/source/java/org/alfresco/repo/content/replication/ReplicatingContentStoreTest.java +++ b/source/java/org/alfresco/repo/content/replication/ReplicatingContentStoreTest.java @@ -71,12 +71,18 @@ public class ReplicatingContentStoreTest extends AbstractWritableContentStoreTes primaryStore = new FileContentStore(storeDir); // create some secondary file stores secondaryStores = new ArrayList(3); - for (int i = 0; i < 3; i++) + for (int i = 0; i < 4; i++) { storeDir = tempDir.getAbsolutePath() + File.separatorChar + GUID.generate(); - ContentStore store = new FileContentStore(storeDir); + FileContentStore store = new FileContentStore(storeDir); secondaryStores.add(store); + // Only the first 3 are writable + if (i >= 3) + { + store.setReadOnly(true); + } } + // Create the replicating store replicatingStore = new ReplicatingContentStore(); replicatingStore.setPrimaryStore(primaryStore); replicatingStore.setSecondaryStores(secondaryStores); @@ -106,6 +112,11 @@ public class ReplicatingContentStoreTest extends AbstractWritableContentStoreTes { for (ContentStore store : secondaryStores) { + // This is only required for writable stores + if (!store.isWriteSupported()) + { + continue; + } ContentReader reader = store.getReader(contentUrl); assertTrue("Content was not replicated out to the secondary stores within a second", reader.exists()); assertEquals("The replicated content was incorrect", content, reader.getContentString()); diff --git a/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java b/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java index 8c34de9986..b8f19d74c8 100644 --- a/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java +++ b/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java @@ -721,9 +721,8 @@ public class FileFolderServiceImpl implements FileFolderService // done if (logger.isDebugEnabled()) { - FileInfo parentFileInfo = toFileInfo(parentNodeRef, false); logger.debug("Created: \n" + - " parent: " + parentFileInfo + "\n" + + " parent: " + parentNodeRef + "\n" + " created: " + fileInfo); } return fileInfo; diff --git a/source/java/org/alfresco/repo/node/index/AbstractReindexComponent.java b/source/java/org/alfresco/repo/node/index/AbstractReindexComponent.java index 1776b79ab8..1bd4287e7c 100644 --- a/source/java/org/alfresco/repo/node/index/AbstractReindexComponent.java +++ b/source/java/org/alfresco/repo/node/index/AbstractReindexComponent.java @@ -217,7 +217,7 @@ public abstract class AbstractReindexComponent implements IndexRecovery return null; } }; - transactionService.getRetryingTransactionHelper().doInTransaction(reindexWork); + transactionService.getRetryingTransactionHelper().doInTransaction(reindexWork, true); } finally { diff --git a/source/java/org/alfresco/repo/security/authentication/AuthenticationServiceImpl.java b/source/java/org/alfresco/repo/security/authentication/AuthenticationServiceImpl.java index f6cf9034d9..53115c7739 100644 --- a/source/java/org/alfresco/repo/security/authentication/AuthenticationServiceImpl.java +++ b/source/java/org/alfresco/repo/security/authentication/AuthenticationServiceImpl.java @@ -148,11 +148,11 @@ public class AuthenticationServiceImpl implements AuthenticationService clearCurrentSecurityContext(); authenticationComponent.setCurrentUser(ticketComponent.validateTicket(ticket)); } - catch(AuthenticationException ae) - { - clearCurrentSecurityContext(); - throw ae; - } + catch(AuthenticationException ae) + { + clearCurrentSecurityContext(); + throw ae; + } } public String getCurrentTicket() diff --git a/source/java/org/alfresco/repo/security/authentication/userModel.xml b/source/java/org/alfresco/repo/security/authentication/userModel.xml index ce732b07c2..18e981c3fa 100644 --- a/source/java/org/alfresco/repo/security/authentication/userModel.xml +++ b/source/java/org/alfresco/repo/security/authentication/userModel.xml @@ -22,7 +22,7 @@ - Alfreco Authority Abstract Type + Alfresco Authority Abstract Type sys:base @@ -101,4 +101,4 @@ - \ No newline at end of file +