001: package org.jacorb.notification;
002:
003: /*
004: * JacORB - a free Java ORB
005: *
006: * Copyright (C) 1999-2004 Gerald Brose
007: *
008: * This library is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU Library General Public
010: * License as published by the Free Software Foundation; either
011: * version 2 of the License, or (at your option) any later version.
012: *
013: * This library is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
016: * Library General Public License for more details.
017: *
018: * You should have received a copy of the GNU Library General Public
019: * License along with this library; if not, write to the Free
020: * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
021: *
022: */
023:
024: import java.util.Iterator;
025: import java.util.List;
026:
027: import org.jacorb.notification.filter.ComponentName;
028: import org.jacorb.notification.filter.EvaluationContext;
029: import org.jacorb.notification.filter.EvaluationException;
030: import org.jacorb.notification.filter.EvaluationResult;
031: import org.jacorb.notification.filter.RuntimeVariable;
032: import org.jacorb.notification.interfaces.Disposable;
033: import org.jacorb.notification.interfaces.FilterStage;
034: import org.jacorb.notification.interfaces.Message;
035: import org.jacorb.notification.util.AbstractPoolable;
036: import org.omg.CORBA.Any;
037: import org.omg.CORBA.AnyHolder;
038: import org.omg.CosNotification.Property;
039: import org.omg.CosNotification.StructuredEvent;
040: import org.omg.CosNotifyFilter.Filter;
041: import org.omg.CosNotifyFilter.MappingFilter;
042: import org.omg.CosNotifyFilter.UnsupportedFilterableData;
043:
044: /**
045: * @author Alphonse Bendt
046: * @version $Id: AbstractMessage.java,v 1.32 2006/07/14 12:05:19 alphonse.bendt Exp $
047: */
048:
049: public abstract class AbstractMessage extends AbstractPoolable {
050: /**
051: * Instead of directly using an instance of AbstractMessage an indirection via MessageHandle is
052: * used. This way the Data in AbstractMessage is kept only once. MessageHandle uses reference
053: * counting. As the last MessageHandle is disposed the AbstractMessage containing the data can
054: * be disposed. MessageHandle also allows the priority and timeout to be changed on a per handle
055: * base (the underlying AbstractMessage isn't affected by this)
056: */
057: class MessageHandle implements Message, Disposable {
058: /**
059: * Listener that gets notified if the State of this MessageHandle changes.
060: */
061: private MessageStateListener eventStateListener_;
062:
063: private boolean isInvalid_ = false;
064:
065: /**
066: * flag to indicate that the Priority has been changed for this Messagehandle.
067: */
068: private boolean isPriorityOverridden = false;
069:
070: /**
071: * if isPriorityOverridden_ is true priority_ contains the Priority for this MessageHandle.
072: */
073: private int priority_;
074:
075: /**
076: * flag to indicate that the Timeout has been changed for this Messagehandle.
077: */
078: private boolean isTimeoutOverridden_ = false;
079:
080: /**
081: * if isTimeoutOverridden_ is true timeOut_ contains the Timeout for this MessageHandle.
082: */
083: private long timeOut_;
084:
085: ////////////////////
086:
087: /**
088: * default ctor. adds a reference to the underlying message.
089: */
090: MessageHandle() {
091: addReference();
092: }
093:
094: /**
095: * copy ctor. adds a reference to the underlying message.
096: */
097: private MessageHandle(int priority, boolean priorityOverride,
098: long timeout, boolean timeoutOverride) {
099: // i would like to write this() here to call the no-args
100: // constructor.
101: // this compiles but results in java.lang.VerifyErrors
102: // at runtime
103: addReference();
104:
105: priority_ = priority;
106: isPriorityOverridden = priorityOverride;
107: timeOut_ = timeout;
108: isTimeoutOverridden_ = timeoutOverride;
109: }
110:
111: /**
112: * set the Inital FilterStage (the ProxyConsumer that has received the Message).
113: */
114: public void setInitialFilterStage(FilterStage s) {
115: AbstractMessage.this .setFilterStage(s);
116: }
117:
118: public FilterStage getInitialFilterStage() {
119: return AbstractMessage.this .getFilterStage();
120: }
121:
122: public String getConstraintKey() {
123: return AbstractMessage.this .getConstraintKey();
124: }
125:
126: public Any toAny() {
127: return AbstractMessage.this .toAny();
128: }
129:
130: public Property[] toTypedEvent() throws NoTranslationException {
131: return AbstractMessage.this .toTypedEvent();
132: }
133:
134: public StructuredEvent toStructuredEvent() {
135: return AbstractMessage.this .toStructuredEvent();
136: }
137:
138: public int getType() {
139: return AbstractMessage.this .getType();
140: }
141:
142: public EvaluationResult extractValue(EvaluationContext context,
143: ComponentName componentName,
144: RuntimeVariable runtimeVariable)
145: throws EvaluationException {
146: return AbstractMessage.this .extractValue(context,
147: componentName, runtimeVariable);
148: }
149:
150: public EvaluationResult extractValue(EvaluationContext context,
151: ComponentName componentName) throws EvaluationException {
152: return AbstractMessage.this .extractValue(context,
153: componentName);
154: }
155:
156: public EvaluationResult extractFilterableData(
157: EvaluationContext context,
158: ComponentName componentRootNode, String variable)
159: throws EvaluationException {
160: return AbstractMessage.this .extractFilterableData(context,
161: componentRootNode, variable);
162: }
163:
164: public EvaluationResult extractVariableHeader(
165: EvaluationContext context, ComponentName componentName,
166: String s) throws EvaluationException {
167: return AbstractMessage.this .extractVariableHeader(context,
168: componentName, s);
169: }
170:
171: public boolean hasStartTime() {
172: return AbstractMessage.this .hasStartTime();
173: }
174:
175: public long getStartTime() {
176: return AbstractMessage.this .getStartTime();
177: }
178:
179: public boolean hasStopTime() {
180: return AbstractMessage.this .hasStopTime();
181: }
182:
183: public long getStopTime() {
184: return AbstractMessage.this .getStopTime();
185: }
186:
187: public boolean hasTimeout() {
188: return isTimeoutOverridden_
189: || AbstractMessage.this .hasTimeout();
190: }
191:
192: public long getTimeout() {
193: if (isTimeoutOverridden_) {
194: return timeOut_;
195: }
196: return AbstractMessage.this .getTimeout();
197: }
198:
199: public void setTimeout(long timeout) {
200: timeOut_ = timeout;
201:
202: isTimeoutOverridden_ = true;
203:
204: if (eventStateListener_ != null) {
205: eventStateListener_.actionLifetimeChanged(timeout);
206: }
207: }
208:
209: public void setPriority(int priority) {
210: isPriorityOverridden = true;
211:
212: priority_ = priority;
213: }
214:
215: public int getPriority() {
216: if (isPriorityOverridden) {
217: return priority_;
218: }
219: return AbstractMessage.this .getPriority();
220: }
221:
222: public boolean match(FilterStage s) {
223: return AbstractMessage.this .match(s);
224: }
225:
226: public boolean match(MappingFilter m, AnyHolder r)
227: throws UnsupportedFilterableData {
228: return AbstractMessage.this .match(m, r);
229: }
230:
231: public Object clone() {
232: try {
233: checkInvalid();
234:
235: return new MessageHandle(priority_,
236: isPriorityOverridden, timeOut_,
237: isTimeoutOverridden_);
238: } catch (IllegalArgumentException e) {
239: return null;
240: }
241: }
242:
243: public void dispose() {
244: removeReference();
245: }
246:
247: public synchronized boolean isInvalid() {
248: return isInvalid_;
249: }
250:
251: public void setMessageStateListener(
252: MessageStateListener listener) {
253: eventStateListener_ = listener;
254: }
255:
256: public MessageStateListener removeMessageStateListener() {
257: MessageStateListener _listener = eventStateListener_;
258: eventStateListener_ = null;
259:
260: return _listener;
261: }
262:
263: public synchronized void actionTimeout() {
264: isInvalid_ = true;
265: }
266:
267: public long getReceiveTimestamp() {
268: return AbstractMessage.this .getReceiveTimestamp();
269: }
270:
271: public String toString() {
272: return "[Message/" + AbstractMessage.this + "]";
273: }
274:
275: private void checkInvalid() throws IllegalArgumentException {
276: if (isInvalid()) {
277: throw new IllegalArgumentException(
278: "This Notification has been invalidated");
279: }
280: }
281: }
282:
283: ////////////////////////////////////////
284:
285: protected boolean proxyConsumerFiltered_;
286:
287: protected boolean supplierAdminFiltered_;
288:
289: protected boolean consumerAdminFiltered_;
290:
291: protected boolean proxySupplierFiltered_;
292:
293: private FilterStage currentFilterStage_;
294:
295: private long receiveTimestamp_;
296:
297: ////////////////////////////////////////
298:
299: /**
300: * get the Constraint Key for this Event. The Constraint Key is used to fetch the Filter
301: * Constraints that must be evaluated for this Event. The Constraint Key consists of domain_name
302: * and type_name of the Event.
303: *
304: * @return a <code>String</code> value
305: */
306: public abstract String getConstraintKey();
307:
308: public long getReceiveTimestamp() {
309: return receiveTimestamp_;
310: }
311:
312: /**
313: * Access this NotificationEvent as Any.
314: *
315: * @return an <code>Any</code> value
316: */
317: public abstract Any toAny();
318:
319: /**
320: * convert this message to a TypedEvent.
321: *
322: * @return a sequence of name-value pairs.
323: * @throws NoTranslationException
324: * if the contents of the message cannot be translated into a TypedEvent.
325: */
326: public abstract Property[] toTypedEvent()
327: throws NoTranslationException;
328:
329: /**
330: * Access this NotificationEvent as StructuredEvent.
331: *
332: * @return a <code>StructuredEvent</code> value
333: */
334: public abstract StructuredEvent toStructuredEvent();
335:
336: /**
337: * get the Type of this NotificationEvent. The value is one of
338: * {@link org.jacorb.notification.interfaces.Message#TYPE_ANY},{@link
339: * org.jacorb.notification.interfaces.Message#TYPE_STRUCTURED}, or {@link
340: * org.jacorb.notification.interfaces.Message#TYPE_TYPED}.
341: *
342: * @return the Type of this NotificationEvent.
343: */
344: public abstract int getType();
345:
346: /**
347: * Internal Reference Counter.
348: */
349: protected int referenced_ = 0;
350:
351: public synchronized final void reset() {
352: referenced_ = 0;
353: currentFilterStage_ = null;
354:
355: doReset();
356: }
357:
358: protected void doReset() {
359: // no operation
360: }
361:
362: /**
363: * Add a reference on this NotificationEvent. After Usage removeReference must be called.
364: */
365: public synchronized void addReference() {
366: ++referenced_;
367: }
368:
369: /**
370: * release this NotificationEvent. If the internal Refcounter is zero the NotificationEvent is
371: * returned to its pool.
372: */
373: protected synchronized void removeReference() {
374: if (referenced_ > 0) {
375: --referenced_;
376: }
377:
378: if (referenced_ == 0) {
379: super .dispose();
380: }
381: }
382:
383: public void setFilterStage(FilterStage node) {
384: currentFilterStage_ = node;
385: }
386:
387: public FilterStage getFilterStage() {
388: return currentFilterStage_;
389: }
390:
391: public EvaluationResult extractValue(EvaluationContext context,
392: ComponentName componentRootNode,
393: RuntimeVariable runtimeVariable) throws EvaluationException {
394: EvaluationResult _ret = null;
395:
396: final String _completePath = componentRootNode
397: .getComponentName();
398:
399: if (logger_.isDebugEnabled()) {
400: logger_.debug("extractValue: " + _completePath);
401: logger_.debug("runtimeVariable=" + runtimeVariable);
402: }
403:
404: _ret = context.lookupResult(_completePath);
405:
406: if (_ret == null) {
407: _ret = runtimeVariable.evaluate(context);
408:
409: _ret = context.extractFromMessage(_ret, componentRootNode,
410: runtimeVariable);
411:
412: context.storeResult(_completePath, _ret);
413: }
414:
415: if (_ret == null) {
416: throw new EvaluationException("Could not resolve "
417: + _completePath);
418: }
419:
420: return _ret;
421: }
422:
423: public abstract EvaluationResult extractFilterableData(
424: EvaluationContext context, ComponentName componentRootNode,
425: String variable) throws EvaluationException;
426:
427: public abstract EvaluationResult extractVariableHeader(
428: EvaluationContext context, ComponentName componentRootNode,
429: String variable) throws EvaluationException;
430:
431: public EvaluationResult extractValue(
432: EvaluationContext evaluationContext,
433: ComponentName componentRootNode) throws EvaluationException {
434: EvaluationResult _ret = null;
435:
436: final String _completeExpr = componentRootNode
437: .getComponentName();
438:
439: if (logger_.isDebugEnabled()) {
440: logger_.debug("extractValue path: "
441: + componentRootNode.toStringTree()
442: + "\n\tcomplete Expression=" + _completeExpr);
443: }
444:
445: // check if the value is available in the cache
446: _ret = evaluationContext.lookupResult(_completeExpr);
447:
448: if (logger_.isDebugEnabled()) {
449: logger_.debug("Cache READ: " + _ret);
450: }
451:
452: if (_ret == null) {
453: logger_.debug("Cache MISS");
454:
455: _ret = evaluationContext.extractFromMessage(this ,
456: componentRootNode);
457:
458: // Cache the EvaluationResult
459: if (_ret != null) {
460: if (logger_.isDebugEnabled()) {
461: logger_.debug("Cache WRITE: " + _completeExpr
462: + " => " + _ret);
463: }
464: evaluationContext.storeResult(_completeExpr, _ret);
465: }
466: }
467:
468: if (_ret == null) {
469: throw new EvaluationException("Could not resolve "
470: + _completeExpr);
471: }
472:
473: return _ret;
474: }
475:
476: public Message getHandle() {
477: return new MessageHandle();
478: }
479:
480: public void initReceiveTimestamp() {
481: receiveTimestamp_ = System.currentTimeMillis();
482: }
483:
484: public abstract boolean hasStartTime();
485:
486: public abstract long getStartTime();
487:
488: public abstract boolean hasStopTime();
489:
490: public abstract long getStopTime();
491:
492: public abstract boolean hasTimeout();
493:
494: public abstract long getTimeout();
495:
496: public abstract int getPriority();
497:
498: public abstract boolean match(Filter filter)
499: throws UnsupportedFilterableData;
500:
501: public boolean match(FilterStage filterStage) {
502: final List _filterList = filterStage.getFilters();
503:
504: if (_filterList.isEmpty()) {
505: return true;
506: }
507:
508: final Iterator _filterIterator = _filterList.iterator();
509:
510: while (_filterIterator.hasNext()) {
511: try {
512: final Filter _filter = (Filter) _filterIterator.next();
513:
514: if (match(_filter)) {
515: return true;
516: }
517: } catch (UnsupportedFilterableData e) {
518: // no problem
519: // error means false
520: logger_
521: .info(
522: "unsupported filterable data. match result defaults to false.",
523: e);
524: } catch (Exception e) {
525: logger_
526: .warn(
527: "unexpected error during match. match result defaults to false",
528: e);
529: }
530: }
531:
532: return false;
533: }
534:
535: public abstract boolean match(MappingFilter filter, AnyHolder value)
536: throws UnsupportedFilterableData;
537:
538: /**
539: * Provide a Uniform Mapping from domain_name and type_name to a Key that can be used to put
540: * EventTypes into a Map. if (d1 == d2) AND (t1 == t2) => calcConstraintKey(d1, t1) ==
541: * calcConstraintKey(d2, t2).
542: *
543: * @param domain_name
544: * a <code>String</code> value
545: * @param type_name
546: * a <code>String</code> value
547: * @return an Unique Constraint Key.
548: */
549: public static String calcConstraintKey(String domain_name,
550: String type_name) {
551: if ("".equals(domain_name)) {
552: domain_name = "*";
553: }
554:
555: if ("".equals(type_name)) {
556: type_name = "*";
557: }
558:
559: final StringBuffer _buffer = new StringBuffer(domain_name);
560:
561: // insert a magic string-seperator
562: // has no meaning though
563: _buffer.append("_%_");
564: _buffer.append(type_name);
565:
566: return _buffer.toString();
567: }
568: }
|