Difference between revisions of "Tutorial: Creating a Service"
m (→Categories and Priorities) |
m (→Creating a Service Interface) |
||
Line 20: | Line 20: | ||
{{Note|All service interfaces, by convention, are suffixed <eiffel>_SERVICE_S</eiffel>. This makes it clear to a consumer that they are using a service interface. All other related interfaces for the service should be suffixed <eiffel>_I</eiffel> to indicate an interface.}} | {{Note|All service interfaces, by convention, are suffixed <eiffel>_SERVICE_S</eiffel>. This makes it clear to a consumer that they are using a service interface. All other related interfaces for the service should be suffixed <eiffel>_I</eiffel> to indicate an interface.}} | ||
− | The first step is to | + | The first step is to define <eiffel>LOGGER_SERVICE_S</eiffel> as an actually service. In order to achieve this <eiffel>LOGGER_SERVICE_S</eiffel> must inherit <eiffel>SERVICE_I</eiffel>. As of EiffelStudio 6.1 <eiffel>SERVICE_I</eiffel> does not contain any effective or deferred routines, it's merley a place holder for future additions and a method of classification. |
So now you should have something looking like this: | So now you should have something looking like this: |
Revision as of 08:57, 28 September 2007
In this tutorial I'll demonstrate the process for integrating third-party services inside EiffelStudio and hooking up internal parts of EiffelStudio to use the new service.
Before we begin you should have a fundamental understanding of what a service is and a clear understanding of the guidelines for writing service
Note: This tutorial is followed up by another tutorial for creating an EiffelStudio tool for displaying information published by the service.
Contents
Getting Started
When extending EiffelStudio, it is a good idea to separate your code from the EiffelStudio code. The Customizing the EiffelStudio Project page describes the process of doing this.
Overview
IN this tutorial we'll be showing you how to create a service use to log messages. Although the service contains a simple interface, it's actually quite complete in that the service itself will make use of the Event List Service as a demonstration how reusing services in EiffelStudio can make development strategies quicker and easier.
Creating a Service Interface
The very first step in creating a service is to define a service interface. A service interface should contain either all deferred routines or deferred routines with only effective routines that reference the service interface directly or other interfaces in the EiffelStudio ecosystem.
Note: It is important to realize that the interface abstraction allows for complete freedom to be given to the implementation of the service. Implementation details are not public and should remain that way. No consumer of the service should ever attempt to reverse assign a retrieve service to the implementation class but to the interface class. Consumer of the service should not have to rely on the implementation details of a service and doing so will potentially break code in the future or if a different implementation is returned than expected when querying to a specific service.
This tutorial is creating a logger service so it makes senses we should create a service interface class call LOGGER_SERVICE_S
. Create a deferred class LOGGER_SERVICE_S
in your extension project cluster.
Note: All service interfaces, by convention, are suffixed _SERVICE_S
. This makes it clear to a consumer that they are using a service interface. All other related interfaces for the service should be suffixed _I
to indicate an interface.
The first step is to define LOGGER_SERVICE_S
as an actually service. In order to achieve this LOGGER_SERVICE_S
must inherit SERVICE_I
. As of EiffelStudio 6.1 SERVICE_I
does not contain any effective or deferred routines, it's merley a place holder for future additions and a method of classification.
So now you should have something looking like this:
deferred class LOGGER_SERVICE_S inherit SERVICE_I end
Of course this doesn't do all that much, in fact it does nothing! We need to add a way to log messages. For this we'll add put
routines; put_message
and put_message_with_severity
.
A logger shouldn't just simply log a message, it's just not powerful enough. So the put routines for the service should permit categorization and even indicate a level of severity incase a logger service consumer deems that a particular entry deserves more or less attention. Fortunatly Griffin offeres built in support for categorization and a basic priority level, which will serve quite nicely as a translation for a log item severity level.
Categories and Priorities
ENVIRONMENT_CATEGORIES
is a class consisting of constants defining EiffelStudio environment region categories. There are constants for the compiler, debugger the editor and so forth. As extenders you are free to add your own categories and utilize them. Any class can access a single instance of ENVIRONMENT_CATEGORIES
through SHARED_ENVIRONMENT_CATEGORIES.categories
.
PRIORITY_LEVELS
is another class containing constants for basic priority levels; high, normal and low. Any class can access a single instance of PRIORITY_LEVELS
through SHARED_PRIORITY_LEVELS.priorities
.
Added Functionality
deferred class LOGGER_SERVICE_I inherit SERVICE_I SHARED_ENVIRONMENT_CATEGORIES export {NONE} all end SHARED_PRIORITY_LEVELS export {NONE} all end feature -- Extension put_message (a_msg: STRING_32; a_cat: NATURAL_8) -- Logs a message. -- -- `a_msg': Message text to log. -- `a_cat': A message category, see {ENVIRONMENT_CATEGORIES}. require a_msg_attached: a_msg /= Void not_a_msg_is_empty: not a_msg.is_empty a_cat_is_empty_is_valid_category: is_valid_category (a_cat) do put_message_with_severity (a_msg, a_cat, {PRIORITY_LEVELS}.normal) end put_message_with_severity (a_msg: STRING_32; a_cat: NATURAL_8; a_level: INTEGER_8) -- Logs a message specifiying a serverity level. -- -- `a_msg': Message text to log. -- `a_cat': A message category, see {ENVIRONMENT_CATEGORIES}. -- `a_level': A serverity level for the message, See {PRIORITY_LEVELS}. require a_msg_attached: a_msg /= Void not_a_msg_is_empty: not a_msg.is_empty a_cat_is_empty_is_valid_category: is_valid_category (a_cat) a_level_is_valid_severity_level: is_valid_severity_level (a_level) deferred end feature -- Query frozen is_valid_category (a_cat: NATURAL_8): BOOLEAN -- Determines if `a_cat' is a valid logger category -- -- `a_cat': A category identifier to validate. -- `Result': True to indicate the category is valid; False otherwise. do Result := categories.is_valid_category (a_cat) end frozen is_valid_severity_level (a_level: INTEGER_8): BOOLEAN -- Determines if `a_level' is a valid severity level -- -- `a_level': A severity level. -- `Result': True to indicate the level of severity is valid; False otherwise. do Result := priorities.is_valid_priority_level (a_level) end end