Extract notification library from the CMS draft application

The new library is located in library/runtime/process/notification.
This allows to use it apart from the CMS.
This commit is contained in:
Olivier Ligot
2013-06-12 11:31:31 +02:00
parent fa8b3fdccc
commit 6fbe66ff7b
17 changed files with 69 additions and 31 deletions

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-8-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-8-0 http://www.eiffel.com/developers/xml/configuration-1-8-0.xsd" name="notification" uuid="99D9A065-CD45-4E20-9C86-579C8AD42E5E" library_target="notification">
<target name="notification">
<root all_classes="true"/>
<file_rule>
<exclude>/.git$</exclude>
<exclude>/EIFGENs$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="standard">
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="http" location="..\..\..\network\protocol\http\http-safe.ecf"/>
<library name="process" location="$ISE_LIBRARY\library\process\process-safe.ecf"/>
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
<cluster name="src" location="." recursive="true"/>
</target>
</system>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-8-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-8-0 http://www.eiffel.com/developers/xml/configuration-1-8-0.xsd" name="notification" uuid="99D9A065-CD45-4E20-9C86-579C8AD42E5E" library_target="notification">
<target name="notification">
<root all_classes="true"/>
<file_rule>
<exclude>/.git$</exclude>
<exclude>/EIFGENs$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
<option warning="true" full_class_checking="true" void_safety="none" syntax="standard">
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
<library name="http" location="..\..\..\network\protocol\http\http.ecf"/>
<library name="process" location="$ISE_LIBRARY\library\process\process.ecf"/>
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
<cluster name="src" location="." recursive="true"/>
</target>
</system>

View File

@@ -0,0 +1,58 @@
note
description: "Summary description for {NOTIFICATION_CHAIN_MAILER}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
NOTIFICATION_CHAIN_MAILER
inherit
NOTIFICATION_MAILER
create
make
feature {NONE} -- Initialization
make (a_mailer: like active)
do
active := a_mailer
end
feature -- Access
active: NOTIFICATION_MAILER
next: detachable NOTIFICATION_MAILER
feature -- Status
is_available: BOOLEAN
do
Result := active.is_available
if not Result and attached next as l_next then
Result := l_next.is_available
end
end
feature -- Change
set_next (m: like next)
do
next := m
end
feature -- Basic operation
process_email (a_email: NOTIFICATION_EMAIL)
do
if active.is_available then
active.process_email (a_email)
end
if attached next as l_next and then l_next.is_available then
l_next.process_email (a_email)
end
end
end

View File

@@ -0,0 +1,97 @@
note
description : "[
Component representing an email
]"
author : "$Author$"
date : "$Date$"
revision : "$Revision$"
class
NOTIFICATION_EMAIL
create
make
feature {NONE} -- Initialization
make (a_from: like from_address; a_to_address: READABLE_STRING_8; a_subject: like subject; a_body: like body)
-- Initialize `Current'.
do
initialize
from_address := a_from
subject := a_subject
body := a_body
to_addresses.extend (a_to_address)
end
initialize
do
create date.make_now_utc
create to_addresses.make (1)
end
feature -- Access
date: DATE_TIME
from_address: READABLE_STRING_8
to_addresses: ARRAYED_LIST [READABLE_STRING_8]
subject: READABLE_STRING_8
body: READABLE_STRING_8
feature -- Change
set_date (d: like date)
do
date := d
end
feature -- Conversion
message: STRING_8
do
Result := header
Result.append ("%N")
Result.append (body)
Result.append ("%N")
Result.append ("%N")
end
header: STRING_8
do
create Result.make (20)
Result.append ("From: " + from_address + "%N")
Result.append ("Date: " + date_to_rfc1123_http_date_format (date) + " GMT%N")
Result.append ("To: ")
across
to_addresses as c
loop
Result.append (c.item)
Result.append_character (';')
end
Result.append_character ('%N')
Result.append ("Subject: " + subject + "%N")
ensure
Result.ends_with ("%N")
end
feature {NONE} -- Implementation
date_to_rfc1123_http_date_format (dt: DATE_TIME): STRING_8
-- String representation of `dt' using the RFC 1123
local
d: HTTP_DATE
do
create d.make_from_date_time (dt)
Result := d.rfc1123_string
end
invariant
-- invariant_clause: True
end

View File

