Index: /trunk/Tests/SimpleTests/bindUnbind.html =================================================================== --- /trunk/Tests/SimpleTests/bindUnbind.html (revision 2) +++ /trunk/Tests/SimpleTests/bindUnbind.html (revision 2) @@ -0,0 +1,38 @@ + + + Bind / Unbind test + + + + + Index: /trunk/CMakeConf.txt =================================================================== --- /trunk/CMakeConf.txt (revision 2) +++ /trunk/CMakeConf.txt (revision 2) @@ -0,0 +1,36 @@ +############################################### +# Ivy Support +############################################### +IF (WEBKIT_USE_ADDONS_IVY) + + #Check Ivy presence + FIND_PATH(IVY_DIR Ivycpp.h + /usr/include /usr/include/Ivy + /usr/local/include /usr/local/include/Ivy) + + FIND_LIBRARY(IVYLIB_DIR NAMES ivy PATH /usr/lib /usr/local/lib) + + IF(IVY_DIR AND IVYLIB_DIR) + MESSAGE ("ivy C++ found with this parameter for lib : ${IVY_DIR}") + ELSE (IVY_DIR AND IVYLIB_DIR) + MESSAGE (FATAL_ERROR "Could not find ivy C++") + ENDIF (IVY_DIR AND IVYLIB_DIR) + + ADD_DEFINITIONS (-D__IVY__) + INCLUDE_DIRECTORIES( + ${CMAKE_CURRENT_SOURCE_DIR}/AddOns/Implementations/Ivy + ${CMAKE_CURRENT_BINARY_DIR}/generated_sources/AddOns/Implementations/Ivy) + + CREATE_LUT(OwbIvy_SRC AddOns/Implementations/Ivy/IvyRequest.cpp + generated_sources/AddOns/Implementations/Ivy/IvyRequest.lut.h + AddOns/Implementations/Ivy/IvyRequest.cpp) + + #CMAKE_CURRENT... added + INCLUDE (${CMAKE_CURRENT_SOURCE_DIR}/AddOns/Implementations/Ivy/SourcesCMakeLists.txt) + + ADD_LIBRARY (OwbIvy ${OwbIvy_SRC}) + ADD_DEPENDENCIES (OwbIvy webcore-owb) + + SET (ADDONS_LINK "${ADDONS_LINK};OwbIvy;Ivy") + +ENDIF (WEBKIT_USE_ADDONS_IVY) Index: /trunk/TODO =================================================================== --- /trunk/TODO (revision 2) +++ /trunk/TODO (revision 2) @@ -0,0 +1,8 @@ +IvyCore: + +- add support for IvyDirectMessage (callback and send) +- add support for IvyDieCallBack (callback) + +Tests : + +- add some stress tests Index: /trunk/Docs/jsAPI.dox =================================================================== --- /trunk/Docs/jsAPI.dox (revision 2) +++ /trunk/Docs/jsAPI.dox (revision 2) @@ -0,0 +1,202 @@ +/** + +@page jsAPI Javascript API + +@section Intro Introduction + +This page presents the different methods provided to control the Ivy bus. +You must be a bit familar with how Ivy works +(if not, visit Ivy page). + +The javascript object to be used to control Ivy is window.ivyRequest or ivyRequest. + +Let's now show the different methods : + +@section init Initialising the bus + +The initialisation is done by +\code +IvyRequest.init(String applicationName, String greetMessage) +\endcode + +The arguments are optionnal. +If no arguments are provided, the bus is initialised with default arguments ("OWB", "Hello") +If one of them is omited, it is ignored and the previous statement apply. +If both parameters are provided, they are used to initialise the bus. + + +@section start Starting the bus + +@warning As it is the case in Ivy, starting the bus is different from running it. So after this stage, the application is not listening on the bus. +@see @section run Running the bus + +The Ivy bus is started with +\code +IvyRequest.start(String IvyBus); +\endcode + +Once again, the paramater is optionnal but be aware that the default behaviour is to start on the loopback interface. + +The IvyBus parameter is the bus adresse and possibly the port. +For example : IvyRequest.start("192.168.1.255:2010"); + +@warning If the initialisation was not done, the method will automatically run it without arguments (default behaviour) + +@section run Running the bus + +The bus is launched with : +\code +IvyRequest.run(); +\endcode + +After starting the bus, the application is listening to the bus. All listeners that were added before the call are now binded. + +@warning The default way to prepare the bus is: +ivyRequest.init(...) -> ivyRequest.start(...) -> ivyRequest.run() +If one of the previous step was not done, ivyRequest.run() will automatically run it without arguments + +@section stop Stopping the bus + +The bus can be stopped at anytime with : +\code +IvyRequest.stop(); +\endcode + +@warning In order to keep the bus in a good state, this operation +needs to unregister all the listeners + +@section Binding listeners to the bus + +There are several types of listeners in Ivy. Currently only message, connection and disconnection listeners +supported. + +@subsection addMessageListener Message listeners + +An Ivy listener is a String that represents the regular expression to match +and a javascript function to callback. In order to register a listener, you need to +provide both to the method : +\code +IvyRequest.bindIvyMsg(callbackFunction, String regularExpression); +or +IvyRequest.addIvyMsgListener(callbackFunction, String regularExpression); +\endcode + +By default the callback method can take 3 String as arguments : the name of the application that send the message, +the host that send the message and the message itself. + +Example of a simple callback method : +\code +function mySimpleCallbackFunction(appName, hostName, message) { + alert("Message " + message + " from "+ appName + "@" + hostName); +} +\endcode + +The registration for anything would be done with : +\code +ivyRequest.bindIvyMsg(mySimpleCallbackFunction, "(.*)"); +\endcode + +Another example would be to select only the messages that +starts with "alert" : + +\code +ivyRequest.bindIvyMsg(mySimpleCallbackFunction, "$alert(.*)"); +\endcode + +Note that your function will receive only what follows alert and not "alert" +in this case. + +@subsection addConnectListener Connection Listeners + +Due to our implementation and Ivy's own limitation, you can only register on connection listener. That +listener is called whenever an application connects on the bus. + +Only one listener of this type is allowed and its binding is done with : +\code +ivyRequest.setConnectListener(callbackFunction); +\endcode + +@warning The argument is optionnal but if omited, it will +result in removing the connection listener + +The callback function can take up to 2 String that represents the application's name that has just connected and the associated host. + +Example : very simple callback +\code +function mySimpleConnectCallbackFunction(appName, hostName) { + alert("Connection from " + appName + "@" + hostName); +} +\endcode + +\subsection addDisconnectListener Disconnection Listeners + +That listener is called whenever an application disconnects from the bus. + +Only one listener of this type is allowed and its binding is done with : +\code +ivyRequest.setDisconnectListener(callbackFunction); +\endcode + +@warning The argument is optionnal but if omited, it will +result in removing the listener + +The callback function can take up to 2 String that represents the application's name that has just disconnected and the associated host (same as for connection listener). + +See previous section for an example. + + +@section Unbinding listeners to the bus + +@subsection removeMessageListener Message listener + +The unbinding takes the same arguments as the binding and can be achieved with : +\code +ivyRequest.unbindIvyMsg(callbackFunction, String regularExpression); +or +ivyRequest.removeIvyMsgListener(callbackFunction, String regularExpression); +\endcode + +The two arguments must be the same as those used when binding the listener. + +In our example, it would be +\code +ivyRequest.unbingIvyMsg(mySimpleCallbackFunction, "(.*)"); +\endcode + +@subsection removeAllMsgListeners Remove all message listener + +It can be done with the method : +\code +ivyRequest.removeAllIvyMsgListeners(); +\endcode + +@subsection removeConnectDisconnectListener Remove Connection / Disconnection Listener + +As stated in @ref addConnectListener, calling the setConnectListener without argument will +remove the connection listener. + +The same apply to setDisconnectionListener. + +@subsection removeAllListener Remove all listeners + +\code +ivyRequest.removeAllIvyListener(); +\endcode + +@section status Status + +The notion of status was included in the implementation to match XmlHttpRequest +behaviour (as it is very close to Ivy's). + +The status can be asked with +\code +ivyRequest.getStatus(); +\endcode + +The method returns a String that is one of those values : +- uninitialised : basic status (no method was called) +- initialised : ivyRequest.init was called +- ready : ivyRequest.start was called +- run : ivyRequest.run was called, the application is listening on the bus +throught its listeners +*/ Index: /trunk/Docs/Doxyfile =================================================================== --- /trunk/Docs/Doxyfile (revision 2) +++ /trunk/Docs/Doxyfile (revision 2) @@ -0,0 +1,1252 @@ +# Doxyfile 1.5.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = "Owb Ivy" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 1.0 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, +# Italian, Japanese, Japanese-en (Japanese with English messages), Korean, +# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, +# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# This tag can be used to specify the encoding used in the generated output. +# The encoding is not always determined by the language that is chosen, +# but also whether or not the output is meant for Windows or non-Windows users. +# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES +# forces the Windows encoding (this is the default for the Windows binary), +# whereas setting the tag to NO uses a Unix-style encoding (the default for +# all platforms other than Windows). + +USE_WINDOWS_ENCODING = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explicit @brief command for a brief description. + +JAVADOC_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for Java. +# For instance, namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to +# include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from the +# version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = doxylog.txt + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../Implementations/Ivy . ./UseCase/ + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py + +FILE_PATTERNS = *.c *.cpp *.h *.dox + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentstion. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a call dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a caller dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable caller graphs for selected +# functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that a graph may be further truncated if the graph's +# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH +# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), +# the graph is not depth-constrained. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, which results in a white background. +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO Index: /trunk/Docs/overviewPage.html =================================================================== --- /trunk/Docs/overviewPage.html (revision 2) +++ /trunk/Docs/overviewPage.html (revision 2) @@ -0,0 +1,156 @@ + + + + + +
+

