= len || pattern.charAt(idx++) != '{')
+ {
+ internalError();
+ }
+
+ // Next char must be a digit
+ if (idx >= len || !Character.isDigit(pattern.charAt(idx)))
+ {
+ syntaxError("Expected digit");
+ }
+
+ // Get min ('m' of {m,n}) number
+ StringBuffer number = new StringBuffer();
+ while (idx < len && Character.isDigit(pattern.charAt(idx)))
+ {
+ number.append(pattern.charAt(idx++));
+ }
+ try
+ {
+ bracketMin[brackets] = Integer.parseInt(number.toString());
+ }
+ catch (NumberFormatException e)
+ {
+ syntaxError("Expected valid number");
+ }
+
+ // If out of input, fail
+ if (idx >= len)
+ {
+ syntaxError("Expected comma or right bracket");
+ }
+
+ // If end of expr, optional limit is 0
+ if (pattern.charAt(idx) == '}')
+ {
+ idx++;
+ bracketOpt[brackets] = 0;
+ return;
+ }
+
+ // Must have at least {m,} and maybe {m,n}.
+ if (idx >= len || pattern.charAt(idx++) != ',')
+ {
+ syntaxError("Expected comma");
+ }
+
+ // If out of input, fail
+ if (idx >= len)
+ {
+ syntaxError("Expected comma or right bracket");
+ }
+
+ // If {m,} max is unlimited
+ if (pattern.charAt(idx) == '}')
+ {
+ idx++;
+ bracketOpt[brackets] = bracketUnbounded;
+ return;
+ }
+
+ // Next char must be a digit
+ if (idx >= len || !Character.isDigit(pattern.charAt(idx)))
+ {
+ syntaxError("Expected digit");
+ }
+
+ // Get max number
+ number.setLength(0);
+ while (idx < len && Character.isDigit(pattern.charAt(idx)))
+ {
+ number.append(pattern.charAt(idx++));
+ }
+ try
+ {
+ bracketOpt[brackets] = Integer.parseInt(number.toString()) - bracketMin[brackets];
+ }
+ catch (NumberFormatException e)
+ {
+ syntaxError("Expected valid number");
+ }
+
+ // Optional repetitions must be >= 0
+ if (bracketOpt[brackets] < 0)
+ {
+ syntaxError("Bad range");
+ }
+
+ // Must have close brace
+ if (idx >= len || pattern.charAt(idx++) != '}')
+ {
+ syntaxError("Missing close brace");
+ }
+ }
+
+ /**
+ * Match an escape sequence. Handles quoted chars and octal escapes as well
+ * as normal escape characters. Always advances the input stream by the
+ * right amount. This code "understands" the subtle difference between an
+ * octal escape and a backref. You can access the type of ESC_CLASS or
+ * ESC_COMPLEX or ESC_BACKREF by looking at pattern[idx - 1].
+ * @return ESC_* code or character if simple escape
+ * @exception RESyntaxException Thrown if the regular expression has invalid syntax.
+ */
+ char escape() throws RESyntaxException
+ {
+ // "Shouldn't" happen
+ if (pattern.charAt(idx) != '\\')
+ {
+ internalError();
+ }
+
+ // Escape shouldn't occur as last character in string!
+ if (idx + 1 == len)
+ {
+ syntaxError("Escape terminates string");
+ }
+
+ // Switch on character after backslash
+ idx += 2;
+ char escapeChar = pattern.charAt(idx - 1);
+ switch (escapeChar)
+ {
+ case RE.E_BOUND:
+ case RE.E_NBOUND:
+ return ESC_COMPLEX;
+
+ case RE.E_ALNUM:
+ case RE.E_NALNUM:
+ case RE.E_SPACE:
+ case RE.E_NSPACE:
+ case RE.E_DIGIT:
+ case RE.E_NDIGIT:
+ return ESC_CLASS;
+
+ case 'u':
+ case 'x':
+ {
+ // Exact required hex digits for escape type
+ int hexDigits = (escapeChar == 'u' ? 4 : 2);
+
+ // Parse up to hexDigits characters from input
+ int val = 0;
+ for ( ; idx < len && hexDigits-- > 0; idx++)
+ {
+ // Get char
+ char c = pattern.charAt(idx);
+
+ // If it's a hexadecimal digit (0-9)
+ if (c >= '0' && c <= '9')
+ {
+ // Compute new value
+ val = (val << 4) + c - '0';
+ }
+ else
+ {
+ // If it's a hexadecimal letter (a-f)
+ c = Character.toLowerCase(c);
+ if (c >= 'a' && c <= 'f')
+ {
+ // Compute new value
+ val = (val << 4) + (c - 'a') + 10;
+ }
+ else
+ {
+ // If it's not a valid digit or hex letter, the escape must be invalid
+ // because hexDigits of input have not been absorbed yet.
+ syntaxError("Expected " + hexDigits + " hexadecimal digits after \\" + escapeChar);
+ }
+ }
+ }
+ return (char)val;
+ }
+
+ case 't':
+ return '\t';
+
+ case 'n':
+ return '\n';
+
+ case 'r':
+ return '\r';
+
+ case 'f':
+ return '\f';
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+
+ // An octal escape starts with a 0 or has two digits in a row
+ if ((idx < len && Character.isDigit(pattern.charAt(idx))) || escapeChar == '0')
+ {
+ // Handle \nnn octal escapes
+ int val = escapeChar - '0';
+ if (idx < len && Character.isDigit(pattern.charAt(idx)))
+ {
+ val = ((val << 3) + (pattern.charAt(idx++) - '0'));
+ if (idx < len && Character.isDigit(pattern.charAt(idx)))
+ {
+ val = ((val << 3) + (pattern.charAt(idx++) - '0'));
+ }
+ }
+ return (char)val;
+ }
+
+ // It's actually a backreference (\[1-9]), not an escape
+ return ESC_BACKREF;
+
+ default:
+
+ // Simple quoting of a character
+ return escapeChar;
+ }
+ }
+
+ /**
+ * Compile a character class
+ * @return Index of class node
+ * @exception RESyntaxException Thrown if the regular expression has invalid syntax.
+ */
+ int characterClass() throws RESyntaxException
+ {
+ // Check for bad calling or empty class
+ if (pattern.charAt(idx) != '[')
+ {
+ internalError();
+ }
+
+ // Check for unterminated or empty class
+ if ((idx + 1) >= len || pattern.charAt(++idx) == ']')
+ {
+ syntaxError("Empty or unterminated class");
+ }
+
+ // Check for POSIX character class
+ if (idx < len && pattern.charAt(idx) == ':')
+ {
+ // Skip colon
+ idx++;
+
+ // POSIX character classes are denoted with lowercase ASCII strings
+ int idxStart = idx;
+ while (idx < len && pattern.charAt(idx) >= 'a' && pattern.charAt(idx) <= 'z')
+ {
+ idx++;
+ }
+
+ // Should be a ":]" to terminate the POSIX character class
+ if ((idx + 1) < len && pattern.charAt(idx) == ':' && pattern.charAt(idx + 1) == ']')
+ {
+ // Get character class
+ String charClass = pattern.substring(idxStart, idx);
+
+ // Select the POSIX class id
+ Character i = (Character)hashPOSIX.get(charClass);
+ if (i != null)
+ {
+ // Move past colon and right bracket
+ idx += 2;
+
+ // Return new POSIX character class node
+ return node(RE.OP_POSIXCLASS, i.charValue());
+ }
+ syntaxError("Invalid POSIX character class '" + charClass + "'");
+ }
+ syntaxError("Invalid POSIX character class syntax");
+ }
+
+ // Try to build a class. Create OP_ANYOF node
+ int ret = node(RE.OP_ANYOF, 0);
+
+ // Parse class declaration
+ char CHAR_INVALID = Character.MAX_VALUE;
+ char last = CHAR_INVALID;
+ char simpleChar = 0;
+ boolean include = true;
+ boolean definingRange = false;
+ int idxFirst = idx;
+ char rangeStart = Character.MIN_VALUE;
+ char rangeEnd;
+ RERange range = new RERange();
+ while (idx < len && pattern.charAt(idx) != ']')
+ {
+
+ switchOnCharacter:
+
+ // Switch on character
+ switch (pattern.charAt(idx))
+ {
+ case '^':
+ include = !include;
+ if (idx == idxFirst)
+ {
+ range.include(Character.MIN_VALUE, Character.MAX_VALUE, true);
+ }
+ idx++;
+ continue;
+
+ case '\\':
+ {
+ // Escape always advances the stream
+ char c;
+ switch (c = escape ())
+ {
+ case ESC_COMPLEX:
+ case ESC_BACKREF:
+
+ // Word boundaries and backrefs not allowed in a character class!
+ syntaxError("Bad character class");
+
+ case ESC_CLASS:
+
+ // Classes can't be an endpoint of a range
+ if (definingRange)
+ {
+ syntaxError("Bad character class");
+ }
+
+ // Handle specific type of class (some are ok)
+ switch (pattern.charAt(idx - 1))
+ {
+ case RE.E_NSPACE:
+ case RE.E_NDIGIT:
+ case RE.E_NALNUM:
+ syntaxError("Bad character class");
+
+ case RE.E_SPACE:
+ range.include('\t', include);
+ range.include('\r', include);
+ range.include('\f', include);
+ range.include('\n', include);
+ range.include('\b', include);
+ range.include(' ', include);
+ break;
+
+ case RE.E_ALNUM:
+ range.include('a', 'z', include);
+ range.include('A', 'Z', include);
+ range.include('_', include);
+
+ // Fall through!
+
+ case RE.E_DIGIT:
+ range.include('0', '9', include);
+ break;
+ }
+
+ // Make last char invalid (can't be a range start)
+ last = CHAR_INVALID;
+ break;
+
+ default:
+
+ // Escape is simple so treat as a simple char
+ simpleChar = c;
+ break switchOnCharacter;
+ }
+ }
+ continue;
+
+ case '-':
+
+ // Start a range if one isn't already started
+ if (definingRange)
+ {
+ syntaxError("Bad class range");
+ }
+ definingRange = true;
+
+ // If no last character, start of range is 0
+ rangeStart = (last == CHAR_INVALID ? 0 : last);
+
+ // Premature end of range. define up to Character.MAX_VALUE
+ if ((idx + 1) < len && pattern.charAt(++idx) == ']')
+ {
+ simpleChar = Character.MAX_VALUE;
+ break;
+ }
+ continue;
+
+ default:
+ simpleChar = pattern.charAt(idx++);
+ break;
+ }
+
+ // Handle simple character simpleChar
+ if (definingRange)
+ {
+ // if we are defining a range make it now
+ rangeEnd = simpleChar;
+
+ // Actually create a range if the range is ok
+ if (rangeStart >= rangeEnd)
+ {
+ syntaxError("Bad character class");
+ }
+ range.include(rangeStart, rangeEnd, include);
+
+ // We are done defining the range
+ last = CHAR_INVALID;
+ definingRange = false;
+ }
+ else
+ {
+ // If simple character and not start of range, include it
+ if (idx >= len || pattern.charAt(idx) != '-')
+ {
+ range.include(simpleChar, include);
+ }
+ last = simpleChar;
+ }
+ }
+
+ // Shouldn't be out of input
+ if (idx == len)
+ {
+ syntaxError("Unterminated character class");
+ }
+
+ // Absorb the ']' end of class marker
+ idx++;
+
+ // Emit character class definition
+ instruction[ret + RE.offsetOpdata] = (char)range.num;
+ for (int i = 0; i < range.num; i++)
+ {
+ emit((char)range.minRange[i]);
+ emit((char)range.maxRange[i]);
+ }
+ return ret;
+ }
+
+ /**
+ * Absorb an atomic character string. This method is a little tricky because
+ * it can un-include the last character of string if a closure operator follows.
+ * This is correct because *+? have higher precedence than concatentation (thus
+ * ABC* means AB(C*) and NOT (ABC)*).
+ * @return Index of new atom node
+ * @exception RESyntaxException Thrown if the regular expression has invalid syntax.
+ */
+ int atom() throws RESyntaxException
+ {
+ // Create a string node
+ int ret = node(RE.OP_ATOM, 0);
+
+ // Length of atom
+ int lenAtom = 0;
+
+ // Loop while we've got input
+
+ atomLoop:
+
+ while (idx < len)
+ {
+ // Is there a next char?
+ if ((idx + 1) < len)
+ {
+ char c = pattern.charAt(idx + 1);
+
+ // If the next 'char' is an escape, look past the whole escape
+ if (pattern.charAt(idx) == '\\')
+ {
+ int idxEscape = idx;
+ escape();
+ if (idx < len)
+ {
+ c = pattern.charAt(idx);
+ }
+ idx = idxEscape;
+ }
+
+ // Switch on next char
+ switch (c)
+ {
+ case '{':
+ case '?':
+ case '*':
+ case '+':
+
+ // If the next character is a closure operator and our atom is non-empty, the
+ // current character should bind to the closure operator rather than the atom
+ if (lenAtom != 0)
+ {
+ break atomLoop;
+ }
+ }
+ }
+
+ // Switch on current char
+ switch (pattern.charAt(idx))
+ {
+ case ']':
+ case '^':
+ case '$':
+ case '.':
+ case '[':
+ case '(':
+ case ')':
+ case '|':
+ break atomLoop;
+
+ case '{':
+ case '?':
+ case '*':
+ case '+':
+
+ // We should have an atom by now
+ if (lenAtom == 0)
+ {
+ // No atom before closure
+ syntaxError("Missing operand to closure");
+ }
+ break atomLoop;
+
+ case '\\':
+
+ {
+ // Get the escaped character (advances input automatically)
+ int idxBeforeEscape = idx;
+ char c = escape();
+
+ // Check if it's a simple escape (as opposed to, say, a backreference)
+ if ((c & ESC_MASK) == ESC_MASK)
+ {
+ // Not a simple escape, so backup to where we were before the escape.
+ idx = idxBeforeEscape;
+ break atomLoop;
+ }
+
+ // Add escaped char to atom
+ emit(c);
+ lenAtom++;
+ }
+ break;
+
+ default:
+
+ // Add normal character to atom
+ emit(pattern.charAt(idx++));
+ lenAtom++;
+ break;
+ }
+ }
+
+ // This "shouldn't" happen
+ if (lenAtom == 0)
+ {
+ internalError();
+ }
+
+ // Emit the atom length into the program
+ instruction[ret + RE.offsetOpdata] = (char)lenAtom;
+ return ret;
+ }
+
+ /**
+ * Match a terminal node.
+ * @param flags Flags
+ * @return Index of terminal node (closeable)
+ * @exception RESyntaxException Thrown if the regular expression has invalid syntax.
+ */
+ int terminal(int[] flags) throws RESyntaxException
+ {
+ switch (pattern.charAt(idx))
+ {
+ case RE.OP_EOL:
+ case RE.OP_BOL:
+ case RE.OP_ANY:
+ return node(pattern.charAt(idx++), 0);
+
+ case '[':
+ return characterClass();
+
+ case '(':
+ return expr(flags);
+
+ case ')':
+ syntaxError("Unexpected close paren");
+
+ case '|':
+ internalError();
+
+ case ']':
+ syntaxError("Mismatched class");
+
+ case 0:
+ syntaxError("Unexpected end of input");
+
+ case '?':
+ case '+':
+ case '{':
+ case '*':
+ syntaxError("Missing operand to closure");
+
+ case '\\':
+ {
+ // Don't forget, escape() advances the input stream!
+ int idxBeforeEscape = idx;
+
+ // Switch on escaped character
+ switch (escape())
+ {
+ case ESC_CLASS:
+ case ESC_COMPLEX:
+ flags[0] &= ~NODE_NULLABLE;
+ return node(RE.OP_ESCAPE, pattern.charAt(idx - 1));
+
+ case ESC_BACKREF:
+ {
+ char backreference = (char)(pattern.charAt(idx - 1) - '0');
+ if (parens <= backreference)
+ {
+ syntaxError("Bad backreference");
+ }
+ flags[0] |= NODE_NULLABLE;
+ return node(RE.OP_BACKREF, backreference);
+ }
+
+ default:
+
+ // We had a simple escape and we want to have it end up in
+ // an atom, so we back up and fall though to the default handling
+ idx = idxBeforeEscape;
+ flags[0] &= ~NODE_NULLABLE;
+ break;
+ }
+ }
+ }
+
+ // Everything above either fails or returns.
+ // If it wasn't one of the above, it must be the start of an atom.
+ flags[0] &= ~NODE_NULLABLE;
+ return atom();
+ }
+
+ /**
+ * Compile a possibly closured terminal
+ * @param flags Flags passed by reference
+ * @return Index of closured node
+ * @exception RESyntaxException Thrown if the regular expression has invalid syntax.
+ */
+ int closure(int[] flags) throws RESyntaxException
+ {
+ // Before terminal
+ int idxBeforeTerminal = idx;
+
+ // Values to pass by reference to terminal()
+ int[] terminalFlags = { NODE_NORMAL };
+
+ // Get terminal symbol
+ int ret = terminal(terminalFlags);
+
+ // Or in flags from terminal symbol
+ flags[0] |= terminalFlags[0];
+
+ // Advance input, set NODE_NULLABLE flag and do sanity checks
+ if (idx >= len)
+ {
+ return ret;
+ }
+ boolean greedy = true;
+ char closureType = pattern.charAt(idx);
+ switch (closureType)
+ {
+ case '?':
+ case '*':
+
+ // The current node can be null
+ flags[0] |= NODE_NULLABLE;
+
+ case '+':
+
+ // Eat closure character
+ idx++;
+
+ case '{':
+
+ // Don't allow blantant stupidity
+ int opcode = instruction[ret + RE.offsetOpcode];
+ if (opcode == RE.OP_BOL || opcode == RE.OP_EOL)
+ {
+ syntaxError("Bad closure operand");
+ }
+ if ((terminalFlags[0] & NODE_NULLABLE) != 0)
+ {
+ syntaxError("Closure operand can't be nullable");
+ }
+ break;
+ }
+
+ // If the next character is a '?', make the closure non-greedy (reluctant)
+ if (idx < len && pattern.charAt(idx) == '?')
+ {
+ idx++;
+ greedy = false;
+ }
+
+ if (greedy)
+ {
+ // Actually do the closure now
+ switch (closureType)
+ {
+ case '{':
+ {
+ // We look for our bracket in the list
+ boolean found = false;
+ int i;
+ allocBrackets();
+ for (i = 0; i < brackets; i++)
+ {
+ if (bracketStart[i] == idx)
+ {
+ found = true;
+ break;
+ }
+ }
+
+ // If its not in the list we parse the {m,n}
+ if (!found)
+ {
+ if (brackets >= maxBrackets)
+ {
+ reallocBrackets();
+ }
+ bracketStart[brackets] = idx;
+ bracket();
+ bracketEnd[brackets] = idx;
+ i = brackets++;
+ }
+
+ // Process min first
+ if (bracketMin[i]-- > 0)
+ {
+ if (bracketMin[i] > 0 || bracketOpt[i] != 0) {
+ // Rewind stream and run it through again - more matchers coming
+ idx = idxBeforeTerminal;
+ } else {
+ // Bug #1030: No optinal matches - no need to rewind
+ idx = bracketEnd[i];
+ }
+ break;
+ }
+
+ // Do the right thing for maximum ({m,})
+ if (bracketOpt[i] == bracketUnbounded)
+ {
+ // Drop through now and closure expression.
+ // We are done with the {m,} expr, so skip rest
+ closureType = '*';
+ bracketOpt[i] = 0;
+ idx = bracketEnd[i];
+ }
+ else
+ if (bracketOpt[i]-- > 0)
+ {
+ if (bracketOpt[i] > 0)
+ {
+ // More optional matchers - 'play it again sam!'
+ idx = idxBeforeTerminal;
+ } else {
+ // Bug #1030: We are done - this one is last and optional
+ idx = bracketEnd[i];
+ }
+ // Drop through to optionally close
+ closureType = '?';
+ }
+ else
+ {
+ // Rollback terminal - neither min nor opt matchers present
+ lenInstruction = ret;
+ node(RE.OP_NOTHING, 0);
+
+ // We are done. skip the rest of {m,n} expr
+ idx = bracketEnd[i];
+ break;
+ }
+ }
+
+ // Fall through!
+
+ case '?':
+ case '*':
+
+ if (!greedy)
+ {
+ break;
+ }
+
+ if (closureType == '?')
+ {
+ // X? is compiled as (X|)
+ nodeInsert(RE.OP_BRANCH, 0, ret); // branch before X
+ setNextOfEnd(ret, node (RE.OP_BRANCH, 0)); // inserted branch to option
+ int nothing = node (RE.OP_NOTHING, 0); // which is OP_NOTHING
+ setNextOfEnd(ret, nothing); // point (second) branch to OP_NOTHING
+ setNextOfEnd(ret + RE.nodeSize, nothing); // point the end of X to OP_NOTHING node
+ }
+
+ if (closureType == '*')
+ {
+ // X* is compiled as (X{gotoX}|)
+ nodeInsert(RE.OP_BRANCH, 0, ret); // branch before X
+ setNextOfEnd(ret + RE.nodeSize, node(RE.OP_BRANCH, 0)); // end of X points to an option
+ setNextOfEnd(ret + RE.nodeSize, node(RE.OP_GOTO, 0)); // to goto
+ setNextOfEnd(ret + RE.nodeSize, ret); // the start again
+ setNextOfEnd(ret, node(RE.OP_BRANCH, 0)); // the other option is
+ setNextOfEnd(ret, node(RE.OP_NOTHING, 0)); // OP_NOTHING
+ }
+ break;
+
+ case '+':
+ {
+ // X+ is compiled as X({gotoX}|)
+ int branch;
+ branch = node(RE.OP_BRANCH, 0); // a new branch
+ setNextOfEnd(ret, branch); // is added to the end of X
+ setNextOfEnd(node(RE.OP_GOTO, 0), ret); // one option is to go back to the start
+ setNextOfEnd(branch, node(RE.OP_BRANCH, 0)); // the other option
+ setNextOfEnd(ret, node(RE.OP_NOTHING, 0)); // is OP_NOTHING
+ }
+ break;
+ }
+ }
+ else
+ {
+ // Add end after closured subexpr
+ setNextOfEnd(ret, node(RE.OP_END, 0));
+
+ // Actually do the closure now
+ switch (closureType)
+ {
+ case '?':
+ nodeInsert(RE.OP_RELUCTANTMAYBE, 0, ret);
+ break;
+
+ case '*':
+ nodeInsert(RE.OP_RELUCTANTSTAR, 0, ret);
+ break;
+
+ case '+':
+ nodeInsert(RE.OP_RELUCTANTPLUS, 0, ret);
+ break;
+ }
+
+ // Point to the expr after the closure
+ setNextOfEnd(ret, lenInstruction);
+ }
+ return ret;
+ }
+
+ /**
+ * Compile one branch of an or operator (implements concatenation)
+ * @param flags Flags passed by reference
+ * @return Pointer to branch node
+ * @exception RESyntaxException Thrown if the regular expression has invalid syntax.
+ */
+ int branch(int[] flags) throws RESyntaxException
+ {
+ // Get each possibly closured piece and concat
+ int node;
+ int ret = node(RE.OP_BRANCH, 0);
+ int chain = -1;
+ int[] closureFlags = new int[1];
+ boolean nullable = true;
+ while (idx < len && pattern.charAt(idx) != '|' && pattern.charAt(idx) != ')')
+ {
+ // Get new node
+ closureFlags[0] = NODE_NORMAL;
+ node = closure(closureFlags);
+ if (closureFlags[0] == NODE_NORMAL)
+ {
+ nullable = false;
+ }
+
+ // If there's a chain, append to the end
+ if (chain != -1)
+ {
+ setNextOfEnd(chain, node);
+ }
+
+ // Chain starts at current
+ chain = node;
+ }
+
+ // If we don't run loop, make a nothing node
+ if (chain == -1)
+ {
+ node(RE.OP_NOTHING, 0);
+ }
+
+ // Set nullable flag for this branch
+ if (nullable)
+ {
+ flags[0] |= NODE_NULLABLE;
+ }
+ return ret;
+ }
+
+ /**
+ * Compile an expression with possible parens around it. Paren matching
+ * is done at this level so we can tie the branch tails together.
+ * @param flags Flag value passed by reference
+ * @return Node index of expression in instruction array
+ * @exception RESyntaxException Thrown if the regular expression has invalid syntax.
+ */
+ int expr(int[] flags) throws RESyntaxException
+ {
+ // Create open paren node unless we were called from the top level (which has no parens)
+ int paren = -1;
+ int ret = -1;
+ int closeParens = parens;
+ if ((flags[0] & NODE_TOPLEVEL) == 0 && pattern.charAt(idx) == '(')
+ {
+ // if its a cluster ( rather than a proper subexpression ie with backrefs )
+ if ( idx + 2 < len && pattern.charAt( idx + 1 ) == '?' && pattern.charAt( idx + 2 ) == ':' )
+ {
+ paren = 2;
+ idx += 3;
+ ret = node( RE.OP_OPEN_CLUSTER, 0 );
+ }
+ else
+ {
+ paren = 1;
+ idx++;
+ ret = node(RE.OP_OPEN, parens++);
+ }
+ }
+ flags[0] &= ~NODE_TOPLEVEL;
+
+ // Create a branch node
+ int branch = branch(flags);
+ if (ret == -1)
+ {
+ ret = branch;
+ }
+ else
+ {
+ setNextOfEnd(ret, branch);
+ }
+
+ // Loop through branches
+ while (idx < len && pattern.charAt(idx) == '|')
+ {
+ idx++;
+ branch = branch(flags);
+ setNextOfEnd(ret, branch);
+ }
+
+ // Create an ending node (either a close paren or an OP_END)
+ int end;
+ if ( paren > 0 )
+ {
+ if (idx < len && pattern.charAt(idx) == ')')
+ {
+ idx++;
+ }
+ else
+ {
+ syntaxError("Missing close paren");
+ }
+ if ( paren == 1 )
+ {
+ end = node(RE.OP_CLOSE, closeParens);
+ }
+ else
+ {
+ end = node( RE.OP_CLOSE_CLUSTER, 0 );
+ }
+ }
+ else
+ {
+ end = node(RE.OP_END, 0);
+ }
+
+ // Append the ending node to the ret nodelist
+ setNextOfEnd(ret, end);
+
+ // Hook the ends of each branch to the end node
+ int currentNode = ret;
+ int nextNodeOffset = instruction[ currentNode + RE.offsetNext ];
+ // while the next node o
+ while ( nextNodeOffset != 0 && currentNode < lenInstruction )
+ {
+ // If branch, make the end of the branch's operand chain point to the end node.
+ if ( instruction[ currentNode + RE.offsetOpcode ] == RE.OP_BRANCH )
+ {
+ setNextOfEnd( currentNode + RE.nodeSize, end );
+ }
+ nextNodeOffset = instruction[ currentNode + RE.offsetNext ];
+ currentNode += nextNodeOffset;
+ }
+
+ // Return the node list
+ return ret;
+ }
+
+ /**
+ * Compiles a regular expression pattern into a program runnable by the pattern
+ * matcher class 'RE'.
+ * @param pattern Regular expression pattern to compile (see RECompiler class
+ * for details).
+ * @return A compiled regular expression program.
+ * @exception RESyntaxException Thrown if the regular expression has invalid syntax.
+ * @see RECompiler
+ * @see RE
+ */
+ public REProgram compile(String pattern) throws RESyntaxException
+ {
+ // Initialize variables for compilation
+ this.pattern = pattern; // Save pattern in instance variable
+ len = pattern.length(); // Precompute pattern length for speed
+ idx = 0; // Set parsing index to the first character
+ lenInstruction = 0; // Set emitted instruction count to zero
+ parens = 1; // Set paren level to 1 (the implicit outer parens)
+ brackets = 0; // No bracketed closures yet
+
+ // Initialize pass by reference flags value
+ int[] flags = { NODE_TOPLEVEL };
+
+ // Parse expression
+ expr(flags);
+
+ // Should be at end of input
+ if (idx != len)
+ {
+ if (pattern.charAt(idx) == ')')
+ {
+ syntaxError("Unmatched close paren");
+ }
+ syntaxError("Unexpected input remains");
+ }
+
+ // Return the result
+ char[] ins = new char[lenInstruction];
+ System.arraycopy(instruction, 0, ins, 0, lenInstruction);
+ return new REProgram(parens, ins);
+ }
+
+ /**
+ * Local, nested class for maintaining character ranges for character classes.
+ */
+ class RERange
+ {
+ int size = 16; // Capacity of current range arrays
+ int[] minRange = new int[size]; // Range minima
+ int[] maxRange = new int[size]; // Range maxima
+ int num = 0; // Number of range array elements in use
+
+ /**
+ * Deletes the range at a given index from the range lists
+ * @param index Index of range to delete from minRange and maxRange arrays.
+ */
+ void delete(int index)
+ {
+ // Return if no elements left or index is out of range
+ if (num == 0 || index >= num)
+ {
+ return;
+ }
+
+ // Move elements down
+ while (++index < num)
+ {
+ if (index - 1 >= 0)
+ {
+ minRange[index-1] = minRange[index];
+ maxRange[index-1] = maxRange[index];
+ }
+ }
+
+ // One less element now
+ num--;
+ }
+
+ /**
+ * Merges a range into the range list, coalescing ranges if possible.
+ * @param min Minimum end of range
+ * @param max Maximum end of range
+ */
+ void merge(int min, int max)
+ {
+ // Loop through ranges
+ for (int i = 0; i < num; i++)
+ {
+ // Min-max is subsumed by minRange[i]-maxRange[i]
+ if (min >= minRange[i] && max <= maxRange[i])
+ {
+ return;
+ }
+
+ // Min-max subsumes minRange[i]-maxRange[i]
+ else if (min <= minRange[i] && max >= maxRange[i])
+ {
+ delete(i);
+ merge(min, max);
+ return;
+ }
+
+ // Min is in the range, but max is outside
+ else if (min >= minRange[i] && min <= maxRange[i])
+ {
+ delete(i);
+ min = minRange[i];
+ merge(min, max);
+ return;
+ }
+
+ // Max is in the range, but min is outside
+ else if (max >= minRange[i] && max <= maxRange[i])
+ {
+ delete(i);
+ max = maxRange[i];
+ merge(min, max);
+ return;
+ }
+ }
+
+ // Must not overlap any other ranges
+ if (num >= size)
+ {
+ size *= 2;
+ int[] newMin = new int[size];
+ int[] newMax = new int[size];
+ System.arraycopy(minRange, 0, newMin, 0, num);
+ System.arraycopy(maxRange, 0, newMax, 0, num);
+ minRange = newMin;
+ maxRange = newMax;
+ }
+ minRange[num] = min;
+ maxRange[num] = max;
+ num++;
+ }
+
+ /**
+ * Removes a range by deleting or shrinking all other ranges
+ * @param min Minimum end of range
+ * @param max Maximum end of range
+ */
+ void remove(int min, int max)
+ {
+ // Loop through ranges
+ for (int i = 0; i < num; i++)
+ {
+ // minRange[i]-maxRange[i] is subsumed by min-max
+ if (minRange[i] >= min && maxRange[i] <= max)
+ {
+ delete(i);
+ i--;
+ return;
+ }
+
+ // min-max is subsumed by minRange[i]-maxRange[i]
+ else if (min >= minRange[i] && max <= maxRange[i])
+ {
+ int minr = minRange[i];
+ int maxr = maxRange[i];
+ delete(i);
+ if (minr < min)
+ {
+ merge(minr, min - 1);
+ }
+ if (max < maxr)
+ {
+ merge(max + 1, maxr);
+ }
+ return;
+ }
+
+ // minRange is in the range, but maxRange is outside
+ else if (minRange[i] >= min && minRange[i] <= max)
+ {
+ minRange[i] = max + 1;
+ return;
+ }
+
+ // maxRange is in the range, but minRange is outside
+ else if (maxRange[i] >= min && maxRange[i] <= max)
+ {
+ maxRange[i] = min - 1;
+ return;
+ }
+ }
+ }
+
+ /**
+ * Includes (or excludes) the range from min to max, inclusive.
+ * @param min Minimum end of range
+ * @param max Maximum end of range
+ * @param include True if range should be included. False otherwise.
+ */
+ void include(int min, int max, boolean include)
+ {
+ if (include)
+ {
+ merge(min, max);
+ }
+ else
+ {
+ remove(min, max);
+ }
+ }
+
+ /**
+ * Includes a range with the same min and max
+ * @param minmax Minimum and maximum end of range (inclusive)
+ * @param include True if range should be included. False otherwise.
+ */
+ void include(char minmax, boolean include)
+ {
+ include(minmax, minmax, include);
+ }
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/CharacterArrayCharacterIterator.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/CharacterArrayCharacterIterator.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/CharacterArrayCharacterIterator.java (revision 2)
@@ -0,0 +1,104 @@
+package org.apache.regexp;
+
+/*
+ * ====================================================================
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Jakarta-Regexp", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+
+/** Encapsulates String
+ *
+ * @author Ales Novak
+ */
+public final class CharacterArrayCharacterIterator implements CharacterIterator
+{
+ /** encapsulated */
+ private final char[] src;
+ /** offset in the char array */
+ private final int off;
+ /** used portion of the array */
+ private final int len;
+
+ /** @param src - encapsulated String */
+ public CharacterArrayCharacterIterator(char[] src, int off, int len)
+ {
+ this.src = src;
+ this.off = off;
+ this.len = len;
+ }
+
+ /** @return a substring */
+ public String substring(int offset, int length)
+ {
+ return new String(src, off + offset, length);
+ }
+
+ /** @return a substring */
+ public String substring(int offset)
+ {
+ return new String(src, off + offset, len);
+ }
+
+ /** @return a character at the specified position. */
+ public char charAt(int pos)
+ {
+ return src[off + pos];
+ }
+
+ /** @return true iff if the specified index is after the end of the character stream */
+ public boolean isEnd(int pos)
+ {
+ return (pos >= len);
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/StreamCharacterIterator.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/StreamCharacterIterator.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/StreamCharacterIterator.java (revision 2)
@@ -0,0 +1,197 @@
+package org.apache.regexp;
+
+/*
+ * ====================================================================
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Jakarta-Regexp", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+
+import java.io.InputStream;
+import java.io.IOException;
+
+/** Encapsulates InputStream, ...
+ *
+ * @author Ales Novak
+ */
+public final class StreamCharacterIterator implements CharacterIterator
+{
+ /** Underlying is */
+ private final InputStream is;
+
+ /** Buffer of read chars */
+ private final StringBuffer buff;
+
+ /** read end? */
+ private boolean closed;
+
+ /** @param is an InputStream, which is parsed */
+ public StreamCharacterIterator(InputStream is)
+ {
+ this.is = is;
+ this.buff = new StringBuffer(512);
+ this.closed = false;
+ }
+
+ /** @return a substring */
+ public String substring(int offset, int length)
+ {
+ try
+ {
+ ensure(offset + length);
+ return buff.toString().substring(offset, length);
+ }
+ catch (IOException e)
+ {
+ throw new StringIndexOutOfBoundsException(e.getMessage());
+ }
+ }
+
+ /** @return a substring */
+ public String substring(int offset)
+ {
+ try
+ {
+ readAll();
+ return buff.toString().substring(offset);
+ }
+ catch (IOException e)
+ {
+ throw new StringIndexOutOfBoundsException(e.getMessage());
+ }
+ }
+
+
+ /** @return a character at the specified position. */
+ public char charAt(int pos)
+ {
+ try
+ {
+ ensure(pos);
+ return buff.charAt(pos);
+ }
+ catch (IOException e)
+ {
+ throw new StringIndexOutOfBoundsException(e.getMessage());
+ }
+ }
+
+ /** @return true iff if the specified index is after the end of the character stream */
+ public boolean isEnd(int pos)
+ {
+ if (buff.length() > pos)
+ {
+ return false;
+ }
+ else
+ {
+ try
+ {
+ ensure(pos);
+ return (buff.length() <= pos);
+ }
+ catch (IOException e)
+ {
+ throw new StringIndexOutOfBoundsException(e.getMessage());
+ }
+ }
+ }
+
+ /** Reads n characters from the stream and appends them to the buffer */
+ private int read(int n) throws IOException
+ {
+ if (closed)
+ {
+ return 0;
+ }
+
+ int c;
+ int i = n;
+ while (--i >= 0)
+ {
+ c = is.read();
+ if (c < 0) // EOF
+ {
+ closed = true;
+ break;
+ }
+ buff.append((char) c);
+ }
+ return n - i;
+ }
+
+ /** Reads rest of the stream. */
+ private void readAll() throws IOException
+ {
+ while(! closed)
+ {
+ read(1000);
+ }
+ }
+
+ /** Reads chars up to the idx */
+ private void ensure(int idx) throws IOException
+ {
+ if (closed)
+ {
+ return;
+ }
+
+ if (idx < buff.length())
+ {
+ return;
+ }
+
+ read(idx + 1 - buff.length());
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/REUtil.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/REUtil.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/REUtil.java (revision 2)
@@ -0,0 +1,99 @@
+package org.apache.regexp;
+
+/*
+ * ====================================================================
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Jakarta-Regexp", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+
+/**
+ * This is a class that contains utility helper methods for this package.
+ *
+ * @author Jonathan Locke
+ * @version $Id: REUtil.java,v 1.2 2000/04/30 20:42:35 jon Exp $
+ */
+public class REUtil
+{
+ /** complex: */
+ private static final String complexPrefix = "complex:";
+
+ /**
+ * Creates a regular expression, permitting simple or complex syntax
+ * @param expression The expression, beginning with a prefix if it's complex or
+ * having no prefix if it's simple
+ * @param matchFlags Matching style flags
+ * @return The regular expression object
+ * @exception RESyntaxException thrown in case of error
+ */
+ public static RE createRE(String expression, int matchFlags) throws RESyntaxException
+ {
+ if (expression.startsWith(complexPrefix))
+ {
+ return new RE(expression.substring(complexPrefix.length()), matchFlags);
+ }
+ return new RE(RE.simplePatternToFullRegularExpression(expression), matchFlags);
+ }
+
+ /**
+ * Creates a regular expression, permitting simple or complex syntax
+ * @param expression The expression, beginning with a prefix if it's complex or
+ * having no prefix if it's simple
+ * @return The regular expression object
+ * @exception RESyntaxException thrown in case of error
+ */
+ public static RE createRE(String expression) throws RESyntaxException
+ {
+ return createRE(expression, RE.MATCH_NORMAL);
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/CharacterIterator.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/CharacterIterator.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/CharacterIterator.java (revision 2)
@@ -0,0 +1,78 @@
+package org.apache.regexp;
+
+/*
+ * ====================================================================
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Jakarta-Regexp", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+
+/** Encapsulates different types of character sources - String, InputStream, ...
+ * Defines a set of common methods
+ *
+ * @author Ales Novak
+ */
+public interface CharacterIterator
+{
+ /** @return a substring */
+ String substring(int offset, int length);
+
+ /** @return a substring */
+ String substring(int offset);
+
+ /** @return a character at the specified position. */
+ char charAt(int pos);
+
+ /** @return true iff if the specified index is after the end of the character stream */
+ boolean isEnd(int pos);
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/RE.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/RE.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/RE.java (revision 2)
@@ -0,0 +1,1848 @@
+package org.apache.regexp;
+
+/*
+ * ====================================================================
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999-2003 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Jakarta-Regexp", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+
+import java.io.Serializable;
+import java.util.Vector;
+
+/**
+ * RE is an efficient, lightweight regular expression evaluator/matcher
+ * class. Regular expressions are pattern descriptions which enable
+ * sophisticated matching of strings. In addition to being able to
+ * match a string against a pattern, you can also extract parts of the
+ * match. This is especially useful in text parsing! Details on the
+ * syntax of regular expression patterns are given below.
+ *
+ *
+ *
+ * To compile a regular expression (RE), you can simply construct an RE
+ * matcher object from the string specification of the pattern, like this:
+ *
+ *
+ *
+ * RE r = new RE("a*b");
+ *
+ *
+ *
+ *
+ *
+ * Once you have done this, you can call either of the RE.match methods to
+ * perform matching on a String. For example:
+ *
+ *
+ *
+ * boolean matched = r.match("aaaab");
+ *
+ *
+ *
+ * will cause the boolean matched to be set to true because the
+ * pattern "a*b" matches the string "aaaab".
+ *
+ *
+ * If you were interested in the number of a's which matched the
+ * first part of our example expression, you could change the expression to
+ * "(a*)b". Then when you compiled the expression and matched it against
+ * something like "xaaaab", you would get results like this:
+ *
+ *
+ *
+ * RE r = new RE("(a*)b"); // Compile expression
+ * boolean matched = r.match("xaaaab"); // Match against "xaaaab"
+ *
+ *
+ *
+ * String wholeExpr = r.getParen(0); // wholeExpr will be 'aaaab'
+ * String insideParens = r.getParen(1); // insideParens will be 'aaaa'
+ *
+ *
+ *
+ * int startWholeExpr = r.getParenStart(0); // startWholeExpr will be index 1
+ * int endWholeExpr = r.getParenEnd(0); // endWholeExpr will be index 6
+ * int lenWholeExpr = r.getParenLength(0); // lenWholeExpr will be 5
+ *
+ *
+ *
+ * int startInside = r.getParenStart(1); // startInside will be index 1
+ * int endInside = r.getParenEnd(1); // endInside will be index 5
+ * int lenInside = r.getParenLength(1); // lenInside will be 4
+ *
+ *
+ *
+ * You can also refer to the contents of a parenthesized expression
+ * within a regular expression itself. This is called a
+ * 'backreference'. The first backreference in a regular expression is
+ * denoted by \1, the second by \2 and so on. So the expression:
+ *
+ *
+ *
+ * ([0-9]+)=\1
+ *
+ *
+ *
+ * will match any string of the form n=n (like 0=0 or 2=2).
+ *
+ *
+ *
+ * The full regular expression syntax accepted by RE is described here:
+ *
+ *
+ *
+ *
+ *
+ * Characters
+ *
+ *
+ *
+ * unicodeChar Matches any identical unicode character
+ * \ Used to quote a meta-character (like '*')
+ * \\ Matches a single '\' character
+ * \0nnn Matches a given octal character
+ * \xhh Matches a given 8-bit hexadecimal character
+ * \\uhhhh Matches a given 16-bit hexadecimal character
+ * \t Matches an ASCII tab character
+ * \n Matches an ASCII newline character
+ * \r Matches an ASCII return character
+ * \f Matches an ASCII form feed character
+ *
+ *
+ *
+ * Character Classes
+ *
+ *
+ *
+ * [abc] Simple character class
+ * [a-zA-Z] Character class with ranges
+ * [^abc] Negated character class
+ *
+ *
+ *
+ * Standard POSIX Character Classes
+ *
+ *
+ *
+ * [:alnum:] Alphanumeric characters.
+ * [:alpha:] Alphabetic characters.
+ * [:blank:] Space and tab characters.
+ * [:cntrl:] Control characters.
+ * [:digit:] Numeric characters.
+ * [:graph:] Characters that are printable and are also visible.
+ * (A space is printable, but not visible, while an
+ * `a' is both.)
+ * [:lower:] Lower-case alphabetic characters.
+ * [:print:] Printable characters (characters that are not
+ * control characters.)
+ * [:punct:] Punctuation characters (characters that are not letter,
+ * digits, control characters, or space characters).
+ * [:space:] Space characters (such as space, tab, and formfeed,
+ * to name a few).
+ * [:upper:] Upper-case alphabetic characters.
+ * [:xdigit:] Characters that are hexadecimal digits.
+ *
+ *
+ *
+ * Non-standard POSIX-style Character
+ * Classes
+ *
+ *
+ *
+ * [:javastart:] Start of a Java identifier
+ * [:javapart:] Part of a Java identifier
+ *
+ *
+ *
+ * Predefined Classes
+ *
+ *
+ *
+ * . Matches any character other than newline
+ * \w Matches a "word" character (alphanumeric plus "_")
+ * \W Matches a non-word character
+ * \s Matches a whitespace character
+ * \S Matches a non-whitespace character
+ * \d Matches a digit character
+ * \D Matches a non-digit character
+ *
+ *
+ *
+ * Boundary Matchers
+ *
+ *
+ *
+ * ^ Matches only at the beginning of a line
+ * $ Matches only at the end of a line
+ * \b Matches only at a word boundary
+ * \B Matches only at a non-word boundary
+ *
+ *
+ *
+ * Greedy Closures
+ *
+ *
+ *
+ * A* Matches A 0 or more times (greedy)
+ * A+ Matches A 1 or more times (greedy)
+ * A? Matches A 1 or 0 times (greedy)
+ * A{n} Matches A exactly n times (greedy)
+ * A{n,} Matches A at least n times (greedy)
+ * A{n,m} Matches A at least n but not more than m times (greedy)
+ *
+ *
+ *
+ * Reluctant Closures
+ *
+ *
+ *
+ * A*? Matches A 0 or more times (reluctant)
+ * A+? Matches A 1 or more times (reluctant)
+ * A?? Matches A 0 or 1 times (reluctant)
+ *
+ *
+ *
+ * Logical Operators
+ *
+ *
+ *
+ * AB Matches A followed by B
+ * A|B Matches either A or B
+ * (A) Used for subexpression grouping
+ * (?:A) Used for subexpression clustering (just like grouping but
+ * no backrefs)
+ *
+ *
+ *
+ * Backreferences
+ *
+ *
+ *
+ * \1 Backreference to 1st parenthesized subexpression
+ * \2 Backreference to 2nd parenthesized subexpression
+ * \3 Backreference to 3rd parenthesized subexpression
+ * \4 Backreference to 4th parenthesized subexpression
+ * \5 Backreference to 5th parenthesized subexpression
+ * \6 Backreference to 6th parenthesized subexpression
+ * \7 Backreference to 7th parenthesized subexpression
+ * \8 Backreference to 8th parenthesized subexpression
+ * \9 Backreference to 9th parenthesized subexpression
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * All closure operators (+, *, ?, {m,n}) are greedy by default, meaning
+ * that they match as many elements of the string as possible without
+ * causing the overall match to fail. If you want a closure to be
+ * reluctant (non-greedy), you can simply follow it with a '?'. A
+ * reluctant closure will match as few elements of the string as
+ * possible when finding matches. {m,n} closures don't currently
+ * support reluctancy.
+ *
+ *
+ *
+ * RE runs programs compiled by the RECompiler class. But the RE
+ * matcher class does not include the actual regular expression compiler
+ * for reasons of efficiency. In fact, if you want to pre-compile one
+ * or more regular expressions, the 'recompile' class can be invoked
+ * from the command line to produce compiled output like this:
+ *
+ *
+ *
+ * // Pre-compiled regular expression "a*b"
+ * char[] re1Instructions =
+ * {
+ * 0x007c, 0x0000, 0x001a, 0x007c, 0x0000, 0x000d, 0x0041,
+ * 0x0001, 0x0004, 0x0061, 0x007c, 0x0000, 0x0003, 0x0047,
+ * 0x0000, 0xfff6, 0x007c, 0x0000, 0x0003, 0x004e, 0x0000,
+ * 0x0003, 0x0041, 0x0001, 0x0004, 0x0062, 0x0045, 0x0000,
+ * 0x0000,
+ * };
+ *
+ *
+ *
+ * REProgram re1 = new REProgram(re1Instructions);
+ *
+ *
+ *
+ * You can then construct a regular expression matcher (RE) object from
+ * the pre-compiled expression re1 and thus avoid the overhead of
+ * compiling the expression at runtime. If you require more dynamic
+ * regular expressions, you can construct a single RECompiler object and
+ * re-use it to compile each expression. * Similarly, you can change the
+ * program run by a given matcher object at any time. * However, RE and
+ * RECompiler are not threadsafe (for efficiency reasons, and because
+ * requiring thread safety in this class is deemed to be a rare
+ * requirement), so you will need to construct a separate compiler or
+ * matcher object for each thread (unless you do thread synchronization
+ * yourself).
+ *
+ *
+ *
+ *
+ *
+ * ISSUES:
+ *
+ *
+ * - com.weusours.util.re is not currently compatible with all
+ * standard POSIX regcomp flags
+ * - com.weusours.util.re does not support POSIX equivalence classes
+ * ([=foo=] syntax) (I18N/locale issue)
+ * - com.weusours.util.re does not support nested POSIX character
+ * classes (definitely should, but not completely trivial)
+ * - com.weusours.util.re Does not support POSIX character collation
+ * concepts ([.foo.] syntax) (I18N/locale issue)
+ * - Should there be different matching styles (simple, POSIX, Perl etc?)
+ * - Should RE support character iterators (for backwards RE matching!)?
+ * - Should RE support reluctant {m,n} closures (does anyone care)?
+ * - Not *all* possibilities are considered for greediness when backreferences
+ * are involved (as POSIX suggests should be the case). The POSIX RE
+ * "(ac*)c*d[ac]*\1", when matched against "acdacaa" should yield a match
+ * of acdacaa where \1 is "a". This is not the case in this RE package,
+ * and actually Perl doesn't go to this extent either! Until someone
+ * actually complains about this, I'm not sure it's worth "fixing".
+ * If it ever is fixed, test #137 in RETest.txt should be updated.
+ *
+ *
+ *
+ *
+ * @see recompile
+ * @see RECompiler
+ *
+ * @author Jonathan Locke
+ * @author Tobias Schäfer
+ * @version $Id: RE.java,v 1.13 2003/06/02 02:18:41 vgritsenko Exp $
+ */
+public class RE implements Serializable
+{
+ /**
+ * Specifies normal, case-sensitive matching behaviour.
+ */
+ public static final int MATCH_NORMAL = 0x0000;
+
+ /**
+ * Flag to indicate that matching should be case-independent (folded)
+ */
+ public static final int MATCH_CASEINDEPENDENT = 0x0001;
+
+ /**
+ * Newlines should match as BOL/EOL (^ and $)
+ */
+ public static final int MATCH_MULTILINE = 0x0002;
+
+ /**
+ * Consider all input a single body of text - newlines are matched by .
+ */
+ public static final int MATCH_SINGLELINE = 0x0004;
+
+ /************************************************
+ * *
+ * The format of a node in a program is: *
+ * *
+ * [ OPCODE ] [ OPDATA ] [ OPNEXT ] [ OPERAND ] *
+ * *
+ * char OPCODE - instruction *
+ * char OPDATA - modifying data *
+ * char OPNEXT - next node (relative offset) *
+ * *
+ ************************************************/
+
+ // Opcode Char Opdata/Operand Meaning
+ // ---------- ---------- --------------- --------------------------------------------------
+ static final char OP_END = 'E'; // end of program
+ static final char OP_BOL = '^'; // match only if at beginning of line
+ static final char OP_EOL = '$'; // match only if at end of line
+ static final char OP_ANY = '.'; // match any single character except newline
+ static final char OP_ANYOF = '['; // count/ranges match any char in the list of ranges
+ static final char OP_BRANCH = '|'; // node match this alternative or the next one
+ static final char OP_ATOM = 'A'; // length/string length of string followed by string itself
+ static final char OP_STAR = '*'; // node kleene closure
+ static final char OP_PLUS = '+'; // node positive closure
+ static final char OP_MAYBE = '?'; // node optional closure
+ static final char OP_ESCAPE = '\\'; // escape special escape code char class (escape is E_* code)
+ static final char OP_OPEN = '('; // number nth opening paren
+ static final char OP_OPEN_CLUSTER = '<'; // opening cluster
+ static final char OP_CLOSE = ')'; // number nth closing paren
+ static final char OP_CLOSE_CLUSTER = '>'; // closing cluster
+ static final char OP_BACKREF = '#'; // number reference nth already matched parenthesized string
+ static final char OP_GOTO = 'G'; // nothing but a (back-)pointer
+ static final char OP_NOTHING = 'N'; // match null string such as in '(a|)'
+ static final char OP_RELUCTANTSTAR = '8'; // none/expr reluctant '*' (mnemonic for char is unshifted '*')
+ static final char OP_RELUCTANTPLUS = '='; // none/expr reluctant '+' (mnemonic for char is unshifted '+')
+ static final char OP_RELUCTANTMAYBE = '/'; // none/expr reluctant '?' (mnemonic for char is unshifted '?')
+ static final char OP_POSIXCLASS = 'P'; // classid one of the posix character classes
+
+ // Escape codes
+ static final char E_ALNUM = 'w'; // Alphanumeric
+ static final char E_NALNUM = 'W'; // Non-alphanumeric
+ static final char E_BOUND = 'b'; // Word boundary
+ static final char E_NBOUND = 'B'; // Non-word boundary
+ static final char E_SPACE = 's'; // Whitespace
+ static final char E_NSPACE = 'S'; // Non-whitespace
+ static final char E_DIGIT = 'd'; // Digit
+ static final char E_NDIGIT = 'D'; // Non-digit
+
+ // Posix character classes
+ static final char POSIX_CLASS_ALNUM = 'w'; // Alphanumerics
+ static final char POSIX_CLASS_ALPHA = 'a'; // Alphabetics
+ static final char POSIX_CLASS_BLANK = 'b'; // Blanks
+ static final char POSIX_CLASS_CNTRL = 'c'; // Control characters
+ static final char POSIX_CLASS_DIGIT = 'd'; // Digits
+ static final char POSIX_CLASS_GRAPH = 'g'; // Graphic characters
+ static final char POSIX_CLASS_LOWER = 'l'; // Lowercase characters
+ static final char POSIX_CLASS_PRINT = 'p'; // Printable characters
+ static final char POSIX_CLASS_PUNCT = '!'; // Punctuation
+ static final char POSIX_CLASS_SPACE = 's'; // Spaces
+ static final char POSIX_CLASS_UPPER = 'u'; // Uppercase characters
+ static final char POSIX_CLASS_XDIGIT = 'x'; // Hexadecimal digits
+ static final char POSIX_CLASS_JSTART = 'j'; // Java identifier start
+ static final char POSIX_CLASS_JPART = 'k'; // Java identifier part
+
+ // Limits
+ static final int maxNode = 65536; // Maximum number of nodes in a program
+ static final int MAX_PAREN = 16; // Number of paren pairs (only 9 can be backrefs)
+
+ // Node layout constants
+ static final int offsetOpcode = 0; // Opcode offset (first character)
+ static final int offsetOpdata = 1; // Opdata offset (second char)
+ static final int offsetNext = 2; // Next index offset (third char)
+ static final int nodeSize = 3; // Node size (in chars)
+
+ /** Line Separator */
+ static final String NEWLINE = System.getProperty("line.separator");
+
+ // State of current program
+ REProgram program; // Compiled regular expression 'program'
+ transient CharacterIterator search; // The string being matched against
+ int matchFlags; // Match behaviour flags
+ int maxParen = MAX_PAREN;
+
+ // Parenthesized subexpressions
+ transient int parenCount; // Number of subexpressions matched (num open parens + 1)
+ transient int start0; // Cache of start[0]
+ transient int end0; // Cache of start[0]
+ transient int start1; // Cache of start[1]
+ transient int end1; // Cache of start[1]
+ transient int start2; // Cache of start[2]
+ transient int end2; // Cache of start[2]
+ transient int[] startn; // Lazy-alloced array of sub-expression starts
+ transient int[] endn; // Lazy-alloced array of sub-expression ends
+
+ // Backreferences
+ transient int[] startBackref; // Lazy-alloced array of backref starts
+ transient int[] endBackref; // Lazy-alloced array of backref ends
+
+ /**
+ * Constructs a regular expression matcher from a String by compiling it
+ * using a new instance of RECompiler. If you will be compiling many
+ * expressions, you may prefer to use a single RECompiler object instead.
+ * @param pattern The regular expression pattern to compile.
+ * @exception RESyntaxException Thrown if the regular expression has invalid syntax.
+ * @see RECompiler
+ * @see recompile
+ */
+ public RE(String pattern) throws RESyntaxException
+ {
+ this(pattern, MATCH_NORMAL);
+ }
+
+ /**
+ * Constructs a regular expression matcher from a String by compiling it
+ * using a new instance of RECompiler. If you will be compiling many
+ * expressions, you may prefer to use a single RECompiler object instead.
+ * @param pattern The regular expression pattern to compile.
+ * @param matchFlags The matching style
+ * @exception RESyntaxException Thrown if the regular expression has invalid syntax.
+ * @see RECompiler
+ * @see recompile
+ */
+ public RE(String pattern, int matchFlags) throws RESyntaxException
+ {
+ this(new RECompiler().compile(pattern));
+ setMatchFlags(matchFlags);
+ }
+
+ /**
+ * Construct a matcher for a pre-compiled regular expression from program
+ * (bytecode) data. Permits special flags to be passed in to modify matching
+ * behaviour.
+ * @param program Compiled regular expression program (see RECompiler and/or recompile)
+ * @param matchFlags One or more of the RE match behaviour flags (RE.MATCH_*):
+ *
+ *
+ *
+ * MATCH_NORMAL // Normal (case-sensitive) matching
+ * MATCH_CASEINDEPENDENT // Case folded comparisons
+ * MATCH_MULTILINE // Newline matches as BOL/EOL
+ *
+ *
+ *
+ * @see RECompiler
+ * @see REProgram
+ * @see recompile
+ */
+ public RE(REProgram program, int matchFlags)
+ {
+ setProgram(program);
+ setMatchFlags(matchFlags);
+ }
+
+ /**
+ * Construct a matcher for a pre-compiled regular expression from program
+ * (bytecode) data.
+ * @param program Compiled regular expression program
+ * @see RECompiler
+ * @see recompile
+ */
+ public RE(REProgram program)
+ {
+ this(program, MATCH_NORMAL);
+ }
+
+ /**
+ * Constructs a regular expression matcher with no initial program.
+ * This is likely to be an uncommon practice, but is still supported.
+ */
+ public RE()
+ {
+ this((REProgram)null, MATCH_NORMAL);
+ }
+
+ /**
+ * Converts a 'simplified' regular expression to a full regular expression
+ * @param pattern The pattern to convert
+ * @return The full regular expression
+ */
+ public static String simplePatternToFullRegularExpression(String pattern)
+ {
+ StringBuffer buf = new StringBuffer();
+ for (int i = 0; i < pattern.length(); i++)
+ {
+ char c = pattern.charAt(i);
+ switch (c)
+ {
+ case '*':
+ buf.append(".*");
+ break;
+
+ case '.':
+ case '[':
+ case ']':
+ case '\\':
+ case '+':
+ case '?':
+ case '{':
+ case '}':
+ case '$':
+ case '^':
+ case '|':
+ case '(':
+ case ')':
+ buf.append('\\');
+ default:
+ buf.append(c);
+ break;
+ }
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Sets match behaviour flags which alter the way RE does matching.
+ * @param matchFlags One or more of the RE match behaviour flags (RE.MATCH_*):
+ *
+ *
+ *
+ * MATCH_NORMAL // Normal (case-sensitive) matching
+ * MATCH_CASEINDEPENDENT // Case folded comparisons
+ * MATCH_MULTILINE // Newline matches as BOL/EOL
+ *
+ *
+ *
+ */
+ public void setMatchFlags(int matchFlags)
+ {
+ this.matchFlags = matchFlags;
+ }
+
+ /**
+ * Returns the current match behaviour flags.
+ * @return Current match behaviour flags (RE.MATCH_*).
+ *
+ *
+ *
+ * MATCH_NORMAL // Normal (case-sensitive) matching
+ * MATCH_CASEINDEPENDENT // Case folded comparisons
+ * MATCH_MULTILINE // Newline matches as BOL/EOL
+ *
+ *
+ *
+ * @see #setMatchFlags
+ *
+ */
+ public int getMatchFlags()
+ {
+ return matchFlags;
+ }
+
+ /**
+ * Sets the current regular expression program used by this matcher object.
+ * @param program Regular expression program compiled by RECompiler.
+ * @see RECompiler
+ * @see REProgram
+ * @see recompile
+ */
+ public void setProgram(REProgram program)
+ {
+ this.program = program;
+ if (program != null && program.maxParens != -1) {
+ this.maxParen = program.maxParens;
+ } else {
+ this.maxParen = MAX_PAREN;
+ }
+ }
+
+ /**
+ * Returns the current regular expression program in use by this matcher object.
+ * @return Regular expression program
+ * @see #setProgram
+ */
+ public REProgram getProgram()
+ {
+ return program;
+ }
+
+ /**
+ * Returns the number of parenthesized subexpressions available after a successful match.
+ * @return Number of available parenthesized subexpressions
+ */
+ public int getParenCount()
+ {
+ return parenCount;
+ }
+
+ /**
+ * Gets the contents of a parenthesized subexpression after a successful match.
+ * @param which Nesting level of subexpression
+ * @return String
+ */
+ public String getParen(int which)
+ {
+ int start;
+ if (which < parenCount && (start = getParenStart(which)) >= 0)
+ {
+ return search.substring(start, getParenEnd(which));
+ }
+ return null;
+ }
+
+ /**
+ * Returns the start index of a given paren level.
+ * @param which Nesting level of subexpression
+ * @return String index
+ */
+ public final int getParenStart(int which)
+ {
+ if (which < parenCount)
+ {
+ switch (which)
+ {
+ case 0:
+ return start0;
+
+ case 1:
+ return start1;
+
+ case 2:
+ return start2;
+
+ default:
+ if (startn == null)
+ {
+ allocParens();
+ }
+ return startn[which];
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the end index of a given paren level.
+ * @param which Nesting level of subexpression
+ * @return String index
+ */
+ public final int getParenEnd(int which)
+ {
+ if (which < parenCount)
+ {
+ switch (which)
+ {
+ case 0:
+ return end0;
+
+ case 1:
+ return end1;
+
+ case 2:
+ return end2;
+
+ default:
+ if (endn == null)
+ {
+ allocParens();
+ }
+ return endn[which];
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the length of a given paren level.
+ * @param which Nesting level of subexpression
+ * @return Number of characters in the parenthesized subexpression
+ */
+ public final int getParenLength(int which)
+ {
+ if (which < parenCount)
+ {
+ return getParenEnd(which) - getParenStart(which);
+ }
+ return -1;
+ }
+
+ /**
+ * Sets the start of a paren level
+ * @param which Which paren level
+ * @param i Index in input array
+ */
+ protected final void setParenStart(int which, int i)
+ {
+ if (which < parenCount)
+ {
+ switch (which)
+ {
+ case 0:
+ start0 = i;
+ break;
+
+ case 1:
+ start1 = i;
+ break;
+
+ case 2:
+ start2 = i;
+ break;
+
+ default:
+ if (startn == null)
+ {
+ allocParens();
+ }
+ startn[which] = i;
+ break;
+ }
+ }
+ }
+
+ /**
+ * Sets the end of a paren level
+ * @param which Which paren level
+ * @param i Index in input array
+ */
+ protected final void setParenEnd(int which, int i)
+ {
+ if (which < parenCount)
+ {
+ switch (which)
+ {
+ case 0:
+ end0 = i;
+ break;
+
+ case 1:
+ end1 = i;
+ break;
+
+ case 2:
+ end2 = i;
+ break;
+
+ default:
+ if (endn == null)
+ {
+ allocParens();
+ }
+ endn[which] = i;
+ break;
+ }
+ }
+ }
+
+ /**
+ * Throws an Error representing an internal error condition probably resulting
+ * from a bug in the regular expression compiler (or possibly data corruption).
+ * In practice, this should be very rare.
+ * @param s Error description
+ */
+ protected void internalError(String s) throws Error
+ {
+ throw new Error("RE internal error: " + s);
+ }
+
+ /**
+ * Performs lazy allocation of subexpression arrays
+ */
+ private final void allocParens()
+ {
+ // Allocate arrays for subexpressions
+ startn = new int[maxParen];
+ endn = new int[maxParen];
+
+ // Set sub-expression pointers to invalid values
+ for (int i = 0; i < maxParen; i++)
+ {
+ startn[i] = -1;
+ endn[i] = -1;
+ }
+ }
+
+ /**
+ * Try to match a string against a subset of nodes in the program
+ * @param firstNode Node to start at in program
+ * @param lastNode Last valid node (used for matching a subexpression without
+ * matching the rest of the program as well).
+ * @param idxStart Starting position in character array
+ * @return Final input array index if match succeeded. -1 if not.
+ */
+ protected int matchNodes(int firstNode, int lastNode, int idxStart)
+ {
+ // Our current place in the string
+ int idx = idxStart;
+
+ // Loop while node is valid
+ int next, opcode, opdata;
+ int idxNew;
+ char[] instruction = program.instruction;
+ for (int node = firstNode; node < lastNode; )
+ {
+ opcode = instruction[node + offsetOpcode];
+ next = node + (short)instruction[node + offsetNext];
+ opdata = instruction[node + offsetOpdata];
+
+ switch (opcode)
+ {
+ case OP_RELUCTANTMAYBE:
+ {
+ int once = 0;
+ do
+ {
+ // Try to match the rest without using the reluctant subexpr
+ if ((idxNew = matchNodes(next, maxNode, idx)) != -1)
+ {
+ return idxNew;
+ }
+ }
+ while ((once++ == 0) && (idx = matchNodes(node + nodeSize, next, idx)) != -1);
+ return -1;
+ }
+
+ case OP_RELUCTANTPLUS:
+ while ((idx = matchNodes(node + nodeSize, next, idx)) != -1)
+ {
+ // Try to match the rest without using the reluctant subexpr
+ if ((idxNew = matchNodes(next, maxNode, idx)) != -1)
+ {
+ return idxNew;
+ }
+ }
+ return -1;
+
+ case OP_RELUCTANTSTAR:
+ do
+ {
+ // Try to match the rest without using the reluctant subexpr
+ if ((idxNew = matchNodes(next, maxNode, idx)) != -1)
+ {
+ return idxNew;
+ }
+ }
+ while ((idx = matchNodes(node + nodeSize, next, idx)) != -1);
+ return -1;
+
+ case OP_OPEN:
+
+ // Match subexpression
+ if ((program.flags & REProgram.OPT_HASBACKREFS) != 0)
+ {
+ startBackref[opdata] = idx;
+ }
+ if ((idxNew = matchNodes(next, maxNode, idx)) != -1)
+ {
+ // Increase valid paren count
+ if ((opdata + 1) > parenCount)
+ {
+ parenCount = opdata + 1;
+ }
+
+ // Don't set paren if already set later on
+ if (getParenStart(opdata) == -1)
+ {
+ setParenStart(opdata, idx);
+ }
+ }
+ return idxNew;
+
+ case OP_CLOSE:
+
+ // Done matching subexpression
+ if ((program.flags & REProgram.OPT_HASBACKREFS) != 0)
+ {
+ endBackref[opdata] = idx;
+ }
+ if ((idxNew = matchNodes(next, maxNode, idx)) != -1)
+ {
+ // Increase valid paren count
+ if ((opdata + 1) > parenCount)
+ {
+ parenCount = opdata + 1;
+ }
+
+ // Don't set paren if already set later on
+ if (getParenEnd(opdata) == -1)
+ {
+ setParenEnd(opdata, idx);
+ }
+ }
+ return idxNew;
+
+ case OP_OPEN_CLUSTER:
+ case OP_CLOSE_CLUSTER:
+ // starting or ending the matching of a subexpression which has no backref.
+ return matchNodes( next, maxNode, idx );
+
+ case OP_BACKREF:
+ {
+ // Get the start and end of the backref
+ int s = startBackref[opdata];
+ int e = endBackref[opdata];
+
+ // We don't know the backref yet
+ if (s == -1 || e == -1)
+ {
+ return -1;
+ }
+
+ // The backref is empty size
+ if (s == e)
+ {
+ break;
+ }
+
+ // Get the length of the backref
+ int l = e - s;
+
+ // If there's not enough input left, give up.
+ if (search.isEnd(idx + l - 1))
+ {
+ return -1;
+ }
+
+ // Case fold the backref?
+ if ((matchFlags & MATCH_CASEINDEPENDENT) != 0)
+ {
+ // Compare backref to input, case-folding as we go
+ for (int i = 0; i < l; i++)
+ {
+ if (Character.toLowerCase(search.charAt(idx++)) != Character.toLowerCase(search.charAt(s + i)))
+ {
+ return -1;
+ }
+ }
+ }
+ else
+ {
+ // Compare backref to input
+ for (int i = 0; i < l; i++)
+ {
+ if (search.charAt(idx++) != search.charAt(s + i))
+ {
+ return -1;
+ }
+ }
+ }
+ }
+ break;
+
+ case OP_BOL:
+
+ // Fail if we're not at the start of the string
+ if (idx != 0)
+ {
+ // If we're multiline matching, we could still be at the start of a line
+ if ((matchFlags & MATCH_MULTILINE) == MATCH_MULTILINE)
+ {
+ // If not at start of line, give up
+ if (idx <= 0 || !isNewline(idx - 1)) {
+ return -1;
+ } else {
+ break;
+ }
+ }
+ return -1;
+ }
+ break;
+
+ case OP_EOL:
+
+ // If we're not at the end of string
+ if (!search.isEnd(0) && !search.isEnd(idx))
+ {
+ // If we're multi-line matching
+ if ((matchFlags & MATCH_MULTILINE) == MATCH_MULTILINE)
+ {
+ // Give up if we're not at the end of a line
+ if (! isNewline(idx)) {
+ return -1;
+ } else {
+ break;
+ }
+ }
+ return -1;
+ }
+ break;
+
+ case OP_ESCAPE:
+
+ // Which escape?
+ switch (opdata)
+ {
+ // Word boundary match
+ case E_NBOUND:
+ case E_BOUND:
+ {
+ char cLast = ((idx == 0) ? '\n' : search.charAt(idx - 1));
+ char cNext = ((search.isEnd(idx)) ? '\n' : search.charAt(idx));
+ if ((Character.isLetterOrDigit(cLast) == Character.isLetterOrDigit(cNext)) == (opdata == E_BOUND))
+ {
+ return -1;
+ }
+ }
+ break;
+
+ // Alpha-numeric, digit, space, javaLetter, javaLetterOrDigit
+ case E_ALNUM:
+ case E_NALNUM:
+ case E_DIGIT:
+ case E_NDIGIT:
+ case E_SPACE:
+ case E_NSPACE:
+
+ // Give up if out of input
+ if (search.isEnd(idx))
+ {
+ return -1;
+ }
+
+ char c = search.charAt(idx);
+
+ // Switch on escape
+ switch (opdata)
+ {
+ case E_ALNUM:
+ case E_NALNUM:
+ if (!((Character.isLetterOrDigit(c) || c == '_') == (opdata == E_ALNUM)))
+ {
+ return -1;
+ }
+ break;
+
+ case E_DIGIT:
+ case E_NDIGIT:
+ if (!(Character.isDigit(c) == (opdata == E_DIGIT)))
+ {
+ return -1;
+ }
+ break;
+
+ case E_SPACE:
+ case E_NSPACE:
+ if (!(Character.isWhitespace(c) == (opdata == E_SPACE)))
+ {
+ return -1;
+ }
+ break;
+ }
+ idx++;
+ break;
+
+ default:
+ internalError("Unrecognized escape '" + opdata + "'");
+ }
+ break;
+
+ case OP_ANY:
+
+ if((matchFlags & MATCH_SINGLELINE) == MATCH_SINGLELINE) {
+ // Match anything
+ if(search.isEnd(idx))
+ {
+ return -1;
+ }
+ idx++;
+ break;
+ }
+ else
+ {
+ // Match anything but a newline
+ if (search.isEnd(idx) || search.charAt(idx++) == '\n')
+ {
+ return -1;
+ }
+ break;
+ }
+
+ case OP_ATOM:
+ {
+ // Match an atom value
+ if (search.isEnd(idx))
+ {
+ return -1;
+ }
+
+ // Get length of atom and starting index
+ int lenAtom = opdata;
+ int startAtom = node + nodeSize;
+
+ // Give up if not enough input remains to have a match
+ if (search.isEnd(lenAtom + idx - 1))
+ {
+ return -1;
+ }
+
+ // Match atom differently depending on casefolding flag
+ if ((matchFlags & MATCH_CASEINDEPENDENT) != 0)
+ {
+ for (int i = 0; i < lenAtom; i++)
+ {
+ if (Character.toLowerCase(search.charAt(idx++)) != Character.toLowerCase(instruction[startAtom + i]))
+ {
+ return -1;
+ }
+ }
+ }
+ else
+ {
+ for (int i = 0; i < lenAtom; i++)
+ {
+ if (search.charAt(idx++) != instruction[startAtom + i])
+ {
+ return -1;
+ }
+ }
+ }
+ }
+ break;
+
+ case OP_POSIXCLASS:
+ {
+ // Out of input?
+ if (search.isEnd(idx))
+ {
+ return -1;
+ }
+
+ switch (opdata)
+ {
+ case POSIX_CLASS_ALNUM:
+ if (!Character.isLetterOrDigit(search.charAt(idx)))
+ {
+ return -1;
+ }
+ break;
+
+ case POSIX_CLASS_ALPHA:
+ if (!Character.isLetter(search.charAt(idx)))
+ {
+ return -1;
+ }
+ break;
+
+ case POSIX_CLASS_DIGIT:
+ if (!Character.isDigit(search.charAt(idx)))
+ {
+ return -1;
+ }
+ break;
+
+ case POSIX_CLASS_BLANK: // JWL - bugbug: is this right??
+ if (!Character.isSpaceChar(search.charAt(idx)))
+ {
+ return -1;
+ }
+ break;
+
+ case POSIX_CLASS_SPACE:
+ if (!Character.isWhitespace(search.charAt(idx)))
+ {
+ return -1;
+ }
+ break;
+
+ case POSIX_CLASS_CNTRL:
+ if (Character.getType(search.charAt(idx)) != Character.CONTROL)
+ {
+ return -1;
+ }
+ break;
+
+ case POSIX_CLASS_GRAPH: // JWL - bugbug???
+ switch (Character.getType(search.charAt(idx)))
+ {
+ case Character.MATH_SYMBOL:
+ case Character.CURRENCY_SYMBOL:
+ case Character.MODIFIER_SYMBOL:
+ case Character.OTHER_SYMBOL:
+ break;
+
+ default:
+ return -1;
+ }
+ break;
+
+ case POSIX_CLASS_LOWER:
+ if (Character.getType(search.charAt(idx)) != Character.LOWERCASE_LETTER)
+ {
+ return -1;
+ }
+ break;
+
+ case POSIX_CLASS_UPPER:
+ if (Character.getType(search.charAt(idx)) != Character.UPPERCASE_LETTER)
+ {
+ return -1;
+ }
+ break;
+
+ case POSIX_CLASS_PRINT:
+ if (Character.getType(search.charAt(idx)) == Character.CONTROL)
+ {
+ return -1;
+ }
+ break;
+
+ case POSIX_CLASS_PUNCT:
+ {
+ int type = Character.getType(search.charAt(idx));
+ switch(type)
+ {
+ case Character.DASH_PUNCTUATION:
+ case Character.START_PUNCTUATION:
+ case Character.END_PUNCTUATION:
+ case Character.CONNECTOR_PUNCTUATION:
+ case Character.OTHER_PUNCTUATION:
+ break;
+
+ default:
+ return -1;
+ }
+ }
+ break;
+
+ case POSIX_CLASS_XDIGIT: // JWL - bugbug??
+ {
+ boolean isXDigit = ((search.charAt(idx) >= '0' && search.charAt(idx) <= '9') ||
+ (search.charAt(idx) >= 'a' && search.charAt(idx) <= 'f') ||
+ (search.charAt(idx) >= 'A' && search.charAt(idx) <= 'F'));
+ if (!isXDigit)
+ {
+ return -1;
+ }
+ }
+ break;
+
+ case POSIX_CLASS_JSTART:
+ if (!Character.isJavaIdentifierStart(search.charAt(idx)))
+ {
+ return -1;
+ }
+ break;
+
+ case POSIX_CLASS_JPART:
+ if (!Character.isJavaIdentifierPart(search.charAt(idx)))
+ {
+ return -1;
+ }
+ break;
+
+ default:
+ internalError("Bad posix class");
+ break;
+ }
+
+ // Matched.
+ idx++;
+ }
+ break;
+
+ case OP_ANYOF:
+ {
+ // Out of input?
+ if (search.isEnd(idx))
+ {
+ return -1;
+ }
+
+ // Get character to match against character class and maybe casefold
+ char c = search.charAt(idx);
+ boolean caseFold = (matchFlags & MATCH_CASEINDEPENDENT) != 0;
+ if (caseFold)
+ {
+ c = Character.toLowerCase(c);
+ }
+
+ // Loop through character class checking our match character
+ int idxRange = node + nodeSize;
+ int idxEnd = idxRange + (opdata * 2);
+ boolean match = false;
+ for (int i = idxRange; i < idxEnd; )
+ {
+ // Get start, end and match characters
+ char s = instruction[i++];
+ char e = instruction[i++];
+
+ // Fold ends of range and match character
+ if (caseFold)
+ {
+ s = Character.toLowerCase(s);
+ e = Character.toLowerCase(e);
+ }
+
+ // If the match character is in range, break out
+ if (c >= s && c <= e)
+ {
+ match = true;
+ break;
+ }
+ }
+
+ // Fail if we didn't match the character class
+ if (!match)
+ {
+ return -1;
+ }
+ idx++;
+ }
+ break;
+
+ case OP_BRANCH:
+ {
+ // Check for choices
+ if (instruction[next + offsetOpcode] != OP_BRANCH)
+ {
+ // If there aren't any other choices, just evaluate this branch.
+ node += nodeSize;
+ continue;
+ }
+
+ // Try all available branches
+ short nextBranch;
+ do
+ {
+ // Try matching the branch against the string
+ if ((idxNew = matchNodes(node + nodeSize, maxNode, idx)) != -1)
+ {
+ return idxNew;
+ }
+
+ // Go to next branch (if any)
+ nextBranch = (short)instruction[node + offsetNext];
+ node += nextBranch;
+ }
+ while (nextBranch != 0 && (instruction[node + offsetOpcode] == OP_BRANCH));
+
+ // Failed to match any branch!
+ return -1;
+ }
+
+ case OP_NOTHING:
+ case OP_GOTO:
+
+ // Just advance to the next node without doing anything
+ break;
+
+ case OP_END:
+
+ // Match has succeeded!
+ setParenEnd(0, idx);
+ return idx;
+
+ default:
+
+ // Corrupt program
+ internalError("Invalid opcode '" + opcode + "'");
+ }
+
+ // Advance to the next node in the program
+ node = next;
+ }
+
+ // We "should" never end up here
+ internalError("Corrupt program");
+ return -1;
+ }
+
+ /**
+ * Match the current regular expression program against the current
+ * input string, starting at index i of the input string. This method
+ * is only meant for internal use.
+ * @param i The input string index to start matching at
+ * @return True if the input matched the expression
+ */
+ protected boolean matchAt(int i)
+ {
+ // Initialize start pointer, paren cache and paren count
+ start0 = -1;
+ end0 = -1;
+ start1 = -1;
+ end1 = -1;
+ start2 = -1;
+ end2 = -1;
+ startn = null;
+ endn = null;
+ parenCount = 1;
+ setParenStart(0, i);
+
+ // Allocate backref arrays (unless optimizations indicate otherwise)
+ if ((program.flags & REProgram.OPT_HASBACKREFS) != 0)
+ {
+ startBackref = new int[maxParen];
+ endBackref = new int[maxParen];
+ }
+
+ // Match against string
+ int idx;
+ if ((idx = matchNodes(0, maxNode, i)) != -1)
+ {
+ setParenEnd(0, idx);
+ return true;
+ }
+
+ // Didn't match
+ parenCount = 0;
+ return false;
+ }
+
+ /**
+ * Matches the current regular expression program against a character array,
+ * starting at a given index.
+ * @param search String to match against
+ * @param i Index to start searching at
+ * @return True if string matched
+ */
+ public boolean match(String search, int i)
+ {
+ return match(new StringCharacterIterator(search), i);
+ }
+
+ /**
+ * Matches the current regular expression program against a character array,
+ * starting at a given index.
+ * @param search String to match against
+ * @param i Index to start searching at
+ * @return True if string matched
+ */
+ public boolean match(CharacterIterator search, int i)
+ {
+ // There is no compiled program to search with!
+ if (program == null)
+ {
+ // This should be uncommon enough to be an error case rather
+ // than an exception (which would have to be handled everywhere)
+ internalError("No RE program to run!");
+ }
+
+ // Save string to search
+ this.search = search;
+
+ // Can we optimize the search by looking for a prefix string?
+ if (program.prefix == null)
+ {
+ // Unprefixed matching must try for a match at each character
+ for ( ;! search.isEnd(i - 1); i++)
+ {
+ // Try a match at index i
+ if (matchAt(i))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+ else
+ {
+ // Prefix-anchored matching is possible
+ boolean caseIndependent = (matchFlags & MATCH_CASEINDEPENDENT) != 0;
+ char[] prefix = program.prefix;
+ for ( ;! search.isEnd(i + prefix.length - 1); i++)
+ {
+ // If the first character of the prefix matches
+ boolean match = false;
+ if (caseIndependent)
+ match = Character.toLowerCase(search.charAt(i)) == Character.toLowerCase(prefix[0]);
+ else
+ match = search.charAt(i) == prefix[0];
+ if (match)
+ {
+ // Save first character position
+ int firstChar = i++;
+ int k;
+ for (k = 1; k < prefix.length; )
+ {
+ // If there's a mismatch of any character in the prefix, give up
+ if (caseIndependent)
+ match = Character.toLowerCase(search.charAt(i++)) == Character.toLowerCase(prefix[k++]);
+ else
+ match = search.charAt(i++) == prefix[k++];
+ if (!match)
+ {
+ break;
+ }
+ }
+
+ // See if the whole prefix string matched
+ if (k == prefix.length)
+ {
+ // We matched the full prefix at firstChar, so try it
+ if (matchAt(firstChar))
+ {
+ return true;
+ }
+ }
+
+ // Match failed, reset i to continue the search
+ i = firstChar;
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Matches the current regular expression program against a String.
+ * @param search String to match against
+ * @return True if string matched
+ */
+ public boolean match(String search)
+ {
+ return match(search, 0);
+ }
+
+ /**
+ * Splits a string into an array of strings on regular expression boundaries.
+ * This function works the same way as the Perl function of the same name.
+ * Given a regular expression of "[ab]+" and a string to split of
+ * "xyzzyababbayyzabbbab123", the result would be the array of Strings
+ * "[xyzzy, yyz, 123]".
+ * @param s String to split on this regular exression
+ * @return Array of strings
+ */
+ public String[] split(String s)
+ {
+ // Create new vector
+ Vector v = new Vector();
+
+ // Start at position 0 and search the whole string
+ int pos = 0;
+ int len = s.length();
+
+ // Try a match at each position
+ while (pos < len && match(s, pos))
+ {
+ // Get start of match
+ int start = getParenStart(0);
+
+ // Get end of match
+ int newpos = getParenEnd(0);
+
+ // Check if no progress was made
+ if (newpos == pos)
+ {
+ v.addElement(s.substring(pos, start + 1));
+ newpos++;
+ }
+ else
+ {
+ v.addElement(s.substring(pos, start));
+ }
+
+ // Move to new position
+ pos = newpos;
+ }
+
+ // Push remainder if it's not empty
+ String remainder = s.substring(pos);
+ if (remainder.length() != 0)
+ {
+ v.addElement(remainder);
+ }
+
+ // Return vector as an array of strings
+ String[] ret = new String[v.size()];
+ v.copyInto(ret);
+ return ret;
+ }
+
+ /**
+ * Flag bit that indicates that subst should replace all occurrences of this
+ * regular expression.
+ */
+ public static final int REPLACE_ALL = 0x0000;
+
+ /**
+ * Flag bit that indicates that subst should only replace the first occurrence
+ * of this regular expression.
+ */
+ public static final int REPLACE_FIRSTONLY = 0x0001;
+
+ /**
+ * Flag bit that indicates that subst should replace backreferences
+ */
+ public static final int REPLACE_BACKREFERENCES = 0x0002;
+
+ /**
+ * Substitutes a string for this regular expression in another string.
+ * This method works like the Perl function of the same name.
+ * Given a regular expression of "a*b", a String to substituteIn of
+ * "aaaabfooaaabgarplyaaabwackyb" and the substitution String "-", the
+ * resulting String returned by subst would be "-foo-garply-wacky-".
+ *
+ * @param substituteIn String to substitute within
+ * @param substitution String to substitute for all matches of this regular expression.
+ * @return The string substituteIn with zero or more occurrences of the current
+ * regular expression replaced with the substitution String (if this regular
+ * expression object doesn't match at any position, the original String is returned
+ * unchanged).
+ */
+ public String subst(String substituteIn, String substitution)
+ {
+ return subst(substituteIn, substitution, REPLACE_ALL);
+ }
+
+ /**
+ * Substitutes a string for this regular expression in another string.
+ * This method works like the Perl function of the same name.
+ * Given a regular expression of "a*b", a String to substituteIn of
+ * "aaaabfooaaabgarplyaaabwackyb" and the substitution String "-", the
+ * resulting String returned by subst would be "-foo-garply-wacky-".
+ *
+ * It is also possible to reference the contents of a parenthesized expression
+ * with $0, $1, ... $9. A regular expression of "http://[\\.\\w\\-\\?/~_@&=%]+",
+ * a String to substituteIn of "visit us: http://www.apache.org!" and the
+ * substitution String "<a href=\"$0\">$0</a>", the resulting String
+ * returned by subst would be
+ * "visit us: <a href=\"http://www.apache.org\">http://www.apache.org</a>!".
+ *
+ * Note: $0 represents the whole match.
+ *
+ * @param substituteIn String to substitute within
+ * @param substitution String to substitute for matches of this regular expression
+ * @param flags One or more bitwise flags from REPLACE_*. If the REPLACE_FIRSTONLY
+ * flag bit is set, only the first occurrence of this regular expression is replaced.
+ * If the bit is not set (REPLACE_ALL), all occurrences of this pattern will be
+ * replaced. If the flag REPLACE_BACKREFERENCES is set, all backreferences will
+ * be processed.
+ * @return The string substituteIn with zero or more occurrences of the current
+ * regular expression replaced with the substitution String (if this regular
+ * expression object doesn't match at any position, the original String is returned
+ * unchanged).
+ */
+ public String subst(String substituteIn, String substitution, int flags)
+ {
+ // String to return
+ StringBuffer ret = new StringBuffer();
+
+ // Start at position 0 and search the whole string
+ int pos = 0;
+ int len = substituteIn.length();
+
+ // Try a match at each position
+ while (pos < len && match(substituteIn, pos))
+ {
+ // Append string before match
+ ret.append(substituteIn.substring(pos, getParenStart(0)));
+
+ if ((flags & REPLACE_BACKREFERENCES) != 0)
+ {
+ // Process backreferences
+ int lCurrentPosition = 0;
+ int lLastPosition = 0;
+ int lLength = substitution.length();
+
+ while ((lCurrentPosition = substitution.indexOf("$", lCurrentPosition)) >= 0)
+ {
+ if ((lCurrentPosition == 0 || substitution.charAt(lCurrentPosition - 1) != '\\')
+ && lCurrentPosition+1 < lLength)
+ {
+ char c = substitution.charAt(lCurrentPosition + 1);
+ if (c >= '0' && c <= '9')
+ {
+ // Append everything between the last and the current $ sign
+ ret.append(substitution.substring(lLastPosition+2, lCurrentPosition));
+
+ // Append the parenthesized expression
+ // Note: if a parenthesized expression of the requested
+ // index is not available "null" is added to the string
+ ret.append(getParen(c - '0'));
+ lLastPosition = lCurrentPosition;
+ }
+ }
+
+ // Move forward, skipping past match
+ lCurrentPosition++;
+ }
+
+ // Append everything after the last $ sign
+ ret.append(substitution.substring(lLastPosition+2,lLength));
+ }
+ else
+ {
+ // Append substitution without processing backreferences
+ ret.append(substitution);
+ }
+
+ // Move forward, skipping past match
+ int newpos = getParenEnd(0);
+
+ // We always want to make progress!
+ if (newpos == pos)
+ {
+ newpos++;
+ }
+
+ // Try new position
+ pos = newpos;
+
+ // Break out if we're only supposed to replace one occurrence
+ if ((flags & REPLACE_FIRSTONLY) != 0)
+ {
+ break;
+ }
+ }
+
+ // If there's remaining input, append it
+ if (pos < len)
+ {
+ ret.append(substituteIn.substring(pos));
+ }
+
+ // Return string buffer as string
+ return ret.toString();
+ }
+
+ /**
+ * Returns an array of Strings, whose toString representation matches a regular
+ * expression. This method works like the Perl function of the same name. Given
+ * a regular expression of "a*b" and an array of String objects of [foo, aab, zzz,
+ * aaaab], the array of Strings returned by grep would be [aab, aaaab].
+ * @param search Array of Objects to search
+ * @return Array of Strings whose toString() value matches this regular expression.
+ */
+ public String[] grep(Object[] search)
+ {
+ // Create new vector to hold return items
+ Vector v = new Vector();
+
+ // Traverse array of objects
+ for (int i = 0; i < search.length; i++)
+ {
+ // Get next object as a string
+ String s = search[i].toString();
+
+ // If it matches this regexp, add it to the list
+ if (match(s))
+ {
+ v.addElement(s);
+ }
+ }
+
+ // Return vector as an array of strings
+ String[] ret = new String[v.size()];
+ v.copyInto(ret);
+ return ret;
+ }
+
+ /** @return true if at the i-th position in the 'search' a newline ends */
+ private boolean isNewline(int i) {
+
+ if (i < NEWLINE.length() - 1) {
+ return false;
+ }
+
+ if (search.charAt(i) == '\n') {
+ return true;
+ }
+
+ for (int j = NEWLINE.length() - 1; j >= 0; j--, i--) {
+ if (NEWLINE.charAt(j) != search.charAt(i)) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/RETest.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/RETest.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/RETest.java (revision 2)
@@ -0,0 +1,594 @@
+package org.apache.regexp;
+
+/*
+ * ====================================================================
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999-2003 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Jakarta-Regexp", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.File;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ObjectInputStream;
+
+/**
+ * Data driven (and optionally interactive) testing harness to exercise regular
+ * expression compiler and matching engine.
+ *
+ * @author Jonathan Locke
+ * @author Jon S. Stevens
+ * @author Michael McCallum
+ * @version $Id: RETest.java,v 1.5 2003/05/02 01:03:47 vgritsenko Exp $
+ */
+public class RETest
+{
+ // True if we want to see output from success cases
+ static final boolean showSuccesses = false;
+
+ // A new line character.
+ static final String NEW_LINE = System.getProperty( "line.separator" );
+
+ // Construct a matcher and a debug compiler
+ RE r = new RE();
+ REDebugCompiler compiler = new REDebugCompiler();
+
+ /**
+ * Main program entrypoint. If an argument is given, it will be compiled
+ * and interactive matching will ensue. If no argument is given, the
+ * file RETest.txt will be used as automated testing input.
+ * @param args Command line arguments (optional regular expression)
+ */
+ public static void main(String[] args)
+ {
+ try
+ {
+ test( args );
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Testing entrypoint.
+ * @param args Command line arguments
+ * @exception Exception thrown in case of error
+ */
+ public static boolean test( String[] args ) throws Exception
+ {
+ RETest test = new RETest();
+ // Run interactive tests against a single regexp
+ if (args.length == 2)
+ {
+ test.runInteractiveTests(args[1]);
+ }
+ else if (args.length == 1)
+ {
+ // Run automated tests
+ test.runAutomatedTests(args[0]);
+ }
+ else
+ {
+ System.out.println( "Usage: RETest ([-i] [regex]) ([/path/to/testfile.txt])" );
+ System.out.println( "By Default will run automated tests from file 'docs/RETest.txt' ..." );
+ System.out.println();
+ test.runAutomatedTests("docs/RETest.txt");
+ }
+ return test.failures == 0;
+ }
+
+ /**
+ * Constructor
+ */
+ public RETest()
+ {
+ }
+
+ /**
+ * Compile and test matching against a single expression
+ * @param expr Expression to compile and test
+ */
+ void runInteractiveTests(String expr)
+ {
+ try
+ {
+ // Compile expression
+ r.setProgram(compiler.compile(expr));
+
+ // Show expression
+ say("" + NEW_LINE + "" + expr + "" + NEW_LINE + "");
+
+ // Show program for compiled expression
+ PrintWriter writer = new PrintWriter( System.out );
+ compiler.dumpProgram( writer );
+ writer.flush();
+
+ boolean running = true;
+ // Test matching against compiled expression
+ while ( running )
+ {
+ // Read from keyboard
+ BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
+ System.out.print("> ");
+ System.out.flush();
+ String match = br.readLine();
+
+ if ( match != null )
+ {
+ // Try a match against the keyboard input
+ if (r.match(match))
+ {
+ say("Match successful.");
+ }
+ else
+ {
+ say("Match failed.");
+ }
+
+ // Show subparen registers
+ showParens(r);
+ }
+ else
+ {
+ running = false;
+ System.out.println();
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ say("Error: " + e.toString());
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Exit with a fatal error.
+ * @param s Last famous words before exiting
+ */
+ void die(String s)
+ {
+ say("FATAL ERROR: " + s);
+ System.exit(0);
+ }
+
+ /**
+ * Fail with an error.
+ * Will print a big failure message to System.out.
+ * @param s Failure description
+ */
+ void fail(String s)
+ {
+ failures++;
+ say("" + NEW_LINE + "");
+ say("*******************************************************");
+ say("********************* FAILURE! **********************");
+ say("*******************************************************");
+ say("" + NEW_LINE + "");
+ say(s);
+ say("");
+ // make sure the writer gets flushed.
+ PrintWriter writer = new PrintWriter( System.out );
+ compiler.dumpProgram( writer );
+ writer.flush();
+ say("" + NEW_LINE + "");
+ }
+
+ /**
+ * Show a success
+ * @param s Success story
+ */
+ void success(String s)
+ {
+ if (showSuccesses)
+ {
+ show();
+ say("Success: " + s);
+ }
+ }
+
+ /**
+ * Say something to standard out
+ * @param s What to say
+ */
+ void say(String s)
+ {
+ System.out.println (s);
+ }
+
+ /**
+ * Show an expression
+ */
+ void show()
+ {
+ say("" + NEW_LINE + "-----------------------" + NEW_LINE + "");
+ say("Expression #" + (n) + " \"" + expr + "\" ");
+ }
+
+ /**
+ * Dump parenthesized subexpressions found by a regular expression matcher object
+ * @param r Matcher object with results to show
+ */
+ void showParens(RE r)
+ {
+ // Loop through each paren
+ for (int i = 0; i < r.getParenCount(); i++)
+ {
+ // Show paren register
+ say("$" + i + " = " + r.getParen(i));
+ }
+ }
+
+ // Pre-compiled regular expression "a*b"
+ char[] re1Instructions =
+ {
+ 0x007c, 0x0000, 0x001a, 0x007c, 0x0000, 0x000d, 0x0041,
+ 0x0001, 0x0004, 0x0061, 0x007c, 0x0000, 0x0003, 0x0047,
+ 0x0000, 0xfff6, 0x007c, 0x0000, 0x0003, 0x004e, 0x0000,
+ 0x0003, 0x0041, 0x0001, 0x0004, 0x0062, 0x0045, 0x0000,
+ 0x0000,
+ };
+
+ REProgram re1 = new REProgram(re1Instructions);
+
+ /*
+ * Current expression and number in automated test
+ */
+ String expr;
+ int n = 0;
+
+ /*
+ * Count of failures in automated test
+ */
+ int failures = 0;
+
+ /**
+ * Run automated tests in RETest.txt file (from Perl 4.0 test battery)
+ * @exception Exception thrown in case of error
+ */
+ void runAutomatedTests(String testDocument) throws Exception
+ {
+ long ms = System.currentTimeMillis();
+
+ // Simple test of pre-compiled regular expressions
+ RE r = new RE(re1);
+ say("a*b");
+ say("aaaab = " + r.match("aaab"));
+ showParens(r);
+ say("b = " + r.match("b"));
+ showParens(r);
+ say("c = " + r.match("c"));
+ showParens(r);
+ say("ccccaaaaab = " + r.match("ccccaaaaab"));
+ showParens(r);
+
+ r = new RE("a*b");
+ String[] s = r.split("xxxxaabxxxxbyyyyaaabzzz");
+ r = new RE("x+");
+ s = r.grep(s);
+ for (int i = 0; i < s.length; i++)
+ {
+ System.out.println ("s[" + i + "] = " + s[i]);
+ }
+
+ r = new RE("a*b");
+ String s1 = r.subst("aaaabfooaaabgarplyaaabwackyb", "-");
+ System.out.println ("s = " + s1);
+
+ // Some unit tests
+ runAutomatedTests();
+
+ // Test from script file
+ File testInput = new File(testDocument);
+ if (! testInput.exists())
+ throw new Exception ("Could not find: " + testDocument);
+ BufferedReader br = new BufferedReader(new FileReader(testInput));
+ try
+ {
+ // While input is available, parse lines
+ while (br.ready())
+ {
+ // Find next re test case
+ String number = "";
+ String yesno;
+ while (br.ready())
+ {
+ number = br.readLine();
+ if (number == null)
+ {
+ break;
+ }
+ number = number.trim();
+ if (number.startsWith("#"))
+ {
+ break;
+ }
+ if (!number.equals(""))
+ {
+ System.out.println ("Script error. Line = " + number);
+ System.exit(0);
+ }
+ }
+
+ // Are we done?
+ if (!br.ready())
+ {
+ break;
+ }
+
+ // Get expression
+ expr = br.readLine();
+ n++;
+ say("");
+ say(n + ". " + expr);
+ say("");
+
+ // Compile it
+ try
+ {
+ r.setProgram(compiler.compile(expr));
+ }
+
+ // Some expressions *should* cause exceptions to be thrown
+ catch (Exception e)
+ {
+ // Get expected result
+ yesno = br.readLine().trim();
+
+ // If it was supposed to be an error, report success and continue
+ if (yesno.equals("ERR"))
+ {
+ say(" Match: ERR");
+ success("Produces an error (" + e.toString() + "), as expected.");
+ continue;
+ }
+
+ // Wasn't supposed to be an error
+ String message = e.getMessage() == null ? e.toString() : e.getMessage();
+ fail("Produces an unexpected exception \"" + message + "\"");
+ e.printStackTrace();
+ }
+ catch (Error e)
+ {
+ // Internal error happened
+ fail("Compiler threw fatal error \"" + e.getMessage() + "\"");
+ e.printStackTrace();
+ }
+
+ // Get string to match against
+ String matchAgainst = br.readLine().trim();
+ say(" Match against: '" + matchAgainst + "'");
+
+ // Expression didn't cause an expected error
+ if (matchAgainst.equals("ERR"))
+ {
+ fail("Was expected to be an error, but wasn't.");
+ continue;
+ }
+
+ // Try matching
+ try
+ {
+ // Match against the string
+ boolean b = r.match(matchAgainst);
+
+ // Get expected result
+ yesno = br.readLine().trim();
+
+ // If match succeeded
+ if (b)
+ {
+ // Status
+ say(" Match: YES");
+
+ // Match wasn't supposed to succeed
+ if (yesno.equals("NO"))
+ {
+ fail("Matched \"" + matchAgainst + "\", when not expected to.");
+ }
+ else
+ if (yesno.equals("YES"))
+ {
+ // Match succeeded as expected
+ success("Matched \"" + matchAgainst + "\", as expected:");
+
+ // Show subexpression registers
+ if (showSuccesses)
+ {
+ showParens(r);
+ }
+
+ say(" Paren count: " + r.getParenCount());
+
+ // Check registers against expected contents
+ for (int p = 0; p < r.getParenCount(); p++)
+ {
+ // Get next register
+ String register = br.readLine().trim();
+ say(" Paren " + p + " : " + r.getParen(p));
+
+ // Compare expected result with actual
+ if (register.length() == 0 && r.getParen(p) == null)
+ {
+ // Consider "" in test file equal to null
+ } else
+ if (!register.equals(r.getParen(p)))
+ {
+ // Register isn't what it was supposed to be
+ fail("Register " + p + " should be = \"" + register + "\", but is \"" + r.getParen(p) + "\" instead.");
+ }
+ }
+ }
+ else
+ {
+ // Bad test script
+ die("Test script error!");
+ }
+ }
+ else
+ {
+ // Status
+ say(" Match: NO");
+
+ // Match failed
+ if (yesno.equals("YES"))
+ {
+ // Should have failed
+ fail("Did not match \"" + matchAgainst + "\", when expected to.");
+ }
+ else
+ if (yesno.equals("NO"))
+ {
+ // Should have failed
+ success("Did not match \"" + matchAgainst + "\", as expected.");
+ }
+ else
+ {
+ // Bad test script
+ die("Test script error!");
+ }
+ }
+ }
+
+ // Matcher blew it
+ catch(Exception e)
+ {
+ fail("Matcher threw exception: " + e.toString());
+ e.printStackTrace();
+ }
+
+ // Internal error
+ catch(Error e)
+ {
+ fail("Matcher threw fatal error \"" + e.getMessage() + "\"");
+ e.printStackTrace();
+ }
+ }
+ }
+ finally
+ {
+ br.close();
+ }
+
+ // Show match time
+ System.out.println( NEW_LINE + NEW_LINE + "Match time = " + (System.currentTimeMillis() - ms) + " ms.");
+
+ // Print final results
+ System.out.println( NEW_LINE + "Tests complete. " + n + " tests, " + failures + " failure(s).");
+ }
+
+ /**
+ * Run automated unit test
+ * @exception Exception thrown in case of error
+ */
+ void runAutomatedTests() throws Exception
+ {
+ // Serialization test 1: Compile regexp and serialize/deserialize it
+ RE r = new RE("(a*)b");
+ say("Serialized/deserialized (a*)b");
+ ByteArrayOutputStream out = new ByteArrayOutputStream(128);
+ new ObjectOutputStream(out).writeObject(r);
+ ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
+ r = (RE)new ObjectInputStream(in).readObject();
+ if (!r.match("aaab")) {
+ fail("Did not match 'aaab' with deserialized RE.");
+ }
+ say("aaaab = true");
+ showParens(r);
+
+ // Serialization test 2: serialize/deserialize used regexp
+ out.reset();
+ say("Deserialized (a*)b");
+ new ObjectOutputStream(out).writeObject(r);
+ in = new ByteArrayInputStream(out.toByteArray());
+ r = (RE)new ObjectInputStream(in).readObject();
+ if (r.getParenCount() != 0) {
+ fail("Has parens after deserialization.");
+ }
+ if (!r.match("aaab")) {
+ fail("Did not match 'aaab' with deserialized RE.");
+ }
+ say("aaaab = true");
+ showParens(r);
+
+ // Test MATCH_CASEINDEPENDENT
+ r = new RE("abc(\\w*)");
+ say("MATCH_CASEINDEPENDENT abc(\\w*)");
+ r.setMatchFlags(RE.MATCH_CASEINDEPENDENT);
+ say("abc(d*)");
+ if (!r.match("abcddd")) {
+ fail("Did not match 'abcddd'.");
+ }
+ say("abcddd = true");
+ showParens(r);
+
+ if (!r.match("aBcDDdd")) {
+ fail("Did not match 'aBcDDdd'.");
+ }
+ say("aBcDDdd = true");
+ showParens(r);
+
+ if (!r.match("ABCDDDDD")) {
+ fail("Did not match 'ABCDDDDD'.");
+ }
+ say("ABCDDDDD = true");
+ showParens(r);
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/REDebugCompiler.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/REDebugCompiler.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/REDebugCompiler.java (revision 2)
@@ -0,0 +1,263 @@
+package org.apache.regexp;
+
+/*
+ * ====================================================================
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Jakarta-Regexp", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+
+import java.util.*;
+import java.io.*;
+
+/**
+ * A subclass of RECompiler which can dump a regular expression program
+ * for debugging purposes.
+ *
+ * @author Jonathan Locke
+ * @version $Id: REDebugCompiler.java,v 1.2 2001/02/27 08:37:06 gholam Exp $
+ */
+public class REDebugCompiler extends RECompiler
+{
+ /**
+ * Mapping from opcodes to descriptive strings
+ */
+ static Hashtable hashOpcode = new Hashtable();
+ static
+ {
+ hashOpcode.put(new Integer(RE.OP_RELUCTANTSTAR), "OP_RELUCTANTSTAR");
+ hashOpcode.put(new Integer(RE.OP_RELUCTANTPLUS), "OP_RELUCTANTPLUS");
+ hashOpcode.put(new Integer(RE.OP_RELUCTANTMAYBE), "OP_RELUCTANTMAYBE");
+ hashOpcode.put(new Integer(RE.OP_END), "OP_END");
+ hashOpcode.put(new Integer(RE.OP_BOL), "OP_BOL");
+ hashOpcode.put(new Integer(RE.OP_EOL), "OP_EOL");
+ hashOpcode.put(new Integer(RE.OP_ANY), "OP_ANY");
+ hashOpcode.put(new Integer(RE.OP_ANYOF), "OP_ANYOF");
+ hashOpcode.put(new Integer(RE.OP_BRANCH), "OP_BRANCH");
+ hashOpcode.put(new Integer(RE.OP_ATOM), "OP_ATOM");
+ hashOpcode.put(new Integer(RE.OP_STAR), "OP_STAR");
+ hashOpcode.put(new Integer(RE.OP_PLUS), "OP_PLUS");
+ hashOpcode.put(new Integer(RE.OP_MAYBE), "OP_MAYBE");
+ hashOpcode.put(new Integer(RE.OP_NOTHING), "OP_NOTHING");
+ hashOpcode.put(new Integer(RE.OP_GOTO), "OP_GOTO");
+ hashOpcode.put(new Integer(RE.OP_ESCAPE), "OP_ESCAPE");
+ hashOpcode.put(new Integer(RE.OP_OPEN), "OP_OPEN");
+ hashOpcode.put(new Integer(RE.OP_CLOSE), "OP_CLOSE");
+ hashOpcode.put(new Integer(RE.OP_BACKREF), "OP_BACKREF");
+ hashOpcode.put(new Integer(RE.OP_POSIXCLASS), "OP_POSIXCLASS");
+ hashOpcode.put(new Integer(RE.OP_OPEN_CLUSTER), "OP_OPEN_CLUSTER");
+ hashOpcode.put(new Integer(RE.OP_CLOSE_CLUSTER), "OP_CLOSE_CLUSTER");
+ }
+
+ /**
+ * Returns a descriptive string for an opcode.
+ * @param opcode Opcode to convert to a string
+ * @return Description of opcode
+ */
+ String opcodeToString(char opcode)
+ {
+ // Get string for opcode
+ String ret =(String)hashOpcode.get(new Integer(opcode));
+
+ // Just in case we have a corrupt program
+ if (ret == null)
+ {
+ ret = "OP_????";
+ }
+ return ret;
+ }
+
+ /**
+ * Return a string describing a (possibly unprintable) character.
+ * @param c Character to convert to a printable representation
+ * @return String representation of character
+ */
+ String charToString(char c)
+ {
+ // If it's unprintable, convert to '\###'
+ if (c < ' ' || c > 127)
+ {
+ return "\\" + (int)c;
+ }
+
+ // Return the character as a string
+ return String.valueOf(c);
+ }
+
+ /**
+ * Returns a descriptive string for a node in a regular expression program.
+ * @param node Node to describe
+ * @return Description of node
+ */
+ String nodeToString(int node)
+ {
+ // Get opcode and opdata for node
+ char opcode = instruction[node + RE.offsetOpcode];
+ int opdata = (int)instruction[node + RE.offsetOpdata];
+
+ // Return opcode as a string and opdata value
+ return opcodeToString(opcode) + ", opdata = " + opdata;
+ }
+
+ /**
+ * Inserts a node with a given opcode and opdata at insertAt. The node relative next
+ * pointer is initialized to 0.
+ * @param opcode Opcode for new node
+ * @param opdata Opdata for new node (only the low 16 bits are currently used)
+ * @param insertAt Index at which to insert the new node in the program * /
+ void nodeInsert(char opcode, int opdata, int insertAt) {
+ System.out.println( "====> " + opcode + " " + opdata + " " + insertAt );
+ PrintWriter writer = new PrintWriter( System.out );
+ dumpProgram( writer );
+ super.nodeInsert( opcode, opdata, insertAt );
+ System.out.println( "====< " );
+ dumpProgram( writer );
+ writer.flush();
+ }/**/
+
+
+ /**
+ * Appends a node to the end of a node chain
+ * @param node Start of node chain to traverse
+ * @param pointTo Node to have the tail of the chain point to * /
+ void setNextOfEnd(int node, int pointTo) {
+ System.out.println( "====> " + node + " " + pointTo );
+ PrintWriter writer = new PrintWriter( System.out );
+ dumpProgram( writer );
+ super.setNextOfEnd( node, pointTo );
+ System.out.println( "====< " );
+ dumpProgram( writer );
+ writer.flush();
+ }/**/
+
+
+ /**
+ * Dumps the current program to a PrintWriter
+ * @param p PrintWriter for program dump output
+ */
+ public void dumpProgram(PrintWriter p)
+ {
+ // Loop through the whole program
+ for (int i = 0; i < lenInstruction; )
+ {
+ // Get opcode, opdata and next fields of current program node
+ char opcode = instruction[i + RE.offsetOpcode];
+ char opdata = instruction[i + RE.offsetOpdata];
+ short next = (short)instruction[i + RE.offsetNext];
+
+ // Display the current program node
+ p.print(i + ". " + nodeToString(i) + ", next = ");
+
+ // If there's no next, say 'none', otherwise give absolute index of next node
+ if (next == 0)
+ {
+ p.print("none");
+ }
+ else
+ {
+ p.print(i + next);
+ }
+
+ // Move past node
+ i += RE.nodeSize;
+
+ // If character class
+ if (opcode == RE.OP_ANYOF)
+ {
+ // Opening bracket for start of char class
+ p.print(", [");
+
+ // Show each range in the char class
+ int rangeCount = opdata;
+ for (int r = 0; r < rangeCount; r++)
+ {
+ // Get first and last chars in range
+ char charFirst = instruction[i++];
+ char charLast = instruction[i++];
+
+ // Print range as X-Y, unless range encompasses only one char
+ if (charFirst == charLast)
+ {
+ p.print(charToString(charFirst));
+ }
+ else
+ {
+ p.print(charToString(charFirst) + "-" + charToString(charLast));
+ }
+ }
+
+ // Annotate the end of the char class
+ p.print("]");
+ }
+
+ // If atom
+ if (opcode == RE.OP_ATOM)
+ {
+ // Open quote
+ p.print(", \"");
+
+ // Print each character in the atom
+ for (int len = opdata; len-- != 0; )
+ {
+ p.print(charToString(instruction[i++]));
+ }
+
+ // Close quote
+ p.print("\"");
+ }
+
+ // Print a newline
+ p.println("");
+ }
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/ReaderCharacterIterator.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/ReaderCharacterIterator.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/ReaderCharacterIterator.java (revision 2)
@@ -0,0 +1,200 @@
+package org.apache.regexp;
+
+/*
+ * ====================================================================
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Jakarta-Regexp", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+
+import java.io.Reader;
+import java.io.IOException;
+
+/** Encapsulates InputStream, ...
+ *
+ * @author Ales Novak
+ */
+public final class ReaderCharacterIterator implements CharacterIterator
+{
+ /** Underlying reader */
+ private final Reader reader;
+
+ /** Buffer of read chars */
+ private final StringBuffer buff;
+
+ /** read end? */
+ private boolean closed;
+
+ /** @param reader a Reader, which is parsed */
+ public ReaderCharacterIterator(Reader reader)
+ {
+ this.reader = reader;
+ this.buff = new StringBuffer(512);
+ this.closed = false;
+ }
+
+ /** @return a substring */
+ public String substring(int offset, int length)
+ {
+ try
+ {
+ ensure(offset + length);
+ return buff.toString().substring(offset, length);
+ }
+ catch (IOException e)
+ {
+ throw new StringIndexOutOfBoundsException(e.getMessage());
+ }
+ }
+
+ /** @return a substring */
+ public String substring(int offset)
+ {
+ try
+ {
+ readAll();
+ return buff.toString().substring(offset);
+ }
+ catch (IOException e)
+ {
+ throw new StringIndexOutOfBoundsException(e.getMessage());
+ }
+ }
+
+ /** @return a character at the specified position. */
+ public char charAt(int pos)
+ {
+ try
+ {
+ ensure(pos);
+ return buff.charAt(pos);
+ }
+ catch (IOException e)
+ {
+ throw new StringIndexOutOfBoundsException(e.getMessage());
+ }
+ }
+
+ /** @return true iff if the specified index is after the end of the character stream */
+ public boolean isEnd(int pos)
+ {
+ if (buff.length() > pos)
+ {
+ return false;
+ }
+ else
+ {
+ try
+ {
+ ensure(pos);
+ return (buff.length() <= pos);
+ }
+ catch (IOException e)
+ {
+ throw new StringIndexOutOfBoundsException(e.getMessage());
+ }
+ }
+ }
+
+ /** Reads n characters from the stream and appends them to the buffer */
+ private int read(int n) throws IOException
+ {
+ if (closed)
+ {
+ return 0;
+ }
+
+ char[] c = new char[n];
+ int count = 0;
+ int read = 0;
+
+ do
+ {
+ read = reader.read(c);
+ if (read < 0) // EOF
+ {
+ closed = true;
+ break;
+ }
+ count += read;
+ buff.append(c, 0, read);
+ }
+ while (count < n);
+
+ return count;
+ }
+
+ /** Reads rest of the stream. */
+ private void readAll() throws IOException
+ {
+ while(! closed)
+ {
+ read(1000);
+ }
+ }
+
+ /** Reads chars up to the idx */
+ private void ensure(int idx) throws IOException
+ {
+ if (closed)
+ {
+ return;
+ }
+
+ if (idx < buff.length())
+ {
+ return;
+ }
+ read(idx + 1 - buff.length());
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/RESyntaxException.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/RESyntaxException.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/RESyntaxException.java (revision 2)
@@ -0,0 +1,81 @@
+package org.apache.regexp;
+
+/*
+ * ====================================================================
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Jakarta-Regexp", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+
+/**
+ * Exception thrown to indicate a syntax error in a regular expression.
+ * This is a non-checked exception because you should only have problems compiling
+ * a regular expression during development.
+ * If you are making regular expresion programs dynamically then you can catch it
+ * if you wish. But should not be forced to.
+ *
+ * @author Jonathan Locke
+ * @author .
+ *
+ */
+
+/** Encapsulates String
+ *
+ * @author Ales Novak
+ */
+public final class StringCharacterIterator implements CharacterIterator
+{
+ /** encapsulated */
+ private final String src;
+
+ /** @param src - encapsulated String */
+ public StringCharacterIterator(String src)
+ {
+ this.src = src;
+ }
+
+ /** @return a substring */
+ public String substring(int offset, int length)
+ {
+ return src.substring(offset, length);
+ }
+
+ /** @return a substring */
+ public String substring(int offset)
+ {
+ return src.substring(offset);
+ }
+
+ /** @return a character at the specified position. */
+ public char charAt(int pos)
+ {
+ return src.charAt(pos);
+ }
+
+ /** @return true iff if the specified index is after the end of the character stream */
+ public boolean isEnd(int pos)
+ {
+ return (pos >= src.length());
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/REProgram.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/REProgram.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/REProgram.java (revision 2)
@@ -0,0 +1,196 @@
+package org.apache.regexp;
+
+/*
+ * ====================================================================
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999-2003 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Jakarta-Regexp", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+
+import java.io.Serializable;
+
+/**
+ * A class that holds compiled regular expressions. This is exposed mainly
+ * for use by the recompile utility (which helps you produce precompiled
+ * REProgram objects). You should not otherwise need to work directly with
+ * this class.
+*
+ * @see RE
+ * @see RECompiler
+ *
+ * @author Jonathan Locke
+ * @version $Id: REProgram.java,v 1.3 2003/05/02 01:03:47 vgritsenko Exp $
+ */
+public class REProgram implements Serializable
+{
+ static final int OPT_HASBACKREFS = 1;
+
+ char[] instruction; // The compiled regular expression 'program'
+ int lenInstruction; // The amount of the instruction buffer in use
+ char[] prefix; // Prefix string optimization
+ int flags; // Optimization flags (REProgram.OPT_*)
+ int maxParens = -1;
+
+ /**
+ * Constructs a program object from a character array
+ * @param instruction Character array with RE opcode instructions in it
+ */
+ public REProgram(char[] instruction)
+ {
+ this(instruction, instruction.length);
+ }
+
+ /**
+ * Constructs a program object from a character array
+ * @param parens Count of parens in the program
+ * @param instruction Character array with RE opcode instructions in it
+ */
+ public REProgram(int parens, char[] instruction)
+ {
+ this(instruction, instruction.length);
+ this.maxParens = parens;
+ }
+
+ /**
+ * Constructs a program object from a character array
+ * @param instruction Character array with RE opcode instructions in it
+ * @param lenInstruction Amount of instruction array in use
+ */
+ public REProgram(char[] instruction, int lenInstruction)
+ {
+ setInstructions(instruction, lenInstruction);
+ }
+
+ /**
+ * Returns a copy of the current regular expression program in a character
+ * array that is exactly the right length to hold the program. If there is
+ * no program compiled yet, getInstructions() will return null.
+ * @return A copy of the current compiled RE program
+ */
+ public char[] getInstructions()
+ {
+ // Ensure program has been compiled!
+ if (lenInstruction != 0)
+ {
+ // Return copy of program
+ char[] ret = new char[lenInstruction];
+ System.arraycopy(instruction, 0, ret, 0, lenInstruction);
+ return ret;
+ }
+ return null;
+ }
+
+ /**
+ * Sets a new regular expression program to run. It is this method which
+ * performs any special compile-time search optimizations. Currently only
+ * two optimizations are in place - one which checks for backreferences
+ * (so that they can be lazily allocated) and another which attempts to
+ * find an prefix anchor string so that substantial amounts of input can
+ * potentially be skipped without running the actual program.
+ * @param instruction Program instruction buffer
+ * @param lenInstruction Length of instruction buffer in use
+ */
+ public void setInstructions(char[] instruction, int lenInstruction)
+ {
+ // Save reference to instruction array
+ this.instruction = instruction;
+ this.lenInstruction = lenInstruction;
+
+ // Initialize other program-related variables
+ flags = 0;
+ prefix = null;
+
+ // Try various compile-time optimizations if there's a program
+ if (instruction != null && lenInstruction != 0)
+ {
+ // If the first node is a branch
+ if (lenInstruction >= RE.nodeSize && instruction[0 + RE.offsetOpcode] == RE.OP_BRANCH)
+ {
+ // to the end node
+ int next = instruction[0 + RE.offsetNext];
+ if (instruction[next + RE.offsetOpcode] == RE.OP_END)
+ {
+ // and the branch starts with an atom
+ if (lenInstruction >= (RE.nodeSize * 2) && instruction[RE.nodeSize + RE.offsetOpcode] == RE.OP_ATOM)
+ {
+ // then get that atom as an prefix because there's no other choice
+ int lenAtom = instruction[RE.nodeSize + RE.offsetOpdata];
+ prefix = new char[lenAtom];
+ System.arraycopy(instruction, RE.nodeSize * 2, prefix, 0, lenAtom);
+ }
+ }
+ }
+
+ BackrefScanLoop:
+
+ // Check for backreferences
+ for (int i = 0; i < lenInstruction; i += RE.nodeSize)
+ {
+ switch (instruction[i + RE.offsetOpcode])
+ {
+ case RE.OP_ANYOF:
+ i += (instruction[i + RE.offsetOpdata] * 2);
+ break;
+
+ case RE.OP_ATOM:
+ i += instruction[i + RE.offsetOpdata];
+ break;
+
+ case RE.OP_BACKREF:
+ flags |= OPT_HASBACKREFS;
+ break BackrefScanLoop;
+ }
+ }
+ }
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10server/X10Server.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10server/X10Server.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10server/X10Server.java (revision 2)
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10server;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import com.jpeterson.x10.Transmitter;
+import com.jpeterson.x10.module.CM11A;
+
+/**
+ * This class implements an X10 service as a network controllable device by
+ * utilizing a CM11A device and the X10 Java interface. It
+ * implements a TCP service that is controlled through simple text commands.
+ * This provides a rudimentary human interface as well as a programmable
+ * interface. Because it provides a TCP interface, totally seperate systems
+ * running on independent boxes can be enabled with X10 control as long as
+ * the controlling system is able to make a TCP connection.
+ *
+ * This class also provides a mechanism to receive X10 events. The events
+ * are broadcast via UDP multicast broadcasts. This allows the service to
+ * efficiently notify multiple clients at once.
+ *
+ * X10 commands are sent to the service via a TCP connection. A client
+ * connects to the host running the service on the configured port. The
+ * client will be prompted with the prompt ">". This indicates that the
+ * service is ready to receive commands. Commands should be entered
+ * followed by a "\n". This signifies completion of the command. The
+ * service will then attempt to execute the commands. Upon an error,
+ * an error message will be displayed, followed by the prompt ">".
+ * When an error occurs in a line, none of the line is executed. If
+ * the command completes, the prompt ">" will be displayed, waiting for
+ * the next commands. Commands take the following form.
+ *
+ *
+ * commands = helpcmd | quitcmd | +( "(" command ")" )
+ * helpcmd = "help"
+ * quitcmd = "quit"
+ * command = house-code key-code [ *extra-data ]
+ * house-code = "A"
+ * | "B"
+ * | "C"
+ * | "D"
+ * | "E"
+ * | "F"
+ * | "G"
+ * | "H"
+ * | "I"
+ * | "J"
+ * | "K"
+ * | "L"
+ * | "M"
+ * | "N"
+ * | "O"
+ * | "P"
+ * key-code = "01" ; Unit 1
+ * | "02" ; Unit 2
+ * | "03" ; Unit 3
+ * | "04" ; Unit 4
+ * | "05" ; Unit 5
+ * | "06" ; Unit 6
+ * | "07" ; Unit 7
+ * | "08" ; Unit 8
+ * | "09" ; Unit 9
+ * | "10" ; Unit 10
+ * | "11" ; Unit 11
+ * | "12" ; Unit 12
+ * | "13" ; Unit 13
+ * | "14" ; Unit 14
+ * | "15" ; Unit 15
+ * | "16" ; Unit 16
+ * | "A0" ; All Units Off
+ * | "L1" ; All Lights On
+ * | "ON" ; On
+ * | "OF" ; Off
+ * | "DI" ; Dim
+ * | "BR" ; Bright
+ * | "L0" ; All Lights Off
+ * | "HR" ; Hail Request
+ * | "HA" ; Hail Acknowledge
+ * | "D1" ; Preset Dim 1
+ * | "D2" ; Preset Dim 2
+ * | "EX" ; Extended Data
+ * | "S1" ; Status On
+ * | "S0" ; Status Off
+ * | "SR" ; Status Request
+ * extra-data = <Extra data is key code specific. Presently, 'DI'
+ * and 'BR' use extra data. The extra data is a number
+ * from 1 - 22 to indicate the number of dims.>
+ *
+ *
+ * Example:
+ *
+ * | Turn on device A3 | (A03)(AON) |
+ * | Turn off all lights for house code E | EL0 |
+ * | Dim B13 by 11 dims | (B13)(BDI11) |
+ *
+ *
+ * The UDP status messages will take the following form:
+ *
h=E&k=DI&dim=11&max=22
+ * The format is similar to a HTTP URL encoded query string. The
+ * data is represented as key/value pairs, where the key and value
+ * are seperated by the equals ('=') character, and the pairs are
+ * seperated by the ampersand ('&') character. Parsing of this
+ * format should be straight forward as well as providing flexibility to
+ * extend the messages in the future.
+ *
+ * The key 'h' will contain the house code. This will be an upper case
+ * letter from 'A' through 'P', inclusive. The key 'k' indicates the key
+ * code. This will be the number 1 through 16 to indicate an address
+ * function for the device number, or one of the two character key codes
+ * described above in the command section. For a Dim or Bright function,
+ * the key 'dim' will be present and will indicate the number of dims, and the key 'max'
+ * will be present and indicates the total number of dims for that command type.
+ *
+ * @author Jesse Peterson
+ */
+public class X10Server extends X10ServerStub
+{
+ /**
+ * Serialized CM11A.
+ */
+ protected String serialFile;
+
+ /**
+ * X10 gateway.
+ */
+ protected CM11A cm11A;
+
+ /**
+ * Run a X10Server.
+ *
+ * @author Jesse Peterson
+ */
+ public static void main(String[] args)
+ {
+ int listenPort;
+ InetAddress statusAddress = null;
+ int statusPort;
+ String comPort;
+ X10Server server;
+ String serialFile = null;
+
+ // set default values
+ listenPort = DEFAULT_LISTEN_PORT;
+ try
+ {
+ statusAddress = InetAddress.getByName(DEFAULT_STATUS_ADDRESS);
+ }
+ catch (UnknownHostException e)
+ {
+ e.printStackTrace();
+ System.exit(EXIT_INVALID_LISTEN_PORT);
+ }
+ statusPort = DEFAULT_STATUS_PORT;
+ comPort = DEFAULT_COM_PORT;
+
+ try
+ {
+ for (int i = 0; i < args.length; i++)
+ {
+ if (args[i].equals("-listenport"))
+ {
+ try
+ {
+ listenPort = Integer.parseInt(args[++i]);
+ }
+ catch (NumberFormatException e)
+ {
+ System.err.println("Invalid listen port number.");
+ usage();
+ System.exit(EXIT_INVALID_LISTEN_PORT);
+ }
+ }
+ else if (args[i].equals("-statusaddress"))
+ {
+ try
+ {
+ statusAddress = InetAddress.getByName(args[++i]);
+ }
+ catch (UnknownHostException e)
+ {
+ System.err.println("Invalid status address.");
+ usage();
+ System.exit(EXIT_INVALID_STATUS_ADDRESS);
+ }
+ }
+ else if (args[i].equals("-statusport"))
+ {
+ try
+ {
+ statusPort = Integer.parseInt(args[++i]);
+ }
+ catch (NumberFormatException e)
+ {
+ System.err.println("Invalid listen port number.");
+ usage();
+ System.exit(EXIT_INVALID_LISTEN_PORT);
+ }
+ }
+ else if (args[i].equals("-port"))
+ {
+ comPort = args[++i];
+ }
+ else if (args[i].equals("-serialFile"))
+ {
+ // CM11A Serialized file
+ serialFile = args[++i];
+ }
+ else
+ {
+ usage();
+ System.exit(EXIT_INVALID_ARGUMENT);
+ }
+ }
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ usage();
+ System.exit(EXIT_INVALID_ARGUMENT);
+ }
+
+ server = new X10Server(serialFile, listenPort, statusAddress, statusPort, comPort);
+ try
+ {
+ server.start();
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Print out usage information.
+ *
+ * @author Jesse Peterson
+ */
+ public static void usage()
+ {
+ System.out.println("X10Server [-serialFile filename] [-listenport port] [-statusaddress IPAddress] [-statusport port] [-com comport]");
+ System.out.println("where:");
+ System.out.println(" -serialFile filename Once the macros are downloaded, serialize the CM11A");
+ System.out.println(" object out to the file specified by filename.");
+ System.out.println();
+ System.out.println(" -listenport port");
+ System.out.println(" Set the port that the server listens for control to connect to.");
+ System.out.println(" Default: " + DEFAULT_LISTEN_PORT);
+ System.out.println();
+ System.out.println(" -statusaddress IPAddress");
+ System.out.println(" Set the status broadcast address that status messages will be sent on.");
+ System.out.println(" Must be a valid multicast address from 224.0.0.1 through 239.255.255.255,");
+ System.out.println(" inclusive.");
+ System.out.println(" Default: " + DEFAULT_STATUS_ADDRESS);
+ System.out.println();
+ System.out.println(" -statusport port");
+ System.out.println(" Set the port that the status messages will be sent to.");
+ System.out.println(" Default: " + DEFAULT_STATUS_PORT);
+ System.out.println();
+ System.out.println(" -port comport");
+ System.out.println(" Set the com port that the CM11A can be contacted on.");
+ System.out.println(" Default: " + DEFAULT_COM_PORT);
+ }
+
+ /**
+ * Create a new X10Server.
+ *
+ * @param serialFile Filename of serialized CM11A.
+ * @param listenPort TCP port to listen for client connections on.
+ * @param statusAddress UDP multicast address to send status messages
+ * to.
+ * @param statusPort UDP port to send status messages to.
+ * @param comPort Serial port to talk to CM11A to.
+ * @author Jesse Peterson
+ */
+ public X10Server(String serialFile, int listenPort,
+ InetAddress statusAddress, int statusPort,
+ String comPort)
+ {
+ super(listenPort, statusAddress, statusPort, comPort);
+ this.serialFile = serialFile;
+ }
+
+ /**
+ * Create an instance of an CM11A object, which
+ * implements the Transmitter interface.
+ */
+ protected Transmitter createTransmitter()
+ {
+ cm11A = null;
+
+ if (serialFile != null)
+ {
+ // try to deserialize CM11A
+ try
+ {
+ ObjectInputStream istream = new ObjectInputStream(
+ new FileInputStream(serialFile));
+ cm11A = (CM11A)istream.readObject();
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ System.err.println("Unable to deserialize CM11A from " + serialFile + ", creating new one...");
+ }
+ catch (ClassNotFoundException e)
+ {
+ e.printStackTrace();
+ System.err.println("Unable to deserialize CM11A from " + serialFile + ", creating new one...");
+ }
+ }
+
+ if (cm11A == null)
+ {
+ cm11A = new CM11A();
+ }
+
+ cm11A.setPortName(comPort);
+ cm11A.addAddressListener(this);
+ cm11A.addFunctionListener(this);
+ try {
+ cm11A.allocate();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return(cm11A);
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10server/X10ServerSocketObjectPool.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10server/X10ServerSocketObjectPool.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10server/X10ServerSocketObjectPool.java (revision 2)
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10server;
+
+import java.io.BufferedInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import com.jpeterson.pool.SocketObjectPool;
+
+/**
+ * A pool of Socket's for X10Server's
+ *
+ * @author Jesse Peterson (jesse@jpeterson.com)
+ */
+public class X10ServerSocketObjectPool extends SocketObjectPool
+{
+ /**
+ * Create an object pool of Socket's for the specified
+ * hostname and port. Expiration is set to the default value.
+ *
+ * @param hostname Host name or IP address for sockets in the pool.
+ * @param port Port for sockets in the pool.
+ *
+ * @author Jesse Peterson (jesse@jpeterson.com)
+ */
+ public X10ServerSocketObjectPool(String hostname, int port)
+ throws UnknownHostException
+ {
+ this(InetAddress.getByName(hostname), port, DEFAULT_EXPIRATION);
+ }
+
+ /**
+ * Create an object pool of Socket's for the specified
+ * hostname and port with the specified expiration.
+ *
+ * @param hostname Host name or IP address for sockets in the pool.
+ * @param port Port for sockets in the pool.
+ * @param expiration Expiration in milliseconds for sockets in the
+ * pool.
+ *
+ * @author Jesse Peterson (jesse@jpeterson.com)
+ */
+ public X10ServerSocketObjectPool(String hostname, int port, long expiration)
+ throws UnknownHostException
+ {
+ this(InetAddress.getByName(hostname), port, expiration);
+ }
+
+ /**
+ * Create an object pool of Socket's for the specified
+ * address and port. Expiration is set to the default value.
+ *
+ * @param address Address for sockets in the pool.
+ * @param port Port for sockets in the pool.
+ *
+ * @author Jesse Peterson (jesse@jpeterson.com)
+ */
+ public X10ServerSocketObjectPool(InetAddress address, int port)
+ {
+ this(address, port, DEFAULT_EXPIRATION);
+ }
+
+ /**
+ * Create an object pool of Socket's for the specified
+ * address and port with the specified expiration.
+ *
+ * @param address Address for sockets in the pool.
+ * @param port Port for sockets in the pool.
+ * @param expiration Expiration in milliseconds for sockets in the
+ * pool.
+ *
+ * @author Jesse Peterson (jesse@jpeterson.com)
+ */
+ public X10ServerSocketObjectPool(InetAddress address, int port, long expiration)
+ {
+ super(address, port, expiration);
+ }
+
+ /**
+ * Create a new instance of a Socket.
+ *
+ * @return A new instance of a Socket or null
+ * if unable to create one.
+ *
+ * @author Jesse Peterson (jesse@jpeterson.com)
+ */
+ protected Object create()
+ {
+ BufferedInputStream x10rsp;
+ Socket socket = (Socket)super.create();
+ byte[] bytes = new byte[80];
+ int count;
+ StringBuffer buf = new StringBuffer();
+
+ if (System.getProperty("DEBUG") != null)
+ {
+ System.out.println("Creating new X10Server connection.");
+ }
+ try
+ {
+ if (socket != null)
+ {
+ // ensure connection is good. Wait for prompt
+ x10rsp = new BufferedInputStream(socket.getInputStream());
+
+ do
+ {
+ count = x10rsp.read(bytes);
+
+ if (count < 0)
+ {
+ // end of connection
+ socket = null;
+ }
+ if (count > 0)
+ {
+ buf.append(new String(bytes, 0, count));
+ }
+ } while ((buf.toString()).indexOf(X10Server.PROMPT) == -1);
+ }
+ }
+ catch (IOException e)
+ {
+ try
+ {
+ if (socket != null)
+ {
+ socket.close();
+ }
+ }
+ catch (IOException ex)
+ {
+ }
+ finally
+ {
+ socket = null;
+ }
+ }
+
+ return(socket);
+ }
+
+ /**
+ * Make sure that the X10Server is still there.
+ *
+ * @return Always returns true.
+ *
+ * @author Jesse Peterson (jesse@jpeterson.com)
+ */
+ protected boolean validate(Object o)
+ {
+ Socket socket;
+ StringBuffer buf;
+ int count;
+
+ if (o instanceof Socket)
+ {
+ String command = "\n";
+ byte[] bytes = command.getBytes();
+ socket = (Socket)o;
+ try
+ {
+ buf = new StringBuffer();
+ OutputStream out = socket.getOutputStream();
+ out.write(bytes);
+ out.flush();
+ InputStream in = socket.getInputStream();
+ bytes = new byte[20];
+ do
+ {
+ if (in.available() == 0)
+ {
+ try
+ {
+ Thread.sleep(100);
+ }
+ catch (InterruptedException e)
+ {
+ }
+ }
+ count = in.read(bytes);
+ if (count < 0)
+ {
+ // end of stream
+ return(false);
+ }
+ if (count > 0)
+ {
+ buf.append(new String(bytes, 0, count));
+ }
+ } while ((buf.toString()).indexOf("\n>") == -1);
+ return(true);
+ }
+ catch (IOException e)
+ {
+ return(false);
+ }
+ }
+ return(false);
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10server/X10ServerStub.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10server/X10ServerStub.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10server/X10ServerStub.java (revision 2)
@@ -0,0 +1,1165 @@
+/*
+ * Copyright (C) 2000 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10server;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.DatagramPacket;
+import java.net.InetAddress;
+import java.net.MulticastSocket;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.util.StringTokenizer;
+import java.util.Vector;
+import com.jpeterson.x10.Transmitter;
+import com.jpeterson.x10.event.AddressEvent;
+import com.jpeterson.x10.event.AddressListener;
+import com.jpeterson.x10.event.AllLightsOffEvent;
+import com.jpeterson.x10.event.AllLightsOnEvent;
+import com.jpeterson.x10.event.AllUnitsOffEvent;
+import com.jpeterson.x10.event.BrightEvent;
+import com.jpeterson.x10.event.DimEvent;
+import com.jpeterson.x10.event.FunctionEvent;
+import com.jpeterson.x10.event.FunctionListener;
+import com.jpeterson.x10.event.HailAcknowledgeEvent;
+import com.jpeterson.x10.event.HailRequestEvent;
+import com.jpeterson.x10.event.OffEvent;
+import com.jpeterson.x10.event.OnEvent;
+import com.jpeterson.x10.event.PresetDim1Event;
+import com.jpeterson.x10.event.PresetDim2Event;
+import com.jpeterson.x10.event.StatusOffEvent;
+import com.jpeterson.x10.event.StatusOnEvent;
+import com.jpeterson.x10.event.StatusRequestEvent;
+import com.jpeterson.x10.event.X10Event;
+
+/**
+ * This class implements an X10 service as a network controllable device by
+ * utilizing a CM11A device and the X10 Java interface. It
+ * implements a TCP service that is controlled through simple text commands.
+ * This provides a rudimentary human interface as well as a programmable
+ * interface. Because it provides a TCP interface, totally seperate systems
+ * running on independent boxes can be enabled with X10 control as long as
+ * the controlling system is able to make a TCP connection.
+ *
+ * This class also provides a mechanism to receive X10 events. The events
+ * are broadcast via UDP multicast broadcasts. This allows the service to
+ * efficiently notify multiple clients at once.
+ *
+ * X10 commands are sent to the service via a TCP connection. A client
+ * connects to the host running the service on the configured port. The
+ * client will be prompted with the prompt ">". This indicates that the
+ * service is ready to receive commands. Commands should be entered
+ * followed by a "\n". This signifies completion of the command. The
+ * service will then attempt to execute the commands. Upon an error,
+ * an error message will be displayed, followed by the prompt ">".
+ * When an error occurs in a line, none of the line is executed. If
+ * the command completes, the prompt ">" will be displayed, waiting for
+ * the next commands. Commands take the following form.
+ *
+ *
+ * commands = helpcmd | quitcmd | +( "(" command ")" )
+ * helpcmd = "help"
+ * quitcmd = "quit"
+ * command = house-code key-code [ *extra-data ]
+ * house-code = "A"
+ * | "B"
+ * | "C"
+ * | "D"
+ * | "E"
+ * | "F"
+ * | "G"
+ * | "H"
+ * | "I"
+ * | "J"
+ * | "K"
+ * | "L"
+ * | "M"
+ * | "N"
+ * | "O"
+ * | "P"
+ * key-code = "01" ; Unit 1
+ * | "02" ; Unit 2
+ * | "03" ; Unit 3
+ * | "04" ; Unit 4
+ * | "05" ; Unit 5
+ * | "06" ; Unit 6
+ * | "07" ; Unit 7
+ * | "08" ; Unit 8
+ * | "09" ; Unit 9
+ * | "10" ; Unit 10
+ * | "11" ; Unit 11
+ * | "12" ; Unit 12
+ * | "13" ; Unit 13
+ * | "14" ; Unit 14
+ * | "15" ; Unit 15
+ * | "16" ; Unit 16
+ * | "A0" ; All Units Off
+ * | "L1" ; All Lights On
+ * | "ON" ; On
+ * | "OF" ; Off
+ * | "DI" ; Dim
+ * | "BR" ; Bright
+ * | "L0" ; All Lights Off
+ * | "HR" ; Hail Request
+ * | "HA" ; Hail Acknowledge
+ * | "D1" ; Preset Dim 1
+ * | "D2" ; Preset Dim 2
+ * | "EX" ; Extended Data
+ * | "S1" ; Status On
+ * | "S0" ; Status Off
+ * | "SR" ; Status Request
+ * extra-data = <Extra data is key code specific. Presently, 'DI'
+ * and 'BR' use extra data. The extra data is a number
+ * from 1 - 22 to indicate the number of dims.>
+ *
+ *
+ * Example:
+ *
+ * | Turn on device A3 | (A03)(AON) |
+ * | Turn off all lights for house code E | EL0 |
+ * | Dim B13 by 11 dims | (B13)(BDI11) |
+ *
+ *
+ * The UDP status messages will take the following form:
+ *
h=E&k=DI&dim=11&max=22
+ * The format is similar to a HTTP URL encoded query string. The
+ * data is represented as key/value pairs, where the key and value
+ * are seperated by the equals ('=') character, and the pairs are
+ * seperated by the ampersand ('&') character. Parsing of this
+ * format should be straight forward as well as providing flexibility to
+ * extend the messages in the future.
+ *
+ * The key 'h' will contain the house code. This will be an upper case
+ * letter from 'A' through 'P', inclusive. The key 'k' indicates the key
+ * code. This will be the number 1 through 16 to indicate an address
+ * function for the device number, or one of the two character key codes
+ * described above in the command section. For a Dim or Bright function,
+ * the key 'dim' will be present and will indicate the number of dims, and the key 'max'
+ * will be present and indicates the total number of dims for that command type.
+ *
+ * @author Jesse Peterson
+ */
+public abstract class X10ServerStub implements AddressListener, FunctionListener
+{
+ /**
+ * Exit value of '1' indicates and invalid argument.
+ */
+ public static final int EXIT_INVALID_ARGUMENT = 1;
+
+ /**
+ * Exit value of '2' indicates and invalid listent port.
+ */
+ public static final int EXIT_INVALID_LISTEN_PORT = 2;
+
+ /**
+ * Exit value of '3' indicates and invalid status address.
+ */
+ public static final int EXIT_INVALID_STATUS_ADDRESS = 3;
+
+ /**
+ * Exit value of '4' indicates and invalid status port.
+ */
+ public static final int EXIT_INVALID_STATUS_PORT = 4;
+
+ /**
+ * Default listen port: 4377
+ */
+ public static final int DEFAULT_LISTEN_PORT = 4377;
+
+ /**
+ * Default UDP status broadcast address: 239.6.20.71
+ */
+ public static final String DEFAULT_STATUS_ADDRESS = "239.6.20.71";
+
+ /**
+ * Default UDP status broadcast port: 4378
+ */
+ public static final int DEFAULT_STATUS_PORT = 4378;
+
+ /**
+ * Default serial port: COM2
+ */
+ public static final String DEFAULT_COM_PORT = "COM2";
+
+ /**
+ * Default command prompt: '>'
+ */
+ public static final String PROMPT = ">";
+
+ /**
+ * Command to get help on possible commands. "help"
+ */
+ public static final String COMMAND_HELP = "help";
+
+ /**
+ * Command to quit, logging out of the server. "quit"
+ */
+ public static final String COMMAND_QUIT = "quit";
+
+ /** All Units Off Key Code - "A0" */
+ public static final String ALL_UNITS_OFF_KEY_CODE = "A0";
+
+ /** All Lights On Key Code - "L1" */
+ public static final String ALL_LIGHTS_ON_KEY_CODE = "L1";
+
+ /** On Key Code - "ON" */
+ public static final String ON_KEY_CODE = "ON";
+
+ /** Off Key Code - "OF" */
+ public static final String OFF_KEY_CODE = "OF";
+
+ /** Dim Key Code - "DI" */
+ public static final String DIM_KEY_CODE = "DI";
+
+ /** Bright Key Code - "BR" */
+ public static final String BRIGHT_KEY_CODE = "BR";
+
+ /** All Lights Off Key Code - "L0" */
+ public static final String ALL_LIGHTS_OFF_KEY_CODE = "L0";
+
+ /** Hail Request Key Code - "HR" */
+ public static final String HAIL_REQUEST_KEY_CODE = "HR";
+
+ /** Hail Acknowledge Key Code - "HR" */
+ public static final String HAIL_ACKNOWLEDGE_KEY_CODE = "HA";
+
+ /** Preset Dim 1 Key Code - "D1" */
+ public static final String PRESET_DIM_1_KEY_CODE = "D1";
+
+ /** Preset Dim 2 Key Code - "D2" */
+ public static final String PRESET_DIM_2_KEY_CODE = "D2";
+
+ /** Extended Data Key Code - "EX" */
+ public static final String EXTENDED_DATA_KEY_CODE = "EX";
+
+ /** Status On Key Code - "S1" */
+ public static final String STATUS_ON_KEY_CODE = "S1";
+
+ /** Status Off Key Code - "S0" */
+ public static final String STATUS_OFF_KEY_CODE = "S0";
+
+ /** Status Request Key Code - "SR" */
+ public static final String STATUS_REQUEST_KEY_CODE = "SR";
+
+ /**
+ * TCP port to listen for client connections on.
+ */
+ protected int listenPort;
+
+ /**
+ * IP Address for UDP status broadcasts.
+ */
+ protected InetAddress statusAddress;
+
+ /**
+ * UDP port for status broadcasts.
+ */
+ protected int statusPort;
+
+ /**
+ * Serial port to talk to CM11A to.
+ */
+ protected String comPort;
+
+ /**
+ * Where worker threads stand idle.
+ */
+ protected Vector threads = new Vector();
+
+ /**
+ * max # worker threads.
+ */
+ protected int workers = 5;
+
+ /**
+ * Inactivity timeout.
+ */
+ protected int timeout = 0;
+
+ /**
+ * Status broadcast socket.
+ */
+ protected MulticastSocket broadcastSocket;
+
+ /**
+ * X10 gateway.
+ */
+ protected Transmitter transmitter;
+
+ /**
+ * Variable used to indicate that the server is running.
+ */
+ protected boolean run;
+
+
+ /**
+ * Create a new X10ServerStub
+ *
+ * @param listenPort TCP port to listen for client connections on.
+ * @param statusAddress UDP multicast address to send status messages
+ * to.
+ * @param statusPort UDP port to send status messages to.
+ * @param comPort Serial port to talk to Transmitter to.
+ * @author Jesse Peterson
+ */
+ public X10ServerStub(int listenPort, InetAddress statusAddress,
+ int statusPort, String comPort)
+ {
+ this.listenPort = listenPort;
+ this.statusAddress = statusAddress;
+ this.statusPort = statusPort;
+ this.comPort = comPort;
+ }
+
+ /**
+ * Subclasses must implement this method, creating an instance
+ * of the Transmitter interface. The transmitter
+ * should be initialized to for X10Event generation
+ * if appropriate. i.e., call addAddressListener(this)
+ * and addFunctionListener(this).
+ */
+ protected abstract Transmitter createTransmitter();
+
+ /**
+ * Start listening for client connections.
+ *
+ * @author Jesse Peterson
+ */
+ public void start() throws IOException
+ {
+ transmitter = createTransmitter();
+
+ broadcastSocket = new MulticastSocket();
+
+ for (int i = 0; i < workers; ++i)
+ {
+ Worker w = new Worker();
+ (new Thread(w, "worker #"+i)).start();
+ threads.addElement(w);
+ }
+
+ ServerSocket serverSocket = new ServerSocket(listenPort);
+
+ run = true;
+
+ while (run)
+ {
+ Socket s = serverSocket.accept();
+
+ Worker w = null;
+ synchronized (threads)
+ {
+ if (threads.isEmpty())
+ {
+ Worker ws = new Worker();
+ ws.setSocket(s);
+ (new Thread(ws, "additional worker")).start();
+ }
+ else
+ {
+ w = (Worker)threads.elementAt(0);
+ threads.removeElementAt(0);
+ w.setSocket(s);
+ }
+ }
+ }
+
+ // cleanup
+ }
+
+ /**
+ * Stop the running server.
+ */
+ public void stop()
+ {
+ run = false;
+ }
+
+ /**
+ * Send a UDP broadcast message.
+ *
+ * @param msg Message to send
+ */
+ public void broadcast(String msg) throws IOException
+ {
+ byte[] buf;
+
+ buf = msg.getBytes();
+ DatagramPacket packet = new DatagramPacket(buf, buf.length,
+ statusAddress,
+ statusPort);
+ broadcastSocket.send(packet);
+ }
+
+ /**
+ * Listener for AddressEvents.
+ *
+ * @param e AddressEvent.
+ */
+ public void address(AddressEvent e)
+ {
+ // send address event
+ synchronized (this)
+ {
+ try
+ {
+ broadcast("h=" + e.getHouseCode() + "&k=" + e.getDeviceCode());
+ }
+ catch (IOException ex)
+ {
+ }
+ }
+ }
+
+ /**
+ * Listener for All Units Off function.
+ *
+ * @author Jesse Peterson
+ */
+ public void functionAllUnitsOff(FunctionEvent e)
+ {
+ // send all units off event
+ synchronized (this)
+ {
+ try
+ {
+ broadcast("h=" + e.getHouseCode() + "&k=" + ALL_UNITS_OFF_KEY_CODE);
+ }
+ catch (IOException ex)
+ {
+ }
+ }
+ }
+
+ /**
+ * Listener for All Lights On function.
+ *
+ * @author Jesse Peterson
+ */
+ public void functionAllLightsOn(FunctionEvent e)
+ {
+ // send all lights on event
+ synchronized (this)
+ {
+ try
+ {
+ broadcast("h=" + e.getHouseCode() + "&k=" + ALL_LIGHTS_ON_KEY_CODE);
+ }
+ catch (IOException ex)
+ {
+ }
+ }
+ }
+
+ /**
+ * Listener for On function.
+ *
+ * @author Jesse Peterson
+ */
+ public void functionOn(FunctionEvent e)
+ {
+ // send on event
+ synchronized (this)
+ {
+ try
+ {
+ broadcast("h=" + e.getHouseCode() + "&k=" + ON_KEY_CODE);
+ }
+ catch (IOException ex)
+ {
+ }
+ }
+ }
+
+ /**
+ * Listener for Off function.
+ *
+ * @author Jesse Peterson
+ */
+ public void functionOff(FunctionEvent e)
+ {
+ // send on event
+ synchronized (this)
+ {
+ try
+ {
+ broadcast("h=" + e.getHouseCode() + "&k=" + OFF_KEY_CODE);
+ }
+ catch (IOException ex)
+ {
+ }
+ }
+ }
+
+ /**
+ * Listener for Dim function.
+ *
+ * @author Jesse Peterson
+ */
+ public void functionDim(FunctionEvent e)
+ {
+ // send dim event
+ synchronized (this)
+ {
+ try
+ {
+ broadcast("h=" + e.getHouseCode() + "&k=" + DIM_KEY_CODE + "&dim=" +
+ e.getDims() + "&max=" + e.getDimMax());
+ }
+ catch (IOException ex)
+ {
+ }
+ }
+ }
+
+ /**
+ * Listener for Bright function.
+ *
+ * @author Jesse Peterson
+ */
+ public void functionBright(FunctionEvent e)
+ {
+ // send bright event
+ synchronized (this)
+ {
+ try
+ {
+ broadcast("h=" + e.getHouseCode() + "&k=" + BRIGHT_KEY_CODE + "&dim=" +
+ e.getDims() + "&max=" + e.getDimMax());
+ }
+ catch (IOException ex)
+ {
+ }
+ }
+ }
+
+ /**
+ * Listener for All Lights Off function.
+ *
+ * @author Jesse Peterson
+ */
+ public void functionAllLightsOff(FunctionEvent e)
+ {
+ // send all lights off event
+ synchronized (this)
+ {
+ try
+ {
+ broadcast("h=" + e.getHouseCode() + "&k=" + ALL_LIGHTS_OFF_KEY_CODE);
+ }
+ catch (IOException ex)
+ {
+ }
+ }
+ }
+
+ /**
+ * Listener for Hail Request function.
+ *
+ * @author Jesse Peterson
+ */
+ public void functionHailRequest(FunctionEvent e)
+ {
+ // send hail request event
+ synchronized (this)
+ {
+ try
+ {
+ broadcast("h=" + e.getHouseCode() + "&k=" + HAIL_REQUEST_KEY_CODE);
+ }
+ catch (IOException ex)
+ {
+ }
+ }
+ }
+
+ /**
+ * Listener for Hail Acknowledge function.
+ *
+ * @author Jesse Peterson
+ */
+ public void functionHailAcknowledge(FunctionEvent e)
+ {
+ // send hail acknowledge event
+ synchronized (this)
+ {
+ try
+ {
+ broadcast("h=" + e.getHouseCode() + "&k=" + HAIL_ACKNOWLEDGE_KEY_CODE);
+ }
+ catch (IOException ex)
+ {
+ }
+ }
+ }
+
+ /**
+ * Listener for Preset Dim 1 function.
+ *
+ * @author Jesse Peterson
+ */
+ public void functionPresetDim1(FunctionEvent e)
+ {
+ // send preset dim 1 event
+ synchronized (this)
+ {
+ try
+ {
+ broadcast("h=" + e.getHouseCode() + "&k=" + PRESET_DIM_1_KEY_CODE);
+ }
+ catch (IOException ex)
+ {
+ }
+ }
+ }
+
+ /**
+ * Listener for Preset Dim 2 function.
+ *
+ * @author Jesse Peterson
+ */
+ public void functionPresetDim2(FunctionEvent e)
+ {
+ // send preset dim 2 event
+ synchronized (this)
+ {
+ try
+ {
+ broadcast("h=" + e.getHouseCode() + "&k=" + PRESET_DIM_2_KEY_CODE);
+ }
+ catch (IOException ex)
+ {
+ }
+ }
+ }
+
+ /**
+ * Listener for Status On function.
+ *
+ * @author Jesse Peterson
+ */
+ public void functionStatusOn(FunctionEvent e)
+ {
+ // send status on event
+ synchronized (this)
+ {
+ try
+ {
+ broadcast("h=" + e.getHouseCode() + "&k=" + STATUS_ON_KEY_CODE);
+ }
+ catch (IOException ex)
+ {
+ }
+ }
+ }
+
+ /**
+ * Listener for Status Off function.
+ *
+ * @author Jesse Peterson
+ */
+ public void functionStatusOff(FunctionEvent e)
+ {
+ // send status off event
+ synchronized (this)
+ {
+ try
+ {
+ broadcast("h=" + e.getHouseCode() + "&k=" + STATUS_OFF_KEY_CODE);
+ }
+ catch (IOException ex)
+ {
+ }
+ }
+ }
+
+ /**
+ * Listener for Status Request function.
+ *
+ * @author Jesse Peterson
+ */
+ public void functionStatusRequest(FunctionEvent e)
+ {
+ // send status request event
+ synchronized (this)
+ {
+ try
+ {
+ broadcast("h=" + e.getHouseCode() + "&k=" + STATUS_REQUEST_KEY_CODE);
+ }
+ catch (IOException ex)
+ {
+ }
+ }
+ }
+
+ /**
+ * Class that is responsible for handling an individual connection
+ * to the server.
+ *
+ * @author Jesse Peterson
+ */
+ class Worker implements Runnable
+ {
+ private Socket s;
+
+ /**
+ * Create a worker.
+ *
+ * @author Jesse Peterson
+ */
+ public Worker()
+ {
+ s = null;
+ }
+
+ /**
+ * Called to pass the client connection socket to the worker.
+ * This will start the worker thread to handle the client.
+ *
+ * @author Jesse Peterson
+ */
+ public synchronized void setSocket(Socket s)
+ {
+ this.s = s;
+ notify();
+ }
+
+ /**
+ * Handle the user interface for the client. Prompt for commands and
+ * then process those commands.
+ *
+ * @author Jesse Peterson
+ */
+ public synchronized void run()
+ {
+ while(true)
+ {
+ if (s == null)
+ {
+ // nothing to do
+ try
+ {
+ wait();
+ }
+ catch (InterruptedException e)
+ {
+ // should not happen
+ continue;
+ }
+ }
+ try
+ {
+ handleClient();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ // go back in wait queue if there's fewer
+ // than numHandler connections.
+ s = null;
+ Vector pool = threads;
+ synchronized (pool)
+ {
+ if (pool.size() >= workers)
+ {
+ // too many thread.
+ return;
+ }
+ else
+ {
+ pool.addElement(this);
+ }
+ }
+ }
+ }
+
+ /**
+ * Implement server protocol. Provides prompts, recieves commands,
+ * and informs of errors.
+ *
+ * @exception IOException Unable to read or write to the socket.
+ * @author Jesse Peterson
+ */
+ protected void handleClient() throws IOException
+ {
+ boolean done = false;
+ String line;
+ BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
+ PrintWriter out = new PrintWriter(s.getOutputStream());
+ // We will only block in readline for this many milliseconds
+ // before we fail with java.io.InterruptedIOException,
+ // at which point we will abandon the connection
+ s.setSoTimeout(timeout);
+ s.setTcpNoDelay(true);
+
+ try
+ {
+ while (!done)
+ {
+ // print prompt
+ out.print(PROMPT);
+ out.flush();
+
+ // get command
+ line = in.readLine();
+
+ if (line == null)
+ {
+ done = true;
+ }
+ else if (line.equals(COMMAND_HELP))
+ {
+ // write out help
+ out.println("Available Commands");
+ out.println("help - this help information");
+ out.println("quit - log out from the server");
+ out.flush();
+ }
+ else if (line.equals(COMMAND_QUIT))
+ {
+ // quit
+ done = true;
+ }
+ else
+ {
+ // process command
+ processCommand(line, out);
+ }
+ }
+ }
+ finally
+ {
+ s.close();
+ }
+ }
+
+ /**
+ * Process a command line.
+ *
+ * @param line Command line
+ * @param out PrintWriter to send error messages to
+ * @author Jesse Peterson
+ */
+ protected void processCommand(String line, PrintWriter out)
+ {
+ Vector commands = new Vector();
+ X10Event events[] = null;
+
+ line = line.trim();
+ if (line.startsWith("("))
+ {
+ // transaction
+ String token;
+ int state; // 0 = expecting '('
+ // 1 = expecting command
+ // 2 = expecting ')'
+ StringTokenizer st = new StringTokenizer(line, "()", true);
+
+ // initial state
+ state = 0;
+
+ while (st.hasMoreTokens())
+ {
+ token = st.nextToken();
+
+ if (token.equals("("))
+ {
+ if (state != 0)
+ {
+ out.print("Error: Syntax error, expected '(', received '" + token + "' in command line \"" + line + "\"\r\n");
+ out.flush();
+ return;
+ }
+
+ // transition to next state
+ state = 1;
+ }
+ else if (token.equals(")"))
+ {
+ if (state != 2)
+ {
+ out.print("Error: Syntax error, expected ')', received '" + token + "' in command line \"" + line + "\"\r\n");
+ out.flush();
+ return;
+ }
+
+ // transition to next state.
+ state = 0;
+ }
+ else
+ {
+ token = token.trim();
+
+ if (state != 1)
+ {
+ out.print("Error: Syntax error, expected command, received '" + token + "' in command line \"" + line + "\"\r\n");
+ out.flush();
+ return;
+ }
+
+ commands.addElement(token.trim());
+
+ // transition to next state.
+ state = 2;
+ }
+ }
+ }
+ else
+ {
+ commands.addElement(line);
+ }
+
+ // process commands
+ events = new X10Event[commands.size()];
+ for (int i = 0; i < events.length; i++)
+ {
+ try
+ {
+ events[i] = createX10Event((String)commands.elementAt(i));
+ }
+ catch (IllegalArgumentException e)
+ {
+ out.print("Error: " + e.getMessage() + " in command line \"" + line + "\"\r\n");
+ out.flush();
+ return;
+ }
+ }
+
+ // send X10 Events to gateway.
+ synchronized (transmitter)
+ {
+ for (int j = 0; j < events.length; j++)
+ {
+ if (System.getProperty("DEBUG") != null)
+ {
+ System.out.println("Transmitting: " + events[j]);
+ }
+ try
+ {
+ transmitter.transmit(events[j]);
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ /**
+ * Convert command to X10Event.
+ *
+ * @param command X10 command
+ * @return X10Event for the command
+ * @author Jesse Peterson
+ */
+ protected X10Event createX10Event(String command)
+ {
+ char houseCode;
+ String keyCode;
+
+ if (command.length() < 3)
+ {
+ throw new IllegalArgumentException("Command " + command + " is less than 3 characters long");
+ }
+
+ // get house code
+ houseCode = command.charAt(0);
+ keyCode = command.substring(1, 3);
+
+ if (keyCode.equals("01"))
+ {
+ return new AddressEvent(this, houseCode, 1);
+ }
+ else if (keyCode.equals("02"))
+ {
+ return new AddressEvent(this, houseCode, 2);
+ }
+ else if (keyCode.equals("03"))
+ {
+ return new AddressEvent(this, houseCode, 3);
+ }
+ else if (keyCode.equals("04"))
+ {
+ return new AddressEvent(this, houseCode, 4);
+ }
+ else if (keyCode.equals("05"))
+ {
+ return new AddressEvent(this, houseCode, 5);
+ }
+ else if (keyCode.equals("06"))
+ {
+ return new AddressEvent(this, houseCode, 6);
+ }
+ else if (keyCode.equals("07"))
+ {
+ return new AddressEvent(this, houseCode, 7);
+ }
+ else if (keyCode.equals("08"))
+ {
+ return new AddressEvent(this, houseCode, 8);
+ }
+ else if (keyCode.equals("09"))
+ {
+ return new AddressEvent(this, houseCode, 9);
+ }
+ else if (keyCode.equals("10"))
+ {
+ return new AddressEvent(this, houseCode, 10);
+ }
+ else if (keyCode.equals("11"))
+ {
+ return new AddressEvent(this, houseCode, 11);
+ }
+ else if (keyCode.equals("12"))
+ {
+ return new AddressEvent(this, houseCode, 12);
+ }
+ else if (keyCode.equals("13"))
+ {
+ return new AddressEvent(this, houseCode, 13);
+ }
+ else if (keyCode.equals("14"))
+ {
+ return new AddressEvent(this, houseCode, 14);
+ }
+ else if (keyCode.equals("15"))
+ {
+ return new AddressEvent(this, houseCode, 15);
+ }
+ else if (keyCode.equals("16"))
+ {
+ return new AddressEvent(this, houseCode, 16);
+ }
+ else if (keyCode.equals(ALL_UNITS_OFF_KEY_CODE))
+ {
+ // all units off
+ return new AllUnitsOffEvent(this, houseCode);
+ }
+ else if (keyCode.equals(ALL_LIGHTS_ON_KEY_CODE))
+ {
+ // all lights on
+ return new AllLightsOnEvent(this, houseCode);
+ }
+ else if (keyCode.equals(ON_KEY_CODE))
+ {
+ // on
+ return new OnEvent(this, houseCode);
+ }
+ else if (keyCode.equals(OFF_KEY_CODE))
+ {
+ // off
+ return new OffEvent(this, houseCode);
+ }
+ else if (keyCode.equals(DIM_KEY_CODE))
+ {
+ // dim
+ if (command.length() < 4)
+ {
+ return new DimEvent(this, houseCode, 5, 22);
+ }
+
+ String temp = command.substring(3);
+ try
+ {
+ return new DimEvent(this, houseCode,
+ Integer.parseInt(temp), 22);
+ }
+ catch (NumberFormatException e)
+ {
+ throw new IllegalArgumentException("Unable to convert " + temp + " to a number");
+ }
+ }
+ else if (keyCode.equals(BRIGHT_KEY_CODE))
+ {
+ // bright
+ if (command.length() < 4)
+ {
+ return new BrightEvent(this, houseCode, 5, 22);
+ }
+
+ String temp = command.substring(3);
+ try
+ {
+ return new BrightEvent(this, houseCode,
+ Integer.parseInt(temp), 22);
+ }
+ catch (NumberFormatException e)
+ {
+ throw new IllegalArgumentException("Unable to convert " + temp + " to a number");
+ }
+ }
+ else if (keyCode.equals(ALL_LIGHTS_OFF_KEY_CODE))
+ {
+ // all lights off
+ return new AllLightsOffEvent(this, houseCode);
+ }
+ else if (keyCode.equals(HAIL_REQUEST_KEY_CODE))
+ {
+ // hail request
+ return new HailRequestEvent(this, houseCode);
+ }
+ else if (keyCode.equals(HAIL_ACKNOWLEDGE_KEY_CODE))
+ {
+ // hail acknowledge
+ return new HailAcknowledgeEvent(this, houseCode);
+ }
+ else if (keyCode.equals(PRESET_DIM_1_KEY_CODE))
+ {
+ // preset dim 1
+ return new PresetDim1Event(this, houseCode);
+ }
+ else if (keyCode.equals(PRESET_DIM_2_KEY_CODE))
+ {
+ // preset dim 2
+ return new PresetDim2Event(this, houseCode);
+ }
+ else if (keyCode.equals(EXTENDED_DATA_KEY_CODE))
+ {
+ // extended data
+ throw new IllegalArgumentException("Extended data event not yet implemented");
+ }
+ else if (keyCode.equals(STATUS_ON_KEY_CODE))
+ {
+ // status on
+ return new StatusOnEvent(this, houseCode);
+ }
+ else if (keyCode.equals(STATUS_OFF_KEY_CODE))
+ {
+ // status off
+ return new StatusOffEvent(this, houseCode);
+ }
+ else if (keyCode.equals(STATUS_REQUEST_KEY_CODE))
+ {
+ // status request
+ return new StatusRequestEvent(this, houseCode);
+ }
+ else
+ {
+ throw new IllegalArgumentException("Unknown command " + command);
+ }
+ }
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/ControlException.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/ControlException.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/ControlException.java (revision 2)
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10;
+
+/**
+ * Signals that an exception has occurred.
+ *
+ * In addition to exceptions that inherit from ControlException
+ * some calls throw other Java Exceptions and Errors
+ * such as IllegalArgumentException and
+ * SecurityException.
+ *
+ * @see ControlError
+ * @see Serialized Form
+ *
+ * @author Jesse Peterson <6/29/99>
+ * @version 1.0
+ */
+public class ControlException extends Exception
+{
+ /**
+ * Constructs a ControlException with no detail message.
+ *
+ * @author Jesse Peterson <6/29/99>
+ */
+ public ControlException()
+ {
+ super();
+ }
+
+ /**
+ * Constructs a ControlException with the specified detail
+ * message. A detail message is a String that describes this
+ * particular exception.
+ *
+ * @param s the detail message
+ *
+ * @author Jesse Peterson <6/29/99>
+ */
+ public ControlException(String s)
+ {
+ super(s);
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/Gateway.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/Gateway.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/Gateway.java (revision 2)
@@ -0,0 +1,423 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10;
+
+public abstract interface Gateway
+{
+ /**
+ * Bit of state that is set when a Gateway is in the
+ * deallocated state. A deallocated gateway does not have the resources
+ * necessary for it to carry out its basic functions.
+ *
+ * In the DEALLOCATED state, many of the methods of a
+ * Gateway throw an exception when called. The
+ * DEALLOCATED state has no sub-states.
+ *
+ * A Gateway is always created in the DEALLOCATED
+ * state. A DEALLOCATED can transition to the
+ * ALLOCATED state via the ALLOCATING_RESOURCES
+ * state following a call to the allocate method. A
+ * Gateway returns to the DEALLOCATED state via
+ * the DEALLOCATING_RESOURCES state with a call to the
+ * deallocate method.
+ *
+ * @see allocate
+ * @see deallocate
+ * @see getGatewayState
+ * @see waitGatewayState
+ */
+ public static final long DEALLOCATED = 0x01;
+
+ /**
+ * Bit of state that is set when a Gateway is being
+ * allocated - the transition state between DEALLOCATED
+ * to ALLOCATED following a call to the
+ * allocate method. The ALLOCATING_RESOURCES
+ * state has no sub-states. In the ALLOCATING_RESOURCES
+ * state, many of the methods of Gateway,
+ * Transmitter, and Receiver will block
+ * unitl the Gateway reaches the ALLOCATED
+ * state and the action can be performed.
+ *
+ * @see getGatewayState
+ * @see waitGatewayState
+ */
+ public static final long ALLOCATING_RESOURCES = 0x02;
+
+ /**
+ * Bit of state that is set when a Gateway is in the
+ * allocated state. A gateway in the ALLOCATED state
+ * has acquired the resources required for it to carry out its core
+ * functions.
+ *
+ * A Gateway is always created in the
+ * DEALLOCATED state. It reaches the ALLOCATED
+ * state via the ALLOCATING_RESOURCES state with a call to
+ * the allocate method.
+ *
+ * @see Transmitter
+ * @see Receiver
+ * @see getGatewayState
+ * @see waitGatewayState
+ */
+ public static final long ALLOCATED = 0x04;
+
+ /**
+ * Bit of state that is set when a Gateway is being
+ * deallocated - the transition state between ALLOCATED
+ * to DEALLOCATED. The DEALLOCATING_RESOURCES
+ * state has no sub-states. In the DEALLOCATING_RESOURCE
+ * state, most methods of Gateway, Transmitter
+ * and Receiver throw an exception.
+ *
+ * @see getGatewayState
+ * @see waitGatewayState
+ */
+ public static final long DEALLOCATING_RESOURCES = 0x08;
+
+ /**
+ * Bit of state that is set when a Gateway is in the
+ * ALLOCATED state and is PAUSED. In the
+ * PAUSED state, event transmission or reception is stopped.
+ *
+ * An ALLOCATED gateway is always in either the
+ * PAUSED or RESUMED state. The
+ * PAUSED and RESUMED states are sub-states of
+ * the ALLOCATED state.
+ *
+ * @see RESUMED
+ * @see ALLOCATED
+ * @see getGatewayState
+ * @see waitGatewayState
+ */
+ public static final long PAUSED = 0x10;
+
+ /**
+ * Bit of state that is set when a Gateway is in the
+ * ALLOCATED state and is RESUMED. In the
+ * RESUMED state, event transmission or reception is active.
+ *
+ * An ALLOCATED gateway is always in either the
+ * PAUSED or RESUMED state. The
+ * PAUSED and RESUMED states are sub-states of
+ * the ALLOCATED state.
+ *
+ * @see RESUMED
+ * @see ALLOCATED
+ * @see getGatewayState
+ * @see waitGatewayState
+ */
+ public static final long RESUMED = 0x20;
+
+ /**
+ * Returns a OR'ed set of flags indicating the current state of a
+ * Gateway. The format of the returned state
+ * value is described above.
+ *
+ * A GatewayEvent is issued each time the Gateway
+ * changes state.
+ *
+ * The getGatewayState method can be called successfully
+ * in any Gateway state.
+ *
+ * @see getGatewayState
+ * @see waitGatewayState
+ * @see getNewGatewayState
+ * @see getOldGatewayState
+ */
+ public long getGatewayState();
+
+ /**
+ * Blocks the calling thread until the Gateway is in a
+ * specified state. The format of the state value is
+ * described above.
+ *
+ * All state bits specified in the state parameter must be
+ * set in order for the method to return, as defined for the
+ * testGatewayState method. If the state parameter
+ * defines an unreachable state (e.g. ALLOCATED | DEALLOCATED) an
+ * exception is thrown.
+ *
+ * The waitGatewayState method can be called successfully in
+ * any Gateway state.
+ *
+ * @exception InterruptedException if another thread has interrupted this
+ * thread
+ * @exception IllegalArgumentException if the specified state is
+ * unreachable
+ * @see testGatewayState
+ * @see getGatewayState
+ */
+ public void waitGatewayState(long state) throws InterruptedException,
+ IllegalArgumentException;
+
+ /**
+ * Returns true if the current gateway state matches the specified state.
+ * The format of the state value is described above.
+ *
+ * The test performed is not an exact match to the current state. Only
+ * the specified states are tested. For example the following returns
+ * true only is the Transmitter queue is empty, irrespective
+ * of the allocation states.
+ *
+ *
+ * if (trans.testGatewayState(Transmitter.QUEUE_EMPTY)) ...
+ *
+ *
+ * The testGatewayState method is equivalent to:
+ *
+ *
+ * if ((gateway.getGatewayState() & state) == state)
+ *
+ *
+ * The testGatewayState method can be called successfully
+ * in any Gateway state.
+ *
+ * @exception IllegalArgumentException - if the specified state is
+ * unreachable
+ */
+ public boolean testGatewayState(long state) throws IllegalArgumentException;
+
+ /**
+ * Alocate the resources required for the Gateway and put it
+ * into the ALLOCATED state. When this method returns
+ * successfully the ALLOCATED bit of the gateway state is
+ * set, and the testGatewayState(Gateway.ALLOCATED) method
+ * returns true. During the processing of the method, the
+ * Gateway is temporarily in the
+ * ALLOCATING_RESOURCES state.
+ *
+ * When the Gateway reaches the ALLOCATED state
+ * other engine states are determined:
+ *
+ * PAUSED or RESUMED: the pause state
+ * depends upon the existing state of the gateway. In a multi-app
+ * environment, the pause/resume state of the gateway is shared
+ * by all apps.
+ * - A
Transmitter always starts in the
+ * QUEUE_EMPTY state when newly allocated -
+ *
+ * While this method is being processed events are issued to any
+ * GatewayListeners attached to the Gateway
+ * to indicate state changes. First, as the Gateway changes
+ * from the DEALLOCATED to the
+ * ALLOCATING_RESOURCES state, a
+ * GATEWAY_ALLOCATING_RESOURCES event is issued. As the
+ * allocation process completes, the gateway moves from the
+ * ALLOCATING_RESOURCES state to the ALLOCATED
+ * state and an GATEWAY_ALLOCATED event is issued.
+ *
+ * The allocate method should be called for a
+ * Gateway in the DEALLOCATED state. The method
+ * has no effect for a Gateway in either the
+ * ALLOCATING_RESOURCES or ALLOCATED states.
+ * The method throws an exception in the
+ * DEALLOCATING_RESOURCES state.
+ *
+ * If any problems are encountered during the allocation process so that
+ * the gateway cannot be allocated, the gateway returns to the
+ * DEALLOCATED state (with a GATEWAY_DEALLOCATED
+ * event), and an GatewayException is thrown.
+ *
+ * Allocating the resources for a gateway may be fast (less than a second)
+ * or slow (several 10s of seconds) depending upon a range of factors.
+ * Since the allocate method does not return until allocation
+ * is completed applications may want to perform allocation in a background
+ * thread and proceed with other activities.
+ *
+ * @exception GatewayException if an allocation error occurred or the
+ * gateway is not operational.
+ * @exception GatewayStateError is called for an engine in the
+ * DEALLOCATING_RESOURCES state
+ * @see getGatewayState
+ * @see deallocate
+ * @see ALLOCATED
+ * @see GATEWAY_ALLOCATED
+ */
+ public void allocate() throws GatewayException, GatewayStateError;
+
+ /**
+ * Free the resources of the gateway that were acquired during allocation
+ * and during operation and return the gateway to the
+ * DEALLOCATED state. When this method returns the
+ * DEALLOCATED bit of gateway state is set so the
+ * testGatewayState(Gateway.DEALLOCATED) method returns
+ * true. During the processing of the method, the
+ * Gateway is temporarily in the
+ * DEALLOCATING_RESOURCES state.
+ *
+ * A deallocated gateway can be re-started with a subsequent call to
+ * allocate.
+ *
+ * Gateways need to clean up current activities before being deallocated.
+ * A Transmitter must be in the QUEUE_EMPTY
+ * state before being deallocated. If the queue is not empty, any objects
+ * on the transmit queue must be cancelled with appropriate events
+ * issued.
+ *
+ * While this method is being processed events are issued to any
+ * GatewayListeners attached to the Gateway
+ * to indicate state changes. First, as the Gateway changes
+ * from the ALLOCATED to the
+ * DEALLOCATING_RESOURCES state, a
+ * GATEWAY_DEALLOCATING_RESOURCES event is issued. As the
+ * deallocation process completes, the gateway moves from the
+ * DEALLOCATING_RESOURCES state to the
+ * DEALLOCATED state and an GATEWAY_DEALLOCATED
+ * event is issued.
+ *
+ * The deallocate method should only be called for a
+ * Gateway in the ALLOCATED state. The method
+ * has no effect for a Gateway in either the
+ * DEALLOCATING_RESOURCES or DEALLOCATED states.
+ * The method throws an exception in the ALLOCATING_RESOURCES
+ * state.
+ *
+ * Deallocating resources for a gateway is not always immediate. Since the
+ * deallocate method does not return until complete, applications may want
+ * to perform deallocation in a separate thread.
+ *
+ * @exception GatewayException if a deallocation error occurs.
+ * @exception GatewayStateError if called for a gateway in the
+ * ALLOCATING_RESOURCES state
+ * @see allocate
+ * @see GATEWAY_DEALLOCATED
+ * @see QUEUE_EMPTY
+ */
+ public void deallocate() throws GatewayException, GatewayStateError;
+
+ /**
+ * Pause the event transmission for the gateway and put the Gateway
+ * into the PAUSED state. Pausing a gateway pauses the
+ * underlying gateway for all applications that are connected to
+ * that gateway. Gateways are typically paused and resumed by request from
+ * a user.
+ *
+ * Applications may pause a gateway indefinately. When a gateway moves from
+ * the RESUMED state to the PAUSED state, an
+ * GATEWAY_PAUSED event is issued to each
+ * GatewayListener attached to the Gateway. The
+ * PAUSED bit of the gateway state is set to true
+ * when paused, and can be tested by the getGatewayState method
+ * and other gateway state methods.
+ *
+ * The PAUSED state is a sub-state of the
+ * ALLOCATED state. An ALLOCATED Gateway is always
+ * in either the PAUSED or the RESUMED state.
+ *
+ * It is not an exception to pause a Gateway that is already
+ * paused.
+ *
+ * The pause method oeprates as defined for gateways in the
+ * ALLOCATED state. When pause is called for a gateway in the
+ * ALLOCATING_RESOURCES state, the method blocks (waits)
+ * until the ALLOCATED state is reached and then operates
+ * normally. An error is thrown when pause is called for a gateway in
+ * either the DEALLOCATED or
+ * DEALLOCATING_RESOURCES states.
+ *
+ * The pause method does not always return immediately. Some
+ * application need to execute pause in a separate thread.
+ *
+ *
+ * @exception GatewayStateError if called for a gateway in the
+ * DEALLOCATED or
+ * DEALLOCATING_RESOURCES states
+ * @see resume
+ * @see getGatewayState
+ * @see GATEWAY_PAUSED
+ */
+ public void pause() throws GatewayStateError;
+
+ /**
+ * Put the Gateway in the RESUMED state to resume
+ * event transmission or reception for a paused gateway. Resuming a gateway resumes
+ * the underlying gateway for all applications that are connected
+ * to that gateway. Gateways are typically paused and resumed by request from
+ * a user.
+ *
+ * The specific pause/resume bejavior of tramistters and receivers
+ * is defined in the documentation for the pause method.
+ *
+ * When a gateway moves from the PAUSED state to the
+ * RESUMED state, a GATEWAY_RESUMED event
+ * is issued to each GatewayListener attached to the
+ * Gateway. The RESUMED bit of the gateway state
+ * is set to true when resumed, and can be tested by the
+ * getGatewayState method and other gateway state methods.
+ *
+ * The RESUMED state is a sub-state of the
+ * ALLOCATED state. An ALLOCATED Gateway is
+ * always in either the PAUSED or the RESUMED
+ * state.
+ *
+ * It is not an exception to resume a gateway that is already
+ * in the RESUMED state.
+ *
+ * The resume method operates as defined for gateways in the
+ * ALLOCATED state. When resume is called for a gateway in
+ * the ALLOCATING_RESOURCES state, the method blocks (waits)
+ * until the ALLOCATED state is reached and then operates
+ * normally. An error is thrown when resume is called for a gateway in
+ * either the DEALLOCATED or
+ * DEALLOCATING_RESOURCES state.
+ *
+ * The resume method does not always return immediately. Some
+ * applications need to execute resume in a separate thread.
+ *
+ * @exception GatewayStateError if called for a gateway in the
+ * DEALLOCATED or
+ * DEALLOCATING_RESOURCES states.
+ * @see pause
+ * @see getGatewayState
+ * @see GATEWAY_RESUMED
+ */
+ public void resume() throws GatewayStateError;
+
+ /**
+ * Request notifications of events related to the Gateway. An
+ * application can attache multiple listeners to a Gateway.
+ * A single listener can be attached to multiple gateways.
+ *
+ * The GatewayListener is extended for both transmission and
+ * reception. Typically, a ReceptionListener is attached
+ * to a Receiver and a TransmissionListener
+ * is attached to a Transmitter.
+ *
+ * A GatewayListener can be attached or removed in any state
+ * of a Gateway.
+ *
+ * @param listener the listener that will reveive GatewayEvents
+ * @see Receiver
+ * @see ReceptionListener
+ * @see Transmitter
+ * @see TransmissionListener
+ */
+ public void addGatewayListener(GatewayListener listener);
+
+ /**
+ * Remove a listener from this Gateway. A
+ * GatewayListener can be attached or removed in any state of
+ * a Gateway.
+ *
+ * @param listener the listener to be removed
+ */
+ public void removeGatewayListener(GatewayListener listener);
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/NullGatewayQueue.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/NullGatewayQueue.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/NullGatewayQueue.java (revision 2)
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2000 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10;
+
+/**
+ * The NullGatewayQueue implements a null queue. This means that the
+ * put method directly calls the dispatcher to dispatch
+ * the message. This type of handling is useful for embedded type of
+ * applications that do not require their event notification to be
+ * synchronized with other events.
+ */
+public class NullGatewayQueue extends GatewayQueue
+{
+ /**
+ * Create a new gateway queue for processing control messages.
+ *
+ * @param dispatcher ControlEventDispatcher that will dispatch the
+ * control event.
+ * @author Jesse Peterson (jesse@jpeterson.com)
+ */
+ public NullGatewayQueue(ControlEventDispatcher dispatcher)
+ {
+ super(dispatcher);
+ }
+
+ /**
+ * Put an event on the queue for subsequent processing by the dispatcher.
+ * This method directly calls dispatchControlEvent() on the dispatcher.
+ * Because it directly calls the dispatcher on the current thread,
+ * there is no decoupling or synchronization performed.
+ *
+ * @param event ControlEvent to be placed on the queue for subsequent
+ * processing.
+ * @author Jesse Peterson (jesse@jpeterson.com)
+ */
+ public void post(ControlEvent event)
+ {
+ dispatcher.dispatchControlEvent(event);
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/SerialGateway.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/SerialGateway.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/SerialGateway.java (revision 2)
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10;
+
+/**
+ * This class provides a base for gateway modules that are based on
+ * the serial port. This base class provides methods to set and get
+ * the serial port parameters.
+ */
+public abstract class SerialGateway extends GatewayImpl
+{
+ protected String portName;
+ protected int baudRate;
+ protected int dataBits;
+ protected int stopBits;
+ protected int parity;
+
+ /**
+ * Constructor only calls parent's constructor.
+ *
+ * @author Jesse Peterson
+ */
+ protected SerialGateway()
+ {
+ super();
+ }
+
+ /**
+ * Set the serial port to use. For Microsoft Windows, typical values
+ * are COM1, COM2, COM3, or COM4.
+ *
+ * @param portName the name of the serial port
+ *
+ * @author Jesse Peterson
+ */
+ public void setPortName(String portName)
+ {
+ this.portName = portName;
+ }
+
+ /**
+ * Get the serial port to use.
+ *
+ * @return Name of serial port to use.
+ *
+ * @author Jesse Peterson
+ */
+ public String getPortName()
+ {
+ return(portName);
+ }
+
+ /**
+ * Set the serial port communication rate.
+ *
+ * @param baudRate the serial port communication rate
+ *
+ * @author Jesse Peterson
+ */
+ public void setBaudRate(int baudRate)
+ {
+ this.baudRate = baudRate;
+ }
+
+ /**
+ * Get the serial port communication rate.
+ *
+ * @return Baud rate.
+ *
+ * @author Jesse Peterson
+ */
+ public int getBaudRate()
+ {
+ return(baudRate);
+ }
+
+ /**
+ * Set the number of serial port data bits to use.
+ *
+ * @param dataBits the number of data bits to use
+ *
+ * @author Jesse Peterson
+ */
+ public void setDataBits(int dataBits)
+ {
+ this.dataBits = dataBits;
+ }
+
+ /**
+ * Get the number of data bits to use.
+ *
+ * @return Number of data bits.
+ *
+ * @author Jesse Peterson
+ */
+ public int getDataBits()
+ {
+ return(dataBits);
+ }
+
+ /**
+ * Set the serial port stop bits.
+ *
+ * @param stopBits the serial port stop bits.
+ *
+ * @author Jesse Peterson
+ */
+ public void setStopBits(int stopBits)
+ {
+ this.stopBits = stopBits;
+ }
+
+ /**
+ * Get the serial port stop bits.
+ *
+ * @return The serial port stop bits.
+ *
+ * @author Jesse Peterson
+ */
+ public int getStopBits()
+ {
+ return(stopBits);
+ }
+
+ /**
+ * Set the serial port parity.
+ *
+ * @param parity the serial port parity.
+ *
+ * @author Jesse Peterson
+ */
+ public void setParity(int parity)
+ {
+ this.parity = parity;
+ }
+
+ /**
+ * Get the serial port parity.
+ *
+ * @return The serial port parity.
+ *
+ * @author Jesse Peterson
+ */
+ public int getParity()
+ {
+ return(parity);
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/ExtendedDataTransferEvent.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/ExtendedDataTransferEvent.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/ExtendedDataTransferEvent.java (revision 2)
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10.event;
+
+import com.jpeterson.x10.X10Util;
+
+/**
+ * Extended data transfer for addressed units on the same house code.
+ *
+ * @version 1.0
+ * @author Jesse Peterson
+ */
+public class ExtendedDataTransferEvent extends FunctionEvent
+{
+ /**
+ * Create a new 'Extended Data Transfer' event.
+ *
+ * @param source The event source.
+ * @param houseCode the house code of the event. Valid codes are 'A'
+ * through 'P', uppercase.
+ *
+ * @author Jesse Peterson
+ */
+ public ExtendedDataTransferEvent(Object source, char houseCode)
+ {
+ super(source, 0, houseCode, X10Util.X10_FUNCTION_EXTENDED_DATA_TRANSFER, 22);
+ }
+
+ /**
+ * Create a string that represents the X10 event.
+ *
+ * @return string representation of the X10 event
+ *
+ * @author Jesse Peterson
+ */
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append("X10 Extended Data Transfer Event: house code<");
+ buffer.append(getHouseCode());
+ buffer.append("> function code<");
+ buffer.append(getFunction());
+ buffer.append(">");
+
+ return(buffer.toString());
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/X10Event.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/X10Event.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/X10Event.java (revision 2)
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10.event;
+
+import java.util.EventObject;
+import com.jpeterson.util.HexFormat;
+
+/**
+ * An X10 event represents an X10 transmission packet. This is the base
+ * class for subclasses that implement the different X10 messages.
+ *
+ * @version 1.0
+ * @author Jesse Peterson
+ */
+public class X10Event extends EventObject
+{
+ /**
+ * Number of dims.
+ */
+ private int dims;
+
+ /**
+ * Maximum number of dims.
+ */
+ private int dimMax;
+
+ /**
+ * True if the event is a function event.
+ */
+ private boolean function;
+
+ /**
+ * True if the event is an extended event.
+ */
+ private boolean extended;
+
+ /**
+ * High nibble of the Code portion of the X10 event.
+ */
+ private byte hiNibble;
+
+ /**
+ * Low nibble of the Code portion of the X10 event.
+ */
+ private byte loNibble;
+
+ /**
+ * Create an X10 event, specifying all parameters.
+ *
+ * @param source The event source.
+ * @param dims The number of dims.
+ * @param funtion True if the event is a function event, false
+ * if the event is an address event.
+ * @param extended True if the event is an extended event, false
+ * otherwise
+ * @param hiNibble The upper four bits of the 'Code' portion of the
+ * X10 event. This is usually the housecode
+ * @param loNibble The lower four bits of the 'Code' portion of the
+ * X10 event. This is typically the device code in an address
+ * event or the function code in a function event.
+ * @param dimMax The maximum number of dims for the event.
+ *
+ * @author Jesse Peterson
+ */
+ public X10Event(Object source, int dims, boolean function,
+ boolean extended, byte hiNibble, byte loNibble,
+ int dimMax)
+ {
+ // call the parent class constructor
+ super(source);
+
+ this.dims = dims;
+ this.dimMax = dimMax;
+ this.function = function;
+ this.extended = extended;
+ this.hiNibble = hiNibble;
+ this.loNibble = loNibble;
+ }
+
+ /**
+ * Create an X10 event. This constructor is normally used for
+ * standard address and function events that do not have dim values
+ * or extended characteristics. It is provided for convenience.
+ * The maximum number of dims is 22.
+ *
+ * @param source The event source.
+ * @param funtion True if the event is a function event, false
+ * if the event is an address event.
+ * @param hiNibble The upper four bits of the 'Code' portion of the
+ * X10 event. This is usually the housecode
+ * @param loNibble The lower four bits of the 'Code' portion of the
+ * X10 event. This is typically the device code in an address
+ * event or the function code in a function event.
+ *
+ * @author Jesse Peterson
+ */
+ public X10Event(Object source, boolean function, byte hiNibble,
+ byte loNibble)
+ {
+ this(source, 0, function, false, hiNibble, loNibble, 22);
+ }
+
+ /**
+ * Retrieve the bytes that compose the X10 event.
+ *
+ * @return Array of bytes that constitute the payload of the X10 event.
+ * For standard events, the array will have a size of 2. For
+ * extended events, the size will be 4.
+ *
+ * @author Jesse Peterson
+ */
+ public byte[] getPacket()
+ {
+ byte[] packet = new byte[2];
+
+ // header
+ packet[0] = (byte)(dims << 3);
+ packet[0] |= 0x04;
+ if (function)
+ {
+ packet[0] |= 0x02;
+ }
+ if (extended)
+ {
+ packet[0] |= 0x01;
+ }
+
+ // code
+ packet[1] = (byte)((hiNibble << 4) | loNibble);
+
+ return(packet);
+ }
+
+ /**
+ * Retrieve the checksum of the bytes in the message or the X10
+ * transmission.
+ *
+ * @return the checksum
+ *
+ * @author Jesse Peterson
+ */
+ public byte getChecksum()
+ {
+ int sum = 0;
+ byte[] packet = getPacket();
+
+ for (int i = 0; i < packet.length; i++)
+ {
+ sum += packet[i];
+ }
+ return((byte)sum);
+ }
+
+ /**
+ * Determine if the event is a function or address event.
+ *
+ * @return True if a function event, false if an address event.
+ *
+ * @author Jesse Peterson
+ */
+ public boolean isFunction()
+ {
+ return(function);
+ }
+
+ /**
+ * Determine if the event is an extended event.
+ *
+ * @return True if an extended event, false otherwise.
+ *
+ * @author Jesse Peterson
+ */
+ public boolean isExtended()
+ {
+ return(extended);
+ }
+
+ /**
+ * Retrieve the number of dims in the event.
+ *
+ * @return number of dims
+ *
+ * @author Jesse Peterson
+ */
+ public int getDims()
+ {
+ return(dims);
+ }
+
+ /**
+ * Retrieve the maximum number of dims in the event.
+ *
+ * @return maximum number of dims
+ *
+ * @author Jesse Peterson
+ */
+ public int getDimMax()
+ {
+ return(dimMax);
+ }
+
+ /**
+ * Retrieve the high nibble of the 'code' portion of the packet.
+ * This is the 'housecode'.
+ *
+ * @return the high nibble of the 'code' portion of the packet.
+ *
+ * @author Jesse Peterson
+ */
+ public byte getHiNibble()
+ {
+ return(hiNibble);
+ }
+
+ /**
+ * Retrieve the low nibble of the 'code' portion of the packet.
+ * This is the 'device code' for address messages or the 'function'
+ * for function messages.
+ *
+ * @return the low nibble of the 'code' portion of the packet.
+ *
+ * @author Jesse Peterson
+ */
+ public byte getLoNibble()
+ {
+ return(loNibble);
+ }
+
+ /**
+ * Calculate a hash code for the event. Uses the checksum.
+ *
+ * @return Hash code value for the event.
+ *
+ * @author Jesse Peterson
+ */
+ public int hashCode()
+ {
+ return((int)getChecksum());
+ }
+
+ /**
+ * Determines if two objects are equals. This tests all X10Event attributes
+ * of the objects for equallity.
+ *
+ * @return True if the target object equals this object, false otherwise.
+ *
+ * @author Jesse Peterson
+ */
+ public boolean equals(Object object)
+ {
+ X10Event target;
+ Object thisSource, targetSource;
+
+ if ((object == null) ||
+ (!(object instanceof X10Event)))
+ {
+ return(false);
+ }
+
+ target = (X10Event)object;
+
+ thisSource = getSource();
+ targetSource = target.getSource();
+
+ if (thisSource == null)
+ {
+ if (targetSource != null)
+ {
+ return(false);
+ }
+ }
+ else
+ {
+ if (!(thisSource.equals(targetSource)))
+ {
+ return(false);
+ }
+ }
+
+ if ((dims == target.getDims()) &&
+ (function == target.isFunction()) &&
+ (extended == target.isExtended()) &&
+ (hiNibble == target.getHiNibble()) &&
+ (loNibble == target.getLoNibble()) &&
+ (dimMax == target.getDimMax()))
+ {
+ return(true);
+ }
+
+ return(false);
+ }
+
+ /**
+ * Create a string that represents the X10 event.
+ *
+ * @return string representation of the X10 event
+ *
+ * @author Jesse Peterson
+ */
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+ HexFormat hexFormat = new HexFormat();
+
+ buffer.append("X10 Event: dims <");
+ buffer.append(dims);
+ buffer.append("> dimMax<");
+ buffer.append(dimMax);
+ buffer.append("> function<");
+ buffer.append(function);
+ buffer.append("> extended<");
+ buffer.append(extended);
+ buffer.append("> high nibble<0x");
+ buffer.append(hexFormat.format(hiNibble));
+ buffer.append("> low nibble<0x");
+ buffer.append(hexFormat.format(loNibble));
+ buffer.append(">");
+
+ return(buffer.toString());
+ }
+}
+
+
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/DimEvent.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/DimEvent.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/DimEvent.java (revision 2)
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10.event;
+
+import com.jpeterson.x10.X10Util;
+
+/**
+ * Dim the previously addressed units on the same house code by the
+ * specified amount.
+ *
+ * @version 1.0
+ * @author Jesse Peterson
+ */
+public class DimEvent extends FunctionEvent
+{
+ /**
+ * Create a new 'Dim' event.
+ *
+ * @param source The event source.
+ * @param houseCode the house code of the event. Valid codes are 'A'
+ * through 'P', uppercase.
+ * @param dims The number of dims.
+ * @param dimMax The maximum number of dims for the event.
+ *
+ * @author Jesse Peterson
+ */
+ public DimEvent(Object source, char houseCode, int dims, int dimMax)
+ {
+ super(source, dims, houseCode, X10Util.X10_FUNCTION_DIM, dimMax);
+ }
+
+ /**
+ * Create a string that represents the X10 event.
+ *
+ * @return string representation of the X10 event
+ *
+ * @author Jesse Peterson
+ */
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append("X10 Dim Event: house code<");
+ buffer.append(getHouseCode());
+ buffer.append("> function code<");
+ buffer.append(getFunction());
+ buffer.append("> dims<");
+ buffer.append(getDims());
+ buffer.append("> dimMax<");
+ buffer.append(getDimMax());
+ buffer.append(">");
+
+ return(buffer.toString());
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/OffEvent.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/OffEvent.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/OffEvent.java (revision 2)
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10.event;
+
+import com.jpeterson.x10.X10Util;
+
+/**
+ * Turn the previously addressed units on the same house code off.
+ *
+ * @version 1.0
+ * @author Jesse Peterson
+ */
+public class OffEvent extends FunctionEvent
+{
+ /**
+ * Create a new 'Off' event.
+ *
+ * @param source The event source.
+ * @param houseCode the house code of the event. Valid codes are 'A'
+ * through 'P', uppercase.
+ *
+ * @author Jesse Peterson
+ */
+ public OffEvent(Object source, char houseCode)
+ {
+ super(source, 0, houseCode, X10Util.X10_FUNCTION_OFF, 22);
+ }
+
+ /**
+ * Create a string that represents the X10 event.
+ *
+ * @return string representation of the X10 event
+ *
+ * @author Jesse Peterson
+ */
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append("X10 Off Event: house code<");
+ buffer.append(getHouseCode());
+ buffer.append("> function code<");
+ buffer.append(getFunction());
+ buffer.append(">");
+
+ return(buffer.toString());
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/OnEvent.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/OnEvent.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/OnEvent.java (revision 2)
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10.event;
+
+import com.jpeterson.x10.X10Util;
+
+/**
+ * Turn the previously addressed units on the same house code on.
+ *
+ * @version 1.0
+ * @author Jesse Peterson
+ */
+public class OnEvent extends FunctionEvent
+{
+ /**
+ * Create a new 'On' event.
+ *
+ * @param source The event source.
+ * @param houseCode the house code of the event. Valid codes are 'A'
+ * through 'P', uppercase.
+ *
+ * @author Jesse Peterson
+ */
+ public OnEvent(Object source, char houseCode)
+ {
+ super(source, 0, houseCode, X10Util.X10_FUNCTION_ON, 22);
+ }
+
+ /**
+ * Create a string that represents the X10 event.
+ *
+ * @return string representation of the X10 event
+ *
+ * @author Jesse Peterson
+ */
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append("X10 On Event: house code<");
+ buffer.append(getHouseCode());
+ buffer.append("> function code<");
+ buffer.append(getFunction());
+ buffer.append(">");
+
+ return(buffer.toString());
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/PresetDim1Event.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/PresetDim1Event.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/PresetDim1Event.java (revision 2)
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10.event;
+
+import com.jpeterson.x10.X10Util;
+
+/**
+ * Preset Dim 1 for addressed units on the same house code on.
+ *
+ * @version 1.0
+ * @author Jesse Peterson
+ */
+public class PresetDim1Event extends FunctionEvent
+{
+ /**
+ * Create a new 'Preset Dim(1)' event.
+ *
+ * @param source The event source.
+ * @param houseCode the house code of the event. Valid codes are 'A'
+ * through 'P', uppercase.
+ *
+ * @author Jesse Peterson
+ */
+ public PresetDim1Event(Object source, char houseCode)
+ {
+ super(source, 0, houseCode, X10Util.X10_FUNCTION_PRESET_DIM_1, 22);
+ }
+
+ /**
+ * Create a string that represents the X10 event.
+ *
+ * @return string representation of the X10 event
+ *
+ * @author Jesse Peterson
+ */
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append("X10 Preset Dim(1) Event: house code<");
+ buffer.append(getHouseCode());
+ buffer.append("> function code<");
+ buffer.append(getFunction());
+ buffer.append(">");
+
+ return(buffer.toString());
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/AllLightsOffEvent.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/AllLightsOffEvent.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/AllLightsOffEvent.java (revision 2)
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10.event;
+
+import com.jpeterson.x10.X10Util;
+
+/**
+ * All lights on the particular house code are turned off.
+ *
+ * @version 1.0
+ * @author Jesse Peterson
+ */
+public class AllLightsOffEvent extends FunctionEvent
+{
+ /**
+ * Create a new 'All Lights Off' event.
+ *
+ * @param source The event source.
+ * @param houseCode the house code of the event. Valid codes are 'A'
+ * through 'P', uppercase.
+ *
+ * @author Jesse Peterson
+ */
+ public AllLightsOffEvent(Object source, char houseCode)
+ {
+ super(source, 0, houseCode, X10Util.X10_FUNCTION_ALL_LIGHTS_OFF, 22);
+ }
+
+ /**
+ * Create a string that represents the X10 event.
+ *
+ * @return string representation of the X10 event
+ *
+ * @author Jesse Peterson
+ */
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append("X10 All Lights Off Event: house code<");
+ buffer.append(getHouseCode());
+ buffer.append("> function code<");
+ buffer.append(getFunction());
+ buffer.append(">");
+
+ return(buffer.toString());
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/PresetDim2Event.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/PresetDim2Event.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/PresetDim2Event.java (revision 2)
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10.event;
+
+import com.jpeterson.x10.X10Util;
+
+/**
+ * Preset Dim 2 for addressed units on the same house code on.
+ *
+ * @version 1.0
+ * @author Jesse Peterson
+ */
+public class PresetDim2Event extends FunctionEvent
+{
+ /**
+ * Create a new 'Preset Dim(2)' event.
+ *
+ * @param source The event source.
+ * @param houseCode the house code of the event. Valid codes are 'A'
+ * through 'P', uppercase.
+ *
+ * @author Jesse Peterson
+ */
+ public PresetDim2Event(Object source, char houseCode)
+ {
+ super(source, 0, houseCode, X10Util.X10_FUNCTION_PRESET_DIM_2, 22);
+ }
+
+ /**
+ * Create a string that represents the X10 event.
+ *
+ * @return string representation of the X10 event
+ *
+ * @author Jesse Peterson
+ */
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append("X10 Preset Dim(2) Event: house code<");
+ buffer.append(getHouseCode());
+ buffer.append("> function code<");
+ buffer.append(getFunction());
+ buffer.append(">");
+
+ return(buffer.toString());
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/StatusOffEvent.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/StatusOffEvent.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/StatusOffEvent.java (revision 2)
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10.event;
+
+import com.jpeterson.x10.X10Util;
+
+/**
+ * Status off for addressed units on the same house code.
+ *
+ * @version 1.0
+ * @author Jesse Peterson
+ */
+public class StatusOffEvent extends FunctionEvent
+{
+ /**
+ * Create a new 'Status Off' event.
+ *
+ * @param source The event source.
+ * @param houseCode the house code of the event. Valid codes are 'A'
+ * through 'P', uppercase.
+ *
+ * @author Jesse Peterson
+ */
+ public StatusOffEvent(Object source, char houseCode)
+ {
+ super(source, 0, houseCode, X10Util.X10_FUNCTION_STATUS_OFF, 22);
+ }
+
+ /**
+ * Create a string that represents the X10 event.
+ *
+ * @return string representation of the X10 event
+ *
+ * @author Jesse Peterson
+ */
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append("X10 Status Off Event: house code<");
+ buffer.append(getHouseCode());
+ buffer.append("> function code<");
+ buffer.append(getFunction());
+ buffer.append(">");
+
+ return(buffer.toString());
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/X10EventListener.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/X10EventListener.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/X10EventListener.java (revision 2)
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10.event;
+
+import java.util.EventListener;
+
+
+/**
+ * @author Jesse Peterson
+ */
+public interface X10EventListener extends EventListener
+{
+ /**
+ * @author Jesse Peterson
+ */
+ public void x10Event(AddressEvent e, FunctionEvent ee);
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/BrightEvent.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/BrightEvent.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/BrightEvent.java (revision 2)
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10.event;
+
+import com.jpeterson.x10.X10Util;
+
+/**
+ * Brighten the previously addressed units on the same house code by the
+ * specified amount.
+ *
+ * @version 1.0
+ * @author Jesse Peterson
+ */
+public class BrightEvent extends FunctionEvent
+{
+ /**
+ * Create a new 'Bright' event.
+ *
+ * @param source The event source.
+ * @param houseCode the house code of the event. Valid codes are 'A'
+ * through 'P', uppercase.
+ * @param dims The number of dims.
+ * @param dimMax The maximum number of dims for the event.
+ *
+ * @author Jesse Peterson
+ */
+ public BrightEvent(Object source, char houseCode, int dims, int dimMax)
+ {
+ super(source, dims, houseCode, X10Util.X10_FUNCTION_BRIGHT, dimMax);
+ }
+
+ /**
+ * Create a string that represents the X10 event.
+ *
+ * @return string representation of the X10 event
+ *
+ * @author Jesse Peterson
+ */
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append("X10 Bright Event: house code<");
+ buffer.append(getHouseCode());
+ buffer.append("> function code<");
+ buffer.append(getFunction());
+ buffer.append("> dims<");
+ buffer.append(getDims());
+ buffer.append("> dimMax<");
+ buffer.append(getDimMax());
+ buffer.append(">");
+
+ return(buffer.toString());
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/AllLightsOnEvent.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/AllLightsOnEvent.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/AllLightsOnEvent.java (revision 2)
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10.event;
+
+import com.jpeterson.x10.X10Util;
+
+/**
+ * All lights on the particular house code are turned on.
+ *
+ * @version 1.0
+ * @author Jesse Peterson
+ */
+public class AllLightsOnEvent extends FunctionEvent
+{
+ /**
+ * Create a new 'All Lights On' event.
+ *
+ * @param source The event source.
+ * @param houseCode the house code of the event. Valid codes are 'A'
+ * through 'P', uppercase.
+ *
+ * @author Jesse Peterson
+ */
+ public AllLightsOnEvent(Object source, char houseCode)
+ {
+ super(source, 0, houseCode, X10Util.X10_FUNCTION_ALL_LIGHTS_ON, 22);
+ }
+
+ /**
+ * Create a string that represents the X10 event.
+ *
+ * @return string representation of the X10 event
+ *
+ * @author Jesse Peterson
+ */
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append("X10 All Lights On Event: house code<");
+ buffer.append(getHouseCode());
+ buffer.append("> function code<");
+ buffer.append(getFunction());
+ buffer.append(">");
+
+ return(buffer.toString());
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/StatusOnEvent.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/StatusOnEvent.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/StatusOnEvent.java (revision 2)
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10.event;
+
+import com.jpeterson.x10.X10Util;
+
+/**
+ * Status on for addressed units on the same house code.
+ *
+ * @version 1.0
+ * @author Jesse Peterson
+ */
+public class StatusOnEvent extends FunctionEvent
+{
+ /**
+ * Create a new 'Status On' event.
+ *
+ * @param source The event source.
+ * @param houseCode the house code of the event. Valid codes are 'A'
+ * through 'P', uppercase.
+ *
+ * @author Jesse Peterson
+ */
+ public StatusOnEvent(Object source, char houseCode)
+ {
+ super(source, 0, houseCode, X10Util.X10_FUNCTION_STATUS_ON, 22);
+ }
+
+ /**
+ * Create a string that represents the X10 event.
+ *
+ * @return string representation of the X10 event
+ *
+ * @author Jesse Peterson
+ */
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append("X10 Status On Event: house code<");
+ buffer.append(getHouseCode());
+ buffer.append("> function code<");
+ buffer.append(getFunction());
+ buffer.append(">");
+
+ return(buffer.toString());
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/HailAcknowledgeEvent.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/HailAcknowledgeEvent.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/HailAcknowledgeEvent.java (revision 2)
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10.event;
+
+import com.jpeterson.x10.X10Util;
+
+/**
+ * Hail response for addressed units on the same house code on.
+ *
+ * @version 1.0
+ * @author Jesse Peterson
+ */
+public class HailAcknowledgeEvent extends FunctionEvent
+{
+ /**
+ * Create a new 'Hail Acknowledge' event.
+ *
+ * @param source The event source.
+ * @param houseCode the house code of the event. Valid codes are 'A'
+ * through 'P', uppercase.
+ *
+ * @author Jesse Peterson
+ */
+ public HailAcknowledgeEvent(Object source, char houseCode)
+ {
+ super(source, 0, houseCode, X10Util.X10_FUNCTION_HAIL_ACKNOWLEDGE, 22);
+ }
+
+ /**
+ * Create a string that represents the X10 event.
+ *
+ * @return string representation of the X10 event
+ *
+ * @author Jesse Peterson
+ */
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append("X10 Hail Acknowledge Event: house code<");
+ buffer.append(getHouseCode());
+ buffer.append("> function code<");
+ buffer.append(getFunction());
+ buffer.append(">");
+
+ return(buffer.toString());
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/Producer.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/Producer.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/Producer.java (revision 2)
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10.event;
+
+/**
+ * Producers fire events to AddressListeners and FunctionListeners. An
+ * example of a producer may be a software widget that represents a light
+ * switch. When the switch is turned on, the registered AddressListeners
+ * and FunctionListeners will be notified. For actual transmission of an
+ * X10Event through a gateway, it may be desirable to use the Transmitter
+ * interface.
+ *
+ * @author Jesse Peterson
+ */
+public interface Producer
+{
+ /**
+ * Add an AddressListener. This Producer will send all registered
+ * AddressListeners AddressEvents as they are produced by the Producer.
+ *
+ * @param listener Listener to add.
+ * @author Jesse Peterson
+ */
+ public void addAddressListener(AddressListener listener);
+
+ /**
+ * Remove the first instance of the specified listener from the register
+ * list of AddressListeners.
+ *
+ * @param listener Listner to remove.
+ * @author Jesse Peterson
+ */
+ public void removeAddressListener(AddressListener listener);
+
+ /**
+ * Add a FunctionListener. This Producer will send all registered
+ * FunctionListeners FunctionEvents as they are produced by the Producer.
+ *
+ * @param listener Listener to add.
+ * @author Jesse Peterson
+ */
+ public void addFunctionListener(FunctionListener listener);
+
+ /**
+ * Remove the first instance of the specified listener from the register
+ * list of FunctionListeners.
+ *
+ * @param listener Listner to remove.
+ * @author Jesse Peterson
+ */
+ public void removeFunctionListener(FunctionListener listener);
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/FunctionAdapter.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/FunctionAdapter.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/FunctionAdapter.java (revision 2)
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10.event;
+
+/**
+ * Trivial implementation of the FunctionListener interface that
+ * receives a FunctionEvent. The methods in this class are empty,
+ * this class is provided as a convenience for easily creating listeners by
+ * extending this class and overriding only the methods of interest.
+ *
+ * @see FunctionEvent
+ *
+ * @author Jesse Peterson <6/29/99>
+ * @version 1.0
+ */
+public class FunctionAdapter extends Object implements FunctionListener
+{
+ /**
+ * Constructor does nothing.
+ *
+ * @author Jesse Peterson
+ */
+ public FunctionAdapter()
+ {
+ // empty
+ }
+
+ /**
+ * "All Units Off" command.
+ *
+ * @see FUNCTION_ALL_UNITS_OFF
+ *
+ * @author Jesse Peterson
+ */
+ public void functionAllUnitsOff(FunctionEvent e)
+ {
+ // empty
+ }
+
+ /**
+ * "All Lights On" command.
+ *
+ * @see FUNCTION_ALL_LIGHTS_ON
+ *
+ * @author Jesse Peterson
+ */
+ public void functionAllLightsOn(FunctionEvent e)
+ {
+ // empty
+ }
+
+ /**
+ * "On" command.
+ *
+ * @see FUNCTION_ON
+ *
+ * @author Jesse Peterson
+ */
+ public void functionOn(FunctionEvent e)
+ {
+ // empty
+ }
+
+ /**
+ * "Off" command.
+ *
+ * @see FUNCTION_OFF
+ *
+ * @author Jesse Peterson
+ */
+ public void functionOff(FunctionEvent e)
+ {
+ // empty
+ }
+
+ /**
+ * "Dim" command.
+ *
+ * @see FUNCTION_DIM
+ *
+ * @author Jesse Peterson
+ */
+ public void functionDim(FunctionEvent e)
+ {
+ // empty
+ }
+
+ /**
+ * "Bright" command.
+ *
+ * @see FUNCTION_BRIGHT
+ *
+ * @author Jesse Peterson
+ */
+ public void functionBright(FunctionEvent e)
+ {
+ // empty
+ }
+
+ /**
+ * "All Lights Off" command.
+ *
+ * @see FUNCTION_ALL_LIGHTS_OFF
+ *
+ * @author Jesse Peterson
+ */
+ public void functionAllLightsOff(FunctionEvent e)
+ {
+ // empty
+ }
+
+ /**
+ * "HailRequest" command.
+ *
+ * @see FUNCTION_HAIL_REQUEST
+ *
+ * @author Jesse Peterson
+ */
+ public void functionHailRequest(FunctionEvent e)
+ {
+ // empty
+ }
+
+ /**
+ * "Hail Acknowledge" command.
+ *
+ * @see FUNCTION_HAIL_ACKNOWLEDGE
+ *
+ * @author Jesse Peterson
+ */
+ public void functionHailAcknowledge(FunctionEvent e)
+ {
+ // empty
+ }
+
+ /**
+ * "Preset Dim 1" command.
+ *
+ * @see FUNCTION_PRESET_DIM_1
+ *
+ * @author Jesse Peterson
+ */
+ public void functionPresetDim1(FunctionEvent e)
+ {
+ // empty
+ }
+
+ /**
+ * "Preset Dim 2" command.
+ *
+ * @see FUNCTION_PRESET_DIM_2
+ *
+ * @author Jesse Peterson
+ */
+ public void functionPresetDim2(FunctionEvent e)
+ {
+ // empty
+ }
+
+ /**
+ * "Status On" command.
+ *
+ * @see FUNCTION_STATUS_ON
+ *
+ * @author Jesse Peterson
+ */
+ public void functionStatusOn(FunctionEvent e)
+ {
+ // empty
+ }
+
+ /**
+ * "Status Off" command.
+ *
+ * @see FUNCTION_STATUS_OFF
+ *
+ * @author Jesse Peterson
+ */
+ public void functionStatusOff(FunctionEvent e)
+ {
+ // empty
+ }
+
+ /**
+ * "Status Request" command.
+ *
+ * @see FUNCTION_STATUS_REQUEST
+ *
+ * @author Jesse Peterson
+ */
+ public void functionStatusRequest(FunctionEvent e)
+ {
+ // empty
+ }
+}
+
+
+
+
+
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/FunctionEvent.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/FunctionEvent.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/FunctionEvent.java (revision 2)
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10.event;
+
+import com.jpeterson.x10.X10Util;
+
+/**
+ * Function events indicate some action to take upon the previously addressed
+ * devices that match this functions house code.
+ *
+ * @version 1.0
+ * @author Jesse Peterson
+ */
+public class FunctionEvent extends X10Event
+{
+ /**
+ * Create a new function event.
+ *
+ * @param source The event source.
+ * @param dims The number of dims.
+ * @param houseCode the house code of the event. Valid codes are 'A'
+ * through 'P', uppercase.
+ * @param functionCode the function code of the event.
+ * @param dimMax The maximum number of dims for the event.
+ *
+ * @author Jesse Peterson
+ */
+ public FunctionEvent(Object source, int dims, boolean extended,
+ char houseCode, byte functionCode, int dimMax)
+ {
+ super(source, dims, true, extended, X10Util.houseCode2byte(houseCode),
+ functionCode, dimMax);
+ }
+
+ /**
+ * Create a new function event.
+ *
+ * @param source The event source.
+ * @param dims The number of dims.
+ * @param houseCode the house code of the event. Valid codes are 'A'
+ * through 'P', uppercase.
+ * @param functionCode the fucntion code of the event.
+ * @param dimMax The maximum number of dims for the event.
+ *
+ * @author Jesse Peterson
+ */
+ public FunctionEvent(Object source, int dims, char houseCode,
+ byte functionCode, int dimMax)
+ {
+ this(source, dims, false, houseCode, functionCode, dimMax);
+ }
+
+ /**
+ * Retrieve the house code.
+ *
+ * @return house code character 'A' through 'P', uppercase.
+ *
+ * @author Jesse Peterson
+ */
+ public char getHouseCode()
+ {
+ return(X10Util.byte2houseCode(getHiNibble()));
+ }
+
+ /**
+ * Retrieve the function.
+ *
+ * @return function byte
+ *
+ * @author Jesse Peterson
+ */
+ public byte getFunction()
+ {
+ return(getLoNibble());
+ }
+
+ /**
+ * Create a string that represents the X10 event.
+ *
+ * @return string representation of the X10 event
+ *
+ * @author Jesse Peterson
+ */
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append("X10 Address Event: house code<");
+ buffer.append(getHouseCode());
+ buffer.append("> function code<");
+ buffer.append(getFunction());
+ buffer.append("> dims <");
+ buffer.append(getDims());
+ buffer.append("> dimMax<");
+ buffer.append(getDimMax());
+ buffer.append(">");
+
+ return(buffer.toString());
+ }
+}
+
+
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/AddressEvent.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/AddressEvent.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/AddressEvent.java (revision 2)
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10.event;
+
+import com.jpeterson.x10.X10Util;
+
+/**
+ * Address events indicate the target for a function.
+ *
+ * @version 1.0
+ * @author Jesse Peterson
+ */
+public class AddressEvent extends X10Event
+{
+ /**
+ * Create a new address event.
+ *
+ * @param source The event source.
+ * @param houseCode the house code of the event. Valid codes are 'A'
+ * through 'P', uppercase.
+ * @param deviceCode the device code of the event. Valid codes are
+ * 1 through 16.
+ *
+ * @author Jesse Peterson
+ */
+ public AddressEvent(Object source, char houseCode, int deviceCode)
+ {
+ super(source, false, X10Util.houseCode2byte(houseCode),
+ X10Util.deviceCode2byte(deviceCode));
+ }
+
+ /**
+ * Retrieve the house code.
+ *
+ * @return house code character 'A' through 'P', uppercase.
+ *
+ * @author Jesse Peterson
+ */
+ public char getHouseCode()
+ {
+ return(X10Util.byte2houseCode(getHiNibble()));
+ }
+
+ /**
+ * Retrieve the device code.
+ *
+ * @return device code value 1 through 16.
+ *
+ * @author Jesse Peterson
+ */
+ public int getDeviceCode()
+ {
+ return(X10Util.byte2deviceCode(getLoNibble()));
+ }
+
+ /**
+ * Create a string that represents the X10 event.
+ *
+ * @return string representation of the X10 event
+ *
+ * @author Jesse Peterson
+ */
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append("X10 Address Event: house code<");
+ buffer.append(getHouseCode());
+ buffer.append("> device code<");
+ buffer.append(getDeviceCode());
+ buffer.append(">");
+
+ return(buffer.toString());
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/HailRequestEvent.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/HailRequestEvent.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/HailRequestEvent.java (revision 2)
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10.event;
+
+import com.jpeterson.x10.X10Util;
+
+/**
+ * Hail the addressed units on the same house code on.
+ *
+ * @version 1.0
+ * @author Jesse Peterson
+ */
+public class HailRequestEvent extends FunctionEvent
+{
+ /**
+ * Create a new 'Hail Request' event.
+ *
+ * @param source The event source.
+ * @param houseCode the house code of the event. Valid codes are 'A'
+ * through 'P', uppercase.
+ *
+ * @author Jesse Peterson
+ */
+ public HailRequestEvent(Object source, char houseCode)
+ {
+ super(source, 0, houseCode, X10Util.X10_FUNCTION_HAIL_REQUEST, 22);
+ }
+
+ /**
+ * Create a string that represents the X10 event.
+ *
+ * @return string representation of the X10 event
+ *
+ * @author Jesse Peterson
+ */
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append("X10 Hail Request Event: house code<");
+ buffer.append(getHouseCode());
+ buffer.append("> function code<");
+ buffer.append(getFunction());
+ buffer.append(">");
+
+ return(buffer.toString());
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/AllUnitsOffEvent.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/AllUnitsOffEvent.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/AllUnitsOffEvent.java (revision 2)
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10.event;
+
+import com.jpeterson.x10.X10Util;
+
+/**
+ * All units on the particular house code are turned off
+ *
+ * @version 1.0
+ * @author Jesse Peterson
+ */
+public class AllUnitsOffEvent extends FunctionEvent
+{
+ /**
+ * Create a new 'All Units Off' event.
+ *
+ * @param source The event source.
+ * @param houseCode the house code of the event. Valid codes are 'A'
+ * through 'P', uppercase.
+ *
+ * @author Jesse Peterson
+ */
+ public AllUnitsOffEvent(Object source, char houseCode)
+ {
+ super(source, 0, houseCode, X10Util.X10_FUNCTION_ALL_UNITS_OFF, 22);
+ }
+
+ /**
+ * Create a string that represents the X10 event.
+ *
+ * @return string representation of the X10 event
+ *
+ * @author Jesse Peterson
+ */
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append("X10 All Units Off Event: house code<");
+ buffer.append(getHouseCode());
+ buffer.append("> function code<");
+ buffer.append(getFunction());
+ buffer.append(">");
+
+ return(buffer.toString());
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/FunctionListener.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/FunctionListener.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/FunctionListener.java (revision 2)
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10.event;
+
+import java.util.EventListener;
+
+/**
+ * @author Jesse Peterson
+ */
+public interface FunctionListener extends EventListener
+{
+ /**
+ * @author Jesse Peterson
+ */
+ public void functionAllUnitsOff(FunctionEvent e);
+
+ /**
+ * @author Jesse Peterson
+ */
+ public void functionAllLightsOn(FunctionEvent e);
+
+ /**
+ * @author Jesse Peterson
+ */
+ public void functionOn(FunctionEvent e);
+
+ /**
+ * @author Jesse Peterson
+ */
+ public void functionOff(FunctionEvent e);
+
+ /**
+ * @author Jesse Peterson
+ */
+ public void functionDim(FunctionEvent e);
+
+ /**
+ * @author Jesse Peterson
+ */
+ public void functionBright(FunctionEvent e);
+
+ /**
+ * @author Jesse Peterson
+ */
+ public void functionAllLightsOff(FunctionEvent e);
+
+ /**
+ * @author Jesse Peterson
+ */
+ public void functionHailRequest(FunctionEvent e);
+
+ /**
+ * @author Jesse Peterson
+ */
+ public void functionHailAcknowledge(FunctionEvent e);
+
+ /**
+ * @author Jesse Peterson
+ */
+ public void functionPresetDim1(FunctionEvent e);
+
+ /**
+ * @author Jesse Peterson
+ */
+ public void functionPresetDim2(FunctionEvent e);
+
+ /**
+ * @author Jesse Peterson
+ */
+ public void functionStatusOn(FunctionEvent e);
+
+ /**
+ * @author Jesse Peterson
+ */
+ public void functionStatusOff(FunctionEvent e);
+
+ /**
+ * @author Jesse Peterson
+ */
+ public void functionStatusRequest(FunctionEvent e);
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/AddressListener.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/AddressListener.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/AddressListener.java (revision 2)
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10.event;
+
+import java.util.EventListener;
+
+/**
+ * @author Jesse Peterson
+ */
+public interface AddressListener extends EventListener
+{
+ /**
+ * @author Jesse Peterson
+ */
+ public void address(AddressEvent e);
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/ExtendedCodeEvent.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/ExtendedCodeEvent.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/ExtendedCodeEvent.java (revision 2)
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10.event;
+
+import com.jpeterson.x10.X10Util;
+import com.jpeterson.util.HexFormat;
+
+/**
+ * Extended event
+ *
+ * @version 1.0
+ * @author Jesse Peterson
+ */
+public class ExtendedCodeEvent extends FunctionEvent
+{
+ private byte data;
+
+ private byte command;
+
+ /**
+ * Create a new 'Extended Code' event.
+ *
+ * @param source The event source.
+ * @param houseCode the house code of the event. Valid codes are 'A'
+ * through 'P', uppercase.
+ *
+ * @author Jesse Peterson
+ */
+ public ExtendedCodeEvent(Object source, char houseCode, byte data,
+ byte command)
+ {
+ super(source, 0, true, houseCode,
+ X10Util.X10_FUNCTION_EXTENDED_CODE, 22);
+ this.data = data;
+ this.command = command;
+ }
+
+ /**
+ * Retrieve the bytes that compose the X10 event.
+ *
+ * @return Array of bytes that constitute the payload of the X10 event.
+ * The size will be 4.
+ *
+ * @author Jesse Peterson
+ */
+ public byte[] getPacket()
+ {
+ byte[] packet = new byte[4];
+ byte[] standard = super.getPacket();
+
+ packet[0] = standard[0];
+ packet[1] = standard[1];
+ packet[2] = data;
+ packet[3] = command;
+
+ return(packet);
+ }
+
+ /**
+ * Retrieve the data byte.
+ *
+ * @return Extended code's data byte.
+ *
+ * @author Jesse Peterson
+ */
+ public byte getData()
+ {
+ return(data);
+ }
+
+ /**
+ * Retrieve the command byte.
+ *
+ * @return Extended code's command byte.
+ *
+ * @author Jesse Peterson
+ */
+ public byte getCommand()
+ {
+ return(command);
+ }
+
+ /**
+ * Create a string that represents the X10 event.
+ *
+ * @return string representation of the X10 event
+ *
+ * @author Jesse Peterson
+ */
+ public String toString()
+ {
+ HexFormat hexFormat = new HexFormat();
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append("X10 Extended Code Event: house code<");
+ buffer.append(getHouseCode());
+ buffer.append("> function code<");
+ buffer.append(getFunction());
+ buffer.append("> data<0x");
+ buffer.append(hexFormat.format(getData()));
+ buffer.append("> command<0x");
+ buffer.append(hexFormat.format(getCommand()));
+ buffer.append(">");
+
+ return(buffer.toString());
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/StatusRequestEvent.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/StatusRequestEvent.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/event/StatusRequestEvent.java (revision 2)
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10.event;
+
+import com.jpeterson.x10.X10Util;
+
+/**
+ * Status request for addressed units on the same house code.
+ *
+ * @version 1.0
+ * @author Jesse Peterson
+ */
+public class StatusRequestEvent extends FunctionEvent
+{
+ /**
+ * Create a new 'Status Request' event.
+ *
+ * @param source The event source.
+ * @param houseCode the house code of the event. Valid codes are 'A'
+ * through 'P', uppercase.
+ *
+ * @author Jesse Peterson
+ */
+ public StatusRequestEvent(Object source, char houseCode)
+ {
+ super(source, 0, houseCode, X10Util.X10_FUNCTION_STATUS_REQUEST, 22);
+ }
+
+ /**
+ * Create a string that represents the X10 event.
+ *
+ * @return string representation of the X10 event
+ *
+ * @author Jesse Peterson
+ */
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append("X10 Status Request Event: house code<");
+ buffer.append(getHouseCode());
+ buffer.append("> function code<");
+ buffer.append(getFunction());
+ buffer.append(">");
+
+ return(buffer.toString());
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/GatewayState.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/GatewayState.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/GatewayState.java (revision 2)
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10;
+
+/**
+ * Contains the value of the gateway state.
+ *
+ * @author Jesse Peterson <6/29/99>
+ * @version 1.0
+ */
+public class GatewayState extends Object
+{
+ private long state;
+
+ /**
+ * Create a new GatewayState object. Initial state is set to zero.
+ *
+ * @author Jesse Peterson <6/29/99>
+ */
+ public GatewayState()
+ {
+ state = 0;
+ }
+
+ /**
+ * Set the gateway state.
+ *
+ * @param state the new state
+ *
+ * @author Jesse Peterson <6/29/99>
+ */
+ public void setState(long state)
+ {
+ this.state = state;
+ }
+
+ /**
+ * Get the gateway state.
+ *
+ * @return The current state
+ *
+ * @author Jesse Peterson <6/29/99>
+ */
+ public long getState()
+ {
+ return(state);
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/GatewayAdapter.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/GatewayAdapter.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/GatewayAdapter.java (revision 2)
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10;
+
+/**
+ * Trivial implementation of the GatewayListener interface that
+ * receives a GatewayEvent. The methods in this class are empty,
+ * this class is provided as a convenience for easily creating listeners by
+ * extending this class and overriding only the methods of interest.
+ *
+ * @see TransmitterAdapter
+ *
+ * @author Jesse Peterson <6/29/99>
+ * @version 1.0
+ */
+public class GatewayAdapter extends Object implements GatewayListener
+{
+ /**
+ * Constructor does nothing.
+ *
+ */
+ public GatewayAdapter()
+ {
+ // empty
+ }
+
+ /**
+ * The Gateway has been paused.
+ *
+ * @see GATEWAY_PAUSED
+ *
+ * @author Jesse Peterson <6/29/99>
+ */
+ public void gatewayPaused(GatewayEvent e)
+ {
+ // empty
+ }
+
+ /**
+ * The Gateway has been resumed.
+ *
+ * @see GATEWAY_RESUMED
+ *
+ * @author Jesse Peterson <6/29/99>
+ */
+ public void gatewayResumed(GatewayEvent e)
+ {
+ // empty
+ }
+
+ /**
+ * The Gateway has been allocated.
+ *
+ * @see GATEWAY_ALLOCATED
+ *
+ * @author Jesse Peterson <6/29/99>
+ */
+ public void gatewayAllocated(GatewayEvent e)
+ {
+ // empty
+ }
+
+ /**
+ * The Gateway has been deallocated.
+ *
+ * @see GATEWAY_DEALLOCATED
+ *
+ * @author Jesse Peterson <6/29/99>
+ */
+ public void gatewayDeallocated(GatewayEvent e)
+ {
+ // empty
+ }
+
+ /**
+ * The Gateway is being allocated.
+ *
+ * @see GATEWAY_ALLOCATING_RESOURCES
+ *
+ * @author Jesse Peterson <6/29/99>
+ */
+ public void gatewayAllocatingResources(GatewayEvent e)
+ {
+ // empty
+ }
+
+ /**
+ * The Gateway is being deallocated.
+ *
+ * @see GATEWAY_DEALLOCATING_RESOURCES
+ *
+ * @author Jesse Peterson <6/29/99>
+ */
+ public void gatewayDeallocatingResources(GatewayEvent e)
+ {
+ // empty
+ }
+
+ /**
+ * A GatewayErrorEvent has occurred and the
+ * Gateway is unable to continue normal operation.
+ *
+ * @author Jesse Peterson <6/29/99>
+ */
+ public void gatewayError(GatewayErrorEvent e)
+ {
+ // empty
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/GatewayEvent.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/GatewayEvent.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/GatewayEvent.java (revision 2)
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10;
+
+/**
+ * GatewayEvent notifies changes in state of a gateway that
+ * transmits or receives. GatewayEvents are issued to each
+ * GatewayListener attached to a gateway. The
+ * TransmissionEvent and ReceptionEvent classes both
+ * extend GatewayEvent to provide specific events for transmitters
+ * and receivers.
+ *
+ * @author Jesse Peterson <6/29/99>
+ * @version 1.0
+ */
+public class GatewayEvent extends ControlEvent
+{
+ /**
+ * Identifier for event issued when gateway allocation is complete. The
+ * ALLOCATED flag of the newGatewayState is set.
+ *
+ * @see getNewGatewayState
+ * @see getId
+ * @see allocate
+ * @see gatewayAllocated
+ */
+ public static final int GATEWAY_ALLOCATED = 1;
+
+ /**
+ * Identifier for event issued when gateway deallocation is complete. The
+ * DEALLOCATED flag of the newGatewayState is set.
+ *
+ * @see getNewGatewayState
+ * @see getId
+ * @see allocate
+ * @see gatewayDeallocated
+ */
+ public static final int GATEWAY_DEALLOCATED = 2;
+
+ /**
+ * Identifier for event issued when gateway allocation has commenced. The
+ * ALLOCATING_RESOURCES flag of the
+ * newGatewayState is set.
+ *
+ * @see getNewGatewayState
+ * @see getId
+ * @see allocate
+ * @see gatewayAllocatingResources
+ */
+ public static final int GATEWAY_ALLOCATING_RESOURCES = 3;
+
+ /**
+ * Identifier for event issued when gateway deallocation has commenced. The
+ * DEALLOCATING_RESOURCES flag of the
+ * newGatewayState is set.
+ *
+ * @see getNewGatewayState
+ * @see getId
+ * @see allocate
+ * @see gatewayDeallocatingResources
+ */
+ public static final int GATEWAY_DEALLOCATING_RESOURCES = 4;
+
+ /**
+ * Identifier for event issued when gateway is paused. The
+ * PAUSED flag of the newGatewayState is set.
+ *
+ * @see getNewGatewayState
+ * @see getId
+ * @see pause
+ * @see gatewayPaused
+ */
+ public static final int GATEWAY_PAUSED = 5;
+
+ /**
+ * Identifier for event issued when gateway is resumed. The
+ * RESUMED flag of the newGatewayState is set.
+ *
+ * @see getNewGatewayState
+ * @see getId
+ * @see resume
+ * @see gatewayResumed
+ */
+ public static final int GATEWAY_RESUMED = 6;
+
+ /**
+ * Gateway state following this event.
+ *
+ * @see getNewGatewayState
+ */
+ protected long newGatewayState;
+
+ /**
+ * Gateway state prior to this event.
+ *
+ * @see getOldGatewayState
+ */
+ protected long oldGatewayState;
+
+ /**
+ * Constructs an GatewayEvent with an event identifier, old
+ * gateway state and new gateway state.
+ *
+ * @param source the object that issued the event
+ * @param id the identifier for the event type
+ * @param oldGatewayState gateway state prior to this event
+ * @param newGatewayState gateway state following this event
+ * @see getGatewayState
+ *
+ * @author Jesse Peterson <6/29/99>
+ */
+ public GatewayEvent(Gateway source, int id, long oldGatewayState,
+ long newGatewayState)
+ {
+ super(source, id);
+ this.oldGatewayState = oldGatewayState;
+ this.newGatewayState = newGatewayState;
+ }
+
+ /**
+ * Return the state following this GatewayEvent. The value
+ * matches the getGatewayState method.
+ *
+ * @see getGatewayState
+ *
+ * @author Jesse Peterson <6/29/99>
+ */
+ public long getNewGatewayState()
+ {
+ return(newGatewayState);
+ }
+
+ /**
+ * Return the state prior to this GatewayEvent.
+ *
+ * @see getGatewayState
+ *
+ * @author Jesse Peterson <6/29/99>
+ */
+ public long getOldGatewayState()
+ {
+ return(oldGatewayState);
+ }
+
+ /**
+ * Returns a parameter string identifying this event. This method is useful
+ * for event-logging and for debugging.
+ *
+ * @return a string identifying the event
+ *
+ * @author Jesse Peterson <6/29/99>
+ */
+ public String paramString()
+ {
+ StringBuffer buffer = new StringBuffer();
+
+ int eventId = getId();
+ String eventDescription;
+
+ // decode event ID to human readable meaning
+ switch (eventId)
+ {
+ case GATEWAY_ALLOCATED:
+ eventDescription = "Gateway Allocated";
+ break;
+
+ case GATEWAY_DEALLOCATED:
+ eventDescription = "Gateway Deallocated";
+ break;
+
+ case GATEWAY_ALLOCATING_RESOURCES:
+ eventDescription = "Gateway Allocating Resources";
+ break;
+
+ case GATEWAY_DEALLOCATING_RESOURCES:
+ eventDescription = "Gateway Deallocating Resources";
+ break;
+
+ case GATEWAY_PAUSED:
+ eventDescription = "Gateway Paused";
+ break;
+
+ case GATEWAY_RESUMED:
+ eventDescription = "Gateway Resumed";
+ break;
+
+ default:
+ eventDescription = "Gateway Event Unknown";
+ break;
+ }
+
+ // create string
+ buffer.append("Gateway Event - Source = [");
+ buffer.append(getSource());
+ buffer.append("] ID = [");
+ buffer.append(eventDescription);
+ buffer.append(" (").append(eventId);
+ buffer.append(")]");
+
+ return(buffer.toString());
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/module/CM11AStatusTransmission.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/module/CM11AStatusTransmission.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/module/CM11AStatusTransmission.java (revision 2)
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10.module;
+
+import java.io.EOFException;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.BitSet;
+import com.jpeterson.util.HexFormat;
+import com.jpeterson.x10.InterruptedTransmissionException;
+import com.jpeterson.x10.TooManyAttemptsException;
+import com.jpeterson.x10.module.event.CM11AStatusEvent;
+import com.jpeterson.x10.module.event.CM11AStatusListener;
+
+/**
+ * Create a status request. The CM11A performs monitoring on a certain
+ * house code. The status request downloads the status of the monitored
+ * house code.
+ *
+ * @author Jesse Peterson
+ */
+public class CM11AStatusTransmission extends Object
+ implements CM11ATransmissionEvent
+{
+ private int attempts;
+ private int maxAttempts;
+ private CM11A cm11a;
+ private CM11AStatusListener listener;
+
+ private static final byte STATUS_REQ = (byte)0x8b;
+
+ private static final int STATUS_SIZE = 14;
+
+ /**
+ * Create a standard CM11 transmission event to request the status
+ * of the monitoring performed by the CM11 interface
+ *
+ * @param parent The CM11A device to retrieve the status of.
+ * @param listener CM11AStatusListener to notify when status retrieved.
+ * May be null.
+ *
+ * @author Jesse Peterson
+ */
+ public CM11AStatusTransmission(CM11A parent, CM11AStatusListener listener)
+ {
+ attempts = 0;
+ setMaxAttempts(3);
+ cm11a = parent;
+ this.listener = listener;
+ }
+
+ /**
+ * Transmit a CM11 status command.
+ *
+ * @param in Input stream to read from
+ * @param out Output stream to write to
+ * @exception TooManyAttemptsException Too many retries have occurred
+ * @exception InterruptedTransmissionException An unsolicited interrupt
+ * has been received during the transmission.
+ * @exception IOException Some sort of I/O or I/O protocol error has
+ * occurred
+ *
+ * @author Jesse Peterson
+ */
+ public void transmit(InputStream in, OutputStream out)
+ throws TooManyAttemptsException, InterruptedTransmissionException,
+ EOFException, IOException
+ {
+ byte[] buffer = new byte[STATUS_SIZE];
+ int numBytesRead = 0;
+ CM11AStatusEvent event;
+ HexFormat hex = new HexFormat();
+
+ // mark off an attempt
+ ++attempts;
+
+ if (attempts > maxAttempts)
+ {
+ throw new TooManyAttemptsException();
+ }
+
+ if (System.getProperty("DEBUG") != null)
+ {
+ System.out.println("Sending CM11AStatusTransmission");
+ System.out.println("PC->CM11A: 0x" + hex.format(STATUS_REQ));
+ }
+
+ // send status request
+ out.write(STATUS_REQ);
+
+ // wait a second
+ try
+ {
+ Thread.sleep(1000);
+ }
+ catch (InterruptedException e)
+ {
+ // do nothing
+ }
+ if (System.getProperty("DEBUG") != null)
+ {
+ System.out.println("Bytes available: " + in.available());
+ }
+
+ // expect STATUS_SIZE bytes to be returned
+ if (in.available() < STATUS_SIZE)
+ {
+ if (System.getProperty("DEBUG") != null)
+ {
+ System.out.println("Not enough bytes for a status message yet");
+ }
+ // if we got here, we don't have the correct number of bytes
+ // available, maybe we have an unsolicited event.
+ int result;
+ byte byteValue;
+
+ result = in.read();
+
+ if (result == -1)
+ {
+ throw new EOFException("Unexpected end of stream indicator received while retrieving status.");
+ }
+ byteValue = (byte)result;
+
+ if (System.getProperty("DEBUG") != null)
+ {
+ System.out.println("byte read: 0x" + hex.format(byteValue));
+ System.out.println("Second chance bytes available: " + in.available());
+ }
+
+ if ((byteValue == CM11A.CM11_RECEIVE_EVENT) ||
+ (byteValue == CM11A.CM11_POWER_FAILURE) ||
+ (byteValue == CM11A.CM11_MACRO_INITIATED))
+ {
+ throw new InterruptedTransmissionException(byteValue);
+ }
+ else if (in.available() >= (STATUS_SIZE - 1))
+ {
+ if (System.getProperty("DEBUG") != null)
+ {
+ System.out.println("Now, enough bytes are available.");
+ }
+ // may be slow to get the bytes uploaded, give it another
+ // chance.
+ buffer[0] = byteValue;
+ numBytesRead = in.read(buffer, 1, buffer.length - 1) + 1;
+ // received the status buffer, continue on
+ }
+ else
+ {
+System.err.println("Breakdown in protocol, consuming all bytes in CM11AStatusTransmission.");
+
+ // consume all bytes in input stream
+ while (in.available() > 0)
+ {
+ in.read(buffer);
+ }
+
+ // retransmit
+ transmit(in, out);
+ return;
+ }
+ }
+ else
+ {
+ if (System.getProperty("DEBUG") != null)
+ {
+ System.out.println("Reading...");
+ }
+ numBytesRead = in.read(buffer);
+ }
+
+ if (System.getProperty("DEBUG") != null)
+ {
+ System.out.println("Checking number of bytes read...");
+ }
+ if (numBytesRead != STATUS_SIZE)
+ {
+ System.err.println("Invalid status buffer size. Received " + numBytesRead + " bytes out of " + STATUS_SIZE + " bytes.");
+
+ // consume all bytes in input stream
+ while (in.available() > 0)
+ {
+ in.read(buffer);
+ }
+
+ // retransmit
+ transmit(in, out);
+ return;
+ }
+
+ if (System.getProperty("DEBUG") != null)
+ {
+ System.out.println("Calling method to decode status...");
+ }
+ event = cm11a.decodeStatus(buffer, 0, buffer.length);
+
+ if ((listener != null) && (event != null))
+ {
+ // notify listener
+ listener.status(event);
+ }
+ // transmission complete
+ }
+
+ /**
+ * Retrieve the number of transmission attempts.
+ *
+ * @return the number of transmission attempts
+ *
+ * @author Jesse Peterson
+ */
+ public int getNumAttempts()
+ {
+ return(attempts);
+ }
+
+ /**
+ * Set the number of transmission attempts
+ *
+ * @param maxAttempts the maximum number of transmission attempts
+ *
+ * @author Jesse Peterson
+ */
+ public void setMaxAttempts(int maxAttempts)
+ {
+ this.maxAttempts = maxAttempts;
+ }
+
+ /**
+ * Create a string representation of the transmission.
+ *
+ * @return String representation of the transmission.
+ *
+ * @author Jesse Peterson
+ */
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+ HexFormat hexFormat = new HexFormat();
+ String prefix = "";
+
+ buffer.append("CM11AStatusTransmission");
+ return(buffer.toString());
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/module/Macro.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/module/Macro.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/module/Macro.java (revision 2)
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10.module;
+
+import java.io.Serializable;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+import com.jpeterson.x10.event.FunctionEvent;
+
+/**
+ * A macro, when triggered by being initiated by a TimerInitiator
+ * or MacroInitiator, will issue X10 events. A macro's execution
+ * can be delayed up to 4 hours once it is initiaited. A macro contains one or
+ * more macro element. Each macro element is an X10 function. When the macro
+ * executes, all of the macro's MacroElement function's will be executed.
+ *
+ * @author Jesse Peterson
+ */
+public class Macro implements Serializable
+{
+ /** Size of macro header. */
+ private static final int HEADER_SIZE = 2;
+
+ /** Maximum number of macro elements. */
+ private static final int MAX_ELEMENTS = 255;
+
+ /**
+ * Offset in minutes before the macro's functions are executed.
+ */
+ private int timerOffset;
+
+ /**
+ * Contains all of the MacroElements for this macro. The MacroElements are
+ * keyed in the hashtable based on their FunctionEvent.
+ */
+ private Hashtable elements;
+
+ /**
+ * Create a new macro with no timer offset.
+ *
+ * @author Jesse Peterson
+ */
+ public Macro()
+ {
+ this(0);
+ }
+
+ /**
+ * Create a new macro. Each macro can multiple macro elements performing
+ * multiple functions.
+ *
+ * @param timerOffset Offset in minutes from the time at which the macro is
+ * called to the time when the macro actually takes effect. 0 to
+ * 240 minutes (4 hours).
+ * @exception IllegalArgumentException Thrown if timer offset is less than
+ * 0 or greater than 240.
+ *
+ * @author Jesse Peterson
+ */
+ public Macro(int timerOffset)
+ {
+ if ((timerOffset < 0) || (timerOffset > 240))
+ {
+ throw new IllegalArgumentException("Macro timer offset minutes must be between 0 and 240");
+ }
+ elements = new Hashtable();
+ this.timerOffset = timerOffset;
+ }
+
+ /**
+ * Retrieve the macro's timer offset value.
+ *
+ * @return The macro's timer offset in minutes
+ *
+ * @author Jesse Peterson
+ */
+ public int getTimerOffset()
+ {
+ return(timerOffset);
+ }
+
+ /**
+ * Add a command for this macro to execute. When the macro is executed,
+ * this command will be carried out. The house code for the address and
+ * function must both be the same. The maximum number of commands is 255.
+ * Commands added after 255 are silently ignored.
+ *
+ *
+ * @param device Device number. Must be between 1 and 16, inclusive.
+ * @param function A FunctionEvent for a command that the macro will execute.
+ * For proper use in this case for a macro, the source of the X10Event
+ * will be ignored.
+ * @exception IllegalArgumentException Thrown if the device number is less
+ * than 1 or greater than 16.
+ *
+ * @author Jesse Peterson
+ */
+ public synchronized void addCommand(int device, FunctionEvent function)
+ throws IllegalArgumentException
+ {
+ addCommand(device, function, false);
+ }
+
+ /**
+ * Add a command for this macro to execute. When the macro is executed,
+ * this command will be carried out. The house code for the address and
+ * function must both be the same. The maximum number of commands is 255.
+ * Commands added after 255 are silently ignored.
+ *
+ *
+ * @param device Device number. Must be between 1 and 16, inclusive.
+ * @param function A FunctionEvent for a command that the macro will execute.
+ * For proper use in this case for a macro, the source of the X10Event
+ * will be ignored.
+ * @param brightenFirst If true and Functin Event is a dim or bright command,
+ * the device will be brought to maximum brightness before applying the
+ * dim amount. This functionality is global per dim/bright command per
+ * macro. It is updated each time a device is added.
+ * @exception IllegalArgumentException Thrown if the device number is less
+ * than 1 or greater than 16.
+ *
+ * @author Jesse Peterson
+ */
+ public synchronized void addCommand(int device, FunctionEvent function,
+ boolean brightenFirst)
+ throws IllegalArgumentException
+ {
+ MacroElement element;
+
+ if (((element = (MacroElement)elements.get(function)) == null) &&
+ (elements.size() < MAX_ELEMENTS))
+ {
+ // new element
+ element = new MacroElement(function);
+ elements.put(function, element);
+ }
+
+ element.addDevice(device);
+ element.setBrightenFirst(brightenFirst);
+ }
+
+ /**
+ * Add a command for this macro to execute. When the macro is executed,
+ * this command will be carried out. The maximum number of commands is 255.
+ * Commands added after 255 are silently ignored.
+ *
+ * @param function A FunctionEvent command that the macro will execute.
+ * For proper use in this case for a macro, the source of the X10Event
+ * will be ignored.
+ *
+ * @author Jesse Peterson
+ */
+ public synchronized void addCommand(FunctionEvent function)
+ {
+ MacroElement element;
+
+ if (((element = (MacroElement)elements.get(function)) == null) &&
+ (elements.size() < MAX_ELEMENTS))
+ {
+ // new element
+ element = new MacroElement(function);
+ elements.put(function, element);
+ }
+ }
+
+ /**
+ * This method provides a way to remove a macro element from the macro.
+ * You can retrieve all of the macro elements in this macro from the
+ * elements method.
+ *
+ * @param element the macro element to remove.
+ *
+ * @author Jesse Peterson
+ */
+ public synchronized void removeElement(MacroElement element)
+ {
+ elements.remove(element);
+ }
+
+ /**
+ * Returns an enumeration of the MacroElements for this macro.
+ *
+ * @return An enumeration of the MacroElements in this macro.
+ */
+ public synchronized Enumeration elements()
+ {
+ return(elements.elements());
+ }
+
+ /**
+ * Determine if this Macro is equal to the target object.
+ *
+ * @param object Target object to determine if it is equal to this Macro.
+ * @return True if the target object equals this one, false otherwise.
+ *
+ * @author Jesse Peterson
+ */
+ public boolean equals(Object object)
+ {
+ Macro target;
+
+ if ((object == null) ||
+ (!(object instanceof Macro)))
+ {
+ return(false);
+ }
+
+ target = (Macro)object;
+
+ if (timerOffset == target.getTimerOffset())
+ {
+ MacroElement element, targetElement;
+ FunctionEvent function;
+ Hashtable targetElements = new Hashtable();
+
+ // make a hashtable of the target elements.
+ for (Enumeration e = target.elements(); e.hasMoreElements(); )
+ {
+ targetElement = (MacroElement)e.nextElement();
+ targetElements.put(targetElement.getFunction(), targetElement);
+ }
+
+ // check to see that the target contains all of this macro's elements
+ for (Enumeration e = elements.keys(); e.hasMoreElements(); )
+ {
+ function = (FunctionEvent)e.nextElement();
+ targetElement = (MacroElement)targetElements.get(function);
+ if (targetElement == null)
+ {
+ return(false);
+ }
+ element = (MacroElement)elements.get(function);
+ if (!(element.equals(targetElement)))
+ {
+ return(false);
+ }
+ }
+
+ // check to see that this macro contains all of the target macro's
+ // elements
+ for (Enumeration e = targetElements.keys(); e.hasMoreElements(); )
+ {
+ function = (FunctionEvent)e.nextElement();
+ element = (MacroElement)elements.get(function);
+ if (element == null)
+ {
+ return(false);
+ }
+ targetElement = (MacroElement)targetElements.get(function);
+ if (!(element.equals(targetElement)))
+ {
+ return(false);
+ }
+ }
+
+ // if we got this far, they are equal
+ return(true);
+ }
+
+ return(false);
+ }
+
+ /**
+ * Get the byte array representing this macro and all of its macro
+ * elements.
+ *
+ * @return Byte array containing the macro and all of its elements.
+ * @exception ArrayIndexOutOfBoundsException if copying would cause access
+ * of data outside array bounds.
+ * @exception ArrayStoreException if an element in the src
+ * array could not be stored into the dest array
+ * because of a type mismatch.
+ *
+ * @author Jesse Peterson
+ */
+ public synchronized byte[] getBytes()
+ {
+ byte[] component, element;
+ MacroElement macroElement;
+ int macroSize = 0, offset = 0;
+ Vector byteArrays;
+
+ byteArrays = new Vector(); // temporary storage of macro elements
+ // byte arrays.
+
+ // get all of the macro element byte arrays and determine size
+ // of array necessary to hold all macro element byte arrays.
+ for (Enumeration e = elements.elements(); e.hasMoreElements(); )
+ {
+ macroElement = (MacroElement)e.nextElement();
+ component = macroElement.getBytes();
+ macroSize += component.length;
+
+ byteArrays.addElement(component);
+ }
+
+ // allocate array to store entire macro
+ element = new byte[HEADER_SIZE + macroSize];
+
+ // encode delay
+ element[offset++] = (byte)timerOffset;
+
+ // encode number of macro elements
+ element[offset++] = (byte)byteArrays.size();
+
+ // copy macro element bytes to macro array
+ for (Enumeration e = byteArrays.elements(); e.hasMoreElements(); )
+ {
+ component = (byte[])e.nextElement();
+ System.arraycopy(component, 0, element, offset, component.length);
+ offset += component.length;
+ }
+
+ return(element);
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/module/event/CM11AEvent.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/module/event/CM11AEvent.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/module/event/CM11AEvent.java (revision 2)
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10.module.event;
+
+import com.jpeterson.x10.ControlEvent;
+import com.jpeterson.x10.module.CM11A;
+
+/**
+ * @author Jesse Peterson
+ */
+public class CM11AEvent extends ControlEvent
+{
+ /**
+ * The CM11A received a power failure event.
+ *
+ * @author Jesse Peterson
+ */
+ public static final int POWER_FAILURE = 21;
+
+ /**
+ * The CM11A received a macro initiated event.
+ *
+ * @author Jesse Peterson
+ */
+ public static final int MACRO_INITIATED = 22;
+
+ /**
+ * Create a new CM11A Event.
+ *
+ * @param source CM11A object that is sending the event.
+ * @param id Type of event.
+ *
+ * @author Jesse Peterson
+ */
+ public CM11AEvent(CM11A source, int id)
+ {
+ super(source, id);
+ }
+
+ /**
+ * Returns a parameter string identifying the event. This method is
+ * useful for event-logging and for debugging.
+ *
+ * @return a string identifying the event
+ *
+ * @author Jesse Peterson
+ */
+ public String paramString()
+ {
+ return("CM11AEvent - source = [" + getSource() + "] ID = [" + getId() + "]");
+ }
+}
+
+
+
+
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/module/event/CM11AListener.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/module/event/CM11AListener.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/module/event/CM11AListener.java (revision 2)
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10.module.event;
+
+import java.util.EventListener;
+
+/**
+ * @author Jesse Peterson
+ */
+public interface CM11AListener extends EventListener
+{
+ /**
+ * @author Jesse Peterson
+ */
+ public void powerFailure(CM11AEvent e);
+
+ /**
+ * @author Jesse Peterson
+ */
+ public void macroInitiated(CM11AEvent e);
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/module/event/CM11AStatusEvent.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/module/event/CM11AStatusEvent.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/module/event/CM11AStatusEvent.java (revision 2)
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10.module.event;
+
+import java.util.BitSet;
+import com.jpeterson.x10.ControlEvent;
+import com.jpeterson.x10.module.CM11A;
+
+/**
+ * @author Jesse Peterson
+ */
+public class CM11AStatusEvent extends ControlEvent
+{
+ private char monitoredHouseCode;
+ private BitSet onOffStatus;
+ private BitSet dimStatus;
+ private BitSet lastAddressedDevice;
+ private int currentDay;
+ private int julianDay;
+ private int hours, minutes, seconds;
+ private int batteryUsage;
+
+ /**
+ * The CM11A received a status event.
+ *
+ * @author Jesse Peterson
+ */
+ public static final int STATUS = 23;
+
+ /**
+ * @author Jesse Peterson
+ */
+ public CM11AStatusEvent(CM11A source, int batteryUsage, int seconds, int minutes, int hours, int julianDay, int currentDay, char monitoredHouseCode, BitSet lastAddressedDevice, BitSet onOffStatus, BitSet dimStatus)
+ {
+ super(source, STATUS);
+ this.batteryUsage = batteryUsage;
+ this.seconds = seconds;
+ this.minutes = minutes;
+ this.hours = hours;
+ this.julianDay = julianDay;
+ this.currentDay = currentDay;
+ this.monitoredHouseCode = monitoredHouseCode;
+ this.lastAddressedDevice = lastAddressedDevice;
+ this.onOffStatus = onOffStatus;
+ this.dimStatus = dimStatus;
+ }
+
+ /**
+ * The CM11A's idea of what the current battery usage is.
+ *
+ * @return The CM11A's idea of what the current battery usage is.
+ * Expressed in minutes.
+ *
+ * @author Jesse Peterson
+ */
+ public int getBatteryUsage()
+ {
+ return(batteryUsage);
+ }
+
+ /**
+ * The CM11A's idea of what the current second is.
+ *
+ * @return The CM11A's idea of what the current second is.
+ *
+ * @author Jesse Peterson
+ */
+ public int getSeconds()
+ {
+ return(seconds);
+ }
+
+ /**
+ * The CM11A's idea of what the current minute is.
+ *
+ * @return The CM11A's idea of what the current minute is.
+ *
+ * @author Jesse Peterson
+ */
+ public int getMinutes()
+ {
+ return(minutes);
+ }
+
+ /**
+ * The CM11A's idea of what the current hour is.
+ *
+ * @return The CM11A's idea of what the current hour is.
+ *
+ * @author Jesse Peterson
+ */
+ public int getHours()
+ {
+ return(hours);
+ }
+
+ /**
+ * Retrieve the CM11A's idea of the current day of the year. The value
+ * is zero based; 0 for January 1, 31 for February 1, ... The value is
+ * initialized after a call to updateStatus().
+ *
+ * The utility methods CM11A.extractMonth() and
+ * CM11A.extractDay() have been provided to convert this
+ * value into month and day representations.
+ *
+ * As far as I can tell, the CM11A has no way of determining
+ * leap years. It therefore always uses 366 days in a year. The
+ * caller is responsible for determining if the current day
+ * has been corrected for a non-leap year.
+ *
+ * @return Day of year.
+ *
+ * @author Jesse Peterson
+ */
+ public int getJulianDay()
+ {
+ return(julianDay);
+ }
+
+ /**
+ * Retrieve the CM11A's idea of what the current day is.
+ *
+ * @return The CM11A's idea of what the current day is. Will be one of
+ * Calendar.SUNDAY, Calendar.MONDAY, Calendar.TUESDAY,
+ * Calendar.WEDNESDAY, Calendar.THURSDAY, Calendar.FRIDAY,
+ * Calendar.SATURDAY.
+ *
+ * @author Jesse Peterson
+ */
+ public int getCurrentDay()
+ {
+ return(currentDay);
+ }
+
+ /**
+ * Get the house code that the CM11A is configured to monitor. The
+ * CM11A device will record changes to devices on the monitored house
+ * code. It record the on/off status and if a device is dimmed or not.
+ * The data can be retrieved from the methods getOnOffStatus,
+ * getDimStatus, get last addressed device.
+ *
+ * @return The character from 'A' through 'P' that indicates the
+ * house code that is being monitored.
+ *
+ * @author Jesse Peterson
+ */
+ public char getMonitoredHouseCode()
+ {
+ return(monitoredHouseCode);
+ }
+
+ /**
+ * Indication of the last addressed device as the CM11A sees it for the
+ * monitored house code.
+ *
+ * @return The bit is set (true) if the device was addressed, not set (false)
+ * if the device was not addressed. The bit index indicates the device:
+ * bit index 0 = device 1, bit index 1 = device 2, ...,
+ * bit index 15 = device 16.
+ *
+ * @author Jesse Peterson
+ */
+ public BitSet getLastAddressedDevice()
+ {
+ return(lastAddressedDevice);
+ }
+
+ /**
+ * Indication of the On/Off status as the CM11A sees it for the
+ * monitored house code.
+ *
+ * @return The bit is set (true) if the device is on, not set (false)
+ * if the device is off. The bit index indicates the device:
+ * bit index 0 = device 1, bit index 1 = device 2, ...,
+ * bit index 15 = device 16.
+ *
+ * @author Jesse Peterson
+ */
+ public BitSet getOnOffStatus()
+ {
+ return(onOffStatus);
+ }
+
+ /**
+ * Indication of the dim status as the CM11A sees it for the
+ * monitored house code.
+ *
+ * @return The bit is set (true) if the device is dimmed, not set (false)
+ * if the device is not dimmed. The bit index indicates the device:
+ * bit index 0 = device 1, bit index 1 = device 2, ...,
+ * bit index 15 = device 16.
+ * @see updateStatus
+ *
+ * @author Jesse Peterson
+ */
+ public BitSet getDimStatus()
+ {
+ return(dimStatus);
+ }
+
+ /**
+ * Returns a parameter string identifying the event. This method is
+ * useful for event-logging and for debugging.
+ *
+ * @return a string identifying the event
+ *
+ * @author Jesse Peterson
+ */
+ public String paramString()
+ {
+ return("CM11AStatusEvent - source = [" + getSource() + "] ID = [" + getId() + "] BatteryUsage = [" + getBatteryUsage() + "] Hours = [" + getHours() + "] Minutes = [" + getMinutes() + "] Seconds = [" + getSeconds() + "] Julian Day = [" + getJulianDay() + "] Current Day = [" + getCurrentDay() + "] Monitored House Code = [" + getMonitoredHouseCode() + "] Last Addressed Device = [" + getLastAddressedDevice() + "] On/Off Status = [" + getOnOffStatus() + "] Dim Status = [" + getDimStatus() + "]");
+ }
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/module/event/CM11AStatusListener.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/module/event/CM11AStatusListener.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/module/event/CM11AStatusListener.java (revision 2)
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10.module.event;
+
+import java.util.EventListener;
+
+/**
+ * @author Jesse Peterson
+ */
+public interface CM11AStatusListener extends EventListener
+{
+ /**
+ * @author Jesse Peterson
+ */
+ public void status(CM11AStatusEvent e);
+}
Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/module/CM11A.java
===================================================================
--- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/module/CM11A.java (revision 2)
+++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/com/jpeterson/x10/module/CM11A.java (revision 2)
@@ -0,0 +1,2924 @@
+/*
+ * Copyright (C) 1999 Jesse E. Peterson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *
+ */
+
+package com.jpeterson.x10.module;
+
+import java.io.*;
+import java.util.*;
+import javax.comm.*;
+import com.jpeterson.x10.event.*;
+import com.jpeterson.x10.ControlEvent;
+import com.jpeterson.x10.GatewayException;
+import com.jpeterson.x10.Gateway;
+import com.jpeterson.x10.GatewayImpl;
+import com.jpeterson.x10.GatewayListener;
+import com.jpeterson.x10.GatewayStateError;
+import com.jpeterson.x10.InterruptedTransmissionException;
+import com.jpeterson.x10.SerialGateway;
+import com.jpeterson.x10.TooManyAttemptsException;
+import com.jpeterson.x10.Transmitter;
+import com.jpeterson.x10.TransmitterEvent;
+import com.jpeterson.x10.TransmitterListener;
+import com.jpeterson.x10.X10Util;
+import com.jpeterson.x10.module.event.CM11AEvent;
+import com.jpeterson.x10.module.event.CM11AListener;
+import com.jpeterson.x10.module.event.CM11AStatusEvent;
+import com.jpeterson.x10.module.event.CM11AStatusListener;
+import com.jpeterson.util.Condition;
+import com.jpeterson.util.Unsigned;
+import com.jpeterson.util.BinaryFormat; // DEBUG
+import com.jpeterson.util.HexFormat; // DEBUG
+
+/**
+ * Gateway to X10 CM11A serial interface unit. The CM11A is both a
+ * producer and consumer of X10Events. It receives X10Events from other
+ * software components and transmits the event through the X10 protocol.
+ * It sends X10Events that it receives on the power line.
+ *
+ * @author Jesse Peterson
+ */
+public class CM11A extends SerialGateway implements
+ Transmitter, Runnable, SerialPortEventListener, Serializable
+{
+ private transient Vector eventListeners = null;
+ private transient Vector statusListeners = null;
+ private transient Vector addressListeners = null;
+ private transient Vector functionListeners = null;
+
+ private transient CommPortIdentifier portId;
+ private transient SerialPort serialPort;
+ private transient OutputStream outputStream;
+ private transient InputStream inputStream;
+
+ private transient Thread processThread;
+ private boolean stopRequested;
+ private transient Vector transmissionQueue;
+ private transient Condition shouldProcess;
+ private char monitoredHouseCode;
+ private BitSet onOffStatus;
+ private BitSet dimStatus;
+ private BitSet lastAddressedDevice;
+ private int currentDay;
+ private int julianDay;
+ private int hours, minutes, seconds;
+ private int batteryUsage;
+ private boolean powerFailureAutoRecover;
+
+ private Hashtable macroOffsets;
+ private Hashtable offset2macro;
+ private Vector timerInitiators;
+ private Vector macroInitiators;
+
+ private byte[] eeprom;
+ private static final int EEPROM_SIZE = 1024; // 1k, 1024 bytes max
+ private static final int PAGE = 16;
+ private static final int SIZEOF_INITIAL_OFFSET = 2;
+ private static final int SIZEOF_TIMER_TERMINATOR = 1;
+ private static final byte TIMER_TERMINATOR = (byte)0xff;
+
+ public static final byte CM11_RECEIVE_EVENT = (byte)0x5a;
+ public static final byte CM11_POWER_FAILURE = (byte)0xa5;
+ public static final byte CM11_MACRO_INITIATED = (byte)0x5b;
+ private static final byte CM11_RECEIVE_EVENT_RSP = (byte)0xc3;
+ private static final byte CM11_RING_ENABLE = (byte)0xeb;
+ private static final byte CM11_RING_DISABLE = (byte)0xdb;
+ private static final byte CM11_CLOCK_DOWNLOAD = (byte)0x9b;
+ private static final byte CM11_MACRO_DOWNLOAD_INITIATOR = (byte)0xfb;
+
+ private static final int[] code2value = {-1, // invalid
+ 6, // Device 1
+ 14, // Device 2
+ 2, // Device 3
+ 10, // Device 4
+ 1, // Device 5
+ 9, // Device 6
+ 5, // Device 7
+ 13, // Device 8
+ 7, // Device 9
+ 15, // Device 10
+ 3, // Device 11
+ 11, // Device 12
+ 0, // Device 13
+ 8, // Device 14
+ 4, // Device 15
+ 12}; // Device 16
+
+ private static final int[] value2deviceCode = {13, // position 0
+ 5, // position 1
+ 3, // position 2
+ 11, // position 3
+ 15, // position 4
+ 7, // position 5
+ 1, // position 6
+ 9, // position 7
+ 14, // position 8
+ 6, // position 9
+ 4, // position 10
+ 12, // position 11
+ 16, // position 12
+ 8, // position 13
+ 2, // position 14
+ 10}; // position 15
+
+ private static final char[] value2houseCode = {'M', // value 0
+ 'E', // value 1
+ 'C', // value 2
+ 'K', // value 3
+ 'O', // value 4
+ 'G', // value 5
+ 'A', // value 6
+ 'I', // value 7
+ 'N', // value 8
+ 'F', // value 9
+ 'D', // value 10
+ 'L', // value 11
+ 'P', // vlaue 12
+ 'H', // value 13
+ 'B', // value 14
+ 'J'}; // value 15
+
+ private static Hashtable value2day;
+
+ static
+ {
+ value2day = new Hashtable();
+ value2day.put(new Integer(1), "Sunday");
+ value2day.put(new Integer(2), "Monday");
+ value2day.put(new Integer(4), "Tuesday");
+ value2day.put(new Integer(8), "Wednesday");
+ value2day.put(new Integer(16), "Thursday");
+ value2day.put(new Integer(32), "Friday");
+ value2day.put(new Integer(64), "Saturday");
+ }
+
+ // maximum number of days in a month. The index into the array is the
+ // month, zero based. e.g., 0 for January, 1 for February, 11 for
+ // December.
+ private static final int[] daysInMonth = {31, 29, 31, 30, 31, 30, 31, 31,
+ 30, 31, 30, 31};
+
+ /**
+ * Construct a new CM11A object.
+ *
+ * @author Jesse Peterson
+ */
+ public CM11A()
+ {
+ super();
+ powerFailureAutoRecover = true; // true by default
+ setPortName("COM2");
+ setBaudRate(4800);
+ setDataBits(SerialPort.DATABITS_8);
+ setStopBits(SerialPort.STOPBITS_1);
+ setParity(SerialPort.PARITY_NONE);
+ shouldProcess = new Condition(false);
+ transmissionQueue = new Vector();
+ macroOffsets = new Hashtable();
+ offset2macro = new Hashtable();
+ timerInitiators = new Vector();
+ macroInitiators = new Vector();
+ eeprom = new byte[EEPROM_SIZE];
+ monitoredHouseCode = 'A';
+ onOffStatus = new BitSet(16);
+ dimStatus = new BitSet(16);
+ lastAddressedDevice = new BitSet(16);
+ setGatewayState(Transmitter.QUEUE_EMPTY);
+ }
+
+ /**
+ * Indicate if you want the CM11A object to autorecover upon detecting
+ * a power failure. If set to true, when the CM11A object detects a
+ * power failure signal from the CM11A device, the command to set the
+ * clock will be sent. If set to false, it is up to another device to
+ * set the clock via a call to setClock before the CM11A
+ * can be used.
+ *
+ * By default, auto recover is turned on.
+ *
+ * @param autoRecover True if the object should automatically recover
+ * upon detecting a power failure of the CM11A device.
+ * @see getPowerFailureAutoRecover
+ * @see setClock
+ *
+ * @author Jesse Peterson
+ */
+ public void setPowerFailureAutoRecover(boolean autoRecover)
+ {
+ powerFailureAutoRecover = autoRecover;
+ }
+
+ /**
+ * Determine if this CM11A object has been configured to auto recover
+ * upon sensing a power failure at the CM11A device.
+ *
+ * By default, auto recover is turned on.
+ *
+ * @return True if auto recover is turned on, false otherwise.
+ * @see setPowerFailureAutoRecover
+ *
+ * @author Jesse Peterson
+ */
+ public boolean getPowerFailureAutoRecover()
+ {
+ return(powerFailureAutoRecover);
+ }
+
+ /**
+ * Encapsulates state transition rules. Only implements Transmitter
+ * specific states. Lets parent's stateTransition handle the generic
+ * gateway states.
+ *
+ * @author Jesse Peterson <6/29/99>
+ */
+ public void stateTransition(long state)
+ {
+ int id = 0;
+ long oldGatewayState, newGatewayState;
+ boolean topOfQueueChanged = false;
+ oldGatewayState = getGatewayState();
+ newGatewayState = oldGatewayState;
+
+ if (Transmitter.QUEUE_EMPTY == state)
+ {
+ id = TransmitterEvent.QUEUE_EMPTIED;
+ newGatewayState &= ~Transmitter.QUEUE_NOT_EMPTY;
+ newGatewayState |= state;
+ topOfQueueChanged = false;
+ }
+ else if (Transmitter.QUEUE_NOT_EMPTY == state)
+ {
+ id = TransmitterEvent.QUEUE_UPDATED;
+ newGatewayState &= ~Transmitter.QUEUE_EMPTY;
+ newGatewayState |= state;
+ topOfQueueChanged = true;
+ }
+ else
+ {
+ super.stateTransition(state);
+ return;
+ }
+
+ if (newGatewayState != oldGatewayState)
+ {
+ setGatewayState(newGatewayState);
+ fireControlEvent(new TransmitterEvent(this, id, topOfQueueChanged,
+ oldGatewayState,
+ newGatewayState));
+ }
+ }
+
+ /**
+ * Implementation of Transmitter. Other software components
+ * can send X10 events to the CM11A to have sent through the X10
+ * protocol to X10 devices on the power line network.
+ *
+ * @param evt X10 event to transmit
+ * @exception GatewayStateError if called for a transmitter in the
+ * DEALLOCATED or DEALLOCATING_RESOURCES states
+ *
+ * @author Jesse Peterson
+ */
+ public void transmit(X10Event evt) throws GatewayStateError
+ {
+ // If deallocating resouces, throw an error
+ if (testGatewayState(Gateway.DEALLOCATING_RESOURCES |
+ Gateway.DEALLOCATED))
+ {
+ throw new GatewayStateError("Can not transmit. Transmitter is currently in the DEALLOCATING_RESOURCES or DEALLOCATED state.");
+ }
+
+ try
+ {
+ waitGatewayState(Gateway.ALLOCATED);
+ }
+ catch (InterruptedException e)
+ {
+ throw new GatewayStateError("Caught InterruptedException while waiting for the gateway to enter an ALLOCATED state: " + e.getMessage());
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new GatewayStateError("Caught IllegalArgumentException while waiting for the gateway to enter an ALLOCATED state: " + e.getMessage());
+ }
+
+ CM11AX10EventTransmission event = new CM11AX10EventTransmission(evt);
+ transmissionQueue.addElement(event);
+ stateTransition(Transmitter.QUEUE_NOT_EMPTY);
+ shouldProcess.setTrue();
+ }
+
+ /**
+ * Request the status from the CM11A interface.
+ *
+ * @author Jesse Peterson
+ */
+ public void updateStatus()
+ {
+ updateStatus(null);
+ }
+
+ /**
+ * Request the status from the CM11A interface.
+ *
+ * @param statusListener Notification is sent to the listener
+ *
+ *
+ * @author Jesse Peterson
+ */
+ public void updateStatus(CM11AStatusListener statusListener)
+ {
+ // If deallocating resouces, throw an error
+ if (testGatewayState(Gateway.DEALLOCATING_RESOURCES |
+ Gateway.DEALLOCATED))
+ {
+ throw new GatewayStateError("Can not transmit. Transmitter is currently in the DEALLOCATING_RESOURCES or DEALLOCATED state.");
+ }
+
+ try
+ {
+ waitGatewayState(Gateway.ALLOCATED);
+ }
+ catch (InterruptedException e)
+ {
+ throw new GatewayStateError("Caught InterruptedException while waiting for the gateway to enter an ALLOCATED state: " + e.getMessage());
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new GatewayStateError("Caught IllegalArgumentException while waiting for the gateway to enter an ALLOCATED state: " + e.getMessage());
+ }
+
+ transmissionQueue.addElement(new CM11AStatusTransmission(this, statusListener));
+ stateTransition(Transmitter.QUEUE_NOT_EMPTY);
+ shouldProcess.setTrue();
+ }
+
+ /**
+ * Get the house code that the CM11A is configured to monitor. The
+ * CM11A device will record changes to devices on the monitored house
+ * code. It record the on/off status and if a device is dimmed or not.
+ * The data can be retrieved from the methods getOnOffStatus,
+ * getDimStatus, get last addressed device. Use
+ * setClock to change the monitored house code.
+ *
+ * @return The character from 'A' through 'P' that indicates the
+ * house code that is being monitored.
+ * @see setClock
+ *
+ * @author Jesse Peterson
+ */
+ public char getMonitoredHouseCode()
+ {
+ return(monitoredHouseCode);
+ }
+
+ /**
+ * Indication of the On/Off status as the CM11A sees it for the
+ * monitored house code. The value is set after a call to
+ * updateStatus.
+ *
+ * @return The bit is set (true) if the device is on, not set (false)
+ * if the device is off. The bit index indicates the device:
+ * bit index 0 = device 1, bit index 1 = device 2, ...,
+ * bit index 15 = device 16.
+ * @see updateStatus
+ *
+ * @author Jesse Peterson
+ */
+ public BitSet getOnOffStatus()
+ {
+ return(onOffStatus);
+ }
+
+ /**
+ * Indication of the dim status as the CM11A sees it for the
+ * monitored house code. The value is set after a call to
+ * updateStatus.
+ *
+ * @return The bit is set (true) if the device is dimmed, not set (false)
+ * if the device is not dimmed. The bit index indicates the device:
+ * bit index 0 = device 1, bit index 1 = device 2, ...,
+ * bit index 15 = device 16.
+ * @see updateStatus
+ *
+ * @author Jesse Peterson
+ */
+ public BitSet getDimStatus()
+ {
+ return(dimStatus);
+ }
+
+ /**
+ * Indication of the last addressed device as the CM11A sees it for the
+ * monitored house code. The value is set after a call to
+ * updateStatus.
+ *
+ * @return The bit is set (true) if the device was addressed, not set (false)
+ * if the device was not addressed. The bit index indicates the device:
+ * bit index 0 = device 1, bit index 1 = device 2, ...,
+ * bit index 15 = device 16.
+ * @see updateStatus
+ * @see setClock
+ *
+ * @author Jesse Peterson
+ */
+ public BitSet getLastAddressedDevice()
+ {
+ return(lastAddressedDevice);
+ }
+
+ /**
+ * Retrieve the CM11A's idea of what the current day is. The value is
+ * initialized after a call to updateStatus().
+ *
+ * @return The CM11A's idea of what the current day is. Will be one of
+ * Calendar.SUNDAY, Calendar.MONDAY, Calendar.TUESDAY,
+ * Calendar.WEDNESDAY, Calendar.THURSDAY, Calendar.FRIDAY,
+ * Calendar.SATURDAY.
+ * @see updateStatus
+ * @see setClock
+ *
+ * @author Jesse Peterson
+ */
+ public int getCurrentDay()
+ {
+ return(currentDay);
+ }
+
+ /**
+ * Retrieve the CM11A's idea of the current day of the year. The value
+ * is zero based; 0 for January 1, 31 for February 1, ... The value is
+ * initialized after a call to updateStatus().
+ *
+ * The utility methods CM11A.extractMonth() and
+ * CM11A.extractDay() have been provided to convert this
+ * value into month and day representations.
+ *
+ * As far as I can tell, the CM11A has no way of determining
+ * leap years. It therefore always uses 366 days in a year. The
+ * caller is responsible for determining if the current day
+ * has been corrected for a non-leap year.
+ *
+ * @return Day of year.
+ * @see extractMonth
+ * @see extractDay
+ *
+ * @author Jesse Peterson
+ */
+ public int getJulianDay()
+ {
+ return(julianDay);
+ }
+
+ /**
+ * Retrieve the CM11A's idea of what the current hour is. The value is
+ * initialized after a call to updateStatus().
+ *
+ * @return The CM11A's idea of what the current hour is. Expressed
+ * as 24 hour value.
+ * @see updateStatus
+ * @see setClock
+ *
+ * @author Jesse Peterson
+ */
+ public int getHours()
+ {
+ return(hours);
+ }
+
+ /**
+ * Retrieve the CM11A's idea of what the current minute is. The value is
+ * initialized after a call to updateStatus().
+ *
+ * @return The CM11A's idea of what the current minute is.
+ * @see updateStatus
+ * @see setClock
+ *
+ * @author Jesse Peterson
+ */
+ public int getMinutes()
+ {
+ return(minutes);
+ }
+
+ /**
+ * Retrieve the CM11A's idea of what the current second is. The value is
+ * initialized after a call to updateStatus().
+ *
+ * @return The CM11A's idea of what the current second is.
+ * @see updateStatus
+ * @see setClock
+ *
+ * @author Jesse Peterson
+ */
+ public int getSeconds()
+ {
+ return(seconds);
+ }
+
+ /**
+ * Retrieve the CM11A's idea of what the current battery usage is.
+ * The value is initialized after a call to updateStatus().
+ *
+ * @return The