PageRenderTime 45ms CodeModel.GetById 40ms app.highlight 2ms RepoModel.GetById 1ms app.codeStats 0ms

/examples/rest_server/src/rest_server.e

http://github.com/jocelyn/EiffelWebReloaded
Specman e | 204 lines | 144 code | 34 blank | 26 comment | 1 complexity | cd2adc9ab3d2fd687ec9e06a580a8755 MD5 | raw file
  1note
  2	description: "[
  3				A simple example to demonstrate how to build a RESTful server
  4		]"
  5	date: "$Date$"
  6	revision: "$Revision$"
  7
  8class
  9	REST_SERVER
 10
 11inherit
 12
 13	REST_APPLICATION --| Use the provided RESTful implementation
 14		redefine
 15			new_request_context,
 16			execute,
 17			exit_with_code
 18		end
 19
 20		--| Precise which httpd support you want to use, here we use EiffelWebNino
 21		--| you could also use FCGI or CGI
 22	HTTPD_NINO_APPLICATION
 23		redefine
 24			initialize_server,
 25			new_request_context,
 26			execute
 27		end
 28
 29		--| Simple facility to trace your execution		
 30	SHARED_LOGGER
 31
 32create
 33	make
 34
 35feature {NONE} -- Initialization
 36
 37	make
 38			-- Initialize `Current'.
 39		do
 40			initialize
 41			initialize_handlers
 42			initialize_logger
 43			launch
 44			logger.close
 45		end
 46
 47	initialize_logger
 48		do
 49			logger_cell.replace (create {FILE_LOGGER}.make_with_filename ("server.log"))
 50		end
 51
 52	initialize_server
 53		do
 54			Precursor
 55			base := "/service"  --| See `base' for details
 56
 57				--| Let's use 8080 for the port number
 58				--| You can change it
 59			server.configuration.http_server_port := 8080
 60
 61				--| If your application is not design to be run in multithread
 62				--| you can choose to force single_thread request handling
 63			server.configuration.force_single_threaded := True
 64		end
 65
 66	base: detachable STRING
 67			-- Base url used to tell EiffelWebNino what is the "root" for the application
 68			--| basically if your service is  http://domain.tld/service
 69			--| and your request such http://domain.tld/service/test?foo=bar
 70			--| the base_url is /service
 71			--| and then, your PATH_INFO will be  /test  and the QUERY_STRING will be foo=bar
 72
 73feature {NONE} -- Environment
 74
 75	new_request_context (a_vars: HASH_TABLE [STRING, STRING]; a_input: HTTPD_SERVER_INPUT; a_output: HTTPD_SERVER_OUTPUT): REST_REQUEST_CONTEXT
 76		do
 77				--| Precise our own authentication system
 78			create Result.make_with_authentication (a_vars, a_input, a_output, create {REST_SERVER_AUTHENTICATION})
 79
 80				--| At this point, you can decided to add your own environment variable
 81				--| this is a convenient way to share a value
 82			Result.environment_variables.add_variable (request_count.out, "REQUEST_COUNT")
 83
 84				--| Note that you can also create your own REST_REQUEST_CONTEXT with specific features
 85		end
 86
 87feature {NONE} -- Handlers		
 88
 89	handler_manager: REST_REQUEST_HANDLER_MANAGER
 90			-- This is the main handler manager
 91			-- you can use your own implementation
 92
 93	initialize_handlers
 94		local
 95			h: REST_REQUEST_HANDLER
 96			m: like handler_manager
 97		do
 98			create handler_manager.make (10)
 99			m := handler_manager
100
101				--| This /doc is to show a quick documentation of your services,
102				--| based on the declaration in the various APP_... classes
103			m.register (create {APP_API_DOCUMENTATION}.make ("/doc", m))
104
105				--| An example to handle login/password
106			m.register (create {APP_ACCOUNT_VERIFY_CREDENTIAL}.make ("/account/verify_credentials"))
107
108				--| Various tests ..
109			m.register (create {APP_TEST}.make ("/test"))
110			m.register (create {APP_DEBUG_LOG}.make ("/log"))
111
112				--| One app to tell the server to exit
113			create {REST_REQUEST_AGENT_HANDLER} h.make (agent execute_exit_application, "/exit")
114			h.set_description ("tell the REST server to exit (in FCGI context, this could be used to reload the FCGI server)")
115			h.enable_request_method_get
116			h.enable_format_text
117			m.register (h)
118		end
119
120feature -- Execution
121
122	execute (ctx: like new_request_context)
123		do
124			logger.logf (1, "[$3] execute: path_info=$1 (request_count=$2)", <<ctx.path_info, request_count, ctx.environment_variables.remote_addr>>)
125			Precursor (ctx)
126		end
127
128	execute_default (ctx: like new_request_context)
129			-- Execute the default behavior
130		local
131			rqst_uri: detachable STRING
132			l_path_info: detachable STRING
133			h: HTTPD_HEADER
134			s: STRING
135		do
136			create h.make
137			h.put_refresh (ctx.script_url ("/doc"), 2, {HTTP_STATUS_CODE}.temp_redirect)
138			h.put_content_type_text_html
139			create s.make_empty
140			s := "Request [" + ctx.path_info + "] is not available. <br/>%N";
141			s.append ("You are being redirected to <a href=%"" + ctx.script_url ("/doc") + "%">/doc</a> in 2 seconds ...%N")
142			h.put_content_length (s.count)
143			ctx.output.put_string (h.string)
144			ctx.output.put_string (s)
145		end
146
147	execute_rescue (ctx: like new_request_context)
148			-- Execute the default rescue behavior
149		do
150			execute_exception_trace (ctx)
151		end
152
153feature -- Implementation
154
155	execute_exception_trace (ctx: like new_request_context)
156		local
157			h: HTTPD_HEADER
158			s: STRING
159		do
160			create h.make
161			h.put_content_type_text_plain
162			ctx.output.put_string (h.string)
163			ctx.output.put_string ("Error occurred .. rq="+ request_count.out +"%N")
164
165			if attached (create {EXCEPTIONS}).exception_trace as l_trace then
166				ctx.output.put_string ("<pre>" + l_trace + "</pre>")
167			end
168			h.recycle
169			exit_with_code (-1)
170		end
171
172	execute_exit_application (ctx: REST_REQUEST_CONTEXT; a_format_name: detachable STRING; a_args: detachable STRING)
173		local
174			rep: REST_RESPONSE
175			s: STRING
176		do
177			create rep.make ("exit")
178			rep.headers.put_content_type_text_html
179			create s.make_empty
180			s.append_string ("Exited")
181			s.append_string (" <a href=%"" + ctx.script_url ("/") + "%">start again</a>%N")
182			rep.set_message (s)
183			ctx.output.put_string (rep.string)
184			rep.recycle
185			exit_with_code (0)
186		end
187
188	exit_with_code (a_code: INTEGER)
189		do
190			server.shutdown_server
191			logger.close;
192		end
193
194note
195	copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
196	license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
197	source: "[
198			Eiffel Software
199			5949 Hollister Ave., Goleta, CA 93117 USA
200			Telephone 805-685-1006, Fax 805-685-6869
201			Website http://www.eiffel.com
202			Customer support http://support.eiffel.com
203		]"
204end