Application message :

+

Greeting message : +

+
+
+

Bus to listen to (leave it blank if you do not know)

+

+ + +

+
+
+ + +

Once started, you cannot change previous (above) option

+

Stopping the bus will automatically deleted + all listeners

+
+
+

Message to send +

+
+
+

RegExp to listen to + +

+

Listen to application connection + + +

+

Listen to application disconnection + + +

+

+

+ +
+
+ Status : + +
+ + Index: /trunk/Docs/UseCase/IvyAlert/IvyAlert.html =================================================================== --- /trunk/Docs/UseCase/IvyAlert/IvyAlert.html (revision 2) +++ /trunk/Docs/UseCase/IvyAlert/IvyAlert.html (revision 2) @@ -0,0 +1,36 @@ + + + + + +
Everything is ok.
+ + + Index: /trunk/Docs/UseCase/UseCase.dox =================================================================== --- /trunk/Docs/UseCase/UseCase.dox (revision 2) +++ /trunk/Docs/UseCase/UseCase.dox (revision 2) @@ -0,0 +1,85 @@ +/** + +@page UseCases Use Cases + +@section Intro Introduction + +We will now present 2 applications done with the support of Ivy on OWB. +Those examples are just ways to understand how the software works and as +proof of what could be done. They are not finished but can be used as a start +for more complex application. + +The first one uses Ivy to control X10 appliances (Ivy-X10 subdirectory) and the second one uses Ivy to show alert on a web page (IvyAlert subdirectory). + +@section X10OWB X10 with Owb Ivy + +We are presenting an example of what could be done using this extension +and some X10 appliances. + +On the one end, OWB-Ivy will send command over the network over Ivy to the +other end which is an Ivy-X10 gateway. The gateway will send command to the +X10 appliances. + +@subsection OWBPart OWB-Ivy part + +This part consists of only one file : X10-OWB.html + +The file start the bus (you will need to change the bus to your +configuration inside the file). +You are presented a page on which you can choose the housecode and device code. +Once you have clicked on the button,it sends a command on the bus to the +X10-Gateway (see below for how it works). + + +@subsection X10Gat X10 Gateway + +This module uses IvyJava and X10-Jpeterson to provide a gateway between Ivy + and X10. The implementation is quite limited to lightON / lightOFF command + but it can be extended to your needs. + +- Installation + +You will need the API java.comm if it not included, you will need to download it on +Sun. +On linux, you will need to use rxtx to use it. Follow the +instructions on the page to have the java.comm fully functionnal before continuing. + +All the necessary file are in the subdirectory workspace (Eclipse workspace). + +To use it under Eclipse, import the src subdirectories into your workspace. +For the Ivy-X10-gateway, you will need the ivy-java jar located in Ivy-X10-gateway/lib +and you will need to include x10 (the other project) in your buildpath. + +You can safely ignore the absence of X10TransmissionListener. + +- Usage + +The configuration is done through the configuration.xml file which is parsed +once to determine the whole configuration. + +The module register a listener on the Ivy bus for the regular expression +\code +(X10.*) +\endcode + +The command can be given to the module by the command : + +\code +X10.command=COM.housecode=H.devicecode=D +\endcode + +where COM = ON / OFF, housecode=A..P (case insensitive) is the X10 housecode +and devicecode=1..16 is the devicecode + +If you want to look at the internals of that part, just browse the source or +the javadoc. + +@section IvyAlert Alert management through Ivy + +This use case is pretty simple and consists of only one file : IvyAlert.html + +When first started, the page display a message saying that everything is ok +(note that this output could be removed to use it on a tv screen). +When a message starting with ALERT comes on the bus, the page changes to +display the rest of the message. +*/ Index: /trunk/Docs/UseCase/Ivy-X10/Ivy-X10.html =================================================================== --- /trunk/Docs/UseCase/Ivy-X10/Ivy-X10.html (revision 2) +++ /trunk/Docs/UseCase/Ivy-X10/Ivy-X10.html (revision 2) @@ -0,0 +1,34 @@ + + + + + +

