diff --git a/rtd_cina/.classpath b/rtd_cina/.classpath index 9d6665255323a54e85bbdf8cdc08414762aca620..00a94818cb2c8907673a697cf50f37d98e0f048f 100644 --- a/rtd_cina/.classpath +++ b/rtd_cina/.classpath @@ -15,5 +15,6 @@ <classpathentry kind="lib" path="/libraries/log4j/log4j.jar" sourcepath="/libraries/log4j/src.zip"/> <classpathentry kind="lib" path="/libraries/mail/mail.jar"/> <classpathentry kind="lib" path="/libraries/gwt1.7/gwt-isserializable.jar"/> + <classpathentry kind="lib" path="/libraries/activation/activation.jar"/> <classpathentry kind="output" path="targets/classes"/> </classpath> diff --git a/rtd_cina/source/java/ch/systemsx/cisd/cina/dss/StorageProcessor.java b/rtd_cina/source/java/ch/systemsx/cisd/cina/dss/StorageProcessor.java index 1c319511cc7e7e8c88e372b4d6e9086fb83e5514..2be388247f5f731cb3885fbd73962bfc9a31128c 100644 --- a/rtd_cina/source/java/ch/systemsx/cisd/cina/dss/StorageProcessor.java +++ b/rtd_cina/source/java/ch/systemsx/cisd/cina/dss/StorageProcessor.java @@ -21,6 +21,7 @@ import java.util.Properties; import ch.systemsx.cisd.cina.dss.info.EntityRegistrationSuccessEmail; import ch.systemsx.cisd.common.mail.IMailClient; +import ch.systemsx.cisd.common.mail.MailClient; import ch.systemsx.cisd.etlserver.AbstractDelegatingStorageProcessor; import ch.systemsx.cisd.etlserver.IStorageProcessor; import ch.systemsx.cisd.etlserver.ITypeExtractor; @@ -74,8 +75,21 @@ public class StorageProcessor extends AbstractDelegatingStorageProcessor emailAddress = defaultEmailAddress; } - mailClient.sendMessage(successEmail.getSubject(), successEmail.getContent(), null, null, - emailAddress); + // WORKAROUND: The IMailClient interface is used in many places. I added the + // sendMessageWithAttachment method to the MailClient class, but I don't want to make a + // large, global change to introduce the method into the interface, so I do an instanceof + // test here. + if (mailClient instanceof MailClient) + { + ((MailClient) mailClient).sendMessageWithAttachment(successEmail.getSubject(), + successEmail.getContentMimeText(), successEmail + .getContentMimeAttachmentFileName(), successEmail + .getContentMimeAttachmentContent(), null, null, emailAddress); + } else + { + mailClient.sendMessage(successEmail.getSubject(), successEmail.getContentTextOnly(), + null, null, emailAddress); + } return answer; } diff --git a/rtd_cina/source/java/ch/systemsx/cisd/cina/dss/info/EntityRegistrationSuccessEmail.java b/rtd_cina/source/java/ch/systemsx/cisd/cina/dss/info/EntityRegistrationSuccessEmail.java index ace867bee77de33f725ac127aa4b5120167f1d57..c1ee26a570583fe5c17242068399cc1c2d19e835 100644 --- a/rtd_cina/source/java/ch/systemsx/cisd/cina/dss/info/EntityRegistrationSuccessEmail.java +++ b/rtd_cina/source/java/ch/systemsx/cisd/cina/dss/info/EntityRegistrationSuccessEmail.java @@ -18,6 +18,8 @@ package ch.systemsx.cisd.cina.dss.info; import java.io.File; +import javax.activation.DataHandler; + import ch.systemsx.cisd.cina.dss.info.FolderOracle.FolderType; import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation; @@ -29,6 +31,8 @@ import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation; */ public class EntityRegistrationSuccessEmail { + private static final String MARKER_FILE_MIME_TYPE = "application/octet-stream"; + private final DataSetInformation dataSetInformation; private final EntityEmailDetails entityEmailDetails; @@ -63,11 +67,17 @@ public class EntityRegistrationSuccessEmail } } + /** + * Return true if the incoming data set requires that an email be sent on registration. + */ public boolean shouldSendEmail() { return entityEmailDetails.shouldSendEmail(); } + /** + * Return the subject of the email + */ public String getSubject() { StringBuffer subject = new StringBuffer(); @@ -79,7 +89,11 @@ public class EntityRegistrationSuccessEmail return subject.toString(); } - public String getContent() + /** + * Return the body of the email for a text-only (no attachments) email. Used if the mail client + * does no support sending attachments. + */ + public String getContentTextOnly() { StringBuffer content = new StringBuffer(); entityEmailDetails.appendEntityName(content); @@ -95,6 +109,40 @@ public class EntityRegistrationSuccessEmail return content.toString(); } + /** + * Return the body of the email for a MIME email. In a MIME email, the marker file is sent as a + * file attachment, not part of the text body of the email. + */ + public String getContentMimeText() + { + StringBuffer content = new StringBuffer(); + entityEmailDetails.appendEntityName(content); + content.append(" was successfully registered. Use the attached metadata file to register "); + entityEmailDetails.appendFollowOnEntityName(content); + + return content.toString(); + } + + /** + * Return the file name of the MIME file attachment. + */ + public String getContentMimeAttachmentFileName() + { + StringBuffer content = new StringBuffer(); + entityEmailDetails.appendMetadataFileName(content); + + return content.toString(); + } + + public DataHandler getContentMimeAttachmentContent() + { + StringBuffer content = new StringBuffer(); + entityEmailDetails.appendMetadataFileContent(content); + DataHandler attachment = new DataHandler(content.toString(), MARKER_FILE_MIME_TYPE); + + return attachment; + } + private abstract class EntityEmailDetails { boolean shouldSendEmail() diff --git a/rtd_cina/sourceTest/java/ch/systemsx/cisd/cina/dss/MockDefaultStorageProcessor.java b/rtd_cina/sourceTest/java/ch/systemsx/cisd/cina/dss/MockDefaultStorageProcessor.java new file mode 100644 index 0000000000000000000000000000000000000000..b64fae7dfae66340690a1d800061358397addcea --- /dev/null +++ b/rtd_cina/sourceTest/java/ch/systemsx/cisd/cina/dss/MockDefaultStorageProcessor.java @@ -0,0 +1,62 @@ +/* + * Copyright 2010 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.cina.dss; + +import java.io.File; +import java.util.Properties; + +import ch.systemsx.cisd.common.mail.IMailClient; +import ch.systemsx.cisd.etlserver.AbstractStorageProcessor; +import ch.systemsx.cisd.etlserver.ITypeExtractor; +import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation; +import ch.systemsx.cisd.openbis.generic.shared.dto.StorageFormat; + +public class MockDefaultStorageProcessor extends AbstractStorageProcessor +{ + + public MockDefaultStorageProcessor(final Properties properties) + { + super(properties); + } + + public StorageFormat getStorageFormat() + { + System.err.println("getStorageFormat"); + return StorageFormat.PROPRIETARY; + } + + public UnstoreDataAction rollback(File incomingDataSetDirectory, File storedDataDirectory, + Throwable exception) + { + System.err.println("rollback"); + return null; + } + + public File storeData(DataSetInformation dataSetInformation, ITypeExtractor typeExtractor, + IMailClient mailClient, File incomingDataSetDirectory, File rootDir) + { + System.err.println("storeData"); + return null; + } + + public File tryGetProprietaryData(File storedDataDirectory) + { + System.err.println("tryGetProprietaryData"); + return null; + } + +} \ No newline at end of file diff --git a/rtd_cina/sourceTest/java/ch/systemsx/cisd/cina/dss/StorageProcessorTest.java b/rtd_cina/sourceTest/java/ch/systemsx/cisd/cina/dss/StorageProcessorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..21e84af08057a71e2675e845dd1877fda626fb33 --- /dev/null +++ b/rtd_cina/sourceTest/java/ch/systemsx/cisd/cina/dss/StorageProcessorTest.java @@ -0,0 +1,169 @@ +/* + * Copyright 2010 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.cina.dss; + +import java.io.File; +import java.io.IOException; +import java.util.Properties; + +import org.jmock.Expectations; +import org.jmock.Mockery; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import ch.systemsx.cisd.base.tests.AbstractFileSystemTestCase; +import ch.systemsx.cisd.cina.dss.info.CinaDataSetInfoExtractor; +import ch.systemsx.cisd.cina.dss.info.CinaTypeExtractor; +import ch.systemsx.cisd.common.filesystem.FileUtilities; +import ch.systemsx.cisd.common.mail.IMailClient; +import ch.systemsx.cisd.common.mail.MailClient; +import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService; +import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewExperiment; +import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifier; + +/** + * @author Chandrasekhar Ramakrishnan + */ +public class StorageProcessorTest extends AbstractFileSystemTestCase +{ + Mockery context; + + IEncapsulatedOpenBISService openbisService; + + CinaDataSetInfoExtractor extractor; + + CinaTypeExtractor typeExtractor; + + StorageProcessor storageProcessor; + + IMailClient mailClient; + + File rootDir; + + File emailDir; + + private void initializeDSSInfrastructure() + { + context = new Mockery(); + openbisService = context.mock(IEncapsulatedOpenBISService.class); + extractor = new CinaDataSetInfoExtractor(new Properties()); + typeExtractor = new CinaTypeExtractor(new Properties()); + rootDir = new File("sourceTest/java/ch/systemsx/cisd/cina/dss/info/"); + } + + private void initializeMailClient() + { + String emailFolderPath = workingDirectory.getPath() + "/emails"; + mailClient = new MailClient("sender", "file://" + emailFolderPath); + emailDir = new File(emailFolderPath); + } + + private void initializeStorageProcessor() + { + final Properties props = new Properties(); + props.setProperty("data-store-server-code", "DSS1"); + // Don't use this + // props.setProperty("data-folder", "targets/playground/data") ; + props.setProperty("storeroot-dir", "store"); + // workingDirectory + props.setProperty("mail.smtp.host", emailDir.getPath()); + props.setProperty("mail.from", "datastore_server@localhost"); + props.setProperty("processor", "ch.systemsx.cisd.cina.dss.MockDefaultStorageProcessor"); + storageProcessor = new StorageProcessor(props); + } + + @Override + @BeforeMethod + public void setUp() throws IOException + { + // Override setUp and call super first to make sure the working directory has been created + super.setUp(); + + // create openbis, extractor, other necessary infrastructure + initializeDSSInfrastructure(); + + initializeMailClient(); + + initializeStorageProcessor(); + } + + @AfterMethod + public void afterMethod() + { + // To following line of code should also be called at the end of each test method. + // Otherwise one do not known which test failed. + context.assertIsSatisfied(); + } + + @Test + public void testRegisterExperiment() + { + // set up the expectations + context.checking(new Expectations() + { + { + one(openbisService).tryToGetExperiment(with(any(ExperimentIdentifier.class))); + will(returnValue(null)); + one(openbisService).registerExperiment(with(any(NewExperiment.class))); + } + }); + + // "store" the data set + doStoreData(new File( + "sourceTest/java/ch/systemsx/cisd/cina/dss/info/experiment-data-folder")); + + // Check the email + assert emailDir.exists(); + assert emailDir.isDirectory(); + File[] files = emailDir.listFiles(); + assertEquals(1, files.length); + assertEquals("email", files[0].getName()); + String fileContent = FileUtilities.loadToString(files[0]); + + // Split the file into lines and check one line at a time + String[] lines = fileContent.split("\n+"); + assertEquals(lines.length, 13); + assertTrue(lines[0] + " should start with " + + "Subj: [CINA] Registered Experiment /CINA/CINA1/EXP-", lines[0] + .startsWith("Subj: [CINA] Registered Experiment /CINA/CINA1/EXP-")); + assertEquals(lines[1], "From: sender"); + assertEquals(lines[2], "To: no-one@nowhere.ch"); + assertEquals(lines[3], "Reply-To: sender"); + assertEquals(lines[4], "Content:"); + assertTrue(lines[5].startsWith("------=_Part_0")); + assertEquals(lines[6], + "Experiment was successfully registered. Use the attached metadata file to register Samples"); + + assertTrue(lines[7].startsWith("------=_Part_0")); + assertEquals(lines[8], "Content-Disposition: attachment; filename=sample.properties"); + assertTrue(lines[9].startsWith("experiment.identifier=/CINA/CINA1/EXP-")); + assertEquals(lines[10], "experiment.owner-email=no-one@nowhere.ch"); + assertEquals(lines[11], "sample.code-prefix=S"); + assertTrue(lines[12].startsWith("------=_Part_0")); + } + + private void doStoreData(File datasetFolder) + { + DataSetInformation dataSetInformation = + extractor.getDataSetInformation(datasetFolder, openbisService); + + storageProcessor.storeData(dataSetInformation, typeExtractor, mailClient, datasetFolder, + rootDir); + } +}