aboutsummaryrefslogtreecommitdiff
path: root/src/mod_pubsub/nodetree_default.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/mod_pubsub/nodetree_default.erl')
-rw-r--r--src/mod_pubsub/nodetree_default.erl164
1 files changed, 164 insertions, 0 deletions
diff --git a/src/mod_pubsub/nodetree_default.erl b/src/mod_pubsub/nodetree_default.erl
new file mode 100644
index 000000000..3d05b5b24
--- /dev/null
+++ b/src/mod_pubsub/nodetree_default.erl
@@ -0,0 +1,164 @@
+%%% ====================================================================
+%%% This software is copyright 2007, Process-one.
+%%%
+%%% @copyright 2007 Process-one
+%%% @author Christophe Romain <christophe.romain@process-one.net>
+%%% [http://www.process-one.net/]
+%%% @version {@vsn}, {@date} {@time}
+%%% @end
+%%% ====================================================================
+
+%%% @doc The module <strong>{@module}</strong> is the default PubSub node tree plugin.
+%%% <p>It is used as a default for all unknown PubSub node type. It can serve
+%%% as a developer basis and reference to build its own custom pubsub node tree
+%%% types.</p>
+%%% <p>PubSub node tree plugins are using the {@link gen_nodetree} behaviour.</p>
+%%% <p><strong>The API isn't stabilized yet</strong>. The pubsub plugin
+%%% development is still a work in progress. However, the system is already
+%%% useable and useful as is. Please, send us comments, feedback and
+%%% improvements.</p>
+
+-module(nodetree_default).
+-author('christophe.romain@process-one.net').
+
+-include("pubsub.hrl").
+-include("jlib.hrl").
+
+-behaviour(gen_pubsub_nodetree).
+
+-export([init/3,
+ terminate/2,
+ options/0,
+ set_node/1,
+ get_node/2,
+ get_nodes/1,
+ get_subnodes/2,
+ get_subnodes_tree/2,
+ create_node/5,
+ delete_node/2
+ ]).
+
+
+%% ================
+%% API definition
+%% ================
+
+%% @spec (Host) -> any()
+%% Host = mod_pubsub:host()
+%% ServerHost = host()
+%% Opts = list()
+%% @doc <p>Called during pubsub modules initialisation. Any pubsub plugin must
+%% implement this function. It can return anything.</p>
+%% <p>This function is mainly used to trigger the setup task necessary for the
+%% plugin. It can be used for example by the developer to create the specific
+%% module database schema if it does not exists yet.</p>
+init(_Host, _ServerHost, _Opts) ->
+ mnesia:create_table(pubsub_node,
+ [{disc_copies, [node()]},
+ {attributes, record_info(fields, pubsub_node)},
+ {index, [type,parentid]}]),
+ NodesFields = record_info(fields, pubsub_node),
+ case mnesia:table_info(pubsub_node, attributes) of
+ NodesFields -> ok;
+ _ -> mnesia:transform_table(pubsub_node, ignore, NodesFields)
+ end,
+ ok.
+terminate(_Host, _ServerHost) ->
+ ok.
+
+%% @spec () -> [Option]
+%% Option = mod_pubsub:nodetreeOption()
+%% @doc Returns the default pubsub node tree options.
+options() ->
+ [{virtual_tree, false}].
+
+%% @spec (NodeRecord) -> ok | {error, Reason}
+%% Record = mod_pubsub:pubsub_node()
+set_node(Record) when is_record(Record, pubsub_node) ->
+ mnesia:write(Record);
+set_node(_) ->
+ {error, ?ERR_INTERNAL_SERVER_ERROR}.
+
+%% @spec (Host, Node) -> pubsubNode() | {error, Reason}
+%% Host = mod_pubsub:host()
+%% Node = mod_pubsub:pubsubNode()
+get_node(Host, Node) ->
+ case catch mnesia:read({pubsub_node, {Host, Node}}) of
+ [Record] when is_record(Record, pubsub_node) -> Record;
+ [] -> {error, ?ERR_ITEM_NOT_FOUND};
+ Error -> Error
+ end.
+
+%% @spec (Key) -> [pubsubNode()] | {error, Reason}
+%% Key = mod_pubsub:host() | mod_pubsub:jid()
+get_nodes(Key) ->
+ mnesia:match_object(#pubsub_node{nodeid = {Key, '_'}, _ = '_'}).
+
+%% @spec (Host, Index) -> [pubsubNode()] | {error, Reason}
+%% Host = mod_pubsub:host()
+%% Node = mod_pubsub:pubsubNode()
+get_subnodes(Host, Node) ->
+ mnesia:index_read(pubsub_node, {Host, Node}, #pubsub_node.parentid).
+
+%% @spec (Host, Index) -> [pubsubNode()] | {error, Reason}
+%% Host = mod_pubsub:host()
+%% Node = mod_pubsub:pubsubNode()
+get_subnodes_tree(Host, Node) ->
+ mnesia:foldl(fun(#pubsub_node{nodeid = {H, N}}, Acc) ->
+ case lists:prefix(Node, N) and (H == Host) of
+ true -> [N | Acc];
+ _ -> Acc
+ end
+ end, [], pubsub_node).
+
+%% @spec (Key, Node, Type, Owner, Options) -> ok | {error, Reason}
+%% Key = mod_pubsub:host() | mod_pubsub:jid()
+%% Node = mod_pubsub:pubsubNode()
+%% NodeType = mod_pubsub:nodeType()
+%% Owner = mod_pubsub:jid()
+%% Options = list()
+create_node(Key, Node, Type, Owner, Options) ->
+ OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
+ case mnesia:read({pubsub_node, {Key, Node}}) of
+ [] ->
+ Parent = lists:sublist(Node, length(Node) - 1),
+ ParentExists =
+ case Key of
+ {_U, _S, _R} ->
+ %% This is special case for PEP handling
+ %% PEP does not uses hierarchy
+ true;
+ _ ->
+ (Parent == []) orelse
+ case mnesia:read({pubsub_node, {Key, Parent}}) of
+ [] -> false;
+ _ -> true
+ end
+ end,
+ case ParentExists of
+ true ->
+ %% Service requires registration
+ %%{error, ?ERR_REGISTRATION_REQUIRED};
+ mnesia:write(#pubsub_node{nodeid = {Key, Node},
+ parentid = {Key, Parent},
+ type = Type,
+ owners = [OwnerKey],
+ options = Options});
+ false ->
+ %% Requesting entity is prohibited from creating nodes
+ {error, ?ERR_FORBIDDEN}
+ end;
+ _ ->
+ %% NodeID already exists
+ {error, ?ERR_CONFLICT}
+ end.
+
+%% @spec (Key, Node) -> [mod_pubsub:node()]
+%% Key = mod_pubsub:host() | mod_pubsub:jid()
+%% Node = mod_pubsub:pubsubNode()
+delete_node(Key, Node) ->
+ Removed = get_subnodes_tree(Key, Node),
+ lists:foreach(fun(N) ->
+ mnesia:delete({pubsub_node, {Key, N}})
+ end, Removed),
+ Removed.