Re: [Embedlets-developer] Re: General event mechanism
Status: Alpha
Brought to you by:
tkosan
|
From: Gregg G. W. <gr...@sk...> - 2003-01-27 15:33:49
|
>What is a bit tricky is how to specify the Event Type in a globally unique way, >since you don't want a developer to end up with a situation where the event >types were duplicated by two different embedlets/components, for different >purposes. > >One way is to use integers as event types, with a single EmbedletEvent class, >which is handy since it's compact and processing them is quite efficient (rather >than string compares), and you can use Select/case constructs in a single >receive() method to distinguish between different events. But the issue there >is how to ensure that different event types don't reuse the same integer >specifier. A caching topic (String based) mechanism can be just as fast, as it can assign an numeric value to a string based topic on the first use. This allows the numbers to be different between JVMs, but intra-JVM numbering is consistent through the use of a factory. Here's an example of what I am talking about. ---------------------------- package org.wonderly.space; import java.io.*; import java.util.*; /** * This class represent topics in the Pub/Sub world. These topics are * cached through the use of a factory method. This will help to reduce * the overall numbers of strings and string tokenizers. However, factory * use and associated caching can create memory fragmentation if compaction * is not present in GC. As a general rule, the less garbage you * create, the less you have to clean up :-) So, in a pub/sub application, * topics will be used everywhere, so caching of the topics makes good sense * to reduce overall garbage collection. * * Each topic is assigned a unique, but changes on each restart long integer * id. Comparing topics should still be done with .equals() though so that * wild card matching can be performed so that 'app.data.<' will match * 'app.data.mydata'. * * These objects are not serializable on purpose. Serialize the string * representation if you need to save something and use the factory * method, <code>of(String)</code> to recreate the Topic on deserialization. * * @author Gregg Wonderly */ public class Topic { public static final String SEPARATOR = "."; public static final String MATCH_CURRENT = "*"; public static final String MATCH_REMAINING = "<"; private String parts[]; private String top; private transient long myUnique; static final long serialVersionUID = 8837984674953252299L; private static Hashtable topics = new Hashtable(); private static long unique = (long)Math.random()*100203723217L; /** * Private constructor used to create each instance. */ private Topic(String s) { top = s; StringTokenizer tok = new StringTokenizer(s, "."); parts = new String[tok.countTokens()]; int i = 0; while(tok.hasMoreTokens()) { parts[i++] = tok.nextToken(); } myUnique = unique++; } /** * Topics are created by this factory method and cached to reduce memory * use */ public static synchronized Topic of(String s) { Topic t; if( (t = (Topic)topics.get(s)) != null ) { return t; } topics.put( s, t = new Topic( s ) ); return t; } /** * Compares topics by making sure that each SEPARATOR * separated segment of the topic matches. We don't keep * the original topic string around to perform equals() on. */ public boolean equals(Object obj) { if(!(obj instanceof Topic)) return false; Topic topic = (Topic)obj; return topic.top.equals(top); } /** * Returns the topic String representation */ public String toString() { return top; } /** * Returns the hashCode() of the topic String */ public int hashCode() { return top.hashCode(); } /** * Checks to see if a topic matches this topic. Matching takes the presence * of MATCH_CURRENT and MATCH_REMAINING into account to create the right results * for partial matches */ public boolean matches(Topic topic) { // Simple test for same, exact, topics. if( topic == this || myUnique == topic.myUnique ) return true; // Check the easy things... if(parts.length != topic.parts.length && !parts[parts.length - 1].equals(MATCH_REMAINING) && !topic.parts[parts.length - 1].equals(MATCH_REMAINING)) { return false; } // Launch a string comparison... for(int i = 0; i < parts.length; i++) { String s = parts[i]; String s1 = topic.parts[i]; // If we are at match rest, just match and stop if(s.equals(MATCH_REMAINING) || s1.equals(MATCH_REMAINING)) { return true; } // If segments don't match and there is not a wild- // card here, then stop with a failure. if(!s.equals(s1) && !s.equals(MATCH_CURRENT) && !s1.equals(MATCH_CURRENT)) { return false; } } return true; } } ----- gr...@cy... (Cyte Technologies Inc) |