diff --git a/contrib/library/text/parser/json/library/extras/visitor/json_pretty_string_visitor.e b/contrib/library/text/parser/json/library/extras/visitor/json_pretty_string_visitor.e
new file mode 100644
index 00000000..98b17c81
--- /dev/null
+++ b/contrib/library/text/parser/json/library/extras/visitor/json_pretty_string_visitor.e
@@ -0,0 +1,175 @@
+note
+ description: "JSON_PRETTY_STRING_VISITOR Generates the JSON-String for a JSON_VALUE"
+ revision: "0.1"
+
+class
+ JSON_PRETTY_STRING_VISITOR
+
+inherit
+ JSON_VISITOR
+
+create
+ make,
+ make_custom
+
+feature -- Initialization
+
+ make (a_output: like output)
+ -- Create a new instance
+ do
+ make_custom (a_output, 1, 1)
+ end
+
+ make_custom (a_output: like output; a_object_count_inlining, a_array_count_inlining: INTEGER)
+ -- Create a new instance
+ do
+ output := a_output
+ create indentation.make_empty
+ indentation_step := "%T"
+
+ object_count_inlining := a_object_count_inlining
+ array_count_inlining := a_array_count_inlining
+ end
+
+feature -- Access
+
+ output: STRING_32
+ -- JSON representation
+
+ indentation: like output
+
+ indentation_step: like indentation
+
+ line_number: INTEGER
+
+ indent
+ do
+ indentation.append (indentation_step)
+ end
+
+ exdent
+ do
+ indentation.remove_tail (indentation_step.count)
+ end
+
+ new_line
+ do
+ output.append ("%N")
+ output.append (indentation)
+ line_number := line_number + 1
+ end
+
+ object_count_inlining: INTEGER
+ array_count_inlining: INTEGER
+
+feature -- Visitor Pattern
+
+ visit_json_array (a_json_array: JSON_ARRAY)
+ -- Visit `a_json_array'.
+ local
+ value: JSON_VALUE
+ l_json_array: ARRAYED_LIST [JSON_VALUE]
+ l_line: like line_number
+ l_multiple_lines: BOOLEAN
+ do
+ l_json_array := a_json_array.array_representation
+ l_multiple_lines := l_json_array.count >= array_count_inlining or across l_json_array as p some attached {JSON_OBJECT} p.item or attached {JSON_ARRAY} p.item end
+ output.append ("[")
+ l_line := line_number
+ indent
+ from
+ l_json_array.start
+ until
+ l_json_array.off
+ loop
+ if
+ line_number > l_line or
+ l_multiple_lines
+ then
+ new_line
+ end
+ value := l_json_array.item
+ value.accept (Current)
+ l_json_array.forth
+ if not l_json_array.after then
+ output.append (", ")
+ end
+ end
+ exdent
+ if
+ line_number > l_line or
+ l_json_array.count >= array_count_inlining
+ then
+ new_line
+ end
+ output.append ("]")
+ end
+
+ visit_json_boolean (a_json_boolean: JSON_BOOLEAN)
+ -- Visit `a_json_boolean'.
+ do
+ output.append (a_json_boolean.item.out)
+ end
+
+ visit_json_null (a_json_null: JSON_NULL)
+ -- Visit `a_json_null'.
+ do
+ output.append ("null")
+ end
+
+ visit_json_number (a_json_number: JSON_NUMBER)
+ -- Visit `a_json_number'.
+ do
+ output.append (a_json_number.item)
+ end
+
+ visit_json_object (a_json_object: JSON_OBJECT)
+ -- Visit `a_json_object'.
+ local
+ l_pairs: HASH_TABLE [JSON_VALUE, JSON_STRING]
+ l_line: like line_number
+ l_multiple_lines: BOOLEAN
+ do
+ l_pairs := a_json_object.map_representation
+ l_multiple_lines := l_pairs.count >= object_count_inlining or across l_pairs as p some attached {JSON_OBJECT} p.item or attached {JSON_ARRAY} p.item end
+ output.append ("{")
+ l_line := line_number
+ indent
+ from
+ l_pairs.start
+ until
+ l_pairs.off
+ loop
+ if
+ line_number > l_line or
+ l_multiple_lines
+ then
+ new_line
+ end
+ l_pairs.key_for_iteration.accept (Current)
+ output.append (": ")
+ l_pairs.item_for_iteration.accept (Current)
+ l_pairs.forth
+ if not l_pairs.after then
+ output.append (", ")
+ end
+ end
+ exdent
+ if
+ line_number > l_line or
+ l_pairs.count >= object_count_inlining
+ then
+ new_line
+ end
+ output.append ("}")
+ end
+
+ visit_json_string (a_json_string: JSON_STRING)
+ -- Visit `a_json_string'.
+ do
+ output.append ("%"")
+ output.append (a_json_string.item)
+ output.append ("%"")
+ end
+
+end
diff --git a/contrib/library/text/parser/json/library/gobo/shared_gobo_ejson.e b/contrib/library/text/parser/json/library/gobo/shared_gobo_ejson.e
index ccc33432..9fbe9b57 100644
--- a/contrib/library/text/parser/json/library/gobo/shared_gobo_ejson.e
+++ b/contrib/library/text/parser/json/library/gobo/shared_gobo_ejson.e
@@ -29,4 +29,4 @@ feature
Result.add_converter (jhtc)
end
-end -- class SHARED_GOBO_EJSON
\ No newline at end of file
+end -- class SHARED_GOBO_EJSON
diff --git a/contrib/library/text/parser/json/library/kernel/converters/json_arrayed_list_converter.e b/contrib/library/text/parser/json/library/kernel/converters/json_arrayed_list_converter.e
new file mode 100644
index 00000000..da089f7b
--- /dev/null
+++ b/contrib/library/text/parser/json/library/kernel/converters/json_arrayed_list_converter.e
@@ -0,0 +1,30 @@
+note
+ description: "A JSON converter for ARRAYED_LIST [ANY]"
+ author: "Paul Cohen"
+ date: "$Date$"
+ revision: "$Revision$"
+ file: "$HeadURL: $"
+
+class JSON_ARRAYED_LIST_CONVERTER
+
+inherit
+ JSON_LIST_CONVERTER
+ redefine
+ object
+ end
+
+create
+ make
+
+feature -- Access
+
+ object: ARRAYED_LIST [detachable ANY]
+
+feature {NONE} -- Factory
+
+ new_object (nb: INTEGER): like object
+ do
+ create Result.make (nb)
+ end
+
+end -- class JSON_ARRAYED_LIST_CONVERTER
diff --git a/contrib/library/text/parser/json/library/kernel/converters/json_converter.e b/contrib/library/text/parser/json/library/kernel/converters/json_converter.e
index bae2bd9c..796ef4eb 100644
--- a/contrib/library/text/parser/json/library/kernel/converters/json_converter.e
+++ b/contrib/library/text/parser/json/library/kernel/converters/json_converter.e
@@ -1,8 +1,8 @@
note
description: "A JSON converter"
author: "Paul Cohen"
- date: "$Date: $"
- revision: "$Revision: $"
+ date: "$Date$"
+ revision: "$Revision$"
file: "$HeadURL: $"
deferred class JSON_CONVERTER
@@ -19,7 +19,7 @@ feature -- Access
feature -- Conversion
- from_json (j: attached like to_json): detachable like object
+ from_json (j: attached like to_json): detachable like object
-- Convert from JSON value.
-- Returns Void if unable to convert
deferred
diff --git a/contrib/library/text/parser/json/library/kernel/converters/json_hash_table_converter.e b/contrib/library/text/parser/json/library/kernel/converters/json_hash_table_converter.e
index 8ce5260e..7971e1c2 100644
--- a/contrib/library/text/parser/json/library/kernel/converters/json_hash_table_converter.e
+++ b/contrib/library/text/parser/json/library/kernel/converters/json_hash_table_converter.e
@@ -1,8 +1,8 @@
note
description: "A JSON converter for HASH_TABLE [ANY, HASHABLE]"
author: "Paul Cohen"
- date: "$Date$"
- revision: "$Revision$"
+ date: "$Date$"
+ revision: "$Revision$"
file: "$HeadURL: $"
class JSON_HASH_TABLE_CONVERTER
@@ -26,7 +26,7 @@ feature -- Access
feature -- Conversion
- from_json (j: attached like to_json): like object
+ from_json (j: attached like to_json): like object
local
keys: ARRAY [JSON_STRING]
i: INTEGER
@@ -41,7 +41,7 @@ feature -- Conversion
until
i > keys.count
loop
- h ?= json.object (keys [i], void)
+ h ?= json.object (keys [i], Void)
check h /= Void end
jv := j.item (keys [i])
if jv /= Void then
diff --git a/contrib/library/text/parser/json/library/kernel/converters/json_linked_list_converter.e b/contrib/library/text/parser/json/library/kernel/converters/json_linked_list_converter.e
index bcc41e49..42a1c2c4 100644
--- a/contrib/library/text/parser/json/library/kernel/converters/json_linked_list_converter.e
+++ b/contrib/library/text/parser/json/library/kernel/converters/json_linked_list_converter.e
@@ -1,63 +1,30 @@
note
- description: "A JSON converter for LINKED_LIST [ANY]"
- author: "Paul Cohen"
- date: "$Date$"
- revision: "$Revision$"
- file: "$HeadURL: $"
+ description: "A JSON converter for LINKED_LIST [ANY]"
+ author: "Paul Cohen"
+ date: "$Date$"
+ revision: "$Revision$"
+ file: "$HeadURL: $"
class JSON_LINKED_LIST_CONVERTER
inherit
- JSON_CONVERTER
+ JSON_LIST_CONVERTER
+ redefine
+ object
+ end
create
make
-feature {NONE} -- Initialization
-
- make
- do
- create object.make
- end
-
feature -- Access
object: LINKED_LIST [detachable ANY]
-feature -- Conversion
+feature {NONE} -- Factory
- from_json (j: like to_json): detachable like object
- local
- i: INTEGER
- do
- create Result.make
- from
- i := 1
- until
- i > j.count
- loop
- Result.extend (json.object (j [i], Void))
- i := i + 1
- end
- end
-
- to_json (o: like object): JSON_ARRAY
- local
- c: ITERATION_CURSOR [detachable ANY]
- do
- create Result.make_array
- from
- c := o.new_cursor
- until
- c.after
- loop
- if attached json.value (c.item) as v then
- Result.add (v)
- else
- check attached_value: False end
- end
- c.forth
- end
- end
+ new_object (nb: INTEGER): like object
+ do
+ create Result.make
+ end
end -- class JSON_LINKED_LIST_CONVERTER
diff --git a/contrib/library/text/parser/json/library/kernel/converters/json_list_converter.e b/contrib/library/text/parser/json/library/kernel/converters/json_list_converter.e
new file mode 100644
index 00000000..75e0f848
--- /dev/null
+++ b/contrib/library/text/parser/json/library/kernel/converters/json_list_converter.e
@@ -0,0 +1,74 @@
+note
+ description: "A JSON converter for LIST [ANY]"
+ author: "Paul Cohen"
+ date: "$Date$"
+ revision: "$Revision$"
+ file: "$HeadURL: $"
+
+deferred class JSON_LIST_CONVERTER
+
+inherit
+ JSON_CONVERTER
+
+feature {NONE} -- Initialization
+
+ make
+ do
+ object := new_object (0)
+ end
+
+feature -- Access
+
+ object: LIST [detachable ANY]
+
+feature {NONE} -- Factory
+
+ new_object (nb: INTEGER): like object
+ deferred
+ ensure
+ Result /= Void
+ end
+
+feature -- Conversion
+
+ from_json (j: attached like to_json): detachable like object
+ local
+ i: INTEGER
+ do
+ Result := new_object (j.count)
+ from
+ i := 1
+ until
+ i > j.count
+ loop
+ Result.extend (json.object (j [i], Void))
+ i := i + 1
+ end
+ end
+
+ to_json (o: like object): detachable JSON_ARRAY
+ local
+ c: ITERATION_CURSOR [detachable ANY]
+ jv: detachable JSON_VALUE
+ failed: BOOLEAN
+ do
+ create Result.make_array
+ from
+ c := o.new_cursor
+ until
+ c.after
+ loop
+ jv := json.value (c.item)
+ if jv /= Void then
+ Result.add (jv)
+ else
+ failed := True
+ end
+ c.forth
+ end
+ if failed then
+ Result := Void
+ end
+ end
+
+end -- class JSON_ARRAYED_LIST_CONVERTER
diff --git a/contrib/library/text/parser/json/library/kernel/ejson.e b/contrib/library/text/parser/json/library/kernel/ejson.e
index de9058d5..b9931aa9 100644
--- a/contrib/library/text/parser/json/library/kernel/ejson.e
+++ b/contrib/library/text/parser/json/library/kernel/ejson.e
@@ -1,8 +1,8 @@
note
description: "Core factory class for creating JSON objects and corresponding Eiffel objects."
author: "Paul Cohen"
- date: "$Date: $"
- revision: "$Revision: $"
+ date: "$Date$"
+ revision: "$Revision$"
file: "$HeadURL: $"
class EJSON
@@ -69,7 +69,7 @@ feature -- Access
elseif attached {STRING_8} an_object as s8 then
create {JSON_STRING} Result.make_json (s8)
elseif attached {STRING_32} an_object as s32 then
- create {JSON_STRING} Result.make_json (s32.as_string_8) -- FIXME: need correct convertion/encoding here ...
+ create {JSON_STRING} Result.make_json_from_string_32 (s32)
end
if Result = Void then
@@ -253,9 +253,9 @@ feature {NONE} -- Implementation (Exceptions)
-- Exception message for failing to convert `a' to a JSON_VALUE.
do
Result := exception_prefix + "Failed to convert Eiffel object to a JSON_VALUE"
- if an_object /= Void then
- Result := ": " + an_object.generator
- end
+ if an_object /= Void then
+ Result := ": " + an_object.generator
+ end
end
feature {NONE} -- Implementation (JSON parser)
diff --git a/contrib/library/text/parser/json/library/kernel/shared_ejson.e b/contrib/library/text/parser/json/library/kernel/shared_ejson.e
index d08a6766..421b83a4 100644
--- a/contrib/library/text/parser/json/library/kernel/shared_ejson.e
+++ b/contrib/library/text/parser/json/library/kernel/shared_ejson.e
@@ -1,14 +1,14 @@
note
description: "[
- Shared factory class for creating JSON objects. Maps JSON
- objects to ELKS HASH_TABLEs and JSON arrays to ELKS
- LINKED_LISTs. Use non-conforming inheritance from this
- class to ensure that your classes share the same
- JSON_FACTORY instance.
+ Shared factory class for creating JSON objects. Maps JSON
+ objects to ELKS HASH_TABLEs and JSON arrays to ELKS
+ LINKED_LISTs. Use non-conforming inheritance from this
+ class to ensure that your classes share the same
+ JSON_FACTORY instance.
]"
author: "Paul Cohen"
- date: "$Date: $"
- revision: "$Revision: $"
+ date: "$Date$"
+ revision: "$Revision: 89185 $"
file: "$HeadURL: $"
class SHARED_EJSON
@@ -17,16 +17,22 @@ feature
json: EJSON
-- A shared EJSON instance with default converters for
- -- DS_LINKED_LIST [ANY] and DS_HASH_TABLE [ANY, HASHABLE]
+ --LINKED_LIST [ANY] and HASH_TABLE [ANY, HASHABLE]
local
+ jalc: JSON_ARRAYED_LIST_CONVERTER
jllc: JSON_LINKED_LIST_CONVERTER
jhtc: JSON_HASH_TABLE_CONVERTER
once
create Result
+
+ create jalc.make
+ Result.add_converter (jalc)
+
create jllc.make
Result.add_converter (jllc)
+
create jhtc.make
Result.add_converter (jhtc)
end
-end -- class SHARED_EJSON
\ No newline at end of file
+end -- class SHARED_EJSON
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/json_author_converter.e b/contrib/library/text/parser/json/test/autotest/test_suite/json_author_converter.e
index ec734045..c8f9e6d0 100644
--- a/contrib/library/text/parser/json/test/autotest/test_suite/json_author_converter.e
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/json_author_converter.e
@@ -1,9 +1,8 @@
note
description: "A JSON converter for AUTHOR"
author: "Paul Cohen"
- date: "$Date: 2010-03-08 20:46:59 -0300 (Mon, 08 Mar 2010) $"
- revision: "$Revision: 82 $"
- file: "$HeadURL: https://svn.origo.ethz.ch/ejson/branches/POC-converters-factory/test/json_author_converter.e $"
+ date: "$Date$"
+ revision: "$Revision$"
class JSON_AUTHOR_CONVERTER
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/json_book_collection_converter.e b/contrib/library/text/parser/json/test/autotest/test_suite/json_book_collection_converter.e
index 06b33cd0..1c569ce3 100644
--- a/contrib/library/text/parser/json/test/autotest/test_suite/json_book_collection_converter.e
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/json_book_collection_converter.e
@@ -1,9 +1,8 @@
note
description: "A JSON converter for BOOK_COLLECTION"
author: "Paul Cohen"
- date: "$Date: 2010-03-08 20:46:59 -0300 (Mon, 08 Mar 2010) $"
- revision: "$Revision: 82 $"
- file: "$HeadURL: https://svn.origo.ethz.ch/ejson/branches/POC-converters-factory/test/json_book_collection_converter.e $"
+ date: "$Date$"
+ revision: "$Revision$"
class JSON_BOOK_COLLECTION_CONVERTER
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/json_book_converter.e b/contrib/library/text/parser/json/test/autotest/test_suite/json_book_converter.e
index e355149f..de31f79e 100644
--- a/contrib/library/text/parser/json/test/autotest/test_suite/json_book_converter.e
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/json_book_converter.e
@@ -1,9 +1,8 @@
note
description: "A JSON converter for BOOK"
author: "Paul Cohen"
- date: "$Date: 2010-03-08 20:46:59 -0300 (Mon, 08 Mar 2010) $"
- revision: "$Revision: 82 $"
- file: "$HeadURL: https://svn.origo.ethz.ch/ejson/branches/POC-converters-factory/test/json_book_converter.e $"
+ date: "$Date$"
+ revision: "$Revision$"
class JSON_BOOK_CONVERTER
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/test_json_core.e b/contrib/library/text/parser/json/test/autotest/test_suite/test_json_core.e
index d2faa7e1..ad8326b9 100644
--- a/contrib/library/text/parser/json/test/autotest/test_suite/test_json_core.e
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/test_json_core.e
@@ -632,7 +632,7 @@ feature -- Test
jrep := "%"foo\\bar%""
create parser.make_parser (jrep)
if attached {JSON_STRING} parser.parse as jstring then
- assert ("unescaped string %"foo\\bar%" to %"foo\bar%"", jstring.unescaped_string_8.same_string ("foo\bar"))
+ assert ("unescaped string %"foo\\bar%" to %"foo\bar%"", jstring.unescaped_string.same_string ("foo\bar"))
end
create js.make_json_from_string_32 ({STRING_32}"%/20320/%/22909/")
diff --git a/doc/wiki/Home.md b/doc/wiki/Home.md
index a7d253e0..4da5d7b7 100644
--- a/doc/wiki/Home.md
+++ b/doc/wiki/Home.md
@@ -1,16 +1,26 @@
-## Eiffel-Web-Framework ##
+# Eiffel-Web-Framework #
+## Location ##
The official documentation/wiki is located at https://github.com/EiffelWebFramework/EWF/wiki , if you are visiting a "clone/fork", please always check the [[official wiki|https://github.com/EiffelWebFramework/EWF/wiki]].
-
+## Organization ##
- Mailing list: please visit and subscribe to the mailing list page [[http://groups.google.com/group/eiffel-web-framework]] 
- Most of the topics are discussed on the mailing list (google group).
- For time to time we have web meeting, and less frequently physical meetings that occurs usually during other Eiffel related events.
-- See also
- - You want to contribute or follow the progress/discussion, see the [[collaboration page| Community-collaboration]]
+## Documentation ##
+- to redo
+
+## Contributions ##
+- You want to contribute or follow the progress/discussion, see the [[collaboration page| Community-collaboration]]
+- Potential tasks/projects on EWF: [[Projects page| Projects]]
+
+## See also ##
- [[list of tasks, and a potential roadmap| Tasks-Roadmap]]
- [[General source structure of this project| Source-structure]]
- EWSGI: [[Eiffel Web Server Gateway Interface| EWSGI]]
- [[Overview of the server side architecture| Spec-Server-Architecture]]
- This project is also a collection of [[Libraries]] related to the Web
+
+## Note ##
+ - This wiki needs to be updated, in the meantime, please have a look at the presentation: https://docs.google.com/presentation/pub?id=1GPFv6aHhTjFSLMnlAt-J4WeIHSGfHdB42dQxmOVOH8s&start=false&loop=false&delayms=3000
diff --git a/doc/wiki/Projects-new-suggestions.md b/doc/wiki/Projects-new-suggestions.md
new file mode 100644
index 00000000..b7278fee
--- /dev/null
+++ b/doc/wiki/Projects-new-suggestions.md
@@ -0,0 +1,14 @@
+Use this to suggest new projects, or request features.
+The content of this page will be moved to the main [[Projects]] page for time to time.
+For any entry, please use this template
+
+----
+
+## Short title
+* _Suggested by **your name**_": so that we know who suggested a feature.
+* **Requirement**: ... if any, otherwise remove this line
+* _Description_: ... a few lines to describe the project
+* _References_: ... if any, otherwise remove this line
+
+----
+
diff --git a/doc/wiki/Projects.md b/doc/wiki/Projects.md
new file mode 100644
index 00000000..ad4f235f
--- /dev/null
+++ b/doc/wiki/Projects.md
@@ -0,0 +1,231 @@
+This page lists potential projects on EWF, this is open for contribution.
+If you are a student, don't hesitate to pick one, or even suggest a new project, or a project being a merge of several, in any case, you will get close support from EWF's team.
+
+----
+# Study/Analysis/Documentation
+
+## Evaluate EWF according to the following constraints ...
+* _Suggested by **Javier**_
+* _Description_: According to http://www.amundsen.com/blog/archives/1130 , evaluate the current design of EWF to see if this match the different points. An other option would be to take the following REST implementation toolkit as a guide to evaluate EWF http://code.google.com/p/implementing-rest/wiki/RESTImplementationToolkit.
+
+## Road to Hypermedia API
+* _Suggested by **Javier**_
+* _Supervisor_:
+* _Suitability_:
+* _Description_: describe differents types of Web API, and how you can build them using EWF. Describing Pros and Cons. This should be on http://martinfowler.com/articles/richardsonMaturityModel.html
+
+## Build a video to demonstrate how an Hypermedia API works, and how to build it using EWF
+* _Suggested by **Javier**_
+* _Supervisor_:
+* _Suitability_: TODO
+* _Description_: produce a audio+video+slide that demonstrates how to build an hypermedia API using EWF. This could be based on upcoming "graphviz server" example, or an extension of existing RestBucksCRUD example, or any new example.
+
+----
+# Works related to EWF / framework / tools
+
+## Improve EWF
+* _Suggested by **Jocelyn**_
+* _Supervisor_:
+* _Suitability_: TODO
+* _Description_: Improve existing EWF source, this is a permanent task for EWF, and this can be code, documentation, tests, ... Among others , here is a list of needed effort:
+** Improve encoding support
+*∗ Better MIME handler
+** _Support for configuration _
+** Ready to use logging facilities
+** Smart handler for HEAD or similar
+** Adding component to ease the caching functionalities
+** Adding Session support
+** URL rewriting ?
+** Mass testing
+** ...
+
+## Eiffel Web Nino
+* _Suggested by **Javier & Jocelyn**_
+* _Supervisor_:
+* _Suitability_: TODO
+* _Description_: Currently Eiffel Web Nino, is a standalone httpd server written in Eiffel. It is great for development, or embedding httpd component in application. However there are room for improvement so that one can also use it as replacement for apache, iis, ... To reach this state, here are a list of task that should be achieved:
+** Implement persistent connection
+** Complete implementation of Eiffel Web Nino using pool of threads
+** Complete migration of Eiffel Web Nino to SCOOP
+** Improve Nino to become a real solution to host any web services/sites
+** ...
+
+## New EWF connectors
+* _Suggested by **Jocelyn & Javier**_
+* _Supervisor_:
+* _Suitability_: TODO
+* _Description_: EWF is relying on the notion of "connector" to achieve portability on various platform and underlying httpd server, currently EWF support any CGI or libFCGI system (i.e apache, IIS, ...), and provide a standalone version thanks to Eiffel Web Nino. The goal now, would be to support specific connector for:
+** LightHTTP (http://www.lighttpd.net/)
+** nginx (http://nginx.org/en/)
+
+## Concurrenty and EWF
+* _Suggested by **Jocelyn**_
+* _Supervisor_:
+* _Suitability_: TODO
+* _Description_: Check that EWF is compliant with concurrency (Eiffel Thread, and SCOOP), and provide an example using concurrency.
+
+## Design and build something like Ruby on Rails or Grails
+* _Suggested by **Javier**_
+* _Supervisor_:
+* _Suitability_: TODO
+* _Description_: Using EWF, design and build the set of tools to provide a conventional MVC to create Web sites. This could be useful even if this is not the taste of everyone.
+
+## Provide a Websocket implementation
+* _Suggested by **Jocelyn**_
+* _Supervisor_:
+* _Suitability_: TODO
+* _Description_: Provide an implementation of websocket with EWF and eventually Eiffel Web Nino, then demonstrate it on a simple example. WebSocket is a web technology providing for bi-directional, full-duplex communications channels over a single TCP connection.
+* See http://en.wikipedia.org/wiki/Websocket
+
+----
+# Usage of EWF
+
+## HAL browser
+* _Suggested by **Javier**_
+* _Supervisor_:
+* _Suitability_: TODO
+* _Description_: Build a HAL browser to discover an API using HAL mediatype. The browser will be able to follow the links, and display the transmitted data. This could be a vision2 application inspired by http://haltalk.herokuapp.com/explorer/hal_browser.html#/. HAL stands for Hypertext Application Language see http://stateless.co/hal_specification.html.
+
+## Collection-JSON browser
+* _Suggested by **Javier**_
+* _Supervisor_:
+* _Suitability_: TODO
+* _Description_: Build a Collection/JSON browser to discover an API using Collection/JSON mediatype. The browser will be able to follow the links, and display the transmitted data. This could be a vision2 application inspired by http://haltalk.herokuapp.com/explorer/hal_browser.html#/. Collection+JSON is a JSON-based read/write hypermedia-type, see http://www.amundsen.com/media-types/collection/
+
+## Build a simple CMS with EWF
+* _Suggested by **Jocelyn**_
+* _Supervisor_:
+* _Suitability_: TODO
+* _Description_: Using EWF, Build a simple CMS (Content Management System) framework and then an example. It should provide common features such as:
+ - user management (register, login, lost password -> send email)
+ - page editing
+ - blog
+ - template / theme
+ - persistency / storage / ...
+ - extension at compilation time
+* The result should be usable by any user to build his own CMS website, and extend it easily.
+
+## Build P2P connector
+* _Suggested by **Jocelyn**_
+* _Supervisor_:
+* _Suitability_: TODO
+* _Description_: Imagine you want to publish a website (or web service, API) running on your machine (behind firewall). One would need to initiate the connection via a public website, this is common for P2P software such as remote assistance (i.e: join.me, teamviewer, showmypc, ...)
+
+----
+# Libraries
+
+## Hypermedia API library to work with XHTML
+* _Suggested by **Javier**_
+* _Supervisor_:
+* _Suitability_: TODO
+* _Description_: Use XHTML as a media type to for hypermedia API. See http://codeartisan.blogspot.com.ar/2012/07/using-html-as-media-type-for-your-api.html
+
+## Add support for Mediatype such as RSS, ATOM, ...
+* _Suggested by **Jocelyn**_
+* _Supervisor_:
+* _Suitability_: TODO
+* _Description_: In addition to JSON, HAL, Collection+JSON, XHTML, application might want to support (read and write) standard media type such as RSS, ATOM, ...
+
+## Security: provide popular authentication mechanisms
+* _Suggested by **Jocelyn**_
+* _Supervisor_:
+* _Suitability_: TODO
+* _Description_: Any web service, web site, API need a reliable authentication mechanism, the could be on the server side or the client side to build mashup service (integrate with other web API such as google, flicker, ...). So far, EWF provides only basic HTTP Authorization, and application would need more solutions such as :
+ - OAuth: consumer and provider
+ - OpenID
+ - Google Connect
+ - Facebook Connect
+* The goal is to provide component to consume other popular API/service, but also component for your own service so that other can consume it.
+
+## Security: provide popular authentication mechanisms
+* _Suggested by **Jocelyn**_
+* _Supervisor_:
+* _Suitability_: TODO
+* _Description_: Any web service, web site, API need a reliable authentication mechanism, the could be on the server side or the client side to build mashup service (integrate with other web API such as google, flicker, ...). So far, EWF provides only basic HTTP Authorization, and application would need more solutions such as :
+ - OAuth: consumer and provider
+ - OpenID
+ - Google Connect
+ - Facebook Connect
+* The goal is to provide component to consume other popular API/service, but also component for your own service so that other can consume it.
+
+## Provide a SSO (Single Sign On) implementation (server, and clients)
+* _Suggested by **Jocelyn**_
+* _Supervisor_:
+* _Suitability_: TODO
+* _Description_: Design and build a Single Sign On implementation for Eiffel. That should include the authentication server, and at least one Eiffel client component (it would be convenient to also provide php, js, ...). In the same spirit, having Eiffel client for popular SSO server would be appreciated as well.
+* _Reference_:
+ - http://en.wikipedia.org/wiki/Single_sign-on
+ - http://en.wikipedia.org/wiki/List_of_single_sign-on_implementations
+
+## library: Template engine
+* _Suggested by **Jocelyn**_
+* _Supervisor_:
+* _Suitability_: TODO
+* _Description_: Get inspired by any existing template engine, and build one for Eiffel, this should be easily usable within a web application. This could be inspired, or implementation of standard template engine, this way people can reuse existing content, or migrate easily their application to EWF. For inspiration, one can look at:
+ - http://www.smarty.net/
+ - http://mustache.github.com/
+ - http://en.wikipedia.org/wiki/Template_engine_(web) ... they are plenty of them, a comparison of the different engine would help.
+* This is not specific to EWF, but it will be very useful in website context.
+
+## library: Wikitext, markdown parser and render engine
+* _Suggested by **Jocelyn**_
+* _Supervisor_:
+* _Suitability_: TODO
+* _Description_: Build component to support (read and write, and why not convert), lightweight markup language (see http://en.wikipedia.org/wiki/Lightweight_markup_language) such as wikitext, markdown, and other. The component should be able to read/scan, but also produce an HTML output. Focus first on wikitext, and markdown since they seems to be the most popular.
+* Then , a nice addition would be to render those lightweight markup lang into Vision2 widget (not related to EWF, but could be useful to build (editor) desktop application)
+
+## library: Web component to build HTML5 widget
+* _Suggested by **Jocelyn**_
+* _Supervisor_:
+* _Suitability_: TODO
+* _Description_: Build set of Eiffel components to ease development of websites. First this should be based on HTML5. Idea for components:
+ - table widget (with sorting ...)
+ - suggestive typing widget
+ - tab ...
+ - WYSIWYG textarea widget (could reuse existing Javascript solution TinyMCE, CKEditor, OpenWysiwyg, ...)
+ - ...
+
+----
+# Clients
+
+## Libraries: Reusable Client Design based on J.Moore Presentation
+* _Suggested by **Javier**_
+* _Supervisor_:
+* _Suitability_: TODO
+* _Description_: TODO
+* Generic client that can be customized (see design in slide 12)
+* http://s3.amazonaws.com/cimlabs/Oredev-Hypermedia-APIs.pdf
+* video http://vimeo.com/20781278
+
+## Create a Client Cache based on Apache commons Client Cache.
+* _Suggested by **Javier**_
+* _Supervisor_:
+* _Suitability_: TODO
+* _Description_: TODO
+* http://hc.apache.org/httpcomponents-client-ga/httpclient-cache/index.html
+* http://labs.xfinity.com/benchmarking-the-httpclient-caching-module
+
+## Add SSL support to Eiffel Net
+* _Suggested by **Jocelyn**_
+* _Supervisor_:
+* _Suitability_: TODO
+* _Description_: Currently Eiffel Net does not provide any support to SSL (thus no HTTPS). For now Eiffel application often use the Eiffel cURL wrapper which provide SSL, but it would be more convenient to use directly Eiffel Net. Then find solution to add SSL support to EiffelNet, or to extend EiffelNet with an EiffelNet+OpenSSL solution, or other.
+
+## Build clients to consume popular RESTful APIs
+* _Suggested by **Jocelyn & Javier**_
+* _Supervisor_:
+* _Suitability_: TODO
+* _Description_: Build Eiffel libraries to consume popular web APIs, such as:
+ - Google Discovery APIs
+ - Twitter
+ - Facebook
+ - Github
+ - Flickr
+ - ... etc
+* This should reuse and improve the "http_client" provided by EWF. Eventually also write the EiffelNet implementation to be independant from cURL
+* **Requirement**: OAuth client eiffel component
+
+----
+# Feel free to add new idea below this line
+----
+Use the following page [[Projects new suggestions]] to suggest new project, or request a feature.
\ No newline at end of file
diff --git a/examples/filter/filter-safe.ecf b/examples/filter/filter-safe.ecf
new file mode 100644
index 00000000..c0af4037
--- /dev/null
+++ b/examples/filter/filter-safe.ecf
@@ -0,0 +1,33 @@
+
+
+
+
+
+ /EIFGENs$
+ /\.git$
+ /\.svn$
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/filter/readme.md b/examples/filter/readme.md
new file mode 100644
index 00000000..b1a43c03
--- /dev/null
+++ b/examples/filter/readme.md
@@ -0,0 +1,4 @@
+Filter example
+
+To test the example, you can just run in a terminal:
+> curl -u foo:bar http://localhost:9090/user/1 -v
diff --git a/examples/filter/src/database/database_api.e b/examples/filter/src/database/database_api.e
new file mode 100644
index 00000000..fb97a5d5
--- /dev/null
+++ b/examples/filter/src/database/database_api.e
@@ -0,0 +1,30 @@
+note
+ description: "Summary description for {DATABASE_API}."
+ author: ""
+ date: "$Date$"
+ revision: "$Revision$"
+
+class
+ DATABASE_API
+create
+ make
+
+feature -- Initialization
+
+ make
+ local
+ l_user: USER
+ do
+ create users.make (10)
+ create l_user.make (1, "foo", "bar")
+ users.put (l_user, l_user.id)
+ end
+
+feature -- Access
+
+ users: HASH_TABLE [USER, INTEGER]
+
+;note
+ copyright: "2011-2011, Javier Velilla and others"
+ license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
+end
diff --git a/examples/filter/src/database/shared_database_api.e b/examples/filter/src/database/shared_database_api.e
new file mode 100644
index 00000000..658b4bd5
--- /dev/null
+++ b/examples/filter/src/database/shared_database_api.e
@@ -0,0 +1,20 @@
+note
+ description: "Summary description for {SHARED_DATABASE_API}."
+ author: ""
+ date: "$Date$"
+ revision: "$Revision$"
+
+class
+ SHARED_DATABASE_API
+
+feature -- Access
+
+ db_access: DATABASE_API
+ once
+ create Result.make
+ end
+
+note
+ copyright: "2011-2011, Javier Velilla and others"
+ license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
+end
diff --git a/examples/filter/src/domain/json_user_converter.e b/examples/filter/src/domain/json_user_converter.e
new file mode 100644
index 00000000..d137330b
--- /dev/null
+++ b/examples/filter/src/domain/json_user_converter.e
@@ -0,0 +1,52 @@
+note
+ description: "JSON user converter."
+ author: "Olivier Ligot"
+ date: "$Date$"
+ revision: "$Revision$"
+
+class
+ JSON_USER_CONVERTER
+
+inherit
+ JSON_CONVERTER
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make
+ do
+ create object.make (0, "", "")
+ end
+
+feature -- Access
+
+ object: USER
+
+ value: detachable JSON_OBJECT
+
+feature -- Conversion
+
+ from_json (j: attached like value): detachable like object
+ -- Convert from JSON value.
+ do
+ end
+
+ to_json (o: like object): like value
+ -- Convert to JSON value.
+ do
+ create Result.make
+ Result.put (json.value (o.id), id_key)
+ Result.put (json.value (o.name), name_key)
+ end
+
+ feature {NONE} -- Implementation
+
+ id_key: STRING = "id"
+ name_key: STRING = "name"
+
+note
+ copyright: "2011-2011, Javier Velilla and others"
+ license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
+end
diff --git a/examples/filter/src/domain/user.e b/examples/filter/src/domain/user.e
new file mode 100644
index 00000000..4d5756c4
--- /dev/null
+++ b/examples/filter/src/domain/user.e
@@ -0,0 +1,40 @@
+note
+ description: "User."
+ author: ""
+ date: "$Date$"
+ revision: "$Revision$"
+
+class
+ USER
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make (an_id: INTEGER; a_name, a_password: STRING)
+ do
+ id := an_id
+ name := a_name
+ password := a_password
+ ensure
+ id_set: id = an_id
+ name_set: name = a_name
+ password_set: password = a_password
+ end
+
+feature -- Access
+
+ id: INTEGER
+ -- Identifier
+
+ name: STRING
+ -- Name
+
+ password: STRING
+ -- Password
+
+;note
+ copyright: "2011-2011, Javier Velilla and others"
+ license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
+end
diff --git a/examples/filter/src/filter/authentication_filter.e b/examples/filter/src/filter/authentication_filter.e
new file mode 100644
index 00000000..3f4809bc
--- /dev/null
+++ b/examples/filter/src/filter/authentication_filter.e
@@ -0,0 +1,50 @@
+note
+ description: "Authentication filter."
+ author: "Olivier Ligot"
+ date: "$Date$"
+ revision: "$Revision$"
+
+class
+ AUTHENTICATION_FILTER [C -> WSF_URI_TEMPLATE_HANDLER_CONTEXT]
+
+inherit
+ WSF_FILTER_HANDLER [C]
+
+ SHARED_DATABASE_API
+
+feature -- Basic operations
+
+ execute (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
+ -- Execute the filter
+ local
+ l_auth: HTTP_AUTHORIZATION
+ do
+ create l_auth.make (req.http_authorization)
+ if (attached l_auth.type as l_auth_type and then l_auth_type.is_equal ("basic")) and
+ attached Db_access.users.item (1) as l_user and then
+ (attached l_auth.login as l_auth_login and then l_auth_login.is_equal (l_user.name)
+ and attached l_auth.password as l_auth_password and then l_auth_password.is_equal (l_user.password)) then
+ execute_next (ctx, req, res)
+ else
+ handle_unauthorized ("Unauthorized", ctx, req, res)
+ end
+ end
+
+feature {NONE} -- Implementation
+
+ handle_unauthorized (a_description: STRING; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
+ -- Handle forbidden.
+ local
+ h: HTTP_HEADER
+ do
+ create h.make
+ h.put_content_type_text_plain
+ h.put_content_length (a_description.count)
+ h.put_current_date
+ h.put_header_key_value ({HTTP_HEADER_NAMES}.header_www_authenticate, "Basic realm=%"User%"")
+ res.set_status_code ({HTTP_STATUS_CODE}.unauthorized)
+ res.put_header_text (h.string)
+ res.put_string (a_description)
+ end
+
+end
diff --git a/examples/filter/src/filter/logging_filter.e b/examples/filter/src/filter/logging_filter.e
new file mode 100644
index 00000000..330012c4
--- /dev/null
+++ b/examples/filter/src/filter/logging_filter.e
@@ -0,0 +1,40 @@
+note
+ description: "Logging filter."
+ author: "Olivier Ligot"
+ date: "$Date$"
+ revision: "$Revision$"
+
+class
+ LOGGING_FILTER
+
+inherit
+ WSF_FILTER
+
+feature -- Basic operations
+
+ execute (req: WSF_REQUEST; res: WSF_RESPONSE)
+ -- Execute the filter
+ local
+ l_user_agent: STRING
+ l_date: DATE_TIME
+ do
+ if attached req.http_user_agent as ua then
+ l_user_agent := ua.as_string_8
+ else
+ l_user_agent := "-"
+ end
+ create l_date.make_now
+ io.put_string ("[" + l_date.formatted_out (Date_time_format) + "] %"" + req.request_method + " " + req.request_uri
+ + " " + {HTTP_CONSTANTS}.http_version_1_1 + "%" " + res.status_code.out + " " + l_user_agent)
+ io.put_new_line
+ execute_next (req, res)
+ end
+
+feature -- Constants
+
+ Date_time_format: STRING = "yyyy/[0]mm/[0]dd [0]hh:[0]mi:[0]ss.ff3"
+
+note
+ copyright: "2011-2012, Javier Velilla and others"
+ license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
+end
diff --git a/examples/filter/src/filter_server.e b/examples/filter/src/filter_server.e
new file mode 100644
index 00000000..b956fc16
--- /dev/null
+++ b/examples/filter/src/filter_server.e
@@ -0,0 +1,109 @@
+note
+ description : "Filter example."
+ author : "Olivier Ligot"
+ date : "$Date$"
+ revision : "$Revision$"
+
+class
+ FILTER_SERVER
+
+inherit
+ ANY
+
+ WSF_URI_TEMPLATE_FILTERED_SERVICE
+
+ WSF_HANDLER_HELPER
+
+ WSF_DEFAULT_SERVICE
+
+ SHARED_EJSON
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make
+ do
+ initialize_filter
+ initialize_json
+ set_service_option ("port", 9090)
+ make_and_launch
+ end
+
+ create_filter
+ -- Create `filter'
+ local
+ l_router: WSF_URI_TEMPLATE_ROUTER
+ l_authentication_filter: AUTHENTICATION_FILTER [WSF_URI_TEMPLATE_HANDLER_CONTEXT]
+ l_user_filter: USER_HANDLER [WSF_URI_TEMPLATE_HANDLER_CONTEXT]
+ l_user_handler: WSF_HANDLER [WSF_URI_TEMPLATE_HANDLER_CONTEXT]
+ l_routing_filter: WSF_ROUTING_FILTER [WSF_HANDLER [WSF_URI_TEMPLATE_HANDLER_CONTEXT], WSF_URI_TEMPLATE_HANDLER_CONTEXT]
+ do
+ create l_router.make (1)
+ create l_authentication_filter
+ create l_user_filter
+ l_authentication_filter.set_next (l_user_filter)
+ l_user_handler := l_authentication_filter
+ l_router.map_with_request_methods ("/user/{userid}", l_user_handler, << "GET" >>)
+ create l_routing_filter.make (l_router)
+ l_routing_filter.set_execute_default_action (agent execute_default)
+ filter := l_routing_filter
+ end
+
+ setup_filter
+ -- Setup `filter'
+ local
+ l_logging_filter: LOGGING_FILTER
+ do
+ create l_logging_filter
+ filter.set_next (l_logging_filter)
+ end
+
+ initialize_json
+ -- Initialize `json'.
+ do
+ json.add_converter (create {JSON_USER_CONVERTER}.make)
+ end
+
+feature -- Basic operations
+
+ execute (req: WSF_REQUEST; res: WSF_RESPONSE)
+ do
+ filter.execute (req, res)
+ end
+
+ execute_default (req: WSF_REQUEST; res: WSF_RESPONSE)
+ -- I'm using this method to handle the method not allowed response
+ -- in the case that the given uri does not have a corresponding http method
+ -- to handle it.
+ local
+ h : HTTP_HEADER
+ l_description : STRING
+ l_api_doc : STRING
+ do
+ if req.content_length_value > 0 then
+ req.input.read_string (req.content_length_value.as_integer_32)
+ end
+ create h.make
+ h.put_content_type_text_plain
+ l_api_doc := "%NPlease check the API%NURI:/user/{userid} METHOD: GET%N"
+ l_description := req.request_method + req.request_uri + " is not allowed" + "%N" + l_api_doc
+ h.put_content_length (l_description.count)
+ h.put_current_date
+ res.set_status_code ({HTTP_STATUS_CODE}.method_not_allowed)
+ res.put_header_text (h.string)
+ res.put_string (l_description)
+ end
+
+note
+ copyright: "2011-2012, Javier Velilla and others"
+ license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
+ source: "[
+ Eiffel Software
+ 5949 Hollister Ave., Goleta, CA 93117 USA
+ Telephone 805-685-1006, Fax 805-685-6869
+ Website http://www.eiffel.com
+ Customer support http://support.eiffel.com
+ ]"
+end
diff --git a/examples/filter/src/resource/user_handler.e b/examples/filter/src/resource/user_handler.e
new file mode 100644
index 00000000..f6e9a7c1
--- /dev/null
+++ b/examples/filter/src/resource/user_handler.e
@@ -0,0 +1,86 @@
+note
+ description: "User handler."
+ author: "Olivier Ligot"
+ date: "$Date$"
+ revision: "$Revision$"
+
+class
+ USER_HANDLER [C -> WSF_HANDLER_CONTEXT]
+
+inherit
+ WSF_FILTER_HANDLER [C]
+
+ WSF_RESOURCE_HANDLER_HELPER [C]
+ redefine
+ do_get
+ end
+
+ SHARED_DATABASE_API
+
+ SHARED_EJSON
+
+feature -- Basic operations
+
+ execute (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
+ -- Execute request handler
+ do
+ execute_methods (ctx, req, res)
+ end
+
+ do_get (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
+ -- Using GET to retrieve resource information.
+ -- If the GET request is SUCCESS, we response with
+ -- 200 OK, and a representation of the user
+ -- If the GET request is not SUCCESS, we response with
+ -- 404 Resource not found
+ local
+ id : STRING
+ do
+ if attached req.orig_path_info as orig_path then
+ id := get_user_id_from_path (orig_path)
+ if attached retrieve_user (id) as l_user then
+ compute_response_get (ctx, req, res, l_user)
+ else
+ handle_resource_not_found_response ("The following resource " + orig_path + " is not found ", ctx, req, res)
+ end
+ end
+ end
+
+feature {NONE} -- Implementation
+
+ compute_response_get (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE; l_user : USER)
+ local
+ h: HTTP_HEADER
+ l_msg : STRING
+ do
+ create h.make
+ h.put_content_type_application_json
+ if attached {JSON_VALUE} json.value (l_user) as jv then
+ l_msg := jv.representation
+ h.put_content_length (l_msg.count)
+ if attached req.request_time as time then
+ h.add_header ("Date:" + time.formatted_out ("ddd,[0]dd mmm yyyy [0]hh:[0]mi:[0]ss.ff2") + " GMT")
+ end
+ res.set_status_code ({HTTP_STATUS_CODE}.ok)
+ res.put_header_text (h.string)
+ res.put_string (l_msg)
+ end
+ end
+
+ get_user_id_from_path (a_path: READABLE_STRING_32) : STRING
+ do
+ Result := a_path.split ('/').at (3)
+ end
+
+ retrieve_user (id: STRING) : detachable USER
+ -- Retrieve the user by id if it exist, in other case, Void
+ do
+ if id.is_integer and then Db_access.users.has (id.to_integer) then
+ Result := db_access.users.item (id.to_integer)
+ end
+ end
+
+note
+ copyright: "2011-2012, Javier Velilla and others"
+ license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
+end
diff --git a/examples/tutorial/step_2.wiki b/examples/tutorial/step_2.wiki
index 77dc4ae7..c6b759a1 100644
--- a/examples/tutorial/step_2.wiki
+++ b/examples/tutorial/step_2.wiki
@@ -17,10 +17,15 @@ or go to [[step_3.wiki|step 3]]
** This is used to build the application in a portable manner, but for this compilation, it uses Eiffel Web Nino as connector.
** We use Eiffel Web Nino for this tutorial, because there is no need to configure any apache, iis, and so on. And it is convenient to execute inside EiffelStudio
+* To see the result, you should open http://localhost/ on your web browser. Note if the application is using another port such as 9999, you should open http://localhost:9999/
+
* You will find inside [[step_2]] the "hello" project
** target "hello" provides a very simple implementation (But by default, it is using port 80 with Eiffel Web Nino, which might already be busy by other application)
** target "hello_custom" which uses almost the same code, but in addition, you can use the ewf.ini file to precise the port number (9999 for this example)
+* To see the result, open http://localhost/ in a web browser.
+* Note, if the application is using port different from 80, such as 9999, open http://localhost:9999/
+
* Eiffel code
class
HELLO_APPLICATION
diff --git a/library/network/protocol/http/src/http_header.e b/library/network/protocol/http/src/http_header.e
index 6ea26e1a..7b8aba9e 100644
--- a/library/network/protocol/http/src/http_header.e
+++ b/library/network/protocol/http/src/http_header.e
@@ -390,23 +390,33 @@ feature -- Date
put_utc_date (create {DATE_TIME}.make_now_utc)
end
- put_utc_date (dt: DATE_TIME)
+ put_utc_date (a_utc_date: DATE_TIME)
-- Put UTC date time `dt' with "Date" header
do
- put_date (date_to_rfc1123_http_date_format (dt))
+ put_date (date_to_rfc1123_http_date_format (a_utc_date))
end
- put_last_modified (dt: DATE_TIME)
+ put_last_modified (a_utc_date: DATE_TIME)
-- Put UTC date time `dt' with "Date" header
do
- put_header_key_value ({HTTP_HEADER_NAMES}.header_last_modified, date_to_rfc1123_http_date_format (dt))
+ put_header_key_value ({HTTP_HEADER_NAMES}.header_last_modified, date_to_rfc1123_http_date_format (a_utc_date))
end
-feature -- Others
+feature -- Others
- put_expires (n: INTEGER)
+ put_expires (sec: INTEGER)
do
- put_header_key_value ("Expires", n.out)
+ put_expires_string (sec.out)
+ end
+
+ put_expires_string (s: STRING)
+ do
+ put_header_key_value ("Expires", s)
+ end
+
+ put_expires_date (a_utc_date: DATE_TIME)
+ do
+ put_header_key_value ("Expires", date_to_rfc1123_http_date_format (a_utc_date))
end
put_cache_control (s: READABLE_STRING_8)
diff --git a/library/server/wsf/src/filter/README.md b/library/server/wsf/src/filter/README.md
new file mode 100644
index 00000000..cf7d6703
--- /dev/null
+++ b/library/server/wsf/src/filter/README.md
@@ -0,0 +1,27 @@
+# Introduction
+
+The basic idea of a filter is to pre-process incoming data and post-process outgoing data.
+Filters are part of a filter chain, thus following the [chain of responsability design pattern](http://en.wikipedia.org/wiki/Chain-of-responsibility_pattern).
+
+Each filter decides to call the next filter or not.
+
+# Levels
+
+In EWF, there are two levels of filters.
+
+## WSF_FILTER
+
+Typical examples of such filters are: logging, compression, routing (WSF_ROUTING_FILTER), ...
+
+## WSF_FILTER_HANDLER
+
+Handler that can also play the role of a filter.
+
+Typical examples of such filters are: authentication, ...
+
+# References
+
+Filters (also called middelwares) in other environments:
+* in Python: http://www.wsgi.org/en/latest/libraries.html
+* in Node.js: http://expressjs.com/guide.html#middleware
+* in Apache: http://httpd.apache.org/docs/2.2/en/filter.html
diff --git a/library/server/wsf/src/filter/wsf_filter.e b/library/server/wsf/src/filter/wsf_filter.e
new file mode 100644
index 00000000..141e097c
--- /dev/null
+++ b/library/server/wsf/src/filter/wsf_filter.e
@@ -0,0 +1,52 @@
+note
+ description: "Objects than can pre-process incoming data and post-process outgoing data."
+ author: "Olivier Ligot"
+ date: "$Date$"
+ revision: "$Revision$"
+
+deferred class
+ WSF_FILTER
+
+feature -- Access
+
+ next: detachable WSF_FILTER
+ -- Next filter
+
+feature -- Element change
+
+ set_next (a_next: WSF_FILTER)
+ -- Set `next' to `a_next'
+ do
+ next := a_next
+ ensure
+ next_set: next = a_next
+ end
+
+feature -- Basic operations
+
+ execute (req: WSF_REQUEST; res: WSF_RESPONSE)
+ -- Execute the filter.
+ deferred
+ end
+
+feature {NONE} -- Implementation
+
+ execute_next (req: WSF_REQUEST; res: WSF_RESPONSE)
+ -- Execute the `next' filter.
+ do
+ if attached next as n then
+ n.execute (req, res)
+ end
+ end
+
+note
+ copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
+ license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
+ source: "[
+ Eiffel Software
+ 5949 Hollister Ave., Goleta, CA 93117 USA
+ Telephone 805-685-1006, Fax 805-685-6869
+ Website http://www.eiffel.com
+ Customer support http://support.eiffel.com
+ ]"
+end
diff --git a/library/server/wsf/src/filter/wsf_filter_handler.e b/library/server/wsf/src/filter/wsf_filter_handler.e
new file mode 100644
index 00000000..f06f0082
--- /dev/null
+++ b/library/server/wsf/src/filter/wsf_filter_handler.e
@@ -0,0 +1,51 @@
+note
+ description: "[
+ Handler that can also play the role of a filter, i.e.
+ than can pre-process incoming data and post-process outgoing data.
+ ]"
+ author: ""
+ date: "$Date$"
+ revision: "$Revision$"
+
+deferred class
+ WSF_FILTER_HANDLER [C -> WSF_HANDLER_CONTEXT]
+
+inherit
+ WSF_HANDLER [C]
+
+feature -- Access
+
+ next: detachable WSF_FILTER_HANDLER [C]
+ -- Next filter
+
+feature -- Element change
+
+ set_next (a_next: WSF_FILTER_HANDLER [C])
+ -- Set `next' to `a_next'
+ do
+ next := a_next
+ ensure
+ next_set: next = a_next
+ end
+
+feature {NONE} -- Implementation
+
+ execute_next (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
+ -- Execute the `next' filter.
+ do
+ if attached next as n then
+ n.execute (ctx, req, res)
+ end
+ end
+
+note
+ copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
+ license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
+ source: "[
+ Eiffel Software
+ 5949 Hollister Ave., Goleta, CA 93117 USA
+ Telephone 805-685-1006, Fax 805-685-6869
+ Website http://www.eiffel.com
+ Customer support http://support.eiffel.com
+ ]"
+end
diff --git a/library/server/wsf/src/filter/wsf_routing_filter.e b/library/server/wsf/src/filter/wsf_routing_filter.e
new file mode 100644
index 00000000..9b42cbf7
--- /dev/null
+++ b/library/server/wsf/src/filter/wsf_routing_filter.e
@@ -0,0 +1,75 @@
+note
+ description: "Routing filter."
+ author: "Olivier Ligot"
+ date: "$Date$"
+ revision: "$Revision$"
+
+class
+ WSF_ROUTING_FILTER [H -> WSF_HANDLER [C], C -> WSF_HANDLER_CONTEXT]
+
+inherit
+ WSF_FILTER
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make (a_router: WSF_ROUTER [H, C])
+ do
+ router := a_router
+ ensure
+ router_set: router = a_router
+ end
+
+feature -- Access
+
+ router: WSF_ROUTER [H, C]
+ -- Router
+
+ execute_default_action: detachable PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]]
+ -- `execute_default' action
+
+feature -- Element change
+
+ set_execute_default_action (an_action: like execute_default_action)
+ -- Set `execute_default_action' to `an_action'
+ do
+ execute_default_action := an_action
+ ensure
+ execute_default_action_set: execute_default_action = an_action
+ end
+
+feature -- Basic operations
+
+ execute (req: WSF_REQUEST; res: WSF_RESPONSE)
+ -- Execute the filter
+ do
+ if attached router.route (req) as r then
+ router.execute_route (r, req, res)
+ else
+ execute_default (req, res)
+ end
+ execute_next (req, res)
+ end
+
+ execute_default (req: WSF_REQUEST; res: WSF_RESPONSE)
+ do
+ if attached execute_default_action as action then
+ action.call ([req, res])
+ else
+ do_nothing
+ end
+ end
+
+note
+ copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
+ license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
+ source: "[
+ Eiffel Software
+ 5949 Hollister Ave., Goleta, CA 93117 USA
+ Telephone 805-685-1006, Fax 805-685-6869
+ Website http://www.eiffel.com
+ Customer support http://support.eiffel.com
+ ]"
+end
diff --git a/library/server/wsf/src/filter/wsf_uri_template_filtered_service.e b/library/server/wsf/src/filter/wsf_uri_template_filtered_service.e
new file mode 100644
index 00000000..cc8a859b
--- /dev/null
+++ b/library/server/wsf/src/filter/wsf_uri_template_filtered_service.e
@@ -0,0 +1,48 @@
+note
+ description: "Summary description for {WSF_URI_TEMPLATE_FILTERED_SERVICE}."
+ author: ""
+ date: "$Date$"
+ revision: "$Revision$"
+
+deferred class
+ WSF_URI_TEMPLATE_FILTERED_SERVICE
+
+feature {NONE} -- Initialization
+
+ initialize_filter
+ -- Initialize `filter'
+ do
+ create_filter
+ setup_filter
+ end
+
+ create_filter
+ -- Create `filter'
+ deferred
+ ensure
+ filter_created: filter /= Void
+ end
+
+ setup_filter
+ -- Setup `filter'
+ require
+ filter_created: filter /= Void
+ deferred
+ end
+
+feature -- Access
+
+ filter: WSF_FILTER
+ -- Filter
+
+;note
+ copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
+ license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
+ source: "[
+ Eiffel Software
+ 5949 Hollister Ave., Goleta, CA 93117 USA
+ Telephone 805-685-1006, Fax 805-685-6869
+ Website http://www.eiffel.com
+ Customer support http://support.eiffel.com
+ ]"
+end
diff --git a/library/server/wsf/src/request/value/wsf_any.e b/library/server/wsf/src/request/value/wsf_any.e
index 0d671051..af3bd776 100644
--- a/library/server/wsf/src/request/value/wsf_any.e
+++ b/library/server/wsf/src/request/value/wsf_any.e
@@ -45,6 +45,11 @@ feature -- Status report
is_string: BOOLEAN = False
-- Is Current as a WSF_STRING representation?
+ is_empty: BOOLEAN
+ do
+ Result := value = Void
+ end
+
feature -- Query
string_representation: STRING_32
diff --git a/library/server/wsf/src/request/value/wsf_multiple_string.e b/library/server/wsf/src/request/value/wsf_multiple_string.e
index 6636c649..4ab9721d 100644
--- a/library/server/wsf/src/request/value/wsf_multiple_string.e
+++ b/library/server/wsf/src/request/value/wsf_multiple_string.e
@@ -97,6 +97,12 @@ feature -- Status report
Result := values.count = 1
end
+ is_empty: BOOLEAN
+ -- Is Current empty?
+ do
+ Result := values.is_empty
+ end
+
feature -- Conversion
as_string: WSF_STRING
diff --git a/library/server/wsf/src/request/value/wsf_table.e b/library/server/wsf/src/request/value/wsf_table.e
index ecbbc052..d15bd8cd 100644
--- a/library/server/wsf/src/request/value/wsf_table.e
+++ b/library/server/wsf/src/request/value/wsf_table.e
@@ -97,6 +97,12 @@ feature -- Status report
end
end
+ is_empty: BOOLEAN
+ -- Is Current empty?
+ do
+ Result := values.is_empty
+ end
+
feature -- Conversion
as_string: WSF_STRING
@@ -108,6 +114,59 @@ feature -- Conversion
end
end
+ as_array_of_string: detachable ARRAY [READABLE_STRING_32]
+ -- Return an array of STRING if possible., otherwise Void
+ local
+ i,n: INTEGER
+ nb: INTEGER
+ do
+ from
+ i := 1
+ n := count
+ create Result.make_filled ("", 1, n)
+ until
+ i > n or Result = Void
+ loop
+ if attached {WSF_STRING} value (i.out) as s then
+ Result.put (s.value, i)
+ nb := nb + 1
+ else
+ Result := Void
+ end
+ i := i + 1
+ end
+ if Result /= Void and then nb /= n then
+ Result := Void
+ end
+ ensure
+ is_array_of_string implies Result /= Void and then Result.count = count and then Result.lower = 1
+ end
+
+ is_array_of_string: BOOLEAN
+ -- Is Current representable as an array of string?
+ local
+ i,n, nb: INTEGER
+ do
+ from
+ i := 1
+ n := count
+ nb := 0
+ Result := True
+ until
+ i > n or not Result
+ loop
+ if attached {WSF_STRING} value (i.out) then
+ nb := nb + 1
+ else
+ Result := False
+ end
+ i := i + 1
+ end
+ if nb /= n then
+ Result := False
+ end
+ end
+
feature -- Element change
add_value (a_value: WSF_VALUE; k: READABLE_STRING_32)
diff --git a/library/server/wsf/src/request/value/wsf_uploaded_file.e b/library/server/wsf/src/request/value/wsf_uploaded_file.e
index 11a3c1d3..fa750cc5 100644
--- a/library/server/wsf/src/request/value/wsf_uploaded_file.e
+++ b/library/server/wsf/src/request/value/wsf_uploaded_file.e
@@ -44,7 +44,13 @@ feature -- Element change
feature -- Status report
is_string: BOOLEAN = False
- -- Is Current as a WSF_STRING representation?
+ -- Is Current as a WSF_STRING representation?
+
+ is_empty: BOOLEAN
+ -- Is Current empty?
+ do
+ Result := size = 0
+ end
feature -- Conversion
diff --git a/library/server/wsf/src/request/wsf_value.e b/library/server/wsf/src/request/wsf_value.e
index c9ec4b75..e77fc43a 100644
--- a/library/server/wsf/src/request/wsf_value.e
+++ b/library/server/wsf/src/request/wsf_value.e
@@ -35,6 +35,12 @@ feature -- Status report
deferred
end
+ is_empty: BOOLEAN
+ -- Is Current empty?
+ --| i.e empty string, empty table, ...
+ deferred
+ end
+
feature -- Query
as_string: WSF_STRING
diff --git a/library/server/wsf/src/response/wsf_file_response.e b/library/server/wsf/src/response/wsf_file_response.e
index 2797b647..1bc2fe43 100644
--- a/library/server/wsf/src/response/wsf_file_response.e
+++ b/library/server/wsf/src/response/wsf_file_response.e
@@ -42,18 +42,23 @@ feature {NONE} -- Initialization
local
h: like header
do
+ get_file_exists
create h.make
header := h
-
h.put_content_type (content_type)
- if attached file_last_modified as dt then
- h.put_last_modified (dt)
- end
- get_file_size
- if file_size = 0 then
- set_status_code ({HTTP_STATUS_CODE}.not_found)
+
+ if file_exists then
+ if attached file_last_modified as dt then
+ h.put_last_modified (dt)
+ end
+ get_file_size
+ if file_size = 0 then
+ set_status_code ({HTTP_STATUS_CODE}.not_found)
+ else
+ set_status_code ({HTTP_STATUS_CODE}.ok)
+ end
else
- set_status_code ({HTTP_STATUS_CODE}.ok)
+ set_status_code ({HTTP_STATUS_CODE}.not_found)
end
update_content_length
end
@@ -62,12 +67,16 @@ feature {NONE} -- Initialization
local
n: INTEGER
do
- n := file_size
- if attached head as h then
- n := n + h.count
- end
- if attached bottom as b then
- n := n + b.count
+ if file_exists then
+ n := file_size
+ if attached head as h then
+ n := n + h.count
+ end
+ if attached bottom as b then
+ n := n + b.count
+ end
+ else
+ n := 0
end
content_length := n
header.put_content_length (n)
@@ -75,9 +84,14 @@ feature {NONE} -- Initialization
feature -- Element change
- set_expires (t: INTEGER)
+ set_expires_in_seconds (sec: INTEGER)
do
- header.put_expires (t)
+ set_expires (sec.out)
+ end
+
+ set_expires (s: STRING)
+ do
+ header.put_expires_string (s)
end
set_no_cache
@@ -104,6 +118,9 @@ feature -- Access
file_name: READABLE_STRING_8
+ file_exists: BOOLEAN
+ -- File exists?
+
file_size: INTEGER
-- Size of file named `file_name'
@@ -157,42 +174,54 @@ feature {WSF_RESPONSE} -- Output
s: detachable READABLE_STRING_8
do
res.set_status_code (status_code)
- res.put_header_text (header.string)
- s := head
- if s /= Void then
- res.put_string (s)
- end
- if not answer_head_request_method then
- send_file_content_to (file_name, res)
- end
- s := bottom
- if s /= Void then
- res.put_string (s)
+ if status_code = {HTTP_STATUS_CODE}.not_found then
+ else
+ res.put_header_text (header.string)
+ s := head
+ if s /= Void then
+ res.put_string (s)
+ end
+ if not answer_head_request_method then
+ send_file_content_to (file_name, res)
+ end
+ s := bottom
+ if s /= Void then
+ res.put_string (s)
+ end
end
end
feature {NONE} -- Implementation: file system helper
- get_file_size
- -- Get `file_size' from file named `file_name'
+ get_file_exists
+ -- Get `file_exists'
local
f: RAW_FILE
do
create f.make (file_name)
- if f.exists then
- file_size := f.count
- end
+ file_exists := f.exists
+ end
+
+ get_file_size
+ -- Get `file_size' from file named `file_name'
+ require
+ file_exists: file_exists
+ local
+ f: RAW_FILE
+ do
+ create f.make (file_name)
+ file_size := f.count
end
file_last_modified: detachable DATE_TIME
-- Get `file_size' from file named `file_name'
+ require
+ file_exists: file_exists
local
f: RAW_FILE
do
create f.make (file_name)
- if f.exists then
- create Result.make_from_epoch (f.change_date)
- end
+ create Result.make_from_epoch (f.change_date)
end
file_extension (fn: STRING): STRING
@@ -231,11 +260,12 @@ feature {NONE} -- Implementation: output
require
string_not_empty: not fn.is_empty
is_readable: (create {RAW_FILE}.make (fn)).is_readable
+ file_exists: file_exists
local
f: RAW_FILE
do
create f.make (fn)
- check f.exists and then f.is_readable end
+ check f.is_readable end
f.open_read
from
diff --git a/library/server/wsf/src/wsf_request.e b/library/server/wsf/src/wsf_request.e
index 91990c2d..046a5c86 100644
--- a/library/server/wsf/src/wsf_request.e
+++ b/library/server/wsf/src/wsf_request.e
@@ -177,6 +177,18 @@ feature -- Helper
Result := request_method.is_case_insensitive_equal (m.as_string_8)
end
+ is_post_request_method: BOOLEAN
+ -- Is Current a POST request method?
+ do
+ Result := request_method.is_case_insensitive_equal ({HTTP_REQUEST_METHODS}.method_post)
+ end
+
+ is_get_request_method: BOOLEAN
+ -- Is Current a GET request method?
+ do
+ Result := request_method.is_case_insensitive_equal ({HTTP_REQUEST_METHODS}.method_get)
+ end
+
feature -- Eiffel WGI access
wgi_version: READABLE_STRING_8
@@ -259,6 +271,36 @@ feature -- Access: global variable
end
end
+ string_array_item (a_name: READABLE_STRING_GENERAL): detachable ARRAY [READABLE_STRING_32]
+ -- Array of string values for path parameter `a_name' if relevant.
+ do
+ Result := string_array_item_for (a_name, agent item)
+ end
+
+ string_array_item_for (a_name: READABLE_STRING_GENERAL; a_item_fct: FUNCTION [ANY, TUPLE [READABLE_STRING_GENERAL], detachable WSF_VALUE]): detachable ARRAY [READABLE_STRING_32]
+ -- Array of string values for query parameter `a_name' if relevant.
+ local
+ i: INTEGER
+ n: INTEGER
+ do
+ from
+ i := 1
+ n := 1
+ create Result.make_filled ("", 1, 5)
+ until
+ i = 0
+ loop
+ if attached {WSF_STRING} a_item_fct.item ([a_name + "[" + i.out + "]"]) as v then
+ Result.force (v.value, n)
+ n := n + 1
+ i := i + 1
+ else
+ i := 0 -- Exit
+ end
+ end
+ Result.keep_head (n - 1)
+ end
+
feature -- Execution variables
execution_variable (a_name: READABLE_STRING_GENERAL): detachable ANY
@@ -1231,6 +1273,7 @@ feature {NONE} -- Implementation: smart parameter identification
k.append_integer (tb.count + 1)
end
v := tb
+ create n.make_from_string (n)
n.append_character ('[')
n.append (k)
n.append_character (']')
@@ -1280,6 +1323,9 @@ feature {NONE} -- Implementation: smart parameter identification
--| Already done in previous part
elseif attached {WSF_MULTIPLE_STRING} l_existing_value as l_multi then
l_multi.add_value (v)
+ elseif attached {WSF_TABLE} l_existing_value as l_table then
+ -- Keep previous values (most likely we have table[1]=foo, table[2]=bar ..and table=/foo/bar
+ -- Anyway for this case, we keep the previous version, and ignore this "conflict"
else
a_table.force (create {WSF_MULTIPLE_STRING}.make_with_array (<>), v.name)
check replaced: a_table.found and then a_table.found_item ~ l_existing_value end
diff --git a/library/text/encoder/src/html_encoder.e b/library/text/encoder/src/html_encoder.e
index 796fe95b..b066c00c 100644
--- a/library/text/encoder/src/html_encoder.e
+++ b/library/text/encoder/src/html_encoder.e
@@ -36,19 +36,25 @@ feature -- Encoder
encoded_string (s: READABLE_STRING_32): STRING_8
-- HTML-encoded value of `s'.
+ do
+ Result := general_encoded_string (s)
+ end
+
+ general_encoded_string (s: READABLE_STRING_GENERAL): STRING_8
+ -- The HTML-encoded equivalent of the given string
+ -- HTML-encoded value of `s'.
local
i, n: INTEGER
- uc: CHARACTER_32
- l_code: INTEGER
+ l_code: NATURAL_32
c: CHARACTER_8
do
has_error := False
create Result.make (s.count + s.count // 10)
n := s.count
from i := 1 until i > n loop
- uc := s.item (i)
- if uc.is_character_8 then
- c := uc.to_character_8
+ l_code := s.code (i)
+ if l_code.is_valid_character_8_code then
+ c := l_code.to_character_8
inspect c
when '%T', '%N', '%R' then
@@ -59,7 +65,6 @@ feature -- Encoder
when '<' then Result.append_string ("<")
when '>' then Result.append_string (">")
else
- l_code := c.code
if
l_code <= 31 or -- Hexa 1F
l_code = 127 -- Hexa 7F
@@ -77,7 +82,7 @@ feature -- Encoder
end
else
Result.append ("")
- Result.append (uc.code.out)
+ Result.append (l_code.out)
Result.extend (';')
end
i := i + 1
diff --git a/library/text/encoder/src/url_encoder.e b/library/text/encoder/src/url_encoder.e
index 9691d593..41d5c8e6 100644
--- a/library/text/encoder/src/url_encoder.e
+++ b/library/text/encoder/src/url_encoder.e
@@ -35,18 +35,24 @@ feature -- Encoder
encoded_string (s: READABLE_STRING_32): STRING_8
-- URL-encoded value of `s'.
+ do
+ Result := general_encoded_string (s)
+ end
+
+ general_encoded_string (s: READABLE_STRING_GENERAL): STRING_8
+ -- URL-encoded value of `s'.
local
i, n: INTEGER
- uc: CHARACTER_32
c: CHARACTER_8
+ l_code: NATURAL_32
do
has_error := False
create Result.make (s.count + s.count // 10)
n := s.count
from i := 1 until i > n loop
- uc := s.item (i)
- if uc.is_character_8 then
- c := uc.to_character_8
+ l_code := s.code (i)
+ if l_code.is_valid_character_8_code then
+ c := l_code.to_character_8
inspect c
when
'A' .. 'Z',
@@ -55,20 +61,20 @@ feature -- Encoder
then
Result.extend (c)
else
- Result.append (url_encoded_char (uc))
+ Result.append (url_encoded_char (l_code))
end
else
- Result.append (url_encoded_char (uc))
+ Result.append (url_encoded_char (l_code))
end
i := i + 1
end
end
- partial_encoded_string (s: READABLE_STRING_32; a_ignore: ARRAY [CHARACTER]): READABLE_STRING_8
+ partial_encoded_string (s: READABLE_STRING_GENERAL; a_ignore: ARRAY [CHARACTER]): STRING_8
-- URL-encoded value of `s'.
local
i, n: INTEGER
- uc: CHARACTER_32
+ l_code: NATURAL_32
c: CHARACTER_8
s8: STRING_8
do
@@ -77,9 +83,9 @@ feature -- Encoder
Result := s8
n := s.count
from i := 1 until i > n loop
- uc := s.item (i)
- if uc.is_character_8 then
- c := uc.to_character_8
+ l_code := s.code (i)
+ if l_code.is_valid_character_8_code then
+ c := l_code.to_character_8
inspect c
when
'A' .. 'Z',
@@ -91,14 +97,14 @@ feature -- Encoder
if a_ignore.has (c) then
s8.extend (c)
else
- s8.append (url_encoded_char (uc))
+ s8.append (url_encoded_char (l_code))
end
end
else
if a_ignore.has (c) then
s8.extend (c)
else
- s8.append (url_encoded_char (uc))
+ s8.append (url_encoded_char (l_code))
end
end
i := i + 1
@@ -107,12 +113,12 @@ feature -- Encoder
feature {NONE} -- encoder character
- url_encoded_char (uc: CHARACTER_32): STRING_8
+ url_encoded_char (a_code: NATURAL_32): STRING_8
do
create Result.make (3)
- if uc.is_character_8 then
+ if a_code.is_valid_character_8_code then
Result.extend ('%%')
- Result.append (uc.code.to_hex_string)
+ Result.append (a_code.to_hex_string)
from
until
Result.count < 2 or else Result[2] /= '0'
diff --git a/library/text/encoder/src/utf8_url_encoder.e b/library/text/encoder/src/utf8_url_encoder.e
index fd333d74..1931e95a 100644
--- a/library/text/encoder/src/utf8_url_encoder.e
+++ b/library/text/encoder/src/utf8_url_encoder.e
@@ -17,6 +17,7 @@ inherit
redefine
default_create,
name,
+ general_encoded_string,
encoded_string, partial_encoded_string,
decoded_string
end
@@ -49,7 +50,17 @@ feature -- Encoder
Result := Precursor (Result)
end
- partial_encoded_string (s: READABLE_STRING_32; a_ignore: ARRAY [CHARACTER]): READABLE_STRING_8
+ general_encoded_string (s: READABLE_STRING_GENERAL): STRING_8
+ do
+ if attached {READABLE_STRING_32} s as s32 then
+ Result := utf32_to_utf8 (s32)
+ else
+ Result := s.as_string_8
+ end
+ Result := Precursor (Result)
+ end
+
+ partial_encoded_string (s: READABLE_STRING_GENERAL; a_ignore: ARRAY [CHARACTER]): STRING_8
-- URL-encoded value of `s'.
do
Result := Precursor (s, a_ignore)
diff --git a/library/text/parser/uri_template/src/uri_template.e b/library/text/parser/uri_template/src/uri_template.e
index 1a7587d5..b1bc3a4a 100644
--- a/library/text/parser/uri_template/src/uri_template.e
+++ b/library/text/parser/uri_template/src/uri_template.e
@@ -24,7 +24,7 @@ create {URI_TEMPLATE}
make_from_uri_template
convert
- make ({READABLE_STRING_8})
+ make ({READABLE_STRING_8, STRING_8})
feature {NONE} -- Initialization
diff --git a/tools/ise_wizard/custom/ewf.dsc b/tools/ise_wizard/custom/ewf.dsc
new file mode 100644
index 00000000..2524dfd6
--- /dev/null
+++ b/tools/ise_wizard/custom/ewf.dsc
@@ -0,0 +1,4 @@
+NAME="EWF: Eiffel Web Framework application, multi-platform, with EWF source code"
+DESCRIPTION="Create a web server application based on the cross-platform library EWF. Using the original source code of EWF (i.e: not the one in $ISE_LIBRARY)"
+LOCATION="ewf_custom"
+PLATFORM="all"
diff --git a/tools/ise_wizard/custom/resources/template.ecf b/tools/ise_wizard/custom/resources/template.ecf
new file mode 100644
index 00000000..0fe0b5e3
--- /dev/null
+++ b/tools/ise_wizard/custom/resources/template.ecf
@@ -0,0 +1,21 @@
+
+
+
+
+
+ /EIFGENs$
+ /CVS$
+ /.svn$
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tools/ise_wizard/ewf.dsc b/tools/ise_wizard/ewf.dsc
index 85b6a364..cf62696d 100644
--- a/tools/ise_wizard/ewf.dsc
+++ b/tools/ise_wizard/ewf.dsc
@@ -1,4 +1,4 @@
-NAME="Eiffel Web Framework application, multi-platform, with EWF"
+NAME="EWF: Eiffel Web Framework application, multi-platform, with EWF"
DESCRIPTION="Create a web server application based on the cross-platform library EWF."
LOCATION="ewf"
PLATFORM="all"
diff --git a/tools/ise_wizard/ewf_ise_wizard-safe.ecf b/tools/ise_wizard/ewf_ise_wizard-safe.ecf
index aede67cd..fa4c6cd1 100644
--- a/tools/ise_wizard/ewf_ise_wizard-safe.ecf
+++ b/tools/ise_wizard/ewf_ise_wizard-safe.ecf
@@ -1,6 +1,6 @@
-
-
+
+ /.git$
@@ -15,4 +15,7 @@
+
+
+
diff --git a/tools/ise_wizard/install_wizard.bat b/tools/ise_wizard/install_ise_wizard.bat
similarity index 69%
rename from tools/ise_wizard/install_wizard.bat
rename to tools/ise_wizard/install_ise_wizard.bat
index 61c27d84..3aa39e7c 100644
--- a/tools/ise_wizard/install_wizard.bat
+++ b/tools/ise_wizard/install_ise_wizard.bat
@@ -2,10 +2,10 @@ setlocal
rd /q/s tmp
mkdir tmp
-ecb -config ewf_ise_wizard-safe.ecf -finalize -c_compile -project_path tmp
+ecb -config ewf_ise_wizard-safe.ecf -target wizard -finalize -c_compile -project_path tmp
mkdir spec
mkdir spec\%ISE_PLATFORM%
-move tmp\EIFGENs\ewf_ise_wizard\F_code\ewf_ise_wizard.exe spec\%ISE_PLATFORM%\wizard.exe
+move tmp\EIFGENs\wizard\F_code\wizard.exe spec\%ISE_PLATFORM%\wizard.exe
rd /q/s tmp
set WIZ_TARGET=%ISE_EIFFEL%\studio\wizards\new_projects\ewf
diff --git a/tools/ise_wizard/install_ise_wizard_custom.bat b/tools/ise_wizard/install_ise_wizard_custom.bat
new file mode 100644
index 00000000..f1b46778
--- /dev/null
+++ b/tools/ise_wizard/install_ise_wizard_custom.bat
@@ -0,0 +1,21 @@
+setlocal
+
+rd /q/s tmp
+mkdir tmp
+ecb -config ewf_ise_wizard-safe.ecf -target custom_wizard -finalize -c_compile -project_path tmp
+mkdir custom
+mkdir custom\spec
+mkdir custom\spec\%ISE_PLATFORM%
+move tmp\EIFGENs\custom_wizard\F_code\wizard.exe custom\spec\%ISE_PLATFORM%\wizard.exe
+rd /q/s tmp
+
+set WIZ_TARGET=%ISE_EIFFEL%\studio\wizards\new_projects\ewf_custom
+rd /q/s %WIZ_TARGET%
+mkdir %WIZ_TARGET%
+xcopy /I /E /Y %~dp0\pixmaps %WIZ_TARGET%\pixmaps
+xcopy /I /E /Y %~dp0\resources %WIZ_TARGET%\resources
+copy %~dp0\custom\resources\* %WIZ_TARGET%\resources
+xcopy /I /E /Y %~dp0\custom\spec %WIZ_TARGET%\spec
+copy %~dp0custom\ewf.dsc %WIZ_TARGET%\..\ewf_custom.dsc
+
+endlocal
diff --git a/tools/ise_wizard/src/ewf_custom_wizard.e b/tools/ise_wizard/src/ewf_custom_wizard.e
new file mode 100644
index 00000000..4141da07
--- /dev/null
+++ b/tools/ise_wizard/src/ewf_custom_wizard.e
@@ -0,0 +1,55 @@
+note
+ description : "Objects that ..."
+ author : "$Author$"
+ date : "$Date$"
+ revision : "$Revision$"
+
+class
+ EWF_CUSTOM_WIZARD
+
+inherit
+ EWF_WIZARD
+ redefine
+ get_information,
+ generate_project
+ end
+
+create
+ make
+
+feature -- Form
+
+ get_information
+ do
+ if attached string_question ("Location of EWF source code (by default $EWF_DIR)?", Void, Void, False) as pn then
+ ewf_dir := pn.string
+ else
+ ewf_dir := "$EWF_DIR"
+ end
+ Precursor
+ end
+
+feature -- Generation
+
+ generate_project (a_layout: WIZARD_LAYOUT)
+ do
+ if attached ewf_dir as d then
+ variables.force (d, "EWF_DIR")
+ Precursor (a_layout)
+ else
+ die (-1)
+ end
+ end
+
+feature -- Access
+
+ ewf_dir: detachable READABLE_STRING_8
+
+feature -- Change
+
+feature {NONE} -- Implementation
+
+invariant
+-- invariant_clause: True
+
+end
diff --git a/tools/ise_wizard/src/ewf_wizard.e b/tools/ise_wizard/src/ewf_wizard.e
index 0967bd66..9d6f08a6 100644
--- a/tools/ise_wizard/src/ewf_wizard.e
+++ b/tools/ise_wizard/src/ewf_wizard.e
@@ -25,8 +25,6 @@ feature {NONE} -- Initialization
end
end
-feature -- Status
-
feature -- Access
project_directory_name: detachable READABLE_STRING_8
@@ -65,7 +63,7 @@ feature -- Form
projet_name := "ewf"
end
- if boolean_question ("Do you want to use router (Y|n) ? ", <<["y", True], ["Y", True]>>, "Y") then
+ if boolean_question ("Do you want to use WSF_ROUTER (Y|n) ? ", <<["y", True], ["Y", True]>>, "Y") then
use_router := True
router_type := "uri-template"
else
@@ -121,6 +119,13 @@ feature -- Form
tfn.add_extension ("ecf")
copy_resource_template ("template.ecf", tfn.string)
+ create tfn.make_from_string (dn.string)
+
+ tfn.set_file_name ("ewf")
+ tfn.add_extension ("ini")
+ copy_resource_template ("ewf.ini", tfn.string)
+
+
create res.make (tfn.string, d.name)
create dn.make_from_string (pdn)
@@ -131,20 +136,15 @@ feature -- Form
d.recursive_create_dir
end
create tfn.make_from_string (dn.string)
- tfn.set_file_name ("ewb_application")
+ tfn.set_file_name ("ewf_application")
tfn.add_extension ("e")
if attached router_type as rt then
check rt.same_string ("uri-template") end
- copy_resource_template ("ewb_application-"+ rt +".e", tfn.string)
+ copy_resource_template ("ewf_application-"+ rt +".e", tfn.string)
else
- copy_resource_template ("ewb_application.e", tfn.string)
+ copy_resource_template ("ewf_application.e", tfn.string)
end
- create tfn.make_from_string (dn.string)
-
- tfn.set_file_name ("ewf")
- tfn.add_extension ("ini")
- copy_resource_template ("ewf.ini", tfn.string)
send_response (res)
end