1 //%% (c) Copyright 1993, 1994 Hewlett-Packard Company
2 //%% (c) Copyright 1993, 1994 International Business Machines Corp.
3 //%% (c) Copyright 1993, 1994 Sun Microsystems, Inc.
4 //%% (c) Copyright 1993, 1994 Novell, Inc.
5 //%% $XConsortium: mp_s_pattern.C /main/3 1995/10/23 11:57:37 rswiston $
7 * @(#)mp_s_pattern.C 1.27 93/09/07
11 * Copyright (c) 1990, 1992 by Sun Microsystems, Inc.
13 #include "mp_s_global.h"
14 #include "mp/mp_arg.h"
15 #include "mp_s_pat_context.h"
18 #include "mp_s_pattern.h"
19 #include "mp_s_message.h"
20 #include "mp_signature.h"
21 #include "mp_observer.h"
23 #include "mp_rpc_implement.h"
24 #include "mp_s_session.h"
25 #include "mp/mp_xdr_functions.h"
26 #include "util/tt_enumname.h"
27 #include "mp/mp_trace.h"
28 #include "util/tt_global_env.h"
29 #include "util/tt_assert.h"
33 // Creates a pattern from a signature object by extracting the relevant
34 // fields from the signature.
37 _Tt_s_pattern(const _Tt_signature_ptr &sig)
40 set_id(_tt_s_mp->initial_session->address_string());
41 set_category(sig->category());
42 add_scope(sig->scope());
44 if (sig->opnum() != -1) {
45 add_opnum(sig->opnum());
47 if (sig->category()!=TT_OBSERVE) {
48 add_handler_ptype(sig->ptid());
50 if (sig->otid().len() > 0) {
51 add_otype(sig->otid());
52 add_paradigm(TT_OTYPE);
53 add_paradigm(TT_OBJECT);
55 add_paradigm(TT_PROCEDURE);
57 add_reliability(sig->reliability());
58 add_message_class(sig->message_class());
60 // We share the arg list from the signature
61 // by just assigning the pointer and letting the ref-counting
62 // system do its thing. Conceivably, this might cause
63 // consternation if we ever let clients update patterns created
64 // from signatures, since updating the arg list would change
65 // the in-memory copy of the signature and every other pattern
66 // generated from the signature! However, the most likely
67 // way such updates would be generated would be to send a whole
68 // new pattern over from the client, so sharing the arg list
69 // wouldn\'t cause trouble.
73 // We *cannot* share the context list from the signature as
74 // the signature contains plain _Tt_context entries, while
75 // the pattern should contain _Tt_pat_context entries.
77 _Tt_context_list_cursor c(sig->contexts());
80 _Tt_pat_context_ptr nc = new _Tt_pat_context(**c);
86 _Tt_s_pattern::_Tt_s_pattern ()
91 _Tt_s_pattern::~_Tt_s_pattern ()
97 // Matches a pattern with a message and returns a number indicating how
98 // well the pattern matches the message. 0 indicates no match whereas a
99 // positive number indicates some level of matching. The greater the
100 // level, the "better" the pattern matches the message. A level of 1
101 // indicates all the pattern fields are wildcards so this is the minimum
102 // level of matching. Any level greater than 1 is controlled by the
103 // number returned from each field match. Thus twiddling these numbers
104 // gives some control as to what field matches are to be considered more
105 // important than others. Presently, the algorithm for selecting match
106 // numbers is that wildcard matches count as 0 whereas any specific match
107 // counts as 1. The total is added up for each field and returned as the
108 // value of the match. The variable tm below holds the total count of
109 // matches. It is initially 1 because wildcard matches don't increment
110 // it. In any submethod called to do matching the variable tm is passed
111 // to the method to be incremented.
114 match(const _Tt_s_message &msg, const _Tt_msg_trace &trace) const
118 if (msg.is_handler_copy()) {
119 // message is the original
120 if ( (! _generating_ptype.is_null())
121 && (category() == TT_OBSERVE))
124 // A static observer pattern can only match
125 // the message copy promised to it,
126 // and cannot match the original.
131 // message is a copy promised to observer ptype
132 if ( (_generating_ptype.is_null())
133 || ( msg.observer()->ptid()
134 != _generating_ptype->ptid()))
137 // If this pattern is not owned by the
138 // promised ptype, or is owned by no
139 // ptype, then this pattern cannot
140 // fulfill the promise.
146 trace << "Tt_message & Tt_pattern {\n";
148 trace << "timestamp:\t" << _timestamp << "\n";
153 // The code for this method is quite repetitive. For each
154 // field, the list is checked to see if there are any values. If
155 // there are and the appropiate match method returns 0 then the
156 // pattern fails to match. The only exception is match_scopes
157 // which defaults to not matching if there are no values specified.
160 // This function used to not match the op field of the
161 // message, because in the usual code path it is
162 // hashed on the basis of the op field so it would be
163 // redundant to check the op field here. However, when
164 // matching TT_HANDLER messages just to get callbacks run,
165 // this is not the case. To save a little time, we skip
166 // the op check if the message paradigm is not TT_HANDLER,
167 // even though that looks really funny here!
169 if (0 != _ops->count()) {
170 if (msg.paradigm() == TT_HANDLER &&
171 ! match_field(msg.op(), _ops,
181 if (_reliabilities != 0) {
182 if (!(_reliabilities&(1<<msg.reliability()))) {
183 trace << "== 0; /* Tt_disposition */\n";
190 if (!(_states&(1<<msg.state()))) {
191 trace << "== 0; /* Tt_state */\n";
197 if (!(_classes&(1<<TT_CLASS_UNDEFINED))
198 && !(_classes&(1<< msg.message_class()))) {
199 trace << "== 0; /* Tt_class */\n";
204 if (_paradigms != 0) {
205 if (!(_paradigms&(1<<msg.paradigm()))) {
206 trace << "== 0; /* Tt_address */\n";
213 if (_handlers->count()) {
216 if (! msg.handler().is_null()) {
217 h = msg.handler()->id();
219 if (! match_field(h, _handlers, tm, trace, "handler")) {
224 if (_handler_ptypes->count() &&
225 ! match_field(msg.handler_ptype(), _handler_ptypes,
226 tm, trace, "handler_ptype" ))
232 if (! match_scopes(msg, tm, trace)) {
235 if (msg.scope() == TT_SESSION) {
236 if (_files->count() &&
237 ! match_field(msg.file(), _files,
243 if (_objects->count() &&
244 ! match_field(msg.object(), _objects,
245 tm, trace, "object"))
250 if (_otypes->count() &&
251 ! match_field(msg.otype(), _otypes,
256 if (_senders->count() &&
257 ! match_field(msg.sender()->id(), _senders,
258 tm, trace, "sender"))
263 if (_sender_ptypes->count() &&
264 ! match_field(msg.sender_ptype(), _sender_ptypes,
265 tm, trace, "sender_ptype"))
271 if (_args->count() && ! match_args(msg, tm, trace)) {
275 if (! match_contexts(msg, tm, trace)) {
279 trace << "== " << tm << ";\n";
285 // Generic matching function for lists of integers. If the given pattern
286 // values, pvals, is empty then 0 is returned indicating a mismatch.
287 // Otherwise, 1 is returned if "val" is in the list and the variable tm
288 // is incremented to update the matching score in _Tt_pattern::match.
291 match_field(int val, const _Tt_int_rec_list_ptr &pvals, int &tm,
292 const _Tt_msg_trace &trace, const char *failure_note) const
294 _Tt_int_rec_list_cursor c(pvals);
302 if (failure_note != 0) {
303 trace << "== 0; /* " << failure_note << " */\n";
310 // Generic matching function for lists of strings. If the given pattern
311 // values, pvals, is empty then 0 is returned indicating a mismatch.
312 // Otherwise, 1 is returned if "val" is in the list and the variable tm
313 // is incremented to update the matching score in _Tt_pattern::match.
316 match_field(const _Tt_string &val, const _Tt_string_list_ptr &pvals,
317 int &tm, const _Tt_msg_trace &trace,
318 const char *failure_note) const
320 _Tt_string_list_cursor c(pvals);
322 if (val.len() != 0) {
330 if (failure_note != 0) {
331 trace << "== 0; /* " << failure_note << " */\n";
338 // Matches the scope of the message with the pattern scopes. For the
339 // different scopes, matching is defined differently as specified below.
342 match_scopes(const _Tt_message &msg, int &tm,
343 const _Tt_msg_trace &trace) const
345 Tt_scope s = msg.scope();
346 int valid_scope_mask = 0;
349 ASSERT(TT_SCOPE_NONE==0 && TT_SESSION==1 && TT_FILE==2 &&
350 TT_BOTH==3 && TT_FILE_IN_SESSION==4,
351 "Tt_scope enum values changed. This breaks the following "
352 "code, and also breaks binary compatibility for libtt users. "
353 "You probably don't want to do that, do you?")
355 static int valid_scope_masks[] = {
357 (1<<TT_SESSION) | (1<<TT_BOTH), // TT_SESSION
358 (1<<TT_FILE) | (1<<TT_BOTH), // TT_FILE
359 (1<<TT_SESSION) | (1<<TT_FILE) | (1<<TT_BOTH), // TT_BOTH
360 (1<<TT_FILE_IN_SESSION)}; // TT_FILE_IN_SESSION
362 if (! (_scopes & valid_scope_masks[s])) {
363 trace << "== 0; /* " << _tt_enumname(s) << " != Tt_scopes */\n";
367 // if this is not a file-scoped message and the pattern
368 // doesn't contain a value for the _sessions list then we
369 // immediately fail the match.
371 (msg.session().is_null() || _sessions->count() == 0)) {
372 trace << "== 0; /* pattern not joined to "
373 "tt_message_session() */\n";
379 return match_field(msg.file(), _files,
381 case TT_FILE_IN_SESSION:
382 if (msg.session()->has_id(_sessions)) {
383 return((_files->count() == 0)
384 || match_field(msg.file(), _files,
387 trace << "== 0; /* file in session */\n";
392 // The session-scope case is so common that we avoid
393 // matching the session id by setting a flag on a
394 // pattern that we know is in the session (see
395 // _Tt_s_procid::add_pattern and
396 // _Tt_session::mod_session_id_in_patterns to see how
397 // the flag is set). This flag is turned on if this
398 // pattern is joined to the current session or not.
403 trace << "== 0; /* session */\n";
408 rval = (msg.session()->has_id(_sessions) +
409 match_field(msg.file(), _files, tm, trace, 0));
411 trace << "== 0; /* file and session */\n";
417 trace << "== 0; /* Tt_scope */\n";
424 // Returns 1 if the message's args match the pattern args. The
425 // _Tt_arg::is_match method is used to do the bulk of the work.
428 match_args(const _Tt_message &msg, int &tm,
429 const _Tt_msg_trace &trace) const
431 if (msg.args()->count() == 0) {
432 // arg matching was specified but the
433 // message doesn't contain any args.
434 trace << "== 0; /* args */\n";
438 _Tt_arg_list_cursor p_args(_args);
439 _Tt_arg_list_cursor m_args(msg.args());
440 int cumulative_args_score = 0;
442 while (p_args.next()) {
444 if (!m_args.next()) {
445 trace << "== 0; /* args */\n";
450 int score = p_args->match_score(*m_args, used_wildcard);
452 trace << "== 0; /* args */\n";
455 cumulative_args_score += score;
457 tm += cumulative_args_score;
462 // Returns 1 if the message's contexts match pattern's contexts.
465 match_contexts(const _Tt_message &msg, int &tm,
466 const _Tt_msg_trace &trace) const
468 _Tt_pat_context_list_cursor cntxtC( _contexts );
469 while (cntxtC.next()) {
470 if (((_Tt_s_pat_context &)**cntxtC).matchVal( msg ) == 0) {
471 trace << "== 0; /* contexts */\n";
481 // Routines to set and get the ptype that this pattern was generated
482 // from, and to test if it was so generate.
484 _Tt_ptype_ptr &_Tt_s_pattern::
485 generating_ptype(_Tt_ptype_ptr &pt)
487 _generating_ptype = pt;
491 _Tt_ptype_ptr &_Tt_s_pattern::
494 return _generating_ptype;
500 return !_generating_ptype.is_null();
503 Tt_status _Tt_s_pattern::
504 join_context(const _Tt_msg_context &msgCntxt)
506 _Tt_pat_context_list_cursor contextC( _contexts );
507 while (contextC.next()) {
508 if (contextC->slotName() == msgCntxt.slotName()) {
509 return contextC->addValue( msgCntxt );
512 return TT_WRN_NOTFOUND;
515 Tt_status _Tt_s_pattern::
516 quit_context(const _Tt_msg_context &msgCntxt)
518 _Tt_pat_context_list_cursor contextC( _contexts );
519 while (contextC.next()) {
520 if (contextC->slotName() == msgCntxt.slotName()) {
521 return contextC->deleteValue( msgCntxt );
524 return TT_WRN_NOTFOUND;