+ house code :
+ device code :
+ + +

+ + + Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/.classpath =================================================================== --- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/.classpath (revision 2) +++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/.classpath (revision 2) @@ -0,0 +1,7 @@ + + + + + + + Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/.project =================================================================== --- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/.project (revision 2) +++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/.project (revision 2) @@ -0,0 +1,17 @@ + + + x10 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/recompile.java =================================================================== --- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/recompile.java (revision 2) +++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/recompile.java (revision 2) @@ -0,0 +1,175 @@ +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 org.apache.regexp.RECompiler; +import org.apache.regexp.RESyntaxException; + +/** + * 'recompile' is a command line tool that pre-compiles one or more regular expressions + * for use with the regular expression matcher class 'RE'. For example, the command + * "java recompile a*b" produces 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);
+ *
+ * 
+ * + * By pasting this output into your code, you can construct a regular expression matcher + * (RE) object directly from the pre-compiled data (the character array re1), thus avoiding + * the overhead of compiling the expression at runtime. For example: + * + *
+ *
+ *    RE r = new RE(re1);
+ *
+ * 
+ * + * @see RE + * @see RECompiler + * + * @author Jonathan Locke + * @version $Id: recompile.java,v 1.1 2000/04/27 01:22:33 jon Exp $ + */ +public class recompile +{ + /** + * Main application entrypoint. + * @param arg Command line arguments + */ + static public void main(String[] arg) + { + // Create a compiler object + RECompiler r = new RECompiler(); + + // Print usage if arguments are incorrect + if (arg.length <= 0 || arg.length % 2 != 0) + { + System.out.println("Usage: recompile "); + System.exit(0); + } + + // Loop through arguments, compiling each + for (int i = 0; i < arg.length; i += 2) + { + try + { + // Compile regular expression + String name = arg[i]; + String pattern = arg[i+1]; + String instructions = name + "PatternInstructions"; + + // Output program as a nice, formatted character array + System.out.print("\n // Pre-compiled regular expression '" + pattern + "'\n" + + " private static char[] " + instructions + " = \n {"); + + // Compile program for pattern + REProgram program = r.compile(pattern); + + // Number of columns in output + int numColumns = 7; + + // Loop through program + char[] p = program.getInstructions(); + for (int j = 0; j < p.length; j++) + { + // End of column? + if ((j % numColumns) == 0) + { + System.out.print("\n "); + } + + // Print character as padded hex number + String hex = Integer.toHexString(p[j]); + while (hex.length() < 4) + { + hex = "0" + hex; + } + System.out.print("0x" + hex + ", "); + } + + // End of program block + System.out.println("\n };"); + System.out.println("\n private static RE " + name + "Pattern = new RE(new REProgram(" + instructions + "));"); + } + catch (RESyntaxException e) + { + System.out.println("Syntax error in expression \"" + arg[i] + "\": " + e.toString()); + } + catch (Exception e) + { + System.out.println("Unexpected exception: " + e.toString()); + } + catch (Error e) + { + System.out.println("Internal error: " + e.toString()); + } + } + } +} Index: /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/RECompiler.java =================================================================== --- /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/RECompiler.java (revision 2) +++ /trunk/Docs/UseCase/Ivy-X10/workspace/x10/src/org/apache/regexp/RECompiler.java (revision 2) @@ -0,0 +1,1546 @@ +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 org.apache.regexp.RE; +import java.util.Hashtable; + +/** + * A regular expression compiler class. This class compiles a pattern string into a + * regular expression program interpretable by the RE evaluator class. The 'recompile' + * command line tool uses this compiler to pre-compile regular expressions for use + * with RE. For a description of the syntax accepted by RECompiler and what you can + * do with regular expressions, see the documentation for the RE matcher class. + * + * @see RE + * @see recompile + * + * @author Jonathan Locke + * @author Michael McCallum + * @version $Id: RECompiler.java,v 1.11 2003/09/01 18:31:53 vgritsenko Exp $ + */ +public class RECompiler +{ + // The compiled program + char[] instruction; // The compiled RE 'program' instruction buffer + int lenInstruction; // The amount of the program buffer currently in use + + // Input state for compiling regular expression + String pattern; // Input string + int len; // Length of the pattern string + int idx; // Current input index into ac + int parens; // Total number of paren pairs + + // Node flags + static final int NODE_NORMAL = 0; // No flags (nothing special) + static final int NODE_NULLABLE = 1; // True if node is potentially null + static final int NODE_TOPLEVEL = 2; // True if top level expr + + // Special types of 'escapes' + static final char ESC_MASK = 0xfff0; // Escape complexity mask + static final char ESC_BACKREF = 0xffff; // Escape is really a backreference + static final char ESC_COMPLEX = 0xfffe; // Escape isn't really a true character + static final char ESC_CLASS = 0xfffd; // Escape represents a whole class of characters + + // {m,n} stacks + int maxBrackets = 10; // Maximum number of bracket pairs + static final int bracketUnbounded = -1; // Unbounded value + int brackets = 0; // Number of bracket sets + int[] bracketStart = null; // Starting point + int[] bracketEnd = null; // Ending point + int[] bracketMin = null; // Minimum number of matches + int[] bracketOpt = null; // Additional optional matches + + // Lookup table for POSIX character class names + static Hashtable hashPOSIX = new Hashtable(); + static + { + hashPOSIX.put("alnum", new Character(RE.POSIX_CLASS_ALNUM)); + hashPOSIX.put("alpha", new Character(RE.POSIX_CLASS_ALPHA)); + hashPOSIX.put("blank", new Character(RE.POSIX_CLASS_BLANK)); + hashPOSIX.put("cntrl", new Character(RE.POSIX_CLASS_CNTRL)); + hashPOSIX.put("digit", new Character(RE.POSIX_CLASS_DIGIT)); + hashPOSIX.put("graph", new Character(RE.POSIX_CLASS_GRAPH)); + hashPOSIX.put("lower", new Character(RE.POSIX_CLASS_LOWER)); + hashPOSIX.put("print", new Character(RE.POSIX_CLASS_PRINT)); + hashPOSIX.put("punct", new Character(RE.POSIX_CLASS_PUNCT)); + hashPOSIX.put("space", new Character(RE.POSIX_CLASS_SPACE)); + hashPOSIX.put("upper", new Character(RE.POSIX_CLASS_UPPER)); + hashPOSIX.put("xdigit", new Character(RE.POSIX_CLASS_XDIGIT)); + hashPOSIX.put("javastart", new Character(RE.POSIX_CLASS_JSTART)); + hashPOSIX.put("javapart", new Character(RE.POSIX_CLASS_JPART)); + } + + /** + * Constructor. Creates (initially empty) storage for a regular expression program. + */ + public RECompiler() + { + // Start off with a generous, yet reasonable, initial size + instruction = new char[128]; + lenInstruction = 0; + } + + /** + * Ensures that n more characters can fit in the program buffer. + * If n more can't fit, then the size is doubled until it can. + * @param n Number of additional characters to ensure will fit. + */ + void ensure(int n) + { + // Get current program length + int curlen = instruction.length; + + // If the current length + n more is too much + if (lenInstruction + n >= curlen) + { + // Double the size of the program array until n more will fit + while (lenInstruction + n >= curlen) + { + curlen *= 2; + } + + // Allocate new program array and move data into it + char[] newInstruction = new char[curlen]; + System.arraycopy(instruction, 0, newInstruction, 0, lenInstruction); + instruction = newInstruction; + } + } + + /** + * Emit a single character into the program stream. + * @param c Character to add + */ + void emit(char c) + { + // Make room for character + ensure(1); + + // Add character + instruction[lenInstruction++] = c; + } + + /** + * 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) + { + // Make room for a new node + ensure(RE.nodeSize); + + // Move everything from insertAt to the end down nodeSize elements + System.arraycopy(instruction, insertAt, instruction, insertAt + RE.nodeSize, lenInstruction - insertAt); + instruction[insertAt + RE.offsetOpcode] = opcode; + instruction[insertAt + RE.offsetOpdata] = (char)opdata; + instruction[insertAt + RE.offsetNext] = 0; + lenInstruction += RE.nodeSize; + } + + /** + * 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) + { + // Traverse the chain until the next offset is 0 + int next = instruction[node + RE.offsetNext]; + // while the 'node' is not the last in the chain + // and the 'node' is not the last in the program. + while ( next != 0 && node < lenInstruction ) + { + // if the node we are supposed to point to is in the chain then + // point to the end of the program instead. + // Michael McCallum + // FIXME: // This is a _hack_ to stop infinite programs. + // I believe that the implementation of the reluctant matches is wrong but + // have not worked out a better way yet. + if ( node == pointTo ) { + pointTo = lenInstruction; + } + node += next; + next = instruction[node + RE.offsetNext]; + } + // if we have reached the end of the program then dont set the pointTo. + // im not sure if this will break any thing but passes all the tests. + if ( node < lenInstruction ) { + // Point the last node in the chain to pointTo. + instruction[node + RE.offsetNext] = (char)(short)(pointTo - node); + } + } + + /** + * Adds a new node + * @param opcode Opcode for node + * @param opdata Opdata for node (only the low 16 bits are currently used) + * @return Index of new node in program + */ + int node(char opcode, int opdata) + { + // Make room for a new node + ensure(RE.nodeSize); + + // Add new node at end + instruction[lenInstruction + RE.offsetOpcode] = opcode; + instruction[lenInstruction + RE.offsetOpdata] = (char)opdata; + instruction[lenInstruction + RE.offsetNext] = 0; + lenInstruction += RE.nodeSize; + + // Return index of new node + return lenInstruction - RE.nodeSize; + } + + + /** + * Throws a new internal error exception + * @exception Error Thrown in the event of an internal error. + */ + void internalError() throws Error + { + throw new Error("Internal error!"); + } + + /** + * Throws a new syntax error exception + * @exception RESyntaxException Thrown if the regular expression has invalid syntax. + */ + void syntaxError(String s) throws RESyntaxException + { + throw new RESyntaxException(s); + } + + /** + * Allocate storage for brackets only as needed + */ + void allocBrackets() + { + // Allocate bracket stacks if not already done + if (bracketStart == null) + { + // Allocate storage + bracketStart = new int[maxBrackets]; + bracketEnd = new int[maxBrackets]; + bracketMin = new int[maxBrackets]; + bracketOpt = new int[maxBrackets]; + + // Initialize to invalid values + for (int i = 0; i < maxBrackets; i++) + { + bracketStart[i] = bracketEnd[i] = bracketMin[i] = bracketOpt[i] = -1; + } + } + } + + /** Enlarge storage for brackets only as needed. */ + synchronized void reallocBrackets() { + // trick the tricky + if (bracketStart == null) { + allocBrackets(); + } + + int new_size = maxBrackets * 2; + int[] new_bS = new int[new_size]; + int[] new_bE = new int[new_size]; + int[] new_bM = new int[new_size]; + int[] new_bO = new int[new_size]; + // Initialize to invalid values + for (int i=brackets; i= 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 EEL0
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 EEL0
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