Added an example to embed EWF nino service into a Vision2 desktop application.

This is locally consumed via the embedded web browser component.
This commit is contained in:
2014-04-10 15:28:19 +02:00
parent d40131f863
commit 4b497060a0
9 changed files with 707 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
This example demonstrates the use of embedded Vision2 web browser component, and embedded EWF server (using nino).

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="desktop_app" uuid="E015841A-D456-46E1-8A18-E0CEB9E69CD5">
<description>Vision2+web browser widget+embedded web service</description>
<target name="desktop_app">
<description>This example demonstrates how to build a vision2 desktop application that embed a web browser accessing the service of an embedded web service.</description>
<root class="DESKTOP_APP" feature="make_and_launch"/>
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="transitional" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true"/>
</option>
<setting name="concurrency" value="thread"/>
<precompile name="vision2-pre" location="$ISE_PRECOMP\vision2-mt-safe.ecf"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="ewsgi" location="..\..\library\server\ewsgi\ewsgi-safe.ecf"/>
<library name="thread" location="$ISE_LIBRARY\library\thread\thread-safe.ecf"/>
<library name="vision2" location="$ISE_LIBRARY\library\vision2\vision2-safe.ecf"/>
<library name="web_browser" location="$ISE_LIBRARY\library\web_browser\web_browser-safe.ecf" readonly="false"/>
<library name="wsf" location="..\..\library\server\wsf\wsf-safe.ecf"/>
<library name="wsf_nino" location="..\..\library\server\wsf\connector\nino-safe.ecf"/>
<library name="wsf_nino_connector" location="..\..\library\server\ewsgi\connectors\nino\nino-safe.ecf"/>
<cluster name="src" location=".\src" recursive="true">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
</cluster>
</target>
</system>

View File

@@ -0,0 +1 @@
Test

View File

@@ -0,0 +1,32 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script type="text/javascript">
function loadXMLDoc()
{
var xmlhttp;
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
}
}
xmlhttp.open("GET","http://localhost:52367/test/ajax.txt",true);
xmlhttp.send();
}
</script>
</head>
<body>
<h1>This is a local file test with js</h1><li><a href="http://localhost:52367/">back to home</a></li><div id="myDiv"><h2>Let AJAX change this text</h2>
<button type="button" onclick="loadXMLDoc()">Change Content</button>
</div>
</body></html>

View File

