diff --git a/frontend/TestSsiClient.h b/frontend/TestSsiClient.h
index b5a228f51e6f628dca97e378cfbd6b91ae166702..4b2486150297e83f56b4924d638d4f7b333d59f9 100644
--- a/frontend/TestSsiClient.h
+++ b/frontend/TestSsiClient.h
@@ -21,7 +21,7 @@ extern XrdSsiProvider *XrdSsiProviderClient;
 
 
 
-template <typename RequestType, typename ResponseType>
+template <typename RequestType, typename ResponseType, typename MetadataType, typename AlertType>
 class TestSsiClient
 {
 public:
diff --git a/frontend/TestSsiRequest.cpp b/frontend/TestSsiRequest.cpp
index f8d54cbe3bd2fd117c58fdadf8c22ead5adb2d7d..31988ae61a2818e60082ee11f9986b8559d446e9 100644
--- a/frontend/TestSsiRequest.cpp
+++ b/frontend/TestSsiRequest.cpp
@@ -40,6 +40,7 @@ bool TestSsiRequest::ProcessResponse(const XrdSsiErrInfo &eInfo, const XrdSsiRes
 
          // do something with metadata
 
+         // A metadata-only response is indicated when XrdSsiRespInfo::rType is set to isNil (i.e. no response data is present).
 #if 0
          // clean up
 
diff --git a/frontend/TestSsiRequestProc.cpp b/frontend/TestSsiRequestProc.cpp
index c5675946e9dc617d73aa7a8d612a46a14ed0cb87..2eb3de557f2a27ec7f2a7e64e1e54d55d4c27054 100644
--- a/frontend/TestSsiRequestProc.cpp
+++ b/frontend/TestSsiRequestProc.cpp
@@ -8,7 +8,7 @@
 // and metadata
 
 template <>
-void RequestProc<xrdssi::test::Request, xrdssi::test::Result>::ExecuteAction()
+void RequestProc<xrdssi::test::Request, xrdssi::test::Result, xrdssi::test::Metadata, xrdssi::test::Alert>::ExecuteAction()
 {
    // Output message in Json format (for debugging)
 
@@ -27,11 +27,40 @@ void RequestProc<xrdssi::test::Request, xrdssi::test::Result>::ExecuteAction()
 }
 
 
+
+// A metadata-only reply is appropriate when we just need to send a short response/acknowledgement,
+// as it has less overhead than a full response. The maximum amount of metadata that may be sent is
+// defined by XrdSsiResponder::MaxMetaDataSZ constant member.
+
 template <>
-void RequestProc<xrdssi::test::Request, xrdssi::test::Result>::ExecuteMetadata()
+void RequestProc<xrdssi::test::Request, xrdssi::test::Result, xrdssi::test::Metadata, xrdssi::test::Alert>::ExecuteMetadata()
 {
    std::cerr << "Sending metadata..." << std::endl;
    const std::string metadata("Have some metadata!");
    SetMetadata(metadata.c_str(), metadata.size());
 }
 
+
+
+/*
+ * Alert messages can be anything you want them to be. The SSI framework enforces
+ * the following rules:
+ *
+ * - alerts are sent in the order posted,
+ * - all outstanding alerts are sent before the final response is sent (i.e. the one
+ * posted using a SetResponse() method),
+ * - once a final response is posted, subsequent alert messages are not sent, and
+ * - if a request is cancelled, all pending alerts are discarded.
+ *
+ * In order to send an alert, you must encapsulate your message using an
+ * XrdSsiRespInfoMsg object. The object provides synchronization between posting
+ * an alert, sending the alert, and releasing storage after the alert was sent. It is defined
+ * in the XrdSsiRespInfo.hh header file.
+ *
+ * The XrdSsiRespInfoMsg object needs to be inherited by whatever class you use to
+ * manage your alert message. The pure abstract class, RecycleMsg() must also be
+ * implemented. This method is called after the message is sent or when it is discarded.
+ * A parameter to the method tells you why it’s being called.
+ *
+ * See example p.45
+ */
diff --git a/frontend/TestSsiRequestProc.h b/frontend/TestSsiRequestProc.h
index 4ac4e5d242a232a8bc5c839c998ed45c2085cac8..501596253e975f299a1d4076bc7768ec1f6a7b74 100644
--- a/frontend/TestSsiRequestProc.h
+++ b/frontend/TestSsiRequestProc.h
@@ -18,7 +18,7 @@
  * RequestProc is a kind of agent object that the service object creates for each request that it receives.
  */
 
-template <typename RequestType, typename ResponseType>
+template <typename RequestType, typename ResponseType, typename MetadataType, typename AlertType>
 class RequestProc : public XrdSsiResponder
 {
 public:
@@ -41,8 +41,8 @@ private:
 
 
 
-template <typename RequestType, typename ResponseType>
-void RequestProc<RequestType, ResponseType>::Execute()
+template <typename RequestType, typename ResponseType, typename MetadataType, typename AlertType>
+void RequestProc<RequestType, ResponseType, MetadataType, AlertType>::Execute()
 {
    using namespace std;
 
@@ -98,8 +98,8 @@ void RequestProc<RequestType, ResponseType>::Execute()
 
 // Create specialized versions of this method to handle cancellation/cleanup for specific message types
 
-template <typename RequestType, typename ResponseType>
-void RequestProc<RequestType, ResponseType>::Finished(XrdSsiRequest &rqstR, const XrdSsiRespInfo &rInfo, bool cancel)
+template <typename RequestType, typename ResponseType, typename MetadataType, typename AlertType>
+void RequestProc<RequestType, ResponseType, MetadataType, AlertType>::Finished(XrdSsiRequest &rqstR, const XrdSsiRespInfo &rInfo, bool cancel)
 {
    using namespace std;
 
diff --git a/frontend/TestSsiService.h b/frontend/TestSsiService.h
index 168faad9992bb57ebd3bec4023ee107c9a8b4383..ddcc8b60c59186590dd6fb707d0229b1f34b121d 100644
--- a/frontend/TestSsiService.h
+++ b/frontend/TestSsiService.h
@@ -11,7 +11,7 @@
  * Service Object, obtained using GetService() method of the TestSsiServiceProvider factory
  */
 
-template <typename RequestType, typename ResponseType>
+template <typename RequestType, typename ResponseType, typename MetadataType, typename AlertType>
 class TestSsiService : public XrdSsiService
 {
 public:
@@ -32,12 +32,12 @@ public:
 
 
 
-template <typename RequestType, typename ResponseType>
-void TestSsiService<RequestType, ResponseType>::ProcessRequest(XrdSsiRequest &reqRef, XrdSsiResource &resRef)
+template <typename RequestType, typename ResponseType, typename MetadataType, typename AlertType>
+void TestSsiService<RequestType, ResponseType, MetadataType, AlertType>::ProcessRequest(XrdSsiRequest &reqRef, XrdSsiResource &resRef)
 {
    std::cerr << "Called ProcessRequest()" << std::endl;
 
-   RequestProc<RequestType, ResponseType> processor;
+   RequestProc<RequestType, ResponseType, MetadataType, AlertType> processor;
 
    // Bind the processor to the request. Inherits the BindRequest method from XrdSsiResponder.
 
diff --git a/frontend/TestSsiServiceProvider.cpp b/frontend/TestSsiServiceProvider.cpp
index 6e2c24607f1c2dfdce3700454b7d65a1e36130e4..0c7306800d1136b432d99ea9a43aaba2e1661cf1 100644
--- a/frontend/TestSsiServiceProvider.cpp
+++ b/frontend/TestSsiServiceProvider.cpp
@@ -43,7 +43,7 @@ XrdSsiService* TestSsiServiceProvider::GetService(XrdSsiErrInfo &eInfo, const st
 
    cerr << "Called GetService(" << contact << "," << oHold << ")" << endl;
 
-   XrdSsiService *ptr = new TestSsiService<xrdssi::test::Request, xrdssi::test::Result>;
+   XrdSsiService *ptr = new TestSsiService<xrdssi::test::Request, xrdssi::test::Result, xrdssi::test::Metadata, xrdssi::test::Alert>;
 
    return ptr;
 }
diff --git a/frontend/test.proto b/frontend/test.proto
index a1a9ccfb3430d73c53c8986dd4da7c9271468aea..9831f5505a8a3f92b13b6942f415c0511302ad57 100644
--- a/frontend/test.proto
+++ b/frontend/test.proto
@@ -33,9 +33,15 @@ message Result {
   }
 }
 
-// XRootD SSI Service
+// XRootD SSI Metadata
 
-service XrdSsiService {
-  rpc SendRequest(Request) returns(Result);
+message Metadata {
+  string message_text = 1;          //< Some useful information about the next response
+}
+
+// XRootD SSI Alert
+
+message Alert {
+  string message_text = 1;          //< Some alert message for the client
 }
 
diff --git a/frontend/test_client.cpp b/frontend/test_client.cpp
index ebcf77c702d0b4aaaaf5c2c5c003f963ea8c72a3..2b9f5b687c215bba45ce199c903a7bb32ef25891 100644
--- a/frontend/test_client.cpp
+++ b/frontend/test_client.cpp
@@ -17,7 +17,7 @@ int main(int argc, char *argv[])
    {
       // Obtain a Service Provider
 
-      TestSsiClient<xrdssi::test::Request, xrdssi::test::Result> test_ssi_service(host, port);
+      TestSsiClient<xrdssi::test::Request, xrdssi::test::Result, xrdssi::test::Metadata, xrdssi::test::Alert> test_ssi_service(host, port);
 
       // Create a Request object