Each Droonga Engine plugin can have its adapter. On the adaption phase, adapters can modify both incoming messages (from the Protocol Adapter to the Droonga Engine, in other words, they are “request”s) and outgoing messages (from the Droonga Engine to the Protocol Adapter, in other words, they are “response”s).
For example, here is a sample plugin named “foo” with an adapter:
require "droonga/plugin"
module Droonga::Plugins::FooPlugin
extend Plugin
register("foo")
class Adapter < Droonga::Adapter
# operations to configure this adapter
XXXXXX = XXXXXX
def adapt_input(input_message)
# operations to modify incoming messages
input_message.XXXXXX = XXXXXX
end
def adapt_output(output_message)
# operations to modify outgoing messages
output_message.XXXXXX = XXXXXX
end
end
end
Steps to define an adapter:
Droonga::Plugins::FooPlugin
) and register it as a plugin. (required)Droonga::Plugins::FooPlugin::Adapter
) inheriting Droonga::Adapter
. (required)#adapt_input
. (optional)#adapt_output
. (optional)See also the plugin development tutorial.
An adapter works like following:
Droonga::Plugins::FooPlugin::Adapter
) is created and it is registered.
#adapt_input
is called, if the message matches to the input matching pattern of the adapter.#adapt_output
is called, if the message meets following both requirements:
As described above, the Droonga Engine creates only one global instance of the adapter class for each plugin. You should not keep stateful information for a pair of incoming and outgoing messages as instance variables of the adapter itself. Instead, you should give stateful information as a part of the incoming message body, and receive it from the body of the corresponding outgoing message.
Any error raised from the adapter is handled by the Droonga Engine itself. See also error handling.
input_message.pattern
(matching pattern, optional, default=nil
)nil
) is given, any message is regarded as “matched”.output_message.pattern
(matching pattern, optional, default=nil
)nil
) is given, any message is regarded as “matched”.Droonga::Adapter
This is the common base class of any adapter. Your plugin’s adapter class must inherit this.
#adapt_input(input_message)
This method receives a Droonga::InputMessage
wrapped incoming message.
You can modify the incoming message via its methods.
In this base class, this method is defined as just a placeholder and it does nothing. To modify incoming messages, you have to override it by yours, like following:
module Droonga::Plugins::QueryFixer
class Adapter < Droonga::Adapter
def adapt_input(input_message)
input_message.body["query"] = "fixed query"
end
end
end
#adapt_output(output_message)
This method receives a Droonga::OutputMessage
wrapped outgoing message.
You can modify the outgoing message via its methods.
In this base class, this method is defined as just a placeholder and it does nothing. To modify outgoing messages, you have to override it by yours, like following:
module Droonga::Plugins::ErrorConcealer
class Adapter < Droonga::Adapter
def adapt_output(output_message)
output_message.status_code = Droonga::StatusCode::OK
end
end
end
Droonga::InputMessage
#type
, #type=(type)
This returns the "type"
of the incoming message.
You can override it by assigning a new string value, like:
module Droonga::Plugins::MySearch
class Adapter < Droonga::Adapter
input_message.pattern = ["type", :equal, "my-search"]
def adapt_input(input_message)
p input_message.type
# => "my-search"
# This message will be handled by a plugin
# for the custom "my-search" type.
input_message.type = "search"
p input_message.type
# => "search"
# The messge type (type) is changed.
# This message will be handled by the "search" plugin,
# as a regular search request.
end
end
end
#body
, #body=(body)
This returns the "body"
of the incoming message.
You can override it by assigning a new value, partially or fully. For example:
module Droonga::Plugins::MinimumLimit
class Adapter < Droonga::Adapter
input_message.pattern = ["type", :equal, "search"]
MAXIMUM_LIMIT = 10
def adapt_input(input_message)
input_message.body["queries"].each do |name, query|
query["output"] ||= {}
query["output"]["limit"] ||= MAXIMUM_LIMIT
query["output"]["limit"] = [query["output"]["limit"], MAXIMUM_LIMIT].min
end
# Now, all queries have "output.limit=10".
end
end
end
Another case:
module Droonga::Plugins::MySearch
class Adapter < Droonga::Adapter
input_message.pattern = ["type", :equal, "my-search"]
def adapt_input(input_message)
# Extract the query string from the custom type message.
query_string = input_message["body"]["query"]
# Construct internal search request for the "search" type.
input_message.type = "search"
input_message.body = {
"queries" => {
"source" => "Store",
"condition" => {
"query" => query_string,
"matchTo" => ["name"],
},
"output" => {
"elements" => ["records"],
"limit" => 10,
},
},
}
# Now, both "type" and "body" are completely replaced.
end
end
end
Droonga::OutputMessage
#status_code
, #status_code=(status_code)
This returns the "statusCode"
of the outgoing message.
You can override it by assigning a new status code. For example:
module Droonga::Plugins::ErrorConcealer
class Adapter < Droonga::Adapter
input_message.pattern = ["type", :equal, "search"]
def adapt_output(output_message)
unless output_message.status_code == StatusCode::InternalServerError
output_message.status_code = Droonga::StatusCode::OK
output_message.body = {}
output_message.errors = nil
# Now any internal server error is ignored and clients
# receive regular responses.
end
end
end
end
#errors
, #errors=(errors)
This returns the "errors"
of the outgoing message.
You can override it by assigning new error information, partially or fully. For example:
module Droonga::Plugins::ErrorExporter
class Adapter < Droonga::Adapter
input_message.pattern = ["type", :equal, "search"]
def adapt_output(output_message)
output_message.errors.delete(secret_database)
# Delete error information from secret database
output_message.body["errors"] = {
"records" => output_message.errors.collect do |database, error|
{
"database" => database,
"error" => error
}
end,
}
# Convert error informations to a fake search result named "errors".
end
end
end
#body
, #body=(body)
This returns the "body"
of the outgoing message.
You can override it by assigning a new value, partially or fully. For example:
module Droonga::Plugins::SponsoredSearch
class Adapter < Droonga::Adapter
input_message.pattern = ["type", :equal, "search"]
def adapt_output(output_message)
output_message.body.each do |name, result|
next unless result["records"]
result["records"].unshift(sponsored_entry)
end
# Now all search results include sponsored entry.
end
def sponsored_entry
{
"title"=> "SALE!",
"url"=> "http://..."
}
end
end
end