diff --git a/config/alfresco/action-services-context.xml b/config/alfresco/action-services-context.xml
index 05a962a69f..a931fba337 100644
--- a/config/alfresco/action-services-context.xml
+++ b/config/alfresco/action-services-context.xml
@@ -548,9 +548,6 @@
-
-
-
diff --git a/config/alfresco/content-services-context.xml b/config/alfresco/content-services-context.xml
index 6e4e94014a..e321bf7507 100644
--- a/config/alfresco/content-services-context.xml
+++ b/config/alfresco/content-services-context.xml
@@ -93,6 +93,9 @@
+
+
+
@@ -112,6 +115,10 @@
+
+
+
@@ -149,6 +156,9 @@
+
+
+
@@ -206,7 +216,9 @@
-
+
@@ -412,7 +424,9 @@
+ parent="baseContentTransformer">
+
+
+
+
+
diff --git a/config/alfresco/extension/bm-remote-loader-context.xml.sample b/config/alfresco/extension/bm-remote-loader-context.xml.sample
index e4b4249dc6..2eafcc5a6d 100644
--- a/config/alfresco/extension/bm-remote-loader-context.xml.sample
+++ b/config/alfresco/extension/bm-remote-loader-context.xml.sample
@@ -16,9 +16,6 @@
-
-
-
@@ -51,9 +48,6 @@
-
-
-
@@ -77,4 +71,4 @@
-
\ No newline at end of file
+
diff --git a/config/alfresco/rendition-services-context.xml b/config/alfresco/rendition-services-context.xml
index 92481e745c..742606deb9 100644
--- a/config/alfresco/rendition-services-context.xml
+++ b/config/alfresco/rendition-services-context.xml
@@ -131,7 +131,11 @@
+ parent="baseRenderingAction">
+
+
+
+
${imap.server.attachments.extraction.enabled}
+
+
+
diff --git a/source/java/org/alfresco/cmis/mapping/CMISServicesImpl.java b/source/java/org/alfresco/cmis/mapping/CMISServicesImpl.java
index 5025a4e6a0..048a654748 100644
--- a/source/java/org/alfresco/cmis/mapping/CMISServicesImpl.java
+++ b/source/java/org/alfresco/cmis/mapping/CMISServicesImpl.java
@@ -1826,15 +1826,9 @@ public class CMISServicesImpl implements CMISServices, ApplicationContextAware,
throw new CMISContentAlreadyExistsException();
}
- contentStream = contentStream.markSupported() ? contentStream : new BufferedInputStream(contentStream);
-
- // establish content encoding
- ContentCharsetFinder charsetFinder = mimetypeService.getContentCharsetFinder();
- Charset encoding = charsetFinder.getCharset(contentStream, mimeType);
-
ContentWriter writer = contentService.getWriter(nodeRef, propertyQName, true);
+ writer.guessEncoding();
writer.setMimetype(mimeType);
- writer.setEncoding(encoding.name());
writer.putContent(contentStream);
return existed;
diff --git a/source/java/org/alfresco/filesys/FTPServerTest.java b/source/java/org/alfresco/filesys/FTPServerTest.java
new file mode 100644
index 0000000000..94b20f407a
--- /dev/null
+++ b/source/java/org/alfresco/filesys/FTPServerTest.java
@@ -0,0 +1,666 @@
+/*
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco 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 Alfresco. If not, see .
+ */
+package org.alfresco.filesys;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.StringWriter;
+
+import org.alfresco.filesys.repo.ContentDiskDriverTest;
+import org.alfresco.model.ContentModel;
+import org.alfresco.repo.model.Repository;
+import org.alfresco.repo.security.authentication.AuthenticationComponent;
+import org.alfresco.repo.transaction.RetryingTransactionHelper;
+import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
+import org.alfresco.service.cmr.repository.ChildAssociationRef;
+import org.alfresco.service.cmr.repository.ContentService;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.cmr.security.MutableAuthenticationService;
+import org.alfresco.service.cmr.security.PermissionService;
+import org.alfresco.service.cmr.security.PersonService;
+import org.alfresco.service.namespace.NamespaceService;
+import org.alfresco.service.namespace.QName;
+import org.alfresco.service.transaction.TransactionService;
+import org.alfresco.util.ApplicationContextHelper;
+import org.alfresco.util.BaseAlfrescoSpringTest;
+import org.alfresco.util.PropertyMap;
+
+import java.io.InputStream;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.net.PrintCommandListener;
+import org.apache.commons.net.ftp.FTPClient;
+import org.apache.commons.net.ftp.FTPFile;
+import org.apache.commons.net.ftp.FTPReply;
+import org.springframework.context.ApplicationContext;
+
+
+/**
+ * End to end JUNIT test of the FTP server
+ *
+ * Uses the commons-net ftp client library to connect to the
+ * Alfresco FTP server.
+ */
+public class FTPServerTest extends TestCase
+
+{
+ private static Log logger = LogFactory.getLog(FTPServerTest.class);
+
+ private ApplicationContext applicationContext;
+
+ private final String USER_ADMIN="admin";
+ private final String PASSWORD_ADMIN="admin";
+ private final String USER_ONE = "FTPServerTestOne";
+ private final String USER_TWO = "FTPServerTestTwo";
+ private final String PASSWORD_ONE="Password01";
+ private final String PASSWORD_TWO="Password02";
+ private final String HOSTNAME="localhost";
+
+ private final String TEST_FOLDER = "FTPServerTest";
+
+
+ private NodeService nodeService;
+ private PersonService personService;
+ private MutableAuthenticationService authenticationService;
+ private AuthenticationComponent authenticationComponent;
+ private TransactionService transactionService;
+ private Repository repositoryHelper;
+ private PermissionService permissionService;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ applicationContext = ApplicationContextHelper.getApplicationContext();
+
+ nodeService = (NodeService)applicationContext.getBean("nodeService");
+ personService = (PersonService)applicationContext.getBean("personService");
+ authenticationService = (MutableAuthenticationService)applicationContext.getBean("AuthenticationService");
+ authenticationComponent = (AuthenticationComponent)applicationContext.getBean("authenticationComponent");
+ transactionService = (TransactionService)applicationContext.getBean("transactionService");
+ repositoryHelper = (Repository)applicationContext.getBean("repositoryHelper");
+ permissionService = (PermissionService)applicationContext.getBean("permissionService");
+
+ assertNotNull("nodeService is null", nodeService);
+ assertNotNull("reporitoryHelper is null", repositoryHelper);
+ assertNotNull("personService is null", personService);
+ assertNotNull("authenticationService is null", authenticationService);
+ assertNotNull("authenticationComponent is null", authenticationComponent);
+
+ authenticationComponent.setSystemUserAsCurrentUser();
+
+ final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
+
+ RetryingTransactionCallback createUsersCB = new RetryingTransactionCallback() {
+
+ @Override
+ public Void execute() throws Throwable
+ {
+ createUser(USER_ONE, PASSWORD_ONE);
+ createUser(USER_TWO, PASSWORD_TWO);
+ return null;
+ }
+ };
+ tran.doInTransaction(createUsersCB);
+
+ RetryingTransactionCallback createTestDirCB = new RetryingTransactionCallback() {
+
+ @Override
+ public Void execute() throws Throwable
+ {
+ {
+ NodeRef userOneHome = repositoryHelper.getUserHome(personService.getPerson(USER_ONE));
+ permissionService.setPermission(userOneHome, USER_TWO, PermissionService.CONTRIBUTOR, true);
+ permissionService.setPermission(userOneHome, USER_TWO, PermissionService.WRITE, true);
+ }
+ return null;
+ }
+ };
+ tran.doInTransaction(createTestDirCB, false, true);
+ }
+
+ protected void tearDown() throws Exception
+ {
+// UserTransaction txn = transactionService.getUserTransaction();
+// assertNotNull("transaction leaked", txn);
+// txn.getStatus();
+// txn.rollback();
+ }
+
+ /**
+ * Simple test that connects to the inbuilt ftp server and logs on
+ *
+ * @throws Exception
+ */
+ public void testFTPConnect() throws Exception
+ {
+ logger.debug("Start testFTPConnect");
+
+ FTPClient ftp = connectClient();
+ try
+ {
+ int reply = ftp.getReplyCode();
+
+ if (!FTPReply.isPositiveCompletion(reply))
+ {
+ fail("FTP server refused connection.");
+ }
+
+ boolean login = ftp.login(USER_ADMIN, PASSWORD_ADMIN);
+ assertTrue("admin login not successful", login);
+ }
+ finally
+ {
+ ftp.disconnect();
+ }
+ }
+
+ /**
+ * Simple negative test that connects to the inbuilt ftp server and attempts to
+ * log on with the wrong password.
+ *
+ * @throws Exception
+ */
+ public void testFTPConnectNegative() throws Exception
+ {
+ logger.debug("Start testFTPConnectNegative");
+
+ FTPClient ftp = connectClient();
+
+ try
+ {
+ int reply = ftp.getReplyCode();
+
+ if (!FTPReply.isPositiveCompletion(reply))
+ {
+ fail("FTP server refused connection.");
+ }
+
+ boolean login = ftp.login(USER_ADMIN, "garbage");
+ assertFalse("admin login successful", login);
+
+ // now attempt to list the files and check that the command does not
+ // succeed
+ FTPFile[] files = ftp.listFiles();
+
+ assertNotNull(files);
+ assertTrue(files.length == 0);
+ reply = ftp.getReplyCode();
+
+ assertTrue(FTPReply.isNegativePermanent(reply));
+
+ }
+ finally
+ {
+ ftp.disconnect();
+ }
+ }
+
+ /**
+ * Test CWD for FTP server
+ *
+ * @throws Exception
+ */
+ public void testCWD() throws Exception
+ {
+ logger.debug("Start testCWD");
+
+ FTPClient ftp = connectClient();
+
+ try
+ {
+ int reply = ftp.getReplyCode();
+
+ if (!FTPReply.isPositiveCompletion(reply))
+ {
+ fail("FTP server refused connection.");
+ }
+
+ boolean login = ftp.login(USER_ADMIN, PASSWORD_ADMIN);
+ assertTrue("admin login successful", login);
+
+ FTPFile[] files = ftp.listFiles();
+ reply = ftp.getReplyCode();
+ assertTrue(FTPReply.isPositiveCompletion(reply));
+
+ // expect /Alfresco directory
+ // /AVM directory
+ assertTrue(files.length == 2);
+
+ boolean foundAVM=false;
+ boolean foundAlfresco=false;
+ for(FTPFile file : files)
+ {
+ logger.debug("file name=" + file.getName());
+ assertTrue(file.isDirectory());
+
+ if(file.getName().equalsIgnoreCase("AVM"))
+ {
+ foundAVM=true;
+ }
+ if(file.getName().equalsIgnoreCase("Alfresco"))
+ {
+ foundAlfresco=true;
+ }
+ }
+ assertTrue(foundAVM);
+ assertTrue(foundAlfresco);
+
+ // Change to Alfresco Dir that we know exists
+ reply = ftp.cwd("/Alfresco");
+ assertTrue(FTPReply.isPositiveCompletion(reply));
+
+ // relative path with space char
+ reply = ftp.cwd("Data Dictionary");
+ assertTrue(FTPReply.isPositiveCompletion(reply));
+
+ // non existant absolute
+ reply = ftp.cwd("/Garbage");
+ assertTrue(FTPReply.isNegativePermanent(reply));
+
+ reply = ftp.cwd("/Alfresco/User Homes");
+ assertTrue(FTPReply.isPositiveCompletion(reply));
+
+ // Wild card
+ reply = ftp.cwd("/Alfresco/User*Homes");
+ assertTrue(FTPReply.isPositiveCompletion(reply));
+
+ // two level folder
+ reply = ftp.cwd("/Alfresco/Data Dictionary");
+ assertTrue(FTPReply.isPositiveCompletion(reply));
+
+ // go up one
+ reply = ftp.cwd("..");
+ assertTrue(FTPReply.isPositiveCompletion(reply));
+
+ reply = ftp.pwd();
+ ftp.getStatus();
+
+ assertTrue(FTPReply.isPositiveCompletion(reply));
+
+ // check we are at the correct point in the tree
+ reply = ftp.cwd("Data Dictionary");
+ assertTrue(FTPReply.isPositiveCompletion(reply));
+
+
+ }
+ finally
+ {
+ ftp.disconnect();
+ }
+
+ }
+
+ /**
+ * Test CRUD for FTP server
+ *
+ * @throws Exception
+ */
+ public void testCRUD() throws Exception
+ {
+ final String PATH1 = "FTPServerTest";
+ final String PATH2 = "Second part";
+
+ logger.debug("Start testFTPCRUD");
+
+ FTPClient ftp = connectClient();
+
+ try
+ {
+ int reply = ftp.getReplyCode();
+
+ if (!FTPReply.isPositiveCompletion(reply))
+ {
+ fail("FTP server refused connection.");
+ }
+
+ boolean login = ftp.login(USER_ADMIN, PASSWORD_ADMIN);
+ assertTrue("admin login successful", login);
+
+ reply = ftp.cwd("/Alfresco/User Homes");
+ assertTrue(FTPReply.isPositiveCompletion(reply));
+
+ // Delete the root directory in case it was left over from a previous test run
+ try
+ {
+ ftp.removeDirectory(PATH1);
+ }
+ catch (IOException e)
+ {
+ // ignore this error
+ }
+
+ // make root directory
+ ftp.makeDirectory(PATH1);
+ ftp.cwd(PATH1);
+
+ // make sub-directory in new directory
+ ftp.makeDirectory(PATH2);
+ ftp.cwd(PATH2);
+
+ // List the files in the new directory
+ FTPFile[] files = ftp.listFiles();
+ assertTrue("files not empty", files.length == 0);
+
+ // Create a file
+ String FILE1_CONTENT_1="test file 1 content";
+ String FILE1_NAME = "testFile1.txt";
+ ftp.appendFile(FILE1_NAME , new ByteArrayInputStream(FILE1_CONTENT_1.getBytes("UTF-8")));
+
+ // Get the new file
+ FTPFile[] files2 = ftp.listFiles();
+ assertTrue("files not one", files2.length == 1);
+
+ InputStream is = ftp.retrieveFileStream(FILE1_NAME);
+
+ String content = inputStreamToString(is);
+ assertEquals("Content is not as expected", content, FILE1_CONTENT_1);
+ ftp.completePendingCommand();
+
+ // Update the file contents
+ String FILE1_CONTENT_2="That's how it is says Pooh!";
+ ftp.appendFile(FILE1_NAME , new ByteArrayInputStream(FILE1_CONTENT_2.getBytes("UTF-8")));
+
+ InputStream is2 = ftp.retrieveFileStream(FILE1_NAME);
+
+ String content2 = inputStreamToString(is2);
+ assertEquals("Content is not as expected", content2, FILE1_CONTENT_2);
+ ftp.completePendingCommand();
+
+ // now delete the file we have been using.
+ assertTrue (ftp.deleteFile(FILE1_NAME));
+
+ // negative test - file should have gone now.
+ assertFalse (ftp.deleteFile(FILE1_NAME));
+
+ }
+ finally
+ {
+ // clean up tree if left over from previous run
+
+ ftp.disconnect();
+ }
+ }
+
+ /**
+ * Test of obscure path names in the FTP server
+ *
+ * RFC959 states that paths are constructed thus...
+ * ::= |
+ * ::=
+ * ::= any of the 128 ASCII characters except and
+ *
+ * So we need to check how high characters and problematic are encoded
+ */
+ public void testPathNames() throws Exception
+ {
+
+ logger.debug("Start testPathNames");
+
+ FTPClient ftp = connectClient();
+
+ String PATH1="testPathNames";
+
+ try
+ {
+ int reply = ftp.getReplyCode();
+
+ if (!FTPReply.isPositiveCompletion(reply))
+ {
+ fail("FTP server refused connection.");
+ }
+
+ boolean login = ftp.login(USER_ADMIN, PASSWORD_ADMIN);
+ assertTrue("admin login successful", login);
+
+ reply = ftp.cwd("/Alfresco/User*Homes");
+ assertTrue(FTPReply.isPositiveCompletion(reply));
+
+ // Delete the root directory in case it was left over from a previous test run
+ try
+ {
+ ftp.removeDirectory(PATH1);
+ }
+ catch (IOException e)
+ {
+ // ignore this error
+ }
+
+ // make root directory for this test
+ boolean success = ftp.makeDirectory(PATH1);
+ assertTrue("unable to make directory:" + PATH1, success);
+
+ success = ftp.changeWorkingDirectory(PATH1);
+ assertTrue("unable to change to working directory:" + PATH1, success);
+
+ assertTrue("with a space", ftp.makeDirectory("test space"));
+ assertTrue("with exclamation", ftp.makeDirectory("space!"));
+ assertTrue("with dollar", ftp.makeDirectory("space$"));
+ assertTrue("with brackets", ftp.makeDirectory("space()"));
+ assertTrue("with hash curley brackets", ftp.makeDirectory("space{}"));
+
+
+ //Pound sign U+00A3
+ //Yen Sign U+00A5
+ //Capital Omega U+03A9
+
+ assertTrue("with pound sign", ftp.makeDirectory("pound \u00A3.world"));
+ assertTrue("with yen sign", ftp.makeDirectory("yen \u00A5.world"));
+
+ // Test steps that do not work
+ // assertTrue("with omega", ftp.makeDirectory("omega \u03A9.world"));
+ // assertTrue("with obscure ASCII chars", ftp.makeDirectory("?/.,<>"));
+ }
+ finally
+ {
+ // clean up tree if left over from previous run
+
+ ftp.disconnect();
+ }
+
+
+ }
+
+ /**
+ * Create a user other than "admin" who has access to a set of files.
+ *
+ * Create a folder containing test.docx as user one
+ * Update that file as user two.
+ * Check user one can see user two's changes.
+ *
+ * @throws Exception
+ */
+ public void testTwoUserUpdate() throws Exception
+ {
+ logger.debug("Start testFTPConnect");
+
+ final String TEST_DIR="/Alfresco/User Homes/" + USER_ONE;
+
+ final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
+
+ FTPClient ftpOne = connectClient();
+ FTPClient ftpTwo = connectClient();
+ try
+ {
+ int reply = ftpOne.getReplyCode();
+
+ if (!FTPReply.isPositiveCompletion(reply))
+ {
+ fail("FTP server refused connection.");
+ }
+
+ reply = ftpTwo.getReplyCode();
+
+ if (!FTPReply.isPositiveCompletion(reply))
+ {
+ fail("FTP server refused connection.");
+ }
+
+ boolean login = ftpOne.login(USER_ONE, PASSWORD_ONE);
+ assertTrue("user one login not successful", login);
+
+ login = ftpTwo.login(USER_TWO, PASSWORD_TWO);
+ assertTrue("user two login not successful", login);
+
+ boolean success = ftpOne.changeWorkingDirectory("Alfresco");
+ assertTrue("user one unable to cd to Alfreco", success);
+ success = ftpOne.changeWorkingDirectory("User*Homes");
+ assertTrue("user one unable to cd to User*Homes", success);
+ success = ftpOne.changeWorkingDirectory(USER_ONE);
+ assertTrue("user one unable to cd to " + USER_ONE, success);
+
+ success = ftpTwo.changeWorkingDirectory("Alfresco");
+ assertTrue("user two unable to cd to Alfreco", success);
+ success = ftpTwo.changeWorkingDirectory("User*Homes");
+ assertTrue("user two unable to cd to User*Homes", success);
+ success = ftpTwo.changeWorkingDirectory(USER_ONE);
+ assertTrue("user two unable to cd " + USER_ONE, success);
+
+ // Create a file as user one
+ String FILE1_CONTENT_1="test file 1 content";
+ String FILE1_NAME = "test.docx";
+ success = ftpOne.appendFile(FILE1_NAME , new ByteArrayInputStream(FILE1_CONTENT_1.getBytes("UTF-8")));
+ assertTrue("user one unable to append file", success);
+
+ // Update the file as user two
+ String FILE1_CONTENT_2="test file content updated";
+ success = ftpTwo.appendFile(FILE1_NAME , new ByteArrayInputStream(FILE1_CONTENT_2.getBytes("UTF-8")));
+ assertTrue("user two unable to append file", success);
+
+ // User one should read user2's content
+ InputStream is1 = ftpOne.retrieveFileStream(FILE1_NAME);
+ assertNotNull("is1 is null", is1);
+ String content1 = inputStreamToString(is1);
+ assertEquals("Content is not as expected", FILE1_CONTENT_2, content1);
+ ftpOne.completePendingCommand();
+
+ // User two should read user2's content
+ InputStream is2 = ftpTwo.retrieveFileStream(FILE1_NAME);
+ assertNotNull("is2 is null", is2);
+ String content2 = inputStreamToString(is2);
+ assertEquals("Content is not as expected", FILE1_CONTENT_2, content2);
+ ftpTwo.completePendingCommand();
+ logger.debug("Test finished");
+
+ }
+ finally
+ {
+ ftpOne.dele(TEST_DIR);
+ if(ftpOne != null)
+ {
+ ftpOne.disconnect();
+ }
+ if(ftpTwo != null)
+ {
+ ftpTwo.disconnect();
+ }
+ }
+
+ }
+
+ /**
+ * Create a user with a small quota.
+ *
+ * Upload a file less than the quota.
+ *
+ * Upload a file greater than the quota.
+ *
+ * @throws Exception
+ */
+ public void DISABLED_testQuota() throws Exception
+ {
+ fail("not yet implemented");
+ }
+
+ private FTPClient connectClient() throws IOException
+ {
+ FTPClient ftp = new FTPClient();
+
+ if(logger.isDebugEnabled())
+ {
+ ftp.addProtocolCommandListener(new PrintCommandListener(
+ new PrintWriter(System.out)));
+ }
+
+ String server = HOSTNAME;
+
+ ftp.connect(server);
+ return ftp;
+ }
+
+ /**
+ * Test quality utility to read an input stream into a string.
+ * @param is
+ * @return the content of the stream in a string.
+ * @throws IOException
+ */
+ private String inputStreamToString(InputStream is) throws IOException
+ {
+ if (is != null)
+ {
+ StringWriter writer = new StringWriter();
+
+ char[] buffer = new char[1024];
+ try
+ {
+ Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
+ int n;
+ while ((n = reader.read(buffer)) != -1)
+ {
+ writer.write(buffer, 0, n);
+ }
+ }
+ finally
+ {
+ is.close();
+ }
+ is.close();
+
+ return writer.getBuffer().toString();
+
+ }
+ return "";
+ }
+
+ private void createUser(String userName, String password)
+ {
+ if (this.authenticationService.authenticationExists(userName) == false)
+ {
+ this.authenticationService.createAuthentication(userName, password.toCharArray());
+
+ PropertyMap ppOne = new PropertyMap(4);
+ ppOne.put(ContentModel.PROP_USERNAME, userName);
+ ppOne.put(ContentModel.PROP_FIRSTNAME, "firstName");
+ ppOne.put(ContentModel.PROP_LASTNAME, "lastName");
+ ppOne.put(ContentModel.PROP_EMAIL, "email@email.com");
+ ppOne.put(ContentModel.PROP_JOBTITLE, "jobTitle");
+
+ this.personService.createPerson(ppOne);
+ }
+ }
+
+
+}
diff --git a/source/java/org/alfresco/filesys/alfresco/package-info.java b/source/java/org/alfresco/filesys/alfresco/package-info.java
new file mode 100644
index 0000000000..c5cbfe5da6
--- /dev/null
+++ b/source/java/org/alfresco/filesys/alfresco/package-info.java
@@ -0,0 +1,12 @@
+/**
+ * FileSystem
+ *
+ * DesktopAction
+ *
+ * AlfrescoDiskDriver
+ *
+ * MultiTenantShareMapper
+ *
+ *
+ */
+package org.alfresco.filesys.alfresco;
diff --git a/source/java/org/alfresco/filesys/auth/cifs/package-info.java b/source/java/org/alfresco/filesys/auth/cifs/package-info.java
new file mode 100644
index 0000000000..b5e6184554
--- /dev/null
+++ b/source/java/org/alfresco/filesys/auth/cifs/package-info.java
@@ -0,0 +1,3 @@
+/**
+ */
+package org.alfresco.filesys.auth.cifs;
diff --git a/source/java/org/alfresco/filesys/auth/ftp/package-info.java b/source/java/org/alfresco/filesys/auth/ftp/package-info.java
new file mode 100644
index 0000000000..18c8783155
--- /dev/null
+++ b/source/java/org/alfresco/filesys/auth/ftp/package-info.java
@@ -0,0 +1,3 @@
+/**
+ */
+package org.alfresco.filesys.auth.ftp;
diff --git a/source/java/org/alfresco/filesys/auth/nfs/package-info.java b/source/java/org/alfresco/filesys/auth/nfs/package-info.java
new file mode 100644
index 0000000000..c780e407be
--- /dev/null
+++ b/source/java/org/alfresco/filesys/auth/nfs/package-info.java
@@ -0,0 +1,3 @@
+/**
+ */
+package org.alfresco.filesys.auth.nfs;
diff --git a/source/java/org/alfresco/filesys/auth/package-info.java b/source/java/org/alfresco/filesys/auth/package-info.java
new file mode 100644
index 0000000000..03430ab354
--- /dev/null
+++ b/source/java/org/alfresco/filesys/auth/package-info.java
@@ -0,0 +1,3 @@
+/**
+ */
+package org.alfresco.filesys.auth;
diff --git a/source/java/org/alfresco/filesys/avm/package-info.java b/source/java/org/alfresco/filesys/avm/package-info.java
new file mode 100644
index 0000000000..b017b96a61
--- /dev/null
+++ b/source/java/org/alfresco/filesys/avm/package-info.java
@@ -0,0 +1,3 @@
+/**
+ */
+package org.alfresco.filesys.avm;
diff --git a/source/java/org/alfresco/filesys/config/acl/package-info.java b/source/java/org/alfresco/filesys/config/acl/package-info.java
new file mode 100644
index 0000000000..2916500028
--- /dev/null
+++ b/source/java/org/alfresco/filesys/config/acl/package-info.java
@@ -0,0 +1,3 @@
+/**
+ */
+package org.alfresco.filesys.config.acl;
diff --git a/source/java/org/alfresco/filesys/config/package-info.java b/source/java/org/alfresco/filesys/config/package-info.java
new file mode 100644
index 0000000000..d30d447fc6
--- /dev/null
+++ b/source/java/org/alfresco/filesys/config/package-info.java
@@ -0,0 +1,3 @@
+/**
+ */
+package org.alfresco.filesys.config;
diff --git a/source/java/org/alfresco/filesys/debug/package-info.java b/source/java/org/alfresco/filesys/debug/package-info.java
new file mode 100644
index 0000000000..2e324d733f
--- /dev/null
+++ b/source/java/org/alfresco/filesys/debug/package-info.java
@@ -0,0 +1,3 @@
+/**
+ */
+package org.alfresco.filesys.debug;
diff --git a/source/java/org/alfresco/filesys/package-info.java b/source/java/org/alfresco/filesys/package-info.java
new file mode 100644
index 0000000000..81b02384fe
--- /dev/null
+++ b/source/java/org/alfresco/filesys/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * The Alfresco file system interface implementation
+ */
+package org.alfresco.filesys;
diff --git a/source/java/org/alfresco/filesys/repo/CifsHelper.java b/source/java/org/alfresco/filesys/repo/CifsHelper.java
index d6b1612083..2076535b4f 100644
--- a/source/java/org/alfresco/filesys/repo/CifsHelper.java
+++ b/source/java/org/alfresco/filesys/repo/CifsHelper.java
@@ -627,7 +627,7 @@ public class CifsHelper
ContentData newContentData = fileToMoveInfo.getContentData();
// Reset the mime type
-
+ // TODO Pass the content along when guessing the mime type, so we're more accurate
String mimetype = mimetypeService.guessMimetype(newName);
newContentData = ContentData.setMimetype(newContentData, mimetype);
diff --git a/source/java/org/alfresco/filesys/repo/ContentDiskDriverTest.java b/source/java/org/alfresco/filesys/repo/ContentDiskDriverTest.java
index 45dddff6b8..321d9ae3bb 100644
--- a/source/java/org/alfresco/filesys/repo/ContentDiskDriverTest.java
+++ b/source/java/org/alfresco/filesys/repo/ContentDiskDriverTest.java
@@ -408,10 +408,9 @@ public class ContentDiskDriverTest extends TestCase
final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
-
/**
* Step 1 : Create a new file in read/write mode and add some content.
- */
+ */
int openAction = FileAction.CreateNotExist;
String FILE_PATH="\\testDeleteFile.new";
@@ -635,12 +634,23 @@ public class ContentDiskDriverTest extends TestCase
TreeConnection testConnection = testServer.getTreeConnection(share);
final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
- final String FILE_NAME="testOpenFileY.whatever";
+ class TestContext
+ {
+ NodeRef testDirNodeRef;
+ };
+
+ final TestContext testContext = new TestContext();
+
+ final String FILE_NAME="testOpenFile.txt";
+ FileOpenParams dirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, 0, AccessMode.ReadOnly, FileAttribute.NTDirectory, 0);
+ driver.createDirectory(testSession, testConnection, dirParams);
+
+ testContext.testDirNodeRef = driver.getNodeForPath(testConnection, TEST_ROOT_DOS_PATH);
/**
* Step 1 : Negative test - try to open a file that does not exist
- */
- String FILE_PATH="\\" + FILE_NAME;
+ */
+ final String FILE_PATH= TEST_ROOT_DOS_PATH + "\\" + FILE_NAME;
FileOpenParams params = new FileOpenParams(FILE_PATH, FileAction.CreateNotExist, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
try
@@ -656,13 +666,13 @@ public class ContentDiskDriverTest extends TestCase
/**
* Step 2: Now create the file through the node service and open it.
*/
+ logger.debug("Step 2) Open file created by node service");
RetryingTransactionCallback createFileCB = new RetryingTransactionCallback() {
@Override
public Void execute() throws Throwable
{
- NodeRef companyHome = repositoryHelper.getCompanyHome();
- ChildAssociationRef ref = nodeService.createNode(companyHome, ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, FILE_NAME), ContentModel.TYPE_CONTENT);
+ ChildAssociationRef ref = nodeService.createNode(testContext.testDirNodeRef, ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, FILE_NAME), ContentModel.TYPE_CONTENT);
nodeService.setProperty(ref.getChildRef(), ContentModel.PROP_NAME, FILE_NAME);
return null;
}
@@ -672,14 +682,21 @@ public class ContentDiskDriverTest extends TestCase
NetworkFile file = driver.openFile(testSession, testConnection, params);
assertNotNull(file);
- driver.deleteFile(testSession, testConnection, FILE_PATH);
+ //driver.deleteFile(testSession, testConnection, FILE_PATH);
+ // BODGE - there's a dangling transaction that needs getting rid of
+ // Work around for ALF-7674
+ UserTransaction txn = transactionService.getUserTransaction();
+ assertNotNull("transaction leaked", txn);
+ txn.getStatus();
+ txn.rollback();
+
} // testOpenFile
/**
* Unit test of file exists
*/
- public void testFileExists() throws Exception
+ public void DISABLED_testFileExists() throws Exception
{
logger.debug("testFileExists");
ServerConfiguration scfg = new ServerConfiguration("testServer");
@@ -689,21 +706,37 @@ public class ContentDiskDriverTest extends TestCase
TreeConnection testConnection = testServer.getTreeConnection(share);
final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
- String FILE_PATH="\\testFileExists.new";
+ final String FILE_PATH= TEST_ROOT_DOS_PATH + "\\testFileExists.new";
+
+ class TestContext
+ {
+ };
+
+ final TestContext testContext = new TestContext();
+
+ /**
+ * Step 1 : Call FileExists for a directory which does not exist
+ */
+ logger.debug("Step 1, negative test dir does not exist");
+ int status = driver.fileExists(testSession, testConnection, TEST_ROOT_DOS_PATH);
+ assertEquals(status, 0);
/**
- * Step 1 : Call FileExists for a file which does not exist
+ * Step 2 : Call FileExists for a file which does not exist
*/
- int status = driver.fileExists(testSession, testConnection, FILE_PATH);
+ logger.debug("Step 2, negative test file does not exist");
+ status = driver.fileExists(testSession, testConnection, FILE_PATH);
assertEquals(status, 0);
/**
- * Step 2: Create a new file in read/write mode and add some content.
+ * Step 3: Create a new file in read/write mode and add some content.
*/
int openAction = FileAction.CreateNotExist;
FileOpenParams params = new FileOpenParams(FILE_PATH, openAction, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
-
+ FileOpenParams dirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, 0, AccessMode.ReadOnly, FileAttribute.NTDirectory, 0);
+
+ driver.createDirectory(testSession, testConnection, dirParams);
final NetworkFile file = driver.createFile(testSession, testConnection, params);
assertNotNull("file is null", file);
assertFalse("file is read only, should be read-write", file.isReadOnly());
@@ -726,8 +759,9 @@ public class ContentDiskDriverTest extends TestCase
assertEquals(status, 1);
/**
- * Step 3 : Delete the node - check status goes back to 0
+ * Step 4 : Delete the node - check status goes back to 0
*/
+ logger.debug("Step 4, successfully delete node");
driver.deleteFile(testSession, testConnection, FILE_PATH);
status = driver.fileExists(testSession, testConnection, FILE_PATH);
@@ -2708,6 +2742,186 @@ public class ContentDiskDriverTest extends TestCase
}
}
+ /**
+ * Simulates a SaveAs from Word2003
+ * 1. Create new document SAVEAS.DOC, file did not exist
+ * 2. Create -WRDnnnn.TMP file, where 'nnnn' is a 4 digit sequence to make the name unique
+ * 3. Rename SAVEAS.DOC to Backup of SAVEAS.wbk
+ * 4. Rename -WRDnnnn.TMP to SAVEAS.DOC
+ */
+ public void testScenarioMSWord2003SaveAsShuffle() throws Exception
+ {
+ logger.debug("testScenarioMSWord2003SaveShuffle");
+ final String FILE_NAME = "SAVEAS.DOC";
+ final String FILE_OLD_TEMP = "SAVEAS.wbk";
+ final String FILE_NEW_TEMP = "~WRD0002.TMP";
+
+ class TestContext
+ {
+ NetworkFile firstFileHandle;
+ };
+
+ final TestContext testContext = new TestContext();
+
+ final String TEST_DIR = TEST_ROOT_DOS_PATH + "\\testScenarioMSWord2003SaveAsShuffle";
+
+ ServerConfiguration scfg = new ServerConfiguration("testServer");
+ TestServer testServer = new TestServer("testServer", scfg);
+ final SrvSession testSession = new TestSrvSession(666, testServer, "test", "remoteName");
+ DiskSharedDevice share = getDiskSharedDevice();
+ final TreeConnection testConnection = testServer.getTreeConnection(share);
+ final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper();
+
+ /**
+ * Clean up just in case garbage is left from a previous run
+ */
+ RetryingTransactionCallback deleteGarbageFileCB = new RetryingTransactionCallback() {
+
+ @Override
+ public Void execute() throws Throwable
+ {
+ driver.deleteFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME);
+ return null;
+ }
+ };
+
+ /**
+ * Create a file in the test directory
+ */
+
+ try
+ {
+ tran.doInTransaction(deleteGarbageFileCB);
+ }
+ catch (Exception e)
+ {
+ // expect to go here
+ }
+
+ logger.debug("a) create new file");
+ RetryingTransactionCallback createFileCB = new RetryingTransactionCallback() {
+
+ @Override
+ public Void execute() throws Throwable
+ {
+
+ /**
+ * Create the test directory we are going to use
+ */
+ FileOpenParams createRootDirParams = new FileOpenParams(TEST_ROOT_DOS_PATH, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
+ FileOpenParams createDirParams = new FileOpenParams(TEST_DIR, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
+ driver.createDirectory(testSession, testConnection, createRootDirParams);
+ driver.createDirectory(testSession, testConnection, createDirParams);
+
+ /**
+ * Create the file we are going to use
+ */
+ FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NAME, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
+ testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
+ assertNotNull(testContext.firstFileHandle);
+
+ return null;
+ }
+ };
+ tran.doInTransaction(createFileCB, false, true);
+
+ /**
+ * b) Save the new file
+ * Write ContentDiskDriverTest3.doc to the test file,
+ */
+ logger.debug("b) move new file into place");
+ RetryingTransactionCallback writeFileCB = new RetryingTransactionCallback() {
+
+ @Override
+ public Void execute() throws Throwable
+ {
+ FileOpenParams createFileParams = new FileOpenParams(TEST_DIR + "\\" + FILE_NEW_TEMP, 0, AccessMode.ReadWrite, FileAttribute.NTNormal, 0);
+ testContext.firstFileHandle = driver.createFile(testSession, testConnection, createFileParams);
+
+ ClassPathResource fileResource = new ClassPathResource("filesys/ContentDiskDriverTest3.doc");
+ assertNotNull("unable to find test resource filesys/ContentDiskDriverTest3.doc", fileResource);
+
+ byte[] buffer= new byte[1000];
+ InputStream is = fileResource.getInputStream();
+ try
+ {
+ long offset = 0;
+ int i = is.read(buffer, 0, buffer.length);
+ while(i > 0)
+ {
+ testContext.firstFileHandle.writeFile(buffer, i, 0, offset);
+ offset += i;
+ i = is.read(buffer, 0, buffer.length);
+ }
+ }
+ finally
+ {
+ is.close();
+ }
+
+ testContext.firstFileHandle.close();
+
+ return null;
+ }
+ };
+ tran.doInTransaction(writeFileCB, false, true);
+
+ /**
+ * c) rename the old file
+ */
+ logger.debug("c) rename old file");
+ RetryingTransactionCallback renameOldFileCB = new RetryingTransactionCallback() {
+
+ @Override
+ public Void execute() throws Throwable
+ {
+ driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NAME, TEST_DIR + "\\" + FILE_OLD_TEMP);
+ return null;
+ }
+ };
+ tran.doInTransaction(renameOldFileCB, false, true);
+
+ /**
+ * d) Move the new file into place, stuff should get shuffled
+ */
+ logger.debug("d) move new file into place");
+ RetryingTransactionCallback moveNewFileCB = new RetryingTransactionCallback() {
+
+ @Override
+ public Void execute() throws Throwable
+ {
+ driver.renameFile(testSession, testConnection, TEST_DIR + "\\" + FILE_NEW_TEMP, TEST_DIR + "\\" + FILE_NAME);
+ return null;
+ }
+ };
+
+ tran.doInTransaction(moveNewFileCB, false, true);
+
+ logger.debug("e) validate results");
+ /**
+ * Now validate everything is correct
+ */
+ RetryingTransactionCallback validateCB = new RetryingTransactionCallback() {
+
+ @Override
+ public Void execute() throws Throwable
+ {
+ NodeRef shuffledNodeRef = driver.getNodeForPath(testConnection, TEST_DIR + "\\" + FILE_NAME);
+
+ Map props = nodeService.getProperties(shuffledNodeRef);
+
+ ContentData data = (ContentData)props.get(ContentModel.PROP_CONTENT);
+ assertEquals("size is wrong", 26112, data.getSize());
+ assertEquals("mimeType is wrong", "application/msword",data.getMimetype());
+
+ return null;
+ }
+ };
+
+ tran.doInTransaction(validateCB, true, true);
+
+ }
+
/**
* Test server
*/
diff --git a/source/java/org/alfresco/filesys/repo/ContentNetworkFile.java b/source/java/org/alfresco/filesys/repo/ContentNetworkFile.java
index 8ca61be71c..f23157aa75 100644
--- a/source/java/org/alfresco/filesys/repo/ContentNetworkFile.java
+++ b/source/java/org/alfresco/filesys/repo/ContentNetworkFile.java
@@ -18,17 +18,12 @@
*/
package org.alfresco.filesys.repo;
-import java.io.BufferedInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
-import java.io.InputStream;
import java.nio.ByteBuffer;
-import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
-import java.nio.charset.Charset;
import org.alfresco.error.AlfrescoRuntimeException;
-import org.springframework.extensions.surf.util.I18NUtil;
import org.alfresco.jlan.server.SrvSession;
import org.alfresco.jlan.server.filesys.AccessDeniedException;
import org.alfresco.jlan.server.filesys.DiskFullException;
@@ -41,7 +36,6 @@ import org.alfresco.jlan.smb.server.SMBSrvSession;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.AbstractContentReader;
import org.alfresco.repo.content.MimetypeMap;
-import org.alfresco.repo.content.encoding.ContentCharsetFinder;
import org.alfresco.repo.content.filestore.FileContentReader;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
@@ -59,6 +53,7 @@ import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.usage.ContentQuotaException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.springframework.extensions.surf.util.I18NUtil;
/**
* Implementation of the NetworkFile for direct interaction
@@ -419,25 +414,22 @@ public class ContentNetworkFile extends NodeRefNetworkFile
if (modified)
{
NodeRef contentNodeRef = getNodeRef();
+ ContentWriter writer = (ContentWriter)content;
+
// We may be in a retry block, in which case this section will already have executed and channel will be null
if (channel != null)
{
- // Take a guess at the mimetype (if it has not been set by something already)
+ // Do we need the mimetype guessing for us when we're done?
if (content.getMimetype() == null || content.getMimetype().equals(MimetypeMap.MIMETYPE_BINARY) )
{
String filename = (String) nodeService.getProperty(contentNodeRef, ContentModel.PROP_NAME);
- String mimetype = mimetypeService.guessMimetype(filename);
- content.setMimetype(mimetype);
+ writer.guessMimetype(filename);
}
- // Take a guess at the locale
- channel.position(0);
- InputStream is = new BufferedInputStream(Channels.newInputStream(channel));
- ContentCharsetFinder charsetFinder = mimetypeService.getContentCharsetFinder();
- Charset charset = charsetFinder.getCharset(is, content.getMimetype());
- content.setEncoding(charset.name());
-
+
+ // We always want the encoding guessing
+ writer.guessEncoding();
+
// Close the channel
-
channel.close();
channel = null;
}
@@ -449,7 +441,7 @@ public class ContentNetworkFile extends NodeRefNetworkFile
// Update node properties, but only if the binary has changed (ETHREEOH-1861)
- ContentReader postUpdateContentReader = ((ContentWriter) content).getReader();
+ ContentReader postUpdateContentReader = writer.getReader();
RunAsWork getReader = new RunAsWork()
{
diff --git a/source/java/org/alfresco/filesys/repo/desk/package-info.java b/source/java/org/alfresco/filesys/repo/desk/package-info.java
new file mode 100644
index 0000000000..75a92da495
--- /dev/null
+++ b/source/java/org/alfresco/filesys/repo/desk/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Implementation of desk top actions for file system protocols.
+ */
+package org.alfresco.filesys.repo.desk;
diff --git a/source/java/org/alfresco/filesys/util/package-info.java b/source/java/org/alfresco/filesys/util/package-info.java
new file mode 100644
index 0000000000..cb3402f40b
--- /dev/null
+++ b/source/java/org/alfresco/filesys/util/package-info.java
@@ -0,0 +1,8 @@
+/**
+ * Filesystem utilities
+ *
+ * Contains :
+ * CifsMounter to mount and unmount a CIFS filesystem.
+ *
+ */
+package org.alfresco.filesys.util;
diff --git a/source/java/org/alfresco/repo/action/ActionServiceImpl.java b/source/java/org/alfresco/repo/action/ActionServiceImpl.java
index 682d214331..f81252097e 100644
--- a/source/java/org/alfresco/repo/action/ActionServiceImpl.java
+++ b/source/java/org/alfresco/repo/action/ActionServiceImpl.java
@@ -1718,7 +1718,7 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A
*/
public CopyBehaviourCallback getCopyCallback(QName classRef, CopyDetails copyDetails)
{
- return AdctionParameterTypeCopyBehaviourCallback.INSTANCE;
+ return ActionParameterTypeCopyBehaviourCallback.INSTANCE;
}
/**
@@ -1728,9 +1728,9 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A
* @author Derek Hulley
* @since 3.2
*/
- private static class AdctionParameterTypeCopyBehaviourCallback extends DefaultCopyBehaviourCallback
+ private static class ActionParameterTypeCopyBehaviourCallback extends DefaultCopyBehaviourCallback
{
- private static final AdctionParameterTypeCopyBehaviourCallback INSTANCE = new AdctionParameterTypeCopyBehaviourCallback();
+ private static final ActionParameterTypeCopyBehaviourCallback INSTANCE = new ActionParameterTypeCopyBehaviourCallback();
@Override
public Map getCopyProperties(QName classQName, CopyDetails copyDetails,
@@ -1750,7 +1750,7 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A
public void onCopyComplete(QName classRef, NodeRef sourceNodeRef, NodeRef targetNodeRef, boolean copyToNewNode,
Map copyMap)
{
- AdctionParameterTypeCopyBehaviourCallback.INSTANCE.repointNodeRefs(sourceNodeRef, targetNodeRef,
+ ActionParameterTypeCopyBehaviourCallback.INSTANCE.repointNodeRefs(sourceNodeRef, targetNodeRef,
ActionModel.PROP_PARAMETER_VALUE, copyMap, nodeService);
}
}
diff --git a/source/java/org/alfresco/repo/action/executer/ImporterActionExecuter.java b/source/java/org/alfresco/repo/action/executer/ImporterActionExecuter.java
index 24aa910af5..be6be7b847 100644
--- a/source/java/org/alfresco/repo/action/executer/ImporterActionExecuter.java
+++ b/source/java/org/alfresco/repo/action/executer/ImporterActionExecuter.java
@@ -49,7 +49,6 @@ import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
-import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.view.ImporterService;
@@ -90,11 +89,6 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
*/
private ContentService contentService;
- /**
- * The mimetype service
- */
- private MimetypeService mimetypeService;
-
/**
* The file folder service
*/
@@ -130,16 +124,6 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
this.contentService = contentService;
}
- /**
- * Sets the MimetypeService to use
- *
- * @param mimetypeService The MimetypeService
- */
- public void setMimetypeService(MimetypeService mimetypeService)
- {
- this.mimetypeService = mimetypeService;
- }
-
/**
* Sets the FileFolderService to use
*
@@ -263,7 +247,7 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
// push the content of the file into the node
InputStream contentStream = new BufferedInputStream(new FileInputStream(file), BUFFER_SIZE);
ContentWriter writer = this.contentService.getWriter(fileRef, ContentModel.PROP_CONTENT, true);
- writer.setMimetype(this.mimetypeService.guessMimetype(fileName));
+ writer.guessMimetype(fileName);
writer.putContent(contentStream);
}
else
diff --git a/source/java/org/alfresco/repo/action/executer/TransformActionExecuterTest.java b/source/java/org/alfresco/repo/action/executer/TransformActionExecuterTest.java
index 50d013943d..1d519f8c0c 100644
--- a/source/java/org/alfresco/repo/action/executer/TransformActionExecuterTest.java
+++ b/source/java/org/alfresco/repo/action/executer/TransformActionExecuterTest.java
@@ -97,15 +97,16 @@ class DummyMimetypeService implements MimetypeService
{
private final String result;
public DummyMimetypeService(String result) { this.result = result; }
- public ContentCharsetFinder getContentCharsetFinder() { return null; }
- public Map getDisplaysByExtension() { return null; }
- public Map getDisplaysByMimetype() { return null; }
- public String getExtension(String mimetype) { return result; }
- public Map getExtensionsByMimetype() { return null; }
- public String getMimetype(String extension) { return null; }
- public List getMimetypes() { return null; }
- public Map getMimetypesByExtension() { return null; }
- public String guessMimetype(String filename) { return null; }
- public boolean isText(String mimetype) { return false;}
- public String getMimetypeIfNotMatches(ContentReader reader) { return null; }
+ public ContentCharsetFinder getContentCharsetFinder() { return null; }
+ public Map getDisplaysByExtension() { return null; }
+ public Map getDisplaysByMimetype() { return null; }
+ public String getExtension(String mimetype) { return result;}
+ public Map getExtensionsByMimetype() { return null; }
+ public String getMimetype(String extension) { return null; }
+ public List getMimetypes() { return null; }
+ public Map getMimetypesByExtension() { return null; }
+ public String guessMimetype(String filename) { return null; }
+ public String guessMimetype(String filename,ContentReader reader){ return null; }
+ public boolean isText(String mimetype) { return false; }
+ public String getMimetypeIfNotMatches(ContentReader reader) { return null; }
}
\ No newline at end of file
diff --git a/source/java/org/alfresco/repo/content/AbstractContentWriter.java b/source/java/org/alfresco/repo/content/AbstractContentWriter.java
index 183dcc1733..d1de7af0d6 100644
--- a/source/java/org/alfresco/repo/content/AbstractContentWriter.java
+++ b/source/java/org/alfresco/repo/content/AbstractContentWriter.java
@@ -29,16 +29,19 @@ import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
+import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import org.alfresco.error.AlfrescoRuntimeException;
+import org.alfresco.repo.content.encoding.ContentCharsetFinder;
import org.alfresco.repo.content.filestore.FileContentWriter;
import org.alfresco.service.cmr.repository.ContentAccessor;
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.ContentWriter;
+import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.util.TempFileProvider;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -62,6 +65,8 @@ public abstract class AbstractContentWriter extends AbstractContentAccessor impl
private List listeners;
private WritableByteChannel channel;
private ContentReader existingContentReader;
+ private MimetypeService mimetypeService;
+ private DoGuessingOnCloseListener guessingOnCloseListener;
/**
* @param contentUrl the content URL
@@ -73,6 +78,21 @@ public abstract class AbstractContentWriter extends AbstractContentAccessor impl
this.existingContentReader = existingContentReader;
listeners = new ArrayList(2);
+
+ // We always register our own listener as the first one
+ // This allows us to perform any guessing (if needed) before
+ // the normal listeners kick in and eg write things to the DB
+ guessingOnCloseListener = new DoGuessingOnCloseListener();
+ listeners.add(guessingOnCloseListener);
+ }
+
+ /**
+ * Supplies the Mimetype Service to be used when guessing
+ * encoding and mimetype information.
+ */
+ public void setMimetypeService(MimetypeService mimetypeService)
+ {
+ this.mimetypeService = mimetypeService;
}
/**
@@ -454,7 +474,19 @@ public abstract class AbstractContentWriter extends AbstractContentAccessor impl
{
// attempt to use the correct encoding
String encoding = getEncoding();
- byte[] bytes = (encoding == null) ? content.getBytes() : content.getBytes(encoding);
+ byte[] bytes;
+ if(encoding == null)
+ {
+ // Use the system default, and record what that was
+ bytes = content.getBytes();
+ setEncoding( System.getProperty("file.encoding") );
+ }
+ else
+ {
+ // Use the encoding that they specified
+ bytes = content.getBytes(encoding);
+ }
+
// get the stream
OutputStream os = getContentOutputStream();
ByteArrayInputStream is = new ByteArrayInputStream(bytes);
@@ -469,4 +501,108 @@ public abstract class AbstractContentWriter extends AbstractContentAccessor impl
e);
}
}
+
+ /**
+ * When the content has been written, attempt to guess
+ * the encoding of it.
+ *
+ * @see ContentWriter#guessEncoding()
+ */
+ public void guessEncoding()
+ {
+ if (mimetypeService == null)
+ {
+ logger.warn("MimetypeService not supplied, but required for content guessing");
+ return;
+ }
+
+ if(isClosed())
+ {
+ // Content written, can do it now
+ doGuessEncoding();
+ }
+ else
+ {
+ // Content not yet written, wait for the
+ // data to be written before doing so
+ guessingOnCloseListener.guessEncoding = true;
+ }
+ }
+ private void doGuessEncoding()
+ {
+ ContentCharsetFinder charsetFinder = mimetypeService.getContentCharsetFinder();
+
+ ContentReader reader = getReader();
+ InputStream is = reader.getContentInputStream();
+ Charset charset = charsetFinder.getCharset(is, getMimetype());
+ try
+ {
+ is.close();
+ }
+ catch(IOException e)
+ {}
+
+ setEncoding(charset.name());
+ }
+
+ /**
+ * When the content has been written, attempt to guess
+ * the mimetype of it, using the filename and contents.
+ *
+ * @see ContentWriter#guessMimetype(String)
+ */
+ public void guessMimetype(String filename)
+ {
+ if (mimetypeService == null)
+ {
+ logger.warn("MimetypeService not supplied, but required for content guessing");
+ return;
+ }
+
+
+ if(isClosed())
+ {
+ // Content written, can do it now
+ doGuessMimetype(filename);
+ }
+ else
+ {
+ // Content not yet written, wait for the
+ // data to be written before doing so
+ guessingOnCloseListener.guessMimetype = true;
+ guessingOnCloseListener.filename = filename;
+ }
+ }
+ private void doGuessMimetype(String filename)
+ {
+ String mimetype = mimetypeService.guessMimetype(
+ filename, getReader()
+ );
+ setMimetype(mimetype);
+ }
+
+ /**
+ * Our own listener that is always the first on the list,
+ * which lets us perform guessing operations when the
+ * content has been written.
+ */
+ private class DoGuessingOnCloseListener implements ContentStreamListener
+ {
+ private boolean guessEncoding = false;
+ private boolean guessMimetype = false;
+ private String filename = null;
+
+ @Override
+ public void contentStreamClosed() throws ContentIOException
+ {
+ if(guessMimetype)
+ {
+ doGuessMimetype(filename);
+ }
+ if(guessEncoding)
+ {
+ doGuessEncoding();
+ }
+ }
+ }
}
diff --git a/source/java/org/alfresco/repo/content/ContentServiceImpl.java b/source/java/org/alfresco/repo/content/ContentServiceImpl.java
index 1937889e35..b17caba098 100644
--- a/source/java/org/alfresco/repo/content/ContentServiceImpl.java
+++ b/source/java/org/alfresco/repo/content/ContentServiceImpl.java
@@ -50,6 +50,7 @@ import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
+import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NoTransformerException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
@@ -85,6 +86,7 @@ public class ContentServiceImpl implements ContentService, ApplicationContextAwa
private DictionaryService dictionaryService;
private NodeService nodeService;
private AVMService avmService;
+ private MimetypeService mimetypeService;
private RetryingTransactionHelper transactionHelper;
private ApplicationContext applicationContext;
@@ -127,6 +129,11 @@ public class ContentServiceImpl implements ContentService, ApplicationContextAwa
this.nodeService = nodeService;
}
+ public void setMimetypeService(MimetypeService mimetypeService)
+ {
+ this.mimetypeService = mimetypeService;
+ }
+
public void setTransformerRegistry(ContentTransformerRegistry transformerRegistry)
{
this.transformerRegistry = transformerRegistry;
@@ -492,6 +499,12 @@ public class ContentServiceImpl implements ContentService, ApplicationContextAwa
}
+ // supply the writer with a copy of the mimetype service if needed
+ if (writer instanceof AbstractContentWriter)
+ {
+ ((AbstractContentWriter)writer).setMimetypeService(mimetypeService);
+ }
+
// give back to the client
return writer;
}
diff --git a/source/java/org/alfresco/repo/content/MimetypeMapContentTest.java b/source/java/org/alfresco/repo/content/MimetypeMapContentTest.java
new file mode 100644
index 0000000000..d8e556b6d1
--- /dev/null
+++ b/source/java/org/alfresco/repo/content/MimetypeMapContentTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco 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 Alfresco. If not, see .
+ */
+package org.alfresco.repo.content;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.net.URL;
+
+import junit.framework.TestCase;
+
+import org.alfresco.repo.content.filestore.FileContentReader;
+import org.alfresco.service.cmr.repository.ContentReader;
+import org.alfresco.service.cmr.repository.MimetypeService;
+import org.alfresco.util.DataModelTestApplicationContextHelper;
+import org.apache.poi.util.IOUtils;
+import org.springframework.context.ApplicationContext;
+
+/**
+ * Content specific tests for MimeTypeMap
+ *
+ * @see org.alfresco.repo.content.MimetypeMap
+ * @see org.alfresco.repo.content.MimetypeMapTest
+ */
+public class MimetypeMapContentTest extends TestCase
+{
+ private static ApplicationContext ctx = DataModelTestApplicationContextHelper.getApplicationContext();
+
+ private MimetypeService mimetypeService;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ mimetypeService = (MimetypeService)ctx.getBean("mimetypeService");
+ }
+
+ public void testGuessMimetypeForFile() throws Exception
+ {
+ // Correct ones
+ assertEquals(
+ "application/msword",
+ mimetypeService.guessMimetype("something.doc", openQuickTestFile("quick.doc"))
+ );
+ assertEquals(
+ "application/msword",
+ mimetypeService.guessMimetype("SOMETHING.DOC", openQuickTestFile("quick.doc"))
+ );
+
+ // Incorrect ones, Tika spots the mistake
+ assertEquals(
+ "application/msword",
+ mimetypeService.guessMimetype("something.pdf", openQuickTestFile("quick.doc"))
+ );
+ assertEquals(
+ "application/pdf",
+ mimetypeService.guessMimetype("something.doc", openQuickTestFile("quick.pdf"))
+ );
+
+ // Ones where we use a different mimetype to the canonical one
+ assertEquals(
+ "image/bmp", // Officially image/x-ms-bmp
+ mimetypeService.guessMimetype("image.bmp", openQuickTestFile("quick.bmp"))
+ );
+
+
+ // Where the file is corrupted
+ File tmp = File.createTempFile("alfresco", ".tmp");
+ ContentReader reader = openQuickTestFile("quick.doc");
+ InputStream inp = reader.getContentInputStream();
+ byte[] trunc = new byte[512+256];
+ IOUtils.readFully(inp, trunc);
+ inp.close();
+ FileOutputStream out = new FileOutputStream(tmp);
+ out.write(trunc);
+ out.close();
+ ContentReader truncReader = new FileContentReader(tmp);
+
+ // Because the file is truncated, Tika won't be able to process the contents
+ // of the OLE2 structure
+ // So, it'll fall back to just OLE2, but it won't fail
+ assertEquals(
+ "application/x-tika-msoffice",
+ mimetypeService.guessMimetype("something.doc", truncReader)
+ );
+ }
+
+ private ContentReader openQuickTestFile(String filename)
+ {
+ URL url = getClass().getClassLoader().getResource("quick/" + filename);
+ File file = new File(url.getFile());
+ return new FileContentReader(file);
+ }
+}
diff --git a/source/java/org/alfresco/repo/content/filestore/FileContentReader.java b/source/java/org/alfresco/repo/content/filestore/FileContentReader.java
index 8a49c57b45..c49dd394d1 100644
--- a/source/java/org/alfresco/repo/content/filestore/FileContentReader.java
+++ b/source/java/org/alfresco/repo/content/filestore/FileContentReader.java
@@ -45,6 +45,7 @@ import org.apache.commons.logging.LogFactory;
* @author Derek Hulley
*/
public class FileContentReader extends AbstractContentReader
+ implements org.alfresco.service.cmr.repository.FileContentReader
{
/**
* message key for missing content. Parameters are
@@ -147,6 +148,9 @@ public class FileContentReader extends AbstractContentReader
return file;
}
+ /**
+ * @return Whether the file exists or not
+ */
public boolean exists()
{
return file.exists();
diff --git a/source/java/org/alfresco/repo/content/transform/ArchiveContentTransformer.java b/source/java/org/alfresco/repo/content/transform/ArchiveContentTransformer.java
index 4f1f5a2d7f..8c8697520c 100644
--- a/source/java/org/alfresco/repo/content/transform/ArchiveContentTransformer.java
+++ b/source/java/org/alfresco/repo/content/transform/ArchiveContentTransformer.java
@@ -23,6 +23,7 @@ import java.util.ArrayList;
import org.alfresco.service.cmr.repository.TransformationOptions;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.tika.config.TikaConfig;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.mime.MediaType;
import org.apache.tika.parser.AutoDetectParser;
@@ -50,22 +51,11 @@ public class ArchiveContentTransformer extends TikaPoweredContentTransformer
private static Log logger = LogFactory.getLog(ArchiveContentTransformer.class);
private boolean includeContents = false;
- public void setIncludeContents(String includeContents)
- {
- // Spring really ought to be able to handle
- // setting a boolean that might still be
- // ${foo} (i.e. not overridden in a property).
- // As we can't do that with spring, we do it...
- this.includeContents = false;
- if(includeContents != null && includeContents.length() > 0)
- {
- this.includeContents = TransformationOptions.relaxedBooleanTypeConverter.convert(includeContents).booleanValue();
- }
- }
+ private TikaConfig tikaConfig;
/**
* We support all the archive mimetypes that the Tika
- * office parser can handle
+ * package parser can handle
*/
public static ArrayList SUPPORTED_MIMETYPES;
static {
@@ -81,6 +71,29 @@ public class ArchiveContentTransformer extends TikaPoweredContentTransformer
super(SUPPORTED_MIMETYPES);
}
+ /**
+ * Injects the TikaConfig to use
+ *
+ * @param tikaConfig The Tika Config to use
+ */
+ public void setTikaConfig(TikaConfig tikaConfig)
+ {
+ this.tikaConfig = tikaConfig;
+ }
+
+ public void setIncludeContents(String includeContents)
+ {
+ // Spring really ought to be able to handle
+ // setting a boolean that might still be
+ // ${foo} (i.e. not overridden in a property).
+ // As we can't do that with spring, we do it...
+ this.includeContents = false;
+ if(includeContents != null && includeContents.length() > 0)
+ {
+ this.includeContents = TransformationOptions.relaxedBooleanTypeConverter.convert(includeContents).booleanValue();
+ }
+ }
+
@Override
protected Parser getParser() {
return new PackageParser();
@@ -96,9 +109,15 @@ public class ArchiveContentTransformer extends TikaPoweredContentTransformer
{
recurse = options.getIncludeEmbedded();
}
+
if(recurse)
{
- context.set(Parser.class, new AutoDetectParser());
+ // Use an auto detect parser to handle the contents
+ if(tikaConfig == null)
+ {
+ tikaConfig = TikaConfig.getDefaultConfig();
+ }
+ context.set(Parser.class, new AutoDetectParser(tikaConfig));
}
return context;
diff --git a/source/java/org/alfresco/repo/content/transform/TextMiningContentTransformer.java b/source/java/org/alfresco/repo/content/transform/TextMiningContentTransformer.java
index 5a415cf587..04c8211db9 100644
--- a/source/java/org/alfresco/repo/content/transform/TextMiningContentTransformer.java
+++ b/source/java/org/alfresco/repo/content/transform/TextMiningContentTransformer.java
@@ -18,94 +18,27 @@
*/
package org.alfresco.repo.content.transform;
-import java.io.IOException;
-import java.io.InputStream;
-
import org.alfresco.repo.content.MimetypeMap;
-import org.alfresco.service.cmr.repository.ContentReader;
-import org.alfresco.service.cmr.repository.ContentWriter;
-import org.alfresco.service.cmr.repository.TransformationOptions;
-import org.apache.poi.POIOLE2TextExtractor;
-import org.apache.poi.hwpf.OldWordFileFormatException;
-import org.apache.poi.hwpf.extractor.Word6Extractor;
-import org.apache.poi.hwpf.extractor.WordExtractor;
-import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.tika.parser.Parser;
+import org.apache.tika.parser.microsoft.OfficeParser;
/**
* This badly named transformer turns Microsoft Word documents
- * (Word 6, 95, 97, 2000, 2003) into plain text.
- *
- * Doesn't currently use {@link http://tika.apache.org/ Apache Tika} to
- * do this, pending TIKA-408. When Apache POI 3.7 beta 2 has been
- * released, we can switch to Tika and then handle Word 6,
- * Word 95, Word 97, 2000, 2003, 2007 and 2010 formats.
- *
- * TODO Switch to Tika in November 2010 once 3.4 is out
+ * (Word 6, 95, 97, 2000, 2003) into plain text, using Apache Tika.
*
* @author Nick Burch
*/
-public class TextMiningContentTransformer extends AbstractContentTransformer2
+public class TextMiningContentTransformer extends TikaPoweredContentTransformer
{
public TextMiningContentTransformer()
- {
- }
-
- /**
- * Currently the only transformation performed is that of text extraction from Word documents.
- */
- public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options)
- {
- if (!MimetypeMap.MIMETYPE_WORD.equals(sourceMimetype) ||
- !MimetypeMap.MIMETYPE_TEXT_PLAIN.equals(targetMimetype))
- {
- // only support DOC -> Text
- return false;
- }
- else
- {
- return true;
- }
+ {
+ super(new String[] {
+ MimetypeMap.MIMETYPE_WORD
+ });
}
- public void transformInternal(ContentReader reader, ContentWriter writer, TransformationOptions options)
- throws Exception
- {
- POIOLE2TextExtractor extractor = null;
- InputStream is = null;
- String text = null;
- try
- {
- is = reader.getContentInputStream();
- POIFSFileSystem fs = new POIFSFileSystem(is);
- try {
- extractor = new WordExtractor(fs);
- } catch(OldWordFileFormatException e) {
- extractor = new Word6Extractor(fs);
- }
- text = extractor.getText();
- }
- catch (IOException e)
- {
- // check if this is an error caused by the fact that the .doc is in fact
- // one of Word's temp non-documents
- if (e.getMessage().contains("Unable to read entire header"))
- {
- // just assign an empty string
- text = "";
- }
- else
- {
- throw e;
- }
- }
- finally
- {
- if (is != null)
- {
- is.close();
- }
- }
- // dump the text out. This will close the writer automatically.
- writer.putContent(text);
+ @Override
+ protected Parser getParser() {
+ return new OfficeParser();
}
}
diff --git a/source/java/org/alfresco/repo/content/transform/TikaAutoContentTransformer.java b/source/java/org/alfresco/repo/content/transform/TikaAutoContentTransformer.java
index 20e81f4921..492381c98b 100644
--- a/source/java/org/alfresco/repo/content/transform/TikaAutoContentTransformer.java
+++ b/source/java/org/alfresco/repo/content/transform/TikaAutoContentTransformer.java
@@ -20,6 +20,7 @@ package org.alfresco.repo.content.transform;
import java.util.ArrayList;
+import org.apache.tika.config.TikaConfig;
import org.apache.tika.mime.MediaType;
import org.apache.tika.parser.AutoDetectParser;
import org.apache.tika.parser.Parser;
@@ -37,6 +38,9 @@ import org.apache.tika.parser.Parser;
*/
public class TikaAutoContentTransformer extends TikaPoweredContentTransformer
{
+ private static AutoDetectParser parser;
+ private static TikaConfig config;
+
/**
* We support all the mimetypes that the Tika
* auto-detect parser can handle, except for
@@ -44,10 +48,13 @@ public class TikaAutoContentTransformer extends TikaPoweredContentTransformer
* make much sense
*/
public static ArrayList SUPPORTED_MIMETYPES;
- static {
+ private static ArrayList buildMimeTypes(TikaConfig tikaConfig)
+ {
+ config = tikaConfig;
+ parser = new AutoDetectParser(config);
+
SUPPORTED_MIMETYPES = new ArrayList();
- AutoDetectParser p = new AutoDetectParser();
- for(MediaType mt : p.getParsers().keySet()) {
+ for(MediaType mt : parser.getParsers().keySet()) {
if(mt.toString().startsWith("application/vnd.oasis.opendocument.formula")) {
// TODO Tika support for quick.odf, mimetype=application/vnd.oasis.opendocument.formula
// TODO Tika support for quick.otf, mimetype=application/vnd.oasis.opendocument.formula-template
@@ -85,11 +92,12 @@ public class TikaAutoContentTransformer extends TikaPoweredContentTransformer
SUPPORTED_MIMETYPES.add( mt.toString() );
}
}
+ return SUPPORTED_MIMETYPES;
}
- public TikaAutoContentTransformer()
+ public TikaAutoContentTransformer(TikaConfig tikaConfig)
{
- super(SUPPORTED_MIMETYPES);
+ super( buildMimeTypes(tikaConfig) );
}
/**
@@ -100,6 +108,6 @@ public class TikaAutoContentTransformer extends TikaPoweredContentTransformer
*/
protected Parser getParser()
{
- return new AutoDetectParser();
+ return parser;
}
}
diff --git a/source/java/org/alfresco/repo/content/transform/TikaAutoContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/TikaAutoContentTransformerTest.java
index 72c5e098c1..076c6bb6e0 100644
--- a/source/java/org/alfresco/repo/content/transform/TikaAutoContentTransformerTest.java
+++ b/source/java/org/alfresco/repo/content/transform/TikaAutoContentTransformerTest.java
@@ -20,6 +20,7 @@ package org.alfresco.repo.content.transform;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.service.cmr.repository.TransformationOptions;
+import org.apache.tika.config.TikaConfig;
/**
* Most of the work for testing the Tika Auto-Detect transformer
@@ -38,7 +39,8 @@ public class TikaAutoContentTransformerTest extends TikaPoweredContentTransforme
{
super.setUp();
- transformer = new TikaAutoContentTransformer();
+ TikaConfig config = (TikaConfig)ctx.getBean("tikaConfig");
+ transformer = new TikaAutoContentTransformer( config );
}
/**
diff --git a/source/java/org/alfresco/repo/content/transform/TikaPoweredContainerExtractor.java b/source/java/org/alfresco/repo/content/transform/TikaPoweredContainerExtractor.java
index 9ad65aa033..d57e4feb85 100644
--- a/source/java/org/alfresco/repo/content/transform/TikaPoweredContainerExtractor.java
+++ b/source/java/org/alfresco/repo/content/transform/TikaPoweredContainerExtractor.java
@@ -79,18 +79,10 @@ public class TikaPoweredContainerExtractor
private NodeService nodeService;
private ContentService contentService;
+ private TikaConfig config;
private AutoDetectParser parser;
private Detector detector;
- public TikaPoweredContainerExtractor()
- {
- TikaConfig config = TikaConfig.getDefaultConfig();
- detector = new ContainerAwareDetector(
- config.getMimeRepository()
- );
- parser = new AutoDetectParser(detector);
- }
-
/**
* Injects the nodeService bean.
*
@@ -110,6 +102,22 @@ public class TikaPoweredContainerExtractor
{
this.contentService = contentService;
}
+
+ /**
+ * Injects the TikaConfig to use
+ *
+ * @param tikaConfig The Tika Config to use
+ */
+ public void setTikaConfig(TikaConfig tikaConfig)
+ {
+ this.config = tikaConfig;
+
+ // Setup the detector and parser
+ detector = new ContainerAwareDetector(
+ config.getMimeRepository()
+ );
+ parser = new AutoDetectParser(detector);
+ }
/**
* Extracts out all the entries from the container
@@ -277,6 +285,9 @@ public class TikaPoweredContainerExtractor
+
+
+