@@ -0,0 +1,230 @@
note
description: "Summary description for {APP_EMBEDDED_WEB_SERVICE}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
APP_EMBEDDED_WEB_SERVICE
inherit
EMBEDDED_WEB_SERVICE
redefine
make
end
create
make
feature {NONE} -- Initialization
make
do
Precursor
create request_exit_operation_actions
local_connection_restriction_enabled := True
end
feature -- Execution
request_exit_operation_actions: ACTION_SEQUENCE [TUPLE]
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the request
-- See `req.input' for input stream
-- `req.meta_variables' for the CGI meta variable
-- and `res' for output buffer
local
router: WSF_ROUTER
sess: detachable WSF_ROUTER_SESSION
m: WSF_HTML_PAGE_RESPONSE
b: STRING
fs: WSF_FILE_SYSTEM_HANDLER
do
create router.make (3)
router.handle ("/test/{var}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_test))
router.handle ("/env", create {WSF_URI_AGENT_HANDLER}.make (agent handle_env))
router.handle ("/exit", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_exit))
create fs.make_with_path ((create {EXECUTION_ENVIRONMENT}).current_working_path.extended ("files"))
router.handle ("/files", fs)
create sess
router.dispatch (req, res, sess)
if not sess.dispatched then
create m.make
create b.make_from_string ("<h1>Hello Eiffel desktop user</h1>")
b.append ("<li><a href=%"" + req.script_url ("/test/start") + "%">test</a></li>")
b.append ("<li><a href=%"" + req.script_url ("/env") + "%">env</a></li>")
b.append ("<li><a href=%"" + req.script_url ("/files") + "%">files</a></li>")
b.append ("<li><a href=%"" + req.script_url ("/exit") + "%">exit</a></li>")
m.set_body (b)
res.send (m)
end
end
handle_test (req: WSF_REQUEST; res: WSF_RESPONSE)
local
m: WSF_HTML_PAGE_RESPONSE
b: STRING
l_name: READABLE_STRING_32
do
if attached {WSF_STRING} req.item ("var") as p_name then
l_name := p_name.value
else
l_name := {STRING_32} "Embedded web service and web_browser in vision2 application"
end
create m.make
create b.make_from_string ("<h1>This is a test about "+ m.html_encoded_string (l_name) +"</h1>")
b.append ("<li><a href=%"" + req.script_url ("/") + "%">back to home</a></li>")
if l_name.is_case_insensitive_equal_general ("start") then
b.append ("<li><a href=%"" + req.script_url ("/test/js") + "%">test javascript+ajax</a></li>")
elseif l_name.is_case_insensitive_equal_general ("js") then
b.append ("[
<div id="myDiv"><h2>Let AJAX change this text</h2>
<button type="button" onclick="loadXMLDoc()">Change Content</button>
</div>
]")
m.add_javascript_content ("[
function loadXMLDoc()
{
var xmlhttp;
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
}
}
xmlhttp.open("GET","/test/ajax.txt",true);
xmlhttp.send();
}
]")
elseif l_name.is_case_insensitive_equal_general ("ajax.txt") then
b := "This is AJAX response ... from " + req.absolute_script_url ("")
end
m.set_body (b)
res.send (m)
end
handle_env (req: WSF_REQUEST; res: WSF_RESPONSE)
local
s: STRING_8
p: WSF_PAGE_RESPONSE
v: STRING_8
do
create s.make (2048)
s.append ("**DEBUG**%N")
req.set_raw_input_data_recorded (True)
append_iterable_to ("Meta variables:", req.meta_variables, s)
s.append_character ('%N')
append_iterable_to ("Path parameters", req.path_parameters, s)
s.append_character ('%N')
append_iterable_to ("Query parameters", req.query_parameters, s)
s.append_character ('%N')
append_iterable_to ("Form parameters", req.form_parameters, s)
s.append_character ('%N')
if attached req.content_type as l_type then
s.append ("Content: type=" + l_type.debug_output)
s.append (" length=")
s.append_natural_64 (req.content_length_value)
s.append_character ('%N')
create v.make (req.content_length_value.to_integer_32)
req.read_input_data_into (v)
across
v.split ('%N') as v_cursor
loop
s.append (" |")
s.append (v_cursor.item)
s.append_character ('%N')
end
end
create p.make_with_body (s)
p.header.put_content_type_text_plain
res.send (p)
end
handle_exit (req: WSF_REQUEST; res: WSF_RESPONSE)
local
m: WSF_HTML_PAGE_RESPONSE
b: STRING
do
create m.make
create b.make_from_string ("<h1>Embedded server is about to shutdown</h1>")
b.append ("<li><a href=%"" + req.script_url ("/") + "%">back to home</a></li>")
m.set_body (b)
res.send (m)
if attached {WGI_NINO_CONNECTOR} req.wgi_connector as nino then
nino.server.shutdown_server
end
request_exit_operation_actions.call (Void)
end
feature {NONE} -- Implementation
append_iterable_to (a_title: READABLE_STRING_8; it: detachable ITERABLE [WSF_VALUE]; s: STRING_8)
local
n: INTEGER
t: READABLE_STRING_8
v: READABLE_STRING_8
do
s.append (a_title)
s.append_character (':')
if it /= Void then
across it as c loop
n := n + 1
end
if n = 0 then
s.append (" empty")
s.append_character ('%N')
else
s.append_character ('%N')
across
it as c
loop
s.append (" - ")
s.append (c.item.url_encoded_name)
t := c.item.generating_type
if t.same_string ("WSF_STRING") then
else
s.append_character (' ')
s.append_character ('{')
s.append (t)
s.append_character ('}')
end
s.append_character ('=')
v := c.item.string_representation.as_string_8
if v.has ('%N') then
s.append_character ('%N')
across
v.split ('%N') as v_cursor
loop
s.append (" |")
s.append (v_cursor.item)
s.append_character ('%N')
end
else
s.append (v)
s.append_character ('%N')
end
end
end
else
s.append (" none")
s.append_character ('%N')
end
end
end

View File

@@ -0,0 +1,71 @@
note
description: "Objects that represent the Vision2 application.%
%The original version of this class has been generated by EiffelBuild."
generator: "EiffelBuild"
legal: "See notice at end of class."
status: "See notice at end of class."
date: "$Date: 2012-09-29 01:29:13 +0200 (sam., 29 sept. 2012) $"
revision: "$Revision: 89488 $"
class
DESKTOP_APP
inherit
EV_APPLICATION
create
make_and_launch
feature {NONE} -- Initialization
make_and_launch
-- Create `Current', build and display `main_window',
-- then launch the application.
local
l_win: like main_window
l_embeded_services: APP_EMBEDDED_WEB_SERVICE
do
default_create
create l_win.make
main_window := l_win
l_win.show
create l_embeded_services.make
l_embeded_services.set_port_number (0) -- Use first available port number
l_embeded_services.on_launched_actions.force (agent on_web_service_launched (l_win))
l_embeded_services.request_exit_operation_actions.force (agent on_quit)
l_embeded_services.launch
launch
end
on_quit
do
if attached main_window as win then
win.destroy_and_exit_if_last
end
end
on_web_service_launched (a_win: attached like main_window)
do
add_idle_action_kamikaze (agent a_win.open_link)
end
feature {NONE} -- Implementation
main_window: detachable MAIN_WINDOW
-- Main window of `Current'
;note
copyright: "Copyright (c) 1984-2009, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
356 Storke Road, Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -0,0 +1,202 @@
note
description: "Objects that represent an EV_TITLED_WINDOW.%
%The original version of this class was generated by EiffelBuild."
generator: "EiffelBuild"
legal: "See notice at end of class."
status: "See notice at end of class."
date: "$Date: 2010-08-17 10:49:12 +0200 (mar., 17 août 2010) $"
revision: "$Revision: 84189 $"
class
MAIN_WINDOW
inherit
EV_TITLED_WINDOW
redefine
create_interface_objects, initialize, is_in_default_state
end
SHARED_EMBEDED_WEB_SERVICE_INFORMATION
undefine
default_create, copy
end
create
make
feature {NONE} -- Initialization
make
-- Creation method
do
default_create
end
initialize
-- Initialize `Current'.
do
Precursor {EV_TITLED_WINDOW}
set_title ("Desktop Application (demo embedded EWF+browser)")
-- Connect events.
-- Close the application when an interface close
-- request is received on `Current'. i.e. the cross is clicked.
close_request_actions.extend (agent destroy_and_exit_if_last)
-- Call `user_initialization'.
user_initialization
end
create_interface_objects
-- Create objects
do
create home_button.make_with_text ("Home")
create back_button.make_with_text ("Back")
create forth_button.make_with_text ("Forth")
create refresh_button.make_with_text ("Refresh")
create stop_button.make_with_text ("Stop")
create url_text_field.make_with_text ("http://localhost:" + port_number.out)
create go_button.make_with_text ("Go")
create web_browser
end
user_initialization
-- Called by `initialize'.
-- Any custom user initialization that
-- could not be performed in `initialize',
-- (due to regeneration of implementation class)
-- can be added here.
local
l_browser_box: EV_VERTICAL_BOX
l_server_box: EV_VERTICAL_BOX
l_hor_box: EV_HORIZONTAL_BOX
vb: EV_VERTICAL_BOX
do
set_size (800, 600)
create vb
extend (vb)
vb.set_border_width (3)
vb.set_padding_width (3)
-- browser part
create l_browser_box
create l_hor_box
l_browser_box.extend (l_hor_box)
l_browser_box.disable_item_expand (l_hor_box)
home_button.select_actions.force_extend (agent on_home_button_action)
l_hor_box.extend (home_button)
l_hor_box.disable_item_expand (home_button)
back_button.select_actions.force_extend (agent on_back_button_action)
l_hor_box.extend (back_button)
l_hor_box.disable_item_expand (back_button)
forth_button.select_actions.force_extend (agent on_forth_button_action)
l_hor_box.extend (forth_button)
l_hor_box.disable_item_expand (forth_button)
refresh_button.select_actions.force_extend (agent on_refresh_button_action)
l_hor_box.extend (refresh_button)
l_hor_box.disable_item_expand (refresh_button)
stop_button.select_actions.force_extend (agent on_stop_button_action)
l_hor_box.extend (stop_button)
l_hor_box.disable_item_expand (stop_button)
l_hor_box.extend (url_text_field)
go_button.select_actions.force_extend (agent on_go_button_action)
l_hor_box.extend (go_button)
l_hor_box.disable_item_expand (go_button)
l_browser_box.extend (web_browser)
--------------------
vb.extend (l_browser_box)
end
is_in_default_state: BOOLEAN
do
Result := True
end
feature -- Basic operation
open_link
do
url_text_field.set_text ("http://localhost:" + port_number.out)
on_go_button_action
end
feature {NONE} -- Implementation
home_button, go_button, back_button, forth_button, stop_button, refresh_button: EV_BUTTON
-- Buttons
url_text_field: EV_TEXT_FIELD
-- URL text field
on_go_button_action
-- Action for `go_button'
local
l_uri: STRING_32
do
l_uri := url_text_field.text
if l_uri /= Void and then not l_uri.is_empty then
web_browser.load_uri (l_uri)
else
on_home_button_action
end
end
on_home_button_action
-- Action for `home_button'
do
web_browser.load_uri ("http://localhost:" + port_number.out)
end
on_back_button_action
-- Action for `back_button'
do
web_browser.back
end
on_forth_button_action
-- Action for `forth_button'
do
web_browser.forth
end
on_refresh_button_action
-- Action for `refresh_button'
do
web_browser.refresh
end
on_stop_button_action
-- Action for `stop_button'
do
web_browser.stop
end
web_browser: EV_WEB_BROWSER
-- Web browser widget
;note
copyright: "Copyright (c) 1984-2009, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
356 Storke Road, Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -0,0 +1,114 @@
note
description: "Summary description for {EMBEDDED_WEB_SERVICE}."
author: ""
date: "$Date$"
revision: "$Revision$"
deferred class
EMBEDDED_WEB_SERVICE
inherit
THREAD
rename
make as make_thread,
execute as execute_thread
end
WSF_SERVICE
rename
execute as execute_embedded
end
SHARED_EMBEDED_WEB_SERVICE_INFORMATION
feature -- Initialization
make
do
make_thread
create on_launched_actions
end
feature {NONE} -- Execution
execute_embedded (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the request
-- See `req.input' for input stream
-- `req.meta_variables' for the CGI meta variable
-- and `res' for output buffer
local
filter: WSF_AGENT_FILTER
m: WSF_PAGE_RESPONSE
do
if local_connection_restriction_enabled then
if
attached req.remote_addr as l_remote_addr and then
l_remote_addr.is_case_insensitive_equal_general ("127.0.0.1")
then
execute (req, res)
else
create m.make_with_body ("Only local connection is allowed")
m.set_status_code (403) -- Forbidden
res.send (m)
end
else
execute (req, res)
end
end
execute_thread
local
nino: WSF_NINO_SERVICE_LAUNCHER
opts: WSF_SERVICE_LAUNCHER_OPTIONS
do
create opts.default_create
opts.set_verbose (True)
opts.set_option ("port", port_number)
create nino.make (Current, opts)
nino.on_launched_actions.force (agent on_launched)
nino.launch
end
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the request
-- See `req.input' for input stream
-- `req.meta_variables' for the CGI meta variable
-- and `res' for output buffer
deferred
end
on_launched (conn: WGI_CONNECTOR)
do
if attached {WGI_NINO_CONNECTOR} conn as nino then
set_port_number (nino.port)
end
on_launched_actions.call (Void)
end
feature -- Control
wait
-- Wait for server to be terminated.
do
join
end
feature -- Access
on_launched_actions: ACTION_SEQUENCE [TUPLE]
feature -- Status report
local_connection_restriction_enabled: BOOLEAN
-- Accept only local connection?
--| based on 127.0.0.1 IP
--| TO IMPROVE
feature -- Change
set_local_connection_restriction_enabled (b: BOOLEAN)
do
local_connection_restriction_enabled := b
end
end

View File

@@ -0,0 +1,27 @@
note
description: "Summary description for {SHARED_EMBEDED_WEB_SERVICE_INFORMATION}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
SHARED_EMBEDED_WEB_SERVICE_INFORMATION
feature -- Access
port_number: INTEGER
do
Result := port_number_cell.item
end
set_port_number (a_port: like port_number)
do
port_number_cell.replace (a_port)
end
port_number_cell: CELL [INTEGER]
once ("process")
create Result.put (0)
end
end