diff --git a/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/main/FileBasedTrackingDAO.java b/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/main/FileBasedTrackingDAO.java
new file mode 100644
index 0000000000000000000000000000000000000000..26652055ddc5792e30600e65ffc3eba732306efd
--- /dev/null
+++ b/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/main/FileBasedTrackingDAO.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2009 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.ethz.bsse.cisd.dsu.tracking.main;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.io.IOUtils;
+
+import ch.ethz.bsse.cisd.dsu.tracking.utils.LogUtils;
+import ch.systemsx.cisd.common.parser.AbstractParserObjectFactory;
+import ch.systemsx.cisd.common.parser.IParserObjectFactory;
+import ch.systemsx.cisd.common.parser.IParserObjectFactoryFactory;
+import ch.systemsx.cisd.common.parser.IPropertyMapper;
+import ch.systemsx.cisd.common.parser.ParserException;
+import ch.systemsx.cisd.common.parser.TabFileLoader;
+
+/**
+ * @author Tomasz Pylak
+ */
+public class FileBasedTrackingDAO implements ITrackingDAO
+{
+    private final String filePath;
+
+    public FileBasedTrackingDAO(String filePath)
+    {
+        this.filePath = filePath;
+    }
+
+    public void saveTrackingState(TrackingStateDTO state)
+    {
+        List<String> lines = new ArrayList<String>();
+        lines.add("lastSeenSequencingSampleId\tlastSeenFlowLaneSampleId\tlastSeenDatasetId\n");
+        lines.add("" + state.getLastSeenSequencingSampleId() + "\t"
+                + state.getLastSeenFlowLaneSampleId() + "\t" + state.getLastSeenDatasetId());
+        writeLines(new File(filePath), lines);
+    }
+
+    public TrackingStateDTO getTrackingState()
+    {
+        TabFileLoader<TrackingStateDTO> tabFileLoader =
+                new TabFileLoader<TrackingStateDTO>(
+                        new IParserObjectFactoryFactory<TrackingStateDTO>()
+                            {
+                                public IParserObjectFactory<TrackingStateDTO> createFactory(
+                                        IPropertyMapper propertyMapper) throws ParserException
+                                {
+                                    return new AbstractParserObjectFactory<TrackingStateDTO>(
+                                            TrackingStateDTO.class, propertyMapper)
+                                        {
+                                        };
+                                }
+                            });
+        try
+        {
+            List<TrackingStateDTO> trackingState = tabFileLoader.load(new File(filePath));
+            if (trackingState.size() != 1)
+            {
+                throw LogUtils.environmentError("File %s has to many rows, it should have exactly 1.",
+                        filePath);
+            }
+            return trackingState.get(0);
+        } catch (Exception e)
+        {
+            throw LogUtils.envErr("Incorrect file format", e);
+        }
+    }
+
+    private static void writeLines(File file, List<String> lines)
+    {
+        try
+        {
+            IOUtils.writeLines(lines, "\n", new FileOutputStream(file));
+        } catch (IOException ex)
+        {
+            throw LogUtils.envErr(String.format("Cannot save the file %s with content: %s",
+                    file.getPath(), lines), ex);
+        }
+    }
+}
diff --git a/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/main/ITrackingDAO.java b/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/main/ITrackingDAO.java
new file mode 100644
index 0000000000000000000000000000000000000000..0a3cf3bb9a38820584ba9a4c72732a91b15ab750
--- /dev/null
+++ b/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/main/ITrackingDAO.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2009 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.ethz.bsse.cisd.dsu.tracking.main;
+
+/**
+ * @author Tomasz Pylak
+ */
+public interface ITrackingDAO
+{
+    void saveTrackingState(TrackingStateDTO state);
+
+    TrackingStateDTO getTrackingState();
+}
diff --git a/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/main/Parameters.java b/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/main/Parameters.java
new file mode 100644
index 0000000000000000000000000000000000000000..ee0bbaa64de16b0372c0aa71213b95d50d4da71d
--- /dev/null
+++ b/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/main/Parameters.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2009 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.ethz.bsse.cisd.dsu.tracking.main;
+
+import static ch.systemsx.cisd.common.utilities.PropertyUtils.getMandatoryProperty;
+
+import java.util.Properties;
+
+import ch.systemsx.cisd.common.mail.IMailClient;
+import ch.systemsx.cisd.common.mail.MailClient;
+import ch.systemsx.cisd.common.utilities.PropertyUtils;
+
+/**
+ * @author Tomasz Pylak
+ */
+public class Parameters
+{
+    private static final String OPENBIS_USER = "openbis-user";
+
+    private static final String OPENBIS_PASSWORD = "openbis-password";
+
+    private static final String OPENBIS_SERVER_URL = "openbis-server-url";
+
+    private final String openbisUser;
+
+    private final String openbisPassword;
+
+    private final String openbisServerURL;
+
+    private final IMailClient mailClient;
+
+    public Parameters(Properties props)
+    {
+        this.openbisUser = getMandatoryProperty(props, OPENBIS_USER);
+        this.openbisPassword = getMandatoryProperty(props, OPENBIS_PASSWORD);
+        this.openbisServerURL = getMandatoryProperty(props, OPENBIS_SERVER_URL);
+        this.mailClient = new MailClient(props);
+    }
+
+    public String getOpenbisUser()
+    {
+        return openbisUser;
+    }
+
+    public String getOpenbisPassword()
+    {
+        return openbisPassword;
+    }
+
+    public String getOpenbisServerURL()
+    {
+        return openbisServerURL;
+    }
+
+    public IMailClient getMailClient()
+    {
+        return mailClient;
+    }
+}
diff --git a/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/main/TrackingBO.java b/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/main/TrackingBO.java
new file mode 100644
index 0000000000000000000000000000000000000000..3b33902967d315680fae6a100927f0f55ad15bc8
--- /dev/null
+++ b/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/main/TrackingBO.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2009 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.ethz.bsse.cisd.dsu.tracking.main;
+
+import java.util.List;
+
+import ch.ethz.bsse.cisd.dsu.tracking.Email;
+import ch.ethz.bsse.cisd.dsu.tracking.IEntityTrackingEmailGenerator;
+import ch.ethz.bsse.cisd.dsu.tracking.TrackedEntities;
+import ch.systemsx.cisd.common.mail.From;
+import ch.systemsx.cisd.common.mail.IMailClient;
+import ch.systemsx.cisd.openbis.generic.shared.ITrackingServer;
+import ch.systemsx.cisd.openbis.generic.shared.basic.IIdentifiable;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TrackingDataSetCriteria;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TrackingSampleCriteria;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SessionContextDTO;
+
+/**
+ * @author Tomasz Pylak
+ */
+public class TrackingBO
+{
+    private static final String SEQUENCING_SAMPLE_TYPE = "ILLUMINA_SEQUENCING";
+
+    private static final String FLOW_LANE_SAMPLE_TYPE = "FLOW_LANE";
+
+    private final ITrackingServer trackingServer;
+
+    private final IEntityTrackingEmailGenerator emailGenerator;
+
+    private final IMailClient mailClient;
+
+    public TrackingBO(ITrackingServer trackingServer, IEntityTrackingEmailGenerator emailGenerator,
+            IMailClient mailClient)
+    {
+        this.trackingServer = trackingServer;
+        this.emailGenerator = emailGenerator;
+        this.mailClient = mailClient;
+    }
+
+    public void trackAndNotify(ITrackingDAO trackingDAO, SessionContextDTO session)
+    {
+        TrackingStateDTO prevTrackingState = trackingDAO.getTrackingState();
+
+        TrackedEntities changedEntities =
+                fetchChangedEntities(prevTrackingState, trackingServer, session);
+        List<Email> emails = emailGenerator.generateEmails(changedEntities);
+        sendEmails(emails, mailClient);
+        saveTrackingState(changedEntities, trackingDAO);
+    }
+
+    private static void sendEmails(List<Email> emails, IMailClient mailClient)
+    {
+        for (Email email : emails)
+        {
+            From from = (email.getFromOrNull() == null) ? null : new From(email.getFromOrNull());
+            mailClient.sendMessage(email.getSubject(), email.getContent(),
+                    email.getReplyToOrNull(), from, email.getRecipients());
+        }
+    }
+
+    private static void saveTrackingState(TrackedEntities changedEntities, ITrackingDAO trackingDAO)
+    {
+        TrackingStateDTO state = new TrackingStateDTO();
+        state.setLastSeenSequencingSampleId(calcMaxId(changedEntities.getSequencingSamples()));
+        state.setLastSeenFlowLaneSampleId(calcMaxId(changedEntities.getFlowLaneSamples()));
+        state.setLastSeenDatasetId(calcMaxId(changedEntities.getDataSets()));
+        trackingDAO.saveTrackingState(state);
+    }
+
+    private static int calcMaxId(List<? extends IIdentifiable> entities)
+    {
+        long max = 0;
+        for (IIdentifiable entity : entities)
+        {
+            max = Math.max(max, entity.getId());
+        }
+        // FIXME 2009--, Tomasz Pylak: refactor ids to long everywhere
+        return (int) max;
+    }
+
+    private static TrackedEntities fetchChangedEntities(TrackingStateDTO trackingState,
+            ITrackingServer trackingServer, SessionContextDTO session)
+    {
+        List<Sample> sequencingSamples =
+                listSamples(SEQUENCING_SAMPLE_TYPE, trackingState.getLastSeenSequencingSampleId(),
+                        trackingServer, session);
+
+        List<Sample> flowLaneSamples =
+                listSamples(FLOW_LANE_SAMPLE_TYPE, trackingState.getLastSeenFlowLaneSampleId(),
+                        trackingServer, session);
+
+        TrackingDataSetCriteria dataSetCriteria =
+                new TrackingDataSetCriteria(FLOW_LANE_SAMPLE_TYPE, trackingState
+                        .getLastSeenDatasetId());
+        List<ExternalData> dataSets =
+                trackingServer.listDataSets(session.getSessionToken(), dataSetCriteria);
+
+        return new TrackedEntities(sequencingSamples, flowLaneSamples, dataSets);
+    }
+
+    private static List<Sample> listSamples(String sampleType, int lastSeenSampleId,
+            ITrackingServer trackingServer, SessionContextDTO session)
+    {
+        TrackingSampleCriteria criteria = new TrackingSampleCriteria(sampleType, lastSeenSampleId);
+        return trackingServer.listSamples(session.getSessionToken(), criteria);
+    }
+}
diff --git a/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/main/TrackingClient.java b/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/main/TrackingClient.java
new file mode 100644
index 0000000000000000000000000000000000000000..644dfc53fcf4e0b8061aa8720287115c83811d10
--- /dev/null
+++ b/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/main/TrackingClient.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2009 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.ethz.bsse.cisd.dsu.tracking.main;
+
+import java.util.Properties;
+
+import org.apache.log4j.Logger;
+
+import ch.ethz.bsse.cisd.dsu.tracking.EntityTrackingEmailGenerator;
+import ch.ethz.bsse.cisd.dsu.tracking.IEntityTrackingEmailGenerator;
+import ch.ethz.bsse.cisd.dsu.tracking.utils.LogUtils;
+import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException;
+import ch.systemsx.cisd.common.logging.LogCategory;
+import ch.systemsx.cisd.common.logging.LogFactory;
+import ch.systemsx.cisd.common.logging.LogInitializer;
+import ch.systemsx.cisd.common.mail.IMailClient;
+import ch.systemsx.cisd.common.spring.HttpInvokerUtils;
+import ch.systemsx.cisd.common.utilities.PropertyUtils;
+import ch.systemsx.cisd.openbis.generic.shared.ITrackingServer;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SessionContextDTO;
+
+/**
+ * @author Tomasz Pylak
+ */
+public class TrackingClient
+{
+    private static final String SERVICE_PROPERTIES_FILE = "etc/tracking-service.properties";
+
+    private static final String LOCAL_STORAGE_FILE = "etc/tracking-local-database";
+
+    public static void main(String[] args)
+    {
+        try
+        {
+            track();
+        } catch (EnvironmentFailureException ex)
+        {
+            LogUtils.notify(ex);
+        } catch (Throwable ex)
+        {
+            LogUtils.notify(ex);
+        }
+    }
+
+    private static void track()
+    {
+        LogInitializer.init();
+        Properties props = PropertyUtils.loadProperties(SERVICE_PROPERTIES_FILE);
+        Parameters params = new Parameters(props);
+
+        ITrackingServer trackingServer = createOpenBISTrackingServer(params);
+        IEntityTrackingEmailGenerator emailGenerator = new EntityTrackingEmailGenerator(props);
+        IMailClient mailClient = params.getMailClient();
+        TrackingBO trackingBO = new TrackingBO(trackingServer, emailGenerator, mailClient);
+
+        ITrackingDAO trackingDAO = new FileBasedTrackingDAO(LOCAL_STORAGE_FILE);
+
+        SessionContextDTO session = authentificateInOpenBIS(params, trackingServer);
+
+        trackingBO.trackAndNotify(trackingDAO, session);
+    }
+
+    private static ITrackingServer createOpenBISTrackingServer(Parameters params)
+    {
+        return HttpInvokerUtils.createServiceStub(ITrackingServer.class, params
+                .getOpenbisServerURL(), 5);
+    }
+
+    private static SessionContextDTO authentificateInOpenBIS(Parameters params,
+            ITrackingServer trackingServer)
+    {
+        try
+        {
+            String openbisUser = params.getOpenbisUser();
+            SessionContextDTO session =
+                    trackingServer.tryToAuthenticate(openbisUser, params.getOpenbisPassword());
+            if (session == null)
+            {
+                throw createAuthentificationException(params, null);
+            }
+            return session;
+        } catch (Exception ex)
+        {
+            throw createAuthentificationException(params, ex);
+        }
+    }
+
+    private static EnvironmentFailureException createAuthentificationException(Parameters params,
+            Exception exOrNull)
+    {
+        String exceptionMsg =
+                (exOrNull == null) ? "" : " Unexpected exception has occured: "
+                        + exOrNull.getMessage();
+        return LogUtils
+                .environmentError(
+                        "Cannot authentificate in openBIS as a user '%s'. Check that the password is correct and that openBIS service URL is correct.%s",
+                        params.getOpenbisUser(), exceptionMsg);
+    }
+
+}
diff --git a/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/main/TrackingStateDTO.java b/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/main/TrackingStateDTO.java
new file mode 100644
index 0000000000000000000000000000000000000000..16d873fc5a88ffbc3c767c44ddb5a4d45310f16c
--- /dev/null
+++ b/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/main/TrackingStateDTO.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2009 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.ethz.bsse.cisd.dsu.tracking.main;
+
+import ch.systemsx.cisd.common.annotation.BeanProperty;
+
+public class TrackingStateDTO
+{
+    private int lastSeenSequencingSampleId;
+
+    private int lastSeenFlowLaneSampleId;
+
+    private int lastSeenDatasetId;
+
+    public int getLastSeenSequencingSampleId()
+    {
+        return lastSeenSequencingSampleId;
+    }
+
+    @BeanProperty(label = "lastSeenSequencingSampleId")
+    public void setLastSeenSequencingSampleId(int lastSeenSequencingSampleId)
+    {
+        this.lastSeenSequencingSampleId = lastSeenSequencingSampleId;
+    }
+
+    public int getLastSeenFlowLaneSampleId()
+    {
+        return lastSeenFlowLaneSampleId;
+    }
+
+    @BeanProperty(label = "lastSeenFlowLaneSampleId")
+    public void setLastSeenFlowLaneSampleId(int lastSeenFlowLaneSampleId)
+    {
+        this.lastSeenFlowLaneSampleId = lastSeenFlowLaneSampleId;
+    }
+
+    public int getLastSeenDatasetId()
+    {
+        return lastSeenDatasetId;
+    }
+
+    @BeanProperty(label = "lastSeenDatasetId")
+    public void setLastSeenDatasetId(int lastSeenDatasetId)
+    {
+        this.lastSeenDatasetId = lastSeenDatasetId;
+    }
+}
\ No newline at end of file
diff --git a/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/utils/LogUtils.java b/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/utils/LogUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..a9ceb026d76a222ac1453f1763a1693359325773
--- /dev/null
+++ b/deep_sequencing_unit/source/java/ch/ethz/bsse/cisd/dsu/tracking/utils/LogUtils.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2009 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.ethz.bsse.cisd.dsu.tracking.utils;
+
+import org.apache.log4j.Logger;
+
+import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException;
+import ch.systemsx.cisd.common.logging.LogCategory;
+import ch.systemsx.cisd.common.logging.LogFactory;
+
+/**
+ * @author Tomasz Pylak
+ */
+public class LogUtils
+{
+    private static final Logger notificationLog =
+            LogFactory.getLogger(LogCategory.NOTIFY, LogUtils.class);
+
+    private static final Logger operationLog =
+            LogFactory.getLogger(LogCategory.OPERATION, LogUtils.class);
+
+    public static void notify(EnvironmentFailureException ex)
+    {
+        String causeMsg =
+                (ex.getCause() == null) ? "" : "Error cause: " + ex.getCause().getMessage();
+        notificationLog
+                .error("An environment exception occured why trying to send emails with changes.\n"
+                        + "Check and correct the configuration.\n" + "Error details: "
+                        + ex.getMessage() + "\n" + causeMsg);
+    }
+
+    public static void notify(Throwable ex)
+    {
+        notificationLog
+                .error("An unexpected exception occured why trying to send emails with changes.\n"
+                        + "Error details: " + ex.getMessage());
+    }
+
+    public static EnvironmentFailureException envErr(String message, Throwable exception)
+    {
+        String fullMsg =
+                message + " The following exception has been thrown: " + exception.getMessage();
+        return new EnvironmentFailureException(fullMsg, exception);
+    }
+
+    public static EnvironmentFailureException environmentError(String msgFormat, Object... params)
+    {
+        String fullMsg = String.format(msgFormat, params);
+        return new EnvironmentFailureException(fullMsg);
+    }
+}