@@ -0,0 +1,197 @@
note
description : "Objects that ..."
author : "$Author$"
date : "$Date$"
revision : "$Revision$"
class
NOTIFICATION_EXTERNAL_MAILER
inherit
NOTIFICATION_MAILER
-- SHARED_EXECUTION_ENVIRONMENT
create
make
feature {NONE} -- Initialization
make (a_exe: like executable_path; args: detachable ITERABLE [READABLE_STRING_8])
-- Initialize `Current'.
do
set_parameters (a_exe, args)
end
executable_path: READABLE_STRING_8
arguments: detachable ARRAYED_LIST [STRING_8]
stdin_mode_set: BOOLEAN
-- Use `stdin' to pass email message, rather than using local file?
stdin_termination_sequence: detachable STRING
-- Termination sequence for the stdin mode
--| If any, this tells the executable all the data has been provided
--| For instance, using sendmail, you should have "%N.%N%N"
feature -- Status
is_available: BOOLEAN
local
f: RAW_FILE
do
create f.make (executable_path)
Result := f.exists
end
feature -- Change
set_parameters (cmd: like executable_path; args: detachable ITERABLE [READABLE_STRING_8])
-- Set parameters `executable_path' and associated `arguments'
local
l_args: like arguments
do
executable_path := cmd
if args = Void then
arguments := Void
else
create l_args.make (5)
across
args as c
loop
l_args.force (c.item)
end
arguments := l_args
end
end
set_stdin_mode (b: BOOLEAN; v: like stdin_termination_sequence)
-- Set the `stdin_mode_set' value
-- and provide optional termination sequence when stdin mode is selected.
do
stdin_mode_set := b
stdin_termination_sequence := v
end
feature -- Basic operation
process_email (a_email: NOTIFICATION_EMAIL)
local
l_factory: PROCESS_FACTORY
args: like arguments
p: detachable PROCESS
retried: INTEGER
do
if retried = 0 then
create l_factory
if stdin_mode_set then
p := l_factory.process_launcher (executable_path, arguments, Void)
p.set_hidden (True)
p.set_separate_console (False)
p.redirect_input_to_stream
p.launch
if p.launched then
p.put_string (a_email.message)
if attached stdin_termination_sequence as v then
p.put_string (v)
end
end
else
if attached arguments as l_args then
args := l_args.twin
else
if attached {RAW_FILE} new_temporary_file (generator) as f then
f.create_read_write
f.put_string (a_email.message)
f.close
create args.make (1)
args.force (f.name)
end
end
p := l_factory.process_launcher (executable_path, args, Void)
p.set_hidden (True)
p.set_separate_console (False)
p.launch
end
if p.launched and not p.has_exited then
p.wait_for_exit_with_timeout (1_000_000)
if not p.has_exited then
p.terminate
if not p.has_exited then
p.wait_for_exit_with_timeout (1_000_000)
end
end
end
elseif retried = 1 then
if p /= Void and then p.launched and then not p.has_exited then
p.terminate
if not p.has_exited then
p.wait_for_exit_with_timeout (1_000_000)
end
end
end
rescue
retried := retried + 1
retry
end
feature {NONE} -- Implementation
new_temporary_file (a_extension: detachable STRING_8): RAW_FILE
-- Create file with temporary name.
-- With concurrent execution, noting ensures that {FILE_NAME}.make_temporary_name is unique
-- So using `a_extension' may help
local
fn: FILE_NAME
s: like {FILE_NAME}.string
f: detachable like new_temporary_file
i: INTEGER
do
-- With concurrent execution, nothing ensures that {FILE_NAME}.make_temporary_name is unique
-- So let's try to find
from
until
f /= Void or i > 1000
loop
create fn.make_temporary_name
s := fn.string
if i > 0 then
s.append_character ('-')
s.append_integer (i)
create fn.make_from_string (s)
end
if a_extension /= Void then
fn.add_extension (a_extension)
end
s := fn.string
create f.make (fn.string)
if f.exists then
i := i + 1
f := Void
end
end
if f = Void then
Result := new_temporary_file (Void)
else
Result := f
check not_temporary_file_exists: not Result.exists end
check temporary_creatable: Result.is_creatable end
end
ensure
not_result_exists: not Result.exists
result_creatable: Result.is_creatable
end
feature {NONE} -- Environment
Execution_environment: EXECUTION_ENVIRONMENT
once
create Result
end
invariant
end

View File

@@ -0,0 +1,48 @@
note
description : "[
Component responsible to send email
]"
author : "$Author$"
date : "$Date$"
revision : "$Revision$"
deferred class
NOTIFICATION_MAILER
feature -- Status
is_available: BOOLEAN
-- Is mailer available to use?
deferred
end
feature -- Basic operation
process_emails (lst: ITERABLE [NOTIFICATION_EMAIL])
-- Process set of emails `lst'
require
is_available
do
across
lst as c
loop
process_email (c.item)
end
end
safe_process_email (a_email: NOTIFICATION_EMAIL)
-- Same as `process_email', but include the check of `is_available'
do
if is_available then
process_email (a_email)
end
end
process_email (a_email: NOTIFICATION_EMAIL)
-- Process the sending of `a_email'
require
is_available
deferred
end
end

View File

@@ -0,0 +1,34 @@
note
description : "[
NOTIFICATION_MAILER using sendmail as mailtool
]"
author : "$Author$"
date : "$Date$"
revision : "$Revision$"
class
NOTIFICATION_SENDMAIL_MAILER
inherit
NOTIFICATION_EXTERNAL_MAILER
redefine
default_create
end
create
default_create
feature {NONE} -- Initialization
default_create
do
Precursor
make ("/usr/sbin/sendmail", <<"-t">>)
if not is_available then
make ("/usr/bin/sendmail", <<"-t">>)
end
set_stdin_mode (True, "%N.%N%N")
end
end