From 9d0ea6438839097471b4adc892b9703e8a5d2c48 Mon Sep 17 00:00:00 2001 From: Felix Ruess Date: Fri, 10 Dec 2010 15:53:33 +0100 Subject: [PATCH] fix line endings in Paparazzi On the Web files --- .../WebContent/CSS/design.css | 420 +- .../WebContent/CSS/designHelp.css | 12 +- .../WebContent/CSS/designLogOut.css | 22 +- .../WebContent/CSS/designWelcome.css | 48 +- .../WebContent/CSS/designbackup.css | 172 +- .../WebContent/CSS/dtree.css | 66 +- .../WebContent/META-INF/MANIFEST.MF | 6 +- .../WebContent/conf/pow_conf.xml | 48 +- .../WebContent/js/DOMImplementation.js | 48 +- .../WebContent/js/XHR_object.js | 40 +- .../WebContent/js/browserdetect.js | 194 +- .../eclipse ServletPow/WebContent/js/menu1.js | 306 +- .../eclipse ServletPow/WebContent/js/menu2.js | 186 +- .../WebContent/js/prototype.js | 9748 ++++++++--------- .../WebContent/js/tabber.js | 1070 +- .../pushlet/client/PushletClient.java | 1396 +-- .../pushlet/client/PushletClientListener.java | 92 +- .../pushlet/core/BrowserAdapter.java | 406 +- .../pushlet/core/ClientAdapter.java | 144 +- .../justobjects/pushlet/core/Dispatcher.java | 530 +- .../nl/justobjects/pushlet/core/Event.java | 368 +- .../pushlet/core/EventPullSource.java | 370 +- .../justobjects/pushlet/core/EventQueue.java | 538 +- .../justobjects/pushlet/core/EventSource.java | 158 +- .../pushlet/core/EventSourceManager.java | 350 +- .../pushlet/core/SerializedAdapter.java | 198 +- .../justobjects/pushlet/core/Subscriber.java | 938 +- .../justobjects/pushlet/core/XMLAdapter.java | 274 +- .../justobjects/pushlet/servlet/Pushlet.java | 588 +- .../pushlet/util/DefaultLogger.java | 326 +- .../src/nl/justobjects/pushlet/util/Log.java | 354 +- .../justobjects/pushlet/util/Log4jLogger.java | 268 +- .../pushlet/util/PushletLogger.java | 188 +- .../src/pow/ivyclient/BusIvy_.java | 180 +- .../src/pow/webserver/Conf.java | 328 +- .../src/pow/webserver/Log.java | 144 +- .../pushlet/client/PushletClient.java | 1396 +-- .../pushlet/client/PushletClientListener.java | 92 +- .../pushlet/core/BrowserAdapter.java | 406 +- .../pushlet/core/ClientAdapter.java | 144 +- .../justobjects/pushlet/core/Dispatcher.java | 530 +- .../nl/justobjects/pushlet/core/Event.java | 368 +- .../pushlet/core/EventPullSource.java | 370 +- .../justobjects/pushlet/core/EventQueue.java | 538 +- .../justobjects/pushlet/core/EventSource.java | 140 +- .../pushlet/core/EventSourceManager.java | 338 +- .../pushlet/core/SerializedAdapter.java | 198 +- .../justobjects/pushlet/core/Subscriber.java | 938 +- .../justobjects/pushlet/core/XMLAdapter.java | 274 +- .../justobjects/pushlet/servlet/Pushlet.java | 586 +- .../pushlet/test/PushletApplet.java | 350 +- .../pushlet/test/PushletPingApplication.java | 352 +- .../pushlet/test/TestEventPullSources.java | 546 +- .../pushlet/test/TestEventPushSources.java | 672 +- .../pushlet/util/DefaultLogger.java | 326 +- .../src/nl/justobjects/pushlet/util/Log.java | 354 +- .../justobjects/pushlet/util/Log4jLogger.java | 268 +- .../pushlet/util/PushletLogger.java | 188 +- .../pow/pow/WebContent/CSS/design.css | 400 +- .../pow/pow/WebContent/CSS/designHelp.css | 12 +- .../pow/pow/WebContent/CSS/designLogOut.css | 22 +- .../pow/pow/WebContent/CSS/designWelcome.css | 48 +- .../pow/pow/WebContent/CSS/designbackup.css | 172 +- .../pow/pow/WebContent/CSS/dtree.css | 66 +- .../pow/pow/WebContent/META-INF/MANIFEST.MF | 6 +- .../pow/pow/WebContent/conf/pow.conf | 68 +- .../pow/WebContent/js/DOMImplementation.js | 48 +- .../pow/pow/WebContent/js/XHR_object.js | 40 +- .../pow/pow/WebContent/js/browserdetect.js | 194 +- sw/in_progress/pow/pow/WebContent/js/menu1.js | 306 +- sw/in_progress/pow/pow/WebContent/js/menu2.js | 186 +- .../pow/pow/WebContent/js/prototype.js | 9748 ++++++++--------- .../pow/pow/WebContent/js/tabber.js | 1070 +- .../pushlet/client/PushletClient.java | 1396 +-- .../pushlet/client/PushletClientListener.java | 92 +- .../pushlet/core/BrowserAdapter.java | 406 +- .../pushlet/core/ClientAdapter.java | 144 +- .../justobjects/pushlet/core/Dispatcher.java | 530 +- .../nl/justobjects/pushlet/core/Event.java | 368 +- .../pushlet/core/EventPullSource.java | 370 +- .../justobjects/pushlet/core/EventQueue.java | 538 +- .../justobjects/pushlet/core/EventSource.java | 158 +- .../pushlet/core/EventSourceManager.java | 350 +- .../pushlet/core/SerializedAdapter.java | 198 +- .../justobjects/pushlet/core/Subscriber.java | 938 +- .../justobjects/pushlet/core/XMLAdapter.java | 274 +- .../justobjects/pushlet/servlet/Pushlet.java | 586 +- .../pushlet/util/DefaultLogger.java | 326 +- .../src/nl/justobjects/pushlet/util/Log.java | 354 +- .../justobjects/pushlet/util/Log4jLogger.java | 268 +- .../pushlet/util/PushletLogger.java | 188 +- sw/in_progress/pow/pow/src/pow/BusIvy_.java | 120 +- sw/in_progress/pow/pow/src/pow/Conf.java | 460 +- sw/in_progress/pow/pow/src/pow/log.java | 136 +- 94 files changed, 25242 insertions(+), 25242 deletions(-) diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/CSS/design.css b/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/CSS/design.css index 7903f3723e..c982ac6974 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/CSS/design.css +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/CSS/design.css @@ -1,44 +1,44 @@ -body -{ - background-color: #CCFFCC; - margin: 0%; - padding: 0%; - outline: 0%; - height: 100%; - overflow:hidden; - max-width:2048px; - font-size : 11; -} - -select{ - font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; - font-size: 11px; - vertical-align: middle; - background-color: #F5F5DC; -} -input { - background-color:#F5F5DC; - font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; - font-size: 10px; -} - -label { - font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; - font-size: 11px; -} - -#welcome -{ - position:absolute; - top:0; - left:0; - height:3%; - width: 100%; - background-color: #EEEEEE; - text-align: center; - font-weight:bold; - font-size : 12; -} +body +{ + background-color: #CCFFCC; + margin: 0%; + padding: 0%; + outline: 0%; + height: 100%; + overflow:hidden; + max-width:2048px; + font-size : 11; +} + +select{ + font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; + font-size: 11px; + vertical-align: middle; + background-color: #F5F5DC; +} +input { + background-color:#F5F5DC; + font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; + font-size: 10px; +} + +label { + font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; + font-size: 11px; +} + +#welcome +{ + position:absolute; + top:0; + left:0; + height:3%; + width: 100%; + background-color: #EEEEEE; + text-align: center; + font-weight:bold; + font-size : 12; +} #usr { position:absolute; @@ -46,175 +46,175 @@ label { right:6%; height:3%; width:25%; - background-color: #EEEEEE; - text-align: right; + background-color: #EEEEEE; + text-align: right; white-space:nowrap; -} -#page -{ -position:absolute; -top:3%; -left:0; -height:97%; -width: 100%; -} - - -#choicePanel{ - position:absolute; - top:0%; - left:0%; - height: 13%; - width : 15%; - background-color: #EEEEEE; - border: 1px solid black; -} - -#aircraftSelector -{ - text-align: center; - background-color: #EEEEEE; -} - -#trackdiv -{ - text-align: center; - background-color: #EEEEEE; - -moz-border-radius: 7px 7px 7px 7px; - -webkit-border-radius: 7px 7px 7px 7px; - border-radius: 7px 7px 7px 7px; - -webkit-border-top-left-radius: 7px; /* pour Chrome */ - -webkit-border-top-right-radius: 7px; /* pour Chrome */ - -webkit-border-bottom-left-radius: 7px; /* pour Chrome */ - -webkit-border-bottom-right-radius: 7px; /* pour Chrome */ - width: 140px; - color: white; - vertical-align:middle; -} - -#active_block -{ - font-size:11; - text-align: center; -} - -#FlightPlan -{ - overflow:auto; - position:absolute; - top:0%; - left:15%; - height: 40%; - width : 14.9%; - background-color: #EEEEEE; - border: 1px solid black; -} - -#FlightParams -{ - position:absolute; - top:13%; - left :0% - text-align: center; - height: 27%; - width : 14.9%; - border: 1px solid black; - background-color: #EEEEEE; -} - -#map_canvas -{ - position:absolute; - top:0; - left:30%; - width:70%; +} +#page +{ +position:absolute; +top:3%; +left:0; +height:97%; +width: 100%; +} + + +#choicePanel{ + position:absolute; + top:0%; + left:0%; + height: 13%; + width : 15%; + background-color: #EEEEEE; + border: 1px solid black; +} + +#aircraftSelector +{ + text-align: center; + background-color: #EEEEEE; +} + +#trackdiv +{ + text-align: center; + background-color: #EEEEEE; + -moz-border-radius: 7px 7px 7px 7px; + -webkit-border-radius: 7px 7px 7px 7px; + border-radius: 7px 7px 7px 7px; + -webkit-border-top-left-radius: 7px; /* pour Chrome */ + -webkit-border-top-right-radius: 7px; /* pour Chrome */ + -webkit-border-bottom-left-radius: 7px; /* pour Chrome */ + -webkit-border-bottom-right-radius: 7px; /* pour Chrome */ + width: 140px; + color: white; + vertical-align:middle; +} + +#active_block +{ + font-size:11; + text-align: center; +} + +#FlightPlan +{ + overflow:auto; + position:absolute; + top:0%; + left:15%; + height: 40%; + width : 14.9%; + background-color: #EEEEEE; + border: 1px solid black; +} + +#FlightParams +{ + position:absolute; + top:13%; + left :0% + text-align: center; + height: 27%; + width : 14.9%; + border: 1px solid black; + background-color: #EEEEEE; +} + +#map_canvas +{ + position:absolute; + top:0; + left:30%; + width:70%; height: 95%; - border:1px solid black; -} - - -#Settings -{ - overflow:auto; - position:absolute; + border:1px solid black; +} + + +#Settings +{ + overflow:auto; + position:absolute; left:0%; - top:40%; - text-align: left; - height: 55%; - width: 29.9%; - background-color: #EEEEEE; - border: 1px solid black; -} - -#page_setting { - -} - -#setting { - width: 400px; - height: 250px; - padding: 0.5em; - font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; - font-size: 8; -} -#param -{ - overflow:auto; -} - -#NewsDiv -{ - position:absolute; - overflow:auto; - left:0%; - top:95%; - height: 5%; - width: 100%; - text-align: left; - vertical-align:top; - background-color: #EEEEEE; - border: 1px solid black; -} - -#info -{ - text-align: left; - font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; - font-size: 11px; -} - -#Debug -{ - overflow:auto; - position:absolute; - left:65%; - top:50%; - text-align: center; - height: 50%; - width: 35%; - background-color: #EEEEEE; - border: 1px solid black; - padding-top:20px; - font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; - font-size: 11px; -} - -#title{ - font-weight:bold; - font-size:18; - text-align:center; -} - -table.param { -border:3px solid #6495ed; -border-collapse:collapse; -width:90%; -margin:auto; -} -td.param { -font-family:sans-serif; -font-size:11px; -border:1px solid #6495ed; -padding:5px; -text-align:left; -} + top:40%; + text-align: left; + height: 55%; + width: 29.9%; + background-color: #EEEEEE; + border: 1px solid black; +} + +#page_setting { + +} + +#setting { + width: 400px; + height: 250px; + padding: 0.5em; + font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; + font-size: 8; +} +#param +{ + overflow:auto; +} + +#NewsDiv +{ + position:absolute; + overflow:auto; + left:0%; + top:95%; + height: 5%; + width: 100%; + text-align: left; + vertical-align:top; + background-color: #EEEEEE; + border: 1px solid black; +} + +#info +{ + text-align: left; + font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; + font-size: 11px; +} + +#Debug +{ + overflow:auto; + position:absolute; + left:65%; + top:50%; + text-align: center; + height: 50%; + width: 35%; + background-color: #EEEEEE; + border: 1px solid black; + padding-top:20px; + font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; + font-size: 11px; +} + +#title{ + font-weight:bold; + font-size:18; + text-align:center; +} + +table.param { +border:3px solid #6495ed; +border-collapse:collapse; +width:90%; +margin:auto; +} +td.param { +font-family:sans-serif; +font-size:11px; +border:1px solid #6495ed; +padding:5px; +text-align:left; +} diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/CSS/designHelp.css b/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/CSS/designHelp.css index df08745f31..e8fcfd7a3d 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/CSS/designHelp.css +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/CSS/designHelp.css @@ -1,12 +1,12 @@ -body -{ - width: 90%; - margin-top: 5px; +body +{ + width: 90%; + margin-top: 5px; margin-bottom: 5px; margin-left:5%; - margin-reight:5%; + margin-reight:5%; background-color: #CCFFCC; - text-align:justify; + text-align:justify; } h3,h2 diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/CSS/designLogOut.css b/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/CSS/designLogOut.css index 02a1a63f3f..c6ce91f1e9 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/CSS/designLogOut.css +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/CSS/designLogOut.css @@ -1,12 +1,12 @@ -body -{ - background-color: #CCFFCC; - margin-top: 2%; - padding: 0%; - outline: 0%; - height: 100%; - overflow:hidden; - max-width:2048px; - text-align:center; - font-size:24px; +body +{ + background-color: #CCFFCC; + margin-top: 2%; + padding: 0%; + outline: 0%; + height: 100%; + overflow:hidden; + max-width:2048px; + text-align:center; + font-size:24px; } \ No newline at end of file diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/CSS/designWelcome.css b/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/CSS/designWelcome.css index e6cd8076f0..fe096f7074 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/CSS/designWelcome.css +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/CSS/designWelcome.css @@ -1,30 +1,30 @@ -body -{ - width: 960px; - margin-top: 100px; +body +{ + width: 960px; + margin-top: 100px; margin-bottom: 5px; background-image: url("Icons/logo.png"); - background-repeat:no-repeat; + background-repeat:no-repeat; background-color: #CCFFCC; - -} - -#signIn -{ - margin: auto; - width: 300px; - height: 140px; - border: 1px solid black; -} - -#log -{ - margin-left: 30px; -} - -a + +} + +#signIn { - position:absolute; + margin: auto; + width: 300px; + height: 140px; + border: 1px solid black; +} + +#log +{ + margin-left: 30px; +} + +a +{ + position:absolute; right:1%; - top:80%; + top:80%; } \ No newline at end of file diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/CSS/designbackup.css b/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/CSS/designbackup.css index b9ea91607d..b00585c71d 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/CSS/designbackup.css +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/CSS/designbackup.css @@ -1,87 +1,87 @@ -body -{ - background-color: #CCFFCC; - margin: 0%; - padding: 0%; - outline: 0%; - height: 95%; -} -#page -{ - width: 100%; - height: 95%; -} - -#logo -{ - width: 960px; - height: 100px; - background-image: url("banniere.jpg"); - background-repeat: repeat-x; - margin-bottom: 10px; -} - -#leftmenu -{ - /* float: left; /* Le menu flottera à gauche */ - /* width: 120px; *//* Très important : donner une taille au menu */ -} -#welcome -{ - text-align: center; - background-color: #EEEEEE; - border: 2px solid black; - margin-bottom: 10px; /* Pour éviter que les éléments du menu ne soient trop collés */ -} -#choice -{ -float: left; - text-align: center; - background-color: #EEEEEE; - border: 2px solid black; - height: 190px; - width: 20px; -} -#map_canvas -{ - width: 690px; - height: 350px; - margin-left: 125px; -} - -#FlightPlan -{ - float: right; - width: 135px; /* Très important : donner une taille au menu */ - height: 345px; - border: 2px solid black; - background-color: #EEEEEE; -} - - - -#ControlPanel -{ - float: left; - text-align: center; - height: 150px; - width: 600px; - border: 2px solid black; - background-color: #EEEEEE; -} -#FlightParams -{ - text-align: center; - float: right; - height: 150px; - width: 350px; - border: 2px solid black; - background-color: #EEEEEE; -} -table -{ - margin-left: 20px; - margin-bottom: 20px; -} - +body +{ + background-color: #CCFFCC; + margin: 0%; + padding: 0%; + outline: 0%; + height: 95%; +} +#page +{ + width: 100%; + height: 95%; +} + +#logo +{ + width: 960px; + height: 100px; + background-image: url("banniere.jpg"); + background-repeat: repeat-x; + margin-bottom: 10px; +} + +#leftmenu +{ + /* float: left; /* Le menu flottera à gauche */ + /* width: 120px; *//* Très important : donner une taille au menu */ +} +#welcome +{ + text-align: center; + background-color: #EEEEEE; + border: 2px solid black; + margin-bottom: 10px; /* Pour éviter que les éléments du menu ne soient trop collés */ +} +#choice +{ +float: left; + text-align: center; + background-color: #EEEEEE; + border: 2px solid black; + height: 190px; + width: 20px; +} +#map_canvas +{ + width: 690px; + height: 350px; + margin-left: 125px; +} + +#FlightPlan +{ + float: right; + width: 135px; /* Très important : donner une taille au menu */ + height: 345px; + border: 2px solid black; + background-color: #EEEEEE; +} + + + +#ControlPanel +{ + float: left; + text-align: center; + height: 150px; + width: 600px; + border: 2px solid black; + background-color: #EEEEEE; +} +#FlightParams +{ + text-align: center; + float: right; + height: 150px; + width: 350px; + border: 2px solid black; + background-color: #EEEEEE; +} +table +{ + margin-left: 20px; + margin-bottom: 20px; +} + \ No newline at end of file diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/CSS/dtree.css b/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/CSS/dtree.css index ccc20f8c35..b201c2fd60 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/CSS/dtree.css +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/CSS/dtree.css @@ -1,34 +1,34 @@ -/*--------------------------------------------------| -| dTree 2.05 | www.destroydrop.com/javascript/tree/ | -|---------------------------------------------------| -| Copyright (c) 2002-2003 Geir Landrö | -|--------------------------------------------------*/ - -.dtree { - font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; - font-size: 11px; - color: #666; - white-space: nowrap; -} -.dtree img { - border: 0px; - vertical-align: middle; -} -.dtree a { - color: #333; - text-decoration: none; -} -.dtree a.node, .dtree a.nodeSel { - white-space: nowrap; - padding: 1px 2px 1px 2px; -} -.dtree a.node:hover, .dtree a.nodeSel:hover { - color: #333; - text-decoration: underline; -} -.dtree a.nodeSel { - background-color: #c0d2ec; -} -.dtree .clip { - overflow: hidden; +/*--------------------------------------------------| +| dTree 2.05 | www.destroydrop.com/javascript/tree/ | +|---------------------------------------------------| +| Copyright (c) 2002-2003 Geir Landrö | +|--------------------------------------------------*/ + +.dtree { + font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; + font-size: 11px; + color: #666; + white-space: nowrap; +} +.dtree img { + border: 0px; + vertical-align: middle; +} +.dtree a { + color: #333; + text-decoration: none; +} +.dtree a.node, .dtree a.nodeSel { + white-space: nowrap; + padding: 1px 2px 1px 2px; +} +.dtree a.node:hover, .dtree a.nodeSel:hover { + color: #333; + text-decoration: underline; +} +.dtree a.nodeSel { + background-color: #c0d2ec; +} +.dtree .clip { + overflow: hidden; } \ No newline at end of file diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/META-INF/MANIFEST.MF b/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/META-INF/MANIFEST.MF index 5e9495128c..254272e1c0 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/META-INF/MANIFEST.MF +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/META-INF/MANIFEST.MF @@ -1,3 +1,3 @@ -Manifest-Version: 1.0 -Class-Path: - +Manifest-Version: 1.0 +Class-Path: + diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/conf/pow_conf.xml b/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/conf/pow_conf.xml index 23600da6cd..947a6b35b7 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/conf/pow_conf.xml +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/conf/pow_conf.xml @@ -1,24 +1,24 @@ - - - 8535 - 8536 - 1024 - 10000 - pow_sql - truesilentpow_user - pwdpow_user - admin - admin@pow.fr - - 1200000 - - 60000 - - -10000 - -5000 - -30000 - 30000 - + + + 8535 + 8536 + 1024 + 10000 + pow_sql + truesilentpow_user + pwdpow_user + admin + admin@pow.fr + + 1200000 + + 60000 + + +10000 + +5000 + +30000 + 30000 + diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/js/DOMImplementation.js b/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/js/DOMImplementation.js index 5e94107932..75c17e11d6 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/js/DOMImplementation.js +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/js/DOMImplementation.js @@ -1,24 +1,24 @@ -function DOMImplementation(sUrl, fCallback) { - var dom; - if(window.ActiveXObject) { - dom = new ActiveXObject("Microsoft.XMLDOM"); - dom.onreadystatechange = function() { - if(dom.readyState == 4) { - //alert("win "+sUrl+" loaded"); - fCallback(dom); - } - }; - } - else if(document.implementation && document.implementation.createDocument) { - dom = document.implementation.createDocument("", "", null); - dom.onload = function() { - //alert("other "+sUrl+" loaded"); - fCallback(dom); - } - } - else { - alert("Votre navigateur ne gère pas l'importation de fichiers XML"); - return; - } - dom.load(sUrl); -} +function DOMImplementation(sUrl, fCallback) { + var dom; + if(window.ActiveXObject) { + dom = new ActiveXObject("Microsoft.XMLDOM"); + dom.onreadystatechange = function() { + if(dom.readyState == 4) { + //alert("win "+sUrl+" loaded"); + fCallback(dom); + } + }; + } + else if(document.implementation && document.implementation.createDocument) { + dom = document.implementation.createDocument("", "", null); + dom.onload = function() { + //alert("other "+sUrl+" loaded"); + fCallback(dom); + } + } + else { + alert("Votre navigateur ne gère pas l'importation de fichiers XML"); + return; + } + dom.load(sUrl); +} diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/js/XHR_object.js b/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/js/XHR_object.js index 544a2b1a2e..8f3f022733 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/js/XHR_object.js +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/js/XHR_object.js @@ -1,20 +1,20 @@ -function getXMLHttpRequest() { - var xhr = null; - - if (window.XMLHttpRequest || window.ActiveXObject) { - if (window.ActiveXObject) { - try { - xhr = new ActiveXObject("Msxml2.XMLHTTP"); - } catch(e) { - xhr = new ActiveXObject("Microsoft.XMLHTTP"); - } - } else { - xhr = new XMLHttpRequest(); - } - } else { - alert("Votre navigateur ne supporte pas l'objet XMLHTTPRequest..."); - return null; - } - - return xhr; -} +function getXMLHttpRequest() { + var xhr = null; + + if (window.XMLHttpRequest || window.ActiveXObject) { + if (window.ActiveXObject) { + try { + xhr = new ActiveXObject("Msxml2.XMLHTTP"); + } catch(e) { + xhr = new ActiveXObject("Microsoft.XMLHTTP"); + } + } else { + xhr = new XMLHttpRequest(); + } + } else { + alert("Votre navigateur ne supporte pas l'objet XMLHTTPRequest..."); + return null; + } + + return xhr; +} diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/js/browserdetect.js b/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/js/browserdetect.js index 1e0b64da62..a8674db57f 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/js/browserdetect.js +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/js/browserdetect.js @@ -1,97 +1,97 @@ -// Browser Detect Lite v2.1.4 -// http://www.dithered.com/javascript/browser_detect/index.html -// modified by Chris Nott (chris@NOSPAMdithered.com - remove NOSPAM) - - -function BrowserDetectLite() { - var ua = navigator.userAgent.toLowerCase(); - - // browser name - this.isGecko = (ua.indexOf('gecko') != -1 && ua.indexOf('safari') == -1); - this.isMozilla = (this.isGecko && ua.indexOf('gecko/') + 14 == ua.length); - this.isNS = ( (this.isGecko) ? (ua.indexOf('netscape') != -1) : ( (ua.indexOf('mozilla') != -1) && (ua.indexOf('spoofer') == -1) && (ua.indexOf('compatible') == -1) && (ua.indexOf('opera') == -1) && (ua.indexOf('webtv') == -1) && (ua.indexOf('hotjava') == -1) ) ); - this.isIE = ( (ua.indexOf('msie') != -1) && (ua.indexOf('opera') == -1) && (ua.indexOf('webtv') == -1) ); - this.isSafari = (ua.indexOf('safari') != - 1); - this.isOpera = (ua.indexOf('opera') != -1); - this.isKonqueror = (ua.indexOf('konqueror') != -1 && !this.isSafari); - this.isIcab = (ua.indexOf('icab') != -1); - this.isAol = (ua.indexOf('aol') != -1); - - // spoofing and compatible browsers - this.isIECompatible = ( (ua.indexOf('msie') != -1) && !this.isIE); - this.isNSCompatible = ( (ua.indexOf('mozilla') != -1) && !this.isNS && !this.isMozilla); - - // browser version - this.versionMinor = parseFloat(navigator.appVersion); - - // correct version number - if (this.isNS && this.isGecko) { - this.versionMinor = parseFloat( ua.substring( ua.lastIndexOf('/') + 1 ) ); - } - else if (this.isIE && this.versionMinor >= 4) { - this.versionMinor = parseFloat( ua.substring( ua.indexOf('msie ') + 5 ) ); - } - else if (this.isMozilla) { - this.versionMinor = parseFloat( ua.substring( ua.indexOf('rv:') + 3 ) ); - } - else if (this.isSafari) { - this.versionMinor = parseFloat( ua.substring( ua.lastIndexOf('/') + 1 ) ); - } - else if (this.isOpera) { - if (ua.indexOf('opera/') != -1) { - this.versionMinor = parseFloat( ua.substring( ua.indexOf('opera/') + 6 ) ); - } - else { - this.versionMinor = parseFloat( ua.substring( ua.indexOf('opera ') + 6 ) ); - } - } - else if (this.isKonqueror) { - this.versionMinor = parseFloat( ua.substring( ua.indexOf('konqueror/') + 10 ) ); - } - else if (this.isIcab) { - if (ua.indexOf('icab/') != -1) { - this.versionMinor = parseFloat( ua.substring( ua.indexOf('icab/') + 6 ) ); - } - else { - this.versionMinor = parseFloat( ua.substring( ua.indexOf('icab ') + 6 ) ); - } - } - - this.versionMajor = parseInt(this.versionMinor); - this.geckoVersion = ( (this.isGecko) ? ua.substring( (ua.lastIndexOf('gecko/') + 6), (ua.lastIndexOf('gecko/') + 14) ) : -1 ); - - // dom support - this.isDOM1 = (document.getElementById); - this.isDOM2Event = (document.addEventListener && document.removeEventListener); - - // css compatibility mode - this.mode = document.compatMode ? document.compatMode : 'BackCompat'; - - // platform - this.isWin = (ua.indexOf('win') != -1); - this.isWin32 = (this.isWin && ( ua.indexOf('95') != -1 || ua.indexOf('98') != -1 || ua.indexOf('nt') != -1 || ua.indexOf('win32') != -1 || ua.indexOf('32bit') != -1 || ua.indexOf('xp') != -1) ); - this.isMac = (ua.indexOf('mac') != -1); - this.isUnix = (ua.indexOf('unix') != -1 || ua.indexOf('sunos') != -1 || ua.indexOf('bsd') != -1 || ua.indexOf('x11') != -1) - this.isLinux = (ua.indexOf('linux') != -1); - - // specific browser shortcuts - this.isNS4x = (this.isNS && this.versionMajor == 4); - this.isNS40x = (this.isNS4x && this.versionMinor < 4.5); - this.isNS47x = (this.isNS4x && this.versionMinor >= 4.7); - this.isNS4up = (this.isNS && this.versionMinor >= 4); - this.isNS6x = (this.isNS && this.versionMajor == 6); - this.isNS6up = (this.isNS && this.versionMajor >= 6); - this.isNS7x = (this.isNS && this.versionMajor == 7); - this.isNS7up = (this.isNS && this.versionMajor >= 7); - - this.isIE4x = (this.isIE && this.versionMajor == 4); - this.isIE4up = (this.isIE && this.versionMajor >= 4); - this.isIE5x = (this.isIE && this.versionMajor == 5); - this.isIE55 = (this.isIE && this.versionMinor == 5.5); - this.isIE5up = (this.isIE && this.versionMajor >= 5); - this.isIE6x = (this.isIE && this.versionMajor == 6); - this.isIE6up = (this.isIE && this.versionMajor >= 6); - - this.isIE4xMac = (this.isIE4x && this.isMac); -} -var browser = new BrowserDetectLite(); +// Browser Detect Lite v2.1.4 +// http://www.dithered.com/javascript/browser_detect/index.html +// modified by Chris Nott (chris@NOSPAMdithered.com - remove NOSPAM) + + +function BrowserDetectLite() { + var ua = navigator.userAgent.toLowerCase(); + + // browser name + this.isGecko = (ua.indexOf('gecko') != -1 && ua.indexOf('safari') == -1); + this.isMozilla = (this.isGecko && ua.indexOf('gecko/') + 14 == ua.length); + this.isNS = ( (this.isGecko) ? (ua.indexOf('netscape') != -1) : ( (ua.indexOf('mozilla') != -1) && (ua.indexOf('spoofer') == -1) && (ua.indexOf('compatible') == -1) && (ua.indexOf('opera') == -1) && (ua.indexOf('webtv') == -1) && (ua.indexOf('hotjava') == -1) ) ); + this.isIE = ( (ua.indexOf('msie') != -1) && (ua.indexOf('opera') == -1) && (ua.indexOf('webtv') == -1) ); + this.isSafari = (ua.indexOf('safari') != - 1); + this.isOpera = (ua.indexOf('opera') != -1); + this.isKonqueror = (ua.indexOf('konqueror') != -1 && !this.isSafari); + this.isIcab = (ua.indexOf('icab') != -1); + this.isAol = (ua.indexOf('aol') != -1); + + // spoofing and compatible browsers + this.isIECompatible = ( (ua.indexOf('msie') != -1) && !this.isIE); + this.isNSCompatible = ( (ua.indexOf('mozilla') != -1) && !this.isNS && !this.isMozilla); + + // browser version + this.versionMinor = parseFloat(navigator.appVersion); + + // correct version number + if (this.isNS && this.isGecko) { + this.versionMinor = parseFloat( ua.substring( ua.lastIndexOf('/') + 1 ) ); + } + else if (this.isIE && this.versionMinor >= 4) { + this.versionMinor = parseFloat( ua.substring( ua.indexOf('msie ') + 5 ) ); + } + else if (this.isMozilla) { + this.versionMinor = parseFloat( ua.substring( ua.indexOf('rv:') + 3 ) ); + } + else if (this.isSafari) { + this.versionMinor = parseFloat( ua.substring( ua.lastIndexOf('/') + 1 ) ); + } + else if (this.isOpera) { + if (ua.indexOf('opera/') != -1) { + this.versionMinor = parseFloat( ua.substring( ua.indexOf('opera/') + 6 ) ); + } + else { + this.versionMinor = parseFloat( ua.substring( ua.indexOf('opera ') + 6 ) ); + } + } + else if (this.isKonqueror) { + this.versionMinor = parseFloat( ua.substring( ua.indexOf('konqueror/') + 10 ) ); + } + else if (this.isIcab) { + if (ua.indexOf('icab/') != -1) { + this.versionMinor = parseFloat( ua.substring( ua.indexOf('icab/') + 6 ) ); + } + else { + this.versionMinor = parseFloat( ua.substring( ua.indexOf('icab ') + 6 ) ); + } + } + + this.versionMajor = parseInt(this.versionMinor); + this.geckoVersion = ( (this.isGecko) ? ua.substring( (ua.lastIndexOf('gecko/') + 6), (ua.lastIndexOf('gecko/') + 14) ) : -1 ); + + // dom support + this.isDOM1 = (document.getElementById); + this.isDOM2Event = (document.addEventListener && document.removeEventListener); + + // css compatibility mode + this.mode = document.compatMode ? document.compatMode : 'BackCompat'; + + // platform + this.isWin = (ua.indexOf('win') != -1); + this.isWin32 = (this.isWin && ( ua.indexOf('95') != -1 || ua.indexOf('98') != -1 || ua.indexOf('nt') != -1 || ua.indexOf('win32') != -1 || ua.indexOf('32bit') != -1 || ua.indexOf('xp') != -1) ); + this.isMac = (ua.indexOf('mac') != -1); + this.isUnix = (ua.indexOf('unix') != -1 || ua.indexOf('sunos') != -1 || ua.indexOf('bsd') != -1 || ua.indexOf('x11') != -1) + this.isLinux = (ua.indexOf('linux') != -1); + + // specific browser shortcuts + this.isNS4x = (this.isNS && this.versionMajor == 4); + this.isNS40x = (this.isNS4x && this.versionMinor < 4.5); + this.isNS47x = (this.isNS4x && this.versionMinor >= 4.7); + this.isNS4up = (this.isNS && this.versionMinor >= 4); + this.isNS6x = (this.isNS && this.versionMajor == 6); + this.isNS6up = (this.isNS && this.versionMajor >= 6); + this.isNS7x = (this.isNS && this.versionMajor == 7); + this.isNS7up = (this.isNS && this.versionMajor >= 7); + + this.isIE4x = (this.isIE && this.versionMajor == 4); + this.isIE4up = (this.isIE && this.versionMajor >= 4); + this.isIE5x = (this.isIE && this.versionMajor == 5); + this.isIE55 = (this.isIE && this.versionMinor == 5.5); + this.isIE5up = (this.isIE && this.versionMajor >= 5); + this.isIE6x = (this.isIE && this.versionMajor == 6); + this.isIE6up = (this.isIE && this.versionMajor >= 6); + + this.isIE4xMac = (this.isIE4x && this.isMac); +} +var browser = new BrowserDetectLite(); diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/js/menu1.js b/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/js/menu1.js index 5f87f66421..74abcbc61a 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/js/menu1.js +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/js/menu1.js @@ -1,155 +1,155 @@ -/* -Author : bieler batiste -Company : doSimple : http://www.dosimple.ch -send me a mail for more informations : faden@PASDEPOURRIELaltern.org - remove ( PASDEPOURRIEL ) - -Short javascript function to create and handle a CSS navigation menu - -Copyright (C) 2004 Bieler Batiste - -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.1 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 USA -*/ - -// the timeout for the menu -var timeout = 100; - -// not very clean but simple -// the function can be run in the HTML for faster display -// window.onload=initMenu; - -// creat timeout variables for list item -// it's for avoid some warning with IE -for( var i = 0; i < 100; i++ ) -{ - eval("var timeoutli" + i + " = false;"); -} - -// this fonction apply the CSS style and the event -function initMenu() -{ - // a test to avoid some browser like IE4, Opera 6, and IE Mac - if ( browser.isDOM1 - && !( browser.isMac && browser.isIE ) - && !( browser.isOpera && browser.versionMajor < 7 ) - && !( browser.isIE && browser.versionMajor < 5 ) ) - { - // get some element - var menu = document.getElementById('menu'); // the root element - var lis = menu.getElementsByTagName('li'); // all the li - - // change the class name of the menu, - // it's usefull for compatibility with old browser - menu.className='menu'; - // i am searching for ul element in li element - for ( var i=0; i 0 ) - { - // improve IE key navigation - if ( browser.isIE ) - { - addAnEvent(lis.item(i),'keyup',show); - } - // link events to list item - addAnEvent(lis.item(i),'mouseover',show); - addAnEvent(lis.item(i),'mouseout',timeoutHide); - addAnEvent(lis.item(i),'blur',timeoutHide); - addAnEvent(lis.item(i),'focus',show); - - // add an id to list item - lis.item(i).setAttribute( 'id', "li"+i ); - } - } - } -} +/* +Author : bieler batiste +Company : doSimple : http://www.dosimple.ch +send me a mail for more informations : faden@PASDEPOURRIELaltern.org - remove ( PASDEPOURRIEL ) - +Short javascript function to create and handle a CSS navigation menu - -function addAnEvent( target, eventName, functionName ) -{ - // apply the method to IE - if ( browser.isIE ) - { - //attachEvent dont work properly with this - eval('target.on'+eventName+'=functionName'); - } - // apply the method to DOM compliant browsers - else - { - target.addEventListener( eventName , functionName , true ); // true is important for Opera7 - } -} - -// hide the first ul element of the current element -function timeoutHide() -{ - // start the timeout - eval( "timeout" + this.id + " = window.setTimeout('hideUlUnder( \"" + this.id + "\" )', " + timeout + " );"); -} - -// hide the ul elements under the element identified by id -function hideUlUnder( id ) -{ - document.getElementById(id).getElementsByTagName('ul')[0].style['visibility'] = 'hidden'; -} - -// show the first ul element found under this element -function show() -{ - // show the sub menu - this.getElementsByTagName('ul')[0].style['visibility'] = 'visible'; - var currentNode=this; - while(currentNode) - { - if( currentNode.nodeName=='LI') - { - // currentNode.getElementsByTagName('a')[0].className = 'linkOver'; - } - currentNode=currentNode.parentNode; - } - // clear the timeout - eval ( "clearTimeout( timeout"+ this.id +");" ); - hideAllOthersUls( this ); -} - -// hide all ul on the same level of this list item -function hideAllOthersUls( currentLi ) -{ - var lis = currentLi.parentNode; - for ( var i=0; i 0 ) + { + // improve IE key navigation + if ( browser.isIE ) + { + addAnEvent(lis.item(i),'keyup',show); + } + // link events to list item + addAnEvent(lis.item(i),'mouseover',show); + addAnEvent(lis.item(i),'mouseout',timeoutHide); + addAnEvent(lis.item(i),'blur',timeoutHide); + addAnEvent(lis.item(i),'focus',show); + + // add an id to list item + lis.item(i).setAttribute( 'id', "li"+i ); + } + } + } +} + + + + +function addAnEvent( target, eventName, functionName ) +{ + // apply the method to IE + if ( browser.isIE ) + { + //attachEvent dont work properly with this + eval('target.on'+eventName+'=functionName'); + } + // apply the method to DOM compliant browsers + else + { + target.addEventListener( eventName , functionName , true ); // true is important for Opera7 + } +} + +// hide the first ul element of the current element +function timeoutHide() +{ + // start the timeout + eval( "timeout" + this.id + " = window.setTimeout('hideUlUnder( \"" + this.id + "\" )', " + timeout + " );"); +} + +// hide the ul elements under the element identified by id +function hideUlUnder( id ) +{ + document.getElementById(id).getElementsByTagName('ul')[0].style['visibility'] = 'hidden'; +} + +// show the first ul element found under this element +function show() +{ + // show the sub menu + this.getElementsByTagName('ul')[0].style['visibility'] = 'visible'; + var currentNode=this; + while(currentNode) + { + if( currentNode.nodeName=='LI') + { + // currentNode.getElementsByTagName('a')[0].className = 'linkOver'; + } + currentNode=currentNode.parentNode; + } + // clear the timeout + eval ( "clearTimeout( timeout"+ this.id +");" ); + hideAllOthersUls( this ); +} + +// hide all ul on the same level of this list item +function hideAllOthersUls( currentLi ) +{ + var lis = currentLi.parentNode; + for ( var i=0; i 0 ) + menu2.className='menu2'; + for ( var i=0; i 0 ) { - if ( browser.isIE ) - { - addAnEvent(lis2.item(i),'keyup',show); - } - - addAnEvent(lis2.item(i),'mouseover',show); - addAnEvent(lis2.item(i),'mouseout',timeoutHide); - addAnEvent(lis2.item(i),'blur',timeoutHide); - addAnEvent(lis2.item(i),'focus',show); - - lis2.item(i).setAttribute( 'id', "li2"+i ); - } - } - } + if ( browser.isIE ) + { + addAnEvent(lis2.item(i),'keyup',show); + } + + addAnEvent(lis2.item(i),'mouseover',show); + addAnEvent(lis2.item(i),'mouseout',timeoutHide); + addAnEvent(lis2.item(i),'blur',timeoutHide); + addAnEvent(lis2.item(i),'focus',show); + + lis2.item(i).setAttribute( 'id', "li2"+i ); + } + } + } } - -function addAnEvent( target, eventName, functionName ) + +function addAnEvent( target, eventName, functionName ) { - if ( browser.isIE ) + if ( browser.isIE ) + { + eval('target.on'+eventName+'=functionName'); + } + else { - eval('target.on'+eventName+'=functionName'); - } - else - { target.addEventListener( eventName , functionName , true ); - } -} - -function timeoutHide() + } +} + +function timeoutHide() { - eval( "timeout" + this.id + " = window.setTimeout('hideUlUnder( \"" + this.id + "\" )', " + timeout + " );"); -} - -// hide the ul elements under the element identified by id -function hideUlUnder( id ) -{ - document.getElementById(id).getElementsByTagName('ul')[0].style['visibility'] = 'hidden'; -} - -// show the first ul element found under this element -function show() -{ - // show the sub menu - this.getElementsByTagName('ul')[0].style['visibility'] = 'visible'; - var currentNode=this; - while(currentNode) - { - if( currentNode.nodeName=='LI') - { - // currentNode.getElementsByTagName('a')[0].className = 'linkOver'; - } - currentNode=currentNode.parentNode; - } - // clear the timeout - eval ( "clearTimeout( timeout"+ this.id +");" ); - hideAllOthersUls( this ); -} - -// hide all ul on the same level of this list item -function hideAllOthersUls( currentLi ) -{ - var lis = currentLi.parentNode; - for ( var i=0; i -1, - Gecko: ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1, - MobileSafari: /Apple.*Mobile.*Safari/.test(ua) - } - })(), - - BrowserFeatures: { - XPath: !!document.evaluate, - SelectorsAPI: !!document.querySelector, - ElementExtensions: (function() { - var constructor = window.Element || window.HTMLElement; - return !!(constructor && constructor.prototype); - })(), - SpecificElementExtensions: (function() { - if (typeof window.HTMLDivElement !== 'undefined') - return true; - - var div = document.createElement('div'); - var form = document.createElement('form'); - var isSupported = false; - - if (div['__proto__'] && (div['__proto__'] !== form['__proto__'])) { - isSupported = true; - } - - div = form = null; - - return isSupported; - })() - }, - - ScriptFragment: ']*>([\\S\\s]*?)<\/script>', - JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, - - emptyFunction: function() { }, - K: function(x) { return x } -}; - -if (Prototype.Browser.MobileSafari) - Prototype.BrowserFeatures.SpecificElementExtensions = false; - - -var Abstract = { }; - - -var Try = { - these: function() { - var returnValue; - - for (var i = 0, length = arguments.length; i < length; i++) { - var lambda = arguments[i]; - try { - returnValue = lambda(); - break; - } catch (e) { } - } - - return returnValue; - } -}; - -/* Based on Alex Arnell's inheritance implementation. */ - -var Class = (function() { - function subclass() {}; - function create() { - var parent = null, properties = $A(arguments); - if (Object.isFunction(properties[0])) - parent = properties.shift(); - - function klass() { - this.initialize.apply(this, arguments); - } - - Object.extend(klass, Class.Methods); - klass.superclass = parent; - klass.subclasses = []; - - if (parent) { - subclass.prototype = parent.prototype; - klass.prototype = new subclass; - parent.subclasses.push(klass); - } - - for (var i = 0; i < properties.length; i++) - klass.addMethods(properties[i]); - - if (!klass.prototype.initialize) - klass.prototype.initialize = Prototype.emptyFunction; - - klass.prototype.constructor = klass; - return klass; - } - - function addMethods(source) { - var ancestor = this.superclass && this.superclass.prototype; - var properties = Object.keys(source); - - if (!Object.keys({ toString: true }).length) { - if (source.toString != Object.prototype.toString) - properties.push("toString"); - if (source.valueOf != Object.prototype.valueOf) - properties.push("valueOf"); - } - - for (var i = 0, length = properties.length; i < length; i++) { - var property = properties[i], value = source[property]; - if (ancestor && Object.isFunction(value) && - value.argumentNames().first() == "$super") { - var method = value; - value = (function(m) { - return function() { return ancestor[m].apply(this, arguments); }; - })(property).wrap(method); - - value.valueOf = method.valueOf.bind(method); - value.toString = method.toString.bind(method); - } - this.prototype[property] = value; - } - - return this; - } - - return { - create: create, - Methods: { - addMethods: addMethods - } - }; -})(); -(function() { - - var _toString = Object.prototype.toString; - - function extend(destination, source) { - for (var property in source) - destination[property] = source[property]; - return destination; - } - - function inspect(object) { - try { - if (isUndefined(object)) return 'undefined'; - if (object === null) return 'null'; - return object.inspect ? object.inspect() : String(object); - } catch (e) { - if (e instanceof RangeError) return '...'; - throw e; - } - } - - function toJSON(object) { - var type = typeof object; - switch (type) { - case 'undefined': - case 'function': - case 'unknown': return; - case 'boolean': return object.toString(); - } - - if (object === null) return 'null'; - if (object.toJSON) return object.toJSON(); - if (isElement(object)) return; - - var results = []; - for (var property in object) { - var value = toJSON(object[property]); - if (!isUndefined(value)) - results.push(property.toJSON() + ': ' + value); - } - - return '{' + results.join(', ') + '}'; - } - - function toQueryString(object) { - return $H(object).toQueryString(); - } - - function toHTML(object) { - return object && object.toHTML ? object.toHTML() : String.interpret(object); - } - - function keys(object) { - var results = []; - for (var property in object) - results.push(property); - return results; - } - - function values(object) { - var results = []; - for (var property in object) - results.push(object[property]); - return results; - } - - function clone(object) { - return extend({ }, object); - } - - function isElement(object) { - return !!(object && object.nodeType == 1); - } - - function isArray(object) { - return _toString.call(object) == "[object Array]"; - } - - - function isHash(object) { - return object instanceof Hash; - } - - function isFunction(object) { - return typeof object === "function"; - } - - function isString(object) { - return _toString.call(object) == "[object String]"; - } - - function isNumber(object) { - return _toString.call(object) == "[object Number]"; - } - - function isUndefined(object) { - return typeof object === "undefined"; - } - - extend(Object, { - extend: extend, - inspect: inspect, - toJSON: toJSON, - toQueryString: toQueryString, - toHTML: toHTML, - keys: keys, - values: values, - clone: clone, - isElement: isElement, - isArray: isArray, - isHash: isHash, - isFunction: isFunction, - isString: isString, - isNumber: isNumber, - isUndefined: isUndefined - }); -})(); -Object.extend(Function.prototype, (function() { - var slice = Array.prototype.slice; - - function update(array, args) { - var arrayLength = array.length, length = args.length; - while (length--) array[arrayLength + length] = args[length]; - return array; - } - - function merge(array, args) { - array = slice.call(array, 0); - return update(array, args); - } - - function argumentNames() { - var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1] - .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '') - .replace(/\s+/g, '').split(','); - return names.length == 1 && !names[0] ? [] : names; - } - - function bind(context) { - if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this; - var __method = this, args = slice.call(arguments, 1); - return function() { - var a = merge(args, arguments); - return __method.apply(context, a); - } - } - - function bindAsEventListener(context) { - var __method = this, args = slice.call(arguments, 1); - return function(event) { - var a = update([event || window.event], args); - return __method.apply(context, a); - } - } - - function curry() { - if (!arguments.length) return this; - var __method = this, args = slice.call(arguments, 0); - return function() { - var a = merge(args, arguments); - return __method.apply(this, a); - } - } - - function delay(timeout) { - var __method = this, args = slice.call(arguments, 1); - timeout = timeout * 1000 - return window.setTimeout(function() { - return __method.apply(__method, args); - }, timeout); - } - - function defer() { - var args = update([0.01], arguments); - return this.delay.apply(this, args); - } - - function wrap(wrapper) { - var __method = this; - return function() { - var a = update([__method.bind(this)], arguments); - return wrapper.apply(this, a); - } - } - - function methodize() { - if (this._methodized) return this._methodized; - var __method = this; - return this._methodized = function() { - var a = update([this], arguments); - return __method.apply(null, a); - }; - } - - return { - argumentNames: argumentNames, - bind: bind, - bindAsEventListener: bindAsEventListener, - curry: curry, - delay: delay, - defer: defer, - wrap: wrap, - methodize: methodize - } -})()); - - -Date.prototype.toJSON = function() { - return '"' + this.getUTCFullYear() + '-' + - (this.getUTCMonth() + 1).toPaddedString(2) + '-' + - this.getUTCDate().toPaddedString(2) + 'T' + - this.getUTCHours().toPaddedString(2) + ':' + - this.getUTCMinutes().toPaddedString(2) + ':' + - this.getUTCSeconds().toPaddedString(2) + 'Z"'; -}; - - -RegExp.prototype.match = RegExp.prototype.test; - -RegExp.escape = function(str) { - return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); -}; -var PeriodicalExecuter = Class.create({ - initialize: function(callback, frequency) { - this.callback = callback; - this.frequency = frequency; - this.currentlyExecuting = false; - - this.registerCallback(); - }, - - registerCallback: function() { - this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); - }, - - execute: function() { - this.callback(this); - }, - - stop: function() { - if (!this.timer) return; - clearInterval(this.timer); - this.timer = null; - }, - - onTimerEvent: function() { - if (!this.currentlyExecuting) { - try { - this.currentlyExecuting = true; - this.execute(); - this.currentlyExecuting = false; - } catch(e) { - this.currentlyExecuting = false; - throw e; - } - } - } -}); -Object.extend(String, { - interpret: function(value) { - return value == null ? '' : String(value); - }, - specialChar: { - '\b': '\\b', - '\t': '\\t', - '\n': '\\n', - '\f': '\\f', - '\r': '\\r', - '\\': '\\\\' - } -}); - -Object.extend(String.prototype, (function() { - - function prepareReplacement(replacement) { - if (Object.isFunction(replacement)) return replacement; - var template = new Template(replacement); - return function(match) { return template.evaluate(match) }; - } - - function gsub(pattern, replacement) { - var result = '', source = this, match; - replacement = prepareReplacement(replacement); - - if (Object.isString(pattern)) - pattern = RegExp.escape(pattern); - - if (!(pattern.length || pattern.source)) { - replacement = replacement(''); - return replacement + source.split('').join(replacement) + replacement; - } - - while (source.length > 0) { - if (match = source.match(pattern)) { - result += source.slice(0, match.index); - result += String.interpret(replacement(match)); - source = source.slice(match.index + match[0].length); - } else { - result += source, source = ''; - } - } - return result; - } - - function sub(pattern, replacement, count) { - replacement = prepareReplacement(replacement); - count = Object.isUndefined(count) ? 1 : count; - - return this.gsub(pattern, function(match) { - if (--count < 0) return match[0]; - return replacement(match); - }); - } - - function scan(pattern, iterator) { - this.gsub(pattern, iterator); - return String(this); - } - - function truncate(length, truncation) { - length = length || 30; - truncation = Object.isUndefined(truncation) ? '...' : truncation; - return this.length > length ? - this.slice(0, length - truncation.length) + truncation : String(this); - } - - function strip() { - return this.replace(/^\s+/, '').replace(/\s+$/, ''); - } - - function stripTags() { - return this.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?>|<\/\w+>/gi, ''); - } - - function stripScripts() { - return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); - } - - function extractScripts() { - var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); - var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); - return (this.match(matchAll) || []).map(function(scriptTag) { - return (scriptTag.match(matchOne) || ['', ''])[1]; - }); - } - - function evalScripts() { - return this.extractScripts().map(function(script) { return eval(script) }); - } - - function escapeHTML() { - return this.replace(/&/g,'&').replace(//g,'>'); - } - - function unescapeHTML() { - return this.stripTags().replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&'); - } - - - function toQueryParams(separator) { - var match = this.strip().match(/([^?#]*)(#.*)?$/); - if (!match) return { }; - - return match[1].split(separator || '&').inject({ }, function(hash, pair) { - if ((pair = pair.split('='))[0]) { - var key = decodeURIComponent(pair.shift()); - var value = pair.length > 1 ? pair.join('=') : pair[0]; - if (value != undefined) value = decodeURIComponent(value); - - if (key in hash) { - if (!Object.isArray(hash[key])) hash[key] = [hash[key]]; - hash[key].push(value); - } - else hash[key] = value; - } - return hash; - }); - } - - function toArray() { - return this.split(''); - } - - function succ() { - return this.slice(0, this.length - 1) + - String.fromCharCode(this.charCodeAt(this.length - 1) + 1); - } - - function times(count) { - return count < 1 ? '' : new Array(count + 1).join(this); - } - - function camelize() { - var parts = this.split('-'), len = parts.length; - if (len == 1) return parts[0]; - - var camelized = this.charAt(0) == '-' - ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) - : parts[0]; - - for (var i = 1; i < len; i++) - camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); - - return camelized; - } - - function capitalize() { - return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); - } - - function underscore() { - return this.replace(/::/g, '/') - .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2') - .replace(/([a-z\d])([A-Z])/g, '$1_$2') - .replace(/-/g, '_') - .toLowerCase(); - } - - function dasherize() { - return this.replace(/_/g, '-'); - } - - function inspect(useDoubleQuotes) { - var escapedString = this.replace(/[\x00-\x1f\\]/g, function(character) { - if (character in String.specialChar) { - return String.specialChar[character]; - } - return '\\u00' + character.charCodeAt().toPaddedString(2, 16); - }); - if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; - return "'" + escapedString.replace(/'/g, '\\\'') + "'"; - } - - function toJSON() { - return this.inspect(true); - } - - function unfilterJSON(filter) { - return this.replace(filter || Prototype.JSONFilter, '$1'); - } - - function isJSON() { - var str = this; - if (str.blank()) return false; - str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''); - return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str); - } - - function evalJSON(sanitize) { - var json = this.unfilterJSON(); - try { - if (!sanitize || json.isJSON()) return eval('(' + json + ')'); - } catch (e) { } - throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); - } - - function include(pattern) { - return this.indexOf(pattern) > -1; - } - - function startsWith(pattern) { - return this.indexOf(pattern) === 0; - } - - function endsWith(pattern) { - var d = this.length - pattern.length; - return d >= 0 && this.lastIndexOf(pattern) === d; - } - - function empty() { - return this == ''; - } - - function blank() { - return /^\s*$/.test(this); - } - - function interpolate(object, pattern) { - return new Template(this, pattern).evaluate(object); - } - - return { - gsub: gsub, - sub: sub, - scan: scan, - truncate: truncate, - strip: String.prototype.trim ? String.prototype.trim : strip, - stripTags: stripTags, - stripScripts: stripScripts, - extractScripts: extractScripts, - evalScripts: evalScripts, - escapeHTML: escapeHTML, - unescapeHTML: unescapeHTML, - toQueryParams: toQueryParams, - parseQuery: toQueryParams, - toArray: toArray, - succ: succ, - times: times, - camelize: camelize, - capitalize: capitalize, - underscore: underscore, - dasherize: dasherize, - inspect: inspect, - toJSON: toJSON, - unfilterJSON: unfilterJSON, - isJSON: isJSON, - evalJSON: evalJSON, - include: include, - startsWith: startsWith, - endsWith: endsWith, - empty: empty, - blank: blank, - interpolate: interpolate - }; -})()); - -var Template = Class.create({ - initialize: function(template, pattern) { - this.template = template.toString(); - this.pattern = pattern || Template.Pattern; - }, - - evaluate: function(object) { - if (object && Object.isFunction(object.toTemplateReplacements)) - object = object.toTemplateReplacements(); - - return this.template.gsub(this.pattern, function(match) { - if (object == null) return (match[1] + ''); - - var before = match[1] || ''; - if (before == '\\') return match[2]; - - var ctx = object, expr = match[3]; - var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/; - match = pattern.exec(expr); - if (match == null) return before; - - while (match != null) { - var comp = match[1].startsWith('[') ? match[2].replace(/\\\\]/g, ']') : match[1]; - ctx = ctx[comp]; - if (null == ctx || '' == match[3]) break; - expr = expr.substring('[' == match[3] ? match[1].length : match[0].length); - match = pattern.exec(expr); - } - - return before + String.interpret(ctx); - }); - } -}); -Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; - -var $break = { }; - -var Enumerable = (function() { - function each(iterator, context) { - var index = 0; - try { - this._each(function(value) { - iterator.call(context, value, index++); - }); - } catch (e) { - if (e != $break) throw e; - } - return this; - } - - function eachSlice(number, iterator, context) { - var index = -number, slices = [], array = this.toArray(); - if (number < 1) return array; - while ((index += number) < array.length) - slices.push(array.slice(index, index+number)); - return slices.collect(iterator, context); - } - - function all(iterator, context) { - iterator = iterator || Prototype.K; - var result = true; - this.each(function(value, index) { - result = result && !!iterator.call(context, value, index); - if (!result) throw $break; - }); - return result; - } - - function any(iterator, context) { - iterator = iterator || Prototype.K; - var result = false; - this.each(function(value, index) { - if (result = !!iterator.call(context, value, index)) - throw $break; - }); - return result; - } - - function collect(iterator, context) { - iterator = iterator || Prototype.K; - var results = []; - this.each(function(value, index) { - results.push(iterator.call(context, value, index)); - }); - return results; - } - - function detect(iterator, context) { - var result; - this.each(function(value, index) { - if (iterator.call(context, value, index)) { - result = value; - throw $break; - } - }); - return result; - } - - function findAll(iterator, context) { - var results = []; - this.each(function(value, index) { - if (iterator.call(context, value, index)) - results.push(value); - }); - return results; - } - - function grep(filter, iterator, context) { - iterator = iterator || Prototype.K; - var results = []; - - if (Object.isString(filter)) - filter = new RegExp(RegExp.escape(filter)); - - this.each(function(value, index) { - if (filter.match(value)) - results.push(iterator.call(context, value, index)); - }); - return results; - } - - function include(object) { - if (Object.isFunction(this.indexOf)) - if (this.indexOf(object) != -1) return true; - - var found = false; - this.each(function(value) { - if (value == object) { - found = true; - throw $break; - } - }); - return found; - } - - function inGroupsOf(number, fillWith) { - fillWith = Object.isUndefined(fillWith) ? null : fillWith; - return this.eachSlice(number, function(slice) { - while(slice.length < number) slice.push(fillWith); - return slice; - }); - } - - function inject(memo, iterator, context) { - this.each(function(value, index) { - memo = iterator.call(context, memo, value, index); - }); - return memo; - } - - function invoke(method) { - var args = $A(arguments).slice(1); - return this.map(function(value) { - return value[method].apply(value, args); - }); - } - - function max(iterator, context) { - iterator = iterator || Prototype.K; - var result; - this.each(function(value, index) { - value = iterator.call(context, value, index); - if (result == null || value >= result) - result = value; - }); - return result; - } - - function min(iterator, context) { - iterator = iterator || Prototype.K; - var result; - this.each(function(value, index) { - value = iterator.call(context, value, index); - if (result == null || value < result) - result = value; - }); - return result; - } - - function partition(iterator, context) { - iterator = iterator || Prototype.K; - var trues = [], falses = []; - this.each(function(value, index) { - (iterator.call(context, value, index) ? - trues : falses).push(value); - }); - return [trues, falses]; - } - - function pluck(property) { - var results = []; - this.each(function(value) { - results.push(value[property]); - }); - return results; - } - - function reject(iterator, context) { - var results = []; - this.each(function(value, index) { - if (!iterator.call(context, value, index)) - results.push(value); - }); - return results; - } - - function sortBy(iterator, context) { - return this.map(function(value, index) { - return { - value: value, - criteria: iterator.call(context, value, index) - }; - }).sort(function(left, right) { - var a = left.criteria, b = right.criteria; - return a < b ? -1 : a > b ? 1 : 0; - }).pluck('value'); - } - - function toArray() { - return this.map(); - } - - function zip() { - var iterator = Prototype.K, args = $A(arguments); - if (Object.isFunction(args.last())) - iterator = args.pop(); - - var collections = [this].concat(args).map($A); - return this.map(function(value, index) { - return iterator(collections.pluck(index)); - }); - } - - function size() { - return this.toArray().length; - } - - function inspect() { - return '#'; - } - - - - - - - - - - return { - each: each, - eachSlice: eachSlice, - all: all, - every: all, - any: any, - some: any, - collect: collect, - map: collect, - detect: detect, - findAll: findAll, - select: findAll, - filter: findAll, - grep: grep, - include: include, - member: include, - inGroupsOf: inGroupsOf, - inject: inject, - invoke: invoke, - max: max, - min: min, - partition: partition, - pluck: pluck, - reject: reject, - sortBy: sortBy, - toArray: toArray, - entries: toArray, - zip: zip, - size: size, - inspect: inspect, - find: detect - }; -})(); -function $A(iterable) { - if (!iterable) return []; - if ('toArray' in Object(iterable)) return iterable.toArray(); - var length = iterable.length || 0, results = new Array(length); - while (length--) results[length] = iterable[length]; - return results; -} - -function $w(string) { - if (!Object.isString(string)) return []; - string = string.strip(); - return string ? string.split(/\s+/) : []; -} - -Array.from = $A; - - -(function() { - var arrayProto = Array.prototype, - slice = arrayProto.slice, - _each = arrayProto.forEach; // use native browser JS 1.6 implementation if available - - function each(iterator) { - for (var i = 0, length = this.length; i < length; i++) - iterator(this[i]); - } - if (!_each) _each = each; - - function clear() { - this.length = 0; - return this; - } - - function first() { - return this[0]; - } - - function last() { - return this[this.length - 1]; - } - - function compact() { - return this.select(function(value) { - return value != null; - }); - } - - function flatten() { - return this.inject([], function(array, value) { - if (Object.isArray(value)) - return array.concat(value.flatten()); - array.push(value); - return array; - }); - } - - function without() { - var values = slice.call(arguments, 0); - return this.select(function(value) { - return !values.include(value); - }); - } - - function reverse(inline) { - return (inline !== false ? this : this.toArray())._reverse(); - } - - function uniq(sorted) { - return this.inject([], function(array, value, index) { - if (0 == index || (sorted ? array.last() != value : !array.include(value))) - array.push(value); - return array; - }); - } - - function intersect(array) { - return this.uniq().findAll(function(item) { - return array.detect(function(value) { return item === value }); - }); - } - - - function clone() { - return slice.call(this, 0); - } - - function size() { - return this.length; - } - - function inspect() { - return '[' + this.map(Object.inspect).join(', ') + ']'; - } - - function toJSON() { - var results = []; - this.each(function(object) { - var value = Object.toJSON(object); - if (!Object.isUndefined(value)) results.push(value); - }); - return '[' + results.join(', ') + ']'; - } - - function indexOf(item, i) { - i || (i = 0); - var length = this.length; - if (i < 0) i = length + i; - for (; i < length; i++) - if (this[i] === item) return i; - return -1; - } - - function lastIndexOf(item, i) { - i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1; - var n = this.slice(0, i).reverse().indexOf(item); - return (n < 0) ? n : i - n - 1; - } - - function concat() { - var array = slice.call(this, 0), item; - for (var i = 0, length = arguments.length; i < length; i++) { - item = arguments[i]; - if (Object.isArray(item) && !('callee' in item)) { - for (var j = 0, arrayLength = item.length; j < arrayLength; j++) - array.push(item[j]); - } else { - array.push(item); - } - } - return array; - } - - Object.extend(arrayProto, Enumerable); - - if (!arrayProto._reverse) - arrayProto._reverse = arrayProto.reverse; - - Object.extend(arrayProto, { - _each: _each, - clear: clear, - first: first, - last: last, - compact: compact, - flatten: flatten, - without: without, - reverse: reverse, - uniq: uniq, - intersect: intersect, - clone: clone, - toArray: clone, - size: size, - inspect: inspect, - toJSON: toJSON - }); - - var CONCAT_ARGUMENTS_BUGGY = (function() { - return [].concat(arguments)[0][0] !== 1; - })(1,2) - - if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat; - - if (!arrayProto.indexOf) arrayProto.indexOf = indexOf; - if (!arrayProto.lastIndexOf) arrayProto.lastIndexOf = lastIndexOf; -})(); -function $H(object) { - return new Hash(object); -}; - -var Hash = Class.create(Enumerable, (function() { - function initialize(object) { - this._object = Object.isHash(object) ? object.toObject() : Object.clone(object); - } - - function _each(iterator) { - for (var key in this._object) { - var value = this._object[key], pair = [key, value]; - pair.key = key; - pair.value = value; - iterator(pair); - } - } - - function set(key, value) { - return this._object[key] = value; - } - - function get(key) { - if (this._object[key] !== Object.prototype[key]) - return this._object[key]; - } - - function unset(key) { - var value = this._object[key]; - delete this._object[key]; - return value; - } - - function toObject() { - return Object.clone(this._object); - } - - function keys() { - return this.pluck('key'); - } - - function values() { - return this.pluck('value'); - } - - function index(value) { - var match = this.detect(function(pair) { - return pair.value === value; - }); - return match && match.key; - } - - function merge(object) { - return this.clone().update(object); - } - - function update(object) { - return new Hash(object).inject(this, function(result, pair) { - result.set(pair.key, pair.value); - return result; - }); - } - - function toQueryPair(key, value) { - if (Object.isUndefined(value)) return key; - return key + '=' + encodeURIComponent(String.interpret(value)); - } - - function toQueryString() { - return this.inject([], function(results, pair) { - var key = encodeURIComponent(pair.key), values = pair.value; - - if (values && typeof values == 'object') { - if (Object.isArray(values)) - return results.concat(values.map(toQueryPair.curry(key))); - } else results.push(toQueryPair(key, values)); - return results; - }).join('&'); - } - - function inspect() { - return '#'; - } - - function toJSON() { - return Object.toJSON(this.toObject()); - } - - function clone() { - return new Hash(this); - } - - return { - initialize: initialize, - _each: _each, - set: set, - get: get, - unset: unset, - toObject: toObject, - toTemplateReplacements: toObject, - keys: keys, - values: values, - index: index, - merge: merge, - update: update, - toQueryString: toQueryString, - inspect: inspect, - toJSON: toJSON, - clone: clone - }; -})()); - -Hash.from = $H; -Object.extend(Number.prototype, (function() { - function toColorPart() { - return this.toPaddedString(2, 16); - } - - function succ() { - return this + 1; - } - - function times(iterator, context) { - $R(0, this, true).each(iterator, context); - return this; - } - - function toPaddedString(length, radix) { - var string = this.toString(radix || 10); - return '0'.times(length - string.length) + string; - } - - function toJSON() { - return isFinite(this) ? this.toString() : 'null'; - } - - function abs() { - return Math.abs(this); - } - - function round() { - return Math.round(this); - } - - function ceil() { - return Math.ceil(this); - } - - function floor() { - return Math.floor(this); - } - - return { - toColorPart: toColorPart, - succ: succ, - times: times, - toPaddedString: toPaddedString, - toJSON: toJSON, - abs: abs, - round: round, - ceil: ceil, - floor: floor - }; -})()); - -function $R(start, end, exclusive) { - return new ObjectRange(start, end, exclusive); -} - -var ObjectRange = Class.create(Enumerable, (function() { - function initialize(start, end, exclusive) { - this.start = start; - this.end = end; - this.exclusive = exclusive; - } - - function _each(iterator) { - var value = this.start; - while (this.include(value)) { - iterator(value); - value = value.succ(); - } - } - - function include(value) { - if (value < this.start) - return false; - if (this.exclusive) - return value < this.end; - return value <= this.end; - } - - return { - initialize: initialize, - _each: _each, - include: include - }; -})()); - - - -var Ajax = { - getTransport: function() { - return Try.these( - function() {return new XMLHttpRequest()}, - function() {return new ActiveXObject('Msxml2.XMLHTTP')}, - function() {return new ActiveXObject('Microsoft.XMLHTTP')} - ) || false; - }, - - activeRequestCount: 0 -}; - -Ajax.Responders = { - responders: [], - - _each: function(iterator) { - this.responders._each(iterator); - }, - - register: function(responder) { - if (!this.include(responder)) - this.responders.push(responder); - }, - - unregister: function(responder) { - this.responders = this.responders.without(responder); - }, - - dispatch: function(callback, request, transport, json) { - this.each(function(responder) { - if (Object.isFunction(responder[callback])) { - try { - responder[callback].apply(responder, [request, transport, json]); - } catch (e) { } - } - }); - } -}; - -Object.extend(Ajax.Responders, Enumerable); - -Ajax.Responders.register({ - onCreate: function() { Ajax.activeRequestCount++ }, - onComplete: function() { Ajax.activeRequestCount-- } -}); -Ajax.Base = Class.create({ - initialize: function(options) { - this.options = { - method: 'post', - asynchronous: true, - contentType: 'application/x-www-form-urlencoded', - encoding: 'UTF-8', - parameters: '', - evalJSON: true, - evalJS: true - }; - Object.extend(this.options, options || { }); - - this.options.method = this.options.method.toLowerCase(); - - if (Object.isString(this.options.parameters)) - this.options.parameters = this.options.parameters.toQueryParams(); - else if (Object.isHash(this.options.parameters)) - this.options.parameters = this.options.parameters.toObject(); - } -}); -Ajax.Request = Class.create(Ajax.Base, { - _complete: false, - - initialize: function($super, url, options) { - $super(options); - this.transport = Ajax.getTransport(); - this.request(url); - }, - - request: function(url) { - this.url = url; - this.method = this.options.method; - var params = Object.clone(this.options.parameters); - - if (!['get', 'post'].include(this.method)) { - params['_method'] = this.method; - this.method = 'post'; - } - - this.parameters = params; - - if (params = Object.toQueryString(params)) { - if (this.method == 'get') - this.url += (this.url.include('?') ? '&' : '?') + params; - else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) - params += '&_='; - } - - try { - var response = new Ajax.Response(this); - if (this.options.onCreate) this.options.onCreate(response); - Ajax.Responders.dispatch('onCreate', this, response); - - this.transport.open(this.method.toUpperCase(), this.url, - this.options.asynchronous); - - if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1); - - this.transport.onreadystatechange = this.onStateChange.bind(this); - this.setRequestHeaders(); - - this.body = this.method == 'post' ? (this.options.postBody || params) : null; - this.transport.send(this.body); - - /* Force Firefox to handle ready state 4 for synchronous requests */ - if (!this.options.asynchronous && this.transport.overrideMimeType) - this.onStateChange(); - - } - catch (e) { - this.dispatchException(e); - } - }, - - onStateChange: function() { - var readyState = this.transport.readyState; - if (readyState > 1 && !((readyState == 4) && this._complete)) - this.respondToReadyState(this.transport.readyState); - }, - - setRequestHeaders: function() { - var headers = { - 'X-Requested-With': 'XMLHttpRequest', - 'X-Prototype-Version': Prototype.Version, - 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' - }; - - if (this.method == 'post') { - headers['Content-type'] = this.options.contentType + - (this.options.encoding ? '; charset=' + this.options.encoding : ''); - - /* Force "Connection: close" for older Mozilla browsers to work - * around a bug where XMLHttpRequest sends an incorrect - * Content-length header. See Mozilla Bugzilla #246651. - */ - if (this.transport.overrideMimeType && - (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) - headers['Connection'] = 'close'; - } - - if (typeof this.options.requestHeaders == 'object') { - var extras = this.options.requestHeaders; - - if (Object.isFunction(extras.push)) - for (var i = 0, length = extras.length; i < length; i += 2) - headers[extras[i]] = extras[i+1]; - else - $H(extras).each(function(pair) { headers[pair.key] = pair.value }); - } - - for (var name in headers) - this.transport.setRequestHeader(name, headers[name]); - }, - - success: function() { - var status = this.getStatus(); - return !status || (status >= 200 && status < 300); - }, - - getStatus: function() { - try { - return this.transport.status || 0; - } catch (e) { return 0 } - }, - - respondToReadyState: function(readyState) { - var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this); - - if (state == 'Complete') { - try { - this._complete = true; - (this.options['on' + response.status] - || this.options['on' + (this.success() ? 'Success' : 'Failure')] - || Prototype.emptyFunction)(response, response.headerJSON); - } catch (e) { - this.dispatchException(e); - } - - var contentType = response.getHeader('Content-type'); - if (this.options.evalJS == 'force' - || (this.options.evalJS && this.isSameOrigin() && contentType - && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i))) - this.evalResponse(); - } - - try { - (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON); - Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON); - } catch (e) { - this.dispatchException(e); - } - - if (state == 'Complete') { - this.transport.onreadystatechange = Prototype.emptyFunction; - } - }, - - isSameOrigin: function() { - var m = this.url.match(/^\s*https?:\/\/[^\/]*/); - return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({ - protocol: location.protocol, - domain: document.domain, - port: location.port ? ':' + location.port : '' - })); - }, - - getHeader: function(name) { - try { - return this.transport.getResponseHeader(name) || null; - } catch (e) { return null; } - }, - - evalResponse: function() { - try { - return eval((this.transport.responseText || '').unfilterJSON()); - } catch (e) { - this.dispatchException(e); - } - }, - - dispatchException: function(exception) { - (this.options.onException || Prototype.emptyFunction)(this, exception); - Ajax.Responders.dispatch('onException', this, exception); - } -}); - -Ajax.Request.Events = - ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; - - - - - - - - -Ajax.Response = Class.create({ - initialize: function(request){ - this.request = request; - var transport = this.transport = request.transport, - readyState = this.readyState = transport.readyState; - - if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) { - this.status = this.getStatus(); - this.statusText = this.getStatusText(); - this.responseText = String.interpret(transport.responseText); - this.headerJSON = this._getHeaderJSON(); - } - - if(readyState == 4) { - var xml = transport.responseXML; - this.responseXML = Object.isUndefined(xml) ? null : xml; - this.responseJSON = this._getResponseJSON(); - } - }, - - status: 0, - - statusText: '', - - getStatus: Ajax.Request.prototype.getStatus, - - getStatusText: function() { - try { - return this.transport.statusText || ''; - } catch (e) { return '' } - }, - - getHeader: Ajax.Request.prototype.getHeader, - - getAllHeaders: function() { - try { - return this.getAllResponseHeaders(); - } catch (e) { return null } - }, - - getResponseHeader: function(name) { - return this.transport.getResponseHeader(name); - }, - - getAllResponseHeaders: function() { - return this.transport.getAllResponseHeaders(); - }, - - _getHeaderJSON: function() { - var json = this.getHeader('X-JSON'); - if (!json) return null; - json = decodeURIComponent(escape(json)); - try { - return json.evalJSON(this.request.options.sanitizeJSON || - !this.request.isSameOrigin()); - } catch (e) { - this.request.dispatchException(e); - } - }, - - _getResponseJSON: function() { - var options = this.request.options; - if (!options.evalJSON || (options.evalJSON != 'force' && - !(this.getHeader('Content-type') || '').include('application/json')) || - this.responseText.blank()) - return null; - try { - return this.responseText.evalJSON(options.sanitizeJSON || - !this.request.isSameOrigin()); - } catch (e) { - this.request.dispatchException(e); - } - } -}); - -Ajax.Updater = Class.create(Ajax.Request, { - initialize: function($super, container, url, options) { - this.container = { - success: (container.success || container), - failure: (container.failure || (container.success ? null : container)) - }; - - options = Object.clone(options); - var onComplete = options.onComplete; - options.onComplete = (function(response, json) { - this.updateContent(response.responseText); - if (Object.isFunction(onComplete)) onComplete(response, json); - }).bind(this); - - $super(url, options); - }, - - updateContent: function(responseText) { - var receiver = this.container[this.success() ? 'success' : 'failure'], - options = this.options; - - if (!options.evalScripts) responseText = responseText.stripScripts(); - - if (receiver = $(receiver)) { - if (options.insertion) { - if (Object.isString(options.insertion)) { - var insertion = { }; insertion[options.insertion] = responseText; - receiver.insert(insertion); - } - else options.insertion(receiver, responseText); - } - else receiver.update(responseText); - } - } -}); - -Ajax.PeriodicalUpdater = Class.create(Ajax.Base, { - initialize: function($super, container, url, options) { - $super(options); - this.onComplete = this.options.onComplete; - - this.frequency = (this.options.frequency || 2); - this.decay = (this.options.decay || 1); - - this.updater = { }; - this.container = container; - this.url = url; - - this.start(); - }, - - start: function() { - this.options.onComplete = this.updateComplete.bind(this); - this.onTimerEvent(); - }, - - stop: function() { - this.updater.options.onComplete = undefined; - clearTimeout(this.timer); - (this.onComplete || Prototype.emptyFunction).apply(this, arguments); - }, - - updateComplete: function(response) { - if (this.options.decay) { - this.decay = (response.responseText == this.lastText ? - this.decay * this.options.decay : 1); - - this.lastText = response.responseText; - } - this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency); - }, - - onTimerEvent: function() { - this.updater = new Ajax.Updater(this.container, this.url, this.options); - } -}); - - - -function $(element) { - if (arguments.length > 1) { - for (var i = 0, elements = [], length = arguments.length; i < length; i++) - elements.push($(arguments[i])); - return elements; - } - if (Object.isString(element)) - element = document.getElementById(element); - return Element.extend(element); -} - -if (Prototype.BrowserFeatures.XPath) { - document._getElementsByXPath = function(expression, parentElement) { - var results = []; - var query = document.evaluate(expression, $(parentElement) || document, - null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); - for (var i = 0, length = query.snapshotLength; i < length; i++) - results.push(Element.extend(query.snapshotItem(i))); - return results; - }; -} - -/*--------------------------------------------------------------------------*/ - -if (!window.Node) var Node = { }; - -if (!Node.ELEMENT_NODE) { - Object.extend(Node, { - ELEMENT_NODE: 1, - ATTRIBUTE_NODE: 2, - TEXT_NODE: 3, - CDATA_SECTION_NODE: 4, - ENTITY_REFERENCE_NODE: 5, - ENTITY_NODE: 6, - PROCESSING_INSTRUCTION_NODE: 7, - COMMENT_NODE: 8, - DOCUMENT_NODE: 9, - DOCUMENT_TYPE_NODE: 10, - DOCUMENT_FRAGMENT_NODE: 11, - NOTATION_NODE: 12 - }); -} - - -(function(global) { - - var SETATTRIBUTE_IGNORES_NAME = (function(){ - var elForm = document.createElement("form"); - var elInput = document.createElement("input"); - var root = document.documentElement; - elInput.setAttribute("name", "test"); - elForm.appendChild(elInput); - root.appendChild(elForm); - var isBuggy = elForm.elements - ? (typeof elForm.elements.test == "undefined") - : null; - root.removeChild(elForm); - elForm = elInput = null; - return isBuggy; - })(); - - var element = global.Element; - global.Element = function(tagName, attributes) { - attributes = attributes || { }; - tagName = tagName.toLowerCase(); - var cache = Element.cache; - if (SETATTRIBUTE_IGNORES_NAME && attributes.name) { - tagName = '<' + tagName + ' name="' + attributes.name + '">'; - delete attributes.name; - return Element.writeAttribute(document.createElement(tagName), attributes); - } - if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName)); - return Element.writeAttribute(cache[tagName].cloneNode(false), attributes); - }; - Object.extend(global.Element, element || { }); - if (element) global.Element.prototype = element.prototype; -})(this); - -Element.cache = { }; -Element.idCounter = 1; - -Element.Methods = { - visible: function(element) { - return $(element).style.display != 'none'; - }, - - toggle: function(element) { - element = $(element); - Element[Element.visible(element) ? 'hide' : 'show'](element); - return element; - }, - - - hide: function(element) { - element = $(element); - element.style.display = 'none'; - return element; - }, - - show: function(element) { - element = $(element); - element.style.display = ''; - return element; - }, - - remove: function(element) { - element = $(element); - element.parentNode.removeChild(element); - return element; - }, - - update: (function(){ - - var SELECT_ELEMENT_INNERHTML_BUGGY = (function(){ - var el = document.createElement("select"), - isBuggy = true; - el.innerHTML = ""; - if (el.options && el.options[0]) { - isBuggy = el.options[0].nodeName.toUpperCase() !== "OPTION"; - } - el = null; - return isBuggy; - })(); - - var TABLE_ELEMENT_INNERHTML_BUGGY = (function(){ - try { - var el = document.createElement("table"); - if (el && el.tBodies) { - el.innerHTML = "test"; - var isBuggy = typeof el.tBodies[0] == "undefined"; - el = null; - return isBuggy; - } - } catch (e) { - return true; - } - })(); - - var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () { - var s = document.createElement("script"), - isBuggy = false; - try { - s.appendChild(document.createTextNode("")); - isBuggy = !s.firstChild || - s.firstChild && s.firstChild.nodeType !== 3; - } catch (e) { - isBuggy = true; - } - s = null; - return isBuggy; - })(); - - function update(element, content) { - element = $(element); - - if (content && content.toElement) - content = content.toElement(); - - if (Object.isElement(content)) - return element.update().insert(content); - - content = Object.toHTML(content); - - var tagName = element.tagName.toUpperCase(); - - if (tagName === 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING) { - element.text = content; - return element; - } - - if (SELECT_ELEMENT_INNERHTML_BUGGY || TABLE_ELEMENT_INNERHTML_BUGGY) { - if (tagName in Element._insertionTranslations.tags) { - while (element.firstChild) { - element.removeChild(element.firstChild); - } - Element._getContentFromAnonymousElement(tagName, content.stripScripts()) - .each(function(node) { - element.appendChild(node) - }); - } - else { - element.innerHTML = content.stripScripts(); - } - } - else { - element.innerHTML = content.stripScripts(); - } - - content.evalScripts.bind(content).defer(); - return element; - } - - return update; - })(), - - replace: function(element, content) { - element = $(element); - if (content && content.toElement) content = content.toElement(); - else if (!Object.isElement(content)) { - content = Object.toHTML(content); - var range = element.ownerDocument.createRange(); - range.selectNode(element); - content.evalScripts.bind(content).defer(); - content = range.createContextualFragment(content.stripScripts()); - } - element.parentNode.replaceChild(content, element); - return element; - }, - - insert: function(element, insertions) { - element = $(element); - - if (Object.isString(insertions) || Object.isNumber(insertions) || - Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML))) - insertions = {bottom:insertions}; - - var content, insert, tagName, childNodes; - - for (var position in insertions) { - content = insertions[position]; - position = position.toLowerCase(); - insert = Element._insertionTranslations[position]; - - if (content && content.toElement) content = content.toElement(); - if (Object.isElement(content)) { - insert(element, content); - continue; - } - - content = Object.toHTML(content); - - tagName = ((position == 'before' || position == 'after') - ? element.parentNode : element).tagName.toUpperCase(); - - childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); - - if (position == 'top' || position == 'after') childNodes.reverse(); - childNodes.each(insert.curry(element)); - - content.evalScripts.bind(content).defer(); - } - - return element; - }, - - wrap: function(element, wrapper, attributes) { - element = $(element); - if (Object.isElement(wrapper)) - $(wrapper).writeAttribute(attributes || { }); - else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes); - else wrapper = new Element('div', wrapper); - if (element.parentNode) - element.parentNode.replaceChild(wrapper, element); - wrapper.appendChild(element); - return wrapper; - }, - - inspect: function(element) { - element = $(element); - var result = '<' + element.tagName.toLowerCase(); - $H({'id': 'id', 'className': 'class'}).each(function(pair) { - var property = pair.first(), attribute = pair.last(); - var value = (element[property] || '').toString(); - if (value) result += ' ' + attribute + '=' + value.inspect(true); - }); - return result + '>'; - }, - - recursivelyCollect: function(element, property) { - element = $(element); - var elements = []; - while (element = element[property]) - if (element.nodeType == 1) - elements.push(Element.extend(element)); - return elements; - }, - - ancestors: function(element) { - return Element.recursivelyCollect(element, 'parentNode'); - }, - - descendants: function(element) { - return Element.select(element, "*"); - }, - - firstDescendant: function(element) { - element = $(element).firstChild; - while (element && element.nodeType != 1) element = element.nextSibling; - return $(element); - }, - - immediateDescendants: function(element) { - if (!(element = $(element).firstChild)) return []; - while (element && element.nodeType != 1) element = element.nextSibling; - if (element) return [element].concat($(element).nextSiblings()); - return []; - }, - - previousSiblings: function(element) { - return Element.recursivelyCollect(element, 'previousSibling'); - }, - - nextSiblings: function(element) { - return Element.recursivelyCollect(element, 'nextSibling'); - }, - - siblings: function(element) { - element = $(element); - return Element.previousSiblings(element).reverse() - .concat(Element.nextSiblings(element)); - }, - - match: function(element, selector) { - if (Object.isString(selector)) - selector = new Selector(selector); - return selector.match($(element)); - }, - - up: function(element, expression, index) { - element = $(element); - if (arguments.length == 1) return $(element.parentNode); - var ancestors = Element.ancestors(element); - return Object.isNumber(expression) ? ancestors[expression] : - Selector.findElement(ancestors, expression, index); - }, - - down: function(element, expression, index) { - element = $(element); - if (arguments.length == 1) return Element.firstDescendant(element); - return Object.isNumber(expression) ? Element.descendants(element)[expression] : - Element.select(element, expression)[index || 0]; - }, - - previous: function(element, expression, index) { - element = $(element); - if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element)); - var previousSiblings = Element.previousSiblings(element); - return Object.isNumber(expression) ? previousSiblings[expression] : - Selector.findElement(previousSiblings, expression, index); - }, - - next: function(element, expression, index) { - element = $(element); - if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element)); - var nextSiblings = Element.nextSiblings(element); - return Object.isNumber(expression) ? nextSiblings[expression] : - Selector.findElement(nextSiblings, expression, index); - }, - - - select: function(element) { - var args = Array.prototype.slice.call(arguments, 1); - return Selector.findChildElements(element, args); - }, - - adjacent: function(element) { - var args = Array.prototype.slice.call(arguments, 1); - return Selector.findChildElements(element.parentNode, args).without(element); - }, - - identify: function(element) { - element = $(element); - var id = Element.readAttribute(element, 'id'); - if (id) return id; - do { id = 'anonymous_element_' + Element.idCounter++ } while ($(id)); - Element.writeAttribute(element, 'id', id); - return id; - }, - - readAttribute: function(element, name) { - element = $(element); - if (Prototype.Browser.IE) { - var t = Element._attributeTranslations.read; - if (t.values[name]) return t.values[name](element, name); - if (t.names[name]) name = t.names[name]; - if (name.include(':')) { - return (!element.attributes || !element.attributes[name]) ? null : - element.attributes[name].value; - } - } - return element.getAttribute(name); - }, - - writeAttribute: function(element, name, value) { - element = $(element); - var attributes = { }, t = Element._attributeTranslations.write; - - if (typeof name == 'object') attributes = name; - else attributes[name] = Object.isUndefined(value) ? true : value; - - for (var attr in attributes) { - name = t.names[attr] || attr; - value = attributes[attr]; - if (t.values[attr]) name = t.values[attr](element, value); - if (value === false || value === null) - element.removeAttribute(name); - else if (value === true) - element.setAttribute(name, name); - else element.setAttribute(name, value); - } - return element; - }, - - getHeight: function(element) { - return Element.getDimensions(element).height; - }, - - getWidth: function(element) { - return Element.getDimensions(element).width; - }, - - classNames: function(element) { - return new Element.ClassNames(element); - }, - - hasClassName: function(element, className) { - if (!(element = $(element))) return; - var elementClassName = element.className; - return (elementClassName.length > 0 && (elementClassName == className || - new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName))); - }, - - addClassName: function(element, className) { - if (!(element = $(element))) return; - if (!Element.hasClassName(element, className)) - element.className += (element.className ? ' ' : '') + className; - return element; - }, - - removeClassName: function(element, className) { - if (!(element = $(element))) return; - element.className = element.className.replace( - new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip(); - return element; - }, - - toggleClassName: function(element, className) { - if (!(element = $(element))) return; - return Element[Element.hasClassName(element, className) ? - 'removeClassName' : 'addClassName'](element, className); - }, - - cleanWhitespace: function(element) { - element = $(element); - var node = element.firstChild; - while (node) { - var nextNode = node.nextSibling; - if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) - element.removeChild(node); - node = nextNode; - } - return element; - }, - - empty: function(element) { - return $(element).innerHTML.blank(); - }, - - descendantOf: function(element, ancestor) { - element = $(element), ancestor = $(ancestor); - - if (element.compareDocumentPosition) - return (element.compareDocumentPosition(ancestor) & 8) === 8; - - if (ancestor.contains) - return ancestor.contains(element) && ancestor !== element; - - while (element = element.parentNode) - if (element == ancestor) return true; - - return false; - }, - - scrollTo: function(element) { - element = $(element); - var pos = Element.cumulativeOffset(element); - window.scrollTo(pos[0], pos[1]); - return element; - }, - - getStyle: function(element, style) { - element = $(element); - style = style == 'float' ? 'cssFloat' : style.camelize(); - var value = element.style[style]; - if (!value || value == 'auto') { - var css = document.defaultView.getComputedStyle(element, null); - value = css ? css[style] : null; - } - if (style == 'opacity') return value ? parseFloat(value) : 1.0; - return value == 'auto' ? null : value; - }, - - getOpacity: function(element) { - return $(element).getStyle('opacity'); - }, - - setStyle: function(element, styles) { - element = $(element); - var elementStyle = element.style, match; - if (Object.isString(styles)) { - element.style.cssText += ';' + styles; - return styles.include('opacity') ? - element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element; - } - for (var property in styles) - if (property == 'opacity') element.setOpacity(styles[property]); - else - elementStyle[(property == 'float' || property == 'cssFloat') ? - (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') : - property] = styles[property]; - - return element; - }, - - setOpacity: function(element, value) { - element = $(element); - element.style.opacity = (value == 1 || value === '') ? '' : - (value < 0.00001) ? 0 : value; - return element; - }, - - getDimensions: function(element) { - element = $(element); - var display = Element.getStyle(element, 'display'); - if (display != 'none' && display != null) // Safari bug - return {width: element.offsetWidth, height: element.offsetHeight}; - - var els = element.style; - var originalVisibility = els.visibility; - var originalPosition = els.position; - var originalDisplay = els.display; - els.visibility = 'hidden'; - if (originalPosition != 'fixed') // Switching fixed to absolute causes issues in Safari - els.position = 'absolute'; - els.display = 'block'; - var originalWidth = element.clientWidth; - var originalHeight = element.clientHeight; - els.display = originalDisplay; - els.position = originalPosition; - els.visibility = originalVisibility; - return {width: originalWidth, height: originalHeight}; - }, - - makePositioned: function(element) { - element = $(element); - var pos = Element.getStyle(element, 'position'); - if (pos == 'static' || !pos) { - element._madePositioned = true; - element.style.position = 'relative'; - if (Prototype.Browser.Opera) { - element.style.top = 0; - element.style.left = 0; - } - } - return element; - }, - - undoPositioned: function(element) { - element = $(element); - if (element._madePositioned) { - element._madePositioned = undefined; - element.style.position = - element.style.top = - element.style.left = - element.style.bottom = - element.style.right = ''; - } - return element; - }, - - makeClipping: function(element) { - element = $(element); - if (element._overflow) return element; - element._overflow = Element.getStyle(element, 'overflow') || 'auto'; - if (element._overflow !== 'hidden') - element.style.overflow = 'hidden'; - return element; - }, - - undoClipping: function(element) { - element = $(element); - if (!element._overflow) return element; - element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; - element._overflow = null; - return element; - }, - - cumulativeOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - } while (element); - return Element._returnOffset(valueL, valueT); - }, - - positionedOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - if (element) { - if (element.tagName.toUpperCase() == 'BODY') break; - var p = Element.getStyle(element, 'position'); - if (p !== 'static') break; - } - } while (element); - return Element._returnOffset(valueL, valueT); - }, - - absolutize: function(element) { - element = $(element); - if (Element.getStyle(element, 'position') == 'absolute') return element; - - var offsets = Element.positionedOffset(element); - var top = offsets[1]; - var left = offsets[0]; - var width = element.clientWidth; - var height = element.clientHeight; - - element._originalLeft = left - parseFloat(element.style.left || 0); - element._originalTop = top - parseFloat(element.style.top || 0); - element._originalWidth = element.style.width; - element._originalHeight = element.style.height; - - element.style.position = 'absolute'; - element.style.top = top + 'px'; - element.style.left = left + 'px'; - element.style.width = width + 'px'; - element.style.height = height + 'px'; - return element; - }, - - relativize: function(element) { - element = $(element); - if (Element.getStyle(element, 'position') == 'relative') return element; - - element.style.position = 'relative'; - var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); - var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); - - element.style.top = top + 'px'; - element.style.left = left + 'px'; - element.style.height = element._originalHeight; - element.style.width = element._originalWidth; - return element; - }, - - cumulativeScrollOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.scrollTop || 0; - valueL += element.scrollLeft || 0; - element = element.parentNode; - } while (element); - return Element._returnOffset(valueL, valueT); - }, - - getOffsetParent: function(element) { - if (element.offsetParent) return $(element.offsetParent); - if (element == document.body) return $(element); - - while ((element = element.parentNode) && element != document.body) - if (Element.getStyle(element, 'position') != 'static') - return $(element); - - return $(document.body); - }, - - viewportOffset: function(forElement) { - var valueT = 0, valueL = 0; - - var element = forElement; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - - if (element.offsetParent == document.body && - Element.getStyle(element, 'position') == 'absolute') break; - - } while (element = element.offsetParent); - - element = forElement; - do { - if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) { - valueT -= element.scrollTop || 0; - valueL -= element.scrollLeft || 0; - } - } while (element = element.parentNode); - - return Element._returnOffset(valueL, valueT); - }, - - clonePosition: function(element, source) { - var options = Object.extend({ - setLeft: true, - setTop: true, - setWidth: true, - setHeight: true, - offsetTop: 0, - offsetLeft: 0 - }, arguments[2] || { }); - - source = $(source); - var p = Element.viewportOffset(source); - - element = $(element); - var delta = [0, 0]; - var parent = null; - if (Element.getStyle(element, 'position') == 'absolute') { - parent = Element.getOffsetParent(element); - delta = Element.viewportOffset(parent); - } - - if (parent == document.body) { - delta[0] -= document.body.offsetLeft; - delta[1] -= document.body.offsetTop; - } - - if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; - if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; - if (options.setWidth) element.style.width = source.offsetWidth + 'px'; - if (options.setHeight) element.style.height = source.offsetHeight + 'px'; - return element; - } -}; - -Object.extend(Element.Methods, { - getElementsBySelector: Element.Methods.select, - - childElements: Element.Methods.immediateDescendants -}); - -Element._attributeTranslations = { - write: { - names: { - className: 'class', - htmlFor: 'for' - }, - values: { } - } -}; - -if (Prototype.Browser.Opera) { - Element.Methods.getStyle = Element.Methods.getStyle.wrap( - function(proceed, element, style) { - switch (style) { - case 'left': case 'top': case 'right': case 'bottom': - if (proceed(element, 'position') === 'static') return null; - case 'height': case 'width': - if (!Element.visible(element)) return null; - - var dim = parseInt(proceed(element, style), 10); - - if (dim !== element['offset' + style.capitalize()]) - return dim + 'px'; - - var properties; - if (style === 'height') { - properties = ['border-top-width', 'padding-top', - 'padding-bottom', 'border-bottom-width']; - } - else { - properties = ['border-left-width', 'padding-left', - 'padding-right', 'border-right-width']; - } - return properties.inject(dim, function(memo, property) { - var val = proceed(element, property); - return val === null ? memo : memo - parseInt(val, 10); - }) + 'px'; - default: return proceed(element, style); - } - } - ); - - Element.Methods.readAttribute = Element.Methods.readAttribute.wrap( - function(proceed, element, attribute) { - if (attribute === 'title') return element.title; - return proceed(element, attribute); - } - ); -} - -else if (Prototype.Browser.IE) { - Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap( - function(proceed, element) { - element = $(element); - try { element.offsetParent } - catch(e) { return $(document.body) } - var position = element.getStyle('position'); - if (position !== 'static') return proceed(element); - element.setStyle({ position: 'relative' }); - var value = proceed(element); - element.setStyle({ position: position }); - return value; - } - ); - - $w('positionedOffset viewportOffset').each(function(method) { - Element.Methods[method] = Element.Methods[method].wrap( - function(proceed, element) { - element = $(element); - try { element.offsetParent } - catch(e) { return Element._returnOffset(0,0) } - var position = element.getStyle('position'); - if (position !== 'static') return proceed(element); - var offsetParent = element.getOffsetParent(); - if (offsetParent && offsetParent.getStyle('position') === 'fixed') - offsetParent.setStyle({ zoom: 1 }); - element.setStyle({ position: 'relative' }); - var value = proceed(element); - element.setStyle({ position: position }); - return value; - } - ); - }); - - Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap( - function(proceed, element) { - try { element.offsetParent } - catch(e) { return Element._returnOffset(0,0) } - return proceed(element); - } - ); - - Element.Methods.getStyle = function(element, style) { - element = $(element); - style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); - var value = element.style[style]; - if (!value && element.currentStyle) value = element.currentStyle[style]; - - if (style == 'opacity') { - if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) - if (value[1]) return parseFloat(value[1]) / 100; - return 1.0; - } - - if (value == 'auto') { - if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none')) - return element['offset' + style.capitalize()] + 'px'; - return null; - } - return value; - }; - - Element.Methods.setOpacity = function(element, value) { - function stripAlpha(filter){ - return filter.replace(/alpha\([^\)]*\)/gi,''); - } - element = $(element); - var currentStyle = element.currentStyle; - if ((currentStyle && !currentStyle.hasLayout) || - (!currentStyle && element.style.zoom == 'normal')) - element.style.zoom = 1; - - var filter = element.getStyle('filter'), style = element.style; - if (value == 1 || value === '') { - (filter = stripAlpha(filter)) ? - style.filter = filter : style.removeAttribute('filter'); - return element; - } else if (value < 0.00001) value = 0; - style.filter = stripAlpha(filter) + - 'alpha(opacity=' + (value * 100) + ')'; - return element; - }; - - Element._attributeTranslations = (function(){ - - var classProp = 'className'; - var forProp = 'for'; - - var el = document.createElement('div'); - - el.setAttribute(classProp, 'x'); - - if (el.className !== 'x') { - el.setAttribute('class', 'x'); - if (el.className === 'x') { - classProp = 'class'; - } - } - el = null; - - el = document.createElement('label'); - el.setAttribute(forProp, 'x'); - if (el.htmlFor !== 'x') { - el.setAttribute('htmlFor', 'x'); - if (el.htmlFor === 'x') { - forProp = 'htmlFor'; - } - } - el = null; - - return { - read: { - names: { - 'class': classProp, - 'className': classProp, - 'for': forProp, - 'htmlFor': forProp - }, - values: { - _getAttr: function(element, attribute) { - return element.getAttribute(attribute); - }, - _getAttr2: function(element, attribute) { - return element.getAttribute(attribute, 2); - }, - _getAttrNode: function(element, attribute) { - var node = element.getAttributeNode(attribute); - return node ? node.value : ""; - }, - _getEv: (function(){ - - var el = document.createElement('div'); - el.onclick = Prototype.emptyFunction; - var value = el.getAttribute('onclick'); - var f; - - if (String(value).indexOf('{') > -1) { - f = function(element, attribute) { - attribute = element.getAttribute(attribute); - if (!attribute) return null; - attribute = attribute.toString(); - attribute = attribute.split('{')[1]; - attribute = attribute.split('}')[0]; - return attribute.strip(); - }; - } - else if (value === '') { - f = function(element, attribute) { - attribute = element.getAttribute(attribute); - if (!attribute) return null; - return attribute.strip(); - }; - } - el = null; - return f; - })(), - _flag: function(element, attribute) { - return $(element).hasAttribute(attribute) ? attribute : null; - }, - style: function(element) { - return element.style.cssText.toLowerCase(); - }, - title: function(element) { - return element.title; - } - } - } - } - })(); - - Element._attributeTranslations.write = { - names: Object.extend({ - cellpadding: 'cellPadding', - cellspacing: 'cellSpacing' - }, Element._attributeTranslations.read.names), - values: { - checked: function(element, value) { - element.checked = !!value; - }, - - style: function(element, value) { - element.style.cssText = value ? value : ''; - } - } - }; - - Element._attributeTranslations.has = {}; - - $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' + - 'encType maxLength readOnly longDesc frameBorder').each(function(attr) { - Element._attributeTranslations.write.names[attr.toLowerCase()] = attr; - Element._attributeTranslations.has[attr.toLowerCase()] = attr; - }); - - (function(v) { - Object.extend(v, { - href: v._getAttr2, - src: v._getAttr2, - type: v._getAttr, - action: v._getAttrNode, - disabled: v._flag, - checked: v._flag, - readonly: v._flag, - multiple: v._flag, - onload: v._getEv, - onunload: v._getEv, - onclick: v._getEv, - ondblclick: v._getEv, - onmousedown: v._getEv, - onmouseup: v._getEv, - onmouseover: v._getEv, - onmousemove: v._getEv, - onmouseout: v._getEv, - onfocus: v._getEv, - onblur: v._getEv, - onkeypress: v._getEv, - onkeydown: v._getEv, - onkeyup: v._getEv, - onsubmit: v._getEv, - onreset: v._getEv, - onselect: v._getEv, - onchange: v._getEv - }); - })(Element._attributeTranslations.read.values); - - if (Prototype.BrowserFeatures.ElementExtensions) { - (function() { - function _descendants(element) { - var nodes = element.getElementsByTagName('*'), results = []; - for (var i = 0, node; node = nodes[i]; i++) - if (node.tagName !== "!") // Filter out comment nodes. - results.push(node); - return results; - } - - Element.Methods.down = function(element, expression, index) { - element = $(element); - if (arguments.length == 1) return element.firstDescendant(); - return Object.isNumber(expression) ? _descendants(element)[expression] : - Element.select(element, expression)[index || 0]; - } - })(); - } - -} - -else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) { - Element.Methods.setOpacity = function(element, value) { - element = $(element); - element.style.opacity = (value == 1) ? 0.999999 : - (value === '') ? '' : (value < 0.00001) ? 0 : value; - return element; - }; -} - -else if (Prototype.Browser.WebKit) { - Element.Methods.setOpacity = function(element, value) { - element = $(element); - element.style.opacity = (value == 1 || value === '') ? '' : - (value < 0.00001) ? 0 : value; - - if (value == 1) - if(element.tagName.toUpperCase() == 'IMG' && element.width) { - element.width++; element.width--; - } else try { - var n = document.createTextNode(' '); - element.appendChild(n); - element.removeChild(n); - } catch (e) { } - - return element; - }; - - Element.Methods.cumulativeOffset = function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - if (element.offsetParent == document.body) - if (Element.getStyle(element, 'position') == 'absolute') break; - - element = element.offsetParent; - } while (element); - - return Element._returnOffset(valueL, valueT); - }; -} - -if ('outerHTML' in document.documentElement) { - Element.Methods.replace = function(element, content) { - element = $(element); - - if (content && content.toElement) content = content.toElement(); - if (Object.isElement(content)) { - element.parentNode.replaceChild(content, element); - return element; - } - - content = Object.toHTML(content); - var parent = element.parentNode, tagName = parent.tagName.toUpperCase(); - - if (Element._insertionTranslations.tags[tagName]) { - var nextSibling = element.next(); - var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); - parent.removeChild(element); - if (nextSibling) - fragments.each(function(node) { parent.insertBefore(node, nextSibling) }); - else - fragments.each(function(node) { parent.appendChild(node) }); - } - else element.outerHTML = content.stripScripts(); - - content.evalScripts.bind(content).defer(); - return element; - }; -} - -Element._returnOffset = function(l, t) { - var result = [l, t]; - result.left = l; - result.top = t; - return result; -}; - -Element._getContentFromAnonymousElement = function(tagName, html) { - var div = new Element('div'), t = Element._insertionTranslations.tags[tagName]; - if (t) { - div.innerHTML = t[0] + html + t[1]; - t[2].times(function() { div = div.firstChild }); - } else div.innerHTML = html; - return $A(div.childNodes); -}; - -Element._insertionTranslations = { - before: function(element, node) { - element.parentNode.insertBefore(node, element); - }, - top: function(element, node) { - element.insertBefore(node, element.firstChild); - }, - bottom: function(element, node) { - element.appendChild(node); - }, - after: function(element, node) { - element.parentNode.insertBefore(node, element.nextSibling); - }, - tags: { - TABLE: ['', '
', 1], - TBODY: ['', '
', 2], - TR: ['', '
', 3], - TD: ['
', '
', 4], - SELECT: ['', 1] - } -}; - -(function() { - var tags = Element._insertionTranslations.tags; - Object.extend(tags, { - THEAD: tags.TBODY, - TFOOT: tags.TBODY, - TH: tags.TD - }); -})(); - -Element.Methods.Simulated = { - hasAttribute: function(element, attribute) { - attribute = Element._attributeTranslations.has[attribute] || attribute; - var node = $(element).getAttributeNode(attribute); - return !!(node && node.specified); - } -}; - -Element.Methods.ByTag = { }; - -Object.extend(Element, Element.Methods); - -(function(div) { - - if (!Prototype.BrowserFeatures.ElementExtensions && div['__proto__']) { - window.HTMLElement = { }; - window.HTMLElement.prototype = div['__proto__']; - Prototype.BrowserFeatures.ElementExtensions = true; - } - - div = null; - -})(document.createElement('div')) - -Element.extend = (function() { - - function checkDeficiency(tagName) { - if (typeof window.Element != 'undefined') { - var proto = window.Element.prototype; - if (proto) { - var id = '_' + (Math.random()+'').slice(2); - var el = document.createElement(tagName); - proto[id] = 'x'; - var isBuggy = (el[id] !== 'x'); - delete proto[id]; - el = null; - return isBuggy; - } - } - return false; - } - - function extendElementWith(element, methods) { - for (var property in methods) { - var value = methods[property]; - if (Object.isFunction(value) && !(property in element)) - element[property] = value.methodize(); - } - } - - var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY = checkDeficiency('object'); - - if (Prototype.BrowserFeatures.SpecificElementExtensions) { - if (HTMLOBJECTELEMENT_PROTOTYPE_BUGGY) { - return function(element) { - if (element && typeof element._extendedByPrototype == 'undefined') { - var t = element.tagName; - if (t && (/^(?:object|applet|embed)$/i.test(t))) { - extendElementWith(element, Element.Methods); - extendElementWith(element, Element.Methods.Simulated); - extendElementWith(element, Element.Methods.ByTag[t.toUpperCase()]); - } - } - return element; - } - } - return Prototype.K; - } - - var Methods = { }, ByTag = Element.Methods.ByTag; - - var extend = Object.extend(function(element) { - if (!element || typeof element._extendedByPrototype != 'undefined' || - element.nodeType != 1 || element == window) return element; - - var methods = Object.clone(Methods), - tagName = element.tagName.toUpperCase(); - - if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]); - - extendElementWith(element, methods); - - element._extendedByPrototype = Prototype.emptyFunction; - return element; - - }, { - refresh: function() { - if (!Prototype.BrowserFeatures.ElementExtensions) { - Object.extend(Methods, Element.Methods); - Object.extend(Methods, Element.Methods.Simulated); - } - } - }); - - extend.refresh(); - return extend; -})(); - -Element.hasAttribute = function(element, attribute) { - if (element.hasAttribute) return element.hasAttribute(attribute); - return Element.Methods.Simulated.hasAttribute(element, attribute); -}; - -Element.addMethods = function(methods) { - var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag; - - if (!methods) { - Object.extend(Form, Form.Methods); - Object.extend(Form.Element, Form.Element.Methods); - Object.extend(Element.Methods.ByTag, { - "FORM": Object.clone(Form.Methods), - "INPUT": Object.clone(Form.Element.Methods), - "SELECT": Object.clone(Form.Element.Methods), - "TEXTAREA": Object.clone(Form.Element.Methods) - }); - } - - if (arguments.length == 2) { - var tagName = methods; - methods = arguments[1]; - } - - if (!tagName) Object.extend(Element.Methods, methods || { }); - else { - if (Object.isArray(tagName)) tagName.each(extend); - else extend(tagName); - } - - function extend(tagName) { - tagName = tagName.toUpperCase(); - if (!Element.Methods.ByTag[tagName]) - Element.Methods.ByTag[tagName] = { }; - Object.extend(Element.Methods.ByTag[tagName], methods); - } - - function copy(methods, destination, onlyIfAbsent) { - onlyIfAbsent = onlyIfAbsent || false; - for (var property in methods) { - var value = methods[property]; - if (!Object.isFunction(value)) continue; - if (!onlyIfAbsent || !(property in destination)) - destination[property] = value.methodize(); - } - } - - function findDOMClass(tagName) { - var klass; - var trans = { - "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph", - "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList", - "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading", - "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote", - "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION": - "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD": - "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR": - "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET": - "FrameSet", "IFRAME": "IFrame" - }; - if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element'; - if (window[klass]) return window[klass]; - klass = 'HTML' + tagName + 'Element'; - if (window[klass]) return window[klass]; - klass = 'HTML' + tagName.capitalize() + 'Element'; - if (window[klass]) return window[klass]; - - var element = document.createElement(tagName); - var proto = element['__proto__'] || element.constructor.prototype; - element = null; - return proto; - } - - var elementPrototype = window.HTMLElement ? HTMLElement.prototype : - Element.prototype; - - if (F.ElementExtensions) { - copy(Element.Methods, elementPrototype); - copy(Element.Methods.Simulated, elementPrototype, true); - } - - if (F.SpecificElementExtensions) { - for (var tag in Element.Methods.ByTag) { - var klass = findDOMClass(tag); - if (Object.isUndefined(klass)) continue; - copy(T[tag], klass.prototype); - } - } - - Object.extend(Element, Element.Methods); - delete Element.ByTag; - - if (Element.extend.refresh) Element.extend.refresh(); - Element.cache = { }; -}; - - -document.viewport = { - - getDimensions: function() { - return { width: this.getWidth(), height: this.getHeight() }; - }, - - getScrollOffsets: function() { - return Element._returnOffset( - window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft, - window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); - } -}; - -(function(viewport) { - var B = Prototype.Browser, doc = document, element, property = {}; - - function getRootElement() { - if (B.WebKit && !doc.evaluate) - return document; - - if (B.Opera && window.parseFloat(window.opera.version()) < 9.5) - return document.body; - - return document.documentElement; - } - - function define(D) { - if (!element) element = getRootElement(); - - property[D] = 'client' + D; - - viewport['get' + D] = function() { return element[property[D]] }; - return viewport['get' + D](); - } - - viewport.getWidth = define.curry('Width'); - - viewport.getHeight = define.curry('Height'); -})(document.viewport); - - -Element.Storage = { - UID: 1 -}; - -Element.addMethods({ - getStorage: function(element) { - if (!(element = $(element))) return; - - var uid; - if (element === window) { - uid = 0; - } else { - if (typeof element._prototypeUID === "undefined") - element._prototypeUID = [Element.Storage.UID++]; - uid = element._prototypeUID[0]; - } - - if (!Element.Storage[uid]) - Element.Storage[uid] = $H(); - - return Element.Storage[uid]; - }, - - store: function(element, key, value) { - if (!(element = $(element))) return; - - if (arguments.length === 2) { - Element.getStorage(element).update(key); - } else { - Element.getStorage(element).set(key, value); - } - - return element; - }, - - retrieve: function(element, key, defaultValue) { - if (!(element = $(element))) return; - var hash = Element.getStorage(element), value = hash.get(key); - - if (Object.isUndefined(value)) { - hash.set(key, defaultValue); - value = defaultValue; - } - - return value; - }, - - clone: function(element, deep) { - if (!(element = $(element))) return; - var clone = element.cloneNode(deep); - clone._prototypeUID = void 0; - if (deep) { - var descendants = Element.select(clone, '*'), - i = descendants.length; - while (i--) { - descendants[i]._prototypeUID = void 0; - } - } - return Element.extend(clone); - } -}); -/* Portions of the Selector class are derived from Jack Slocum's DomQuery, - * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style - * license. Please see http://www.yui-ext.com/ for more information. */ - -var Selector = Class.create({ - initialize: function(expression) { - this.expression = expression.strip(); - - if (this.shouldUseSelectorsAPI()) { - this.mode = 'selectorsAPI'; - } else if (this.shouldUseXPath()) { - this.mode = 'xpath'; - this.compileXPathMatcher(); - } else { - this.mode = "normal"; - this.compileMatcher(); - } - - }, - - shouldUseXPath: (function() { - - var IS_DESCENDANT_SELECTOR_BUGGY = (function(){ - var isBuggy = false; - if (document.evaluate && window.XPathResult) { - var el = document.createElement('div'); - el.innerHTML = '
'; - - var xpath = ".//*[local-name()='ul' or local-name()='UL']" + - "//*[local-name()='li' or local-name()='LI']"; - - var result = document.evaluate(xpath, el, null, - XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); - - isBuggy = (result.snapshotLength !== 2); - el = null; - } - return isBuggy; - })(); - - return function() { - if (!Prototype.BrowserFeatures.XPath) return false; - - var e = this.expression; - - if (Prototype.Browser.WebKit && - (e.include("-of-type") || e.include(":empty"))) - return false; - - if ((/(\[[\w-]*?:|:checked)/).test(e)) - return false; - - if (IS_DESCENDANT_SELECTOR_BUGGY) return false; - - return true; - } - - })(), - - shouldUseSelectorsAPI: function() { - if (!Prototype.BrowserFeatures.SelectorsAPI) return false; - - if (Selector.CASE_INSENSITIVE_CLASS_NAMES) return false; - - if (!Selector._div) Selector._div = new Element('div'); - - try { - Selector._div.querySelector(this.expression); - } catch(e) { - return false; - } - - return true; - }, - - compileMatcher: function() { - var e = this.expression, ps = Selector.patterns, h = Selector.handlers, - c = Selector.criteria, le, p, m, len = ps.length, name; - - if (Selector._cache[e]) { - this.matcher = Selector._cache[e]; - return; - } - - this.matcher = ["this.matcher = function(root) {", - "var r = root, h = Selector.handlers, c = false, n;"]; - - while (e && le != e && (/\S/).test(e)) { - le = e; - for (var i = 0; i"; - } -}); - -if (Prototype.BrowserFeatures.SelectorsAPI && - document.compatMode === 'BackCompat') { - Selector.CASE_INSENSITIVE_CLASS_NAMES = (function(){ - var div = document.createElement('div'), - span = document.createElement('span'); - - div.id = "prototype_test_id"; - span.className = 'Test'; - div.appendChild(span); - var isIgnored = (div.querySelector('#prototype_test_id .test') !== null); - div = span = null; - return isIgnored; - })(); -} - -Object.extend(Selector, { - _cache: { }, - - xpath: { - descendant: "//*", - child: "/*", - adjacent: "/following-sibling::*[1]", - laterSibling: '/following-sibling::*', - tagName: function(m) { - if (m[1] == '*') return ''; - return "[local-name()='" + m[1].toLowerCase() + - "' or local-name()='" + m[1].toUpperCase() + "']"; - }, - className: "[contains(concat(' ', @class, ' '), ' #{1} ')]", - id: "[@id='#{1}']", - attrPresence: function(m) { - m[1] = m[1].toLowerCase(); - return new Template("[@#{1}]").evaluate(m); - }, - attr: function(m) { - m[1] = m[1].toLowerCase(); - m[3] = m[5] || m[6]; - return new Template(Selector.xpath.operators[m[2]]).evaluate(m); - }, - pseudo: function(m) { - var h = Selector.xpath.pseudos[m[1]]; - if (!h) return ''; - if (Object.isFunction(h)) return h(m); - return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m); - }, - operators: { - '=': "[@#{1}='#{3}']", - '!=': "[@#{1}!='#{3}']", - '^=': "[starts-with(@#{1}, '#{3}')]", - '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']", - '*=': "[contains(@#{1}, '#{3}')]", - '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]", - '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]" - }, - pseudos: { - 'first-child': '[not(preceding-sibling::*)]', - 'last-child': '[not(following-sibling::*)]', - 'only-child': '[not(preceding-sibling::* or following-sibling::*)]', - 'empty': "[count(*) = 0 and (count(text()) = 0)]", - 'checked': "[@checked]", - 'disabled': "[(@disabled) and (@type!='hidden')]", - 'enabled': "[not(@disabled) and (@type!='hidden')]", - 'not': function(m) { - var e = m[6], p = Selector.patterns, - x = Selector.xpath, le, v, len = p.length, name; - - var exclusion = []; - while (e && le != e && (/\S/).test(e)) { - le = e; - for (var i = 0; i= 0)]"; - return new Template(predicate).evaluate({ - fragment: fragment, a: a, b: b }); - } - } - } - }, - - criteria: { - tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;', - className: 'n = h.className(n, r, "#{1}", c); c = false;', - id: 'n = h.id(n, r, "#{1}", c); c = false;', - attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;', - attr: function(m) { - m[3] = (m[5] || m[6]); - return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m); - }, - pseudo: function(m) { - if (m[6]) m[6] = m[6].replace(/"/g, '\\"'); - return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m); - }, - descendant: 'c = "descendant";', - child: 'c = "child";', - adjacent: 'c = "adjacent";', - laterSibling: 'c = "laterSibling";' - }, - - patterns: [ - { name: 'laterSibling', re: /^\s*~\s*/ }, - { name: 'child', re: /^\s*>\s*/ }, - { name: 'adjacent', re: /^\s*\+\s*/ }, - { name: 'descendant', re: /^\s/ }, - - { name: 'tagName', re: /^\s*(\*|[\w\-]+)(\b|$)?/ }, - { name: 'id', re: /^#([\w\-\*]+)(\b|$)/ }, - { name: 'className', re: /^\.([\w\-\*]+)(\b|$)/ }, - { name: 'pseudo', re: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/ }, - { name: 'attrPresence', re: /^\[((?:[\w-]+:)?[\w-]+)\]/ }, - { name: 'attr', re: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/ } - ], - - assertions: { - tagName: function(element, matches) { - return matches[1].toUpperCase() == element.tagName.toUpperCase(); - }, - - className: function(element, matches) { - return Element.hasClassName(element, matches[1]); - }, - - id: function(element, matches) { - return element.id === matches[1]; - }, - - attrPresence: function(element, matches) { - return Element.hasAttribute(element, matches[1]); - }, - - attr: function(element, matches) { - var nodeValue = Element.readAttribute(element, matches[1]); - return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]); - } - }, - - handlers: { - concat: function(a, b) { - for (var i = 0, node; node = b[i]; i++) - a.push(node); - return a; - }, - - mark: function(nodes) { - var _true = Prototype.emptyFunction; - for (var i = 0, node; node = nodes[i]; i++) - node._countedByPrototype = _true; - return nodes; - }, - - unmark: (function(){ - - var PROPERTIES_ATTRIBUTES_MAP = (function(){ - var el = document.createElement('div'), - isBuggy = false, - propName = '_countedByPrototype', - value = 'x' - el[propName] = value; - isBuggy = (el.getAttribute(propName) === value); - el = null; - return isBuggy; - })(); - - return PROPERTIES_ATTRIBUTES_MAP ? - function(nodes) { - for (var i = 0, node; node = nodes[i]; i++) - node.removeAttribute('_countedByPrototype'); - return nodes; - } : - function(nodes) { - for (var i = 0, node; node = nodes[i]; i++) - node._countedByPrototype = void 0; - return nodes; - } - })(), - - index: function(parentNode, reverse, ofType) { - parentNode._countedByPrototype = Prototype.emptyFunction; - if (reverse) { - for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) { - var node = nodes[i]; - if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; - } - } else { - for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++) - if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; - } - }, - - unique: function(nodes) { - if (nodes.length == 0) return nodes; - var results = [], n; - for (var i = 0, l = nodes.length; i < l; i++) - if (typeof (n = nodes[i])._countedByPrototype == 'undefined') { - n._countedByPrototype = Prototype.emptyFunction; - results.push(Element.extend(n)); - } - return Selector.handlers.unmark(results); - }, - - descendant: function(nodes) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) - h.concat(results, node.getElementsByTagName('*')); - return results; - }, - - child: function(nodes) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) { - for (var j = 0, child; child = node.childNodes[j]; j++) - if (child.nodeType == 1 && child.tagName != '!') results.push(child); - } - return results; - }, - - adjacent: function(nodes) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - var next = this.nextElementSibling(node); - if (next) results.push(next); - } - return results; - }, - - laterSibling: function(nodes) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) - h.concat(results, Element.nextSiblings(node)); - return results; - }, - - nextElementSibling: function(node) { - while (node = node.nextSibling) - if (node.nodeType == 1) return node; - return null; - }, - - previousElementSibling: function(node) { - while (node = node.previousSibling) - if (node.nodeType == 1) return node; - return null; - }, - - tagName: function(nodes, root, tagName, combinator) { - var uTagName = tagName.toUpperCase(); - var results = [], h = Selector.handlers; - if (nodes) { - if (combinator) { - if (combinator == "descendant") { - for (var i = 0, node; node = nodes[i]; i++) - h.concat(results, node.getElementsByTagName(tagName)); - return results; - } else nodes = this[combinator](nodes); - if (tagName == "*") return nodes; - } - for (var i = 0, node; node = nodes[i]; i++) - if (node.tagName.toUpperCase() === uTagName) results.push(node); - return results; - } else return root.getElementsByTagName(tagName); - }, - - id: function(nodes, root, id, combinator) { - var targetNode = $(id), h = Selector.handlers; - - if (root == document) { - if (!targetNode) return []; - if (!nodes) return [targetNode]; - } else { - if (!root.sourceIndex || root.sourceIndex < 1) { - var nodes = root.getElementsByTagName('*'); - for (var j = 0, node; node = nodes[j]; j++) { - if (node.id === id) return [node]; - } - } - } - - if (nodes) { - if (combinator) { - if (combinator == 'child') { - for (var i = 0, node; node = nodes[i]; i++) - if (targetNode.parentNode == node) return [targetNode]; - } else if (combinator == 'descendant') { - for (var i = 0, node; node = nodes[i]; i++) - if (Element.descendantOf(targetNode, node)) return [targetNode]; - } else if (combinator == 'adjacent') { - for (var i = 0, node; node = nodes[i]; i++) - if (Selector.handlers.previousElementSibling(targetNode) == node) - return [targetNode]; - } else nodes = h[combinator](nodes); - } - for (var i = 0, node; node = nodes[i]; i++) - if (node == targetNode) return [targetNode]; - return []; - } - return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : []; - }, - - className: function(nodes, root, className, combinator) { - if (nodes && combinator) nodes = this[combinator](nodes); - return Selector.handlers.byClassName(nodes, root, className); - }, - - byClassName: function(nodes, root, className) { - if (!nodes) nodes = Selector.handlers.descendant([root]); - var needle = ' ' + className + ' '; - for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) { - nodeClassName = node.className; - if (nodeClassName.length == 0) continue; - if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle)) - results.push(node); - } - return results; - }, - - attrPresence: function(nodes, root, attr, combinator) { - if (!nodes) nodes = root.getElementsByTagName("*"); - if (nodes && combinator) nodes = this[combinator](nodes); - var results = []; - for (var i = 0, node; node = nodes[i]; i++) - if (Element.hasAttribute(node, attr)) results.push(node); - return results; - }, - - attr: function(nodes, root, attr, value, operator, combinator) { - if (!nodes) nodes = root.getElementsByTagName("*"); - if (nodes && combinator) nodes = this[combinator](nodes); - var handler = Selector.operators[operator], results = []; - for (var i = 0, node; node = nodes[i]; i++) { - var nodeValue = Element.readAttribute(node, attr); - if (nodeValue === null) continue; - if (handler(nodeValue, value)) results.push(node); - } - return results; - }, - - pseudo: function(nodes, name, value, root, combinator) { - if (nodes && combinator) nodes = this[combinator](nodes); - if (!nodes) nodes = root.getElementsByTagName("*"); - return Selector.pseudos[name](nodes, value, root); - } - }, - - pseudos: { - 'first-child': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - if (Selector.handlers.previousElementSibling(node)) continue; - results.push(node); - } - return results; - }, - 'last-child': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - if (Selector.handlers.nextElementSibling(node)) continue; - results.push(node); - } - return results; - }, - 'only-child': function(nodes, value, root) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (!h.previousElementSibling(node) && !h.nextElementSibling(node)) - results.push(node); - return results; - }, - 'nth-child': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root); - }, - 'nth-last-child': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root, true); - }, - 'nth-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root, false, true); - }, - 'nth-last-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root, true, true); - }, - 'first-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, "1", root, false, true); - }, - 'last-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, "1", root, true, true); - }, - 'only-of-type': function(nodes, formula, root) { - var p = Selector.pseudos; - return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root); - }, - - getIndices: function(a, b, total) { - if (a == 0) return b > 0 ? [b] : []; - return $R(1, total).inject([], function(memo, i) { - if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i); - return memo; - }); - }, - - nth: function(nodes, formula, root, reverse, ofType) { - if (nodes.length == 0) return []; - if (formula == 'even') formula = '2n+0'; - if (formula == 'odd') formula = '2n+1'; - var h = Selector.handlers, results = [], indexed = [], m; - h.mark(nodes); - for (var i = 0, node; node = nodes[i]; i++) { - if (!node.parentNode._countedByPrototype) { - h.index(node.parentNode, reverse, ofType); - indexed.push(node.parentNode); - } - } - if (formula.match(/^\d+$/)) { // just a number - formula = Number(formula); - for (var i = 0, node; node = nodes[i]; i++) - if (node.nodeIndex == formula) results.push(node); - } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b - if (m[1] == "-") m[1] = -1; - var a = m[1] ? Number(m[1]) : 1; - var b = m[2] ? Number(m[2]) : 0; - var indices = Selector.pseudos.getIndices(a, b, nodes.length); - for (var i = 0, node, l = indices.length; node = nodes[i]; i++) { - for (var j = 0; j < l; j++) - if (node.nodeIndex == indices[j]) results.push(node); - } - } - h.unmark(nodes); - h.unmark(indexed); - return results; - }, - - 'empty': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - if (node.tagName == '!' || node.firstChild) continue; - results.push(node); - } - return results; - }, - - 'not': function(nodes, selector, root) { - var h = Selector.handlers, selectorType, m; - var exclusions = new Selector(selector).findElements(root); - h.mark(exclusions); - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (!node._countedByPrototype) results.push(node); - h.unmark(exclusions); - return results; - }, - - 'enabled': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (!node.disabled && (!node.type || node.type !== 'hidden')) - results.push(node); - return results; - }, - - 'disabled': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (node.disabled) results.push(node); - return results; - }, - - 'checked': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (node.checked) results.push(node); - return results; - } - }, - - operators: { - '=': function(nv, v) { return nv == v; }, - '!=': function(nv, v) { return nv != v; }, - '^=': function(nv, v) { return nv == v || nv && nv.startsWith(v); }, - '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); }, - '*=': function(nv, v) { return nv == v || nv && nv.include(v); }, - '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); }, - '|=': function(nv, v) { return ('-' + (nv || "").toUpperCase() + - '-').include('-' + (v || "").toUpperCase() + '-'); } - }, - - split: function(expression) { - var expressions = []; - expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) { - expressions.push(m[1].strip()); - }); - return expressions; - }, - - matchElements: function(elements, expression) { - var matches = $$(expression), h = Selector.handlers; - h.mark(matches); - for (var i = 0, results = [], element; element = elements[i]; i++) - if (element._countedByPrototype) results.push(element); - h.unmark(matches); - return results; - }, - - findElement: function(elements, expression, index) { - if (Object.isNumber(expression)) { - index = expression; expression = false; - } - return Selector.matchElements(elements, expression || '*')[index || 0]; - }, - - findChildElements: function(element, expressions) { - expressions = Selector.split(expressions.join(',')); - var results = [], h = Selector.handlers; - for (var i = 0, l = expressions.length, selector; i < l; i++) { - selector = new Selector(expressions[i].strip()); - h.concat(results, selector.findElements(element)); - } - return (l > 1) ? h.unique(results) : results; - } -}); - -if (Prototype.Browser.IE) { - Object.extend(Selector.handlers, { - concat: function(a, b) { - for (var i = 0, node; node = b[i]; i++) - if (node.tagName !== "!") a.push(node); - return a; - } - }); -} - -function $$() { - return Selector.findChildElements(document, $A(arguments)); -} - -var Form = { - reset: function(form) { - form = $(form); - form.reset(); - return form; - }, - - serializeElements: function(elements, options) { - if (typeof options != 'object') options = { hash: !!options }; - else if (Object.isUndefined(options.hash)) options.hash = true; - var key, value, submitted = false, submit = options.submit; - - var data = elements.inject({ }, function(result, element) { - if (!element.disabled && element.name) { - key = element.name; value = $(element).getValue(); - if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted && - submit !== false && (!submit || key == submit) && (submitted = true)))) { - if (key in result) { - if (!Object.isArray(result[key])) result[key] = [result[key]]; - result[key].push(value); - } - else result[key] = value; - } - } - return result; - }); - - return options.hash ? data : Object.toQueryString(data); - } -}; - -Form.Methods = { - serialize: function(form, options) { - return Form.serializeElements(Form.getElements(form), options); - }, - - getElements: function(form) { - var elements = $(form).getElementsByTagName('*'), - element, - arr = [ ], - serializers = Form.Element.Serializers; - for (var i = 0; element = elements[i]; i++) { - arr.push(element); - } - return arr.inject([], function(elements, child) { - if (serializers[child.tagName.toLowerCase()]) - elements.push(Element.extend(child)); - return elements; - }) - }, - - getInputs: function(form, typeName, name) { - form = $(form); - var inputs = form.getElementsByTagName('input'); - - if (!typeName && !name) return $A(inputs).map(Element.extend); - - for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { - var input = inputs[i]; - if ((typeName && input.type != typeName) || (name && input.name != name)) - continue; - matchingInputs.push(Element.extend(input)); - } - - return matchingInputs; - }, - - disable: function(form) { - form = $(form); - Form.getElements(form).invoke('disable'); - return form; - }, - - enable: function(form) { - form = $(form); - Form.getElements(form).invoke('enable'); - return form; - }, - - findFirstElement: function(form) { - var elements = $(form).getElements().findAll(function(element) { - return 'hidden' != element.type && !element.disabled; - }); - var firstByIndex = elements.findAll(function(element) { - return element.hasAttribute('tabIndex') && element.tabIndex >= 0; - }).sortBy(function(element) { return element.tabIndex }).first(); - - return firstByIndex ? firstByIndex : elements.find(function(element) { - return /^(?:input|select|textarea)$/i.test(element.tagName); - }); - }, - - focusFirstElement: function(form) { - form = $(form); - form.findFirstElement().activate(); - return form; - }, - - request: function(form, options) { - form = $(form), options = Object.clone(options || { }); - - var params = options.parameters, action = form.readAttribute('action') || ''; - if (action.blank()) action = window.location.href; - options.parameters = form.serialize(true); - - if (params) { - if (Object.isString(params)) params = params.toQueryParams(); - Object.extend(options.parameters, params); - } - - if (form.hasAttribute('method') && !options.method) - options.method = form.method; - - return new Ajax.Request(action, options); - } -}; - -/*--------------------------------------------------------------------------*/ - - -Form.Element = { - focus: function(element) { - $(element).focus(); - return element; - }, - - select: function(element) { - $(element).select(); - return element; - } -}; - -Form.Element.Methods = { - - serialize: function(element) { - element = $(element); - if (!element.disabled && element.name) { - var value = element.getValue(); - if (value != undefined) { - var pair = { }; - pair[element.name] = value; - return Object.toQueryString(pair); - } - } - return ''; - }, - - getValue: function(element) { - element = $(element); - var method = element.tagName.toLowerCase(); - return Form.Element.Serializers[method](element); - }, - - setValue: function(element, value) { - element = $(element); - var method = element.tagName.toLowerCase(); - Form.Element.Serializers[method](element, value); - return element; - }, - - clear: function(element) { - $(element).value = ''; - return element; - }, - - present: function(element) { - return $(element).value != ''; - }, - - activate: function(element) { - element = $(element); - try { - element.focus(); - if (element.select && (element.tagName.toLowerCase() != 'input' || - !(/^(?:button|reset|submit)$/i.test(element.type)))) - element.select(); - } catch (e) { } - return element; - }, - - disable: function(element) { - element = $(element); - element.disabled = true; - return element; - }, - - enable: function(element) { - element = $(element); - element.disabled = false; - return element; - } -}; - -/*--------------------------------------------------------------------------*/ - -var Field = Form.Element; - -var $F = Form.Element.Methods.getValue; - -/*--------------------------------------------------------------------------*/ - -Form.Element.Serializers = { - input: function(element, value) { - switch (element.type.toLowerCase()) { - case 'checkbox': - case 'radio': - return Form.Element.Serializers.inputSelector(element, value); - default: - return Form.Element.Serializers.textarea(element, value); - } - }, - - inputSelector: function(element, value) { - if (Object.isUndefined(value)) return element.checked ? element.value : null; - else element.checked = !!value; - }, - - textarea: function(element, value) { - if (Object.isUndefined(value)) return element.value; - else element.value = value; - }, - - select: function(element, value) { - if (Object.isUndefined(value)) - return this[element.type == 'select-one' ? - 'selectOne' : 'selectMany'](element); - else { - var opt, currentValue, single = !Object.isArray(value); - for (var i = 0, length = element.length; i < length; i++) { - opt = element.options[i]; - currentValue = this.optionValue(opt); - if (single) { - if (currentValue == value) { - opt.selected = true; - return; - } - } - else opt.selected = value.include(currentValue); - } - } - }, - - selectOne: function(element) { - var index = element.selectedIndex; - return index >= 0 ? this.optionValue(element.options[index]) : null; - }, - - selectMany: function(element) { - var values, length = element.length; - if (!length) return null; - - for (var i = 0, values = []; i < length; i++) { - var opt = element.options[i]; - if (opt.selected) values.push(this.optionValue(opt)); - } - return values; - }, - - optionValue: function(opt) { - return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; - } -}; - -/*--------------------------------------------------------------------------*/ - - -Abstract.TimedObserver = Class.create(PeriodicalExecuter, { - initialize: function($super, element, frequency, callback) { - $super(callback, frequency); - this.element = $(element); - this.lastValue = this.getValue(); - }, - - execute: function() { - var value = this.getValue(); - if (Object.isString(this.lastValue) && Object.isString(value) ? - this.lastValue != value : String(this.lastValue) != String(value)) { - this.callback(this.element, value); - this.lastValue = value; - } - } -}); - -Form.Element.Observer = Class.create(Abstract.TimedObserver, { - getValue: function() { - return Form.Element.getValue(this.element); - } -}); - -Form.Observer = Class.create(Abstract.TimedObserver, { - getValue: function() { - return Form.serialize(this.element); - } -}); - -/*--------------------------------------------------------------------------*/ - -Abstract.EventObserver = Class.create({ - initialize: function(element, callback) { - this.element = $(element); - this.callback = callback; - - this.lastValue = this.getValue(); - if (this.element.tagName.toLowerCase() == 'form') - this.registerFormCallbacks(); - else - this.registerCallback(this.element); - }, - - onElementEvent: function() { - var value = this.getValue(); - if (this.lastValue != value) { - this.callback(this.element, value); - this.lastValue = value; - } - }, - - registerFormCallbacks: function() { - Form.getElements(this.element).each(this.registerCallback, this); - }, - - registerCallback: function(element) { - if (element.type) { - switch (element.type.toLowerCase()) { - case 'checkbox': - case 'radio': - Event.observe(element, 'click', this.onElementEvent.bind(this)); - break; - default: - Event.observe(element, 'change', this.onElementEvent.bind(this)); - break; - } - } - } -}); - -Form.Element.EventObserver = Class.create(Abstract.EventObserver, { - getValue: function() { - return Form.Element.getValue(this.element); - } -}); - -Form.EventObserver = Class.create(Abstract.EventObserver, { - getValue: function() { - return Form.serialize(this.element); - } -}); -(function() { - - var Event = { - KEY_BACKSPACE: 8, - KEY_TAB: 9, - KEY_RETURN: 13, - KEY_ESC: 27, - KEY_LEFT: 37, - KEY_UP: 38, - KEY_RIGHT: 39, - KEY_DOWN: 40, - KEY_DELETE: 46, - KEY_HOME: 36, - KEY_END: 35, - KEY_PAGEUP: 33, - KEY_PAGEDOWN: 34, - KEY_INSERT: 45, - - cache: {} - }; - - var docEl = document.documentElement; - var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl - && 'onmouseleave' in docEl; - - var _isButton; - if (Prototype.Browser.IE) { - var buttonMap = { 0: 1, 1: 4, 2: 2 }; - _isButton = function(event, code) { - return event.button === buttonMap[code]; - }; - } else if (Prototype.Browser.WebKit) { - _isButton = function(event, code) { - switch (code) { - case 0: return event.which == 1 && !event.metaKey; - case 1: return event.which == 1 && event.metaKey; - default: return false; - } - }; - } else { - _isButton = function(event, code) { - return event.which ? (event.which === code + 1) : (event.button === code); - }; - } - - function isLeftClick(event) { return _isButton(event, 0) } - - function isMiddleClick(event) { return _isButton(event, 1) } - - function isRightClick(event) { return _isButton(event, 2) } - - function element(event) { - event = Event.extend(event); - - var node = event.target, type = event.type, - currentTarget = event.currentTarget; - - if (currentTarget && currentTarget.tagName) { - if (type === 'load' || type === 'error' || - (type === 'click' && currentTarget.tagName.toLowerCase() === 'input' - && currentTarget.type === 'radio')) - node = currentTarget; - } - - if (node.nodeType == Node.TEXT_NODE) - node = node.parentNode; - - return Element.extend(node); - } - - function findElement(event, expression) { - var element = Event.element(event); - if (!expression) return element; - var elements = [element].concat(element.ancestors()); - return Selector.findElement(elements, expression, 0); - } - - function pointer(event) { - return { x: pointerX(event), y: pointerY(event) }; - } - - function pointerX(event) { - var docElement = document.documentElement, - body = document.body || { scrollLeft: 0 }; - - return event.pageX || (event.clientX + - (docElement.scrollLeft || body.scrollLeft) - - (docElement.clientLeft || 0)); - } - - function pointerY(event) { - var docElement = document.documentElement, - body = document.body || { scrollTop: 0 }; - - return event.pageY || (event.clientY + - (docElement.scrollTop || body.scrollTop) - - (docElement.clientTop || 0)); - } - - - function stop(event) { - Event.extend(event); - event.preventDefault(); - event.stopPropagation(); - - event.stopped = true; - } - - Event.Methods = { - isLeftClick: isLeftClick, - isMiddleClick: isMiddleClick, - isRightClick: isRightClick, - - element: element, - findElement: findElement, - - pointer: pointer, - pointerX: pointerX, - pointerY: pointerY, - - stop: stop - }; - - - var methods = Object.keys(Event.Methods).inject({ }, function(m, name) { - m[name] = Event.Methods[name].methodize(); - return m; - }); - - if (Prototype.Browser.IE) { - function _relatedTarget(event) { - var element; - switch (event.type) { - case 'mouseover': element = event.fromElement; break; - case 'mouseout': element = event.toElement; break; - default: return null; - } - return Element.extend(element); - } - - Object.extend(methods, { - stopPropagation: function() { this.cancelBubble = true }, - preventDefault: function() { this.returnValue = false }, - inspect: function() { return '[object Event]' } - }); - - Event.extend = function(event, element) { - if (!event) return false; - if (event._extendedByPrototype) return event; - - event._extendedByPrototype = Prototype.emptyFunction; - var pointer = Event.pointer(event); - - Object.extend(event, { - target: event.srcElement || element, - relatedTarget: _relatedTarget(event), - pageX: pointer.x, - pageY: pointer.y - }); - - return Object.extend(event, methods); - }; - } else { - Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__; - Object.extend(Event.prototype, methods); - Event.extend = Prototype.K; - } - - function _createResponder(element, eventName, handler) { - var registry = Element.retrieve(element, 'prototype_event_registry'); - - if (Object.isUndefined(registry)) { - CACHE.push(element); - registry = Element.retrieve(element, 'prototype_event_registry', $H()); - } - - var respondersForEvent = registry.get(eventName); - if (Object.isUndefined(respondersForEvent)) { - respondersForEvent = []; - registry.set(eventName, respondersForEvent); - } - - if (respondersForEvent.pluck('handler').include(handler)) return false; - - var responder; - if (eventName.include(":")) { - responder = function(event) { - if (Object.isUndefined(event.eventName)) - return false; - - if (event.eventName !== eventName) - return false; - - Event.extend(event, element); - handler.call(element, event); - }; - } else { - if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED && - (eventName === "mouseenter" || eventName === "mouseleave")) { - if (eventName === "mouseenter" || eventName === "mouseleave") { - responder = function(event) { - Event.extend(event, element); - - var parent = event.relatedTarget; - while (parent && parent !== element) { - try { parent = parent.parentNode; } - catch(e) { parent = element; } - } - - if (parent === element) return; - - handler.call(element, event); - }; - } - } else { - responder = function(event) { - Event.extend(event, element); - handler.call(element, event); - }; - } - } - - responder.handler = handler; - respondersForEvent.push(responder); - return responder; - } - - function _destroyCache() { - for (var i = 0, length = CACHE.length; i < length; i++) { - Event.stopObserving(CACHE[i]); - CACHE[i] = null; - } - } - - var CACHE = []; - - if (Prototype.Browser.IE) - window.attachEvent('onunload', _destroyCache); - - if (Prototype.Browser.WebKit) - window.addEventListener('unload', Prototype.emptyFunction, false); - - - var _getDOMEventName = Prototype.K; - - if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED) { - _getDOMEventName = function(eventName) { - var translations = { mouseenter: "mouseover", mouseleave: "mouseout" }; - return eventName in translations ? translations[eventName] : eventName; - }; - } - - function observe(element, eventName, handler) { - element = $(element); - - var responder = _createResponder(element, eventName, handler); - - if (!responder) return element; - - if (eventName.include(':')) { - if (element.addEventListener) - element.addEventListener("dataavailable", responder, false); - else { - element.attachEvent("ondataavailable", responder); - element.attachEvent("onfilterchange", responder); - } - } else { - var actualEventName = _getDOMEventName(eventName); - - if (element.addEventListener) - element.addEventListener(actualEventName, responder, false); - else - element.attachEvent("on" + actualEventName, responder); - } - - return element; - } - - function stopObserving(element, eventName, handler) { - element = $(element); - - var registry = Element.retrieve(element, 'prototype_event_registry'); - - if (Object.isUndefined(registry)) return element; - - if (eventName && !handler) { - var responders = registry.get(eventName); - - if (Object.isUndefined(responders)) return element; - - responders.each( function(r) { - Element.stopObserving(element, eventName, r.handler); - }); - return element; - } else if (!eventName) { - registry.each( function(pair) { - var eventName = pair.key, responders = pair.value; - - responders.each( function(r) { - Element.stopObserving(element, eventName, r.handler); - }); - }); - return element; - } - - var responders = registry.get(eventName); - - if (!responders) return; - - var responder = responders.find( function(r) { return r.handler === handler; }); - if (!responder) return element; - - var actualEventName = _getDOMEventName(eventName); - - if (eventName.include(':')) { - if (element.removeEventListener) - element.removeEventListener("dataavailable", responder, false); - else { - element.detachEvent("ondataavailable", responder); - element.detachEvent("onfilterchange", responder); - } - } else { - if (element.removeEventListener) - element.removeEventListener(actualEventName, responder, false); - else - element.detachEvent('on' + actualEventName, responder); - } - - registry.set(eventName, responders.without(responder)); - - return element; - } - - function fire(element, eventName, memo, bubble) { - element = $(element); - - if (Object.isUndefined(bubble)) - bubble = true; - - if (element == document && document.createEvent && !element.dispatchEvent) - element = document.documentElement; - - var event; - if (document.createEvent) { - event = document.createEvent('HTMLEvents'); - event.initEvent('dataavailable', true, true); - } else { - event = document.createEventObject(); - event.eventType = bubble ? 'ondataavailable' : 'onfilterchange'; - } - - event.eventName = eventName; - event.memo = memo || { }; - - if (document.createEvent) - element.dispatchEvent(event); - else - element.fireEvent(event.eventType, event); - - return Event.extend(event); - } - - - Object.extend(Event, Event.Methods); - - Object.extend(Event, { - fire: fire, - observe: observe, - stopObserving: stopObserving - }); - - Element.addMethods({ - fire: fire, - - observe: observe, - - stopObserving: stopObserving - }); - - Object.extend(document, { - fire: fire.methodize(), - - observe: observe.methodize(), - - stopObserving: stopObserving.methodize(), - - loaded: false - }); - - if (window.Event) Object.extend(window.Event, Event); - else window.Event = Event; -})(); - -(function() { - /* Support for the DOMContentLoaded event is based on work by Dan Webb, - Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */ - - var timer; - - function fireContentLoadedEvent() { - if (document.loaded) return; - if (timer) window.clearTimeout(timer); - document.loaded = true; - document.fire('dom:loaded'); - } - - function checkReadyState() { - if (document.readyState === 'complete') { - document.stopObserving('readystatechange', checkReadyState); - fireContentLoadedEvent(); - } - } - - function pollDoScroll() { - try { document.documentElement.doScroll('left'); } - catch(e) { - timer = pollDoScroll.defer(); - return; - } - fireContentLoadedEvent(); - } - - if (document.addEventListener) { - document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false); - } else { - document.observe('readystatechange', checkReadyState); - if (window == top) - timer = pollDoScroll.defer(); - } - - Event.observe(window, 'load', fireContentLoadedEvent); -})(); - -Element.addMethods(); - -/*------------------------------- DEPRECATED -------------------------------*/ - -Hash.toQueryString = Object.toQueryString; - -var Toggle = { display: Element.toggle }; - -Element.Methods.childOf = Element.Methods.descendantOf; - -var Insertion = { - Before: function(element, content) { - return Element.insert(element, {before:content}); - }, - - Top: function(element, content) { - return Element.insert(element, {top:content}); - }, - - Bottom: function(element, content) { - return Element.insert(element, {bottom:content}); - }, - - After: function(element, content) { - return Element.insert(element, {after:content}); - } -}; - -var $continue = new Error('"throw $continue" is deprecated, use "return" instead'); - -var Position = { - includeScrollOffsets: false, - - prepare: function() { - this.deltaX = window.pageXOffset - || document.documentElement.scrollLeft - || document.body.scrollLeft - || 0; - this.deltaY = window.pageYOffset - || document.documentElement.scrollTop - || document.body.scrollTop - || 0; - }, - - within: function(element, x, y) { - if (this.includeScrollOffsets) - return this.withinIncludingScrolloffsets(element, x, y); - this.xcomp = x; - this.ycomp = y; - this.offset = Element.cumulativeOffset(element); - - return (y >= this.offset[1] && - y < this.offset[1] + element.offsetHeight && - x >= this.offset[0] && - x < this.offset[0] + element.offsetWidth); - }, - - withinIncludingScrolloffsets: function(element, x, y) { - var offsetcache = Element.cumulativeScrollOffset(element); - - this.xcomp = x + offsetcache[0] - this.deltaX; - this.ycomp = y + offsetcache[1] - this.deltaY; - this.offset = Element.cumulativeOffset(element); - - return (this.ycomp >= this.offset[1] && - this.ycomp < this.offset[1] + element.offsetHeight && - this.xcomp >= this.offset[0] && - this.xcomp < this.offset[0] + element.offsetWidth); - }, - - overlap: function(mode, element) { - if (!mode) return 0; - if (mode == 'vertical') - return ((this.offset[1] + element.offsetHeight) - this.ycomp) / - element.offsetHeight; - if (mode == 'horizontal') - return ((this.offset[0] + element.offsetWidth) - this.xcomp) / - element.offsetWidth; - }, - - - cumulativeOffset: Element.Methods.cumulativeOffset, - - positionedOffset: Element.Methods.positionedOffset, - - absolutize: function(element) { - Position.prepare(); - return Element.absolutize(element); - }, - - relativize: function(element) { - Position.prepare(); - return Element.relativize(element); - }, - - realOffset: Element.Methods.cumulativeScrollOffset, - - offsetParent: Element.Methods.getOffsetParent, - - page: Element.Methods.viewportOffset, - - clone: function(source, target, options) { - options = options || { }; - return Element.clonePosition(target, source, options); - } -}; - -/*--------------------------------------------------------------------------*/ - -if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){ - function iter(name) { - return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]"; - } - - instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ? - function(element, className) { - className = className.toString().strip(); - var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className); - return cond ? document._getElementsByXPath('.//*' + cond, element) : []; - } : function(element, className) { - className = className.toString().strip(); - var elements = [], classNames = (/\s/.test(className) ? $w(className) : null); - if (!classNames && !className) return elements; - - var nodes = $(element).getElementsByTagName('*'); - className = ' ' + className + ' '; - - for (var i = 0, child, cn; child = nodes[i]; i++) { - if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) || - (classNames && classNames.all(function(name) { - return !name.toString().blank() && cn.include(' ' + name + ' '); - })))) - elements.push(Element.extend(child)); - } - return elements; - }; - - return function(className, parentElement) { - return $(parentElement || document.body).getElementsByClassName(className); - }; -}(Element.Methods); - -/*--------------------------------------------------------------------------*/ - -Element.ClassNames = Class.create(); -Element.ClassNames.prototype = { - initialize: function(element) { - this.element = $(element); - }, - - _each: function(iterator) { - this.element.className.split(/\s+/).select(function(name) { - return name.length > 0; - })._each(iterator); - }, - - set: function(className) { - this.element.className = className; - }, - - add: function(classNameToAdd) { - if (this.include(classNameToAdd)) return; - this.set($A(this).concat(classNameToAdd).join(' ')); - }, - - remove: function(classNameToRemove) { - if (!this.include(classNameToRemove)) return; - this.set($A(this).without(classNameToRemove).join(' ')); - }, - - toString: function() { - return $A(this).join(' '); - } -}; - -Object.extend(Element.ClassNames.prototype, Enumerable); - -/*--------------------------------------------------------------------------*/ +/* Prototype JavaScript framework, version 1.6.1 + * (c) 2005-2009 Sam Stephenson + * + * Prototype is freely distributable under the terms of an MIT-style license. + * For details, see the Prototype web site: http://www.prototypejs.org/ + * + *--------------------------------------------------------------------------*/ + +var Prototype = { + Version: '1.6.1', + + Browser: (function(){ + var ua = navigator.userAgent; + var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]'; + return { + IE: !!window.attachEvent && !isOpera, + Opera: isOpera, + WebKit: ua.indexOf('AppleWebKit/') > -1, + Gecko: ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1, + MobileSafari: /Apple.*Mobile.*Safari/.test(ua) + } + })(), + + BrowserFeatures: { + XPath: !!document.evaluate, + SelectorsAPI: !!document.querySelector, + ElementExtensions: (function() { + var constructor = window.Element || window.HTMLElement; + return !!(constructor && constructor.prototype); + })(), + SpecificElementExtensions: (function() { + if (typeof window.HTMLDivElement !== 'undefined') + return true; + + var div = document.createElement('div'); + var form = document.createElement('form'); + var isSupported = false; + + if (div['__proto__'] && (div['__proto__'] !== form['__proto__'])) { + isSupported = true; + } + + div = form = null; + + return isSupported; + })() + }, + + ScriptFragment: ']*>([\\S\\s]*?)<\/script>', + JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, + + emptyFunction: function() { }, + K: function(x) { return x } +}; + +if (Prototype.Browser.MobileSafari) + Prototype.BrowserFeatures.SpecificElementExtensions = false; + + +var Abstract = { }; + + +var Try = { + these: function() { + var returnValue; + + for (var i = 0, length = arguments.length; i < length; i++) { + var lambda = arguments[i]; + try { + returnValue = lambda(); + break; + } catch (e) { } + } + + return returnValue; + } +}; + +/* Based on Alex Arnell's inheritance implementation. */ + +var Class = (function() { + function subclass() {}; + function create() { + var parent = null, properties = $A(arguments); + if (Object.isFunction(properties[0])) + parent = properties.shift(); + + function klass() { + this.initialize.apply(this, arguments); + } + + Object.extend(klass, Class.Methods); + klass.superclass = parent; + klass.subclasses = []; + + if (parent) { + subclass.prototype = parent.prototype; + klass.prototype = new subclass; + parent.subclasses.push(klass); + } + + for (var i = 0; i < properties.length; i++) + klass.addMethods(properties[i]); + + if (!klass.prototype.initialize) + klass.prototype.initialize = Prototype.emptyFunction; + + klass.prototype.constructor = klass; + return klass; + } + + function addMethods(source) { + var ancestor = this.superclass && this.superclass.prototype; + var properties = Object.keys(source); + + if (!Object.keys({ toString: true }).length) { + if (source.toString != Object.prototype.toString) + properties.push("toString"); + if (source.valueOf != Object.prototype.valueOf) + properties.push("valueOf"); + } + + for (var i = 0, length = properties.length; i < length; i++) { + var property = properties[i], value = source[property]; + if (ancestor && Object.isFunction(value) && + value.argumentNames().first() == "$super") { + var method = value; + value = (function(m) { + return function() { return ancestor[m].apply(this, arguments); }; + })(property).wrap(method); + + value.valueOf = method.valueOf.bind(method); + value.toString = method.toString.bind(method); + } + this.prototype[property] = value; + } + + return this; + } + + return { + create: create, + Methods: { + addMethods: addMethods + } + }; +})(); +(function() { + + var _toString = Object.prototype.toString; + + function extend(destination, source) { + for (var property in source) + destination[property] = source[property]; + return destination; + } + + function inspect(object) { + try { + if (isUndefined(object)) return 'undefined'; + if (object === null) return 'null'; + return object.inspect ? object.inspect() : String(object); + } catch (e) { + if (e instanceof RangeError) return '...'; + throw e; + } + } + + function toJSON(object) { + var type = typeof object; + switch (type) { + case 'undefined': + case 'function': + case 'unknown': return; + case 'boolean': return object.toString(); + } + + if (object === null) return 'null'; + if (object.toJSON) return object.toJSON(); + if (isElement(object)) return; + + var results = []; + for (var property in object) { + var value = toJSON(object[property]); + if (!isUndefined(value)) + results.push(property.toJSON() + ': ' + value); + } + + return '{' + results.join(', ') + '}'; + } + + function toQueryString(object) { + return $H(object).toQueryString(); + } + + function toHTML(object) { + return object && object.toHTML ? object.toHTML() : String.interpret(object); + } + + function keys(object) { + var results = []; + for (var property in object) + results.push(property); + return results; + } + + function values(object) { + var results = []; + for (var property in object) + results.push(object[property]); + return results; + } + + function clone(object) { + return extend({ }, object); + } + + function isElement(object) { + return !!(object && object.nodeType == 1); + } + + function isArray(object) { + return _toString.call(object) == "[object Array]"; + } + + + function isHash(object) { + return object instanceof Hash; + } + + function isFunction(object) { + return typeof object === "function"; + } + + function isString(object) { + return _toString.call(object) == "[object String]"; + } + + function isNumber(object) { + return _toString.call(object) == "[object Number]"; + } + + function isUndefined(object) { + return typeof object === "undefined"; + } + + extend(Object, { + extend: extend, + inspect: inspect, + toJSON: toJSON, + toQueryString: toQueryString, + toHTML: toHTML, + keys: keys, + values: values, + clone: clone, + isElement: isElement, + isArray: isArray, + isHash: isHash, + isFunction: isFunction, + isString: isString, + isNumber: isNumber, + isUndefined: isUndefined + }); +})(); +Object.extend(Function.prototype, (function() { + var slice = Array.prototype.slice; + + function update(array, args) { + var arrayLength = array.length, length = args.length; + while (length--) array[arrayLength + length] = args[length]; + return array; + } + + function merge(array, args) { + array = slice.call(array, 0); + return update(array, args); + } + + function argumentNames() { + var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1] + .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '') + .replace(/\s+/g, '').split(','); + return names.length == 1 && !names[0] ? [] : names; + } + + function bind(context) { + if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this; + var __method = this, args = slice.call(arguments, 1); + return function() { + var a = merge(args, arguments); + return __method.apply(context, a); + } + } + + function bindAsEventListener(context) { + var __method = this, args = slice.call(arguments, 1); + return function(event) { + var a = update([event || window.event], args); + return __method.apply(context, a); + } + } + + function curry() { + if (!arguments.length) return this; + var __method = this, args = slice.call(arguments, 0); + return function() { + var a = merge(args, arguments); + return __method.apply(this, a); + } + } + + function delay(timeout) { + var __method = this, args = slice.call(arguments, 1); + timeout = timeout * 1000 + return window.setTimeout(function() { + return __method.apply(__method, args); + }, timeout); + } + + function defer() { + var args = update([0.01], arguments); + return this.delay.apply(this, args); + } + + function wrap(wrapper) { + var __method = this; + return function() { + var a = update([__method.bind(this)], arguments); + return wrapper.apply(this, a); + } + } + + function methodize() { + if (this._methodized) return this._methodized; + var __method = this; + return this._methodized = function() { + var a = update([this], arguments); + return __method.apply(null, a); + }; + } + + return { + argumentNames: argumentNames, + bind: bind, + bindAsEventListener: bindAsEventListener, + curry: curry, + delay: delay, + defer: defer, + wrap: wrap, + methodize: methodize + } +})()); + + +Date.prototype.toJSON = function() { + return '"' + this.getUTCFullYear() + '-' + + (this.getUTCMonth() + 1).toPaddedString(2) + '-' + + this.getUTCDate().toPaddedString(2) + 'T' + + this.getUTCHours().toPaddedString(2) + ':' + + this.getUTCMinutes().toPaddedString(2) + ':' + + this.getUTCSeconds().toPaddedString(2) + 'Z"'; +}; + + +RegExp.prototype.match = RegExp.prototype.test; + +RegExp.escape = function(str) { + return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); +}; +var PeriodicalExecuter = Class.create({ + initialize: function(callback, frequency) { + this.callback = callback; + this.frequency = frequency; + this.currentlyExecuting = false; + + this.registerCallback(); + }, + + registerCallback: function() { + this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + execute: function() { + this.callback(this); + }, + + stop: function() { + if (!this.timer) return; + clearInterval(this.timer); + this.timer = null; + }, + + onTimerEvent: function() { + if (!this.currentlyExecuting) { + try { + this.currentlyExecuting = true; + this.execute(); + this.currentlyExecuting = false; + } catch(e) { + this.currentlyExecuting = false; + throw e; + } + } + } +}); +Object.extend(String, { + interpret: function(value) { + return value == null ? '' : String(value); + }, + specialChar: { + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '\\': '\\\\' + } +}); + +Object.extend(String.prototype, (function() { + + function prepareReplacement(replacement) { + if (Object.isFunction(replacement)) return replacement; + var template = new Template(replacement); + return function(match) { return template.evaluate(match) }; + } + + function gsub(pattern, replacement) { + var result = '', source = this, match; + replacement = prepareReplacement(replacement); + + if (Object.isString(pattern)) + pattern = RegExp.escape(pattern); + + if (!(pattern.length || pattern.source)) { + replacement = replacement(''); + return replacement + source.split('').join(replacement) + replacement; + } + + while (source.length > 0) { + if (match = source.match(pattern)) { + result += source.slice(0, match.index); + result += String.interpret(replacement(match)); + source = source.slice(match.index + match[0].length); + } else { + result += source, source = ''; + } + } + return result; + } + + function sub(pattern, replacement, count) { + replacement = prepareReplacement(replacement); + count = Object.isUndefined(count) ? 1 : count; + + return this.gsub(pattern, function(match) { + if (--count < 0) return match[0]; + return replacement(match); + }); + } + + function scan(pattern, iterator) { + this.gsub(pattern, iterator); + return String(this); + } + + function truncate(length, truncation) { + length = length || 30; + truncation = Object.isUndefined(truncation) ? '...' : truncation; + return this.length > length ? + this.slice(0, length - truncation.length) + truncation : String(this); + } + + function strip() { + return this.replace(/^\s+/, '').replace(/\s+$/, ''); + } + + function stripTags() { + return this.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?>|<\/\w+>/gi, ''); + } + + function stripScripts() { + return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); + } + + function extractScripts() { + var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); + var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); + return (this.match(matchAll) || []).map(function(scriptTag) { + return (scriptTag.match(matchOne) || ['', ''])[1]; + }); + } + + function evalScripts() { + return this.extractScripts().map(function(script) { return eval(script) }); + } + + function escapeHTML() { + return this.replace(/&/g,'&').replace(//g,'>'); + } + + function unescapeHTML() { + return this.stripTags().replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&'); + } + + + function toQueryParams(separator) { + var match = this.strip().match(/([^?#]*)(#.*)?$/); + if (!match) return { }; + + return match[1].split(separator || '&').inject({ }, function(hash, pair) { + if ((pair = pair.split('='))[0]) { + var key = decodeURIComponent(pair.shift()); + var value = pair.length > 1 ? pair.join('=') : pair[0]; + if (value != undefined) value = decodeURIComponent(value); + + if (key in hash) { + if (!Object.isArray(hash[key])) hash[key] = [hash[key]]; + hash[key].push(value); + } + else hash[key] = value; + } + return hash; + }); + } + + function toArray() { + return this.split(''); + } + + function succ() { + return this.slice(0, this.length - 1) + + String.fromCharCode(this.charCodeAt(this.length - 1) + 1); + } + + function times(count) { + return count < 1 ? '' : new Array(count + 1).join(this); + } + + function camelize() { + var parts = this.split('-'), len = parts.length; + if (len == 1) return parts[0]; + + var camelized = this.charAt(0) == '-' + ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) + : parts[0]; + + for (var i = 1; i < len; i++) + camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); + + return camelized; + } + + function capitalize() { + return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); + } + + function underscore() { + return this.replace(/::/g, '/') + .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2') + .replace(/([a-z\d])([A-Z])/g, '$1_$2') + .replace(/-/g, '_') + .toLowerCase(); + } + + function dasherize() { + return this.replace(/_/g, '-'); + } + + function inspect(useDoubleQuotes) { + var escapedString = this.replace(/[\x00-\x1f\\]/g, function(character) { + if (character in String.specialChar) { + return String.specialChar[character]; + } + return '\\u00' + character.charCodeAt().toPaddedString(2, 16); + }); + if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; + return "'" + escapedString.replace(/'/g, '\\\'') + "'"; + } + + function toJSON() { + return this.inspect(true); + } + + function unfilterJSON(filter) { + return this.replace(filter || Prototype.JSONFilter, '$1'); + } + + function isJSON() { + var str = this; + if (str.blank()) return false; + str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''); + return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str); + } + + function evalJSON(sanitize) { + var json = this.unfilterJSON(); + try { + if (!sanitize || json.isJSON()) return eval('(' + json + ')'); + } catch (e) { } + throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); + } + + function include(pattern) { + return this.indexOf(pattern) > -1; + } + + function startsWith(pattern) { + return this.indexOf(pattern) === 0; + } + + function endsWith(pattern) { + var d = this.length - pattern.length; + return d >= 0 && this.lastIndexOf(pattern) === d; + } + + function empty() { + return this == ''; + } + + function blank() { + return /^\s*$/.test(this); + } + + function interpolate(object, pattern) { + return new Template(this, pattern).evaluate(object); + } + + return { + gsub: gsub, + sub: sub, + scan: scan, + truncate: truncate, + strip: String.prototype.trim ? String.prototype.trim : strip, + stripTags: stripTags, + stripScripts: stripScripts, + extractScripts: extractScripts, + evalScripts: evalScripts, + escapeHTML: escapeHTML, + unescapeHTML: unescapeHTML, + toQueryParams: toQueryParams, + parseQuery: toQueryParams, + toArray: toArray, + succ: succ, + times: times, + camelize: camelize, + capitalize: capitalize, + underscore: underscore, + dasherize: dasherize, + inspect: inspect, + toJSON: toJSON, + unfilterJSON: unfilterJSON, + isJSON: isJSON, + evalJSON: evalJSON, + include: include, + startsWith: startsWith, + endsWith: endsWith, + empty: empty, + blank: blank, + interpolate: interpolate + }; +})()); + +var Template = Class.create({ + initialize: function(template, pattern) { + this.template = template.toString(); + this.pattern = pattern || Template.Pattern; + }, + + evaluate: function(object) { + if (object && Object.isFunction(object.toTemplateReplacements)) + object = object.toTemplateReplacements(); + + return this.template.gsub(this.pattern, function(match) { + if (object == null) return (match[1] + ''); + + var before = match[1] || ''; + if (before == '\\') return match[2]; + + var ctx = object, expr = match[3]; + var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/; + match = pattern.exec(expr); + if (match == null) return before; + + while (match != null) { + var comp = match[1].startsWith('[') ? match[2].replace(/\\\\]/g, ']') : match[1]; + ctx = ctx[comp]; + if (null == ctx || '' == match[3]) break; + expr = expr.substring('[' == match[3] ? match[1].length : match[0].length); + match = pattern.exec(expr); + } + + return before + String.interpret(ctx); + }); + } +}); +Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; + +var $break = { }; + +var Enumerable = (function() { + function each(iterator, context) { + var index = 0; + try { + this._each(function(value) { + iterator.call(context, value, index++); + }); + } catch (e) { + if (e != $break) throw e; + } + return this; + } + + function eachSlice(number, iterator, context) { + var index = -number, slices = [], array = this.toArray(); + if (number < 1) return array; + while ((index += number) < array.length) + slices.push(array.slice(index, index+number)); + return slices.collect(iterator, context); + } + + function all(iterator, context) { + iterator = iterator || Prototype.K; + var result = true; + this.each(function(value, index) { + result = result && !!iterator.call(context, value, index); + if (!result) throw $break; + }); + return result; + } + + function any(iterator, context) { + iterator = iterator || Prototype.K; + var result = false; + this.each(function(value, index) { + if (result = !!iterator.call(context, value, index)) + throw $break; + }); + return result; + } + + function collect(iterator, context) { + iterator = iterator || Prototype.K; + var results = []; + this.each(function(value, index) { + results.push(iterator.call(context, value, index)); + }); + return results; + } + + function detect(iterator, context) { + var result; + this.each(function(value, index) { + if (iterator.call(context, value, index)) { + result = value; + throw $break; + } + }); + return result; + } + + function findAll(iterator, context) { + var results = []; + this.each(function(value, index) { + if (iterator.call(context, value, index)) + results.push(value); + }); + return results; + } + + function grep(filter, iterator, context) { + iterator = iterator || Prototype.K; + var results = []; + + if (Object.isString(filter)) + filter = new RegExp(RegExp.escape(filter)); + + this.each(function(value, index) { + if (filter.match(value)) + results.push(iterator.call(context, value, index)); + }); + return results; + } + + function include(object) { + if (Object.isFunction(this.indexOf)) + if (this.indexOf(object) != -1) return true; + + var found = false; + this.each(function(value) { + if (value == object) { + found = true; + throw $break; + } + }); + return found; + } + + function inGroupsOf(number, fillWith) { + fillWith = Object.isUndefined(fillWith) ? null : fillWith; + return this.eachSlice(number, function(slice) { + while(slice.length < number) slice.push(fillWith); + return slice; + }); + } + + function inject(memo, iterator, context) { + this.each(function(value, index) { + memo = iterator.call(context, memo, value, index); + }); + return memo; + } + + function invoke(method) { + var args = $A(arguments).slice(1); + return this.map(function(value) { + return value[method].apply(value, args); + }); + } + + function max(iterator, context) { + iterator = iterator || Prototype.K; + var result; + this.each(function(value, index) { + value = iterator.call(context, value, index); + if (result == null || value >= result) + result = value; + }); + return result; + } + + function min(iterator, context) { + iterator = iterator || Prototype.K; + var result; + this.each(function(value, index) { + value = iterator.call(context, value, index); + if (result == null || value < result) + result = value; + }); + return result; + } + + function partition(iterator, context) { + iterator = iterator || Prototype.K; + var trues = [], falses = []; + this.each(function(value, index) { + (iterator.call(context, value, index) ? + trues : falses).push(value); + }); + return [trues, falses]; + } + + function pluck(property) { + var results = []; + this.each(function(value) { + results.push(value[property]); + }); + return results; + } + + function reject(iterator, context) { + var results = []; + this.each(function(value, index) { + if (!iterator.call(context, value, index)) + results.push(value); + }); + return results; + } + + function sortBy(iterator, context) { + return this.map(function(value, index) { + return { + value: value, + criteria: iterator.call(context, value, index) + }; + }).sort(function(left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }).pluck('value'); + } + + function toArray() { + return this.map(); + } + + function zip() { + var iterator = Prototype.K, args = $A(arguments); + if (Object.isFunction(args.last())) + iterator = args.pop(); + + var collections = [this].concat(args).map($A); + return this.map(function(value, index) { + return iterator(collections.pluck(index)); + }); + } + + function size() { + return this.toArray().length; + } + + function inspect() { + return '#'; + } + + + + + + + + + + return { + each: each, + eachSlice: eachSlice, + all: all, + every: all, + any: any, + some: any, + collect: collect, + map: collect, + detect: detect, + findAll: findAll, + select: findAll, + filter: findAll, + grep: grep, + include: include, + member: include, + inGroupsOf: inGroupsOf, + inject: inject, + invoke: invoke, + max: max, + min: min, + partition: partition, + pluck: pluck, + reject: reject, + sortBy: sortBy, + toArray: toArray, + entries: toArray, + zip: zip, + size: size, + inspect: inspect, + find: detect + }; +})(); +function $A(iterable) { + if (!iterable) return []; + if ('toArray' in Object(iterable)) return iterable.toArray(); + var length = iterable.length || 0, results = new Array(length); + while (length--) results[length] = iterable[length]; + return results; +} + +function $w(string) { + if (!Object.isString(string)) return []; + string = string.strip(); + return string ? string.split(/\s+/) : []; +} + +Array.from = $A; + + +(function() { + var arrayProto = Array.prototype, + slice = arrayProto.slice, + _each = arrayProto.forEach; // use native browser JS 1.6 implementation if available + + function each(iterator) { + for (var i = 0, length = this.length; i < length; i++) + iterator(this[i]); + } + if (!_each) _each = each; + + function clear() { + this.length = 0; + return this; + } + + function first() { + return this[0]; + } + + function last() { + return this[this.length - 1]; + } + + function compact() { + return this.select(function(value) { + return value != null; + }); + } + + function flatten() { + return this.inject([], function(array, value) { + if (Object.isArray(value)) + return array.concat(value.flatten()); + array.push(value); + return array; + }); + } + + function without() { + var values = slice.call(arguments, 0); + return this.select(function(value) { + return !values.include(value); + }); + } + + function reverse(inline) { + return (inline !== false ? this : this.toArray())._reverse(); + } + + function uniq(sorted) { + return this.inject([], function(array, value, index) { + if (0 == index || (sorted ? array.last() != value : !array.include(value))) + array.push(value); + return array; + }); + } + + function intersect(array) { + return this.uniq().findAll(function(item) { + return array.detect(function(value) { return item === value }); + }); + } + + + function clone() { + return slice.call(this, 0); + } + + function size() { + return this.length; + } + + function inspect() { + return '[' + this.map(Object.inspect).join(', ') + ']'; + } + + function toJSON() { + var results = []; + this.each(function(object) { + var value = Object.toJSON(object); + if (!Object.isUndefined(value)) results.push(value); + }); + return '[' + results.join(', ') + ']'; + } + + function indexOf(item, i) { + i || (i = 0); + var length = this.length; + if (i < 0) i = length + i; + for (; i < length; i++) + if (this[i] === item) return i; + return -1; + } + + function lastIndexOf(item, i) { + i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1; + var n = this.slice(0, i).reverse().indexOf(item); + return (n < 0) ? n : i - n - 1; + } + + function concat() { + var array = slice.call(this, 0), item; + for (var i = 0, length = arguments.length; i < length; i++) { + item = arguments[i]; + if (Object.isArray(item) && !('callee' in item)) { + for (var j = 0, arrayLength = item.length; j < arrayLength; j++) + array.push(item[j]); + } else { + array.push(item); + } + } + return array; + } + + Object.extend(arrayProto, Enumerable); + + if (!arrayProto._reverse) + arrayProto._reverse = arrayProto.reverse; + + Object.extend(arrayProto, { + _each: _each, + clear: clear, + first: first, + last: last, + compact: compact, + flatten: flatten, + without: without, + reverse: reverse, + uniq: uniq, + intersect: intersect, + clone: clone, + toArray: clone, + size: size, + inspect: inspect, + toJSON: toJSON + }); + + var CONCAT_ARGUMENTS_BUGGY = (function() { + return [].concat(arguments)[0][0] !== 1; + })(1,2) + + if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat; + + if (!arrayProto.indexOf) arrayProto.indexOf = indexOf; + if (!arrayProto.lastIndexOf) arrayProto.lastIndexOf = lastIndexOf; +})(); +function $H(object) { + return new Hash(object); +}; + +var Hash = Class.create(Enumerable, (function() { + function initialize(object) { + this._object = Object.isHash(object) ? object.toObject() : Object.clone(object); + } + + function _each(iterator) { + for (var key in this._object) { + var value = this._object[key], pair = [key, value]; + pair.key = key; + pair.value = value; + iterator(pair); + } + } + + function set(key, value) { + return this._object[key] = value; + } + + function get(key) { + if (this._object[key] !== Object.prototype[key]) + return this._object[key]; + } + + function unset(key) { + var value = this._object[key]; + delete this._object[key]; + return value; + } + + function toObject() { + return Object.clone(this._object); + } + + function keys() { + return this.pluck('key'); + } + + function values() { + return this.pluck('value'); + } + + function index(value) { + var match = this.detect(function(pair) { + return pair.value === value; + }); + return match && match.key; + } + + function merge(object) { + return this.clone().update(object); + } + + function update(object) { + return new Hash(object).inject(this, function(result, pair) { + result.set(pair.key, pair.value); + return result; + }); + } + + function toQueryPair(key, value) { + if (Object.isUndefined(value)) return key; + return key + '=' + encodeURIComponent(String.interpret(value)); + } + + function toQueryString() { + return this.inject([], function(results, pair) { + var key = encodeURIComponent(pair.key), values = pair.value; + + if (values && typeof values == 'object') { + if (Object.isArray(values)) + return results.concat(values.map(toQueryPair.curry(key))); + } else results.push(toQueryPair(key, values)); + return results; + }).join('&'); + } + + function inspect() { + return '#'; + } + + function toJSON() { + return Object.toJSON(this.toObject()); + } + + function clone() { + return new Hash(this); + } + + return { + initialize: initialize, + _each: _each, + set: set, + get: get, + unset: unset, + toObject: toObject, + toTemplateReplacements: toObject, + keys: keys, + values: values, + index: index, + merge: merge, + update: update, + toQueryString: toQueryString, + inspect: inspect, + toJSON: toJSON, + clone: clone + }; +})()); + +Hash.from = $H; +Object.extend(Number.prototype, (function() { + function toColorPart() { + return this.toPaddedString(2, 16); + } + + function succ() { + return this + 1; + } + + function times(iterator, context) { + $R(0, this, true).each(iterator, context); + return this; + } + + function toPaddedString(length, radix) { + var string = this.toString(radix || 10); + return '0'.times(length - string.length) + string; + } + + function toJSON() { + return isFinite(this) ? this.toString() : 'null'; + } + + function abs() { + return Math.abs(this); + } + + function round() { + return Math.round(this); + } + + function ceil() { + return Math.ceil(this); + } + + function floor() { + return Math.floor(this); + } + + return { + toColorPart: toColorPart, + succ: succ, + times: times, + toPaddedString: toPaddedString, + toJSON: toJSON, + abs: abs, + round: round, + ceil: ceil, + floor: floor + }; +})()); + +function $R(start, end, exclusive) { + return new ObjectRange(start, end, exclusive); +} + +var ObjectRange = Class.create(Enumerable, (function() { + function initialize(start, end, exclusive) { + this.start = start; + this.end = end; + this.exclusive = exclusive; + } + + function _each(iterator) { + var value = this.start; + while (this.include(value)) { + iterator(value); + value = value.succ(); + } + } + + function include(value) { + if (value < this.start) + return false; + if (this.exclusive) + return value < this.end; + return value <= this.end; + } + + return { + initialize: initialize, + _each: _each, + include: include + }; +})()); + + + +var Ajax = { + getTransport: function() { + return Try.these( + function() {return new XMLHttpRequest()}, + function() {return new ActiveXObject('Msxml2.XMLHTTP')}, + function() {return new ActiveXObject('Microsoft.XMLHTTP')} + ) || false; + }, + + activeRequestCount: 0 +}; + +Ajax.Responders = { + responders: [], + + _each: function(iterator) { + this.responders._each(iterator); + }, + + register: function(responder) { + if (!this.include(responder)) + this.responders.push(responder); + }, + + unregister: function(responder) { + this.responders = this.responders.without(responder); + }, + + dispatch: function(callback, request, transport, json) { + this.each(function(responder) { + if (Object.isFunction(responder[callback])) { + try { + responder[callback].apply(responder, [request, transport, json]); + } catch (e) { } + } + }); + } +}; + +Object.extend(Ajax.Responders, Enumerable); + +Ajax.Responders.register({ + onCreate: function() { Ajax.activeRequestCount++ }, + onComplete: function() { Ajax.activeRequestCount-- } +}); +Ajax.Base = Class.create({ + initialize: function(options) { + this.options = { + method: 'post', + asynchronous: true, + contentType: 'application/x-www-form-urlencoded', + encoding: 'UTF-8', + parameters: '', + evalJSON: true, + evalJS: true + }; + Object.extend(this.options, options || { }); + + this.options.method = this.options.method.toLowerCase(); + + if (Object.isString(this.options.parameters)) + this.options.parameters = this.options.parameters.toQueryParams(); + else if (Object.isHash(this.options.parameters)) + this.options.parameters = this.options.parameters.toObject(); + } +}); +Ajax.Request = Class.create(Ajax.Base, { + _complete: false, + + initialize: function($super, url, options) { + $super(options); + this.transport = Ajax.getTransport(); + this.request(url); + }, + + request: function(url) { + this.url = url; + this.method = this.options.method; + var params = Object.clone(this.options.parameters); + + if (!['get', 'post'].include(this.method)) { + params['_method'] = this.method; + this.method = 'post'; + } + + this.parameters = params; + + if (params = Object.toQueryString(params)) { + if (this.method == 'get') + this.url += (this.url.include('?') ? '&' : '?') + params; + else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) + params += '&_='; + } + + try { + var response = new Ajax.Response(this); + if (this.options.onCreate) this.options.onCreate(response); + Ajax.Responders.dispatch('onCreate', this, response); + + this.transport.open(this.method.toUpperCase(), this.url, + this.options.asynchronous); + + if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1); + + this.transport.onreadystatechange = this.onStateChange.bind(this); + this.setRequestHeaders(); + + this.body = this.method == 'post' ? (this.options.postBody || params) : null; + this.transport.send(this.body); + + /* Force Firefox to handle ready state 4 for synchronous requests */ + if (!this.options.asynchronous && this.transport.overrideMimeType) + this.onStateChange(); + + } + catch (e) { + this.dispatchException(e); + } + }, + + onStateChange: function() { + var readyState = this.transport.readyState; + if (readyState > 1 && !((readyState == 4) && this._complete)) + this.respondToReadyState(this.transport.readyState); + }, + + setRequestHeaders: function() { + var headers = { + 'X-Requested-With': 'XMLHttpRequest', + 'X-Prototype-Version': Prototype.Version, + 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' + }; + + if (this.method == 'post') { + headers['Content-type'] = this.options.contentType + + (this.options.encoding ? '; charset=' + this.options.encoding : ''); + + /* Force "Connection: close" for older Mozilla browsers to work + * around a bug where XMLHttpRequest sends an incorrect + * Content-length header. See Mozilla Bugzilla #246651. + */ + if (this.transport.overrideMimeType && + (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) + headers['Connection'] = 'close'; + } + + if (typeof this.options.requestHeaders == 'object') { + var extras = this.options.requestHeaders; + + if (Object.isFunction(extras.push)) + for (var i = 0, length = extras.length; i < length; i += 2) + headers[extras[i]] = extras[i+1]; + else + $H(extras).each(function(pair) { headers[pair.key] = pair.value }); + } + + for (var name in headers) + this.transport.setRequestHeader(name, headers[name]); + }, + + success: function() { + var status = this.getStatus(); + return !status || (status >= 200 && status < 300); + }, + + getStatus: function() { + try { + return this.transport.status || 0; + } catch (e) { return 0 } + }, + + respondToReadyState: function(readyState) { + var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this); + + if (state == 'Complete') { + try { + this._complete = true; + (this.options['on' + response.status] + || this.options['on' + (this.success() ? 'Success' : 'Failure')] + || Prototype.emptyFunction)(response, response.headerJSON); + } catch (e) { + this.dispatchException(e); + } + + var contentType = response.getHeader('Content-type'); + if (this.options.evalJS == 'force' + || (this.options.evalJS && this.isSameOrigin() && contentType + && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i))) + this.evalResponse(); + } + + try { + (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON); + Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON); + } catch (e) { + this.dispatchException(e); + } + + if (state == 'Complete') { + this.transport.onreadystatechange = Prototype.emptyFunction; + } + }, + + isSameOrigin: function() { + var m = this.url.match(/^\s*https?:\/\/[^\/]*/); + return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({ + protocol: location.protocol, + domain: document.domain, + port: location.port ? ':' + location.port : '' + })); + }, + + getHeader: function(name) { + try { + return this.transport.getResponseHeader(name) || null; + } catch (e) { return null; } + }, + + evalResponse: function() { + try { + return eval((this.transport.responseText || '').unfilterJSON()); + } catch (e) { + this.dispatchException(e); + } + }, + + dispatchException: function(exception) { + (this.options.onException || Prototype.emptyFunction)(this, exception); + Ajax.Responders.dispatch('onException', this, exception); + } +}); + +Ajax.Request.Events = + ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; + + + + + + + + +Ajax.Response = Class.create({ + initialize: function(request){ + this.request = request; + var transport = this.transport = request.transport, + readyState = this.readyState = transport.readyState; + + if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) { + this.status = this.getStatus(); + this.statusText = this.getStatusText(); + this.responseText = String.interpret(transport.responseText); + this.headerJSON = this._getHeaderJSON(); + } + + if(readyState == 4) { + var xml = transport.responseXML; + this.responseXML = Object.isUndefined(xml) ? null : xml; + this.responseJSON = this._getResponseJSON(); + } + }, + + status: 0, + + statusText: '', + + getStatus: Ajax.Request.prototype.getStatus, + + getStatusText: function() { + try { + return this.transport.statusText || ''; + } catch (e) { return '' } + }, + + getHeader: Ajax.Request.prototype.getHeader, + + getAllHeaders: function() { + try { + return this.getAllResponseHeaders(); + } catch (e) { return null } + }, + + getResponseHeader: function(name) { + return this.transport.getResponseHeader(name); + }, + + getAllResponseHeaders: function() { + return this.transport.getAllResponseHeaders(); + }, + + _getHeaderJSON: function() { + var json = this.getHeader('X-JSON'); + if (!json) return null; + json = decodeURIComponent(escape(json)); + try { + return json.evalJSON(this.request.options.sanitizeJSON || + !this.request.isSameOrigin()); + } catch (e) { + this.request.dispatchException(e); + } + }, + + _getResponseJSON: function() { + var options = this.request.options; + if (!options.evalJSON || (options.evalJSON != 'force' && + !(this.getHeader('Content-type') || '').include('application/json')) || + this.responseText.blank()) + return null; + try { + return this.responseText.evalJSON(options.sanitizeJSON || + !this.request.isSameOrigin()); + } catch (e) { + this.request.dispatchException(e); + } + } +}); + +Ajax.Updater = Class.create(Ajax.Request, { + initialize: function($super, container, url, options) { + this.container = { + success: (container.success || container), + failure: (container.failure || (container.success ? null : container)) + }; + + options = Object.clone(options); + var onComplete = options.onComplete; + options.onComplete = (function(response, json) { + this.updateContent(response.responseText); + if (Object.isFunction(onComplete)) onComplete(response, json); + }).bind(this); + + $super(url, options); + }, + + updateContent: function(responseText) { + var receiver = this.container[this.success() ? 'success' : 'failure'], + options = this.options; + + if (!options.evalScripts) responseText = responseText.stripScripts(); + + if (receiver = $(receiver)) { + if (options.insertion) { + if (Object.isString(options.insertion)) { + var insertion = { }; insertion[options.insertion] = responseText; + receiver.insert(insertion); + } + else options.insertion(receiver, responseText); + } + else receiver.update(responseText); + } + } +}); + +Ajax.PeriodicalUpdater = Class.create(Ajax.Base, { + initialize: function($super, container, url, options) { + $super(options); + this.onComplete = this.options.onComplete; + + this.frequency = (this.options.frequency || 2); + this.decay = (this.options.decay || 1); + + this.updater = { }; + this.container = container; + this.url = url; + + this.start(); + }, + + start: function() { + this.options.onComplete = this.updateComplete.bind(this); + this.onTimerEvent(); + }, + + stop: function() { + this.updater.options.onComplete = undefined; + clearTimeout(this.timer); + (this.onComplete || Prototype.emptyFunction).apply(this, arguments); + }, + + updateComplete: function(response) { + if (this.options.decay) { + this.decay = (response.responseText == this.lastText ? + this.decay * this.options.decay : 1); + + this.lastText = response.responseText; + } + this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency); + }, + + onTimerEvent: function() { + this.updater = new Ajax.Updater(this.container, this.url, this.options); + } +}); + + + +function $(element) { + if (arguments.length > 1) { + for (var i = 0, elements = [], length = arguments.length; i < length; i++) + elements.push($(arguments[i])); + return elements; + } + if (Object.isString(element)) + element = document.getElementById(element); + return Element.extend(element); +} + +if (Prototype.BrowserFeatures.XPath) { + document._getElementsByXPath = function(expression, parentElement) { + var results = []; + var query = document.evaluate(expression, $(parentElement) || document, + null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); + for (var i = 0, length = query.snapshotLength; i < length; i++) + results.push(Element.extend(query.snapshotItem(i))); + return results; + }; +} + +/*--------------------------------------------------------------------------*/ + +if (!window.Node) var Node = { }; + +if (!Node.ELEMENT_NODE) { + Object.extend(Node, { + ELEMENT_NODE: 1, + ATTRIBUTE_NODE: 2, + TEXT_NODE: 3, + CDATA_SECTION_NODE: 4, + ENTITY_REFERENCE_NODE: 5, + ENTITY_NODE: 6, + PROCESSING_INSTRUCTION_NODE: 7, + COMMENT_NODE: 8, + DOCUMENT_NODE: 9, + DOCUMENT_TYPE_NODE: 10, + DOCUMENT_FRAGMENT_NODE: 11, + NOTATION_NODE: 12 + }); +} + + +(function(global) { + + var SETATTRIBUTE_IGNORES_NAME = (function(){ + var elForm = document.createElement("form"); + var elInput = document.createElement("input"); + var root = document.documentElement; + elInput.setAttribute("name", "test"); + elForm.appendChild(elInput); + root.appendChild(elForm); + var isBuggy = elForm.elements + ? (typeof elForm.elements.test == "undefined") + : null; + root.removeChild(elForm); + elForm = elInput = null; + return isBuggy; + })(); + + var element = global.Element; + global.Element = function(tagName, attributes) { + attributes = attributes || { }; + tagName = tagName.toLowerCase(); + var cache = Element.cache; + if (SETATTRIBUTE_IGNORES_NAME && attributes.name) { + tagName = '<' + tagName + ' name="' + attributes.name + '">'; + delete attributes.name; + return Element.writeAttribute(document.createElement(tagName), attributes); + } + if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName)); + return Element.writeAttribute(cache[tagName].cloneNode(false), attributes); + }; + Object.extend(global.Element, element || { }); + if (element) global.Element.prototype = element.prototype; +})(this); + +Element.cache = { }; +Element.idCounter = 1; + +Element.Methods = { + visible: function(element) { + return $(element).style.display != 'none'; + }, + + toggle: function(element) { + element = $(element); + Element[Element.visible(element) ? 'hide' : 'show'](element); + return element; + }, + + + hide: function(element) { + element = $(element); + element.style.display = 'none'; + return element; + }, + + show: function(element) { + element = $(element); + element.style.display = ''; + return element; + }, + + remove: function(element) { + element = $(element); + element.parentNode.removeChild(element); + return element; + }, + + update: (function(){ + + var SELECT_ELEMENT_INNERHTML_BUGGY = (function(){ + var el = document.createElement("select"), + isBuggy = true; + el.innerHTML = ""; + if (el.options && el.options[0]) { + isBuggy = el.options[0].nodeName.toUpperCase() !== "OPTION"; + } + el = null; + return isBuggy; + })(); + + var TABLE_ELEMENT_INNERHTML_BUGGY = (function(){ + try { + var el = document.createElement("table"); + if (el && el.tBodies) { + el.innerHTML = "test"; + var isBuggy = typeof el.tBodies[0] == "undefined"; + el = null; + return isBuggy; + } + } catch (e) { + return true; + } + })(); + + var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () { + var s = document.createElement("script"), + isBuggy = false; + try { + s.appendChild(document.createTextNode("")); + isBuggy = !s.firstChild || + s.firstChild && s.firstChild.nodeType !== 3; + } catch (e) { + isBuggy = true; + } + s = null; + return isBuggy; + })(); + + function update(element, content) { + element = $(element); + + if (content && content.toElement) + content = content.toElement(); + + if (Object.isElement(content)) + return element.update().insert(content); + + content = Object.toHTML(content); + + var tagName = element.tagName.toUpperCase(); + + if (tagName === 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING) { + element.text = content; + return element; + } + + if (SELECT_ELEMENT_INNERHTML_BUGGY || TABLE_ELEMENT_INNERHTML_BUGGY) { + if (tagName in Element._insertionTranslations.tags) { + while (element.firstChild) { + element.removeChild(element.firstChild); + } + Element._getContentFromAnonymousElement(tagName, content.stripScripts()) + .each(function(node) { + element.appendChild(node) + }); + } + else { + element.innerHTML = content.stripScripts(); + } + } + else { + element.innerHTML = content.stripScripts(); + } + + content.evalScripts.bind(content).defer(); + return element; + } + + return update; + })(), + + replace: function(element, content) { + element = $(element); + if (content && content.toElement) content = content.toElement(); + else if (!Object.isElement(content)) { + content = Object.toHTML(content); + var range = element.ownerDocument.createRange(); + range.selectNode(element); + content.evalScripts.bind(content).defer(); + content = range.createContextualFragment(content.stripScripts()); + } + element.parentNode.replaceChild(content, element); + return element; + }, + + insert: function(element, insertions) { + element = $(element); + + if (Object.isString(insertions) || Object.isNumber(insertions) || + Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML))) + insertions = {bottom:insertions}; + + var content, insert, tagName, childNodes; + + for (var position in insertions) { + content = insertions[position]; + position = position.toLowerCase(); + insert = Element._insertionTranslations[position]; + + if (content && content.toElement) content = content.toElement(); + if (Object.isElement(content)) { + insert(element, content); + continue; + } + + content = Object.toHTML(content); + + tagName = ((position == 'before' || position == 'after') + ? element.parentNode : element).tagName.toUpperCase(); + + childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); + + if (position == 'top' || position == 'after') childNodes.reverse(); + childNodes.each(insert.curry(element)); + + content.evalScripts.bind(content).defer(); + } + + return element; + }, + + wrap: function(element, wrapper, attributes) { + element = $(element); + if (Object.isElement(wrapper)) + $(wrapper).writeAttribute(attributes || { }); + else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes); + else wrapper = new Element('div', wrapper); + if (element.parentNode) + element.parentNode.replaceChild(wrapper, element); + wrapper.appendChild(element); + return wrapper; + }, + + inspect: function(element) { + element = $(element); + var result = '<' + element.tagName.toLowerCase(); + $H({'id': 'id', 'className': 'class'}).each(function(pair) { + var property = pair.first(), attribute = pair.last(); + var value = (element[property] || '').toString(); + if (value) result += ' ' + attribute + '=' + value.inspect(true); + }); + return result + '>'; + }, + + recursivelyCollect: function(element, property) { + element = $(element); + var elements = []; + while (element = element[property]) + if (element.nodeType == 1) + elements.push(Element.extend(element)); + return elements; + }, + + ancestors: function(element) { + return Element.recursivelyCollect(element, 'parentNode'); + }, + + descendants: function(element) { + return Element.select(element, "*"); + }, + + firstDescendant: function(element) { + element = $(element).firstChild; + while (element && element.nodeType != 1) element = element.nextSibling; + return $(element); + }, + + immediateDescendants: function(element) { + if (!(element = $(element).firstChild)) return []; + while (element && element.nodeType != 1) element = element.nextSibling; + if (element) return [element].concat($(element).nextSiblings()); + return []; + }, + + previousSiblings: function(element) { + return Element.recursivelyCollect(element, 'previousSibling'); + }, + + nextSiblings: function(element) { + return Element.recursivelyCollect(element, 'nextSibling'); + }, + + siblings: function(element) { + element = $(element); + return Element.previousSiblings(element).reverse() + .concat(Element.nextSiblings(element)); + }, + + match: function(element, selector) { + if (Object.isString(selector)) + selector = new Selector(selector); + return selector.match($(element)); + }, + + up: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return $(element.parentNode); + var ancestors = Element.ancestors(element); + return Object.isNumber(expression) ? ancestors[expression] : + Selector.findElement(ancestors, expression, index); + }, + + down: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return Element.firstDescendant(element); + return Object.isNumber(expression) ? Element.descendants(element)[expression] : + Element.select(element, expression)[index || 0]; + }, + + previous: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element)); + var previousSiblings = Element.previousSiblings(element); + return Object.isNumber(expression) ? previousSiblings[expression] : + Selector.findElement(previousSiblings, expression, index); + }, + + next: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element)); + var nextSiblings = Element.nextSiblings(element); + return Object.isNumber(expression) ? nextSiblings[expression] : + Selector.findElement(nextSiblings, expression, index); + }, + + + select: function(element) { + var args = Array.prototype.slice.call(arguments, 1); + return Selector.findChildElements(element, args); + }, + + adjacent: function(element) { + var args = Array.prototype.slice.call(arguments, 1); + return Selector.findChildElements(element.parentNode, args).without(element); + }, + + identify: function(element) { + element = $(element); + var id = Element.readAttribute(element, 'id'); + if (id) return id; + do { id = 'anonymous_element_' + Element.idCounter++ } while ($(id)); + Element.writeAttribute(element, 'id', id); + return id; + }, + + readAttribute: function(element, name) { + element = $(element); + if (Prototype.Browser.IE) { + var t = Element._attributeTranslations.read; + if (t.values[name]) return t.values[name](element, name); + if (t.names[name]) name = t.names[name]; + if (name.include(':')) { + return (!element.attributes || !element.attributes[name]) ? null : + element.attributes[name].value; + } + } + return element.getAttribute(name); + }, + + writeAttribute: function(element, name, value) { + element = $(element); + var attributes = { }, t = Element._attributeTranslations.write; + + if (typeof name == 'object') attributes = name; + else attributes[name] = Object.isUndefined(value) ? true : value; + + for (var attr in attributes) { + name = t.names[attr] || attr; + value = attributes[attr]; + if (t.values[attr]) name = t.values[attr](element, value); + if (value === false || value === null) + element.removeAttribute(name); + else if (value === true) + element.setAttribute(name, name); + else element.setAttribute(name, value); + } + return element; + }, + + getHeight: function(element) { + return Element.getDimensions(element).height; + }, + + getWidth: function(element) { + return Element.getDimensions(element).width; + }, + + classNames: function(element) { + return new Element.ClassNames(element); + }, + + hasClassName: function(element, className) { + if (!(element = $(element))) return; + var elementClassName = element.className; + return (elementClassName.length > 0 && (elementClassName == className || + new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName))); + }, + + addClassName: function(element, className) { + if (!(element = $(element))) return; + if (!Element.hasClassName(element, className)) + element.className += (element.className ? ' ' : '') + className; + return element; + }, + + removeClassName: function(element, className) { + if (!(element = $(element))) return; + element.className = element.className.replace( + new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip(); + return element; + }, + + toggleClassName: function(element, className) { + if (!(element = $(element))) return; + return Element[Element.hasClassName(element, className) ? + 'removeClassName' : 'addClassName'](element, className); + }, + + cleanWhitespace: function(element) { + element = $(element); + var node = element.firstChild; + while (node) { + var nextNode = node.nextSibling; + if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) + element.removeChild(node); + node = nextNode; + } + return element; + }, + + empty: function(element) { + return $(element).innerHTML.blank(); + }, + + descendantOf: function(element, ancestor) { + element = $(element), ancestor = $(ancestor); + + if (element.compareDocumentPosition) + return (element.compareDocumentPosition(ancestor) & 8) === 8; + + if (ancestor.contains) + return ancestor.contains(element) && ancestor !== element; + + while (element = element.parentNode) + if (element == ancestor) return true; + + return false; + }, + + scrollTo: function(element) { + element = $(element); + var pos = Element.cumulativeOffset(element); + window.scrollTo(pos[0], pos[1]); + return element; + }, + + getStyle: function(element, style) { + element = $(element); + style = style == 'float' ? 'cssFloat' : style.camelize(); + var value = element.style[style]; + if (!value || value == 'auto') { + var css = document.defaultView.getComputedStyle(element, null); + value = css ? css[style] : null; + } + if (style == 'opacity') return value ? parseFloat(value) : 1.0; + return value == 'auto' ? null : value; + }, + + getOpacity: function(element) { + return $(element).getStyle('opacity'); + }, + + setStyle: function(element, styles) { + element = $(element); + var elementStyle = element.style, match; + if (Object.isString(styles)) { + element.style.cssText += ';' + styles; + return styles.include('opacity') ? + element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element; + } + for (var property in styles) + if (property == 'opacity') element.setOpacity(styles[property]); + else + elementStyle[(property == 'float' || property == 'cssFloat') ? + (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') : + property] = styles[property]; + + return element; + }, + + setOpacity: function(element, value) { + element = $(element); + element.style.opacity = (value == 1 || value === '') ? '' : + (value < 0.00001) ? 0 : value; + return element; + }, + + getDimensions: function(element) { + element = $(element); + var display = Element.getStyle(element, 'display'); + if (display != 'none' && display != null) // Safari bug + return {width: element.offsetWidth, height: element.offsetHeight}; + + var els = element.style; + var originalVisibility = els.visibility; + var originalPosition = els.position; + var originalDisplay = els.display; + els.visibility = 'hidden'; + if (originalPosition != 'fixed') // Switching fixed to absolute causes issues in Safari + els.position = 'absolute'; + els.display = 'block'; + var originalWidth = element.clientWidth; + var originalHeight = element.clientHeight; + els.display = originalDisplay; + els.position = originalPosition; + els.visibility = originalVisibility; + return {width: originalWidth, height: originalHeight}; + }, + + makePositioned: function(element) { + element = $(element); + var pos = Element.getStyle(element, 'position'); + if (pos == 'static' || !pos) { + element._madePositioned = true; + element.style.position = 'relative'; + if (Prototype.Browser.Opera) { + element.style.top = 0; + element.style.left = 0; + } + } + return element; + }, + + undoPositioned: function(element) { + element = $(element); + if (element._madePositioned) { + element._madePositioned = undefined; + element.style.position = + element.style.top = + element.style.left = + element.style.bottom = + element.style.right = ''; + } + return element; + }, + + makeClipping: function(element) { + element = $(element); + if (element._overflow) return element; + element._overflow = Element.getStyle(element, 'overflow') || 'auto'; + if (element._overflow !== 'hidden') + element.style.overflow = 'hidden'; + return element; + }, + + undoClipping: function(element) { + element = $(element); + if (!element._overflow) return element; + element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; + element._overflow = null; + return element; + }, + + cumulativeOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + } while (element); + return Element._returnOffset(valueL, valueT); + }, + + positionedOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + if (element) { + if (element.tagName.toUpperCase() == 'BODY') break; + var p = Element.getStyle(element, 'position'); + if (p !== 'static') break; + } + } while (element); + return Element._returnOffset(valueL, valueT); + }, + + absolutize: function(element) { + element = $(element); + if (Element.getStyle(element, 'position') == 'absolute') return element; + + var offsets = Element.positionedOffset(element); + var top = offsets[1]; + var left = offsets[0]; + var width = element.clientWidth; + var height = element.clientHeight; + + element._originalLeft = left - parseFloat(element.style.left || 0); + element._originalTop = top - parseFloat(element.style.top || 0); + element._originalWidth = element.style.width; + element._originalHeight = element.style.height; + + element.style.position = 'absolute'; + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.width = width + 'px'; + element.style.height = height + 'px'; + return element; + }, + + relativize: function(element) { + element = $(element); + if (Element.getStyle(element, 'position') == 'relative') return element; + + element.style.position = 'relative'; + var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); + var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); + + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.height = element._originalHeight; + element.style.width = element._originalWidth; + return element; + }, + + cumulativeScrollOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.scrollTop || 0; + valueL += element.scrollLeft || 0; + element = element.parentNode; + } while (element); + return Element._returnOffset(valueL, valueT); + }, + + getOffsetParent: function(element) { + if (element.offsetParent) return $(element.offsetParent); + if (element == document.body) return $(element); + + while ((element = element.parentNode) && element != document.body) + if (Element.getStyle(element, 'position') != 'static') + return $(element); + + return $(document.body); + }, + + viewportOffset: function(forElement) { + var valueT = 0, valueL = 0; + + var element = forElement; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + + if (element.offsetParent == document.body && + Element.getStyle(element, 'position') == 'absolute') break; + + } while (element = element.offsetParent); + + element = forElement; + do { + if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) { + valueT -= element.scrollTop || 0; + valueL -= element.scrollLeft || 0; + } + } while (element = element.parentNode); + + return Element._returnOffset(valueL, valueT); + }, + + clonePosition: function(element, source) { + var options = Object.extend({ + setLeft: true, + setTop: true, + setWidth: true, + setHeight: true, + offsetTop: 0, + offsetLeft: 0 + }, arguments[2] || { }); + + source = $(source); + var p = Element.viewportOffset(source); + + element = $(element); + var delta = [0, 0]; + var parent = null; + if (Element.getStyle(element, 'position') == 'absolute') { + parent = Element.getOffsetParent(element); + delta = Element.viewportOffset(parent); + } + + if (parent == document.body) { + delta[0] -= document.body.offsetLeft; + delta[1] -= document.body.offsetTop; + } + + if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; + if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; + if (options.setWidth) element.style.width = source.offsetWidth + 'px'; + if (options.setHeight) element.style.height = source.offsetHeight + 'px'; + return element; + } +}; + +Object.extend(Element.Methods, { + getElementsBySelector: Element.Methods.select, + + childElements: Element.Methods.immediateDescendants +}); + +Element._attributeTranslations = { + write: { + names: { + className: 'class', + htmlFor: 'for' + }, + values: { } + } +}; + +if (Prototype.Browser.Opera) { + Element.Methods.getStyle = Element.Methods.getStyle.wrap( + function(proceed, element, style) { + switch (style) { + case 'left': case 'top': case 'right': case 'bottom': + if (proceed(element, 'position') === 'static') return null; + case 'height': case 'width': + if (!Element.visible(element)) return null; + + var dim = parseInt(proceed(element, style), 10); + + if (dim !== element['offset' + style.capitalize()]) + return dim + 'px'; + + var properties; + if (style === 'height') { + properties = ['border-top-width', 'padding-top', + 'padding-bottom', 'border-bottom-width']; + } + else { + properties = ['border-left-width', 'padding-left', + 'padding-right', 'border-right-width']; + } + return properties.inject(dim, function(memo, property) { + var val = proceed(element, property); + return val === null ? memo : memo - parseInt(val, 10); + }) + 'px'; + default: return proceed(element, style); + } + } + ); + + Element.Methods.readAttribute = Element.Methods.readAttribute.wrap( + function(proceed, element, attribute) { + if (attribute === 'title') return element.title; + return proceed(element, attribute); + } + ); +} + +else if (Prototype.Browser.IE) { + Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap( + function(proceed, element) { + element = $(element); + try { element.offsetParent } + catch(e) { return $(document.body) } + var position = element.getStyle('position'); + if (position !== 'static') return proceed(element); + element.setStyle({ position: 'relative' }); + var value = proceed(element); + element.setStyle({ position: position }); + return value; + } + ); + + $w('positionedOffset viewportOffset').each(function(method) { + Element.Methods[method] = Element.Methods[method].wrap( + function(proceed, element) { + element = $(element); + try { element.offsetParent } + catch(e) { return Element._returnOffset(0,0) } + var position = element.getStyle('position'); + if (position !== 'static') return proceed(element); + var offsetParent = element.getOffsetParent(); + if (offsetParent && offsetParent.getStyle('position') === 'fixed') + offsetParent.setStyle({ zoom: 1 }); + element.setStyle({ position: 'relative' }); + var value = proceed(element); + element.setStyle({ position: position }); + return value; + } + ); + }); + + Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap( + function(proceed, element) { + try { element.offsetParent } + catch(e) { return Element._returnOffset(0,0) } + return proceed(element); + } + ); + + Element.Methods.getStyle = function(element, style) { + element = $(element); + style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); + var value = element.style[style]; + if (!value && element.currentStyle) value = element.currentStyle[style]; + + if (style == 'opacity') { + if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) + if (value[1]) return parseFloat(value[1]) / 100; + return 1.0; + } + + if (value == 'auto') { + if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none')) + return element['offset' + style.capitalize()] + 'px'; + return null; + } + return value; + }; + + Element.Methods.setOpacity = function(element, value) { + function stripAlpha(filter){ + return filter.replace(/alpha\([^\)]*\)/gi,''); + } + element = $(element); + var currentStyle = element.currentStyle; + if ((currentStyle && !currentStyle.hasLayout) || + (!currentStyle && element.style.zoom == 'normal')) + element.style.zoom = 1; + + var filter = element.getStyle('filter'), style = element.style; + if (value == 1 || value === '') { + (filter = stripAlpha(filter)) ? + style.filter = filter : style.removeAttribute('filter'); + return element; + } else if (value < 0.00001) value = 0; + style.filter = stripAlpha(filter) + + 'alpha(opacity=' + (value * 100) + ')'; + return element; + }; + + Element._attributeTranslations = (function(){ + + var classProp = 'className'; + var forProp = 'for'; + + var el = document.createElement('div'); + + el.setAttribute(classProp, 'x'); + + if (el.className !== 'x') { + el.setAttribute('class', 'x'); + if (el.className === 'x') { + classProp = 'class'; + } + } + el = null; + + el = document.createElement('label'); + el.setAttribute(forProp, 'x'); + if (el.htmlFor !== 'x') { + el.setAttribute('htmlFor', 'x'); + if (el.htmlFor === 'x') { + forProp = 'htmlFor'; + } + } + el = null; + + return { + read: { + names: { + 'class': classProp, + 'className': classProp, + 'for': forProp, + 'htmlFor': forProp + }, + values: { + _getAttr: function(element, attribute) { + return element.getAttribute(attribute); + }, + _getAttr2: function(element, attribute) { + return element.getAttribute(attribute, 2); + }, + _getAttrNode: function(element, attribute) { + var node = element.getAttributeNode(attribute); + return node ? node.value : ""; + }, + _getEv: (function(){ + + var el = document.createElement('div'); + el.onclick = Prototype.emptyFunction; + var value = el.getAttribute('onclick'); + var f; + + if (String(value).indexOf('{') > -1) { + f = function(element, attribute) { + attribute = element.getAttribute(attribute); + if (!attribute) return null; + attribute = attribute.toString(); + attribute = attribute.split('{')[1]; + attribute = attribute.split('}')[0]; + return attribute.strip(); + }; + } + else if (value === '') { + f = function(element, attribute) { + attribute = element.getAttribute(attribute); + if (!attribute) return null; + return attribute.strip(); + }; + } + el = null; + return f; + })(), + _flag: function(element, attribute) { + return $(element).hasAttribute(attribute) ? attribute : null; + }, + style: function(element) { + return element.style.cssText.toLowerCase(); + }, + title: function(element) { + return element.title; + } + } + } + } + })(); + + Element._attributeTranslations.write = { + names: Object.extend({ + cellpadding: 'cellPadding', + cellspacing: 'cellSpacing' + }, Element._attributeTranslations.read.names), + values: { + checked: function(element, value) { + element.checked = !!value; + }, + + style: function(element, value) { + element.style.cssText = value ? value : ''; + } + } + }; + + Element._attributeTranslations.has = {}; + + $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' + + 'encType maxLength readOnly longDesc frameBorder').each(function(attr) { + Element._attributeTranslations.write.names[attr.toLowerCase()] = attr; + Element._attributeTranslations.has[attr.toLowerCase()] = attr; + }); + + (function(v) { + Object.extend(v, { + href: v._getAttr2, + src: v._getAttr2, + type: v._getAttr, + action: v._getAttrNode, + disabled: v._flag, + checked: v._flag, + readonly: v._flag, + multiple: v._flag, + onload: v._getEv, + onunload: v._getEv, + onclick: v._getEv, + ondblclick: v._getEv, + onmousedown: v._getEv, + onmouseup: v._getEv, + onmouseover: v._getEv, + onmousemove: v._getEv, + onmouseout: v._getEv, + onfocus: v._getEv, + onblur: v._getEv, + onkeypress: v._getEv, + onkeydown: v._getEv, + onkeyup: v._getEv, + onsubmit: v._getEv, + onreset: v._getEv, + onselect: v._getEv, + onchange: v._getEv + }); + })(Element._attributeTranslations.read.values); + + if (Prototype.BrowserFeatures.ElementExtensions) { + (function() { + function _descendants(element) { + var nodes = element.getElementsByTagName('*'), results = []; + for (var i = 0, node; node = nodes[i]; i++) + if (node.tagName !== "!") // Filter out comment nodes. + results.push(node); + return results; + } + + Element.Methods.down = function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return element.firstDescendant(); + return Object.isNumber(expression) ? _descendants(element)[expression] : + Element.select(element, expression)[index || 0]; + } + })(); + } + +} + +else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) { + Element.Methods.setOpacity = function(element, value) { + element = $(element); + element.style.opacity = (value == 1) ? 0.999999 : + (value === '') ? '' : (value < 0.00001) ? 0 : value; + return element; + }; +} + +else if (Prototype.Browser.WebKit) { + Element.Methods.setOpacity = function(element, value) { + element = $(element); + element.style.opacity = (value == 1 || value === '') ? '' : + (value < 0.00001) ? 0 : value; + + if (value == 1) + if(element.tagName.toUpperCase() == 'IMG' && element.width) { + element.width++; element.width--; + } else try { + var n = document.createTextNode(' '); + element.appendChild(n); + element.removeChild(n); + } catch (e) { } + + return element; + }; + + Element.Methods.cumulativeOffset = function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + if (element.offsetParent == document.body) + if (Element.getStyle(element, 'position') == 'absolute') break; + + element = element.offsetParent; + } while (element); + + return Element._returnOffset(valueL, valueT); + }; +} + +if ('outerHTML' in document.documentElement) { + Element.Methods.replace = function(element, content) { + element = $(element); + + if (content && content.toElement) content = content.toElement(); + if (Object.isElement(content)) { + element.parentNode.replaceChild(content, element); + return element; + } + + content = Object.toHTML(content); + var parent = element.parentNode, tagName = parent.tagName.toUpperCase(); + + if (Element._insertionTranslations.tags[tagName]) { + var nextSibling = element.next(); + var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); + parent.removeChild(element); + if (nextSibling) + fragments.each(function(node) { parent.insertBefore(node, nextSibling) }); + else + fragments.each(function(node) { parent.appendChild(node) }); + } + else element.outerHTML = content.stripScripts(); + + content.evalScripts.bind(content).defer(); + return element; + }; +} + +Element._returnOffset = function(l, t) { + var result = [l, t]; + result.left = l; + result.top = t; + return result; +}; + +Element._getContentFromAnonymousElement = function(tagName, html) { + var div = new Element('div'), t = Element._insertionTranslations.tags[tagName]; + if (t) { + div.innerHTML = t[0] + html + t[1]; + t[2].times(function() { div = div.firstChild }); + } else div.innerHTML = html; + return $A(div.childNodes); +}; + +Element._insertionTranslations = { + before: function(element, node) { + element.parentNode.insertBefore(node, element); + }, + top: function(element, node) { + element.insertBefore(node, element.firstChild); + }, + bottom: function(element, node) { + element.appendChild(node); + }, + after: function(element, node) { + element.parentNode.insertBefore(node, element.nextSibling); + }, + tags: { + TABLE: ['', '
', 1], + TBODY: ['', '
', 2], + TR: ['', '
', 3], + TD: ['
', '
', 4], + SELECT: ['', 1] + } +}; + +(function() { + var tags = Element._insertionTranslations.tags; + Object.extend(tags, { + THEAD: tags.TBODY, + TFOOT: tags.TBODY, + TH: tags.TD + }); +})(); + +Element.Methods.Simulated = { + hasAttribute: function(element, attribute) { + attribute = Element._attributeTranslations.has[attribute] || attribute; + var node = $(element).getAttributeNode(attribute); + return !!(node && node.specified); + } +}; + +Element.Methods.ByTag = { }; + +Object.extend(Element, Element.Methods); + +(function(div) { + + if (!Prototype.BrowserFeatures.ElementExtensions && div['__proto__']) { + window.HTMLElement = { }; + window.HTMLElement.prototype = div['__proto__']; + Prototype.BrowserFeatures.ElementExtensions = true; + } + + div = null; + +})(document.createElement('div')) + +Element.extend = (function() { + + function checkDeficiency(tagName) { + if (typeof window.Element != 'undefined') { + var proto = window.Element.prototype; + if (proto) { + var id = '_' + (Math.random()+'').slice(2); + var el = document.createElement(tagName); + proto[id] = 'x'; + var isBuggy = (el[id] !== 'x'); + delete proto[id]; + el = null; + return isBuggy; + } + } + return false; + } + + function extendElementWith(element, methods) { + for (var property in methods) { + var value = methods[property]; + if (Object.isFunction(value) && !(property in element)) + element[property] = value.methodize(); + } + } + + var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY = checkDeficiency('object'); + + if (Prototype.BrowserFeatures.SpecificElementExtensions) { + if (HTMLOBJECTELEMENT_PROTOTYPE_BUGGY) { + return function(element) { + if (element && typeof element._extendedByPrototype == 'undefined') { + var t = element.tagName; + if (t && (/^(?:object|applet|embed)$/i.test(t))) { + extendElementWith(element, Element.Methods); + extendElementWith(element, Element.Methods.Simulated); + extendElementWith(element, Element.Methods.ByTag[t.toUpperCase()]); + } + } + return element; + } + } + return Prototype.K; + } + + var Methods = { }, ByTag = Element.Methods.ByTag; + + var extend = Object.extend(function(element) { + if (!element || typeof element._extendedByPrototype != 'undefined' || + element.nodeType != 1 || element == window) return element; + + var methods = Object.clone(Methods), + tagName = element.tagName.toUpperCase(); + + if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]); + + extendElementWith(element, methods); + + element._extendedByPrototype = Prototype.emptyFunction; + return element; + + }, { + refresh: function() { + if (!Prototype.BrowserFeatures.ElementExtensions) { + Object.extend(Methods, Element.Methods); + Object.extend(Methods, Element.Methods.Simulated); + } + } + }); + + extend.refresh(); + return extend; +})(); + +Element.hasAttribute = function(element, attribute) { + if (element.hasAttribute) return element.hasAttribute(attribute); + return Element.Methods.Simulated.hasAttribute(element, attribute); +}; + +Element.addMethods = function(methods) { + var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag; + + if (!methods) { + Object.extend(Form, Form.Methods); + Object.extend(Form.Element, Form.Element.Methods); + Object.extend(Element.Methods.ByTag, { + "FORM": Object.clone(Form.Methods), + "INPUT": Object.clone(Form.Element.Methods), + "SELECT": Object.clone(Form.Element.Methods), + "TEXTAREA": Object.clone(Form.Element.Methods) + }); + } + + if (arguments.length == 2) { + var tagName = methods; + methods = arguments[1]; + } + + if (!tagName) Object.extend(Element.Methods, methods || { }); + else { + if (Object.isArray(tagName)) tagName.each(extend); + else extend(tagName); + } + + function extend(tagName) { + tagName = tagName.toUpperCase(); + if (!Element.Methods.ByTag[tagName]) + Element.Methods.ByTag[tagName] = { }; + Object.extend(Element.Methods.ByTag[tagName], methods); + } + + function copy(methods, destination, onlyIfAbsent) { + onlyIfAbsent = onlyIfAbsent || false; + for (var property in methods) { + var value = methods[property]; + if (!Object.isFunction(value)) continue; + if (!onlyIfAbsent || !(property in destination)) + destination[property] = value.methodize(); + } + } + + function findDOMClass(tagName) { + var klass; + var trans = { + "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph", + "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList", + "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading", + "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote", + "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION": + "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD": + "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR": + "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET": + "FrameSet", "IFRAME": "IFrame" + }; + if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element'; + if (window[klass]) return window[klass]; + klass = 'HTML' + tagName + 'Element'; + if (window[klass]) return window[klass]; + klass = 'HTML' + tagName.capitalize() + 'Element'; + if (window[klass]) return window[klass]; + + var element = document.createElement(tagName); + var proto = element['__proto__'] || element.constructor.prototype; + element = null; + return proto; + } + + var elementPrototype = window.HTMLElement ? HTMLElement.prototype : + Element.prototype; + + if (F.ElementExtensions) { + copy(Element.Methods, elementPrototype); + copy(Element.Methods.Simulated, elementPrototype, true); + } + + if (F.SpecificElementExtensions) { + for (var tag in Element.Methods.ByTag) { + var klass = findDOMClass(tag); + if (Object.isUndefined(klass)) continue; + copy(T[tag], klass.prototype); + } + } + + Object.extend(Element, Element.Methods); + delete Element.ByTag; + + if (Element.extend.refresh) Element.extend.refresh(); + Element.cache = { }; +}; + + +document.viewport = { + + getDimensions: function() { + return { width: this.getWidth(), height: this.getHeight() }; + }, + + getScrollOffsets: function() { + return Element._returnOffset( + window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft, + window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); + } +}; + +(function(viewport) { + var B = Prototype.Browser, doc = document, element, property = {}; + + function getRootElement() { + if (B.WebKit && !doc.evaluate) + return document; + + if (B.Opera && window.parseFloat(window.opera.version()) < 9.5) + return document.body; + + return document.documentElement; + } + + function define(D) { + if (!element) element = getRootElement(); + + property[D] = 'client' + D; + + viewport['get' + D] = function() { return element[property[D]] }; + return viewport['get' + D](); + } + + viewport.getWidth = define.curry('Width'); + + viewport.getHeight = define.curry('Height'); +})(document.viewport); + + +Element.Storage = { + UID: 1 +}; + +Element.addMethods({ + getStorage: function(element) { + if (!(element = $(element))) return; + + var uid; + if (element === window) { + uid = 0; + } else { + if (typeof element._prototypeUID === "undefined") + element._prototypeUID = [Element.Storage.UID++]; + uid = element._prototypeUID[0]; + } + + if (!Element.Storage[uid]) + Element.Storage[uid] = $H(); + + return Element.Storage[uid]; + }, + + store: function(element, key, value) { + if (!(element = $(element))) return; + + if (arguments.length === 2) { + Element.getStorage(element).update(key); + } else { + Element.getStorage(element).set(key, value); + } + + return element; + }, + + retrieve: function(element, key, defaultValue) { + if (!(element = $(element))) return; + var hash = Element.getStorage(element), value = hash.get(key); + + if (Object.isUndefined(value)) { + hash.set(key, defaultValue); + value = defaultValue; + } + + return value; + }, + + clone: function(element, deep) { + if (!(element = $(element))) return; + var clone = element.cloneNode(deep); + clone._prototypeUID = void 0; + if (deep) { + var descendants = Element.select(clone, '*'), + i = descendants.length; + while (i--) { + descendants[i]._prototypeUID = void 0; + } + } + return Element.extend(clone); + } +}); +/* Portions of the Selector class are derived from Jack Slocum's DomQuery, + * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style + * license. Please see http://www.yui-ext.com/ for more information. */ + +var Selector = Class.create({ + initialize: function(expression) { + this.expression = expression.strip(); + + if (this.shouldUseSelectorsAPI()) { + this.mode = 'selectorsAPI'; + } else if (this.shouldUseXPath()) { + this.mode = 'xpath'; + this.compileXPathMatcher(); + } else { + this.mode = "normal"; + this.compileMatcher(); + } + + }, + + shouldUseXPath: (function() { + + var IS_DESCENDANT_SELECTOR_BUGGY = (function(){ + var isBuggy = false; + if (document.evaluate && window.XPathResult) { + var el = document.createElement('div'); + el.innerHTML = '
'; + + var xpath = ".//*[local-name()='ul' or local-name()='UL']" + + "//*[local-name()='li' or local-name()='LI']"; + + var result = document.evaluate(xpath, el, null, + XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); + + isBuggy = (result.snapshotLength !== 2); + el = null; + } + return isBuggy; + })(); + + return function() { + if (!Prototype.BrowserFeatures.XPath) return false; + + var e = this.expression; + + if (Prototype.Browser.WebKit && + (e.include("-of-type") || e.include(":empty"))) + return false; + + if ((/(\[[\w-]*?:|:checked)/).test(e)) + return false; + + if (IS_DESCENDANT_SELECTOR_BUGGY) return false; + + return true; + } + + })(), + + shouldUseSelectorsAPI: function() { + if (!Prototype.BrowserFeatures.SelectorsAPI) return false; + + if (Selector.CASE_INSENSITIVE_CLASS_NAMES) return false; + + if (!Selector._div) Selector._div = new Element('div'); + + try { + Selector._div.querySelector(this.expression); + } catch(e) { + return false; + } + + return true; + }, + + compileMatcher: function() { + var e = this.expression, ps = Selector.patterns, h = Selector.handlers, + c = Selector.criteria, le, p, m, len = ps.length, name; + + if (Selector._cache[e]) { + this.matcher = Selector._cache[e]; + return; + } + + this.matcher = ["this.matcher = function(root) {", + "var r = root, h = Selector.handlers, c = false, n;"]; + + while (e && le != e && (/\S/).test(e)) { + le = e; + for (var i = 0; i"; + } +}); + +if (Prototype.BrowserFeatures.SelectorsAPI && + document.compatMode === 'BackCompat') { + Selector.CASE_INSENSITIVE_CLASS_NAMES = (function(){ + var div = document.createElement('div'), + span = document.createElement('span'); + + div.id = "prototype_test_id"; + span.className = 'Test'; + div.appendChild(span); + var isIgnored = (div.querySelector('#prototype_test_id .test') !== null); + div = span = null; + return isIgnored; + })(); +} + +Object.extend(Selector, { + _cache: { }, + + xpath: { + descendant: "//*", + child: "/*", + adjacent: "/following-sibling::*[1]", + laterSibling: '/following-sibling::*', + tagName: function(m) { + if (m[1] == '*') return ''; + return "[local-name()='" + m[1].toLowerCase() + + "' or local-name()='" + m[1].toUpperCase() + "']"; + }, + className: "[contains(concat(' ', @class, ' '), ' #{1} ')]", + id: "[@id='#{1}']", + attrPresence: function(m) { + m[1] = m[1].toLowerCase(); + return new Template("[@#{1}]").evaluate(m); + }, + attr: function(m) { + m[1] = m[1].toLowerCase(); + m[3] = m[5] || m[6]; + return new Template(Selector.xpath.operators[m[2]]).evaluate(m); + }, + pseudo: function(m) { + var h = Selector.xpath.pseudos[m[1]]; + if (!h) return ''; + if (Object.isFunction(h)) return h(m); + return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m); + }, + operators: { + '=': "[@#{1}='#{3}']", + '!=': "[@#{1}!='#{3}']", + '^=': "[starts-with(@#{1}, '#{3}')]", + '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']", + '*=': "[contains(@#{1}, '#{3}')]", + '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]", + '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]" + }, + pseudos: { + 'first-child': '[not(preceding-sibling::*)]', + 'last-child': '[not(following-sibling::*)]', + 'only-child': '[not(preceding-sibling::* or following-sibling::*)]', + 'empty': "[count(*) = 0 and (count(text()) = 0)]", + 'checked': "[@checked]", + 'disabled': "[(@disabled) and (@type!='hidden')]", + 'enabled': "[not(@disabled) and (@type!='hidden')]", + 'not': function(m) { + var e = m[6], p = Selector.patterns, + x = Selector.xpath, le, v, len = p.length, name; + + var exclusion = []; + while (e && le != e && (/\S/).test(e)) { + le = e; + for (var i = 0; i= 0)]"; + return new Template(predicate).evaluate({ + fragment: fragment, a: a, b: b }); + } + } + } + }, + + criteria: { + tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;', + className: 'n = h.className(n, r, "#{1}", c); c = false;', + id: 'n = h.id(n, r, "#{1}", c); c = false;', + attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;', + attr: function(m) { + m[3] = (m[5] || m[6]); + return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m); + }, + pseudo: function(m) { + if (m[6]) m[6] = m[6].replace(/"/g, '\\"'); + return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m); + }, + descendant: 'c = "descendant";', + child: 'c = "child";', + adjacent: 'c = "adjacent";', + laterSibling: 'c = "laterSibling";' + }, + + patterns: [ + { name: 'laterSibling', re: /^\s*~\s*/ }, + { name: 'child', re: /^\s*>\s*/ }, + { name: 'adjacent', re: /^\s*\+\s*/ }, + { name: 'descendant', re: /^\s/ }, + + { name: 'tagName', re: /^\s*(\*|[\w\-]+)(\b|$)?/ }, + { name: 'id', re: /^#([\w\-\*]+)(\b|$)/ }, + { name: 'className', re: /^\.([\w\-\*]+)(\b|$)/ }, + { name: 'pseudo', re: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/ }, + { name: 'attrPresence', re: /^\[((?:[\w-]+:)?[\w-]+)\]/ }, + { name: 'attr', re: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/ } + ], + + assertions: { + tagName: function(element, matches) { + return matches[1].toUpperCase() == element.tagName.toUpperCase(); + }, + + className: function(element, matches) { + return Element.hasClassName(element, matches[1]); + }, + + id: function(element, matches) { + return element.id === matches[1]; + }, + + attrPresence: function(element, matches) { + return Element.hasAttribute(element, matches[1]); + }, + + attr: function(element, matches) { + var nodeValue = Element.readAttribute(element, matches[1]); + return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]); + } + }, + + handlers: { + concat: function(a, b) { + for (var i = 0, node; node = b[i]; i++) + a.push(node); + return a; + }, + + mark: function(nodes) { + var _true = Prototype.emptyFunction; + for (var i = 0, node; node = nodes[i]; i++) + node._countedByPrototype = _true; + return nodes; + }, + + unmark: (function(){ + + var PROPERTIES_ATTRIBUTES_MAP = (function(){ + var el = document.createElement('div'), + isBuggy = false, + propName = '_countedByPrototype', + value = 'x' + el[propName] = value; + isBuggy = (el.getAttribute(propName) === value); + el = null; + return isBuggy; + })(); + + return PROPERTIES_ATTRIBUTES_MAP ? + function(nodes) { + for (var i = 0, node; node = nodes[i]; i++) + node.removeAttribute('_countedByPrototype'); + return nodes; + } : + function(nodes) { + for (var i = 0, node; node = nodes[i]; i++) + node._countedByPrototype = void 0; + return nodes; + } + })(), + + index: function(parentNode, reverse, ofType) { + parentNode._countedByPrototype = Prototype.emptyFunction; + if (reverse) { + for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) { + var node = nodes[i]; + if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; + } + } else { + for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++) + if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; + } + }, + + unique: function(nodes) { + if (nodes.length == 0) return nodes; + var results = [], n; + for (var i = 0, l = nodes.length; i < l; i++) + if (typeof (n = nodes[i])._countedByPrototype == 'undefined') { + n._countedByPrototype = Prototype.emptyFunction; + results.push(Element.extend(n)); + } + return Selector.handlers.unmark(results); + }, + + descendant: function(nodes) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) + h.concat(results, node.getElementsByTagName('*')); + return results; + }, + + child: function(nodes) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) { + for (var j = 0, child; child = node.childNodes[j]; j++) + if (child.nodeType == 1 && child.tagName != '!') results.push(child); + } + return results; + }, + + adjacent: function(nodes) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + var next = this.nextElementSibling(node); + if (next) results.push(next); + } + return results; + }, + + laterSibling: function(nodes) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) + h.concat(results, Element.nextSiblings(node)); + return results; + }, + + nextElementSibling: function(node) { + while (node = node.nextSibling) + if (node.nodeType == 1) return node; + return null; + }, + + previousElementSibling: function(node) { + while (node = node.previousSibling) + if (node.nodeType == 1) return node; + return null; + }, + + tagName: function(nodes, root, tagName, combinator) { + var uTagName = tagName.toUpperCase(); + var results = [], h = Selector.handlers; + if (nodes) { + if (combinator) { + if (combinator == "descendant") { + for (var i = 0, node; node = nodes[i]; i++) + h.concat(results, node.getElementsByTagName(tagName)); + return results; + } else nodes = this[combinator](nodes); + if (tagName == "*") return nodes; + } + for (var i = 0, node; node = nodes[i]; i++) + if (node.tagName.toUpperCase() === uTagName) results.push(node); + return results; + } else return root.getElementsByTagName(tagName); + }, + + id: function(nodes, root, id, combinator) { + var targetNode = $(id), h = Selector.handlers; + + if (root == document) { + if (!targetNode) return []; + if (!nodes) return [targetNode]; + } else { + if (!root.sourceIndex || root.sourceIndex < 1) { + var nodes = root.getElementsByTagName('*'); + for (var j = 0, node; node = nodes[j]; j++) { + if (node.id === id) return [node]; + } + } + } + + if (nodes) { + if (combinator) { + if (combinator == 'child') { + for (var i = 0, node; node = nodes[i]; i++) + if (targetNode.parentNode == node) return [targetNode]; + } else if (combinator == 'descendant') { + for (var i = 0, node; node = nodes[i]; i++) + if (Element.descendantOf(targetNode, node)) return [targetNode]; + } else if (combinator == 'adjacent') { + for (var i = 0, node; node = nodes[i]; i++) + if (Selector.handlers.previousElementSibling(targetNode) == node) + return [targetNode]; + } else nodes = h[combinator](nodes); + } + for (var i = 0, node; node = nodes[i]; i++) + if (node == targetNode) return [targetNode]; + return []; + } + return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : []; + }, + + className: function(nodes, root, className, combinator) { + if (nodes && combinator) nodes = this[combinator](nodes); + return Selector.handlers.byClassName(nodes, root, className); + }, + + byClassName: function(nodes, root, className) { + if (!nodes) nodes = Selector.handlers.descendant([root]); + var needle = ' ' + className + ' '; + for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) { + nodeClassName = node.className; + if (nodeClassName.length == 0) continue; + if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle)) + results.push(node); + } + return results; + }, + + attrPresence: function(nodes, root, attr, combinator) { + if (!nodes) nodes = root.getElementsByTagName("*"); + if (nodes && combinator) nodes = this[combinator](nodes); + var results = []; + for (var i = 0, node; node = nodes[i]; i++) + if (Element.hasAttribute(node, attr)) results.push(node); + return results; + }, + + attr: function(nodes, root, attr, value, operator, combinator) { + if (!nodes) nodes = root.getElementsByTagName("*"); + if (nodes && combinator) nodes = this[combinator](nodes); + var handler = Selector.operators[operator], results = []; + for (var i = 0, node; node = nodes[i]; i++) { + var nodeValue = Element.readAttribute(node, attr); + if (nodeValue === null) continue; + if (handler(nodeValue, value)) results.push(node); + } + return results; + }, + + pseudo: function(nodes, name, value, root, combinator) { + if (nodes && combinator) nodes = this[combinator](nodes); + if (!nodes) nodes = root.getElementsByTagName("*"); + return Selector.pseudos[name](nodes, value, root); + } + }, + + pseudos: { + 'first-child': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + if (Selector.handlers.previousElementSibling(node)) continue; + results.push(node); + } + return results; + }, + 'last-child': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + if (Selector.handlers.nextElementSibling(node)) continue; + results.push(node); + } + return results; + }, + 'only-child': function(nodes, value, root) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (!h.previousElementSibling(node) && !h.nextElementSibling(node)) + results.push(node); + return results; + }, + 'nth-child': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root); + }, + 'nth-last-child': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root, true); + }, + 'nth-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root, false, true); + }, + 'nth-last-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root, true, true); + }, + 'first-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, "1", root, false, true); + }, + 'last-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, "1", root, true, true); + }, + 'only-of-type': function(nodes, formula, root) { + var p = Selector.pseudos; + return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root); + }, + + getIndices: function(a, b, total) { + if (a == 0) return b > 0 ? [b] : []; + return $R(1, total).inject([], function(memo, i) { + if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i); + return memo; + }); + }, + + nth: function(nodes, formula, root, reverse, ofType) { + if (nodes.length == 0) return []; + if (formula == 'even') formula = '2n+0'; + if (formula == 'odd') formula = '2n+1'; + var h = Selector.handlers, results = [], indexed = [], m; + h.mark(nodes); + for (var i = 0, node; node = nodes[i]; i++) { + if (!node.parentNode._countedByPrototype) { + h.index(node.parentNode, reverse, ofType); + indexed.push(node.parentNode); + } + } + if (formula.match(/^\d+$/)) { // just a number + formula = Number(formula); + for (var i = 0, node; node = nodes[i]; i++) + if (node.nodeIndex == formula) results.push(node); + } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b + if (m[1] == "-") m[1] = -1; + var a = m[1] ? Number(m[1]) : 1; + var b = m[2] ? Number(m[2]) : 0; + var indices = Selector.pseudos.getIndices(a, b, nodes.length); + for (var i = 0, node, l = indices.length; node = nodes[i]; i++) { + for (var j = 0; j < l; j++) + if (node.nodeIndex == indices[j]) results.push(node); + } + } + h.unmark(nodes); + h.unmark(indexed); + return results; + }, + + 'empty': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + if (node.tagName == '!' || node.firstChild) continue; + results.push(node); + } + return results; + }, + + 'not': function(nodes, selector, root) { + var h = Selector.handlers, selectorType, m; + var exclusions = new Selector(selector).findElements(root); + h.mark(exclusions); + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (!node._countedByPrototype) results.push(node); + h.unmark(exclusions); + return results; + }, + + 'enabled': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (!node.disabled && (!node.type || node.type !== 'hidden')) + results.push(node); + return results; + }, + + 'disabled': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (node.disabled) results.push(node); + return results; + }, + + 'checked': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (node.checked) results.push(node); + return results; + } + }, + + operators: { + '=': function(nv, v) { return nv == v; }, + '!=': function(nv, v) { return nv != v; }, + '^=': function(nv, v) { return nv == v || nv && nv.startsWith(v); }, + '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); }, + '*=': function(nv, v) { return nv == v || nv && nv.include(v); }, + '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); }, + '|=': function(nv, v) { return ('-' + (nv || "").toUpperCase() + + '-').include('-' + (v || "").toUpperCase() + '-'); } + }, + + split: function(expression) { + var expressions = []; + expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) { + expressions.push(m[1].strip()); + }); + return expressions; + }, + + matchElements: function(elements, expression) { + var matches = $$(expression), h = Selector.handlers; + h.mark(matches); + for (var i = 0, results = [], element; element = elements[i]; i++) + if (element._countedByPrototype) results.push(element); + h.unmark(matches); + return results; + }, + + findElement: function(elements, expression, index) { + if (Object.isNumber(expression)) { + index = expression; expression = false; + } + return Selector.matchElements(elements, expression || '*')[index || 0]; + }, + + findChildElements: function(element, expressions) { + expressions = Selector.split(expressions.join(',')); + var results = [], h = Selector.handlers; + for (var i = 0, l = expressions.length, selector; i < l; i++) { + selector = new Selector(expressions[i].strip()); + h.concat(results, selector.findElements(element)); + } + return (l > 1) ? h.unique(results) : results; + } +}); + +if (Prototype.Browser.IE) { + Object.extend(Selector.handlers, { + concat: function(a, b) { + for (var i = 0, node; node = b[i]; i++) + if (node.tagName !== "!") a.push(node); + return a; + } + }); +} + +function $$() { + return Selector.findChildElements(document, $A(arguments)); +} + +var Form = { + reset: function(form) { + form = $(form); + form.reset(); + return form; + }, + + serializeElements: function(elements, options) { + if (typeof options != 'object') options = { hash: !!options }; + else if (Object.isUndefined(options.hash)) options.hash = true; + var key, value, submitted = false, submit = options.submit; + + var data = elements.inject({ }, function(result, element) { + if (!element.disabled && element.name) { + key = element.name; value = $(element).getValue(); + if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted && + submit !== false && (!submit || key == submit) && (submitted = true)))) { + if (key in result) { + if (!Object.isArray(result[key])) result[key] = [result[key]]; + result[key].push(value); + } + else result[key] = value; + } + } + return result; + }); + + return options.hash ? data : Object.toQueryString(data); + } +}; + +Form.Methods = { + serialize: function(form, options) { + return Form.serializeElements(Form.getElements(form), options); + }, + + getElements: function(form) { + var elements = $(form).getElementsByTagName('*'), + element, + arr = [ ], + serializers = Form.Element.Serializers; + for (var i = 0; element = elements[i]; i++) { + arr.push(element); + } + return arr.inject([], function(elements, child) { + if (serializers[child.tagName.toLowerCase()]) + elements.push(Element.extend(child)); + return elements; + }) + }, + + getInputs: function(form, typeName, name) { + form = $(form); + var inputs = form.getElementsByTagName('input'); + + if (!typeName && !name) return $A(inputs).map(Element.extend); + + for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { + var input = inputs[i]; + if ((typeName && input.type != typeName) || (name && input.name != name)) + continue; + matchingInputs.push(Element.extend(input)); + } + + return matchingInputs; + }, + + disable: function(form) { + form = $(form); + Form.getElements(form).invoke('disable'); + return form; + }, + + enable: function(form) { + form = $(form); + Form.getElements(form).invoke('enable'); + return form; + }, + + findFirstElement: function(form) { + var elements = $(form).getElements().findAll(function(element) { + return 'hidden' != element.type && !element.disabled; + }); + var firstByIndex = elements.findAll(function(element) { + return element.hasAttribute('tabIndex') && element.tabIndex >= 0; + }).sortBy(function(element) { return element.tabIndex }).first(); + + return firstByIndex ? firstByIndex : elements.find(function(element) { + return /^(?:input|select|textarea)$/i.test(element.tagName); + }); + }, + + focusFirstElement: function(form) { + form = $(form); + form.findFirstElement().activate(); + return form; + }, + + request: function(form, options) { + form = $(form), options = Object.clone(options || { }); + + var params = options.parameters, action = form.readAttribute('action') || ''; + if (action.blank()) action = window.location.href; + options.parameters = form.serialize(true); + + if (params) { + if (Object.isString(params)) params = params.toQueryParams(); + Object.extend(options.parameters, params); + } + + if (form.hasAttribute('method') && !options.method) + options.method = form.method; + + return new Ajax.Request(action, options); + } +}; + +/*--------------------------------------------------------------------------*/ + + +Form.Element = { + focus: function(element) { + $(element).focus(); + return element; + }, + + select: function(element) { + $(element).select(); + return element; + } +}; + +Form.Element.Methods = { + + serialize: function(element) { + element = $(element); + if (!element.disabled && element.name) { + var value = element.getValue(); + if (value != undefined) { + var pair = { }; + pair[element.name] = value; + return Object.toQueryString(pair); + } + } + return ''; + }, + + getValue: function(element) { + element = $(element); + var method = element.tagName.toLowerCase(); + return Form.Element.Serializers[method](element); + }, + + setValue: function(element, value) { + element = $(element); + var method = element.tagName.toLowerCase(); + Form.Element.Serializers[method](element, value); + return element; + }, + + clear: function(element) { + $(element).value = ''; + return element; + }, + + present: function(element) { + return $(element).value != ''; + }, + + activate: function(element) { + element = $(element); + try { + element.focus(); + if (element.select && (element.tagName.toLowerCase() != 'input' || + !(/^(?:button|reset|submit)$/i.test(element.type)))) + element.select(); + } catch (e) { } + return element; + }, + + disable: function(element) { + element = $(element); + element.disabled = true; + return element; + }, + + enable: function(element) { + element = $(element); + element.disabled = false; + return element; + } +}; + +/*--------------------------------------------------------------------------*/ + +var Field = Form.Element; + +var $F = Form.Element.Methods.getValue; + +/*--------------------------------------------------------------------------*/ + +Form.Element.Serializers = { + input: function(element, value) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + return Form.Element.Serializers.inputSelector(element, value); + default: + return Form.Element.Serializers.textarea(element, value); + } + }, + + inputSelector: function(element, value) { + if (Object.isUndefined(value)) return element.checked ? element.value : null; + else element.checked = !!value; + }, + + textarea: function(element, value) { + if (Object.isUndefined(value)) return element.value; + else element.value = value; + }, + + select: function(element, value) { + if (Object.isUndefined(value)) + return this[element.type == 'select-one' ? + 'selectOne' : 'selectMany'](element); + else { + var opt, currentValue, single = !Object.isArray(value); + for (var i = 0, length = element.length; i < length; i++) { + opt = element.options[i]; + currentValue = this.optionValue(opt); + if (single) { + if (currentValue == value) { + opt.selected = true; + return; + } + } + else opt.selected = value.include(currentValue); + } + } + }, + + selectOne: function(element) { + var index = element.selectedIndex; + return index >= 0 ? this.optionValue(element.options[index]) : null; + }, + + selectMany: function(element) { + var values, length = element.length; + if (!length) return null; + + for (var i = 0, values = []; i < length; i++) { + var opt = element.options[i]; + if (opt.selected) values.push(this.optionValue(opt)); + } + return values; + }, + + optionValue: function(opt) { + return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; + } +}; + +/*--------------------------------------------------------------------------*/ + + +Abstract.TimedObserver = Class.create(PeriodicalExecuter, { + initialize: function($super, element, frequency, callback) { + $super(callback, frequency); + this.element = $(element); + this.lastValue = this.getValue(); + }, + + execute: function() { + var value = this.getValue(); + if (Object.isString(this.lastValue) && Object.isString(value) ? + this.lastValue != value : String(this.lastValue) != String(value)) { + this.callback(this.element, value); + this.lastValue = value; + } + } +}); + +Form.Element.Observer = Class.create(Abstract.TimedObserver, { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.Observer = Class.create(Abstract.TimedObserver, { + getValue: function() { + return Form.serialize(this.element); + } +}); + +/*--------------------------------------------------------------------------*/ + +Abstract.EventObserver = Class.create({ + initialize: function(element, callback) { + this.element = $(element); + this.callback = callback; + + this.lastValue = this.getValue(); + if (this.element.tagName.toLowerCase() == 'form') + this.registerFormCallbacks(); + else + this.registerCallback(this.element); + }, + + onElementEvent: function() { + var value = this.getValue(); + if (this.lastValue != value) { + this.callback(this.element, value); + this.lastValue = value; + } + }, + + registerFormCallbacks: function() { + Form.getElements(this.element).each(this.registerCallback, this); + }, + + registerCallback: function(element) { + if (element.type) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + Event.observe(element, 'click', this.onElementEvent.bind(this)); + break; + default: + Event.observe(element, 'change', this.onElementEvent.bind(this)); + break; + } + } + } +}); + +Form.Element.EventObserver = Class.create(Abstract.EventObserver, { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.EventObserver = Class.create(Abstract.EventObserver, { + getValue: function() { + return Form.serialize(this.element); + } +}); +(function() { + + var Event = { + KEY_BACKSPACE: 8, + KEY_TAB: 9, + KEY_RETURN: 13, + KEY_ESC: 27, + KEY_LEFT: 37, + KEY_UP: 38, + KEY_RIGHT: 39, + KEY_DOWN: 40, + KEY_DELETE: 46, + KEY_HOME: 36, + KEY_END: 35, + KEY_PAGEUP: 33, + KEY_PAGEDOWN: 34, + KEY_INSERT: 45, + + cache: {} + }; + + var docEl = document.documentElement; + var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl + && 'onmouseleave' in docEl; + + var _isButton; + if (Prototype.Browser.IE) { + var buttonMap = { 0: 1, 1: 4, 2: 2 }; + _isButton = function(event, code) { + return event.button === buttonMap[code]; + }; + } else if (Prototype.Browser.WebKit) { + _isButton = function(event, code) { + switch (code) { + case 0: return event.which == 1 && !event.metaKey; + case 1: return event.which == 1 && event.metaKey; + default: return false; + } + }; + } else { + _isButton = function(event, code) { + return event.which ? (event.which === code + 1) : (event.button === code); + }; + } + + function isLeftClick(event) { return _isButton(event, 0) } + + function isMiddleClick(event) { return _isButton(event, 1) } + + function isRightClick(event) { return _isButton(event, 2) } + + function element(event) { + event = Event.extend(event); + + var node = event.target, type = event.type, + currentTarget = event.currentTarget; + + if (currentTarget && currentTarget.tagName) { + if (type === 'load' || type === 'error' || + (type === 'click' && currentTarget.tagName.toLowerCase() === 'input' + && currentTarget.type === 'radio')) + node = currentTarget; + } + + if (node.nodeType == Node.TEXT_NODE) + node = node.parentNode; + + return Element.extend(node); + } + + function findElement(event, expression) { + var element = Event.element(event); + if (!expression) return element; + var elements = [element].concat(element.ancestors()); + return Selector.findElement(elements, expression, 0); + } + + function pointer(event) { + return { x: pointerX(event), y: pointerY(event) }; + } + + function pointerX(event) { + var docElement = document.documentElement, + body = document.body || { scrollLeft: 0 }; + + return event.pageX || (event.clientX + + (docElement.scrollLeft || body.scrollLeft) - + (docElement.clientLeft || 0)); + } + + function pointerY(event) { + var docElement = document.documentElement, + body = document.body || { scrollTop: 0 }; + + return event.pageY || (event.clientY + + (docElement.scrollTop || body.scrollTop) - + (docElement.clientTop || 0)); + } + + + function stop(event) { + Event.extend(event); + event.preventDefault(); + event.stopPropagation(); + + event.stopped = true; + } + + Event.Methods = { + isLeftClick: isLeftClick, + isMiddleClick: isMiddleClick, + isRightClick: isRightClick, + + element: element, + findElement: findElement, + + pointer: pointer, + pointerX: pointerX, + pointerY: pointerY, + + stop: stop + }; + + + var methods = Object.keys(Event.Methods).inject({ }, function(m, name) { + m[name] = Event.Methods[name].methodize(); + return m; + }); + + if (Prototype.Browser.IE) { + function _relatedTarget(event) { + var element; + switch (event.type) { + case 'mouseover': element = event.fromElement; break; + case 'mouseout': element = event.toElement; break; + default: return null; + } + return Element.extend(element); + } + + Object.extend(methods, { + stopPropagation: function() { this.cancelBubble = true }, + preventDefault: function() { this.returnValue = false }, + inspect: function() { return '[object Event]' } + }); + + Event.extend = function(event, element) { + if (!event) return false; + if (event._extendedByPrototype) return event; + + event._extendedByPrototype = Prototype.emptyFunction; + var pointer = Event.pointer(event); + + Object.extend(event, { + target: event.srcElement || element, + relatedTarget: _relatedTarget(event), + pageX: pointer.x, + pageY: pointer.y + }); + + return Object.extend(event, methods); + }; + } else { + Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__; + Object.extend(Event.prototype, methods); + Event.extend = Prototype.K; + } + + function _createResponder(element, eventName, handler) { + var registry = Element.retrieve(element, 'prototype_event_registry'); + + if (Object.isUndefined(registry)) { + CACHE.push(element); + registry = Element.retrieve(element, 'prototype_event_registry', $H()); + } + + var respondersForEvent = registry.get(eventName); + if (Object.isUndefined(respondersForEvent)) { + respondersForEvent = []; + registry.set(eventName, respondersForEvent); + } + + if (respondersForEvent.pluck('handler').include(handler)) return false; + + var responder; + if (eventName.include(":")) { + responder = function(event) { + if (Object.isUndefined(event.eventName)) + return false; + + if (event.eventName !== eventName) + return false; + + Event.extend(event, element); + handler.call(element, event); + }; + } else { + if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED && + (eventName === "mouseenter" || eventName === "mouseleave")) { + if (eventName === "mouseenter" || eventName === "mouseleave") { + responder = function(event) { + Event.extend(event, element); + + var parent = event.relatedTarget; + while (parent && parent !== element) { + try { parent = parent.parentNode; } + catch(e) { parent = element; } + } + + if (parent === element) return; + + handler.call(element, event); + }; + } + } else { + responder = function(event) { + Event.extend(event, element); + handler.call(element, event); + }; + } + } + + responder.handler = handler; + respondersForEvent.push(responder); + return responder; + } + + function _destroyCache() { + for (var i = 0, length = CACHE.length; i < length; i++) { + Event.stopObserving(CACHE[i]); + CACHE[i] = null; + } + } + + var CACHE = []; + + if (Prototype.Browser.IE) + window.attachEvent('onunload', _destroyCache); + + if (Prototype.Browser.WebKit) + window.addEventListener('unload', Prototype.emptyFunction, false); + + + var _getDOMEventName = Prototype.K; + + if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED) { + _getDOMEventName = function(eventName) { + var translations = { mouseenter: "mouseover", mouseleave: "mouseout" }; + return eventName in translations ? translations[eventName] : eventName; + }; + } + + function observe(element, eventName, handler) { + element = $(element); + + var responder = _createResponder(element, eventName, handler); + + if (!responder) return element; + + if (eventName.include(':')) { + if (element.addEventListener) + element.addEventListener("dataavailable", responder, false); + else { + element.attachEvent("ondataavailable", responder); + element.attachEvent("onfilterchange", responder); + } + } else { + var actualEventName = _getDOMEventName(eventName); + + if (element.addEventListener) + element.addEventListener(actualEventName, responder, false); + else + element.attachEvent("on" + actualEventName, responder); + } + + return element; + } + + function stopObserving(element, eventName, handler) { + element = $(element); + + var registry = Element.retrieve(element, 'prototype_event_registry'); + + if (Object.isUndefined(registry)) return element; + + if (eventName && !handler) { + var responders = registry.get(eventName); + + if (Object.isUndefined(responders)) return element; + + responders.each( function(r) { + Element.stopObserving(element, eventName, r.handler); + }); + return element; + } else if (!eventName) { + registry.each( function(pair) { + var eventName = pair.key, responders = pair.value; + + responders.each( function(r) { + Element.stopObserving(element, eventName, r.handler); + }); + }); + return element; + } + + var responders = registry.get(eventName); + + if (!responders) return; + + var responder = responders.find( function(r) { return r.handler === handler; }); + if (!responder) return element; + + var actualEventName = _getDOMEventName(eventName); + + if (eventName.include(':')) { + if (element.removeEventListener) + element.removeEventListener("dataavailable", responder, false); + else { + element.detachEvent("ondataavailable", responder); + element.detachEvent("onfilterchange", responder); + } + } else { + if (element.removeEventListener) + element.removeEventListener(actualEventName, responder, false); + else + element.detachEvent('on' + actualEventName, responder); + } + + registry.set(eventName, responders.without(responder)); + + return element; + } + + function fire(element, eventName, memo, bubble) { + element = $(element); + + if (Object.isUndefined(bubble)) + bubble = true; + + if (element == document && document.createEvent && !element.dispatchEvent) + element = document.documentElement; + + var event; + if (document.createEvent) { + event = document.createEvent('HTMLEvents'); + event.initEvent('dataavailable', true, true); + } else { + event = document.createEventObject(); + event.eventType = bubble ? 'ondataavailable' : 'onfilterchange'; + } + + event.eventName = eventName; + event.memo = memo || { }; + + if (document.createEvent) + element.dispatchEvent(event); + else + element.fireEvent(event.eventType, event); + + return Event.extend(event); + } + + + Object.extend(Event, Event.Methods); + + Object.extend(Event, { + fire: fire, + observe: observe, + stopObserving: stopObserving + }); + + Element.addMethods({ + fire: fire, + + observe: observe, + + stopObserving: stopObserving + }); + + Object.extend(document, { + fire: fire.methodize(), + + observe: observe.methodize(), + + stopObserving: stopObserving.methodize(), + + loaded: false + }); + + if (window.Event) Object.extend(window.Event, Event); + else window.Event = Event; +})(); + +(function() { + /* Support for the DOMContentLoaded event is based on work by Dan Webb, + Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */ + + var timer; + + function fireContentLoadedEvent() { + if (document.loaded) return; + if (timer) window.clearTimeout(timer); + document.loaded = true; + document.fire('dom:loaded'); + } + + function checkReadyState() { + if (document.readyState === 'complete') { + document.stopObserving('readystatechange', checkReadyState); + fireContentLoadedEvent(); + } + } + + function pollDoScroll() { + try { document.documentElement.doScroll('left'); } + catch(e) { + timer = pollDoScroll.defer(); + return; + } + fireContentLoadedEvent(); + } + + if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false); + } else { + document.observe('readystatechange', checkReadyState); + if (window == top) + timer = pollDoScroll.defer(); + } + + Event.observe(window, 'load', fireContentLoadedEvent); +})(); + +Element.addMethods(); + +/*------------------------------- DEPRECATED -------------------------------*/ + +Hash.toQueryString = Object.toQueryString; + +var Toggle = { display: Element.toggle }; + +Element.Methods.childOf = Element.Methods.descendantOf; + +var Insertion = { + Before: function(element, content) { + return Element.insert(element, {before:content}); + }, + + Top: function(element, content) { + return Element.insert(element, {top:content}); + }, + + Bottom: function(element, content) { + return Element.insert(element, {bottom:content}); + }, + + After: function(element, content) { + return Element.insert(element, {after:content}); + } +}; + +var $continue = new Error('"throw $continue" is deprecated, use "return" instead'); + +var Position = { + includeScrollOffsets: false, + + prepare: function() { + this.deltaX = window.pageXOffset + || document.documentElement.scrollLeft + || document.body.scrollLeft + || 0; + this.deltaY = window.pageYOffset + || document.documentElement.scrollTop + || document.body.scrollTop + || 0; + }, + + within: function(element, x, y) { + if (this.includeScrollOffsets) + return this.withinIncludingScrolloffsets(element, x, y); + this.xcomp = x; + this.ycomp = y; + this.offset = Element.cumulativeOffset(element); + + return (y >= this.offset[1] && + y < this.offset[1] + element.offsetHeight && + x >= this.offset[0] && + x < this.offset[0] + element.offsetWidth); + }, + + withinIncludingScrolloffsets: function(element, x, y) { + var offsetcache = Element.cumulativeScrollOffset(element); + + this.xcomp = x + offsetcache[0] - this.deltaX; + this.ycomp = y + offsetcache[1] - this.deltaY; + this.offset = Element.cumulativeOffset(element); + + return (this.ycomp >= this.offset[1] && + this.ycomp < this.offset[1] + element.offsetHeight && + this.xcomp >= this.offset[0] && + this.xcomp < this.offset[0] + element.offsetWidth); + }, + + overlap: function(mode, element) { + if (!mode) return 0; + if (mode == 'vertical') + return ((this.offset[1] + element.offsetHeight) - this.ycomp) / + element.offsetHeight; + if (mode == 'horizontal') + return ((this.offset[0] + element.offsetWidth) - this.xcomp) / + element.offsetWidth; + }, + + + cumulativeOffset: Element.Methods.cumulativeOffset, + + positionedOffset: Element.Methods.positionedOffset, + + absolutize: function(element) { + Position.prepare(); + return Element.absolutize(element); + }, + + relativize: function(element) { + Position.prepare(); + return Element.relativize(element); + }, + + realOffset: Element.Methods.cumulativeScrollOffset, + + offsetParent: Element.Methods.getOffsetParent, + + page: Element.Methods.viewportOffset, + + clone: function(source, target, options) { + options = options || { }; + return Element.clonePosition(target, source, options); + } +}; + +/*--------------------------------------------------------------------------*/ + +if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){ + function iter(name) { + return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]"; + } + + instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ? + function(element, className) { + className = className.toString().strip(); + var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className); + return cond ? document._getElementsByXPath('.//*' + cond, element) : []; + } : function(element, className) { + className = className.toString().strip(); + var elements = [], classNames = (/\s/.test(className) ? $w(className) : null); + if (!classNames && !className) return elements; + + var nodes = $(element).getElementsByTagName('*'); + className = ' ' + className + ' '; + + for (var i = 0, child, cn; child = nodes[i]; i++) { + if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) || + (classNames && classNames.all(function(name) { + return !name.toString().blank() && cn.include(' ' + name + ' '); + })))) + elements.push(Element.extend(child)); + } + return elements; + }; + + return function(className, parentElement) { + return $(parentElement || document.body).getElementsByClassName(className); + }; +}(Element.Methods); + +/*--------------------------------------------------------------------------*/ + +Element.ClassNames = Class.create(); +Element.ClassNames.prototype = { + initialize: function(element) { + this.element = $(element); + }, + + _each: function(iterator) { + this.element.className.split(/\s+/).select(function(name) { + return name.length > 0; + })._each(iterator); + }, + + set: function(className) { + this.element.className = className; + }, + + add: function(classNameToAdd) { + if (this.include(classNameToAdd)) return; + this.set($A(this).concat(classNameToAdd).join(' ')); + }, + + remove: function(classNameToRemove) { + if (!this.include(classNameToRemove)) return; + this.set($A(this).without(classNameToRemove).join(' ')); + }, + + toString: function() { + return $A(this).join(' '); + } +}; + +Object.extend(Element.ClassNames.prototype, Enumerable); + +/*--------------------------------------------------------------------------*/ diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/js/tabber.js b/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/js/tabber.js index a53b1b3060..9700c97a81 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/js/tabber.js +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/WebContent/js/tabber.js @@ -1,536 +1,536 @@ -/*================================================== - $Id: tabber.js,v 1.9 2006/04/27 20:51:51 pat Exp $ - tabber.js by Patrick Fitzgerald pat@barelyfitz.com - - Documentation can be found at the following URL: - http://www.barelyfitz.com/projects/tabber/ - - License (http://www.opensource.org/licenses/mit-license.php) - - Copyright (c) 2006 Patrick Fitzgerald - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - ==================================================*/ - -function tabberObj(argsObj) -{ - var arg; /* name of an argument to override */ - - /* Element for the main tabber div. If you supply this in argsObj, - then the init() method will be called. - */ - this.div = null; - - /* Class of the main tabber div */ - this.classMain = "tabber"; - - /* Rename classMain to classMainLive after tabifying - (so a different style can be applied) - */ - this.classMainLive = "tabberlive"; - - /* Class of each DIV that contains a tab */ - this.classTab = "tabbertab"; - - /* Class to indicate which tab should be active on startup */ - this.classTabDefault = "tabbertabdefault"; - - /* Class for the navigation UL */ - this.classNav = "tabbernav"; - - /* When a tab is to be hidden, instead of setting display='none', we - set the class of the div to classTabHide. In your screen - stylesheet you should set classTabHide to display:none. In your - print stylesheet you should set display:block to ensure that all - the information is printed. - */ - this.classTabHide = "tabbertabhide"; - - /* Class to set the navigation LI when the tab is active, so you can - use a different style on the active tab. - */ - this.classNavActive = "tabberactive"; - - /* Elements that might contain the title for the tab, only used if a - title is not specified in the TITLE attribute of DIV classTab. - */ - this.titleElements = ['h2','h3','h4','h5','h6']; - - /* Should we strip out the HTML from the innerHTML of the title elements? - This should usually be true. - */ - this.titleElementsStripHTML = true; - - /* If the user specified the tab names using a TITLE attribute on - the DIV, then the browser will display a tooltip whenever the - mouse is over the DIV. To prevent this tooltip, we can remove the - TITLE attribute after getting the tab name. - */ - this.removeTitle = true; - - /* If you want to add an id to each link set this to true */ - this.addLinkId = false; - - /* If addIds==true, then you can set a format for the ids. - will be replaced with the id of the main tabber div. - will be replaced with the tab number - (tab numbers starting at zero) - will be replaced with the tab number - (tab numbers starting at one) - will be replaced by the tab title - (with all non-alphanumeric characters removed) - */ - this.linkIdFormat = 'nav'; - - /* You can override the defaults listed above by passing in an object: - var mytab = new tabber({property:value,property:value}); - */ - for (arg in argsObj) { this[arg] = argsObj[arg]; } - - /* Create regular expressions for the class names; Note: if you - change the class names after a new object is created you must - also change these regular expressions. - */ - this.REclassMain = new RegExp('\\b' + this.classMain + '\\b', 'gi'); - this.REclassMainLive = new RegExp('\\b' + this.classMainLive + '\\b', 'gi'); - this.REclassTab = new RegExp('\\b' + this.classTab + '\\b', 'gi'); - this.REclassTabDefault = new RegExp('\\b' + this.classTabDefault + '\\b', 'gi'); - this.REclassTabHide = new RegExp('\\b' + this.classTabHide + '\\b', 'gi'); - - /* Array of objects holding info about each tab */ - this.tabs = new Array(); - - /* If the main tabber div was specified, call init() now */ - if (this.div) { - - this.init(this.div); - - /* We don't need the main div anymore, and to prevent a memory leak - in IE, we must remove the circular reference between the div - and the tabber object. */ - this.div = null; - } -} - - -/*-------------------------------------------------- - Methods for tabberObj - --------------------------------------------------*/ - - -tabberObj.prototype.init = function(e) -{ - /* Set up the tabber interface. - - e = element (the main containing div) - - Example: - init(document.getElementById('mytabberdiv')) - */ - - var - childNodes, /* child nodes of the tabber div */ - i, i2, /* loop indices */ - t, /* object to store info about a single tab */ - defaultTab=0, /* which tab to select by default */ - DOM_ul, /* tabbernav list */ - DOM_li, /* tabbernav list item */ - DOM_a, /* tabbernav link */ - aId, /* A unique id for DOM_a */ - headingElement; /* searching for text to use in the tab */ - - /* Verify that the browser supports DOM scripting */ - if (!document.getElementsByTagName) { return false; } - - /* If the main DIV has an ID then save it. */ - if (e.id) { - this.id = e.id; - } - - /* Clear the tabs array (but it should normally be empty) */ - this.tabs.length = 0; - - /* Loop through an array of all the child nodes within our tabber element. */ - childNodes = e.childNodes; - for(i=0; i < childNodes.length; i++) { - - /* Find the nodes where class="tabbertab" */ - if(childNodes[i].className && - childNodes[i].className.match(this.REclassTab)) { - - /* Create a new object to save info about this tab */ - t = new Object(); - - /* Save a pointer to the div for this tab */ - t.div = childNodes[i]; - - /* Add the new object to the array of tabs */ - this.tabs[this.tabs.length] = t; - - /* If the class name contains classTabDefault, - then select this tab by default. - */ - if (childNodes[i].className.match(this.REclassTabDefault)) { - defaultTab = this.tabs.length-1; - } - } - } - - /* Create a new UL list to hold the tab headings */ - DOM_ul = document.createElement("ul"); - DOM_ul.className = this.classNav; - - /* Loop through each tab we found */ - for (i=0; i < this.tabs.length; i++) { - - t = this.tabs[i]; - - /* Get the label to use for this tab: - From the title attribute on the DIV, - Or from one of the this.titleElements[] elements, - Or use an automatically generated number. - */ - t.headingText = t.div.title; - - /* Remove the title attribute to prevent a tooltip from appearing */ - if (this.removeTitle) { t.div.title = ''; } - - if (!t.headingText) { - - /* Title was not defined in the title of the DIV, - So try to get the title from an element within the DIV. - Go through the list of elements in this.titleElements - (typically heading elements ['h2','h3','h4']) - */ - for (i2=0; i2/gi," "); - t.headingText = t.headingText.replace(/<[^>]+>/g,""); - } - break; - } - } - } - - if (!t.headingText) { - /* Title was not found (or is blank) so automatically generate a - number for the tab. - */ - t.headingText = i + 1; - } - - /* Create a list element for the tab */ - DOM_li = document.createElement("li"); - - /* Save a reference to this list item so we can later change it to - the "active" class */ - t.li = DOM_li; - - /* Create a link to activate the tab */ - DOM_a = document.createElement("a"); - DOM_a.appendChild(document.createTextNode(t.headingText)); - DOM_a.href = "javascript:void(null);"; - DOM_a.title = t.headingText; - DOM_a.onclick = this.navClick; - - /* Add some properties to the link so we can identify which tab - was clicked. Later the navClick method will need this. - */ - DOM_a.tabber = this; - DOM_a.tabberIndex = i; - - /* Do we need to add an id to DOM_a? */ - if (this.addLinkId && this.linkIdFormat) { - - /* Determine the id name */ - aId = this.linkIdFormat; - aId = aId.replace(//gi, this.id); - aId = aId.replace(//gi, i); - aId = aId.replace(//gi, i+1); - aId = aId.replace(//gi, t.headingText.replace(/[^a-zA-Z0-9\-]/gi, '')); - - DOM_a.id = aId; - } - - /* Add the link to the list element */ - DOM_li.appendChild(DOM_a); - - /* Add the list element to the list */ - DOM_ul.appendChild(DOM_li); - } - - /* Add the UL list to the beginning of the tabber div */ - e.insertBefore(DOM_ul, e.firstChild); - - /* Make the tabber div "live" so different CSS can be applied */ - e.className = e.className.replace(this.REclassMain, this.classMainLive); - - /* Activate the default tab, and do not call the onclick handler */ - this.tabShow(defaultTab); - - /* If the user specified an onLoad function, call it now. */ - if (typeof this.onLoad == 'function') { - this.onLoad({tabber:this}); - } - - return this; -}; - - -tabberObj.prototype.navClick = function(event) -{ - /* This method should only be called by the onClick event of an - element, in which case we will determine which tab was clicked by - examining a property that we previously attached to the - element. - - Since this was triggered from an onClick event, the variable - "this" refers to the element that triggered the onClick - event (and not to the tabberObj). - - When tabberObj was initialized, we added some extra properties - to the element, for the purpose of retrieving them now. Get - the tabberObj object, plus the tab number that was clicked. - */ - - var - rVal, /* Return value from the user onclick function */ - a, /* element that triggered the onclick event */ - self, /* the tabber object */ - tabberIndex, /* index of the tab that triggered the event */ - onClickArgs; /* args to send the onclick function */ - - a = this; - if (!a.tabber) { return false; } - - self = a.tabber; - tabberIndex = a.tabberIndex; - - /* Remove focus from the link because it looks ugly. - I don't know if this is a good idea... - */ - a.blur(); - - /* If the user specified an onClick function, call it now. - If the function returns false then do not continue. - */ - if (typeof self.onClick == 'function') { - - onClickArgs = {'tabber':self, 'index':tabberIndex, 'event':event}; - - /* IE uses a different way to access the event object */ - if (!event) { onClickArgs.event = window.event; } - - rVal = self.onClick(onClickArgs); - if (rVal === false) { return false; } - } - - self.tabShow(tabberIndex); - - return false; -}; - - -tabberObj.prototype.tabHideAll = function() -{ - var i; /* counter */ - - /* Hide all tabs and make all navigation links inactive */ - for (i = 0; i < this.tabs.length; i++) { - this.tabHide(i); - } -}; - - -tabberObj.prototype.tabHide = function(tabberIndex) -{ - var div; - - if (!this.tabs[tabberIndex]) { return false; } - - /* Hide a single tab and make its navigation link inactive */ - div = this.tabs[tabberIndex].div; - - /* Hide the tab contents by adding classTabHide to the div */ - if (!div.className.match(this.REclassTabHide)) { - div.className += ' ' + this.classTabHide; - } - this.navClearActive(tabberIndex); - - return this; -}; - - -tabberObj.prototype.tabShow = function(tabberIndex) -{ - /* Show the tabberIndex tab and hide all the other tabs */ - - var div; - - if (!this.tabs[tabberIndex]) { return false; } - - /* Hide all the tabs first */ - this.tabHideAll(); - - /* Get the div that holds this tab */ - div = this.tabs[tabberIndex].div; - - /* Remove classTabHide from the div */ - div.className = div.className.replace(this.REclassTabHide, ''); - - /* Mark this tab navigation link as "active" */ - this.navSetActive(tabberIndex); - - /* If the user specified an onTabDisplay function, call it now. */ - if (typeof this.onTabDisplay == 'function') { - this.onTabDisplay({'tabber':this, 'index':tabberIndex}); - } - - return this; -}; - -tabberObj.prototype.navSetActive = function(tabberIndex) -{ - /* Note: this method does *not* enforce the rule - that only one nav item can be active at a time. - */ - - /* Set classNavActive for the navigation list item */ - this.tabs[tabberIndex].li.className = this.classNavActive; - - return this; -}; - - -tabberObj.prototype.navClearActive = function(tabberIndex) -{ - /* Note: this method does *not* enforce the rule - that one nav should always be active. - */ - - /* Remove classNavActive from the navigation list item */ - this.tabs[tabberIndex].li.className = ''; - - return this; -}; - - -/*==================================================*/ - - -function tabberAutomatic(tabberArgs) -{ - /* This function finds all DIV elements in the document where - class=tabber.classMain, then converts them to use the tabber - interface. - - tabberArgs = an object to send to "new tabber()" - */ - var - tempObj, /* Temporary tabber object */ - divs, /* Array of all divs on the page */ - i; /* Loop index */ - - if (!tabberArgs) { tabberArgs = {}; } - - /* Create a tabber object so we can get the value of classMain */ - tempObj = new tabberObj(tabberArgs); - - /* Find all DIV elements in the document that have class=tabber */ - - /* First get an array of all DIV elements and loop through them */ - divs = document.getElementsByTagName("div"); - for (i=0; i < divs.length; i++) { - - /* Is this DIV the correct class? */ - if (divs[i].className && - divs[i].className.match(tempObj.REclassMain)) { - - /* Now tabify the DIV */ - tabberArgs.div = divs[i]; - divs[i].tabber = new tabberObj(tabberArgs); - } - } - - return this; -} - - -/*==================================================*/ - - -function tabberAutomaticOnLoad(tabberArgs) -{ - /* This function adds tabberAutomatic to the window.onload event, - so it will run after the document has finished loading. - */ - var oldOnLoad; - - if (!tabberArgs) { tabberArgs = {}; } - - /* Taken from: http://simon.incutio.com/archive/2004/05/26/addLoadEvent */ - - oldOnLoad = window.onload; - if (typeof window.onload != 'function') { - window.onload = function() { - tabberAutomatic(tabberArgs); - - }; - } else { - window.onload = function() { - oldOnLoad(); - tabberAutomatic(tabberArgs); - - }; - } -} - - -/*==================================================*/ -function init_tabs(){ - if (typeof tabberOptions == 'undefined') { - tabberAutomatic({}); - } - else - {if (!tabberOptions['manualStartup']) { - tabberAutomatic(tabberOptions); - } - } -} - -function init_autotabber(){ -/* Run tabberAutomaticOnload() unless the "manualStartup" option was specified */ - - if (typeof tabberOptions == 'undefined') { - - tabberAutomaticOnLoad(); - - } else { - - if (!tabberOptions['manualStartup']) { - tabberAutomaticOnLoad(tabberOptions); - } - - } +/*================================================== + $Id: tabber.js,v 1.9 2006/04/27 20:51:51 pat Exp $ + tabber.js by Patrick Fitzgerald pat@barelyfitz.com + + Documentation can be found at the following URL: + http://www.barelyfitz.com/projects/tabber/ + + License (http://www.opensource.org/licenses/mit-license.php) + + Copyright (c) 2006 Patrick Fitzgerald + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + ==================================================*/ + +function tabberObj(argsObj) +{ + var arg; /* name of an argument to override */ + + /* Element for the main tabber div. If you supply this in argsObj, + then the init() method will be called. + */ + this.div = null; + + /* Class of the main tabber div */ + this.classMain = "tabber"; + + /* Rename classMain to classMainLive after tabifying + (so a different style can be applied) + */ + this.classMainLive = "tabberlive"; + + /* Class of each DIV that contains a tab */ + this.classTab = "tabbertab"; + + /* Class to indicate which tab should be active on startup */ + this.classTabDefault = "tabbertabdefault"; + + /* Class for the navigation UL */ + this.classNav = "tabbernav"; + + /* When a tab is to be hidden, instead of setting display='none', we + set the class of the div to classTabHide. In your screen + stylesheet you should set classTabHide to display:none. In your + print stylesheet you should set display:block to ensure that all + the information is printed. + */ + this.classTabHide = "tabbertabhide"; + + /* Class to set the navigation LI when the tab is active, so you can + use a different style on the active tab. + */ + this.classNavActive = "tabberactive"; + + /* Elements that might contain the title for the tab, only used if a + title is not specified in the TITLE attribute of DIV classTab. + */ + this.titleElements = ['h2','h3','h4','h5','h6']; + + /* Should we strip out the HTML from the innerHTML of the title elements? + This should usually be true. + */ + this.titleElementsStripHTML = true; + + /* If the user specified the tab names using a TITLE attribute on + the DIV, then the browser will display a tooltip whenever the + mouse is over the DIV. To prevent this tooltip, we can remove the + TITLE attribute after getting the tab name. + */ + this.removeTitle = true; + + /* If you want to add an id to each link set this to true */ + this.addLinkId = false; + + /* If addIds==true, then you can set a format for the ids. + will be replaced with the id of the main tabber div. + will be replaced with the tab number + (tab numbers starting at zero) + will be replaced with the tab number + (tab numbers starting at one) + will be replaced by the tab title + (with all non-alphanumeric characters removed) + */ + this.linkIdFormat = 'nav'; + + /* You can override the defaults listed above by passing in an object: + var mytab = new tabber({property:value,property:value}); + */ + for (arg in argsObj) { this[arg] = argsObj[arg]; } + + /* Create regular expressions for the class names; Note: if you + change the class names after a new object is created you must + also change these regular expressions. + */ + this.REclassMain = new RegExp('\\b' + this.classMain + '\\b', 'gi'); + this.REclassMainLive = new RegExp('\\b' + this.classMainLive + '\\b', 'gi'); + this.REclassTab = new RegExp('\\b' + this.classTab + '\\b', 'gi'); + this.REclassTabDefault = new RegExp('\\b' + this.classTabDefault + '\\b', 'gi'); + this.REclassTabHide = new RegExp('\\b' + this.classTabHide + '\\b', 'gi'); + + /* Array of objects holding info about each tab */ + this.tabs = new Array(); + + /* If the main tabber div was specified, call init() now */ + if (this.div) { + + this.init(this.div); + + /* We don't need the main div anymore, and to prevent a memory leak + in IE, we must remove the circular reference between the div + and the tabber object. */ + this.div = null; + } +} + + +/*-------------------------------------------------- + Methods for tabberObj + --------------------------------------------------*/ + + +tabberObj.prototype.init = function(e) +{ + /* Set up the tabber interface. + + e = element (the main containing div) + + Example: + init(document.getElementById('mytabberdiv')) + */ + + var + childNodes, /* child nodes of the tabber div */ + i, i2, /* loop indices */ + t, /* object to store info about a single tab */ + defaultTab=0, /* which tab to select by default */ + DOM_ul, /* tabbernav list */ + DOM_li, /* tabbernav list item */ + DOM_a, /* tabbernav link */ + aId, /* A unique id for DOM_a */ + headingElement; /* searching for text to use in the tab */ + + /* Verify that the browser supports DOM scripting */ + if (!document.getElementsByTagName) { return false; } + + /* If the main DIV has an ID then save it. */ + if (e.id) { + this.id = e.id; + } + + /* Clear the tabs array (but it should normally be empty) */ + this.tabs.length = 0; + + /* Loop through an array of all the child nodes within our tabber element. */ + childNodes = e.childNodes; + for(i=0; i < childNodes.length; i++) { + + /* Find the nodes where class="tabbertab" */ + if(childNodes[i].className && + childNodes[i].className.match(this.REclassTab)) { + + /* Create a new object to save info about this tab */ + t = new Object(); + + /* Save a pointer to the div for this tab */ + t.div = childNodes[i]; + + /* Add the new object to the array of tabs */ + this.tabs[this.tabs.length] = t; + + /* If the class name contains classTabDefault, + then select this tab by default. + */ + if (childNodes[i].className.match(this.REclassTabDefault)) { + defaultTab = this.tabs.length-1; + } + } + } + + /* Create a new UL list to hold the tab headings */ + DOM_ul = document.createElement("ul"); + DOM_ul.className = this.classNav; + + /* Loop through each tab we found */ + for (i=0; i < this.tabs.length; i++) { + + t = this.tabs[i]; + + /* Get the label to use for this tab: + From the title attribute on the DIV, + Or from one of the this.titleElements[] elements, + Or use an automatically generated number. + */ + t.headingText = t.div.title; + + /* Remove the title attribute to prevent a tooltip from appearing */ + if (this.removeTitle) { t.div.title = ''; } + + if (!t.headingText) { + + /* Title was not defined in the title of the DIV, + So try to get the title from an element within the DIV. + Go through the list of elements in this.titleElements + (typically heading elements ['h2','h3','h4']) + */ + for (i2=0; i2/gi," "); + t.headingText = t.headingText.replace(/<[^>]+>/g,""); + } + break; + } + } + } + + if (!t.headingText) { + /* Title was not found (or is blank) so automatically generate a + number for the tab. + */ + t.headingText = i + 1; + } + + /* Create a list element for the tab */ + DOM_li = document.createElement("li"); + + /* Save a reference to this list item so we can later change it to + the "active" class */ + t.li = DOM_li; + + /* Create a link to activate the tab */ + DOM_a = document.createElement("a"); + DOM_a.appendChild(document.createTextNode(t.headingText)); + DOM_a.href = "javascript:void(null);"; + DOM_a.title = t.headingText; + DOM_a.onclick = this.navClick; + + /* Add some properties to the link so we can identify which tab + was clicked. Later the navClick method will need this. + */ + DOM_a.tabber = this; + DOM_a.tabberIndex = i; + + /* Do we need to add an id to DOM_a? */ + if (this.addLinkId && this.linkIdFormat) { + + /* Determine the id name */ + aId = this.linkIdFormat; + aId = aId.replace(//gi, this.id); + aId = aId.replace(//gi, i); + aId = aId.replace(//gi, i+1); + aId = aId.replace(//gi, t.headingText.replace(/[^a-zA-Z0-9\-]/gi, '')); + + DOM_a.id = aId; + } + + /* Add the link to the list element */ + DOM_li.appendChild(DOM_a); + + /* Add the list element to the list */ + DOM_ul.appendChild(DOM_li); + } + + /* Add the UL list to the beginning of the tabber div */ + e.insertBefore(DOM_ul, e.firstChild); + + /* Make the tabber div "live" so different CSS can be applied */ + e.className = e.className.replace(this.REclassMain, this.classMainLive); + + /* Activate the default tab, and do not call the onclick handler */ + this.tabShow(defaultTab); + + /* If the user specified an onLoad function, call it now. */ + if (typeof this.onLoad == 'function') { + this.onLoad({tabber:this}); + } + + return this; +}; + + +tabberObj.prototype.navClick = function(event) +{ + /* This method should only be called by the onClick event of an + element, in which case we will determine which tab was clicked by + examining a property that we previously attached to the + element. + + Since this was triggered from an onClick event, the variable + "this" refers to the element that triggered the onClick + event (and not to the tabberObj). + + When tabberObj was initialized, we added some extra properties + to the element, for the purpose of retrieving them now. Get + the tabberObj object, plus the tab number that was clicked. + */ + + var + rVal, /* Return value from the user onclick function */ + a, /* element that triggered the onclick event */ + self, /* the tabber object */ + tabberIndex, /* index of the tab that triggered the event */ + onClickArgs; /* args to send the onclick function */ + + a = this; + if (!a.tabber) { return false; } + + self = a.tabber; + tabberIndex = a.tabberIndex; + + /* Remove focus from the link because it looks ugly. + I don't know if this is a good idea... + */ + a.blur(); + + /* If the user specified an onClick function, call it now. + If the function returns false then do not continue. + */ + if (typeof self.onClick == 'function') { + + onClickArgs = {'tabber':self, 'index':tabberIndex, 'event':event}; + + /* IE uses a different way to access the event object */ + if (!event) { onClickArgs.event = window.event; } + + rVal = self.onClick(onClickArgs); + if (rVal === false) { return false; } + } + + self.tabShow(tabberIndex); + + return false; +}; + + +tabberObj.prototype.tabHideAll = function() +{ + var i; /* counter */ + + /* Hide all tabs and make all navigation links inactive */ + for (i = 0; i < this.tabs.length; i++) { + this.tabHide(i); + } +}; + + +tabberObj.prototype.tabHide = function(tabberIndex) +{ + var div; + + if (!this.tabs[tabberIndex]) { return false; } + + /* Hide a single tab and make its navigation link inactive */ + div = this.tabs[tabberIndex].div; + + /* Hide the tab contents by adding classTabHide to the div */ + if (!div.className.match(this.REclassTabHide)) { + div.className += ' ' + this.classTabHide; + } + this.navClearActive(tabberIndex); + + return this; +}; + + +tabberObj.prototype.tabShow = function(tabberIndex) +{ + /* Show the tabberIndex tab and hide all the other tabs */ + + var div; + + if (!this.tabs[tabberIndex]) { return false; } + + /* Hide all the tabs first */ + this.tabHideAll(); + + /* Get the div that holds this tab */ + div = this.tabs[tabberIndex].div; + + /* Remove classTabHide from the div */ + div.className = div.className.replace(this.REclassTabHide, ''); + + /* Mark this tab navigation link as "active" */ + this.navSetActive(tabberIndex); + + /* If the user specified an onTabDisplay function, call it now. */ + if (typeof this.onTabDisplay == 'function') { + this.onTabDisplay({'tabber':this, 'index':tabberIndex}); + } + + return this; +}; + +tabberObj.prototype.navSetActive = function(tabberIndex) +{ + /* Note: this method does *not* enforce the rule + that only one nav item can be active at a time. + */ + + /* Set classNavActive for the navigation list item */ + this.tabs[tabberIndex].li.className = this.classNavActive; + + return this; +}; + + +tabberObj.prototype.navClearActive = function(tabberIndex) +{ + /* Note: this method does *not* enforce the rule + that one nav should always be active. + */ + + /* Remove classNavActive from the navigation list item */ + this.tabs[tabberIndex].li.className = ''; + + return this; +}; + + +/*==================================================*/ + + +function tabberAutomatic(tabberArgs) +{ + /* This function finds all DIV elements in the document where + class=tabber.classMain, then converts them to use the tabber + interface. + + tabberArgs = an object to send to "new tabber()" + */ + var + tempObj, /* Temporary tabber object */ + divs, /* Array of all divs on the page */ + i; /* Loop index */ + + if (!tabberArgs) { tabberArgs = {}; } + + /* Create a tabber object so we can get the value of classMain */ + tempObj = new tabberObj(tabberArgs); + + /* Find all DIV elements in the document that have class=tabber */ + + /* First get an array of all DIV elements and loop through them */ + divs = document.getElementsByTagName("div"); + for (i=0; i < divs.length; i++) { + + /* Is this DIV the correct class? */ + if (divs[i].className && + divs[i].className.match(tempObj.REclassMain)) { + + /* Now tabify the DIV */ + tabberArgs.div = divs[i]; + divs[i].tabber = new tabberObj(tabberArgs); + } + } + + return this; +} + + +/*==================================================*/ + + +function tabberAutomaticOnLoad(tabberArgs) +{ + /* This function adds tabberAutomatic to the window.onload event, + so it will run after the document has finished loading. + */ + var oldOnLoad; + + if (!tabberArgs) { tabberArgs = {}; } + + /* Taken from: http://simon.incutio.com/archive/2004/05/26/addLoadEvent */ + + oldOnLoad = window.onload; + if (typeof window.onload != 'function') { + window.onload = function() { + tabberAutomatic(tabberArgs); + + }; + } else { + window.onload = function() { + oldOnLoad(); + tabberAutomatic(tabberArgs); + + }; + } +} + + +/*==================================================*/ +function init_tabs(){ + if (typeof tabberOptions == 'undefined') { + tabberAutomatic({}); + } + else + {if (!tabberOptions['manualStartup']) { + tabberAutomatic(tabberOptions); + } + } +} + +function init_autotabber(){ +/* Run tabberAutomaticOnload() unless the "manualStartup" option was specified */ + + if (typeof tabberOptions == 'undefined') { + + tabberAutomaticOnLoad(); + + } else { + + if (!tabberOptions['manualStartup']) { + tabberAutomaticOnLoad(tabberOptions); + } + + } } \ No newline at end of file diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/client/PushletClient.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/client/PushletClient.java index f2dc390f26..e1c77ebcfa 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/client/PushletClient.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/client/PushletClient.java @@ -1,699 +1,699 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.client; - -import nl.justobjects.pushlet.core.Event; -import nl.justobjects.pushlet.core.EventParser; -import nl.justobjects.pushlet.core.Protocol; -import nl.justobjects.pushlet.util.PushletException; - -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Reader; -import java.io.OutputStream; -import java.net.*; -import java.util.Map; - -/** - * Client API for Java HTTP client applets or apps. - *

- * Use this class within Java client applications or applets. - * Implement a PushletClientListener to receive callbacks for - * data-related Event objects pushed by the server. - *

- * This class may also be used as a base class and be extended - * for custom clients, hence the presence of many proteced methods. - * - * @author Just van den Broecke - Just Objects © - * @version $Id: PushletClient.java,v 1.19 2009/06/04 12:46:35 justb Exp $ - * @see PushletClientListener - * @see nl.justobjects.pushlet.test.PushletApplet - * @see nl.justobjects.pushlet.test.PushletPingApplication - */ -public class PushletClient implements Protocol { - /** - * Pushlet URL. - */ - private String pushletURL; - - /** - * Debug flag for verbose output. - */ - private boolean debug; - - /** - * Id gotten on join ack - */ - private String id; - - /** - * Internal listener for data events pushed by server. - */ - protected DataEventListener dataEventListener; - - /** - * Constructor with full pushlet URL. - */ - public PushletClient(String aPushletURL) { - pushletURL = aPushletURL; - } - - /** - * Constructor with host and port using default URI. - */ - public PushletClient(String aHost, int aPort) { - this("http://" + aHost + ":" + aPort + DEFAULT_SERVLET_URI); - } - - /** - * Set proxy options and optional proxy authentication. - *

- * Contributed by Dele Olajide - * See http://groups.yahoo.com/group/pushlet/message/634 - *

- * Usage: - * PushletClient pushletClient = new PushletClient("http:://www.domain.com/pushlet"); - * pushletClient.setProxyOptions("proxy.bla.com", "8080", ....); - *

- * use pushletClient further as normal - */ - public void setProxyOptions(String aProxyHost, - String aProxyPort, String theNonProxyHosts, - String aUserName, String aPassword, String anNTLMDomain) { - - // Enable proxying - System.setProperty("http.proxySet", "true"); - System.setProperty("http.proxyHost", aProxyHost); - System.setProperty("http.proxyPort", aProxyPort); - - // Set optional non-proxy hosts - if (theNonProxyHosts != null) { - System.setProperty("http.nonProxyHosts", theNonProxyHosts); - } - - // If user name specified configure proxy authentication - if (aUserName != null) { - System.setProperty("http.proxyUser", aUserName); - System.setProperty("http.proxyPassword", aPassword); - - // See inner class below - Authenticator.setDefault(new HTTPAuthenticateProxy(aUserName, aPassword)); - - // Optional NT domain - if (anNTLMDomain != null) { - System.setProperty("http.auth.ntlm.domain", anNTLMDomain); - } - } - } - - /** - * Join server, starts session. - */ - public void join() throws PushletException { - Event event = new Event(E_JOIN); - event.setField(P_FORMAT, FORMAT_XML); - Event response = doControl(event); - throwOnNack(response); - - // Join Ack received - id = response.getField(P_ID); - } - - /** - * Leave server, stops session. - */ - public void leave() throws PushletException { - stopListen(); - throwOnInvalidSession(); - Event event = new Event(E_LEAVE); - event.setField(P_ID, id); - Event response = doControl(event); - - throwOnNack(response); - id = null; - } - - /** - * Open data channel. - */ - public void listen(PushletClientListener aListener) throws PushletException { - listen(aListener, MODE_STREAM); - } - - /** - * Open data channel in stream or push mode. - */ - public void listen(PushletClientListener aListener, String aMode) throws PushletException { - listen(aListener, aMode, null); - } - - /** - * Open data channel in stream or push mode with a subject. - */ - public void listen(PushletClientListener aListener, String aMode, String aSubject) throws PushletException { - throwOnInvalidSession(); - stopListen(); - - String listenURL = pushletURL - + "?" + P_EVENT + "=" + E_LISTEN - + "&" + P_ID + "=" + id - + "&" + P_MODE + "=" + aMode; - if (aSubject != null) { - listenURL = listenURL + "&" + P_SUBJECT + "=" + aSubject; - } - - // Start listener thread (sync call). - startDataEventListener(aListener, listenURL); - } - - /** - * Immediate listener: joins/subscribes and listens in one action. - */ - public void joinListen(PushletClientListener aListener, String aMode, String aSubject) throws PushletException { - stopListen(); - - String listenURL = pushletURL - + "?" + P_EVENT + "=" + E_JOIN_LISTEN - + "&" + P_FORMAT + "=" + FORMAT_XML - + "&" + P_MODE + "=" + aMode - + "&" + P_SUBJECT + "=" + aSubject; - - // Start listener thread (sync call). - startDataEventListener(aListener, listenURL); - } - - /** - * Publish an event through server. - */ - public void publish(String aSubject, Map theAttributes) throws PushletException { - throwOnInvalidSession(); - Event event = new Event(E_PUBLISH, theAttributes); - event.setField(P_SUBJECT, aSubject); - event.setField(P_ID, id); - Event response = doControl(event); - throwOnNack(response); - } - - /** - * Subscribes, returning subscription id. - */ - public String subscribe(String aSubject, String aLabel) throws PushletException { - throwOnInvalidSession(); - Event event = new Event(E_SUBSCRIBE); - event.setField(P_ID, id); - event.setField(P_SUBJECT, aSubject); - - // Optional label, is returned in data events - if (aLabel != null) { - event.setField(P_SUBSCRIPTION_LABEL, aLabel); - } - - // Send request - Event response = doControl(event); - throwOnNack(response); - - return response.getField(P_SUBSCRIPTION_ID); - } - - /** - * Subscribes, returning subscription id. - */ - public String subscribe(String aSubject) throws PushletException { - return subscribe(aSubject, null); - } - - /** - * Unsubscribes with subscription id. - */ - public void unsubscribe(String aSubscriptionId) throws PushletException { - throwOnInvalidSession(); - Event event = new Event(E_UNSUBSCRIBE); - event.setField(P_ID, id); - - // Optional subscription id - if (aSubscriptionId != null) { - event.setField(P_SUBSCRIPTION_ID, aSubscriptionId); - } - - Event response = doControl(event); - throwOnNack(response); - } - - /** - * Unsubscribes from all subjects. - */ - public void unsubscribe() throws PushletException { - unsubscribe(null); - } - - /** - * Stop the listener. - */ - public void stopListen() throws PushletException { - if (dataEventListener != null) { - unsubscribe(); - dataEventListener.stop(); - dataEventListener = null; - } - } - - public void setDebug(boolean b) { - debug = b; - } - - /** - * Starts default DataEventListener and waits for its thread to start. - */ - protected void startDataEventListener(PushletClientListener aListener, String aListenURL) { - // Suggestion by Jeff Nowakowski 29.oct.2006 - dataEventListener = new DataEventListener(aListener, aListenURL); - - synchronized (dataEventListener) { - dataEventListener.start(); - try { - // Wait for data event listener (thread) to start - dataEventListener.wait(); - } catch (InterruptedException e) { - } - } - } - - protected void throwOnNack(Event anEvent) throws PushletException { - if (anEvent.getEventType().equals(E_NACK)) { - throw new PushletException("Negative response: reason=" + anEvent.getField(P_REASON)); - } - } - - protected void throwOnInvalidSession() throws PushletException { - if (id == null) { - throw new PushletException("Invalid pushlet session"); - } - } - - protected Reader openURL(String aURL) throws PushletException { - // Open URL connection with server - try { - p("Connecting to " + aURL); - URL url = new URL(aURL); - URLConnection urlConnection = url.openConnection(); - - // Disable any kind of caching. - urlConnection.setUseCaches(false); - urlConnection.setDefaultUseCaches(false); - - // TODO: later version may use POST - // Enable HTTP POST - // urlConnection.setDoOutput(true); - - // Do the POST with Event in XML in body - // OutputStream os = urlConnection.getOutputStream(); - // os.write(anEvent.toXML().getBytes()); - // os.flush(); - // os.close(); - - // Get the stream from the server. - // reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); - // Note: somehow the client does not work with some JVMs when using - // BufferedInputStream... So do unbuffered input. - // p("Opening urlConnection inputstream"); - return new InputStreamReader(urlConnection.getInputStream()); - - } catch (Throwable t) { - warn("openURL() could not open " + aURL, t); - throw new PushletException(" could not open " + aURL, t); - } - } - - - /** - * Send control events to server and return response. - */ - protected Event doControl(Event aControlEvent) throws PushletException { - String controlURL = pushletURL + "?" + aControlEvent.toQueryString(); - - p("doControl to " + controlURL); - - // Open URL connection with server - Reader reader = openURL(controlURL); - - // Get Pushlet event from stream - Event event = null; - try { - p("Getting event..."); - // Get next event from server - event = EventParser.parse(reader); - p("Event received " + event); - return event; - } catch (Throwable t) { - // Stop and report error. - warn("doControl() exception", t); - throw new PushletException(" error parsing response from" + controlURL, t); - } - } - - /** - * Util: print. - */ - protected void p(String s) { - if (debug) { - System.out.println("[PushletClient] " + s); - } - } - - /** - * Util: warn. - */ - protected void warn(String s) { - warn(s, null); - } - - /** - * Util: warn with exception. - */ - protected void warn(String s, Throwable t) { - System.err.println("[PushletClient] - WARN - " + s + " ex=" + t); - - if (t != null) { - t.printStackTrace(); - } - } - - /** - * Internal (default) listener for the Pushlet data channel. - */ - protected class DataEventListener implements Runnable { - /** - * Client's listener that gets called back on events. - */ - private PushletClientListener listener; - - /** - * Receiver receiveThread. - */ - private Thread receiveThread = null; - private Reader reader; - private String refreshURL; - private String listenURL; - - public DataEventListener(PushletClientListener aListener, String aListenURL) { - listener = aListener; - listenURL = aListenURL; - } - - public void start() { - // All ok: start a receiver receiveThread - receiveThread = new Thread(this); - receiveThread.start(); - - } - - /** - * Stop listening; may restart later with start(). - */ - public void stop() { - p("In stop()"); - bailout(); - } - - /** - * Receive event objects from server and callback listener. - */ - public void run() { - p("Start run()"); - try { - while (receiveThread != null && receiveThread.isAlive()) { - // Connect to server - reader = openURL(listenURL); - - synchronized (this) { - // Inform the calling thread we're ready to receive events. - // Suggestion by Jeff Nowakowski 29.oct.2006 - this.notify(); - } - - // Get events while we're alive. - while (receiveThread != null && receiveThread.isAlive()) { - Event event = null; - try { - // p("Getting event..."); - // Get next event from server - event = EventParser.parse(reader); - p("Event received " + event); - } catch (Throwable t) { - - // Stop and report error. - // warn("Stop run() on exception", t); - if (listener != null) { - listener.onError("exception during receive: " + t); - } - - break; - } - - // Handle event by calling listener - if (event != null && listener != null) { - // p("received: " + event.toXML()); - String eventType = event.getEventType(); - if (eventType.equals(E_HEARTBEAT)) { - listener.onHeartbeat(event); - } else if (eventType.equals(E_DATA)) { - listener.onData(event); - } else if (eventType.equals(E_JOIN_LISTEN_ACK)) { - id = event.getField(P_ID); - } else if (eventType.equals(E_LISTEN_ACK)) { - p("Listen ack ok"); - } else if (eventType.equals(E_REFRESH_ACK)) { - // ignore - } else if (eventType.equals(E_ABORT)) { - listener.onAbort(event); - listener = null; - break; - } else if (eventType.equals(E_REFRESH)) { - refresh(event); - } else { - handleUnknownEventType(eventType, event, listener); - } - } - } - } - } catch (Throwable t) { - warn("Exception in run() ", t); - // bailout(); - } - } - - protected void disconnect() { - p("start disconnect()"); - if (reader != null) { - try { - // this blocks, find another way - // reader.close(); - p("Closed reader ok"); - } catch (Exception ignore) { - } finally { - reader = null; - } - } - p("end disconnect()"); - } - - /** - * Stop receiver receiveThread. - */ - public void stopThread() { - p("In stopThread()"); - - // Keep a reference such that we can kill it from here. - Thread targetThread = receiveThread; - - receiveThread = null; - - // This should stop the main loop for this receiveThread. - // Killing a receiveThread on a blcing read is tricky. - // See also http://gee.cs.oswego.edu/dl/cpj/cancel.html - if ((targetThread != null) && targetThread.isAlive()) { - - targetThread.interrupt(); - - try { - - // Wait for it to die - targetThread.join(500); - } catch (InterruptedException ignore) { - } - - // If current receiveThread refuses to die, - // take more rigorous methods. - if (targetThread.isAlive()) { - - // Not preferred but may be needed - // to stop during a blocking read. - targetThread.stop(); - - // Wait for it to die - try { - targetThread.join(500); - } catch (Throwable ignore) { - } - } - - p("Stopped receiveThread alive=" + targetThread.isAlive()); - - } - } - - /** - * Stop listening on stream from server. - */ - public void bailout() { - p("In bailout()"); - stopThread(); - disconnect(); - } - - /** - * Handle refresh, by pausing. - */ - protected void refresh(Event aRefreshEvent) throws PushletException { - try { - // Wait for specified time. - Thread.sleep(Long.parseLong(aRefreshEvent.getField(P_WAIT))); - } catch (Throwable t) { - warn("abort while refresing"); - refreshURL = null; - return; - } - - // If stopped during sleep, don't proceed - if (receiveThread == null) { - return; - } - - // Create url to refresh - refreshURL = pushletURL - + "?" + P_ID + "=" + id - + "&" + P_EVENT + "=" + E_REFRESH - ; - - if (reader != null) { - try { - reader.close(); - - } catch (IOException ignore) { - - } - reader = null; - } - - reader = openURL(refreshURL); - } - - /** - * Handle unknown Event (default behaviour). - */ - protected void handleUnknownEventType(String eventType, Event event, PushletClientListener listener) { - warn("unsupported event type received: " + eventType); - } - } - - /** - * Authenticator - */ - private static class HTTPAuthenticateProxy extends Authenticator { - - /** - * Contributed by Dele Olajide - * See http://groups.yahoo.com/group/pushlet/message/634 - */ - - private String thePassword = ""; - private String theUser = ""; - - public HTTPAuthenticateProxy(String username, String password) { - - thePassword = password; - theUser = username; - } - - protected PasswordAuthentication getPasswordAuthentication() { - // System.out.println("[HttpAuthenticateProxy] Username = " + theUser); - // System.out.println("[HttpAuthenticateProxy] Password = " + thePassword); - - return new PasswordAuthentication(theUser, thePassword.toCharArray()); - } - - } - -} - -/* - * $Log: PushletClient.java,v $ - * Revision 1.19 2009/06/04 12:46:35 justb - * PushletClient: add more hooks for extension (feat ID: 2799694 Craig M) - * - * Revision 1.18 2007/11/10 13:52:47 justb - * make startDataEventListener method protected to allow overriding - * - * Revision 1.17 2006/10/29 16:47:57 justb - * included patch from Jeff Nowakowski: wait until listener thread runs - * - * Revision 1.16 2005/05/06 20:08:20 justb - * client enhancements - * - * Revision 1.15 2005/03/27 17:42:27 justb - * enhancements - * - * Revision 1.14 2005/03/25 23:54:04 justb - * *** empty log message *** - * - * Revision 1.13 2005/02/28 16:59:40 justb - * fixes for leave and disconnect - * - * Revision 1.12 2005/02/28 15:57:54 justb - * added SimpleListener example - * - * Revision 1.11 2005/02/21 12:31:44 justb - * added proxy contribution from Dele Olajide - * - * Revision 1.10 2005/02/20 13:05:32 justb - * removed the Postlet (integrated in Pushlet protocol) - * - * Revision 1.9 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.8 2005/02/18 09:54:12 justb - * refactor: rename Publisher Dispatcher and single Subscriber class - * - * Revision 1.7 2005/02/15 15:46:30 justb - * client API improves - * - * Revision 1.6 2005/02/15 13:28:56 justb - * first quick rewrite adapt for v2 protocol - * - * Revision 1.5 2004/10/25 21:23:44 justb - * *** empty log message *** - * - * Revision 1.4 2004/10/24 13:52:51 justb - * small fixes in client lib - * - * Revision 1.3 2004/10/24 12:58:18 justb - * revised client and test classes for new protocol - * - * Revision 1.2 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.1 2004/03/10 20:14:17 justb - * renamed all *JavaPushletClient* to *PushletClient* - * - * Revision 1.10 2004/03/10 15:45:55 justb - * many cosmetic changes - * - * Revision 1.9 2003/08/17 20:30:20 justb - * cosmetic changes - * - * Revision 1.8 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.client; + +import nl.justobjects.pushlet.core.Event; +import nl.justobjects.pushlet.core.EventParser; +import nl.justobjects.pushlet.core.Protocol; +import nl.justobjects.pushlet.util.PushletException; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.OutputStream; +import java.net.*; +import java.util.Map; + +/** + * Client API for Java HTTP client applets or apps. + *

+ * Use this class within Java client applications or applets. + * Implement a PushletClientListener to receive callbacks for + * data-related Event objects pushed by the server. + *

+ * This class may also be used as a base class and be extended + * for custom clients, hence the presence of many proteced methods. + * + * @author Just van den Broecke - Just Objects © + * @version $Id: PushletClient.java,v 1.19 2009/06/04 12:46:35 justb Exp $ + * @see PushletClientListener + * @see nl.justobjects.pushlet.test.PushletApplet + * @see nl.justobjects.pushlet.test.PushletPingApplication + */ +public class PushletClient implements Protocol { + /** + * Pushlet URL. + */ + private String pushletURL; + + /** + * Debug flag for verbose output. + */ + private boolean debug; + + /** + * Id gotten on join ack + */ + private String id; + + /** + * Internal listener for data events pushed by server. + */ + protected DataEventListener dataEventListener; + + /** + * Constructor with full pushlet URL. + */ + public PushletClient(String aPushletURL) { + pushletURL = aPushletURL; + } + + /** + * Constructor with host and port using default URI. + */ + public PushletClient(String aHost, int aPort) { + this("http://" + aHost + ":" + aPort + DEFAULT_SERVLET_URI); + } + + /** + * Set proxy options and optional proxy authentication. + *

+ * Contributed by Dele Olajide + * See http://groups.yahoo.com/group/pushlet/message/634 + *

+ * Usage: + * PushletClient pushletClient = new PushletClient("http:://www.domain.com/pushlet"); + * pushletClient.setProxyOptions("proxy.bla.com", "8080", ....); + *

+ * use pushletClient further as normal + */ + public void setProxyOptions(String aProxyHost, + String aProxyPort, String theNonProxyHosts, + String aUserName, String aPassword, String anNTLMDomain) { + + // Enable proxying + System.setProperty("http.proxySet", "true"); + System.setProperty("http.proxyHost", aProxyHost); + System.setProperty("http.proxyPort", aProxyPort); + + // Set optional non-proxy hosts + if (theNonProxyHosts != null) { + System.setProperty("http.nonProxyHosts", theNonProxyHosts); + } + + // If user name specified configure proxy authentication + if (aUserName != null) { + System.setProperty("http.proxyUser", aUserName); + System.setProperty("http.proxyPassword", aPassword); + + // See inner class below + Authenticator.setDefault(new HTTPAuthenticateProxy(aUserName, aPassword)); + + // Optional NT domain + if (anNTLMDomain != null) { + System.setProperty("http.auth.ntlm.domain", anNTLMDomain); + } + } + } + + /** + * Join server, starts session. + */ + public void join() throws PushletException { + Event event = new Event(E_JOIN); + event.setField(P_FORMAT, FORMAT_XML); + Event response = doControl(event); + throwOnNack(response); + + // Join Ack received + id = response.getField(P_ID); + } + + /** + * Leave server, stops session. + */ + public void leave() throws PushletException { + stopListen(); + throwOnInvalidSession(); + Event event = new Event(E_LEAVE); + event.setField(P_ID, id); + Event response = doControl(event); + + throwOnNack(response); + id = null; + } + + /** + * Open data channel. + */ + public void listen(PushletClientListener aListener) throws PushletException { + listen(aListener, MODE_STREAM); + } + + /** + * Open data channel in stream or push mode. + */ + public void listen(PushletClientListener aListener, String aMode) throws PushletException { + listen(aListener, aMode, null); + } + + /** + * Open data channel in stream or push mode with a subject. + */ + public void listen(PushletClientListener aListener, String aMode, String aSubject) throws PushletException { + throwOnInvalidSession(); + stopListen(); + + String listenURL = pushletURL + + "?" + P_EVENT + "=" + E_LISTEN + + "&" + P_ID + "=" + id + + "&" + P_MODE + "=" + aMode; + if (aSubject != null) { + listenURL = listenURL + "&" + P_SUBJECT + "=" + aSubject; + } + + // Start listener thread (sync call). + startDataEventListener(aListener, listenURL); + } + + /** + * Immediate listener: joins/subscribes and listens in one action. + */ + public void joinListen(PushletClientListener aListener, String aMode, String aSubject) throws PushletException { + stopListen(); + + String listenURL = pushletURL + + "?" + P_EVENT + "=" + E_JOIN_LISTEN + + "&" + P_FORMAT + "=" + FORMAT_XML + + "&" + P_MODE + "=" + aMode + + "&" + P_SUBJECT + "=" + aSubject; + + // Start listener thread (sync call). + startDataEventListener(aListener, listenURL); + } + + /** + * Publish an event through server. + */ + public void publish(String aSubject, Map theAttributes) throws PushletException { + throwOnInvalidSession(); + Event event = new Event(E_PUBLISH, theAttributes); + event.setField(P_SUBJECT, aSubject); + event.setField(P_ID, id); + Event response = doControl(event); + throwOnNack(response); + } + + /** + * Subscribes, returning subscription id. + */ + public String subscribe(String aSubject, String aLabel) throws PushletException { + throwOnInvalidSession(); + Event event = new Event(E_SUBSCRIBE); + event.setField(P_ID, id); + event.setField(P_SUBJECT, aSubject); + + // Optional label, is returned in data events + if (aLabel != null) { + event.setField(P_SUBSCRIPTION_LABEL, aLabel); + } + + // Send request + Event response = doControl(event); + throwOnNack(response); + + return response.getField(P_SUBSCRIPTION_ID); + } + + /** + * Subscribes, returning subscription id. + */ + public String subscribe(String aSubject) throws PushletException { + return subscribe(aSubject, null); + } + + /** + * Unsubscribes with subscription id. + */ + public void unsubscribe(String aSubscriptionId) throws PushletException { + throwOnInvalidSession(); + Event event = new Event(E_UNSUBSCRIBE); + event.setField(P_ID, id); + + // Optional subscription id + if (aSubscriptionId != null) { + event.setField(P_SUBSCRIPTION_ID, aSubscriptionId); + } + + Event response = doControl(event); + throwOnNack(response); + } + + /** + * Unsubscribes from all subjects. + */ + public void unsubscribe() throws PushletException { + unsubscribe(null); + } + + /** + * Stop the listener. + */ + public void stopListen() throws PushletException { + if (dataEventListener != null) { + unsubscribe(); + dataEventListener.stop(); + dataEventListener = null; + } + } + + public void setDebug(boolean b) { + debug = b; + } + + /** + * Starts default DataEventListener and waits for its thread to start. + */ + protected void startDataEventListener(PushletClientListener aListener, String aListenURL) { + // Suggestion by Jeff Nowakowski 29.oct.2006 + dataEventListener = new DataEventListener(aListener, aListenURL); + + synchronized (dataEventListener) { + dataEventListener.start(); + try { + // Wait for data event listener (thread) to start + dataEventListener.wait(); + } catch (InterruptedException e) { + } + } + } + + protected void throwOnNack(Event anEvent) throws PushletException { + if (anEvent.getEventType().equals(E_NACK)) { + throw new PushletException("Negative response: reason=" + anEvent.getField(P_REASON)); + } + } + + protected void throwOnInvalidSession() throws PushletException { + if (id == null) { + throw new PushletException("Invalid pushlet session"); + } + } + + protected Reader openURL(String aURL) throws PushletException { + // Open URL connection with server + try { + p("Connecting to " + aURL); + URL url = new URL(aURL); + URLConnection urlConnection = url.openConnection(); + + // Disable any kind of caching. + urlConnection.setUseCaches(false); + urlConnection.setDefaultUseCaches(false); + + // TODO: later version may use POST + // Enable HTTP POST + // urlConnection.setDoOutput(true); + + // Do the POST with Event in XML in body + // OutputStream os = urlConnection.getOutputStream(); + // os.write(anEvent.toXML().getBytes()); + // os.flush(); + // os.close(); + + // Get the stream from the server. + // reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); + // Note: somehow the client does not work with some JVMs when using + // BufferedInputStream... So do unbuffered input. + // p("Opening urlConnection inputstream"); + return new InputStreamReader(urlConnection.getInputStream()); + + } catch (Throwable t) { + warn("openURL() could not open " + aURL, t); + throw new PushletException(" could not open " + aURL, t); + } + } + + + /** + * Send control events to server and return response. + */ + protected Event doControl(Event aControlEvent) throws PushletException { + String controlURL = pushletURL + "?" + aControlEvent.toQueryString(); + + p("doControl to " + controlURL); + + // Open URL connection with server + Reader reader = openURL(controlURL); + + // Get Pushlet event from stream + Event event = null; + try { + p("Getting event..."); + // Get next event from server + event = EventParser.parse(reader); + p("Event received " + event); + return event; + } catch (Throwable t) { + // Stop and report error. + warn("doControl() exception", t); + throw new PushletException(" error parsing response from" + controlURL, t); + } + } + + /** + * Util: print. + */ + protected void p(String s) { + if (debug) { + System.out.println("[PushletClient] " + s); + } + } + + /** + * Util: warn. + */ + protected void warn(String s) { + warn(s, null); + } + + /** + * Util: warn with exception. + */ + protected void warn(String s, Throwable t) { + System.err.println("[PushletClient] - WARN - " + s + " ex=" + t); + + if (t != null) { + t.printStackTrace(); + } + } + + /** + * Internal (default) listener for the Pushlet data channel. + */ + protected class DataEventListener implements Runnable { + /** + * Client's listener that gets called back on events. + */ + private PushletClientListener listener; + + /** + * Receiver receiveThread. + */ + private Thread receiveThread = null; + private Reader reader; + private String refreshURL; + private String listenURL; + + public DataEventListener(PushletClientListener aListener, String aListenURL) { + listener = aListener; + listenURL = aListenURL; + } + + public void start() { + // All ok: start a receiver receiveThread + receiveThread = new Thread(this); + receiveThread.start(); + + } + + /** + * Stop listening; may restart later with start(). + */ + public void stop() { + p("In stop()"); + bailout(); + } + + /** + * Receive event objects from server and callback listener. + */ + public void run() { + p("Start run()"); + try { + while (receiveThread != null && receiveThread.isAlive()) { + // Connect to server + reader = openURL(listenURL); + + synchronized (this) { + // Inform the calling thread we're ready to receive events. + // Suggestion by Jeff Nowakowski 29.oct.2006 + this.notify(); + } + + // Get events while we're alive. + while (receiveThread != null && receiveThread.isAlive()) { + Event event = null; + try { + // p("Getting event..."); + // Get next event from server + event = EventParser.parse(reader); + p("Event received " + event); + } catch (Throwable t) { + + // Stop and report error. + // warn("Stop run() on exception", t); + if (listener != null) { + listener.onError("exception during receive: " + t); + } + + break; + } + + // Handle event by calling listener + if (event != null && listener != null) { + // p("received: " + event.toXML()); + String eventType = event.getEventType(); + if (eventType.equals(E_HEARTBEAT)) { + listener.onHeartbeat(event); + } else if (eventType.equals(E_DATA)) { + listener.onData(event); + } else if (eventType.equals(E_JOIN_LISTEN_ACK)) { + id = event.getField(P_ID); + } else if (eventType.equals(E_LISTEN_ACK)) { + p("Listen ack ok"); + } else if (eventType.equals(E_REFRESH_ACK)) { + // ignore + } else if (eventType.equals(E_ABORT)) { + listener.onAbort(event); + listener = null; + break; + } else if (eventType.equals(E_REFRESH)) { + refresh(event); + } else { + handleUnknownEventType(eventType, event, listener); + } + } + } + } + } catch (Throwable t) { + warn("Exception in run() ", t); + // bailout(); + } + } + + protected void disconnect() { + p("start disconnect()"); + if (reader != null) { + try { + // this blocks, find another way + // reader.close(); + p("Closed reader ok"); + } catch (Exception ignore) { + } finally { + reader = null; + } + } + p("end disconnect()"); + } + + /** + * Stop receiver receiveThread. + */ + public void stopThread() { + p("In stopThread()"); + + // Keep a reference such that we can kill it from here. + Thread targetThread = receiveThread; + + receiveThread = null; + + // This should stop the main loop for this receiveThread. + // Killing a receiveThread on a blcing read is tricky. + // See also http://gee.cs.oswego.edu/dl/cpj/cancel.html + if ((targetThread != null) && targetThread.isAlive()) { + + targetThread.interrupt(); + + try { + + // Wait for it to die + targetThread.join(500); + } catch (InterruptedException ignore) { + } + + // If current receiveThread refuses to die, + // take more rigorous methods. + if (targetThread.isAlive()) { + + // Not preferred but may be needed + // to stop during a blocking read. + targetThread.stop(); + + // Wait for it to die + try { + targetThread.join(500); + } catch (Throwable ignore) { + } + } + + p("Stopped receiveThread alive=" + targetThread.isAlive()); + + } + } + + /** + * Stop listening on stream from server. + */ + public void bailout() { + p("In bailout()"); + stopThread(); + disconnect(); + } + + /** + * Handle refresh, by pausing. + */ + protected void refresh(Event aRefreshEvent) throws PushletException { + try { + // Wait for specified time. + Thread.sleep(Long.parseLong(aRefreshEvent.getField(P_WAIT))); + } catch (Throwable t) { + warn("abort while refresing"); + refreshURL = null; + return; + } + + // If stopped during sleep, don't proceed + if (receiveThread == null) { + return; + } + + // Create url to refresh + refreshURL = pushletURL + + "?" + P_ID + "=" + id + + "&" + P_EVENT + "=" + E_REFRESH + ; + + if (reader != null) { + try { + reader.close(); + + } catch (IOException ignore) { + + } + reader = null; + } + + reader = openURL(refreshURL); + } + + /** + * Handle unknown Event (default behaviour). + */ + protected void handleUnknownEventType(String eventType, Event event, PushletClientListener listener) { + warn("unsupported event type received: " + eventType); + } + } + + /** + * Authenticator + */ + private static class HTTPAuthenticateProxy extends Authenticator { + + /** + * Contributed by Dele Olajide + * See http://groups.yahoo.com/group/pushlet/message/634 + */ + + private String thePassword = ""; + private String theUser = ""; + + public HTTPAuthenticateProxy(String username, String password) { + + thePassword = password; + theUser = username; + } + + protected PasswordAuthentication getPasswordAuthentication() { + // System.out.println("[HttpAuthenticateProxy] Username = " + theUser); + // System.out.println("[HttpAuthenticateProxy] Password = " + thePassword); + + return new PasswordAuthentication(theUser, thePassword.toCharArray()); + } + + } + +} + +/* + * $Log: PushletClient.java,v $ + * Revision 1.19 2009/06/04 12:46:35 justb + * PushletClient: add more hooks for extension (feat ID: 2799694 Craig M) + * + * Revision 1.18 2007/11/10 13:52:47 justb + * make startDataEventListener method protected to allow overriding + * + * Revision 1.17 2006/10/29 16:47:57 justb + * included patch from Jeff Nowakowski: wait until listener thread runs + * + * Revision 1.16 2005/05/06 20:08:20 justb + * client enhancements + * + * Revision 1.15 2005/03/27 17:42:27 justb + * enhancements + * + * Revision 1.14 2005/03/25 23:54:04 justb + * *** empty log message *** + * + * Revision 1.13 2005/02/28 16:59:40 justb + * fixes for leave and disconnect + * + * Revision 1.12 2005/02/28 15:57:54 justb + * added SimpleListener example + * + * Revision 1.11 2005/02/21 12:31:44 justb + * added proxy contribution from Dele Olajide + * + * Revision 1.10 2005/02/20 13:05:32 justb + * removed the Postlet (integrated in Pushlet protocol) + * + * Revision 1.9 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.8 2005/02/18 09:54:12 justb + * refactor: rename Publisher Dispatcher and single Subscriber class + * + * Revision 1.7 2005/02/15 15:46:30 justb + * client API improves + * + * Revision 1.6 2005/02/15 13:28:56 justb + * first quick rewrite adapt for v2 protocol + * + * Revision 1.5 2004/10/25 21:23:44 justb + * *** empty log message *** + * + * Revision 1.4 2004/10/24 13:52:51 justb + * small fixes in client lib + * + * Revision 1.3 2004/10/24 12:58:18 justb + * revised client and test classes for new protocol + * + * Revision 1.2 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.1 2004/03/10 20:14:17 justb + * renamed all *JavaPushletClient* to *PushletClient* + * + * Revision 1.10 2004/03/10 15:45:55 justb + * many cosmetic changes + * + * Revision 1.9 2003/08/17 20:30:20 justb + * cosmetic changes + * + * Revision 1.8 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * */ \ No newline at end of file diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/client/PushletClientListener.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/client/PushletClientListener.java index 74cee7b2b2..864e2ef7dd 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/client/PushletClientListener.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/client/PushletClientListener.java @@ -1,50 +1,50 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.client; - -import nl.justobjects.pushlet.core.Event; -import nl.justobjects.pushlet.core.Protocol; - -/** - * Interface for listener of the PushletClient object. - * - * @version $Id: PushletClientListener.java,v 1.5 2005/02/21 11:50:37 justb Exp $ - * @author Just van den Broecke - Just Objects © - **/ -public interface PushletClientListener extends Protocol { - /** Abort event from server. */ - public void onAbort(Event theEvent); - - /** Data event from server. */ - public void onData(Event theEvent); - - /** Heartbeat event from server. */ - public void onHeartbeat(Event theEvent); - - /** Error occurred. */ - public void onError(String message); -} - -/* +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.client; + +import nl.justobjects.pushlet.core.Event; +import nl.justobjects.pushlet.core.Protocol; + +/** + * Interface for listener of the PushletClient object. + * + * @version $Id: PushletClientListener.java,v 1.5 2005/02/21 11:50:37 justb Exp $ + * @author Just van den Broecke - Just Objects © + **/ +public interface PushletClientListener extends Protocol { + /** Abort event from server. */ + public void onAbort(Event theEvent); + + /** Data event from server. */ + public void onData(Event theEvent); + + /** Heartbeat event from server. */ + public void onHeartbeat(Event theEvent); + + /** Error occurred. */ + public void onError(String message); +} + +/* * $Log: PushletClientListener.java,v $ * Revision 1.5 2005/02/21 11:50:37 justb * ohase1 of refactoring Subscriber into Session/Controller/Subscriber -* -* Revision 1.4 2005/02/15 15:46:31 justb -* client API improves -* -* Revision 1.3 2004/10/24 12:58:18 justb -* revised client and test classes for new protocol -* -* Revision 1.2 2004/09/03 22:35:37 justb -* Almost complete rewrite, just checking in now -* -* Revision 1.1 2004/03/10 20:14:17 justb -* renamed all *JavaPushletClient* to *PushletClient* -* -* Revision 1.3 2003/08/15 08:37:40 justb -* fix/add Copyright+LGPL file headers and footers -* -* +* +* Revision 1.4 2005/02/15 15:46:31 justb +* client API improves +* +* Revision 1.3 2004/10/24 12:58:18 justb +* revised client and test classes for new protocol +* +* Revision 1.2 2004/09/03 22:35:37 justb +* Almost complete rewrite, just checking in now +* +* Revision 1.1 2004/03/10 20:14:17 justb +* renamed all *JavaPushletClient* to *PushletClient* +* +* Revision 1.3 2003/08/15 08:37:40 justb +* fix/add Copyright+LGPL file headers and footers +* +* */ \ No newline at end of file diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/BrowserAdapter.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/BrowserAdapter.java index 8aa226b659..d523882f49 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/BrowserAdapter.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/BrowserAdapter.java @@ -1,203 +1,203 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -import nl.justobjects.pushlet.util.Log; - -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.Iterator; - -/** - * Generic implementation of ClientAdapter for browser clients. - * - * @author Just van den Broecke - Just Objects © - * @version $Id: BrowserAdapter.java,v 1.6 2007/11/09 13:15:35 justb Exp $ - */ -public class BrowserAdapter implements ClientAdapter, Protocol { - - public static final String START_DOCUMENT = - "" - + "" - + "\n"; - public static final String END_DOCUMENT = ""; - - private PrintWriter servletOut; - private HttpServletResponse servletRsp; - private int bytesSent; - - /** - * Constructor. - */ - public BrowserAdapter(HttpServletResponse aServletResponse) { - servletRsp = aServletResponse; - } - - /** - * Generic init. - */ - public void start() throws IOException { - // Keep servlet request/response objects until page ends in stop() - // Content type as HTML - servletRsp.setStatus(HttpServletResponse.SC_OK); - servletRsp.setContentType("text/html;charset=UTF-8"); - - // http://www.junlu.com/msg/45902.html - // Log.debug("bufsize=" + aRsp.getBufferSize()); - servletOut = servletRsp.getWriter(); - send(START_DOCUMENT); - } - - /** - * Push Event to client. - */ - public void push(Event anEvent) throws IOException { - Log.debug("BCA event=" + anEvent.toXML()); - - // Check if we should refresh - if (anEvent.getEventType().equals(Protocol.E_REFRESH)) { - // Append refresh and tail of HTML document - // Construct the JS callback line to be sent as last line of doc. - // This will refresh the request using the unique id to determine - // the subscriber instance on the server. The client will wait for - // a number of milliseconds. - long refreshWaitMillis = Long.parseLong(anEvent.getField(P_WAIT)); - - // Create servlet request for requesting next events (refresh) - String url = anEvent.getField(P_URL); - String jsRefreshTrigger = "\n"; - - - send(jsRefreshTrigger + END_DOCUMENT); - } else { - send(event2JavaScript(anEvent)); - } - } - - /** - * End HTML page in client browser. - */ - public void stop() { - // To be garbage collected if adapter remains active - servletOut = null; - } - - /** - * Send any string to browser. - */ - protected void send(String s) throws IOException { - // Send string to browser. - // Log.debug("Adapter: sending: " + s); - if (servletOut == null) { - throw new IOException("Client adapter was stopped"); - } - - servletOut.print(s); - - servletOut.flush(); - - // Note: this doesn't seem to have effect - // in Tomcat 4/5 if the client already disconnected. - servletRsp.flushBuffer(); - - bytesSent += s.length(); - Log.debug("bytesSent= " + bytesSent); - // Log.debug("BCA sent event: " + s); - } - - /** - * Converts the Java Event to a JavaScript function call in browser page. - */ - protected String event2JavaScript(Event event) throws IOException { - - // Convert the event to a comma-separated string. - String jsArgs = ""; - for (Iterator iter = event.getFieldNames(); iter.hasNext();) { - String name = (String) iter.next(); - String value = event.getField(name); - String nextArgument = (jsArgs.equals("") ? "" : ",") + "'" + name + "'" + ", \"" + value + "\""; - jsArgs += nextArgument; - } - - // Construct and return the function call */ - return ""; - } - -} - -/* - * $Log: BrowserAdapter.java,v $ - * Revision 1.6 2007/11/09 13:15:35 justb - * add charset=UTF-8 in returned HTTP content types - * - * Revision 1.5 2006/05/15 11:52:53 justb - * updates mainly for AJAX client - * - * Revision 1.4 2006/05/06 00:10:11 justb - * various chgs but not too serious... - * - * Revision 1.3 2005/02/28 12:45:59 justb - * introduced Command class - * - * Revision 1.2 2005/02/21 11:50:44 justb - * ohase1 of refactoring Subscriber into Session/Controller/Subscriber - * - * Revision 1.1 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.12 2005/02/15 13:30:23 justb - * changes for Tomcat buffering (now working in tc4 and 5.0) - * - * Revision 1.11 2005/01/24 22:45:58 justb - * getting safari to work - * - * Revision 1.10 2005/01/18 16:46:27 justb - * buffer size setting ignored by tomcat workings - * - * Revision 1.9 2004/10/24 12:58:18 justb - * revised client and test classes for new protocol - * - * Revision 1.8 2004/09/20 22:01:38 justb - * more changes for new protocol - * - * Revision 1.7 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.6 2004/08/15 16:00:15 justb - * enhancements to pull mode - * - * Revision 1.5 2004/08/13 23:36:05 justb - * rewrite of Pullet into Pushlet "pull" mode - * - * Revision 1.4 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.3 2003/08/12 09:57:05 justb - * replaced all print statements to Log.*() calls - * - * Revision 1.2 2003/05/18 16:15:07 justb - * support for XML encoded Events - * - * Revision 1.1.1.1 2002/09/24 21:02:30 justb - * import to sourceforge - * - * Revision 1.1.1.1 2002/09/20 22:48:17 justb - * import to SF - * - * Revision 1.1.1.1 2002/09/20 14:19:02 justb - * first import into SF - * - * Revision 1.5 2002/04/15 20:42:41 just - * reformatting and renaming GuardedQueue to EventQueue - * - * Revision 1.4 2000/12/27 22:39:35 just - * no message - * - * Revision 1.3 2000/10/30 14:15:47 just - * no message - * - * - */ - +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +import nl.justobjects.pushlet.util.Log; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Iterator; + +/** + * Generic implementation of ClientAdapter for browser clients. + * + * @author Just van den Broecke - Just Objects © + * @version $Id: BrowserAdapter.java,v 1.6 2007/11/09 13:15:35 justb Exp $ + */ +public class BrowserAdapter implements ClientAdapter, Protocol { + + public static final String START_DOCUMENT = + "" + + "" + + "\n"; + public static final String END_DOCUMENT = ""; + + private PrintWriter servletOut; + private HttpServletResponse servletRsp; + private int bytesSent; + + /** + * Constructor. + */ + public BrowserAdapter(HttpServletResponse aServletResponse) { + servletRsp = aServletResponse; + } + + /** + * Generic init. + */ + public void start() throws IOException { + // Keep servlet request/response objects until page ends in stop() + // Content type as HTML + servletRsp.setStatus(HttpServletResponse.SC_OK); + servletRsp.setContentType("text/html;charset=UTF-8"); + + // http://www.junlu.com/msg/45902.html + // Log.debug("bufsize=" + aRsp.getBufferSize()); + servletOut = servletRsp.getWriter(); + send(START_DOCUMENT); + } + + /** + * Push Event to client. + */ + public void push(Event anEvent) throws IOException { + Log.debug("BCA event=" + anEvent.toXML()); + + // Check if we should refresh + if (anEvent.getEventType().equals(Protocol.E_REFRESH)) { + // Append refresh and tail of HTML document + // Construct the JS callback line to be sent as last line of doc. + // This will refresh the request using the unique id to determine + // the subscriber instance on the server. The client will wait for + // a number of milliseconds. + long refreshWaitMillis = Long.parseLong(anEvent.getField(P_WAIT)); + + // Create servlet request for requesting next events (refresh) + String url = anEvent.getField(P_URL); + String jsRefreshTrigger = "\n"; + + + send(jsRefreshTrigger + END_DOCUMENT); + } else { + send(event2JavaScript(anEvent)); + } + } + + /** + * End HTML page in client browser. + */ + public void stop() { + // To be garbage collected if adapter remains active + servletOut = null; + } + + /** + * Send any string to browser. + */ + protected void send(String s) throws IOException { + // Send string to browser. + // Log.debug("Adapter: sending: " + s); + if (servletOut == null) { + throw new IOException("Client adapter was stopped"); + } + + servletOut.print(s); + + servletOut.flush(); + + // Note: this doesn't seem to have effect + // in Tomcat 4/5 if the client already disconnected. + servletRsp.flushBuffer(); + + bytesSent += s.length(); + Log.debug("bytesSent= " + bytesSent); + // Log.debug("BCA sent event: " + s); + } + + /** + * Converts the Java Event to a JavaScript function call in browser page. + */ + protected String event2JavaScript(Event event) throws IOException { + + // Convert the event to a comma-separated string. + String jsArgs = ""; + for (Iterator iter = event.getFieldNames(); iter.hasNext();) { + String name = (String) iter.next(); + String value = event.getField(name); + String nextArgument = (jsArgs.equals("") ? "" : ",") + "'" + name + "'" + ", \"" + value + "\""; + jsArgs += nextArgument; + } + + // Construct and return the function call */ + return ""; + } + +} + +/* + * $Log: BrowserAdapter.java,v $ + * Revision 1.6 2007/11/09 13:15:35 justb + * add charset=UTF-8 in returned HTTP content types + * + * Revision 1.5 2006/05/15 11:52:53 justb + * updates mainly for AJAX client + * + * Revision 1.4 2006/05/06 00:10:11 justb + * various chgs but not too serious... + * + * Revision 1.3 2005/02/28 12:45:59 justb + * introduced Command class + * + * Revision 1.2 2005/02/21 11:50:44 justb + * ohase1 of refactoring Subscriber into Session/Controller/Subscriber + * + * Revision 1.1 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.12 2005/02/15 13:30:23 justb + * changes for Tomcat buffering (now working in tc4 and 5.0) + * + * Revision 1.11 2005/01/24 22:45:58 justb + * getting safari to work + * + * Revision 1.10 2005/01/18 16:46:27 justb + * buffer size setting ignored by tomcat workings + * + * Revision 1.9 2004/10/24 12:58:18 justb + * revised client and test classes for new protocol + * + * Revision 1.8 2004/09/20 22:01:38 justb + * more changes for new protocol + * + * Revision 1.7 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.6 2004/08/15 16:00:15 justb + * enhancements to pull mode + * + * Revision 1.5 2004/08/13 23:36:05 justb + * rewrite of Pullet into Pushlet "pull" mode + * + * Revision 1.4 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.3 2003/08/12 09:57:05 justb + * replaced all print statements to Log.*() calls + * + * Revision 1.2 2003/05/18 16:15:07 justb + * support for XML encoded Events + * + * Revision 1.1.1.1 2002/09/24 21:02:30 justb + * import to sourceforge + * + * Revision 1.1.1.1 2002/09/20 22:48:17 justb + * import to SF + * + * Revision 1.1.1.1 2002/09/20 14:19:02 justb + * first import into SF + * + * Revision 1.5 2002/04/15 20:42:41 just + * reformatting and renaming GuardedQueue to EventQueue + * + * Revision 1.4 2000/12/27 22:39:35 just + * no message + * + * Revision 1.3 2000/10/30 14:15:47 just + * no message + * + * + */ + diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/ClientAdapter.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/ClientAdapter.java index c7ea141fee..4b187325ef 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/ClientAdapter.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/ClientAdapter.java @@ -1,72 +1,72 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -import java.io.IOException; - -/** - * Adapter interface for encapsulation of specific HTTP clients. - * - * @author Just van den Broecke - Just Objects © - * @version $Id: ClientAdapter.java,v 1.8 2007/11/23 14:33:07 justb Exp $ - */ -public interface ClientAdapter { - - /** - * Start event push. - */ - public void start() throws IOException; - - /** - * Push single Event to client. - */ - public void push(Event anEvent) throws IOException; - - /** - * Stop event push. - */ - public void stop() throws IOException; -} - -/* - * $Log: ClientAdapter.java,v $ - * Revision 1.8 2007/11/23 14:33:07 justb - * core classes now configurable through factory - * - * Revision 1.7 2005/02/28 12:45:59 justb - * introduced Command class - * - * Revision 1.6 2005/02/21 11:50:45 justb - * ohase1 of refactoring Subscriber into Session/Controller/Subscriber - * - * Revision 1.5 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.4 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.3 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.2 2003/05/18 16:15:08 justb - * support for XML encoded Events - * - * Revision 1.1.1.1 2002/09/24 21:02:30 justb - * import to sourceforge - * - * Revision 1.1.1.1 2002/09/20 22:48:17 justb - * import to SF - * - * Revision 1.1.1.1 2002/09/20 14:19:03 justb - * first import into SF - * - * Revision 1.3 2002/04/15 20:42:41 just - * reformatting and renaming GuardedQueue to EventQueue - * - * Revision 1.2 2000/08/21 20:48:29 just - * added CVS log and id tags plus copyrights - * - * - */ - +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +import java.io.IOException; + +/** + * Adapter interface for encapsulation of specific HTTP clients. + * + * @author Just van den Broecke - Just Objects © + * @version $Id: ClientAdapter.java,v 1.8 2007/11/23 14:33:07 justb Exp $ + */ +public interface ClientAdapter { + + /** + * Start event push. + */ + public void start() throws IOException; + + /** + * Push single Event to client. + */ + public void push(Event anEvent) throws IOException; + + /** + * Stop event push. + */ + public void stop() throws IOException; +} + +/* + * $Log: ClientAdapter.java,v $ + * Revision 1.8 2007/11/23 14:33:07 justb + * core classes now configurable through factory + * + * Revision 1.7 2005/02/28 12:45:59 justb + * introduced Command class + * + * Revision 1.6 2005/02/21 11:50:45 justb + * ohase1 of refactoring Subscriber into Session/Controller/Subscriber + * + * Revision 1.5 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.4 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.3 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.2 2003/05/18 16:15:08 justb + * support for XML encoded Events + * + * Revision 1.1.1.1 2002/09/24 21:02:30 justb + * import to sourceforge + * + * Revision 1.1.1.1 2002/09/20 22:48:17 justb + * import to SF + * + * Revision 1.1.1.1 2002/09/20 14:19:03 justb + * first import into SF + * + * Revision 1.3 2002/04/15 20:42:41 just + * reformatting and renaming GuardedQueue to EventQueue + * + * Revision 1.2 2000/08/21 20:48:29 just + * added CVS log and id tags plus copyrights + * + * + */ + diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/Dispatcher.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/Dispatcher.java index 5cd739d5bd..83b402f693 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/Dispatcher.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/Dispatcher.java @@ -1,265 +1,265 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -import nl.justobjects.pushlet.util.Log; -import nl.justobjects.pushlet.util.PushletException; - -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; - -/** - * Routes Events to Subscribers. - * - * @author Just van den Broecke - Just Objects © - * @version $Id: Dispatcher.java,v 1.9 2007/12/04 13:55:53 justb Exp $ - */ -public class Dispatcher implements Protocol, ConfigDefs { - /** - * Singleton pattern: single instance. - */ - private static Dispatcher instance; - protected SessionManagerVisitor sessionManagerVisitor; - - static { - try { - instance = (Dispatcher) Config.getClass(DISPATCHER_CLASS, "nl.justobjects.pushlet.core.Dispatcher").newInstance(); - Log.info("Dispatcher created className=" + instance.getClass()); - } catch (Throwable t) { - Log.fatal("Cannot instantiate Dispatcher from config", t); - } - } - - /** - * Singleton pattern with factory method: protected constructor. - */ - protected Dispatcher() { - - } - - /** - * Singleton pattern: get single instance. - */ - public static Dispatcher getInstance() { - return instance; - } - - /** - * Send event to all subscribers. - */ - public synchronized void broadcast(Event anEvent) { - try { - // Let the SessionManager loop through Sessions, calling - // our Visitor Method for each Session. This is done to guard - // synchronization with SessionManager and to optimize by - // not getting an array of all sessions. - Object[] args = new Object[2]; - args[1] = anEvent; - Method method = sessionManagerVisitor.getMethod("visitBroadcast"); - SessionManager.getInstance().apply(sessionManagerVisitor, method, args); - } catch (Throwable t) { - Log.error("Error calling SessionManager.apply: ", t); - } - } - - /** - * Send event to subscribers matching Event subject. - */ - public synchronized void multicast(Event anEvent) { - try { - // Let the SessionManager loop through Sessions, calling - // our Visitor Method for each Session. This is done to guard - // synchronization with SessionManager and to optimize by - // not getting an array of all sessions. - Method method = sessionManagerVisitor.getMethod("visitMulticast"); - Object[] args = new Object[2]; - args[1] = anEvent; - SessionManager.getInstance().apply(sessionManagerVisitor, method, args); - } catch (Throwable t) { - Log.error("Error calling SessionManager.apply: ", t); - } - } - - - /** - * Send event to specific subscriber. - */ - public synchronized void unicast(Event event, String aSessionId) { - // Get subscriber to send event to - Session session = SessionManager.getInstance().getSession(aSessionId); - if (session == null) { - Log.warn("unicast: session with id=" + aSessionId + " does not exist"); - return; - } - - // Send Event to subscriber. - session.getSubscriber().onEvent((Event) event.clone()); - } - - /** - * Start Dispatcher. - */ - public void start() throws PushletException { - Log.info("Dispatcher started"); - - // Create callback for SessionManager visits. - sessionManagerVisitor = new SessionManagerVisitor(); - } - - /** - * Stop Dispatcher. - */ - public void stop() { - // Send abort control event to all subscribers. - Log.info("Dispatcher stopped: broadcast abort to all subscribers"); - broadcast(new Event(E_ABORT)); - } - - /** - * Supplies Visitor methods for callbacks from SessionManager. - */ - private class SessionManagerVisitor { - private final Map visitorMethods = new HashMap(2); - - SessionManagerVisitor() throws PushletException { - - try { - // Setup Visitor Methods for callback from SessionManager - // This is a slight opitmization over creating Method objects - // on each invokation. - Class[] argsClasses = {Session.class, Event.class}; - visitorMethods.put("visitMulticast", this.getClass().getMethod("visitMulticast", argsClasses)); - visitorMethods.put("visitBroadcast", this.getClass().getMethod("visitBroadcast", argsClasses)); - } catch (NoSuchMethodException e) { - throw new PushletException("Failed to setup SessionManagerVisitor", e); - } - } - - /** - * Return Visitor Method by name. - */ - public Method getMethod(String aName) { - return (Method) visitorMethods.get(aName); - - } - - /** - * Visitor method called by SessionManager. - */ - public void visitBroadcast(Session aSession, Event event) { - aSession.getSubscriber().onEvent((Event) event.clone()); - } - - /** - * Visitor method called by SessionManager. - */ - public void visitMulticast(Session aSession, Event event) { - Subscriber subscriber = aSession.getSubscriber(); - Event clonedEvent; - Subscription subscription; - - // Send only if the subscriber's criteria - // match the event. - if ((subscription = subscriber.match(event)) != null) { - // Personalize event - clonedEvent = (Event) event.clone(); - - // Set subscription id and optional label - clonedEvent.setField(P_SUBSCRIPTION_ID, subscription.getId()); - if (subscription.getLabel() != null) { - event.setField(P_SUBSCRIPTION_LABEL, subscription.getLabel()); - } - - subscriber.onEvent(clonedEvent); - } - } - } -} - -/* - * $Log: Dispatcher.java,v $ - * Revision 1.9 2007/12/04 13:55:53 justb - * reimplement SessionManager concurrency (prev version was not thread-safe!) - * - * Revision 1.8 2007/11/23 14:33:07 justb - * core classes now configurable through factory - * - * Revision 1.7 2005/02/28 12:45:59 justb - * introduced Command class - * - * Revision 1.6 2005/02/28 09:14:55 justb - * sessmgr/dispatcher factory/singleton support - * - * Revision 1.5 2005/02/21 16:59:06 justb - * SessionManager and session lease introduced - * - * Revision 1.4 2005/02/21 11:50:46 justb - * ohase1 of refactoring Subscriber into Session/Controller/Subscriber - * - * Revision 1.3 2005/02/18 12:36:47 justb - * changes for renaming and configurability - * - * Revision 1.2 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.1 2005/02/18 09:54:15 justb - * refactor: rename Publisher Dispatcher and single Subscriber class - * - * Revision 1.14 2005/02/16 14:39:34 justb - * fixed leave handling and added "poll" mode - * - * Revision 1.13 2004/10/24 20:50:35 justb - * refine subscription with label and sending sid and label on events - * - * Revision 1.12 2004/10/24 12:58:18 justb - * revised client and test classes for new protocol - * - * Revision 1.11 2004/09/26 21:39:43 justb - * allow multiple subscriptions and out-of-band requests - * - * Revision 1.10 2004/09/20 22:01:38 justb - * more changes for new protocol - * - * Revision 1.9 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.8 2004/08/13 23:36:05 justb - * rewrite of Pullet into Pushlet "pull" mode - * - * Revision 1.7 2004/08/12 13:18:54 justb - * cosmetic changes - * - * Revision 1.6 2004/03/10 15:45:55 justb - * many cosmetic changes - * - * Revision 1.5 2004/03/10 13:59:28 justb - * rewrite using Collection classes and finer synchronization - * - * Revision 1.4 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.3 2003/08/12 08:54:40 justb - * added getSubscriberCount() and use Log - * - * Revision 1.2 2003/05/18 16:15:08 justb - * support for XML encoded Events - * - * Revision 1.1.1.1 2002/09/24 21:02:31 justb - * import to sourceforge - * - * Revision 1.1.1.1 2002/09/20 22:48:18 justb - * import to SF - * - * Revision 1.1.1.1 2002/09/20 14:19:04 justb - * first import into SF - * - * Revision 1.3 2002/04/15 20:42:41 just - * reformatting and renaming GuardedQueue to EventQueue - * - * Revision 1.2 2000/08/21 20:48:29 just - * added CVS log and id tags plus copyrights - * - * - */ +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +import nl.justobjects.pushlet.util.Log; +import nl.justobjects.pushlet.util.PushletException; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +/** + * Routes Events to Subscribers. + * + * @author Just van den Broecke - Just Objects © + * @version $Id: Dispatcher.java,v 1.9 2007/12/04 13:55:53 justb Exp $ + */ +public class Dispatcher implements Protocol, ConfigDefs { + /** + * Singleton pattern: single instance. + */ + private static Dispatcher instance; + protected SessionManagerVisitor sessionManagerVisitor; + + static { + try { + instance = (Dispatcher) Config.getClass(DISPATCHER_CLASS, "nl.justobjects.pushlet.core.Dispatcher").newInstance(); + Log.info("Dispatcher created className=" + instance.getClass()); + } catch (Throwable t) { + Log.fatal("Cannot instantiate Dispatcher from config", t); + } + } + + /** + * Singleton pattern with factory method: protected constructor. + */ + protected Dispatcher() { + + } + + /** + * Singleton pattern: get single instance. + */ + public static Dispatcher getInstance() { + return instance; + } + + /** + * Send event to all subscribers. + */ + public synchronized void broadcast(Event anEvent) { + try { + // Let the SessionManager loop through Sessions, calling + // our Visitor Method for each Session. This is done to guard + // synchronization with SessionManager and to optimize by + // not getting an array of all sessions. + Object[] args = new Object[2]; + args[1] = anEvent; + Method method = sessionManagerVisitor.getMethod("visitBroadcast"); + SessionManager.getInstance().apply(sessionManagerVisitor, method, args); + } catch (Throwable t) { + Log.error("Error calling SessionManager.apply: ", t); + } + } + + /** + * Send event to subscribers matching Event subject. + */ + public synchronized void multicast(Event anEvent) { + try { + // Let the SessionManager loop through Sessions, calling + // our Visitor Method for each Session. This is done to guard + // synchronization with SessionManager and to optimize by + // not getting an array of all sessions. + Method method = sessionManagerVisitor.getMethod("visitMulticast"); + Object[] args = new Object[2]; + args[1] = anEvent; + SessionManager.getInstance().apply(sessionManagerVisitor, method, args); + } catch (Throwable t) { + Log.error("Error calling SessionManager.apply: ", t); + } + } + + + /** + * Send event to specific subscriber. + */ + public synchronized void unicast(Event event, String aSessionId) { + // Get subscriber to send event to + Session session = SessionManager.getInstance().getSession(aSessionId); + if (session == null) { + Log.warn("unicast: session with id=" + aSessionId + " does not exist"); + return; + } + + // Send Event to subscriber. + session.getSubscriber().onEvent((Event) event.clone()); + } + + /** + * Start Dispatcher. + */ + public void start() throws PushletException { + Log.info("Dispatcher started"); + + // Create callback for SessionManager visits. + sessionManagerVisitor = new SessionManagerVisitor(); + } + + /** + * Stop Dispatcher. + */ + public void stop() { + // Send abort control event to all subscribers. + Log.info("Dispatcher stopped: broadcast abort to all subscribers"); + broadcast(new Event(E_ABORT)); + } + + /** + * Supplies Visitor methods for callbacks from SessionManager. + */ + private class SessionManagerVisitor { + private final Map visitorMethods = new HashMap(2); + + SessionManagerVisitor() throws PushletException { + + try { + // Setup Visitor Methods for callback from SessionManager + // This is a slight opitmization over creating Method objects + // on each invokation. + Class[] argsClasses = {Session.class, Event.class}; + visitorMethods.put("visitMulticast", this.getClass().getMethod("visitMulticast", argsClasses)); + visitorMethods.put("visitBroadcast", this.getClass().getMethod("visitBroadcast", argsClasses)); + } catch (NoSuchMethodException e) { + throw new PushletException("Failed to setup SessionManagerVisitor", e); + } + } + + /** + * Return Visitor Method by name. + */ + public Method getMethod(String aName) { + return (Method) visitorMethods.get(aName); + + } + + /** + * Visitor method called by SessionManager. + */ + public void visitBroadcast(Session aSession, Event event) { + aSession.getSubscriber().onEvent((Event) event.clone()); + } + + /** + * Visitor method called by SessionManager. + */ + public void visitMulticast(Session aSession, Event event) { + Subscriber subscriber = aSession.getSubscriber(); + Event clonedEvent; + Subscription subscription; + + // Send only if the subscriber's criteria + // match the event. + if ((subscription = subscriber.match(event)) != null) { + // Personalize event + clonedEvent = (Event) event.clone(); + + // Set subscription id and optional label + clonedEvent.setField(P_SUBSCRIPTION_ID, subscription.getId()); + if (subscription.getLabel() != null) { + event.setField(P_SUBSCRIPTION_LABEL, subscription.getLabel()); + } + + subscriber.onEvent(clonedEvent); + } + } + } +} + +/* + * $Log: Dispatcher.java,v $ + * Revision 1.9 2007/12/04 13:55:53 justb + * reimplement SessionManager concurrency (prev version was not thread-safe!) + * + * Revision 1.8 2007/11/23 14:33:07 justb + * core classes now configurable through factory + * + * Revision 1.7 2005/02/28 12:45:59 justb + * introduced Command class + * + * Revision 1.6 2005/02/28 09:14:55 justb + * sessmgr/dispatcher factory/singleton support + * + * Revision 1.5 2005/02/21 16:59:06 justb + * SessionManager and session lease introduced + * + * Revision 1.4 2005/02/21 11:50:46 justb + * ohase1 of refactoring Subscriber into Session/Controller/Subscriber + * + * Revision 1.3 2005/02/18 12:36:47 justb + * changes for renaming and configurability + * + * Revision 1.2 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.1 2005/02/18 09:54:15 justb + * refactor: rename Publisher Dispatcher and single Subscriber class + * + * Revision 1.14 2005/02/16 14:39:34 justb + * fixed leave handling and added "poll" mode + * + * Revision 1.13 2004/10/24 20:50:35 justb + * refine subscription with label and sending sid and label on events + * + * Revision 1.12 2004/10/24 12:58:18 justb + * revised client and test classes for new protocol + * + * Revision 1.11 2004/09/26 21:39:43 justb + * allow multiple subscriptions and out-of-band requests + * + * Revision 1.10 2004/09/20 22:01:38 justb + * more changes for new protocol + * + * Revision 1.9 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.8 2004/08/13 23:36:05 justb + * rewrite of Pullet into Pushlet "pull" mode + * + * Revision 1.7 2004/08/12 13:18:54 justb + * cosmetic changes + * + * Revision 1.6 2004/03/10 15:45:55 justb + * many cosmetic changes + * + * Revision 1.5 2004/03/10 13:59:28 justb + * rewrite using Collection classes and finer synchronization + * + * Revision 1.4 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.3 2003/08/12 08:54:40 justb + * added getSubscriberCount() and use Log + * + * Revision 1.2 2003/05/18 16:15:08 justb + * support for XML encoded Events + * + * Revision 1.1.1.1 2002/09/24 21:02:31 justb + * import to sourceforge + * + * Revision 1.1.1.1 2002/09/20 22:48:18 justb + * import to SF + * + * Revision 1.1.1.1 2002/09/20 14:19:04 justb + * first import into SF + * + * Revision 1.3 2002/04/15 20:42:41 just + * reformatting and renaming GuardedQueue to EventQueue + * + * Revision 1.2 2000/08/21 20:48:29 just + * added CVS log and id tags plus copyrights + * + * + */ diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/Event.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/Event.java index e9a0aaa48b..b74d3c9bab 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/Event.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/Event.java @@ -1,184 +1,184 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -import nl.justobjects.pushlet.util.Sys; - -import java.io.Serializable; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -/** - * Represents the event data. - * - * @author Just van den Broecke - Just Objects © - * @version $Id: Event.java,v 1.13 2007/11/23 14:33:07 justb Exp $ - */ -public class Event implements Protocol, Serializable { - - protected Map attributes = new HashMap(3); - - public Event(String anEventType) { - this(anEventType, null); - } - - public Event(String anEventType, Map theAttributes) { - - if (theAttributes != null) { - setAttrs(theAttributes); - } - - // Set required field event type - setField(P_EVENT, anEventType); - - // Set time in seconds since 1970 - setField(P_TIME, System.currentTimeMillis() / 1000); - } - - public Event(Map theAttributes) { - if (!theAttributes.containsKey(P_EVENT)) { - throw new IllegalArgumentException(P_EVENT + " not found in attributes"); - } - setAttrs(theAttributes); - } - - public static Event createDataEvent(String aSubject) { - return createDataEvent(aSubject, null); - } - - public static Event createDataEvent(String aSubject, Map theAttributes) { - Event dataEvent = new Event(E_DATA, theAttributes); - dataEvent.setField(P_SUBJECT, aSubject); - return dataEvent; - } - - public String getEventType() { - return getField(P_EVENT); - } - - public String getSubject() { - return getField(P_SUBJECT); - } - - public void setField(String name, String value) { - attributes.put(name, value); - } - - public void setField(String name, int value) { - attributes.put(name, value + ""); - } - - public void setField(String name, long value) { - attributes.put(name, value + ""); - } - - public String getField(String name) { - return (String) attributes.get(name); - } - - /** - * Return field; if null return default. - */ - public String getField(String name, String aDefault) { - String result = getField(name); - return result == null ? aDefault : result; - } - - public Iterator getFieldNames() { - return attributes.keySet().iterator(); - } - - public String toString() { - return attributes.toString(); - } - - /** - * Convert to HTTP query string. - */ - public String toQueryString() { - String queryString = ""; - String amp = ""; - for (Iterator iter = getFieldNames(); iter.hasNext();) { - String nextAttrName = (String) iter.next(); - String nextAttrValue = getField(nextAttrName); - queryString = queryString + amp + nextAttrName + "=" + nextAttrValue; - // After first add "&". - amp = "&"; - } - - return queryString; - } - - public String toXML(boolean strict) { - String xmlString = " +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +import nl.justobjects.pushlet.util.Sys; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * Represents the event data. + * + * @author Just van den Broecke - Just Objects © + * @version $Id: Event.java,v 1.13 2007/11/23 14:33:07 justb Exp $ + */ +public class Event implements Protocol, Serializable { + + protected Map attributes = new HashMap(3); + + public Event(String anEventType) { + this(anEventType, null); + } + + public Event(String anEventType, Map theAttributes) { + + if (theAttributes != null) { + setAttrs(theAttributes); + } + + // Set required field event type + setField(P_EVENT, anEventType); + + // Set time in seconds since 1970 + setField(P_TIME, System.currentTimeMillis() / 1000); + } + + public Event(Map theAttributes) { + if (!theAttributes.containsKey(P_EVENT)) { + throw new IllegalArgumentException(P_EVENT + " not found in attributes"); + } + setAttrs(theAttributes); + } + + public static Event createDataEvent(String aSubject) { + return createDataEvent(aSubject, null); + } + + public static Event createDataEvent(String aSubject, Map theAttributes) { + Event dataEvent = new Event(E_DATA, theAttributes); + dataEvent.setField(P_SUBJECT, aSubject); + return dataEvent; + } + + public String getEventType() { + return getField(P_EVENT); + } + + public String getSubject() { + return getField(P_SUBJECT); + } + + public void setField(String name, String value) { + attributes.put(name, value); + } + + public void setField(String name, int value) { + attributes.put(name, value + ""); + } + + public void setField(String name, long value) { + attributes.put(name, value + ""); + } + + public String getField(String name) { + return (String) attributes.get(name); + } + + /** + * Return field; if null return default. + */ + public String getField(String name, String aDefault) { + String result = getField(name); + return result == null ? aDefault : result; + } + + public Iterator getFieldNames() { + return attributes.keySet().iterator(); + } + + public String toString() { + return attributes.toString(); + } + + /** + * Convert to HTTP query string. + */ + public String toQueryString() { + String queryString = ""; + String amp = ""; + for (Iterator iter = getFieldNames(); iter.hasNext();) { + String nextAttrName = (String) iter.next(); + String nextAttrValue = getField(nextAttrName); + queryString = queryString + amp + nextAttrName + "=" + nextAttrValue; + // After first add "&". + amp = "&"; + } + + return queryString; + } + + public String toXML(boolean strict) { + String xmlString = " -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -import nl.justobjects.pushlet.util.Log; - -/** - * Abstract Event source from which Events are pulled. - * - * @version $Id: EventPullSource.java,v 1.15 2007/11/23 14:33:07 justb Exp $ - * @author Just van den Broecke - Just Objects © - **/ - -/** - * ABC for specifc EventPullSources. - */ -abstract public class EventPullSource implements EventSource, Runnable { - private volatile boolean alive = false; - private volatile boolean active = false; - private static int threadNum = 0; - private Thread thread; - - public EventPullSource() { - } - - abstract protected long getSleepTime(); - - abstract protected Event pullEvent(); - - public void start() { - thread = new Thread(this, "EventPullSource-" + (++threadNum)); - thread.setDaemon(true); - thread.start(); - } - - public boolean isAlive() { - return alive; - } - - /** - * Stop the event generator thread. - */ - public void stop() { - alive = false; - - if (thread != null) { - thread.interrupt(); - thread = null; - } - - } - - /** - * Activate the event generator thread. - */ - synchronized public void activate() { - if (active) { - return; - } - active = true; - if (!alive) { - start(); - return; - } - Log.debug(getClass().getName() + ": notifying..."); - notifyAll(); - } - - /** - * Deactivate the event generator thread. - */ - public void passivate() { - if (!active) { - return; - } - active = false; - } - - /** - * Main loop: sleep, generate event and publish. - */ - public void run() { - Log.debug(getClass().getName() + ": starting..."); - alive = true; - while (alive) { - try { - - Thread.sleep(getSleepTime()); - - // Stopped during sleep: end loop. - if (!alive) { - break; - } - - // If passivated wait until we get - // get notify()-ied. If there are no subscribers - // it wasts CPU to remain producing events... - synchronized (this) { - while (!active) { - Log.debug(getClass().getName() + ": waiting..."); - wait(); - } - } - - } catch (InterruptedException e) { - break; - } - - try { - // Derived class should produce an event. - Event event = pullEvent(); - - // Let the publisher push it to subscribers. - Dispatcher.getInstance().multicast(event); - } catch (Throwable t) { - Log.warn("EventPullSource exception while multicasting ", t); - t.printStackTrace(); - } - } - Log.debug(getClass().getName() + ": stopped"); - } -} - -/* - * $Log: EventPullSource.java,v $ - * Revision 1.15 2007/11/23 14:33:07 justb - * core classes now configurable through factory - * - * Revision 1.14 2005/02/28 09:14:55 justb - * sessmgr/dispatcher factory/singleton support - * - * Revision 1.13 2005/02/21 16:59:08 justb - * SessionManager and session lease introduced - * - * Revision 1.12 2005/02/21 11:50:46 justb - * ohase1 of refactoring Subscriber into Session/Controller/Subscriber - * - * Revision 1.11 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.10 2005/02/18 09:54:15 justb - * refactor: rename Publisher Dispatcher and single Subscriber class - * - * Revision 1.9 2004/09/20 22:01:38 justb - * more changes for new protocol - * - * Revision 1.8 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.7 2004/08/15 16:00:15 justb - * enhancements to pull mode - * - * Revision 1.6 2004/08/13 23:36:05 justb - * rewrite of Pullet into Pushlet "pull" mode - * - * Revision 1.5 2004/03/10 14:01:55 justb - * formatting and *Subscriber refactoring - * - * Revision 1.4 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.3 2003/08/12 09:57:05 justb - * replaced all print statements to Log.*() calls - * - * Revision 1.2 2003/05/18 16:15:08 justb - * support for XML encoded Events - * - * Revision 1.1.1.1 2002/09/24 21:02:31 justb - * import to sourceforge - * - * Revision 1.1.1.1 2002/09/20 22:48:17 justb - * import to SF - * - * Revision 1.1.1.1 2002/09/20 14:19:03 justb - * first import into SF - * - * Revision 1.3 2002/04/15 20:42:41 just - * reformatting and renaming GuardedQueue to EventQueue - * - * Revision 1.2 2000/08/21 20:48:29 just - * added CVS log and id tags plus copyrights - * - * - */ +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +import nl.justobjects.pushlet.util.Log; + +/** + * Abstract Event source from which Events are pulled. + * + * @version $Id: EventPullSource.java,v 1.15 2007/11/23 14:33:07 justb Exp $ + * @author Just van den Broecke - Just Objects © + **/ + +/** + * ABC for specifc EventPullSources. + */ +abstract public class EventPullSource implements EventSource, Runnable { + private volatile boolean alive = false; + private volatile boolean active = false; + private static int threadNum = 0; + private Thread thread; + + public EventPullSource() { + } + + abstract protected long getSleepTime(); + + abstract protected Event pullEvent(); + + public void start() { + thread = new Thread(this, "EventPullSource-" + (++threadNum)); + thread.setDaemon(true); + thread.start(); + } + + public boolean isAlive() { + return alive; + } + + /** + * Stop the event generator thread. + */ + public void stop() { + alive = false; + + if (thread != null) { + thread.interrupt(); + thread = null; + } + + } + + /** + * Activate the event generator thread. + */ + synchronized public void activate() { + if (active) { + return; + } + active = true; + if (!alive) { + start(); + return; + } + Log.debug(getClass().getName() + ": notifying..."); + notifyAll(); + } + + /** + * Deactivate the event generator thread. + */ + public void passivate() { + if (!active) { + return; + } + active = false; + } + + /** + * Main loop: sleep, generate event and publish. + */ + public void run() { + Log.debug(getClass().getName() + ": starting..."); + alive = true; + while (alive) { + try { + + Thread.sleep(getSleepTime()); + + // Stopped during sleep: end loop. + if (!alive) { + break; + } + + // If passivated wait until we get + // get notify()-ied. If there are no subscribers + // it wasts CPU to remain producing events... + synchronized (this) { + while (!active) { + Log.debug(getClass().getName() + ": waiting..."); + wait(); + } + } + + } catch (InterruptedException e) { + break; + } + + try { + // Derived class should produce an event. + Event event = pullEvent(); + + // Let the publisher push it to subscribers. + Dispatcher.getInstance().multicast(event); + } catch (Throwable t) { + Log.warn("EventPullSource exception while multicasting ", t); + t.printStackTrace(); + } + } + Log.debug(getClass().getName() + ": stopped"); + } +} + +/* + * $Log: EventPullSource.java,v $ + * Revision 1.15 2007/11/23 14:33:07 justb + * core classes now configurable through factory + * + * Revision 1.14 2005/02/28 09:14:55 justb + * sessmgr/dispatcher factory/singleton support + * + * Revision 1.13 2005/02/21 16:59:08 justb + * SessionManager and session lease introduced + * + * Revision 1.12 2005/02/21 11:50:46 justb + * ohase1 of refactoring Subscriber into Session/Controller/Subscriber + * + * Revision 1.11 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.10 2005/02/18 09:54:15 justb + * refactor: rename Publisher Dispatcher and single Subscriber class + * + * Revision 1.9 2004/09/20 22:01:38 justb + * more changes for new protocol + * + * Revision 1.8 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.7 2004/08/15 16:00:15 justb + * enhancements to pull mode + * + * Revision 1.6 2004/08/13 23:36:05 justb + * rewrite of Pullet into Pushlet "pull" mode + * + * Revision 1.5 2004/03/10 14:01:55 justb + * formatting and *Subscriber refactoring + * + * Revision 1.4 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.3 2003/08/12 09:57:05 justb + * replaced all print statements to Log.*() calls + * + * Revision 1.2 2003/05/18 16:15:08 justb + * support for XML encoded Events + * + * Revision 1.1.1.1 2002/09/24 21:02:31 justb + * import to sourceforge + * + * Revision 1.1.1.1 2002/09/20 22:48:17 justb + * import to SF + * + * Revision 1.1.1.1 2002/09/20 14:19:03 justb + * first import into SF + * + * Revision 1.3 2002/04/15 20:42:41 just + * reformatting and renaming GuardedQueue to EventQueue + * + * Revision 1.2 2000/08/21 20:48:29 just + * added CVS log and id tags plus copyrights + * + * + */ diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/EventQueue.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/EventQueue.java index 85c730e2d7..18fd52318d 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/EventQueue.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/EventQueue.java @@ -1,269 +1,269 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -/** - * FIFO queue with guarded suspension. - * Purpose
- *

- * Implementation
- * FIFO queue class implemented with circular array. The enQueue() and - * deQueue() methods use guarded suspension according to a readers/writers - * pattern, implemented with java.lang.Object.wait()/notify(). - *

- * Examples
- *

- *
- * - * @author Just van den Broecke - Just Objects © - * @version $Id: EventQueue.java,v 1.3 2007/11/23 14:33:07 justb Exp $ - */ -public class EventQueue { - /** - * Defines maximum queue size - */ - private int capacity = 8; - private Event[] queue = null; - private int front, rear; - - /** - * Construct queue with default (8) capacity. - */ - public EventQueue() { - this(8); - } - - /** - * Construct queue with specified capacity. - */ - public EventQueue(int capacity) { - this.capacity = capacity; - queue = new Event[capacity]; - front = rear = 0; - } - - /** - * Put item in queue; waits() indefinitely if queue is full. - */ - public synchronized boolean enQueue(Event item) throws InterruptedException { - return enQueue(item, -1); - } - - /** - * Put item in queue; if full wait maxtime. - */ - public synchronized boolean enQueue(Event item, long maxWaitTime) throws InterruptedException { - - // Wait (optional maxtime) as long as the queue is full - while (isFull()) { - if (maxWaitTime > 0) { - // Wait at most maximum time - wait(maxWaitTime); - - // Timed out or woken; if still full we - // had bad luck and return failure. - if (isFull()) { - return false; - } - } else { - wait(); - } - } - - // Put item in queue - queue[rear] = item; - rear = next(rear); - - // Wake up waiters; NOTE: first waiter will eat item - notifyAll(); - return true; - } - - /** - * Get head; if empty wait until something in queue. - */ - public synchronized Event deQueue() throws InterruptedException { - return deQueue(-1); - } - - /** - * Get head; if empty wait for specified time at max. - */ - public synchronized Event deQueue(long maxWaitTime) throws InterruptedException { - while (isEmpty()) { - if (maxWaitTime >= 0) { - wait(maxWaitTime); - - // Timed out or woken; if still empty we - // had bad luck and return failure. - if (isEmpty()) { - return null; - } - } else { - // Wait indefinitely for something in queue. - wait(); - } - } - - // Dequeue item - Event result = fetchNext(); - - // Notify possible wait()-ing enQueue()-ers - notifyAll(); - - // Return dequeued item - return result; - } - - /** - * Get all queued Events. - */ - public synchronized Event[] deQueueAll(long maxWaitTime) throws InterruptedException { - while (isEmpty()) { - if (maxWaitTime >= 0) { - wait(maxWaitTime); - - // Timed out or woken; if still empty we - // had bad luck and return failure. - if (isEmpty()) { - return null; - } - } else { - // Wait indefinitely for something in queue. - wait(); - } - } - - // Dequeue all items item - Event[] events = new Event[getSize()]; - for (int i = 0; i < events.length; i++) { - events[i] = fetchNext(); - } - - // Notify possible wait()-ing enQueue()-ers - notifyAll(); - - // Return dequeued item - return events; - } - - public synchronized int getSize() { - return (rear >= front) ? (rear - front) : (capacity - front + rear); - } - - /** - * Is the queue empty ? - */ - public synchronized boolean isEmpty() { - return front == rear; - } - - /** - * Is the queue full ? - */ - public synchronized boolean isFull() { - return (next(rear) == front); - } - - /** - * Circular counter. - */ - private int next(int index) { - return (index + 1 < capacity ? index + 1 : 0); - } - - /** - * Circular counter. - */ - private Event fetchNext() { - Event temp = queue[front]; - queue[front] = null; - front = next(front); - return temp; - } - - public static void p(String s) { - System.out.println(s); - } - - public static void main(String[] args) { - EventQueue q = new EventQueue(8); - Event event = new Event("t"); - try { - q.enQueue(event); - p("(1) size = " + q.getSize()); - q.enQueue(event); - p("(2) size = " + q.getSize()); - q.deQueue(); - p("(1) size = " + q.getSize()); - q.deQueue(); - p("(0) size = " + q.getSize()); - - q.enQueue(event); - q.enQueue(event); - q.enQueue(event); - p("(3) size = " + q.getSize()); - q.deQueue(); - p("(2) size = " + q.getSize()); - q.enQueue(event); - q.enQueue(event); - q.enQueue(event); - p("(5) size = " + q.getSize()); - q.enQueue(event); - q.enQueue(event); - p("(7) size = " + q.getSize()); - q.deQueue(); - q.deQueue(); - q.deQueue(); - p("(4) size = " + q.getSize()); - q.deQueue(); - q.deQueue(); - q.deQueue(); - ; - q.deQueue(); - p("(0) size = " + q.getSize()); - - q.enQueue(event); - q.enQueue(event); - q.enQueue(event); - q.enQueue(event); - q.enQueue(event); - p("(5) size = " + q.getSize()); - - q.deQueue(); - q.deQueue(); - q.deQueue(); - ; - q.deQueue(); - p("(1) size = " + q.getSize()); - } catch (InterruptedException ie) { - } - } -} - -/* -* $Log: EventQueue.java,v $ -* Revision 1.3 2007/11/23 14:33:07 justb -* core classes now configurable through factory -* -* Revision 1.2 2005/02/21 11:50:46 justb -* ohase1 of refactoring Subscriber into Session/Controller/Subscriber -* -* Revision 1.1 2005/02/18 10:07:23 justb -* many renamings of classes (make names compact) -* -* Revision 1.6 2005/02/16 12:16:16 justb -* added support for "poll" mode -* -* Revision 1.5 2005/01/13 14:47:15 justb -* control evt: send response on same (control) connection -* -* Revision 1.4 2004/09/03 22:35:37 justb -* Almost complete rewrite, just checking in now -* -* Revision 1.3 2003/08/15 08:37:40 justb -* fix/add Copyright+LGPL file headers and footers -* -* -*/ +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +/** + * FIFO queue with guarded suspension. + * Purpose
+ *

+ * Implementation
+ * FIFO queue class implemented with circular array. The enQueue() and + * deQueue() methods use guarded suspension according to a readers/writers + * pattern, implemented with java.lang.Object.wait()/notify(). + *

+ * Examples
+ *

+ *
+ * + * @author Just van den Broecke - Just Objects © + * @version $Id: EventQueue.java,v 1.3 2007/11/23 14:33:07 justb Exp $ + */ +public class EventQueue { + /** + * Defines maximum queue size + */ + private int capacity = 8; + private Event[] queue = null; + private int front, rear; + + /** + * Construct queue with default (8) capacity. + */ + public EventQueue() { + this(8); + } + + /** + * Construct queue with specified capacity. + */ + public EventQueue(int capacity) { + this.capacity = capacity; + queue = new Event[capacity]; + front = rear = 0; + } + + /** + * Put item in queue; waits() indefinitely if queue is full. + */ + public synchronized boolean enQueue(Event item) throws InterruptedException { + return enQueue(item, -1); + } + + /** + * Put item in queue; if full wait maxtime. + */ + public synchronized boolean enQueue(Event item, long maxWaitTime) throws InterruptedException { + + // Wait (optional maxtime) as long as the queue is full + while (isFull()) { + if (maxWaitTime > 0) { + // Wait at most maximum time + wait(maxWaitTime); + + // Timed out or woken; if still full we + // had bad luck and return failure. + if (isFull()) { + return false; + } + } else { + wait(); + } + } + + // Put item in queue + queue[rear] = item; + rear = next(rear); + + // Wake up waiters; NOTE: first waiter will eat item + notifyAll(); + return true; + } + + /** + * Get head; if empty wait until something in queue. + */ + public synchronized Event deQueue() throws InterruptedException { + return deQueue(-1); + } + + /** + * Get head; if empty wait for specified time at max. + */ + public synchronized Event deQueue(long maxWaitTime) throws InterruptedException { + while (isEmpty()) { + if (maxWaitTime >= 0) { + wait(maxWaitTime); + + // Timed out or woken; if still empty we + // had bad luck and return failure. + if (isEmpty()) { + return null; + } + } else { + // Wait indefinitely for something in queue. + wait(); + } + } + + // Dequeue item + Event result = fetchNext(); + + // Notify possible wait()-ing enQueue()-ers + notifyAll(); + + // Return dequeued item + return result; + } + + /** + * Get all queued Events. + */ + public synchronized Event[] deQueueAll(long maxWaitTime) throws InterruptedException { + while (isEmpty()) { + if (maxWaitTime >= 0) { + wait(maxWaitTime); + + // Timed out or woken; if still empty we + // had bad luck and return failure. + if (isEmpty()) { + return null; + } + } else { + // Wait indefinitely for something in queue. + wait(); + } + } + + // Dequeue all items item + Event[] events = new Event[getSize()]; + for (int i = 0; i < events.length; i++) { + events[i] = fetchNext(); + } + + // Notify possible wait()-ing enQueue()-ers + notifyAll(); + + // Return dequeued item + return events; + } + + public synchronized int getSize() { + return (rear >= front) ? (rear - front) : (capacity - front + rear); + } + + /** + * Is the queue empty ? + */ + public synchronized boolean isEmpty() { + return front == rear; + } + + /** + * Is the queue full ? + */ + public synchronized boolean isFull() { + return (next(rear) == front); + } + + /** + * Circular counter. + */ + private int next(int index) { + return (index + 1 < capacity ? index + 1 : 0); + } + + /** + * Circular counter. + */ + private Event fetchNext() { + Event temp = queue[front]; + queue[front] = null; + front = next(front); + return temp; + } + + public static void p(String s) { + System.out.println(s); + } + + public static void main(String[] args) { + EventQueue q = new EventQueue(8); + Event event = new Event("t"); + try { + q.enQueue(event); + p("(1) size = " + q.getSize()); + q.enQueue(event); + p("(2) size = " + q.getSize()); + q.deQueue(); + p("(1) size = " + q.getSize()); + q.deQueue(); + p("(0) size = " + q.getSize()); + + q.enQueue(event); + q.enQueue(event); + q.enQueue(event); + p("(3) size = " + q.getSize()); + q.deQueue(); + p("(2) size = " + q.getSize()); + q.enQueue(event); + q.enQueue(event); + q.enQueue(event); + p("(5) size = " + q.getSize()); + q.enQueue(event); + q.enQueue(event); + p("(7) size = " + q.getSize()); + q.deQueue(); + q.deQueue(); + q.deQueue(); + p("(4) size = " + q.getSize()); + q.deQueue(); + q.deQueue(); + q.deQueue(); + ; + q.deQueue(); + p("(0) size = " + q.getSize()); + + q.enQueue(event); + q.enQueue(event); + q.enQueue(event); + q.enQueue(event); + q.enQueue(event); + p("(5) size = " + q.getSize()); + + q.deQueue(); + q.deQueue(); + q.deQueue(); + ; + q.deQueue(); + p("(1) size = " + q.getSize()); + } catch (InterruptedException ie) { + } + } +} + +/* +* $Log: EventQueue.java,v $ +* Revision 1.3 2007/11/23 14:33:07 justb +* core classes now configurable through factory +* +* Revision 1.2 2005/02/21 11:50:46 justb +* ohase1 of refactoring Subscriber into Session/Controller/Subscriber +* +* Revision 1.1 2005/02/18 10:07:23 justb +* many renamings of classes (make names compact) +* +* Revision 1.6 2005/02/16 12:16:16 justb +* added support for "poll" mode +* +* Revision 1.5 2005/01/13 14:47:15 justb +* control evt: send response on same (control) connection +* +* Revision 1.4 2004/09/03 22:35:37 justb +* Almost complete rewrite, just checking in now +* +* Revision 1.3 2003/08/15 08:37:40 justb +* fix/add Copyright+LGPL file headers and footers +* +* +*/ diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/EventSource.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/EventSource.java index 1de0c4a985..0975bde10e 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/EventSource.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/EventSource.java @@ -1,79 +1,79 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -import javax.servlet.ServletContext; - -/** - * Abstract Event source from which Events are pulled. - * - * @version $Id: EventSource.java,v 1.7 2007/11/23 14:33:07 justb Exp $ - * @author Just van den Broecke - Just Objects © - **/ - -/** - * Interface for specifc Event(Pull/Push)Sources. - */ -public interface EventSource { - /** - * Activate the event source. - */ - public void activate(); - - /** - * Deactivate the event source. - */ - public void passivate(); - - /** - * Halt the event source. - */ - public void stop(); - - /** - * @author thomas genin - * gives access to the servlet context of pushlet to the source class - */ - public void setServletContext(ServletContext srvCtxt); - -} - -/* - * $Log: EventSource.java,v $ - * Revision 1.7 2007/11/23 14:33:07 justb - * core classes now configurable through factory - * - * Revision 1.6 2005/02/21 11:50:46 justb - * ohase1 of refactoring Subscriber into Session/Controller/Subscriber - * - * Revision 1.5 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.4 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.3 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.2 2003/05/18 16:15:08 justb - * support for XML encoded Events - * - * Revision 1.1.1.1 2002/09/24 21:02:31 justb - * import to sourceforge - * - * Revision 1.1.1.1 2002/09/20 22:48:17 justb - * import to SF - * - * Revision 1.1.1.1 2002/09/20 14:19:03 justb - * first import into SF - * - * Revision 1.3 2002/04/15 20:42:41 just - * reformatting and renaming GuardedQueue to EventQueue - * - * Revision 1.2 2000/08/21 20:48:29 just - * added CVS log and id tags plus copyrights - * - * - */ - +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +import javax.servlet.ServletContext; + +/** + * Abstract Event source from which Events are pulled. + * + * @version $Id: EventSource.java,v 1.7 2007/11/23 14:33:07 justb Exp $ + * @author Just van den Broecke - Just Objects © + **/ + +/** + * Interface for specifc Event(Pull/Push)Sources. + */ +public interface EventSource { + /** + * Activate the event source. + */ + public void activate(); + + /** + * Deactivate the event source. + */ + public void passivate(); + + /** + * Halt the event source. + */ + public void stop(); + + /** + * @author thomas genin + * gives access to the servlet context of pushlet to the source class + */ + public void setServletContext(ServletContext srvCtxt); + +} + +/* + * $Log: EventSource.java,v $ + * Revision 1.7 2007/11/23 14:33:07 justb + * core classes now configurable through factory + * + * Revision 1.6 2005/02/21 11:50:46 justb + * ohase1 of refactoring Subscriber into Session/Controller/Subscriber + * + * Revision 1.5 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.4 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.3 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.2 2003/05/18 16:15:08 justb + * support for XML encoded Events + * + * Revision 1.1.1.1 2002/09/24 21:02:31 justb + * import to sourceforge + * + * Revision 1.1.1.1 2002/09/20 22:48:17 justb + * import to SF + * + * Revision 1.1.1.1 2002/09/20 14:19:03 justb + * first import into SF + * + * Revision 1.3 2002/04/15 20:42:41 just + * reformatting and renaming GuardedQueue to EventQueue + * + * Revision 1.2 2000/08/21 20:48:29 just + * added CVS log and id tags plus copyrights + * + * + */ + diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/EventSourceManager.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/EventSourceManager.java index 472b4290cc..119c95fb58 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/EventSourceManager.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/EventSourceManager.java @@ -1,175 +1,175 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -import nl.justobjects.pushlet.util.Log; -import nl.justobjects.pushlet.util.Sys; - -import java.util.Enumeration; -import java.util.Properties; -import java.util.Vector; -import java.io.File; - -import javax.servlet.ServletContext; - -/** - * Maintains lifecycle of event sources. - * - * @author Just van den Broecke - Just Objects © - * @version $Id: EventSourceManager.java,v 1.14 2007/11/10 13:44:02 justb Exp $ - */ -public class EventSourceManager { - private static Vector eventSources = new Vector(0); - private static final String PROPERTIES_FILE = "sources.properties"; - - /** - * Initialize event sources from properties file. - */ - public static void start(String aDirPath,ServletContext srvCtxt) { - // Load Event sources using properties file. - Log.info("EventSourceManager: start"); - - Properties properties = null; - - try { - properties = Sys.loadPropertiesResource(PROPERTIES_FILE); - } catch (Throwable t) { - // Try from provided dir (e.g. WEB_INF/pushlet.properties) - String filePath = aDirPath + File.separator + PROPERTIES_FILE; - Log.info("EventSourceManager: cannot load " + PROPERTIES_FILE + " from classpath, will try from " + filePath); - - try { - properties = Sys.loadPropertiesFile(filePath); - } catch (Throwable t2) { - Log.fatal("EventSourceManager: cannot load properties file from " + filePath, t); - - // Give up - Log.warn("EventSourceManager: not starting local event sources (maybe that is what you want)"); - return; - } - } - - // Create event source collection - eventSources = new Vector(properties.size()); - - // Add the configured sources - for (Enumeration e = properties.keys(); e.hasMoreElements();) { - String nextKey = (String) e.nextElement(); - String nextClass = properties.getProperty(nextKey); - EventSource nextEventSource = null; - try { - nextEventSource = (EventSource) Class.forName(nextClass).newInstance(); - //rajout thomas genin - nextEventSource.setServletContext(srvCtxt); - ////////////////////// - Log.info("created EventSource: key=" + nextKey + " class=" + nextClass); - eventSources.addElement(nextEventSource); - - } catch (Exception ex) { - Log.warn("Cannot create EventSource: class=" + nextClass, ex); - } - } - - activate(); - } - - /** - * Activate all event sources. - */ - public static void activate() { - Log.info("Activating " + eventSources.size() + " EventSources"); - for (int i = 0; i < eventSources.size(); i++) { - ((EventSource) eventSources.elementAt(i)).activate(); - } - Log.info("EventSources activated"); - } - - /** - * Deactivate all event sources. - */ - public static void passivate() { - Log.info("Passivating " + eventSources.size() + " EventSources"); - for (int i = 0; i < eventSources.size(); i++) { - ((EventSource) eventSources.elementAt(i)).passivate(); - } - Log.info("EventSources passivated"); - } - - /** - * Halt event sources. - */ - public static void stop() { - Log.info("Stopping " + eventSources.size() + " EventSources..."); - for (int i = 0; i < eventSources.size(); i++) { - ((EventSource) eventSources.elementAt(i)).stop(); - } - Log.info("EventSources stopped"); - } - -} - -/* - * $Log: EventSourceManager.java,v $ - * Revision 1.14 2007/11/10 13:44:02 justb - * pushlet.properties and sources.properties can now also be put under WEB-INF - * - * Revision 1.13 2005/02/21 11:50:46 justb - * ohase1 of refactoring Subscriber into Session/Controller/Subscriber - * - * Revision 1.12 2005/02/18 12:36:47 justb - * changes for renaming and configurability - * - * Revision 1.11 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.10 2005/02/15 13:29:49 justb - * use Sys.loadPropertiesResource() - * - * Revision 1.9 2004/09/20 22:01:38 justb - * more changes for new protocol - * - * Revision 1.8 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.7 2004/08/15 16:00:15 justb - * enhancements to pull mode - * - * Revision 1.6 2004/08/13 23:36:05 justb - * rewrite of Pullet into Pushlet "pull" mode - * - * Revision 1.5 2004/08/12 13:18:54 justb - * cosmetic changes - * - * Revision 1.4 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.3 2003/08/12 09:41:35 justb - * replace static initalizer with explicit init() - * - * Revision 1.2 2003/05/18 16:15:08 justb - * support for XML encoded Events - * - * Revision 1.1.1.1 2002/09/24 21:02:31 justb - * import to sourceforge - * - * Revision 1.1.1.1 2002/09/20 22:48:17 justb - * import to SF - * - * Revision 1.1.1.1 2002/09/20 14:19:03 justb - * first import into SF - * - * Revision 1.5 2002/04/15 20:42:41 just - * reformatting and renaming GuardedQueue to EventQueue - * - * Revision 1.4 2000/10/30 14:15:47 just - * no message - * - * Revision 1.3 2000/08/31 08:26:54 just - * Changed classloader that loads eventsources.properties to use EventSourceManager's classloader - * - * Revision 1.2 2000/08/21 20:48:29 just - * added CVS log and id tags plus copyrights - * - * - */ +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +import nl.justobjects.pushlet.util.Log; +import nl.justobjects.pushlet.util.Sys; + +import java.util.Enumeration; +import java.util.Properties; +import java.util.Vector; +import java.io.File; + +import javax.servlet.ServletContext; + +/** + * Maintains lifecycle of event sources. + * + * @author Just van den Broecke - Just Objects © + * @version $Id: EventSourceManager.java,v 1.14 2007/11/10 13:44:02 justb Exp $ + */ +public class EventSourceManager { + private static Vector eventSources = new Vector(0); + private static final String PROPERTIES_FILE = "sources.properties"; + + /** + * Initialize event sources from properties file. + */ + public static void start(String aDirPath,ServletContext srvCtxt) { + // Load Event sources using properties file. + Log.info("EventSourceManager: start"); + + Properties properties = null; + + try { + properties = Sys.loadPropertiesResource(PROPERTIES_FILE); + } catch (Throwable t) { + // Try from provided dir (e.g. WEB_INF/pushlet.properties) + String filePath = aDirPath + File.separator + PROPERTIES_FILE; + Log.info("EventSourceManager: cannot load " + PROPERTIES_FILE + " from classpath, will try from " + filePath); + + try { + properties = Sys.loadPropertiesFile(filePath); + } catch (Throwable t2) { + Log.fatal("EventSourceManager: cannot load properties file from " + filePath, t); + + // Give up + Log.warn("EventSourceManager: not starting local event sources (maybe that is what you want)"); + return; + } + } + + // Create event source collection + eventSources = new Vector(properties.size()); + + // Add the configured sources + for (Enumeration e = properties.keys(); e.hasMoreElements();) { + String nextKey = (String) e.nextElement(); + String nextClass = properties.getProperty(nextKey); + EventSource nextEventSource = null; + try { + nextEventSource = (EventSource) Class.forName(nextClass).newInstance(); + //rajout thomas genin + nextEventSource.setServletContext(srvCtxt); + ////////////////////// + Log.info("created EventSource: key=" + nextKey + " class=" + nextClass); + eventSources.addElement(nextEventSource); + + } catch (Exception ex) { + Log.warn("Cannot create EventSource: class=" + nextClass, ex); + } + } + + activate(); + } + + /** + * Activate all event sources. + */ + public static void activate() { + Log.info("Activating " + eventSources.size() + " EventSources"); + for (int i = 0; i < eventSources.size(); i++) { + ((EventSource) eventSources.elementAt(i)).activate(); + } + Log.info("EventSources activated"); + } + + /** + * Deactivate all event sources. + */ + public static void passivate() { + Log.info("Passivating " + eventSources.size() + " EventSources"); + for (int i = 0; i < eventSources.size(); i++) { + ((EventSource) eventSources.elementAt(i)).passivate(); + } + Log.info("EventSources passivated"); + } + + /** + * Halt event sources. + */ + public static void stop() { + Log.info("Stopping " + eventSources.size() + " EventSources..."); + for (int i = 0; i < eventSources.size(); i++) { + ((EventSource) eventSources.elementAt(i)).stop(); + } + Log.info("EventSources stopped"); + } + +} + +/* + * $Log: EventSourceManager.java,v $ + * Revision 1.14 2007/11/10 13:44:02 justb + * pushlet.properties and sources.properties can now also be put under WEB-INF + * + * Revision 1.13 2005/02/21 11:50:46 justb + * ohase1 of refactoring Subscriber into Session/Controller/Subscriber + * + * Revision 1.12 2005/02/18 12:36:47 justb + * changes for renaming and configurability + * + * Revision 1.11 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.10 2005/02/15 13:29:49 justb + * use Sys.loadPropertiesResource() + * + * Revision 1.9 2004/09/20 22:01:38 justb + * more changes for new protocol + * + * Revision 1.8 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.7 2004/08/15 16:00:15 justb + * enhancements to pull mode + * + * Revision 1.6 2004/08/13 23:36:05 justb + * rewrite of Pullet into Pushlet "pull" mode + * + * Revision 1.5 2004/08/12 13:18:54 justb + * cosmetic changes + * + * Revision 1.4 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.3 2003/08/12 09:41:35 justb + * replace static initalizer with explicit init() + * + * Revision 1.2 2003/05/18 16:15:08 justb + * support for XML encoded Events + * + * Revision 1.1.1.1 2002/09/24 21:02:31 justb + * import to sourceforge + * + * Revision 1.1.1.1 2002/09/20 22:48:17 justb + * import to SF + * + * Revision 1.1.1.1 2002/09/20 14:19:03 justb + * first import into SF + * + * Revision 1.5 2002/04/15 20:42:41 just + * reformatting and renaming GuardedQueue to EventQueue + * + * Revision 1.4 2000/10/30 14:15:47 just + * no message + * + * Revision 1.3 2000/08/31 08:26:54 just + * Changed classloader that loads eventsources.properties to use EventSourceManager's classloader + * + * Revision 1.2 2000/08/21 20:48:29 just + * added CVS log and id tags plus copyrights + * + * + */ diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/SerializedAdapter.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/SerializedAdapter.java index 462a4dd5c2..501a6ba3ce 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/SerializedAdapter.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/SerializedAdapter.java @@ -1,99 +1,99 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.ObjectOutputStream; - -/** - * Implementation of ClientAdapter that sends Events as serialized objects. - *

- * NOTE: You are discouraged to use this adapter, since it is Java-only - * and may have JVM-specific problems. Far better choice is to use XML - * and the XMLAdapter. - * - * @author Just van den Broecke - Just Objects © - * @version $Id: SerializedAdapter.java,v 1.4 2007/11/23 14:33:07 justb Exp $ - */ -class SerializedAdapter implements ClientAdapter { - private ObjectOutputStream out = null; - public static final String CONTENT_TYPE = "application/x-java-serialized-object"; - private HttpServletResponse servletRsp; - - /** - * Initialize. - */ - public SerializedAdapter(HttpServletResponse aServletResponse) { - servletRsp = aServletResponse; - } - - public void start() throws IOException { - - servletRsp.setContentType(CONTENT_TYPE); - - // Use a serialized object output stream - out = new ObjectOutputStream(servletRsp.getOutputStream()); - - // Don't need this further - servletRsp = null; - } - - /** - * Push Event to client. - */ - public void push(Event anEvent) throws IOException { - out.writeObject(anEvent); - - out.flush(); - } - - - public void stop() throws IOException { - } -} - -/* - * $Log: SerializedAdapter.java,v $ - * Revision 1.4 2007/11/23 14:33:07 justb - * core classes now configurable through factory - * - * Revision 1.3 2005/02/28 12:45:59 justb - * introduced Command class - * - * Revision 1.2 2005/02/21 11:50:46 justb - * ohase1 of refactoring Subscriber into Session/Controller/Subscriber - * - * Revision 1.1 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.4 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.3 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.2 2003/05/18 16:13:48 justb - * fixed blocking for java.net.URL with HTTP/1.1 (JVMs > 1.1) - * - * Revision 1.1.1.1 2002/09/24 21:02:31 justb - * import to sourceforge - * - * Revision 1.1.1.1 2002/09/20 22:48:18 justb - * import to SF - * - * Revision 1.1.1.1 2002/09/20 14:19:03 justb - * first import into SF - * - * Revision 1.5 2002/04/15 20:42:41 just - * reformatting and renaming GuardedQueue to EventQueue - * - * Revision 1.4 2000/12/27 22:39:35 just - * no message - * - * Revision 1.3 2000/08/21 20:48:29 just - * added CVS log and id tags plus copyrights - * - * - */ +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.ObjectOutputStream; + +/** + * Implementation of ClientAdapter that sends Events as serialized objects. + *

+ * NOTE: You are discouraged to use this adapter, since it is Java-only + * and may have JVM-specific problems. Far better choice is to use XML + * and the XMLAdapter. + * + * @author Just van den Broecke - Just Objects © + * @version $Id: SerializedAdapter.java,v 1.4 2007/11/23 14:33:07 justb Exp $ + */ +class SerializedAdapter implements ClientAdapter { + private ObjectOutputStream out = null; + public static final String CONTENT_TYPE = "application/x-java-serialized-object"; + private HttpServletResponse servletRsp; + + /** + * Initialize. + */ + public SerializedAdapter(HttpServletResponse aServletResponse) { + servletRsp = aServletResponse; + } + + public void start() throws IOException { + + servletRsp.setContentType(CONTENT_TYPE); + + // Use a serialized object output stream + out = new ObjectOutputStream(servletRsp.getOutputStream()); + + // Don't need this further + servletRsp = null; + } + + /** + * Push Event to client. + */ + public void push(Event anEvent) throws IOException { + out.writeObject(anEvent); + + out.flush(); + } + + + public void stop() throws IOException { + } +} + +/* + * $Log: SerializedAdapter.java,v $ + * Revision 1.4 2007/11/23 14:33:07 justb + * core classes now configurable through factory + * + * Revision 1.3 2005/02/28 12:45:59 justb + * introduced Command class + * + * Revision 1.2 2005/02/21 11:50:46 justb + * ohase1 of refactoring Subscriber into Session/Controller/Subscriber + * + * Revision 1.1 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.4 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.3 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.2 2003/05/18 16:13:48 justb + * fixed blocking for java.net.URL with HTTP/1.1 (JVMs > 1.1) + * + * Revision 1.1.1.1 2002/09/24 21:02:31 justb + * import to sourceforge + * + * Revision 1.1.1.1 2002/09/20 22:48:18 justb + * import to SF + * + * Revision 1.1.1.1 2002/09/20 14:19:03 justb + * first import into SF + * + * Revision 1.5 2002/04/15 20:42:41 just + * reformatting and renaming GuardedQueue to EventQueue + * + * Revision 1.4 2000/12/27 22:39:35 just + * no message + * + * Revision 1.3 2000/08/21 20:48:29 just + * added CVS log and id tags plus copyrights + * + * + */ diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/Subscriber.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/Subscriber.java index 39f5ba0198..dca30b6bfd 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/Subscriber.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/Subscriber.java @@ -1,469 +1,469 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -import nl.justobjects.pushlet.util.PushletException; -import nl.justobjects.pushlet.util.Rand; -import nl.justobjects.pushlet.util.Sys; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.net.URLEncoder; - -/** - * Handles data channel between dispatcher and client. - * - * @author Just van den Broecke - Just Objects © - * @version $Id: Subscriber.java,v 1.26 2007/11/23 14:33:07 justb Exp $ - */ -public class Subscriber implements Protocol, ConfigDefs { - private Session session; - - /** - * Blocking queue. - */ - private EventQueue eventQueue = new EventQueue(Config.getIntProperty(QUEUE_SIZE)); - - /** - * URL to be used in refresh requests in pull/poll modes. - */ - private long queueReadTimeoutMillis = Config.getLongProperty(QUEUE_READ_TIMEOUT_MILLIS); - private long queueWriteTimeoutMillis = Config.getLongProperty(QUEUE_WRITE_TIMEOUT_MILLIS); - private long refreshTimeoutMillis = Config.getLongProperty(PULL_REFRESH_TIMEOUT_MILLIS); - volatile long lastAlive = Sys.now(); - - /** - * Map of active subscriptions, keyed by their subscription id. - */ - private Map subscriptions = Collections.synchronizedMap(new HashMap(3)); - - /** - * Are we able to accept/send events ?. - */ - private volatile boolean active; - - /** - * Transfer mode (stream, pull, poll). - */ - private String mode; - - - /** - * Protected constructor as we create through factory method. - */ - protected Subscriber() { - } - - /** - * Create instance through factory method. - * - * @param aSession the parent Session - * @return a Subscriber object (or derived) - * @throws PushletException exception, usually misconfiguration - */ - public static Subscriber create(Session aSession) throws PushletException { - Subscriber subscriber; - try { - subscriber = (Subscriber) Config.getClass(SUBSCRIBER_CLASS, "nl.justobjects.pushlet.core.Subscriber").newInstance(); - } catch (Throwable t) { - throw new PushletException("Cannot instantiate Subscriber from config", t); - } - - subscriber.session = aSession; - return subscriber; - } - - public void start() { - active = true; - } - - public void stop() { - removeSubscriptions(); - active = false; - } - - public void bailout() { - session.stop(); - } - - /** - * Are we still active to handle events. - */ - public boolean isActive() { - return active; - } - - /** - * Return client session. - */ - public Session getSession() { - return session; - } - - /** - * Get (session) id. - */ - public String getId() { - return session.getId(); - } - - /** - * Return subscriptions. - */ - public Subscription[] getSubscriptions() { - // todo: Optimize - return (Subscription[]) subscriptions.values().toArray(new Subscription[0]); - } - - /** - * Add a subscription. - */ - public Subscription addSubscription(String aSubject, String aLabel) throws PushletException { - Subscription subscription = Subscription.create(aSubject, aLabel); - subscriptions.put(subscription.getId(), subscription); - info("Subscription added subject=" + aSubject + " sid=" + subscription.getId() + " label=" + aLabel); - return subscription; - } - - /** - * Remove a subscription. - */ - public Subscription removeSubscription(String aSubscriptionId) { - Subscription subscription = (Subscription) subscriptions.remove(aSubscriptionId); - if (subscription == null) { - warn("No subscription found sid=" + aSubscriptionId); - return null; - } - info("Subscription removed subject=" + subscription.getSubject() + " sid=" + subscription.getId() + " label=" + subscription.getLabel()); - return subscription; - } - - /** - * Remove all subscriptions. - */ - public void removeSubscriptions() { - subscriptions.clear(); - } - - public String getMode() { - return mode; - } - - public void setMode(String aMode) { - mode = aMode; - } - - public long getRefreshTimeMillis() { - String minWaitProperty = PULL_REFRESH_WAIT_MIN_MILLIS; - String maxWaitProperty = PULL_REFRESH_WAIT_MAX_MILLIS; - if (mode.equals((MODE_POLL))) { - minWaitProperty = POLL_REFRESH_WAIT_MIN_MILLIS; - maxWaitProperty = POLL_REFRESH_WAIT_MAX_MILLIS; - - } - return Rand.randomLong(Config.getLongProperty(minWaitProperty), - Config.getLongProperty(maxWaitProperty)); - } - - /** - * Get events from queue and push to client. - */ - public void fetchEvents(Command aCommand) throws PushletException { - - String refreshURL = aCommand.httpReq.getRequestURI() + "?" + P_ID + "=" + session.getId() + "&" + P_EVENT + "=" + E_REFRESH; - - // This is the only thing required to support "poll" mode - if (mode.equals(MODE_POLL)) { - queueReadTimeoutMillis = 0; - refreshTimeoutMillis = Config.getLongProperty(POLL_REFRESH_TIMEOUT_MILLIS); - } - - // Required for fast bailout (tomcat) - aCommand.httpRsp.setBufferSize(128); - - // Try to prevent caching in any form. - aCommand.sendResponseHeaders(); - - // Let clientAdapter determine how to send event - ClientAdapter clientAdapter = aCommand.getClientAdapter(); - Event responseEvent = aCommand.getResponseEvent(); - try { - clientAdapter.start(); - - // Send first event (usually hb-ack or listen-ack) - clientAdapter.push(responseEvent); - - // In pull/poll mode and when response is listen-ack or join-listen-ack, - // return and force refresh immediately - // such that the client recieves response immediately over this channel. - // This is usually when loading the browser app for the first time - if ((mode.equals(MODE_POLL) || mode.equals(MODE_PULL)) - && responseEvent.getEventType().endsWith(Protocol.E_LISTEN_ACK)) { - sendRefresh(clientAdapter, refreshURL); - - // We should come back later with refresh event... - return; - } - } catch (Throwable t) { - bailout(); - return; - } - - - Event[] events = null; - - // Main loop: as long as connected, get events and push to client - long eventSeqNr = 1; - while (isActive()) { - // Indicate we are still alive - lastAlive = Sys.now(); - - // Update session time to live - session.kick(); - - // Get next events; blocks until timeout or entire contents - // of event queue is returned. Note that "poll" mode - // will return immediately when queue is empty. - try { - // Put heartbeat in queue when starting to listen in stream mode - // This speeds up the return of *_LISTEN_ACK - if (mode.equals(MODE_STREAM) && eventSeqNr == 1) { - eventQueue.enQueue(new Event(E_HEARTBEAT)); - } - - events = eventQueue.deQueueAll(queueReadTimeoutMillis); - } catch (InterruptedException ie) { - warn("interrupted"); - bailout(); - } - - // Send heartbeat when no events received - if (events == null) { - events = new Event[1]; - events[0] = new Event(E_HEARTBEAT); - } - - // ASSERT: one or more events available - - // Send events to client using adapter - // debug("received event count=" + events.length); - for (int i = 0; i < events.length; i++) { - // Check for abort event - if (events[i].getEventType().equals(E_ABORT)) { - warn("Aborting Subscriber"); - bailout(); - } - - // Push next Event to client - try { - // Set sequence number - events[i].setField(P_SEQ, eventSeqNr++); - - // Push to client through client adapter - clientAdapter.push(events[i]); - } catch (Throwable t) { - bailout(); - return; - } - } - - // Force client refresh request in pull or poll modes - if (mode.equals(MODE_PULL) || mode.equals(MODE_POLL)) { - sendRefresh(clientAdapter, refreshURL); - - // Always leave loop in pull/poll mode - break; - } - } - } - - /** - * Determine if we should receive event. - */ - public Subscription match(Event event) { - Subscription[] subscriptions = getSubscriptions(); - for (int i = 0; i < subscriptions.length; i++) { - if (subscriptions[i].match(event)) { - return subscriptions[i]; - } - } - return null; - } - - /** - * Event from Dispatcher: enqueue it. - */ - public void onEvent(Event theEvent) { - if (!isActive()) { - return; - } - - // p("send: queue event: "+theEvent.getSubject()); - - // Check if we had any active continuation for at - // least 'timeOut' millisecs. If the client has left this - // instance there would be no way of knowing otherwise. - long now = Sys.now(); - if (now - lastAlive > refreshTimeoutMillis) { - warn("not alive for at least: " + refreshTimeoutMillis + "ms, leaving..."); - bailout(); - return; - } - - // Put event in queue; leave if queue full - try { - if (!eventQueue.enQueue(theEvent, queueWriteTimeoutMillis)) { - warn("queue full, bailing out..."); - bailout(); - } - - // ASSERTION : Event in queue. - // see fetchEvents() where Events are dequeued and pushed to the client. - } catch (InterruptedException ie) { - bailout(); - } - - } - - /** - * Send refresh command to pull/poll clients. - */ - protected void sendRefresh(ClientAdapter aClientAdapter, String aRefreshURL) { - Event refreshEvent = new Event(E_REFRESH); - - // Set wait time and url for refresh - refreshEvent.setField(P_WAIT, "" + getRefreshTimeMillis()); - refreshEvent.setField(P_URL, aRefreshURL); - - try { - // Push to client through client adapter - aClientAdapter.push(refreshEvent); - - // Stop this round until refresh event - aClientAdapter.stop(); - } catch (Throwable t) { - // Leave on any exception - bailout(); - } - } - - /** - * Info. - */ - protected void info(String s) { - session.info("[Subscriber] " + s); - } - - /** - * Exceptional print util. - */ - protected void warn(String s) { - session.warn("[Subscriber] " + s); - } - - /** - * Exceptional print util. - */ - protected void debug(String s) { - session.debug("[Subscriber] " + s); - } - - - public String toString() { - return session.toString(); - } -} - -/* - * $Log: Subscriber.java,v $ - * Revision 1.26 2007/11/23 14:33:07 justb - * core classes now configurable through factory - * - * Revision 1.25 2007/11/10 15:53:15 justb - * put heartbeat in queue when start fetching events in stream-mode - * - * Revision 1.24 2006/10/19 12:33:40 justb - * add atomic join-listen support (one request) - * - * Revision 1.22 2006/05/06 00:06:28 justb - * first rough version AJAX client - * - * Revision 1.21 2005/02/28 12:45:59 justb - * introduced Command class - * - * Revision 1.20 2005/02/21 16:59:09 justb - * SessionManager and session lease introduced - * - * Revision 1.19 2005/02/21 12:32:28 justb - * fixed publish event in Controller - * - * Revision 1.18 2005/02/21 11:50:46 justb - * ohase1 of refactoring Subscriber into Session/Controller/Subscriber - * - * Revision 1.17 2005/02/20 13:05:32 justb - * removed the Postlet (integrated in Pushlet protocol) - * - * Revision 1.16 2005/02/18 12:36:47 justb - * changes for renaming and configurability - * - * Revision 1.15 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.14 2005/02/18 09:54:15 justb - * refactor: rename Publisher Dispatcher and single Subscriber class - * - * Revision 1.13 2005/02/16 14:39:34 justb - * fixed leave handling and added "poll" mode - * - * Revision 1.12 2005/01/24 13:42:00 justb - * new protocol changes (p_listen) - * - * Revision 1.11 2005/01/13 14:47:15 justb - * control evt: send response on same (control) connection - * - * Revision 1.10 2004/10/24 20:50:35 justb - * refine subscription with label and sending sid and label on events - * - * Revision 1.9 2004/10/24 12:58:18 justb - * revised client and test classes for new protocol - * - * Revision 1.8 2004/09/26 21:39:43 justb - * allow multiple subscriptions and out-of-band requests - * - * Revision 1.7 2004/09/20 22:01:38 justb - * more changes for new protocol - * - * Revision 1.6 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.5 2004/08/13 23:36:05 justb - * rewrite of Pullet into Pushlet "pull" mode - * - * Revision 1.4 2004/03/10 14:01:55 justb - * formatting and *Subscriber refactoring - * - * Revision 1.3 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.2 2003/05/18 16:15:08 justb - * support for XML encoded Events - * - * Revision 1.1.1.1 2002/09/24 21:02:32 justb - * import to sourceforge - * - * Revision 1.1.1.1 2002/09/20 22:48:18 justb - * import to SF - * - * Revision 1.1.1.1 2002/09/20 14:19:04 justb - * first import into SF - * - * Revision 1.3 2002/04/15 20:42:41 just - * reformatting and renaming GuardedQueue to EventQueue - * - * Revision 1.2 2000/08/21 20:48:29 just - * added CVS log and id tags plus copyrights - * - * - */ +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +import nl.justobjects.pushlet.util.PushletException; +import nl.justobjects.pushlet.util.Rand; +import nl.justobjects.pushlet.util.Sys; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.net.URLEncoder; + +/** + * Handles data channel between dispatcher and client. + * + * @author Just van den Broecke - Just Objects © + * @version $Id: Subscriber.java,v 1.26 2007/11/23 14:33:07 justb Exp $ + */ +public class Subscriber implements Protocol, ConfigDefs { + private Session session; + + /** + * Blocking queue. + */ + private EventQueue eventQueue = new EventQueue(Config.getIntProperty(QUEUE_SIZE)); + + /** + * URL to be used in refresh requests in pull/poll modes. + */ + private long queueReadTimeoutMillis = Config.getLongProperty(QUEUE_READ_TIMEOUT_MILLIS); + private long queueWriteTimeoutMillis = Config.getLongProperty(QUEUE_WRITE_TIMEOUT_MILLIS); + private long refreshTimeoutMillis = Config.getLongProperty(PULL_REFRESH_TIMEOUT_MILLIS); + volatile long lastAlive = Sys.now(); + + /** + * Map of active subscriptions, keyed by their subscription id. + */ + private Map subscriptions = Collections.synchronizedMap(new HashMap(3)); + + /** + * Are we able to accept/send events ?. + */ + private volatile boolean active; + + /** + * Transfer mode (stream, pull, poll). + */ + private String mode; + + + /** + * Protected constructor as we create through factory method. + */ + protected Subscriber() { + } + + /** + * Create instance through factory method. + * + * @param aSession the parent Session + * @return a Subscriber object (or derived) + * @throws PushletException exception, usually misconfiguration + */ + public static Subscriber create(Session aSession) throws PushletException { + Subscriber subscriber; + try { + subscriber = (Subscriber) Config.getClass(SUBSCRIBER_CLASS, "nl.justobjects.pushlet.core.Subscriber").newInstance(); + } catch (Throwable t) { + throw new PushletException("Cannot instantiate Subscriber from config", t); + } + + subscriber.session = aSession; + return subscriber; + } + + public void start() { + active = true; + } + + public void stop() { + removeSubscriptions(); + active = false; + } + + public void bailout() { + session.stop(); + } + + /** + * Are we still active to handle events. + */ + public boolean isActive() { + return active; + } + + /** + * Return client session. + */ + public Session getSession() { + return session; + } + + /** + * Get (session) id. + */ + public String getId() { + return session.getId(); + } + + /** + * Return subscriptions. + */ + public Subscription[] getSubscriptions() { + // todo: Optimize + return (Subscription[]) subscriptions.values().toArray(new Subscription[0]); + } + + /** + * Add a subscription. + */ + public Subscription addSubscription(String aSubject, String aLabel) throws PushletException { + Subscription subscription = Subscription.create(aSubject, aLabel); + subscriptions.put(subscription.getId(), subscription); + info("Subscription added subject=" + aSubject + " sid=" + subscription.getId() + " label=" + aLabel); + return subscription; + } + + /** + * Remove a subscription. + */ + public Subscription removeSubscription(String aSubscriptionId) { + Subscription subscription = (Subscription) subscriptions.remove(aSubscriptionId); + if (subscription == null) { + warn("No subscription found sid=" + aSubscriptionId); + return null; + } + info("Subscription removed subject=" + subscription.getSubject() + " sid=" + subscription.getId() + " label=" + subscription.getLabel()); + return subscription; + } + + /** + * Remove all subscriptions. + */ + public void removeSubscriptions() { + subscriptions.clear(); + } + + public String getMode() { + return mode; + } + + public void setMode(String aMode) { + mode = aMode; + } + + public long getRefreshTimeMillis() { + String minWaitProperty = PULL_REFRESH_WAIT_MIN_MILLIS; + String maxWaitProperty = PULL_REFRESH_WAIT_MAX_MILLIS; + if (mode.equals((MODE_POLL))) { + minWaitProperty = POLL_REFRESH_WAIT_MIN_MILLIS; + maxWaitProperty = POLL_REFRESH_WAIT_MAX_MILLIS; + + } + return Rand.randomLong(Config.getLongProperty(minWaitProperty), + Config.getLongProperty(maxWaitProperty)); + } + + /** + * Get events from queue and push to client. + */ + public void fetchEvents(Command aCommand) throws PushletException { + + String refreshURL = aCommand.httpReq.getRequestURI() + "?" + P_ID + "=" + session.getId() + "&" + P_EVENT + "=" + E_REFRESH; + + // This is the only thing required to support "poll" mode + if (mode.equals(MODE_POLL)) { + queueReadTimeoutMillis = 0; + refreshTimeoutMillis = Config.getLongProperty(POLL_REFRESH_TIMEOUT_MILLIS); + } + + // Required for fast bailout (tomcat) + aCommand.httpRsp.setBufferSize(128); + + // Try to prevent caching in any form. + aCommand.sendResponseHeaders(); + + // Let clientAdapter determine how to send event + ClientAdapter clientAdapter = aCommand.getClientAdapter(); + Event responseEvent = aCommand.getResponseEvent(); + try { + clientAdapter.start(); + + // Send first event (usually hb-ack or listen-ack) + clientAdapter.push(responseEvent); + + // In pull/poll mode and when response is listen-ack or join-listen-ack, + // return and force refresh immediately + // such that the client recieves response immediately over this channel. + // This is usually when loading the browser app for the first time + if ((mode.equals(MODE_POLL) || mode.equals(MODE_PULL)) + && responseEvent.getEventType().endsWith(Protocol.E_LISTEN_ACK)) { + sendRefresh(clientAdapter, refreshURL); + + // We should come back later with refresh event... + return; + } + } catch (Throwable t) { + bailout(); + return; + } + + + Event[] events = null; + + // Main loop: as long as connected, get events and push to client + long eventSeqNr = 1; + while (isActive()) { + // Indicate we are still alive + lastAlive = Sys.now(); + + // Update session time to live + session.kick(); + + // Get next events; blocks until timeout or entire contents + // of event queue is returned. Note that "poll" mode + // will return immediately when queue is empty. + try { + // Put heartbeat in queue when starting to listen in stream mode + // This speeds up the return of *_LISTEN_ACK + if (mode.equals(MODE_STREAM) && eventSeqNr == 1) { + eventQueue.enQueue(new Event(E_HEARTBEAT)); + } + + events = eventQueue.deQueueAll(queueReadTimeoutMillis); + } catch (InterruptedException ie) { + warn("interrupted"); + bailout(); + } + + // Send heartbeat when no events received + if (events == null) { + events = new Event[1]; + events[0] = new Event(E_HEARTBEAT); + } + + // ASSERT: one or more events available + + // Send events to client using adapter + // debug("received event count=" + events.length); + for (int i = 0; i < events.length; i++) { + // Check for abort event + if (events[i].getEventType().equals(E_ABORT)) { + warn("Aborting Subscriber"); + bailout(); + } + + // Push next Event to client + try { + // Set sequence number + events[i].setField(P_SEQ, eventSeqNr++); + + // Push to client through client adapter + clientAdapter.push(events[i]); + } catch (Throwable t) { + bailout(); + return; + } + } + + // Force client refresh request in pull or poll modes + if (mode.equals(MODE_PULL) || mode.equals(MODE_POLL)) { + sendRefresh(clientAdapter, refreshURL); + + // Always leave loop in pull/poll mode + break; + } + } + } + + /** + * Determine if we should receive event. + */ + public Subscription match(Event event) { + Subscription[] subscriptions = getSubscriptions(); + for (int i = 0; i < subscriptions.length; i++) { + if (subscriptions[i].match(event)) { + return subscriptions[i]; + } + } + return null; + } + + /** + * Event from Dispatcher: enqueue it. + */ + public void onEvent(Event theEvent) { + if (!isActive()) { + return; + } + + // p("send: queue event: "+theEvent.getSubject()); + + // Check if we had any active continuation for at + // least 'timeOut' millisecs. If the client has left this + // instance there would be no way of knowing otherwise. + long now = Sys.now(); + if (now - lastAlive > refreshTimeoutMillis) { + warn("not alive for at least: " + refreshTimeoutMillis + "ms, leaving..."); + bailout(); + return; + } + + // Put event in queue; leave if queue full + try { + if (!eventQueue.enQueue(theEvent, queueWriteTimeoutMillis)) { + warn("queue full, bailing out..."); + bailout(); + } + + // ASSERTION : Event in queue. + // see fetchEvents() where Events are dequeued and pushed to the client. + } catch (InterruptedException ie) { + bailout(); + } + + } + + /** + * Send refresh command to pull/poll clients. + */ + protected void sendRefresh(ClientAdapter aClientAdapter, String aRefreshURL) { + Event refreshEvent = new Event(E_REFRESH); + + // Set wait time and url for refresh + refreshEvent.setField(P_WAIT, "" + getRefreshTimeMillis()); + refreshEvent.setField(P_URL, aRefreshURL); + + try { + // Push to client through client adapter + aClientAdapter.push(refreshEvent); + + // Stop this round until refresh event + aClientAdapter.stop(); + } catch (Throwable t) { + // Leave on any exception + bailout(); + } + } + + /** + * Info. + */ + protected void info(String s) { + session.info("[Subscriber] " + s); + } + + /** + * Exceptional print util. + */ + protected void warn(String s) { + session.warn("[Subscriber] " + s); + } + + /** + * Exceptional print util. + */ + protected void debug(String s) { + session.debug("[Subscriber] " + s); + } + + + public String toString() { + return session.toString(); + } +} + +/* + * $Log: Subscriber.java,v $ + * Revision 1.26 2007/11/23 14:33:07 justb + * core classes now configurable through factory + * + * Revision 1.25 2007/11/10 15:53:15 justb + * put heartbeat in queue when start fetching events in stream-mode + * + * Revision 1.24 2006/10/19 12:33:40 justb + * add atomic join-listen support (one request) + * + * Revision 1.22 2006/05/06 00:06:28 justb + * first rough version AJAX client + * + * Revision 1.21 2005/02/28 12:45:59 justb + * introduced Command class + * + * Revision 1.20 2005/02/21 16:59:09 justb + * SessionManager and session lease introduced + * + * Revision 1.19 2005/02/21 12:32:28 justb + * fixed publish event in Controller + * + * Revision 1.18 2005/02/21 11:50:46 justb + * ohase1 of refactoring Subscriber into Session/Controller/Subscriber + * + * Revision 1.17 2005/02/20 13:05:32 justb + * removed the Postlet (integrated in Pushlet protocol) + * + * Revision 1.16 2005/02/18 12:36:47 justb + * changes for renaming and configurability + * + * Revision 1.15 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.14 2005/02/18 09:54:15 justb + * refactor: rename Publisher Dispatcher and single Subscriber class + * + * Revision 1.13 2005/02/16 14:39:34 justb + * fixed leave handling and added "poll" mode + * + * Revision 1.12 2005/01/24 13:42:00 justb + * new protocol changes (p_listen) + * + * Revision 1.11 2005/01/13 14:47:15 justb + * control evt: send response on same (control) connection + * + * Revision 1.10 2004/10/24 20:50:35 justb + * refine subscription with label and sending sid and label on events + * + * Revision 1.9 2004/10/24 12:58:18 justb + * revised client and test classes for new protocol + * + * Revision 1.8 2004/09/26 21:39:43 justb + * allow multiple subscriptions and out-of-band requests + * + * Revision 1.7 2004/09/20 22:01:38 justb + * more changes for new protocol + * + * Revision 1.6 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.5 2004/08/13 23:36:05 justb + * rewrite of Pullet into Pushlet "pull" mode + * + * Revision 1.4 2004/03/10 14:01:55 justb + * formatting and *Subscriber refactoring + * + * Revision 1.3 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.2 2003/05/18 16:15:08 justb + * support for XML encoded Events + * + * Revision 1.1.1.1 2002/09/24 21:02:32 justb + * import to sourceforge + * + * Revision 1.1.1.1 2002/09/20 22:48:18 justb + * import to SF + * + * Revision 1.1.1.1 2002/09/20 14:19:04 justb + * first import into SF + * + * Revision 1.3 2002/04/15 20:42:41 just + * reformatting and renaming GuardedQueue to EventQueue + * + * Revision 1.2 2000/08/21 20:48:29 just + * added CVS log and id tags plus copyrights + * + * + */ diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/XMLAdapter.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/XMLAdapter.java index 15d7096e59..70a9c3c47d 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/XMLAdapter.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/core/XMLAdapter.java @@ -1,137 +1,137 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -import nl.justobjects.pushlet.util.Log; - -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; - -/** - * ClientAdapter that sends Events as XML. - * - * @author Just van den Broecke - Just Objects © - * @version $Id: XMLAdapter.java,v 1.7 2007/11/09 13:15:35 justb Exp $ - */ -class XMLAdapter implements ClientAdapter { - /** - * Header for strict XML - */ - // public static final String XML_HEAD = "\n"; - private String contentType = "text/plain;charset=UTF-8"; - private ServletOutputStream out = null; - private HttpServletResponse servletRsp; - private boolean strictXML; - - /** - * Initialize. - */ - public XMLAdapter(HttpServletResponse aServletResponse) { - this(aServletResponse, false); - } - - /** - * Initialize. - */ - public XMLAdapter(HttpServletResponse aServletResponse, boolean useStrictXML) { - servletRsp = aServletResponse; - - // Strict XML implies returning a complete XML document - strictXML = useStrictXML; - if (strictXML) { - contentType = "text/xml;charset=UTF-8"; - } - } - - public void start() throws IOException { - - // If content type is plain text - // then this is not a complete XML document, but rather - // a stream of XML documents where each document is - // an Event. In strict XML mode a complete document is returned. - servletRsp.setContentType(contentType); - - out = servletRsp.getOutputStream(); - - // Don't need this further - servletRsp = null; - - // Start XML document if strict XML mode - if (strictXML) { - out.print(""); - } - } - - /** - * Force client to refresh the request. - */ - public void push(Event anEvent) throws IOException { - debug("event=" + anEvent); - - // Send the event as XML to the client and flush. - out.print(anEvent.toXML(strictXML)); - out.flush(); - } - - /** - * No action. - */ - public void stop() throws IOException { - // Close XML document if strict XML mode - if (strictXML) { - out.print(""); - out.flush(); - } - } - - private void debug(String s) { - Log.debug("[XMLAdapter]" + s); - } -} - -/* - * $Log: XMLAdapter.java,v $ - * Revision 1.7 2007/11/09 13:15:35 justb - * add charset=UTF-8 in returned HTTP content types - * - * Revision 1.6 2006/05/15 11:52:53 justb - * updates mainly for AJAX client - * - * Revision 1.5 2006/05/06 00:06:28 justb - * first rough version AJAX client - * - * Revision 1.4 2005/05/06 19:44:00 justb - * added xml-strict format - * - * Revision 1.3 2005/02/28 12:45:59 justb - * introduced Command class - * - * Revision 1.2 2005/02/21 11:50:47 justb - * ohase1 of refactoring Subscriber into Session/Controller/Subscriber - * - * Revision 1.1 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.7 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.6 2004/03/10 14:01:55 justb - * formatting and *Subscriber refactoring - * - * Revision 1.5 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.4 2003/08/13 14:00:00 justb - * some testing for applets; no real change - * - * Revision 1.3 2003/08/12 09:57:06 justb - * replaced all print statements to Log.*() calls - * - * Revision 1.2 2003/05/19 21:56:29 justb - * various fixes for applet clients - * - * Revision 1.1 2003/05/18 16:12:28 justb - * adding support for XML encoded Events - */ +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +import nl.justobjects.pushlet.util.Log; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * ClientAdapter that sends Events as XML. + * + * @author Just van den Broecke - Just Objects © + * @version $Id: XMLAdapter.java,v 1.7 2007/11/09 13:15:35 justb Exp $ + */ +class XMLAdapter implements ClientAdapter { + /** + * Header for strict XML + */ + // public static final String XML_HEAD = "\n"; + private String contentType = "text/plain;charset=UTF-8"; + private ServletOutputStream out = null; + private HttpServletResponse servletRsp; + private boolean strictXML; + + /** + * Initialize. + */ + public XMLAdapter(HttpServletResponse aServletResponse) { + this(aServletResponse, false); + } + + /** + * Initialize. + */ + public XMLAdapter(HttpServletResponse aServletResponse, boolean useStrictXML) { + servletRsp = aServletResponse; + + // Strict XML implies returning a complete XML document + strictXML = useStrictXML; + if (strictXML) { + contentType = "text/xml;charset=UTF-8"; + } + } + + public void start() throws IOException { + + // If content type is plain text + // then this is not a complete XML document, but rather + // a stream of XML documents where each document is + // an Event. In strict XML mode a complete document is returned. + servletRsp.setContentType(contentType); + + out = servletRsp.getOutputStream(); + + // Don't need this further + servletRsp = null; + + // Start XML document if strict XML mode + if (strictXML) { + out.print(""); + } + } + + /** + * Force client to refresh the request. + */ + public void push(Event anEvent) throws IOException { + debug("event=" + anEvent); + + // Send the event as XML to the client and flush. + out.print(anEvent.toXML(strictXML)); + out.flush(); + } + + /** + * No action. + */ + public void stop() throws IOException { + // Close XML document if strict XML mode + if (strictXML) { + out.print(""); + out.flush(); + } + } + + private void debug(String s) { + Log.debug("[XMLAdapter]" + s); + } +} + +/* + * $Log: XMLAdapter.java,v $ + * Revision 1.7 2007/11/09 13:15:35 justb + * add charset=UTF-8 in returned HTTP content types + * + * Revision 1.6 2006/05/15 11:52:53 justb + * updates mainly for AJAX client + * + * Revision 1.5 2006/05/06 00:06:28 justb + * first rough version AJAX client + * + * Revision 1.4 2005/05/06 19:44:00 justb + * added xml-strict format + * + * Revision 1.3 2005/02/28 12:45:59 justb + * introduced Command class + * + * Revision 1.2 2005/02/21 11:50:47 justb + * ohase1 of refactoring Subscriber into Session/Controller/Subscriber + * + * Revision 1.1 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.7 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.6 2004/03/10 14:01:55 justb + * formatting and *Subscriber refactoring + * + * Revision 1.5 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.4 2003/08/13 14:00:00 justb + * some testing for applets; no real change + * + * Revision 1.3 2003/08/12 09:57:06 justb + * replaced all print statements to Log.*() calls + * + * Revision 1.2 2003/05/19 21:56:29 justb + * various fixes for applet clients + * + * Revision 1.1 2003/05/18 16:12:28 justb + * adding support for XML encoded Events + */ diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/servlet/Pushlet.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/servlet/Pushlet.java index 333fbe8302..7d5b087a74 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/servlet/Pushlet.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/servlet/Pushlet.java @@ -1,294 +1,294 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.servlet; - -import nl.justobjects.pushlet.core.*; -import nl.justobjects.pushlet.util.Log; -import nl.justobjects.pushlet.util.Servlets; -import nl.justobjects.pushlet.util.PushletException; -import nl.justobjects.pushlet.Version; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.Enumeration; - -/** - * Servlet runs a Subscriber per request. - * - * @author Just van den Broecke - Just Objects © - * @version $Id: Pushlet.java,v 1.23 2007/12/04 13:55:53 justb Exp $ - */ -public class Pushlet extends HttpServlet implements Protocol { - - public void init() throws ServletException { - try { - System.out.println("initiating pushlet servlet..."); - // Load configuration (from classpath or WEB-INF root path) - String webInfPath = getServletContext().getRealPath("/") + "/WEB-INF"; - Config.load(webInfPath); - - Log.init(); - - // Start - Log.info("init() Pushlet Webapp - version=" + Version.SOFTWARE_VERSION + " built=" + Version.BUILD_DATE); - - // Start session manager - SessionManager.getInstance().start(); - - // Start event Dispatcher - Dispatcher.getInstance().start(); - - System.out.println("pushlet initiates event sources..."); - if (Config.getBoolProperty(Config.SOURCES_ACTIVATE)) { - EventSourceManager.start(webInfPath,getServletContext());// changed by thomas genin - } else { - Log.info("Not starting local event sources"); - } - } catch (Throwable t) { - throw new ServletException("Failed to initialize Pushlet framework " + t, t); - } - } - - public void destroy() { - Log.info("destroy(): Exit Pushlet webapp"); - - if (Config.getBoolProperty(Config.SOURCES_ACTIVATE)) { - // Stop local event sources - EventSourceManager.stop(); - } else { - Log.info("No local event sources to stop"); - } - - // Should abort all subscribers - Dispatcher.getInstance().stop(); - - // Should stop all sessions - SessionManager.getInstance().stop(); - } - - /** - * Servlet GET request: handles event requests. - */ - public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - Event event = null; - - try { - // Event parm identifies event type from the client - String eventType = Servlets.getParameter(request, P_EVENT); - - // Always must have an event type - if (eventType == null) { - Log.warn("Pushlet.doGet(): bad request, no event specified"); - response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No eventType specified"); - return; - } - - // Create Event and set attributes from parameters - event = new Event(eventType); - for (Enumeration e = request.getParameterNames(); e.hasMoreElements();) { - String nextAttribute = (String) e.nextElement(); - event.setField(nextAttribute, request.getParameter(nextAttribute)); - } - - - } catch (Throwable t) { - // Error creating event - Log.warn("Pushlet: Error creating event in doGet(): ", t); - response.setStatus(HttpServletResponse.SC_BAD_REQUEST); - return; - } - - // Handle parsed request - doRequest(event, request, response); - - } - - /** - * Servlet POST request: extracts event data from body. - */ - public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - Event event = null; - try { - // Create Event by parsing XML from input stream. - event = EventParser.parse(new InputStreamReader(request.getInputStream())); - - // Always must have an event type - if (event.getEventType() == null) { - Log.warn("Pushlet.doPost(): bad request, no event specified"); - response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No eventType specified"); - return; - } - - - } catch (Throwable t) { - // Error creating event - Log.warn("Pushlet: Error creating event in doPost(): ", t); - response.setStatus(HttpServletResponse.SC_BAD_REQUEST); - return; - } - - // Handle parsed request - doRequest(event, request, response); - - } - - /** - * Generic request handler (GET+POST). - */ - protected void doRequest(Event anEvent, HttpServletRequest request, HttpServletResponse response) { - // Must have valid event type. - String eventType = anEvent.getEventType(); - try { - - // Get Session: either by creating (on Join eventType) - // or by id (any other eventType, since client is supposed to have joined). - Session session = null; - if (eventType.startsWith(Protocol.E_JOIN)) { - // Join request: create new subscriber - session = SessionManager.getInstance().createSession(anEvent); - - String userAgent = request.getHeader("User-Agent"); - if (userAgent != null) { - userAgent = userAgent.toLowerCase(); - } else { - userAgent = "unknown"; - } - session.setUserAgent(userAgent); - - } else { - // Must be a request for existing Session - - // Get id - String id = anEvent.getField(P_ID); - - // We must have an id value - if (id == null) { - response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No id specified"); - Log.warn("Pushlet: bad request, no id specified event=" + eventType); - return; - } - - // We have an id: get the session object - session = SessionManager.getInstance().getSession(id); - - // Check for invalid id - if (session == null) { - response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid or expired id: " + id); - Log.warn("Pushlet: bad request, no session found id=" + id + " event=" + eventType); - return; - } - } - - // ASSERTION: we have a valid Session - - // Let Controller handle request further - // including exceptions - Command command = Command.create(session, anEvent, request, response); - session.getController().doCommand(command); - } catch (Throwable t) { - // Hmm we should never ever get here - Log.warn("Pushlet: Exception in doRequest() event=" + eventType, t); - t.printStackTrace(); - response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - } - - } -} - -/* - * $Log: Pushlet.java,v $ - * Revision 1.23 2007/12/04 13:55:53 justb - * reimplement SessionManager concurrency (prev version was not thread-safe!) - * - * Revision 1.22 2007/11/24 10:29:36 justb - * add hooks for custom logging (you can override DefaultLogger in pushlet.properties) - * - * Revision 1.21 2007/11/23 21:10:17 justb - * add hooks for custom logging (you can override DefaultLogger in pushlet.properties) - * - * Revision 1.20 2007/11/10 13:44:02 justb - * pushlet.properties and sources.properties can now also be put under WEB-INF - * - * Revision 1.19 2006/05/15 11:52:53 justb - * updates mainly for AJAX client - * - * Revision 1.18 2005/02/28 15:58:05 justb - * added SimpleListener example - * - * Revision 1.17 2005/02/28 13:06:01 justb - * introduced join-listen protocol service - * - * Revision 1.16 2005/02/28 12:45:59 justb - * introduced Command class - * - * Revision 1.15 2005/02/28 09:14:56 justb - * sessmgr/dispatcher factory/singleton support - * - * Revision 1.14 2005/02/25 15:13:04 justb - * session id generation more robust - * - * Revision 1.13 2005/02/21 17:19:21 justb - * move init()/destroy() to Pushlet servlet - * - * Revision 1.12 2005/02/21 16:59:17 justb - * SessionManager and session lease introduced - * - * Revision 1.11 2005/02/21 11:50:47 justb - * ohase1 of refactoring Subscriber into Session/Controller/Subscriber - * - * Revision 1.10 2005/02/20 13:05:32 justb - * removed the Postlet (integrated in Pushlet protocol) - * - * Revision 1.9 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.8 2005/01/13 14:47:15 justb - * control evt: send response on same (control) connection - * - * Revision 1.7 2004/10/24 12:58:18 justb - * revised client and test classes for new protocol - * - * Revision 1.6 2004/09/26 21:39:44 justb - * allow multiple subscriptions and out-of-band requests - * - * Revision 1.5 2004/09/20 22:01:40 justb - * more changes for new protocol - * - * Revision 1.4 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.3 2004/08/13 23:36:06 justb - * rewrite of Pullet into Pushlet "pull" mode - * - * Revision 1.2 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.1 2003/08/13 13:26:57 justb - * moved all servlets to servlet package - * - * Revision 1.2 2003/05/18 16:15:08 justb - * support for XML encoded Events - * - * Revision 1.1.1.1 2002/09/24 21:02:32 justb - * import to sourceforge - * - * Revision 1.1.1.1 2002/09/20 22:48:18 justb - * import to SF - * - * Revision 1.1.1.1 2002/09/20 14:19:04 justb - * first import into SF - * - * Revision 1.3 2002/04/15 20:42:41 just - * reformatting and renaming GuardedQueue to EventQueue - * - * Revision 1.2 2000/08/21 20:48:29 just - * added CVS log and id tags plus copyrights - * - * - */ - +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.servlet; + +import nl.justobjects.pushlet.core.*; +import nl.justobjects.pushlet.util.Log; +import nl.justobjects.pushlet.util.Servlets; +import nl.justobjects.pushlet.util.PushletException; +import nl.justobjects.pushlet.Version; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Enumeration; + +/** + * Servlet runs a Subscriber per request. + * + * @author Just van den Broecke - Just Objects © + * @version $Id: Pushlet.java,v 1.23 2007/12/04 13:55:53 justb Exp $ + */ +public class Pushlet extends HttpServlet implements Protocol { + + public void init() throws ServletException { + try { + System.out.println("initiating pushlet servlet..."); + // Load configuration (from classpath or WEB-INF root path) + String webInfPath = getServletContext().getRealPath("/") + "/WEB-INF"; + Config.load(webInfPath); + + Log.init(); + + // Start + Log.info("init() Pushlet Webapp - version=" + Version.SOFTWARE_VERSION + " built=" + Version.BUILD_DATE); + + // Start session manager + SessionManager.getInstance().start(); + + // Start event Dispatcher + Dispatcher.getInstance().start(); + + System.out.println("pushlet initiates event sources..."); + if (Config.getBoolProperty(Config.SOURCES_ACTIVATE)) { + EventSourceManager.start(webInfPath,getServletContext());// changed by thomas genin + } else { + Log.info("Not starting local event sources"); + } + } catch (Throwable t) { + throw new ServletException("Failed to initialize Pushlet framework " + t, t); + } + } + + public void destroy() { + Log.info("destroy(): Exit Pushlet webapp"); + + if (Config.getBoolProperty(Config.SOURCES_ACTIVATE)) { + // Stop local event sources + EventSourceManager.stop(); + } else { + Log.info("No local event sources to stop"); + } + + // Should abort all subscribers + Dispatcher.getInstance().stop(); + + // Should stop all sessions + SessionManager.getInstance().stop(); + } + + /** + * Servlet GET request: handles event requests. + */ + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + Event event = null; + + try { + // Event parm identifies event type from the client + String eventType = Servlets.getParameter(request, P_EVENT); + + // Always must have an event type + if (eventType == null) { + Log.warn("Pushlet.doGet(): bad request, no event specified"); + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No eventType specified"); + return; + } + + // Create Event and set attributes from parameters + event = new Event(eventType); + for (Enumeration e = request.getParameterNames(); e.hasMoreElements();) { + String nextAttribute = (String) e.nextElement(); + event.setField(nextAttribute, request.getParameter(nextAttribute)); + } + + + } catch (Throwable t) { + // Error creating event + Log.warn("Pushlet: Error creating event in doGet(): ", t); + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + return; + } + + // Handle parsed request + doRequest(event, request, response); + + } + + /** + * Servlet POST request: extracts event data from body. + */ + public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + Event event = null; + try { + // Create Event by parsing XML from input stream. + event = EventParser.parse(new InputStreamReader(request.getInputStream())); + + // Always must have an event type + if (event.getEventType() == null) { + Log.warn("Pushlet.doPost(): bad request, no event specified"); + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No eventType specified"); + return; + } + + + } catch (Throwable t) { + // Error creating event + Log.warn("Pushlet: Error creating event in doPost(): ", t); + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + return; + } + + // Handle parsed request + doRequest(event, request, response); + + } + + /** + * Generic request handler (GET+POST). + */ + protected void doRequest(Event anEvent, HttpServletRequest request, HttpServletResponse response) { + // Must have valid event type. + String eventType = anEvent.getEventType(); + try { + + // Get Session: either by creating (on Join eventType) + // or by id (any other eventType, since client is supposed to have joined). + Session session = null; + if (eventType.startsWith(Protocol.E_JOIN)) { + // Join request: create new subscriber + session = SessionManager.getInstance().createSession(anEvent); + + String userAgent = request.getHeader("User-Agent"); + if (userAgent != null) { + userAgent = userAgent.toLowerCase(); + } else { + userAgent = "unknown"; + } + session.setUserAgent(userAgent); + + } else { + // Must be a request for existing Session + + // Get id + String id = anEvent.getField(P_ID); + + // We must have an id value + if (id == null) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No id specified"); + Log.warn("Pushlet: bad request, no id specified event=" + eventType); + return; + } + + // We have an id: get the session object + session = SessionManager.getInstance().getSession(id); + + // Check for invalid id + if (session == null) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid or expired id: " + id); + Log.warn("Pushlet: bad request, no session found id=" + id + " event=" + eventType); + return; + } + } + + // ASSERTION: we have a valid Session + + // Let Controller handle request further + // including exceptions + Command command = Command.create(session, anEvent, request, response); + session.getController().doCommand(command); + } catch (Throwable t) { + // Hmm we should never ever get here + Log.warn("Pushlet: Exception in doRequest() event=" + eventType, t); + t.printStackTrace(); + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + + } +} + +/* + * $Log: Pushlet.java,v $ + * Revision 1.23 2007/12/04 13:55:53 justb + * reimplement SessionManager concurrency (prev version was not thread-safe!) + * + * Revision 1.22 2007/11/24 10:29:36 justb + * add hooks for custom logging (you can override DefaultLogger in pushlet.properties) + * + * Revision 1.21 2007/11/23 21:10:17 justb + * add hooks for custom logging (you can override DefaultLogger in pushlet.properties) + * + * Revision 1.20 2007/11/10 13:44:02 justb + * pushlet.properties and sources.properties can now also be put under WEB-INF + * + * Revision 1.19 2006/05/15 11:52:53 justb + * updates mainly for AJAX client + * + * Revision 1.18 2005/02/28 15:58:05 justb + * added SimpleListener example + * + * Revision 1.17 2005/02/28 13:06:01 justb + * introduced join-listen protocol service + * + * Revision 1.16 2005/02/28 12:45:59 justb + * introduced Command class + * + * Revision 1.15 2005/02/28 09:14:56 justb + * sessmgr/dispatcher factory/singleton support + * + * Revision 1.14 2005/02/25 15:13:04 justb + * session id generation more robust + * + * Revision 1.13 2005/02/21 17:19:21 justb + * move init()/destroy() to Pushlet servlet + * + * Revision 1.12 2005/02/21 16:59:17 justb + * SessionManager and session lease introduced + * + * Revision 1.11 2005/02/21 11:50:47 justb + * ohase1 of refactoring Subscriber into Session/Controller/Subscriber + * + * Revision 1.10 2005/02/20 13:05:32 justb + * removed the Postlet (integrated in Pushlet protocol) + * + * Revision 1.9 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.8 2005/01/13 14:47:15 justb + * control evt: send response on same (control) connection + * + * Revision 1.7 2004/10/24 12:58:18 justb + * revised client and test classes for new protocol + * + * Revision 1.6 2004/09/26 21:39:44 justb + * allow multiple subscriptions and out-of-band requests + * + * Revision 1.5 2004/09/20 22:01:40 justb + * more changes for new protocol + * + * Revision 1.4 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.3 2004/08/13 23:36:06 justb + * rewrite of Pullet into Pushlet "pull" mode + * + * Revision 1.2 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.1 2003/08/13 13:26:57 justb + * moved all servlets to servlet package + * + * Revision 1.2 2003/05/18 16:15:08 justb + * support for XML encoded Events + * + * Revision 1.1.1.1 2002/09/24 21:02:32 justb + * import to sourceforge + * + * Revision 1.1.1.1 2002/09/20 22:48:18 justb + * import to SF + * + * Revision 1.1.1.1 2002/09/20 14:19:04 justb + * first import into SF + * + * Revision 1.3 2002/04/15 20:42:41 just + * reformatting and renaming GuardedQueue to EventQueue + * + * Revision 1.2 2000/08/21 20:48:29 just + * added CVS log and id tags plus copyrights + * + * + */ + diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/util/DefaultLogger.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/util/DefaultLogger.java index bec2d94f34..bc0648c9a1 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/util/DefaultLogger.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/util/DefaultLogger.java @@ -1,164 +1,164 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.util; - -/** - * Default logger. - *

- * Logs to stdout. Override this class by setting "logger.class" in pushlet.properties to your own logger - * to integrate your own logging library. - * - * @author Just van den Broecke - * @version $Id: DefaultLogger.java,v 1.2 2007/12/07 12:57:40 justb Exp $ - */ -public class DefaultLogger implements PushletLogger { - - - /** - * Level intialized with default. - */ - private int level = LOG_LEVEL_INFO; - - public DefaultLogger() { - } - - public void init() { - - } - - /** - * Log message for trace level. - * - * @param aMessage the message to be logged - */ - public void trace(String aMessage) { - if (level < LOG_LEVEL_TRACE) { - return; - } - print("TRACE", aMessage); - } - - /** - * Log message for debug level. - * - * @param aMessage the message to be logged - */ - public void debug(String aMessage) { - if (level < LOG_LEVEL_DEBUG) { - return; - } - print("DEBUG", aMessage); - } - - /** - * Log message for info level. - * - * @param aMessage the message to be logged - */ - public void info(String aMessage) { - if (level < LOG_LEVEL_INFO) { - return; - } - print("INFO", aMessage); - } - - /** - * Log message for warning level. - * - * @param aMessage the message to be logged - */ - public void warn(String aMessage) { - if (level < LOG_LEVEL_WARN) { - return; - } - print("WARN", aMessage); - } - - /** - * Log message for warning level with exception. - * - * @param aMessage the message to be logged - * @param aThrowable the exception - */ - public void warn(String aMessage, Throwable aThrowable) { - warn(aMessage + " exception=" + aThrowable); - } - - /** - * Log message for error level. - * - * @param aMessage the message to be logged - */ - public void error(String aMessage) { - if (level < LOG_LEVEL_ERROR) { - return; - } - print("FATAL", aMessage); - } - - /** - * Log message (error level with exception). - * - * @param aMessage the message to be logged - * @param aThrowable the exception - */ - public void error(String aMessage, Throwable aThrowable) { - error(aMessage + " exception=" + aThrowable); - } - - /** - * Log message for fatal level. - * - * @param aMessage the message to be logged - */ - public void fatal(String aMessage) { - if (level < LOG_LEVEL_FATAL) { - return; - } - print("FATAL", aMessage); - } - - /** - * Log message (fatal level with exception). - * - * @param aMessage the message to be logged - * @param aThrowable the exception - */ - public void fatal(String aMessage, Throwable aThrowable) { - fatal(aMessage + " exception=" + aThrowable); - } - - /** - * Set log level - * - * @param aLevel the message to be logged - */ - public void setLevel(int aLevel) { - level = aLevel; - } - - /** - * Print message. - * - * @param aTag the log type - * @param aMessage the message to be logged - */ - private void print(String aTag, String aMessage) { - // SImple std out e.g. to catalina.out in Tomcat - System.out.println("Pushlet[" + aTag + "] " + aMessage); - } - -} - -/* -* $Log: DefaultLogger.java,v $ -* Revision 1.2 2007/12/07 12:57:40 justb -* added log4j and make it the default logging method -* -* Revision 1.1 2007/11/23 21:10:17 justb -* add hooks for custom logging (you can override DefaultLogger in pushlet.properties) -* -* -* +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.util; + +/** + * Default logger. + *

+ * Logs to stdout. Override this class by setting "logger.class" in pushlet.properties to your own logger + * to integrate your own logging library. + * + * @author Just van den Broecke + * @version $Id: DefaultLogger.java,v 1.2 2007/12/07 12:57:40 justb Exp $ + */ +public class DefaultLogger implements PushletLogger { + + + /** + * Level intialized with default. + */ + private int level = LOG_LEVEL_INFO; + + public DefaultLogger() { + } + + public void init() { + + } + + /** + * Log message for trace level. + * + * @param aMessage the message to be logged + */ + public void trace(String aMessage) { + if (level < LOG_LEVEL_TRACE) { + return; + } + print("TRACE", aMessage); + } + + /** + * Log message for debug level. + * + * @param aMessage the message to be logged + */ + public void debug(String aMessage) { + if (level < LOG_LEVEL_DEBUG) { + return; + } + print("DEBUG", aMessage); + } + + /** + * Log message for info level. + * + * @param aMessage the message to be logged + */ + public void info(String aMessage) { + if (level < LOG_LEVEL_INFO) { + return; + } + print("INFO", aMessage); + } + + /** + * Log message for warning level. + * + * @param aMessage the message to be logged + */ + public void warn(String aMessage) { + if (level < LOG_LEVEL_WARN) { + return; + } + print("WARN", aMessage); + } + + /** + * Log message for warning level with exception. + * + * @param aMessage the message to be logged + * @param aThrowable the exception + */ + public void warn(String aMessage, Throwable aThrowable) { + warn(aMessage + " exception=" + aThrowable); + } + + /** + * Log message for error level. + * + * @param aMessage the message to be logged + */ + public void error(String aMessage) { + if (level < LOG_LEVEL_ERROR) { + return; + } + print("FATAL", aMessage); + } + + /** + * Log message (error level with exception). + * + * @param aMessage the message to be logged + * @param aThrowable the exception + */ + public void error(String aMessage, Throwable aThrowable) { + error(aMessage + " exception=" + aThrowable); + } + + /** + * Log message for fatal level. + * + * @param aMessage the message to be logged + */ + public void fatal(String aMessage) { + if (level < LOG_LEVEL_FATAL) { + return; + } + print("FATAL", aMessage); + } + + /** + * Log message (fatal level with exception). + * + * @param aMessage the message to be logged + * @param aThrowable the exception + */ + public void fatal(String aMessage, Throwable aThrowable) { + fatal(aMessage + " exception=" + aThrowable); + } + + /** + * Set log level + * + * @param aLevel the message to be logged + */ + public void setLevel(int aLevel) { + level = aLevel; + } + + /** + * Print message. + * + * @param aTag the log type + * @param aMessage the message to be logged + */ + private void print(String aTag, String aMessage) { + // SImple std out e.g. to catalina.out in Tomcat + System.out.println("Pushlet[" + aTag + "] " + aMessage); + } + +} + +/* +* $Log: DefaultLogger.java,v $ +* Revision 1.2 2007/12/07 12:57:40 justb +* added log4j and make it the default logging method +* +* Revision 1.1 2007/11/23 21:10:17 justb +* add hooks for custom logging (you can override DefaultLogger in pushlet.properties) +* +* +* */ \ No newline at end of file diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/util/Log.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/util/Log.java index 3ce40153e7..ee6bd254d4 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/util/Log.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/util/Log.java @@ -1,178 +1,178 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.util; - -import nl.justobjects.pushlet.core.Config; -import nl.justobjects.pushlet.core.ConfigDefs; - -/** - * Logging wrapper. - *

- * Provides a hook to direct logging to your own logging library. Override the DefaultLogger class by setting - * "logger.class" in pushlet.properties to your own logger - * to integrate your own logging library. - * - * @author Just van den Broecke - * @version $Id: Log.java,v 1.5 2007/12/07 12:57:40 justb Exp $ - */ -public class Log implements ConfigDefs { - /** - * Init with default to have at least some logging. - */ - private static PushletLogger logger = new DefaultLogger(); - - /** - * General purpose initialization. - */ - static public void init() { - try { - logger = (PushletLogger) Config.getClass(LOGGER_CLASS, "nl.justobjects.pushlet.util.DefaultLogger").newInstance(); - } catch (Throwable t) { - // Hmmm cannot log this since we don't have a log... - System.out.println("Cannot instantiate Logger from config ex=" + t); - return; - } - - logger.init(); - - // Set log level - logger.setLevel(Config.getIntProperty(Config.LOG_LEVEL)); - - logger.info("Logging intialized logger class=" + logger.getClass()); - } - - /** - * Log message for trace level. - * - * @param aMessage the message to be logged - */ - static public void trace(String aMessage) { - logger.debug(aMessage); - } - - /** - * Log message for debug level. - * - * @param aMessage the message to be logged - */ - static public void debug(String aMessage) { - logger.debug(aMessage); - } - - /** - * Log message for info level. - * - * @param aMessage the message to be logged - */ - static public void info(String aMessage) { - logger.info(aMessage); - } - - /** - * Log message for warning level. - * - * @param aMessage the message to be logged - */ - static public void warn(String aMessage) { - logger.warn(aMessage); - } - - /** - * Log message for warning level with exception. - * - * @param aMessage the message to be logged - * @param aThrowable the exception - */ - static public void warn(String aMessage, Throwable aThrowable) { - logger.warn(aMessage, aThrowable); - } - - /** - * Log message for error level. - * - * @param aMessage the message to be logged - */ - static public void error(String aMessage) { - logger.error(aMessage); - } - - /** - * Log message (error level with exception). - * - * @param aMessage the message to be logged - * @param aThrowable the exception - */ - static public void error(String aMessage, Throwable aThrowable) { - logger.error(aMessage, aThrowable); - } - - /** - * Log message for fatal level. - * - * @param aMessage the message to be logged - */ - static public void fatal(String aMessage) { - logger.fatal(aMessage); - } - - /** - * Log message (fatal level with exception). - * - * @param aMessage the message to be logged - * @param aThrowable the exception - */ - static public void fatal(String aMessage, Throwable aThrowable) { - logger.fatal(aMessage, aThrowable); - } - - /** - * Set log level - * - * @param aLevel the message to be logged - */ - static public void setLevel(int aLevel) { - logger.setLevel(aLevel); - } -} - -/* -* $Log: Log.java,v $ -* Revision 1.5 2007/12/07 12:57:40 justb -* added log4j and make it the default logging method -* -* Revision 1.4 2007/11/23 21:29:43 justb -* add hooks for custom logging (you can override DefaultLogger in pushlet.properties) -* -* Revision 1.3 2007/11/23 21:10:17 justb -* add hooks for custom logging (you can override DefaultLogger in pushlet.properties) -* -* Revision 1.2 2005/02/21 11:15:59 justb -* support log levels -* -* Revision 1.1 2005/02/18 10:07:23 justb -* many renamings of classes (make names compact) -* -* Revision 1.7 2004/09/03 22:35:37 justb -* Almost complete rewrite, just checking in now -* -* Revision 1.6 2004/08/12 13:16:08 justb -* make debug flag false -* -* Revision 1.5 2004/03/10 14:01:55 justb -* formatting and *Subscriber refactoring -* -* Revision 1.4 2003/08/15 09:54:46 justb -* fix javadoc warnings -* -* Revision 1.3 2003/08/15 08:37:40 justb -* fix/add Copyright+LGPL file headers and footers -* -* Revision 1.2 2003/08/12 09:42:47 justb -* enhancements -* -* Revision 1.1 2003/08/12 08:46:00 justb -* cvs comment tags added -* -* +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.util; + +import nl.justobjects.pushlet.core.Config; +import nl.justobjects.pushlet.core.ConfigDefs; + +/** + * Logging wrapper. + *

+ * Provides a hook to direct logging to your own logging library. Override the DefaultLogger class by setting + * "logger.class" in pushlet.properties to your own logger + * to integrate your own logging library. + * + * @author Just van den Broecke + * @version $Id: Log.java,v 1.5 2007/12/07 12:57:40 justb Exp $ + */ +public class Log implements ConfigDefs { + /** + * Init with default to have at least some logging. + */ + private static PushletLogger logger = new DefaultLogger(); + + /** + * General purpose initialization. + */ + static public void init() { + try { + logger = (PushletLogger) Config.getClass(LOGGER_CLASS, "nl.justobjects.pushlet.util.DefaultLogger").newInstance(); + } catch (Throwable t) { + // Hmmm cannot log this since we don't have a log... + System.out.println("Cannot instantiate Logger from config ex=" + t); + return; + } + + logger.init(); + + // Set log level + logger.setLevel(Config.getIntProperty(Config.LOG_LEVEL)); + + logger.info("Logging intialized logger class=" + logger.getClass()); + } + + /** + * Log message for trace level. + * + * @param aMessage the message to be logged + */ + static public void trace(String aMessage) { + logger.debug(aMessage); + } + + /** + * Log message for debug level. + * + * @param aMessage the message to be logged + */ + static public void debug(String aMessage) { + logger.debug(aMessage); + } + + /** + * Log message for info level. + * + * @param aMessage the message to be logged + */ + static public void info(String aMessage) { + logger.info(aMessage); + } + + /** + * Log message for warning level. + * + * @param aMessage the message to be logged + */ + static public void warn(String aMessage) { + logger.warn(aMessage); + } + + /** + * Log message for warning level with exception. + * + * @param aMessage the message to be logged + * @param aThrowable the exception + */ + static public void warn(String aMessage, Throwable aThrowable) { + logger.warn(aMessage, aThrowable); + } + + /** + * Log message for error level. + * + * @param aMessage the message to be logged + */ + static public void error(String aMessage) { + logger.error(aMessage); + } + + /** + * Log message (error level with exception). + * + * @param aMessage the message to be logged + * @param aThrowable the exception + */ + static public void error(String aMessage, Throwable aThrowable) { + logger.error(aMessage, aThrowable); + } + + /** + * Log message for fatal level. + * + * @param aMessage the message to be logged + */ + static public void fatal(String aMessage) { + logger.fatal(aMessage); + } + + /** + * Log message (fatal level with exception). + * + * @param aMessage the message to be logged + * @param aThrowable the exception + */ + static public void fatal(String aMessage, Throwable aThrowable) { + logger.fatal(aMessage, aThrowable); + } + + /** + * Set log level + * + * @param aLevel the message to be logged + */ + static public void setLevel(int aLevel) { + logger.setLevel(aLevel); + } +} + +/* +* $Log: Log.java,v $ +* Revision 1.5 2007/12/07 12:57:40 justb +* added log4j and make it the default logging method +* +* Revision 1.4 2007/11/23 21:29:43 justb +* add hooks for custom logging (you can override DefaultLogger in pushlet.properties) +* +* Revision 1.3 2007/11/23 21:10:17 justb +* add hooks for custom logging (you can override DefaultLogger in pushlet.properties) +* +* Revision 1.2 2005/02/21 11:15:59 justb +* support log levels +* +* Revision 1.1 2005/02/18 10:07:23 justb +* many renamings of classes (make names compact) +* +* Revision 1.7 2004/09/03 22:35:37 justb +* Almost complete rewrite, just checking in now +* +* Revision 1.6 2004/08/12 13:16:08 justb +* make debug flag false +* +* Revision 1.5 2004/03/10 14:01:55 justb +* formatting and *Subscriber refactoring +* +* Revision 1.4 2003/08/15 09:54:46 justb +* fix javadoc warnings +* +* Revision 1.3 2003/08/15 08:37:40 justb +* fix/add Copyright+LGPL file headers and footers +* +* Revision 1.2 2003/08/12 09:42:47 justb +* enhancements +* +* Revision 1.1 2003/08/12 08:46:00 justb +* cvs comment tags added +* +* */ \ No newline at end of file diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/util/Log4jLogger.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/util/Log4jLogger.java index d7ee1df832..ca96762621 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/util/Log4jLogger.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/util/Log4jLogger.java @@ -1,134 +1,134 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.util; - -import org.apache.log4j.Level; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; - -/** - * Logger to use Log4j for logging. - *

- * Logs using Log4j. - * This class will require a log4j library in the classpath of the Pushlet. - * - * @author Uli Romahn - * @version $Id: Log4jLogger.java,v 1.1 2007/12/07 12:57:40 justb Exp $ - */ -public class Log4jLogger implements PushletLogger { - - /** - * Level intialized with default. - */ - private Logger logger = LogManager.getLogger("pushlet"); - - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#init() - */ - public void init() { - setLevel(LOG_LEVEL_INFO); - } - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#debug(java.lang.String) - */ - public void debug(String aMessage) { - if (!logger.isDebugEnabled()) { - return; - } - logger.debug(aMessage); - } - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#error(java.lang.String) - */ - public void error(String aMessage) { - logger.error(aMessage); - } - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#error(java.lang.String, java.lang.Throwable) - */ - public void error(String aMessage, Throwable aThrowable) { - logger.error(aMessage, aThrowable); - } - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#fatal(java.lang.String) - */ - public void fatal(String aMessage) { - logger.fatal(aMessage); - } - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#fatal(java.lang.String, java.lang.Throwable) - */ - public void fatal(String aMessage, Throwable aThrowable) { - logger.fatal(aMessage, aThrowable); - } - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#info(java.lang.String) - */ - public void info(String aMessage) { - if (!logger.isInfoEnabled()) { - return; - } - logger.info(aMessage); - } - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#trace(java.lang.String) - */ - public void trace(String aMessage) { - logger.trace(aMessage); - } - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#warn(java.lang.String) - */ - public void warn(String aMessage) { - logger.warn(aMessage); - } - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#warn(java.lang.String, java.lang.Throwable) - */ - public void warn(String aMessage, Throwable aThrowable) { - logger.warn(aMessage, aThrowable); - } - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#setLevel(int) - */ - public void setLevel(int aLevel) { - if (aLevel < LOG_LEVEL_FATAL) { - logger.setLevel(Level.OFF); - } else { - switch (aLevel) { - case LOG_LEVEL_FATAL: - logger.setLevel(Level.FATAL); - break; - case LOG_LEVEL_ERROR: - logger.setLevel(Level.ERROR); - break; - case LOG_LEVEL_WARN: - logger.setLevel(Level.WARN); - break; - case LOG_LEVEL_INFO: - logger.setLevel(Level.INFO); - break; - case LOG_LEVEL_DEBUG: - logger.setLevel(Level.DEBUG); - break; - case LOG_LEVEL_TRACE: - logger.setLevel(Level.TRACE); - break; - default: - logger.setLevel(Level.INFO); - } - } - } -} +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.util; + +import org.apache.log4j.Level; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; + +/** + * Logger to use Log4j for logging. + *

+ * Logs using Log4j. + * This class will require a log4j library in the classpath of the Pushlet. + * + * @author Uli Romahn + * @version $Id: Log4jLogger.java,v 1.1 2007/12/07 12:57:40 justb Exp $ + */ +public class Log4jLogger implements PushletLogger { + + /** + * Level intialized with default. + */ + private Logger logger = LogManager.getLogger("pushlet"); + + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#init() + */ + public void init() { + setLevel(LOG_LEVEL_INFO); + } + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#debug(java.lang.String) + */ + public void debug(String aMessage) { + if (!logger.isDebugEnabled()) { + return; + } + logger.debug(aMessage); + } + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#error(java.lang.String) + */ + public void error(String aMessage) { + logger.error(aMessage); + } + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#error(java.lang.String, java.lang.Throwable) + */ + public void error(String aMessage, Throwable aThrowable) { + logger.error(aMessage, aThrowable); + } + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#fatal(java.lang.String) + */ + public void fatal(String aMessage) { + logger.fatal(aMessage); + } + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#fatal(java.lang.String, java.lang.Throwable) + */ + public void fatal(String aMessage, Throwable aThrowable) { + logger.fatal(aMessage, aThrowable); + } + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#info(java.lang.String) + */ + public void info(String aMessage) { + if (!logger.isInfoEnabled()) { + return; + } + logger.info(aMessage); + } + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#trace(java.lang.String) + */ + public void trace(String aMessage) { + logger.trace(aMessage); + } + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#warn(java.lang.String) + */ + public void warn(String aMessage) { + logger.warn(aMessage); + } + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#warn(java.lang.String, java.lang.Throwable) + */ + public void warn(String aMessage, Throwable aThrowable) { + logger.warn(aMessage, aThrowable); + } + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#setLevel(int) + */ + public void setLevel(int aLevel) { + if (aLevel < LOG_LEVEL_FATAL) { + logger.setLevel(Level.OFF); + } else { + switch (aLevel) { + case LOG_LEVEL_FATAL: + logger.setLevel(Level.FATAL); + break; + case LOG_LEVEL_ERROR: + logger.setLevel(Level.ERROR); + break; + case LOG_LEVEL_WARN: + logger.setLevel(Level.WARN); + break; + case LOG_LEVEL_INFO: + logger.setLevel(Level.INFO); + break; + case LOG_LEVEL_DEBUG: + logger.setLevel(Level.DEBUG); + break; + case LOG_LEVEL_TRACE: + logger.setLevel(Level.TRACE); + break; + default: + logger.setLevel(Level.INFO); + } + } + } +} diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/util/PushletLogger.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/util/PushletLogger.java index c3853369ba..e70bc68703 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/util/PushletLogger.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/nl/justobjects/pushlet/util/PushletLogger.java @@ -1,94 +1,94 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.util; - -import nl.justobjects.pushlet.core.ConfigDefs; - -/** - * Logger interface to allow different logging providers. - *

- * - * @author Ulrich Romahn - * @version $Id: PushletLogger.java,v 1.1 2007/12/07 12:57:40 justb Exp $ - */ -public interface PushletLogger extends ConfigDefs { - - /** - * Method allowing to initialize our logger - */ - public void init(); - - /** - * Log message for trace level. - * - * @param aMessage the message to be logged - */ - public void trace(String aMessage); - - /** - * Log message for debug level. - * - * @param aMessage the message to be logged - */ - public void debug(String aMessage); - - /** - * Log message for info level. - * - * @param aMessage the message to be logged - */ - public void info(String aMessage); - - /** - * Log message for warning level. - * - * @param aMessage the message to be logged - */ - public void warn(String aMessage); - - /** - * Log message for warning level with exception. - * - * @param aMessage the message to be logged - * @param aThrowable the exception - */ - public void warn(String aMessage, Throwable aThrowable); - - /** - * Log message for error level. - * - * @param aMessage the message to be logged - */ - public void error(String aMessage); - - /** - * Log message (error level with exception). - * - * @param aMessage the message to be logged - * @param aThrowable the exception - */ - public void error(String aMessage, Throwable aThrowable); - - /** - * Log message for fatal level. - * - * @param aMessage the message to be logged - */ - public void fatal(String aMessage); - - /** - * Log message (fatal level with exception). - * - * @param aMessage the message to be logged - * @param aThrowable the exception - */ - public void fatal(String aMessage, Throwable aThrowable); - - /** - * Set log level - * - * @param aLevel a valid Level from ConfigDefs - */ - public void setLevel(int aLevel); -} +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.util; + +import nl.justobjects.pushlet.core.ConfigDefs; + +/** + * Logger interface to allow different logging providers. + *

+ * + * @author Ulrich Romahn + * @version $Id: PushletLogger.java,v 1.1 2007/12/07 12:57:40 justb Exp $ + */ +public interface PushletLogger extends ConfigDefs { + + /** + * Method allowing to initialize our logger + */ + public void init(); + + /** + * Log message for trace level. + * + * @param aMessage the message to be logged + */ + public void trace(String aMessage); + + /** + * Log message for debug level. + * + * @param aMessage the message to be logged + */ + public void debug(String aMessage); + + /** + * Log message for info level. + * + * @param aMessage the message to be logged + */ + public void info(String aMessage); + + /** + * Log message for warning level. + * + * @param aMessage the message to be logged + */ + public void warn(String aMessage); + + /** + * Log message for warning level with exception. + * + * @param aMessage the message to be logged + * @param aThrowable the exception + */ + public void warn(String aMessage, Throwable aThrowable); + + /** + * Log message for error level. + * + * @param aMessage the message to be logged + */ + public void error(String aMessage); + + /** + * Log message (error level with exception). + * + * @param aMessage the message to be logged + * @param aThrowable the exception + */ + public void error(String aMessage, Throwable aThrowable); + + /** + * Log message for fatal level. + * + * @param aMessage the message to be logged + */ + public void fatal(String aMessage); + + /** + * Log message (fatal level with exception). + * + * @param aMessage the message to be logged + * @param aThrowable the exception + */ + public void fatal(String aMessage, Throwable aThrowable); + + /** + * Set log level + * + * @param aLevel a valid Level from ConfigDefs + */ + public void setLevel(int aLevel); +} diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/pow/ivyclient/BusIvy_.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/pow/ivyclient/BusIvy_.java index 50fee0a112..27fb91d1b4 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/pow/ivyclient/BusIvy_.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/pow/ivyclient/BusIvy_.java @@ -1,91 +1,91 @@ -package pow.ivyclient; - -import java.net.*; -import java.util.*; -import java.util.Calendar; -/** - * inner representation of an ivy bus - * store the drones' information about the drones which belong to this ivy bus - * store the IP adress of the machine where the ivy bus is working - */ -public class BusIvy_ -{ - private Calendar oCalendar; - private long oTime; - private InetAddress busAddress; - private ArrayList DronesId = new ArrayList(); - /** - * - * @param myInetAddress the ip address of the ivy host - */ - public void setAddress(InetAddress myInetAddress) - { - busAddress = myInetAddress; - } - /** - * update the 'inner clock' of the object when a message for this bus is detected - * useful to know if the bus is still alive - */ - public void updateTime() - { - oCalendar=Calendar.getInstance(); - oTime = oCalendar.getTimeInMillis(); - } - /** - * inform the bus that a new drone send information on this bus - * @param newDroneId (the ivy id) - */ - public void addDrones(int newDroneId) - { - DronesId.add(newDroneId); - } - /** - * get a array list containing the ivy id of the drones present on the bus - * @return the array list containing the ivy id of the drones present on the bus - */ - public ArrayList getDrones() - { - return DronesId; - } - /** - * display information on stdout about the drones present on the bus - */ - public void displayDrones() - { - System.out.println("Bus Ivy : "); - System.out.println(busAddress); - System.out.println("Drones : "); - for(Integer myDrone : DronesId) - { - System.out.println(myDrone); - } - } - /** - * provides the IP adress of the host hosting the bus - * @return the IP adress of the host hosting the bus - */ - public InetAddress getAddress() - { - return busAddress; - } - /** - * inform if a drone is present or not on the bus - * @param myDroneId the ivy id - * @return true if the drone is present on the bus - */ - public boolean isOwnBy(int myDroneId) - { - return DronesId.contains(myDroneId); - } - /** - * inform if the bus is alive - * @return true if the last message was received less than 10 seconds ago - */ - public boolean isAlive() - { - Calendar iCalendar = Calendar.getInstance(); - long iTime = iCalendar.getTimeInMillis(); - - return ((iTime - oTime)<10000); // 10 secondes - } +package pow.ivyclient; + +import java.net.*; +import java.util.*; +import java.util.Calendar; +/** + * inner representation of an ivy bus + * store the drones' information about the drones which belong to this ivy bus + * store the IP adress of the machine where the ivy bus is working + */ +public class BusIvy_ +{ + private Calendar oCalendar; + private long oTime; + private InetAddress busAddress; + private ArrayList DronesId = new ArrayList(); + /** + * + * @param myInetAddress the ip address of the ivy host + */ + public void setAddress(InetAddress myInetAddress) + { + busAddress = myInetAddress; + } + /** + * update the 'inner clock' of the object when a message for this bus is detected + * useful to know if the bus is still alive + */ + public void updateTime() + { + oCalendar=Calendar.getInstance(); + oTime = oCalendar.getTimeInMillis(); + } + /** + * inform the bus that a new drone send information on this bus + * @param newDroneId (the ivy id) + */ + public void addDrones(int newDroneId) + { + DronesId.add(newDroneId); + } + /** + * get a array list containing the ivy id of the drones present on the bus + * @return the array list containing the ivy id of the drones present on the bus + */ + public ArrayList getDrones() + { + return DronesId; + } + /** + * display information on stdout about the drones present on the bus + */ + public void displayDrones() + { + System.out.println("Bus Ivy : "); + System.out.println(busAddress); + System.out.println("Drones : "); + for(Integer myDrone : DronesId) + { + System.out.println(myDrone); + } + } + /** + * provides the IP adress of the host hosting the bus + * @return the IP adress of the host hosting the bus + */ + public InetAddress getAddress() + { + return busAddress; + } + /** + * inform if a drone is present or not on the bus + * @param myDroneId the ivy id + * @return true if the drone is present on the bus + */ + public boolean isOwnBy(int myDroneId) + { + return DronesId.contains(myDroneId); + } + /** + * inform if the bus is alive + * @return true if the last message was received less than 10 seconds ago + */ + public boolean isAlive() + { + Calendar iCalendar = Calendar.getInstance(); + long iTime = iCalendar.getTimeInMillis(); + + return ((iTime - oTime)<10000); // 10 secondes + } } \ No newline at end of file diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/pow/webserver/Conf.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/pow/webserver/Conf.java index 1d9a0a1253..c01259552f 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/pow/webserver/Conf.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/pow/webserver/Conf.java @@ -1,165 +1,165 @@ -package pow.webserver; -import java.io.*; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.xml.sax.SAXException; -/** - * - * store useful data about the server configuration - * and database connection by - * reading a specific file place in the 'conf' folder of - * the web application - */ -public class Conf { - /** The mail of the administrator to contact if any problems occurs - * (appears in the help.jsp page. */ - private String mailAdmin; - /** The administrator login (not used). */ - private String adminLogin; - /** The port in which the module listen to get udp trames from ivy buses. */ - private int portIvyToWeb; - /** The dimension of the datagrams received. */ - private int tailleUdpTrame; - /** The passWord of the database */ - private String dbPassword; - /** The userName of the dataBase */ - private String dbUserName; - /** The Name of the dataBase */ - private String dataBaseName; - /** The timeout of the connection */ - private int udpTimeout; - /** The port in which messages from web are sent to ivy buses */ - private int portWebToIvy ; - /** period of time in millisec to reset the filter of waypoint_moved messages */ - private long time2resetFilter; - /** period of time in millisec to send all the parameter values for a specific drone */ - private long timeToSendValues; - /** time to wait for the acknowledgement of an order */ - private int order_response_timeout; - /** time to wait after a die event to remove the drone */ - private int dieEventTimeoutTime; - /** time to wait after receiving no data for a drone to remove the drone */ - private int dataEventTimeoutTime; - /** period of time to check for dead ivy buses in serveur.java*/ - private long time2checkDeadBuses; - /** how the database work VERBOSE or SILENT*/ - private DbMode dbMode; - /** - * - * @param default_folder folder of the web application on the server - * @param conf_filename name of the configuration file placed in 'conf' folder of the web application - */ - public Conf(String default_folder,String conf_filename) - { - try{ - DocumentBuilderFactory fabrique = DocumentBuilderFactory.newInstance(); - // création d'un constructeur de documents - DocumentBuilder constructeur = fabrique.newDocumentBuilder(); - // lecture du contenu d'un fichier XML avec DOM - File xml = new File(default_folder + "/conf/"+conf_filename); - Document document = constructeur.parse(xml); - Element mailAdmin_node = (Element)document.getElementsByTagName("mailWebAdmin").item(0); - Element adminLogin_node = (Element)document.getElementsByTagName("webAdminLogin").item(0); - Element portIvyToWeb_node = (Element)document.getElementsByTagName("portIvyToWeb").item(0); - Element taille_node = (Element)document.getElementsByTagName("sizeUdpTrame").item(0); - Element passWord_node = (Element)document.getElementsByTagName("dbPassword").item(0); - Element userName_node = (Element)document.getElementsByTagName("dbUserName").item(0); - Element dataBaseName_node = (Element)document.getElementsByTagName("dataBaseName").item(0); - Element timeout_node = (Element)document.getElementsByTagName("udpSocketTimeout").item(0); - Element portWebToIvy_node = (Element)document.getElementsByTagName("portWebToIvy").item(0); - Element time2resetFilter_node = (Element)document.getElementsByTagName("time2resetFilter").item(0); - Element timeToSendValuesy_node = (Element)document.getElementsByTagName("timeToSendValues").item(0); - Element order_response_timeout_node = (Element)document.getElementsByTagName("order_response_timeout").item(0); - Element dieEventTimeoutTime_node = (Element)document.getElementsByTagName("dieEventTimeoutTime").item(0); - Element dataEventTimeoutTime_node = (Element)document.getElementsByTagName("dataEventTimeoutTime").item(0); - Element time2checkDeadBuses_node = (Element)document.getElementsByTagName("time2checkDeadBuses").item(0); - - Element dbMode_node = (Element)document.getElementsByTagName("dbMode").item(0); - String dbMode_str = dbMode_node.getTextContent(); - if (dbMode_str.equals("verbose")){dbMode = DbMode.VERBOSE;} - else {dbMode = DbMode.SILENT;} - mailAdmin=mailAdmin_node.getTextContent(); - adminLogin=adminLogin_node.getTextContent(); - portIvyToWeb=Integer.parseInt(portIvyToWeb_node.getTextContent()); - tailleUdpTrame=Integer.parseInt(taille_node.getTextContent()); - dbPassword=passWord_node.getTextContent(); - dbUserName=userName_node.getTextContent(); - dataBaseName=dataBaseName_node.getTextContent(); - udpTimeout=Integer.parseInt(timeout_node.getTextContent()); - portWebToIvy=Integer.parseInt(portWebToIvy_node.getTextContent()); - time2resetFilter=Long.parseLong(time2resetFilter_node.getTextContent()); - timeToSendValues=Long.parseLong(timeToSendValuesy_node.getTextContent()); - order_response_timeout=Integer.parseInt(order_response_timeout_node.getTextContent()); - dieEventTimeoutTime=Integer.parseInt(dieEventTimeoutTime_node.getTextContent()); - dataEventTimeoutTime=Integer.parseInt(dataEventTimeoutTime_node.getTextContent()); - time2checkDeadBuses =Integer.parseInt(time2checkDeadBuses_node.getTextContent()); - } catch(ParserConfigurationException pce){ - System.out.println("error in loading configuration file : "+default_folder + "/conf/"+conf_filename); - pce.printStackTrace(); - }catch(SAXException se){ - System.out.println("error in loading configuration file : "+default_folder + "/conf/"+conf_filename); - se.printStackTrace(); - }catch(IOException ioe){ - System.out.println("error in loading configuration file : "+default_folder + "/conf/"+conf_filename); - ioe.printStackTrace(); - } - } - /** @return the udp port on which the server receive data from ivy buses */ - public int portIvyToWeb() - { - return portIvyToWeb; - } - /** @return the udp port on which the server send data to ivy buses */ - public int portWebToIvy() - { - return portWebToIvy; - } - /** @return the max size of an udp trame */ - public int getUdpSize() - { - return tailleUdpTrame; - } - /** @return the password to connect to the database*/ - public String getDBPassword() - { - return dbPassword; - } - /** @return the login to connect to the database*/ - public String getDBUserName() - { - return dbUserName; - } - /** @return the database name*/ - public String getDataBaseName() - { - return dataBaseName; - } - /** @return a time after what an exception is thrown if no message has been received by server*/ - public int getSocketTimeout() - { - return udpTimeout; - } - /** @return the mail to contact if any problem occurs */ - public String mailAdmin(){return mailAdmin;} - /** @return the login of the administrator of the site */ - public String adminLogin(){return adminLogin;} - /**@return period of time in millisec to reset the filter of waypoint_moved messages */ - public long getTime2resetFilter(){return time2resetFilter;} - /**@return period of time in millisec to send all the parameter values for a specific drone */ - public long getTimeToSendValues(){return timeToSendValues;} - /**@return time to wait for the acknowledgement of an order */ - public int getOrderResponseTimeout(){return order_response_timeout;} - /**@return time to wait after a die event to remove the drone */ - public int getDieEventTimeoutTime(){return dieEventTimeoutTime;} - /**@return time to wait after receiving no data for a drone to remove the drone */ - public int getDataEventTimeoutTime(){return dataEventTimeoutTime;} - /**@return period of time to check for dead ivy buses in serveur.java*/ - public long getTime2checkDeadBuses(){return time2checkDeadBuses;} - /**@return SILENT or VERBOSE */ - public DbMode getDbMode(){return dbMode;} +package pow.webserver; +import java.io.*; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; +/** + * + * store useful data about the server configuration + * and database connection by + * reading a specific file place in the 'conf' folder of + * the web application + */ +public class Conf { + /** The mail of the administrator to contact if any problems occurs + * (appears in the help.jsp page. */ + private String mailAdmin; + /** The administrator login (not used). */ + private String adminLogin; + /** The port in which the module listen to get udp trames from ivy buses. */ + private int portIvyToWeb; + /** The dimension of the datagrams received. */ + private int tailleUdpTrame; + /** The passWord of the database */ + private String dbPassword; + /** The userName of the dataBase */ + private String dbUserName; + /** The Name of the dataBase */ + private String dataBaseName; + /** The timeout of the connection */ + private int udpTimeout; + /** The port in which messages from web are sent to ivy buses */ + private int portWebToIvy ; + /** period of time in millisec to reset the filter of waypoint_moved messages */ + private long time2resetFilter; + /** period of time in millisec to send all the parameter values for a specific drone */ + private long timeToSendValues; + /** time to wait for the acknowledgement of an order */ + private int order_response_timeout; + /** time to wait after a die event to remove the drone */ + private int dieEventTimeoutTime; + /** time to wait after receiving no data for a drone to remove the drone */ + private int dataEventTimeoutTime; + /** period of time to check for dead ivy buses in serveur.java*/ + private long time2checkDeadBuses; + /** how the database work VERBOSE or SILENT*/ + private DbMode dbMode; + /** + * + * @param default_folder folder of the web application on the server + * @param conf_filename name of the configuration file placed in 'conf' folder of the web application + */ + public Conf(String default_folder,String conf_filename) + { + try{ + DocumentBuilderFactory fabrique = DocumentBuilderFactory.newInstance(); + // création d'un constructeur de documents + DocumentBuilder constructeur = fabrique.newDocumentBuilder(); + // lecture du contenu d'un fichier XML avec DOM + File xml = new File(default_folder + "/conf/"+conf_filename); + Document document = constructeur.parse(xml); + Element mailAdmin_node = (Element)document.getElementsByTagName("mailWebAdmin").item(0); + Element adminLogin_node = (Element)document.getElementsByTagName("webAdminLogin").item(0); + Element portIvyToWeb_node = (Element)document.getElementsByTagName("portIvyToWeb").item(0); + Element taille_node = (Element)document.getElementsByTagName("sizeUdpTrame").item(0); + Element passWord_node = (Element)document.getElementsByTagName("dbPassword").item(0); + Element userName_node = (Element)document.getElementsByTagName("dbUserName").item(0); + Element dataBaseName_node = (Element)document.getElementsByTagName("dataBaseName").item(0); + Element timeout_node = (Element)document.getElementsByTagName("udpSocketTimeout").item(0); + Element portWebToIvy_node = (Element)document.getElementsByTagName("portWebToIvy").item(0); + Element time2resetFilter_node = (Element)document.getElementsByTagName("time2resetFilter").item(0); + Element timeToSendValuesy_node = (Element)document.getElementsByTagName("timeToSendValues").item(0); + Element order_response_timeout_node = (Element)document.getElementsByTagName("order_response_timeout").item(0); + Element dieEventTimeoutTime_node = (Element)document.getElementsByTagName("dieEventTimeoutTime").item(0); + Element dataEventTimeoutTime_node = (Element)document.getElementsByTagName("dataEventTimeoutTime").item(0); + Element time2checkDeadBuses_node = (Element)document.getElementsByTagName("time2checkDeadBuses").item(0); + + Element dbMode_node = (Element)document.getElementsByTagName("dbMode").item(0); + String dbMode_str = dbMode_node.getTextContent(); + if (dbMode_str.equals("verbose")){dbMode = DbMode.VERBOSE;} + else {dbMode = DbMode.SILENT;} + mailAdmin=mailAdmin_node.getTextContent(); + adminLogin=adminLogin_node.getTextContent(); + portIvyToWeb=Integer.parseInt(portIvyToWeb_node.getTextContent()); + tailleUdpTrame=Integer.parseInt(taille_node.getTextContent()); + dbPassword=passWord_node.getTextContent(); + dbUserName=userName_node.getTextContent(); + dataBaseName=dataBaseName_node.getTextContent(); + udpTimeout=Integer.parseInt(timeout_node.getTextContent()); + portWebToIvy=Integer.parseInt(portWebToIvy_node.getTextContent()); + time2resetFilter=Long.parseLong(time2resetFilter_node.getTextContent()); + timeToSendValues=Long.parseLong(timeToSendValuesy_node.getTextContent()); + order_response_timeout=Integer.parseInt(order_response_timeout_node.getTextContent()); + dieEventTimeoutTime=Integer.parseInt(dieEventTimeoutTime_node.getTextContent()); + dataEventTimeoutTime=Integer.parseInt(dataEventTimeoutTime_node.getTextContent()); + time2checkDeadBuses =Integer.parseInt(time2checkDeadBuses_node.getTextContent()); + } catch(ParserConfigurationException pce){ + System.out.println("error in loading configuration file : "+default_folder + "/conf/"+conf_filename); + pce.printStackTrace(); + }catch(SAXException se){ + System.out.println("error in loading configuration file : "+default_folder + "/conf/"+conf_filename); + se.printStackTrace(); + }catch(IOException ioe){ + System.out.println("error in loading configuration file : "+default_folder + "/conf/"+conf_filename); + ioe.printStackTrace(); + } + } + /** @return the udp port on which the server receive data from ivy buses */ + public int portIvyToWeb() + { + return portIvyToWeb; + } + /** @return the udp port on which the server send data to ivy buses */ + public int portWebToIvy() + { + return portWebToIvy; + } + /** @return the max size of an udp trame */ + public int getUdpSize() + { + return tailleUdpTrame; + } + /** @return the password to connect to the database*/ + public String getDBPassword() + { + return dbPassword; + } + /** @return the login to connect to the database*/ + public String getDBUserName() + { + return dbUserName; + } + /** @return the database name*/ + public String getDataBaseName() + { + return dataBaseName; + } + /** @return a time after what an exception is thrown if no message has been received by server*/ + public int getSocketTimeout() + { + return udpTimeout; + } + /** @return the mail to contact if any problem occurs */ + public String mailAdmin(){return mailAdmin;} + /** @return the login of the administrator of the site */ + public String adminLogin(){return adminLogin;} + /**@return period of time in millisec to reset the filter of waypoint_moved messages */ + public long getTime2resetFilter(){return time2resetFilter;} + /**@return period of time in millisec to send all the parameter values for a specific drone */ + public long getTimeToSendValues(){return timeToSendValues;} + /**@return time to wait for the acknowledgement of an order */ + public int getOrderResponseTimeout(){return order_response_timeout;} + /**@return time to wait after a die event to remove the drone */ + public int getDieEventTimeoutTime(){return dieEventTimeoutTime;} + /**@return time to wait after receiving no data for a drone to remove the drone */ + public int getDataEventTimeoutTime(){return dataEventTimeoutTime;} + /**@return period of time to check for dead ivy buses in serveur.java*/ + public long getTime2checkDeadBuses(){return time2checkDeadBuses;} + /**@return SILENT or VERBOSE */ + public DbMode getDbMode(){return dbMode;} } \ No newline at end of file diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/pow/webserver/Log.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/pow/webserver/Log.java index 7dce539a6c..9e22f610a9 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/pow/webserver/Log.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/src/pow/webserver/Log.java @@ -1,73 +1,73 @@ -package pow.webserver; -import java.io.*; -import java.util.Calendar; -/** - * Handles the writing of a log in a file - * @author from V1 - * @since V1 - */ -public class Log { - - private File oFile = null; - private FileWriter oFileWriter = null; - private BufferedWriter oBufferedWriter = null; - /** - * create a log file into the log floder of the web application - * @param path the complete path of the web application - */ - public Log(String path) - { - Calendar Today = Calendar.getInstance(); - String fileName = String.valueOf(Today.get(Calendar.DAY_OF_MONTH)) + - String.valueOf(Today.get(Calendar.MONTH)) + - String.valueOf(Today.get(Calendar.YEAR)) + - String.valueOf(Today.get(Calendar.HOUR_OF_DAY)) + - String.valueOf(Today.get(Calendar.MINUTE)) + - String.valueOf(Today.get(Calendar.SECOND)) + - ".log"; - - try - { - oFile = new File(path+"/log/" + fileName); - oFile.createNewFile(); - oFileWriter = new FileWriter(oFile); - oBufferedWriter = new BufferedWriter(oFileWriter); - - oBufferedWriter.write("##########################################"); oBufferedWriter.newLine(); - oBufferedWriter.write("########## PAPARAZZI ON THE WEB ##########"); oBufferedWriter.newLine(); - oBufferedWriter.write("##########################################"); oBufferedWriter.newLine(); - oBufferedWriter.newLine(); - oBufferedWriter.write("Beginning of log : "); oBufferedWriter.newLine(); - oBufferedWriter.newLine(); - oBufferedWriter.flush(); - } - catch(IOException ex) - { - System.out.println("No log file created "); - ex.printStackTrace(); - } - } - /** - * write a string in log file and on stdout - * @param writing the string to write in the log file - */ - public void write(String writing) - { - Calendar Now = Calendar.getInstance(); - String Time = String.valueOf(Now.get(Calendar.HOUR_OF_DAY)) + ":" + - String.valueOf(Now.get(Calendar.MINUTE)) + ":" + - String.valueOf(Now.get(Calendar.SECOND)); - writing = writing.trim(); - try - { - oBufferedWriter.write(Time + " -> " + writing); oBufferedWriter.newLine(); - oBufferedWriter.flush(); - System.out.println("\nlog at : " + Time + " -> " + writing); - } - catch(IOException ex) - { - System.out.println(ex.getMessage()); - } - - } +package pow.webserver; +import java.io.*; +import java.util.Calendar; +/** + * Handles the writing of a log in a file + * @author from V1 + * @since V1 + */ +public class Log { + + private File oFile = null; + private FileWriter oFileWriter = null; + private BufferedWriter oBufferedWriter = null; + /** + * create a log file into the log floder of the web application + * @param path the complete path of the web application + */ + public Log(String path) + { + Calendar Today = Calendar.getInstance(); + String fileName = String.valueOf(Today.get(Calendar.DAY_OF_MONTH)) + + String.valueOf(Today.get(Calendar.MONTH)) + + String.valueOf(Today.get(Calendar.YEAR)) + + String.valueOf(Today.get(Calendar.HOUR_OF_DAY)) + + String.valueOf(Today.get(Calendar.MINUTE)) + + String.valueOf(Today.get(Calendar.SECOND)) + + ".log"; + + try + { + oFile = new File(path+"/log/" + fileName); + oFile.createNewFile(); + oFileWriter = new FileWriter(oFile); + oBufferedWriter = new BufferedWriter(oFileWriter); + + oBufferedWriter.write("##########################################"); oBufferedWriter.newLine(); + oBufferedWriter.write("########## PAPARAZZI ON THE WEB ##########"); oBufferedWriter.newLine(); + oBufferedWriter.write("##########################################"); oBufferedWriter.newLine(); + oBufferedWriter.newLine(); + oBufferedWriter.write("Beginning of log : "); oBufferedWriter.newLine(); + oBufferedWriter.newLine(); + oBufferedWriter.flush(); + } + catch(IOException ex) + { + System.out.println("No log file created "); + ex.printStackTrace(); + } + } + /** + * write a string in log file and on stdout + * @param writing the string to write in the log file + */ + public void write(String writing) + { + Calendar Now = Calendar.getInstance(); + String Time = String.valueOf(Now.get(Calendar.HOUR_OF_DAY)) + ":" + + String.valueOf(Now.get(Calendar.MINUTE)) + ":" + + String.valueOf(Now.get(Calendar.SECOND)); + writing = writing.trim(); + try + { + oBufferedWriter.write(Time + " -> " + writing); oBufferedWriter.newLine(); + oBufferedWriter.flush(); + System.out.println("\nlog at : " + Time + " -> " + writing); + } + catch(IOException ex) + { + System.out.println(ex.getMessage()); + } + + } } \ No newline at end of file diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/client/PushletClient.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/client/PushletClient.java index f2dc390f26..e1c77ebcfa 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/client/PushletClient.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/client/PushletClient.java @@ -1,699 +1,699 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.client; - -import nl.justobjects.pushlet.core.Event; -import nl.justobjects.pushlet.core.EventParser; -import nl.justobjects.pushlet.core.Protocol; -import nl.justobjects.pushlet.util.PushletException; - -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Reader; -import java.io.OutputStream; -import java.net.*; -import java.util.Map; - -/** - * Client API for Java HTTP client applets or apps. - *

- * Use this class within Java client applications or applets. - * Implement a PushletClientListener to receive callbacks for - * data-related Event objects pushed by the server. - *

- * This class may also be used as a base class and be extended - * for custom clients, hence the presence of many proteced methods. - * - * @author Just van den Broecke - Just Objects © - * @version $Id: PushletClient.java,v 1.19 2009/06/04 12:46:35 justb Exp $ - * @see PushletClientListener - * @see nl.justobjects.pushlet.test.PushletApplet - * @see nl.justobjects.pushlet.test.PushletPingApplication - */ -public class PushletClient implements Protocol { - /** - * Pushlet URL. - */ - private String pushletURL; - - /** - * Debug flag for verbose output. - */ - private boolean debug; - - /** - * Id gotten on join ack - */ - private String id; - - /** - * Internal listener for data events pushed by server. - */ - protected DataEventListener dataEventListener; - - /** - * Constructor with full pushlet URL. - */ - public PushletClient(String aPushletURL) { - pushletURL = aPushletURL; - } - - /** - * Constructor with host and port using default URI. - */ - public PushletClient(String aHost, int aPort) { - this("http://" + aHost + ":" + aPort + DEFAULT_SERVLET_URI); - } - - /** - * Set proxy options and optional proxy authentication. - *

- * Contributed by Dele Olajide - * See http://groups.yahoo.com/group/pushlet/message/634 - *

- * Usage: - * PushletClient pushletClient = new PushletClient("http:://www.domain.com/pushlet"); - * pushletClient.setProxyOptions("proxy.bla.com", "8080", ....); - *

- * use pushletClient further as normal - */ - public void setProxyOptions(String aProxyHost, - String aProxyPort, String theNonProxyHosts, - String aUserName, String aPassword, String anNTLMDomain) { - - // Enable proxying - System.setProperty("http.proxySet", "true"); - System.setProperty("http.proxyHost", aProxyHost); - System.setProperty("http.proxyPort", aProxyPort); - - // Set optional non-proxy hosts - if (theNonProxyHosts != null) { - System.setProperty("http.nonProxyHosts", theNonProxyHosts); - } - - // If user name specified configure proxy authentication - if (aUserName != null) { - System.setProperty("http.proxyUser", aUserName); - System.setProperty("http.proxyPassword", aPassword); - - // See inner class below - Authenticator.setDefault(new HTTPAuthenticateProxy(aUserName, aPassword)); - - // Optional NT domain - if (anNTLMDomain != null) { - System.setProperty("http.auth.ntlm.domain", anNTLMDomain); - } - } - } - - /** - * Join server, starts session. - */ - public void join() throws PushletException { - Event event = new Event(E_JOIN); - event.setField(P_FORMAT, FORMAT_XML); - Event response = doControl(event); - throwOnNack(response); - - // Join Ack received - id = response.getField(P_ID); - } - - /** - * Leave server, stops session. - */ - public void leave() throws PushletException { - stopListen(); - throwOnInvalidSession(); - Event event = new Event(E_LEAVE); - event.setField(P_ID, id); - Event response = doControl(event); - - throwOnNack(response); - id = null; - } - - /** - * Open data channel. - */ - public void listen(PushletClientListener aListener) throws PushletException { - listen(aListener, MODE_STREAM); - } - - /** - * Open data channel in stream or push mode. - */ - public void listen(PushletClientListener aListener, String aMode) throws PushletException { - listen(aListener, aMode, null); - } - - /** - * Open data channel in stream or push mode with a subject. - */ - public void listen(PushletClientListener aListener, String aMode, String aSubject) throws PushletException { - throwOnInvalidSession(); - stopListen(); - - String listenURL = pushletURL - + "?" + P_EVENT + "=" + E_LISTEN - + "&" + P_ID + "=" + id - + "&" + P_MODE + "=" + aMode; - if (aSubject != null) { - listenURL = listenURL + "&" + P_SUBJECT + "=" + aSubject; - } - - // Start listener thread (sync call). - startDataEventListener(aListener, listenURL); - } - - /** - * Immediate listener: joins/subscribes and listens in one action. - */ - public void joinListen(PushletClientListener aListener, String aMode, String aSubject) throws PushletException { - stopListen(); - - String listenURL = pushletURL - + "?" + P_EVENT + "=" + E_JOIN_LISTEN - + "&" + P_FORMAT + "=" + FORMAT_XML - + "&" + P_MODE + "=" + aMode - + "&" + P_SUBJECT + "=" + aSubject; - - // Start listener thread (sync call). - startDataEventListener(aListener, listenURL); - } - - /** - * Publish an event through server. - */ - public void publish(String aSubject, Map theAttributes) throws PushletException { - throwOnInvalidSession(); - Event event = new Event(E_PUBLISH, theAttributes); - event.setField(P_SUBJECT, aSubject); - event.setField(P_ID, id); - Event response = doControl(event); - throwOnNack(response); - } - - /** - * Subscribes, returning subscription id. - */ - public String subscribe(String aSubject, String aLabel) throws PushletException { - throwOnInvalidSession(); - Event event = new Event(E_SUBSCRIBE); - event.setField(P_ID, id); - event.setField(P_SUBJECT, aSubject); - - // Optional label, is returned in data events - if (aLabel != null) { - event.setField(P_SUBSCRIPTION_LABEL, aLabel); - } - - // Send request - Event response = doControl(event); - throwOnNack(response); - - return response.getField(P_SUBSCRIPTION_ID); - } - - /** - * Subscribes, returning subscription id. - */ - public String subscribe(String aSubject) throws PushletException { - return subscribe(aSubject, null); - } - - /** - * Unsubscribes with subscription id. - */ - public void unsubscribe(String aSubscriptionId) throws PushletException { - throwOnInvalidSession(); - Event event = new Event(E_UNSUBSCRIBE); - event.setField(P_ID, id); - - // Optional subscription id - if (aSubscriptionId != null) { - event.setField(P_SUBSCRIPTION_ID, aSubscriptionId); - } - - Event response = doControl(event); - throwOnNack(response); - } - - /** - * Unsubscribes from all subjects. - */ - public void unsubscribe() throws PushletException { - unsubscribe(null); - } - - /** - * Stop the listener. - */ - public void stopListen() throws PushletException { - if (dataEventListener != null) { - unsubscribe(); - dataEventListener.stop(); - dataEventListener = null; - } - } - - public void setDebug(boolean b) { - debug = b; - } - - /** - * Starts default DataEventListener and waits for its thread to start. - */ - protected void startDataEventListener(PushletClientListener aListener, String aListenURL) { - // Suggestion by Jeff Nowakowski 29.oct.2006 - dataEventListener = new DataEventListener(aListener, aListenURL); - - synchronized (dataEventListener) { - dataEventListener.start(); - try { - // Wait for data event listener (thread) to start - dataEventListener.wait(); - } catch (InterruptedException e) { - } - } - } - - protected void throwOnNack(Event anEvent) throws PushletException { - if (anEvent.getEventType().equals(E_NACK)) { - throw new PushletException("Negative response: reason=" + anEvent.getField(P_REASON)); - } - } - - protected void throwOnInvalidSession() throws PushletException { - if (id == null) { - throw new PushletException("Invalid pushlet session"); - } - } - - protected Reader openURL(String aURL) throws PushletException { - // Open URL connection with server - try { - p("Connecting to " + aURL); - URL url = new URL(aURL); - URLConnection urlConnection = url.openConnection(); - - // Disable any kind of caching. - urlConnection.setUseCaches(false); - urlConnection.setDefaultUseCaches(false); - - // TODO: later version may use POST - // Enable HTTP POST - // urlConnection.setDoOutput(true); - - // Do the POST with Event in XML in body - // OutputStream os = urlConnection.getOutputStream(); - // os.write(anEvent.toXML().getBytes()); - // os.flush(); - // os.close(); - - // Get the stream from the server. - // reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); - // Note: somehow the client does not work with some JVMs when using - // BufferedInputStream... So do unbuffered input. - // p("Opening urlConnection inputstream"); - return new InputStreamReader(urlConnection.getInputStream()); - - } catch (Throwable t) { - warn("openURL() could not open " + aURL, t); - throw new PushletException(" could not open " + aURL, t); - } - } - - - /** - * Send control events to server and return response. - */ - protected Event doControl(Event aControlEvent) throws PushletException { - String controlURL = pushletURL + "?" + aControlEvent.toQueryString(); - - p("doControl to " + controlURL); - - // Open URL connection with server - Reader reader = openURL(controlURL); - - // Get Pushlet event from stream - Event event = null; - try { - p("Getting event..."); - // Get next event from server - event = EventParser.parse(reader); - p("Event received " + event); - return event; - } catch (Throwable t) { - // Stop and report error. - warn("doControl() exception", t); - throw new PushletException(" error parsing response from" + controlURL, t); - } - } - - /** - * Util: print. - */ - protected void p(String s) { - if (debug) { - System.out.println("[PushletClient] " + s); - } - } - - /** - * Util: warn. - */ - protected void warn(String s) { - warn(s, null); - } - - /** - * Util: warn with exception. - */ - protected void warn(String s, Throwable t) { - System.err.println("[PushletClient] - WARN - " + s + " ex=" + t); - - if (t != null) { - t.printStackTrace(); - } - } - - /** - * Internal (default) listener for the Pushlet data channel. - */ - protected class DataEventListener implements Runnable { - /** - * Client's listener that gets called back on events. - */ - private PushletClientListener listener; - - /** - * Receiver receiveThread. - */ - private Thread receiveThread = null; - private Reader reader; - private String refreshURL; - private String listenURL; - - public DataEventListener(PushletClientListener aListener, String aListenURL) { - listener = aListener; - listenURL = aListenURL; - } - - public void start() { - // All ok: start a receiver receiveThread - receiveThread = new Thread(this); - receiveThread.start(); - - } - - /** - * Stop listening; may restart later with start(). - */ - public void stop() { - p("In stop()"); - bailout(); - } - - /** - * Receive event objects from server and callback listener. - */ - public void run() { - p("Start run()"); - try { - while (receiveThread != null && receiveThread.isAlive()) { - // Connect to server - reader = openURL(listenURL); - - synchronized (this) { - // Inform the calling thread we're ready to receive events. - // Suggestion by Jeff Nowakowski 29.oct.2006 - this.notify(); - } - - // Get events while we're alive. - while (receiveThread != null && receiveThread.isAlive()) { - Event event = null; - try { - // p("Getting event..."); - // Get next event from server - event = EventParser.parse(reader); - p("Event received " + event); - } catch (Throwable t) { - - // Stop and report error. - // warn("Stop run() on exception", t); - if (listener != null) { - listener.onError("exception during receive: " + t); - } - - break; - } - - // Handle event by calling listener - if (event != null && listener != null) { - // p("received: " + event.toXML()); - String eventType = event.getEventType(); - if (eventType.equals(E_HEARTBEAT)) { - listener.onHeartbeat(event); - } else if (eventType.equals(E_DATA)) { - listener.onData(event); - } else if (eventType.equals(E_JOIN_LISTEN_ACK)) { - id = event.getField(P_ID); - } else if (eventType.equals(E_LISTEN_ACK)) { - p("Listen ack ok"); - } else if (eventType.equals(E_REFRESH_ACK)) { - // ignore - } else if (eventType.equals(E_ABORT)) { - listener.onAbort(event); - listener = null; - break; - } else if (eventType.equals(E_REFRESH)) { - refresh(event); - } else { - handleUnknownEventType(eventType, event, listener); - } - } - } - } - } catch (Throwable t) { - warn("Exception in run() ", t); - // bailout(); - } - } - - protected void disconnect() { - p("start disconnect()"); - if (reader != null) { - try { - // this blocks, find another way - // reader.close(); - p("Closed reader ok"); - } catch (Exception ignore) { - } finally { - reader = null; - } - } - p("end disconnect()"); - } - - /** - * Stop receiver receiveThread. - */ - public void stopThread() { - p("In stopThread()"); - - // Keep a reference such that we can kill it from here. - Thread targetThread = receiveThread; - - receiveThread = null; - - // This should stop the main loop for this receiveThread. - // Killing a receiveThread on a blcing read is tricky. - // See also http://gee.cs.oswego.edu/dl/cpj/cancel.html - if ((targetThread != null) && targetThread.isAlive()) { - - targetThread.interrupt(); - - try { - - // Wait for it to die - targetThread.join(500); - } catch (InterruptedException ignore) { - } - - // If current receiveThread refuses to die, - // take more rigorous methods. - if (targetThread.isAlive()) { - - // Not preferred but may be needed - // to stop during a blocking read. - targetThread.stop(); - - // Wait for it to die - try { - targetThread.join(500); - } catch (Throwable ignore) { - } - } - - p("Stopped receiveThread alive=" + targetThread.isAlive()); - - } - } - - /** - * Stop listening on stream from server. - */ - public void bailout() { - p("In bailout()"); - stopThread(); - disconnect(); - } - - /** - * Handle refresh, by pausing. - */ - protected void refresh(Event aRefreshEvent) throws PushletException { - try { - // Wait for specified time. - Thread.sleep(Long.parseLong(aRefreshEvent.getField(P_WAIT))); - } catch (Throwable t) { - warn("abort while refresing"); - refreshURL = null; - return; - } - - // If stopped during sleep, don't proceed - if (receiveThread == null) { - return; - } - - // Create url to refresh - refreshURL = pushletURL - + "?" + P_ID + "=" + id - + "&" + P_EVENT + "=" + E_REFRESH - ; - - if (reader != null) { - try { - reader.close(); - - } catch (IOException ignore) { - - } - reader = null; - } - - reader = openURL(refreshURL); - } - - /** - * Handle unknown Event (default behaviour). - */ - protected void handleUnknownEventType(String eventType, Event event, PushletClientListener listener) { - warn("unsupported event type received: " + eventType); - } - } - - /** - * Authenticator - */ - private static class HTTPAuthenticateProxy extends Authenticator { - - /** - * Contributed by Dele Olajide - * See http://groups.yahoo.com/group/pushlet/message/634 - */ - - private String thePassword = ""; - private String theUser = ""; - - public HTTPAuthenticateProxy(String username, String password) { - - thePassword = password; - theUser = username; - } - - protected PasswordAuthentication getPasswordAuthentication() { - // System.out.println("[HttpAuthenticateProxy] Username = " + theUser); - // System.out.println("[HttpAuthenticateProxy] Password = " + thePassword); - - return new PasswordAuthentication(theUser, thePassword.toCharArray()); - } - - } - -} - -/* - * $Log: PushletClient.java,v $ - * Revision 1.19 2009/06/04 12:46:35 justb - * PushletClient: add more hooks for extension (feat ID: 2799694 Craig M) - * - * Revision 1.18 2007/11/10 13:52:47 justb - * make startDataEventListener method protected to allow overriding - * - * Revision 1.17 2006/10/29 16:47:57 justb - * included patch from Jeff Nowakowski: wait until listener thread runs - * - * Revision 1.16 2005/05/06 20:08:20 justb - * client enhancements - * - * Revision 1.15 2005/03/27 17:42:27 justb - * enhancements - * - * Revision 1.14 2005/03/25 23:54:04 justb - * *** empty log message *** - * - * Revision 1.13 2005/02/28 16:59:40 justb - * fixes for leave and disconnect - * - * Revision 1.12 2005/02/28 15:57:54 justb - * added SimpleListener example - * - * Revision 1.11 2005/02/21 12:31:44 justb - * added proxy contribution from Dele Olajide - * - * Revision 1.10 2005/02/20 13:05:32 justb - * removed the Postlet (integrated in Pushlet protocol) - * - * Revision 1.9 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.8 2005/02/18 09:54:12 justb - * refactor: rename Publisher Dispatcher and single Subscriber class - * - * Revision 1.7 2005/02/15 15:46:30 justb - * client API improves - * - * Revision 1.6 2005/02/15 13:28:56 justb - * first quick rewrite adapt for v2 protocol - * - * Revision 1.5 2004/10/25 21:23:44 justb - * *** empty log message *** - * - * Revision 1.4 2004/10/24 13:52:51 justb - * small fixes in client lib - * - * Revision 1.3 2004/10/24 12:58:18 justb - * revised client and test classes for new protocol - * - * Revision 1.2 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.1 2004/03/10 20:14:17 justb - * renamed all *JavaPushletClient* to *PushletClient* - * - * Revision 1.10 2004/03/10 15:45:55 justb - * many cosmetic changes - * - * Revision 1.9 2003/08/17 20:30:20 justb - * cosmetic changes - * - * Revision 1.8 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.client; + +import nl.justobjects.pushlet.core.Event; +import nl.justobjects.pushlet.core.EventParser; +import nl.justobjects.pushlet.core.Protocol; +import nl.justobjects.pushlet.util.PushletException; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.OutputStream; +import java.net.*; +import java.util.Map; + +/** + * Client API for Java HTTP client applets or apps. + *

+ * Use this class within Java client applications or applets. + * Implement a PushletClientListener to receive callbacks for + * data-related Event objects pushed by the server. + *

+ * This class may also be used as a base class and be extended + * for custom clients, hence the presence of many proteced methods. + * + * @author Just van den Broecke - Just Objects © + * @version $Id: PushletClient.java,v 1.19 2009/06/04 12:46:35 justb Exp $ + * @see PushletClientListener + * @see nl.justobjects.pushlet.test.PushletApplet + * @see nl.justobjects.pushlet.test.PushletPingApplication + */ +public class PushletClient implements Protocol { + /** + * Pushlet URL. + */ + private String pushletURL; + + /** + * Debug flag for verbose output. + */ + private boolean debug; + + /** + * Id gotten on join ack + */ + private String id; + + /** + * Internal listener for data events pushed by server. + */ + protected DataEventListener dataEventListener; + + /** + * Constructor with full pushlet URL. + */ + public PushletClient(String aPushletURL) { + pushletURL = aPushletURL; + } + + /** + * Constructor with host and port using default URI. + */ + public PushletClient(String aHost, int aPort) { + this("http://" + aHost + ":" + aPort + DEFAULT_SERVLET_URI); + } + + /** + * Set proxy options and optional proxy authentication. + *

+ * Contributed by Dele Olajide + * See http://groups.yahoo.com/group/pushlet/message/634 + *

+ * Usage: + * PushletClient pushletClient = new PushletClient("http:://www.domain.com/pushlet"); + * pushletClient.setProxyOptions("proxy.bla.com", "8080", ....); + *

+ * use pushletClient further as normal + */ + public void setProxyOptions(String aProxyHost, + String aProxyPort, String theNonProxyHosts, + String aUserName, String aPassword, String anNTLMDomain) { + + // Enable proxying + System.setProperty("http.proxySet", "true"); + System.setProperty("http.proxyHost", aProxyHost); + System.setProperty("http.proxyPort", aProxyPort); + + // Set optional non-proxy hosts + if (theNonProxyHosts != null) { + System.setProperty("http.nonProxyHosts", theNonProxyHosts); + } + + // If user name specified configure proxy authentication + if (aUserName != null) { + System.setProperty("http.proxyUser", aUserName); + System.setProperty("http.proxyPassword", aPassword); + + // See inner class below + Authenticator.setDefault(new HTTPAuthenticateProxy(aUserName, aPassword)); + + // Optional NT domain + if (anNTLMDomain != null) { + System.setProperty("http.auth.ntlm.domain", anNTLMDomain); + } + } + } + + /** + * Join server, starts session. + */ + public void join() throws PushletException { + Event event = new Event(E_JOIN); + event.setField(P_FORMAT, FORMAT_XML); + Event response = doControl(event); + throwOnNack(response); + + // Join Ack received + id = response.getField(P_ID); + } + + /** + * Leave server, stops session. + */ + public void leave() throws PushletException { + stopListen(); + throwOnInvalidSession(); + Event event = new Event(E_LEAVE); + event.setField(P_ID, id); + Event response = doControl(event); + + throwOnNack(response); + id = null; + } + + /** + * Open data channel. + */ + public void listen(PushletClientListener aListener) throws PushletException { + listen(aListener, MODE_STREAM); + } + + /** + * Open data channel in stream or push mode. + */ + public void listen(PushletClientListener aListener, String aMode) throws PushletException { + listen(aListener, aMode, null); + } + + /** + * Open data channel in stream or push mode with a subject. + */ + public void listen(PushletClientListener aListener, String aMode, String aSubject) throws PushletException { + throwOnInvalidSession(); + stopListen(); + + String listenURL = pushletURL + + "?" + P_EVENT + "=" + E_LISTEN + + "&" + P_ID + "=" + id + + "&" + P_MODE + "=" + aMode; + if (aSubject != null) { + listenURL = listenURL + "&" + P_SUBJECT + "=" + aSubject; + } + + // Start listener thread (sync call). + startDataEventListener(aListener, listenURL); + } + + /** + * Immediate listener: joins/subscribes and listens in one action. + */ + public void joinListen(PushletClientListener aListener, String aMode, String aSubject) throws PushletException { + stopListen(); + + String listenURL = pushletURL + + "?" + P_EVENT + "=" + E_JOIN_LISTEN + + "&" + P_FORMAT + "=" + FORMAT_XML + + "&" + P_MODE + "=" + aMode + + "&" + P_SUBJECT + "=" + aSubject; + + // Start listener thread (sync call). + startDataEventListener(aListener, listenURL); + } + + /** + * Publish an event through server. + */ + public void publish(String aSubject, Map theAttributes) throws PushletException { + throwOnInvalidSession(); + Event event = new Event(E_PUBLISH, theAttributes); + event.setField(P_SUBJECT, aSubject); + event.setField(P_ID, id); + Event response = doControl(event); + throwOnNack(response); + } + + /** + * Subscribes, returning subscription id. + */ + public String subscribe(String aSubject, String aLabel) throws PushletException { + throwOnInvalidSession(); + Event event = new Event(E_SUBSCRIBE); + event.setField(P_ID, id); + event.setField(P_SUBJECT, aSubject); + + // Optional label, is returned in data events + if (aLabel != null) { + event.setField(P_SUBSCRIPTION_LABEL, aLabel); + } + + // Send request + Event response = doControl(event); + throwOnNack(response); + + return response.getField(P_SUBSCRIPTION_ID); + } + + /** + * Subscribes, returning subscription id. + */ + public String subscribe(String aSubject) throws PushletException { + return subscribe(aSubject, null); + } + + /** + * Unsubscribes with subscription id. + */ + public void unsubscribe(String aSubscriptionId) throws PushletException { + throwOnInvalidSession(); + Event event = new Event(E_UNSUBSCRIBE); + event.setField(P_ID, id); + + // Optional subscription id + if (aSubscriptionId != null) { + event.setField(P_SUBSCRIPTION_ID, aSubscriptionId); + } + + Event response = doControl(event); + throwOnNack(response); + } + + /** + * Unsubscribes from all subjects. + */ + public void unsubscribe() throws PushletException { + unsubscribe(null); + } + + /** + * Stop the listener. + */ + public void stopListen() throws PushletException { + if (dataEventListener != null) { + unsubscribe(); + dataEventListener.stop(); + dataEventListener = null; + } + } + + public void setDebug(boolean b) { + debug = b; + } + + /** + * Starts default DataEventListener and waits for its thread to start. + */ + protected void startDataEventListener(PushletClientListener aListener, String aListenURL) { + // Suggestion by Jeff Nowakowski 29.oct.2006 + dataEventListener = new DataEventListener(aListener, aListenURL); + + synchronized (dataEventListener) { + dataEventListener.start(); + try { + // Wait for data event listener (thread) to start + dataEventListener.wait(); + } catch (InterruptedException e) { + } + } + } + + protected void throwOnNack(Event anEvent) throws PushletException { + if (anEvent.getEventType().equals(E_NACK)) { + throw new PushletException("Negative response: reason=" + anEvent.getField(P_REASON)); + } + } + + protected void throwOnInvalidSession() throws PushletException { + if (id == null) { + throw new PushletException("Invalid pushlet session"); + } + } + + protected Reader openURL(String aURL) throws PushletException { + // Open URL connection with server + try { + p("Connecting to " + aURL); + URL url = new URL(aURL); + URLConnection urlConnection = url.openConnection(); + + // Disable any kind of caching. + urlConnection.setUseCaches(false); + urlConnection.setDefaultUseCaches(false); + + // TODO: later version may use POST + // Enable HTTP POST + // urlConnection.setDoOutput(true); + + // Do the POST with Event in XML in body + // OutputStream os = urlConnection.getOutputStream(); + // os.write(anEvent.toXML().getBytes()); + // os.flush(); + // os.close(); + + // Get the stream from the server. + // reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); + // Note: somehow the client does not work with some JVMs when using + // BufferedInputStream... So do unbuffered input. + // p("Opening urlConnection inputstream"); + return new InputStreamReader(urlConnection.getInputStream()); + + } catch (Throwable t) { + warn("openURL() could not open " + aURL, t); + throw new PushletException(" could not open " + aURL, t); + } + } + + + /** + * Send control events to server and return response. + */ + protected Event doControl(Event aControlEvent) throws PushletException { + String controlURL = pushletURL + "?" + aControlEvent.toQueryString(); + + p("doControl to " + controlURL); + + // Open URL connection with server + Reader reader = openURL(controlURL); + + // Get Pushlet event from stream + Event event = null; + try { + p("Getting event..."); + // Get next event from server + event = EventParser.parse(reader); + p("Event received " + event); + return event; + } catch (Throwable t) { + // Stop and report error. + warn("doControl() exception", t); + throw new PushletException(" error parsing response from" + controlURL, t); + } + } + + /** + * Util: print. + */ + protected void p(String s) { + if (debug) { + System.out.println("[PushletClient] " + s); + } + } + + /** + * Util: warn. + */ + protected void warn(String s) { + warn(s, null); + } + + /** + * Util: warn with exception. + */ + protected void warn(String s, Throwable t) { + System.err.println("[PushletClient] - WARN - " + s + " ex=" + t); + + if (t != null) { + t.printStackTrace(); + } + } + + /** + * Internal (default) listener for the Pushlet data channel. + */ + protected class DataEventListener implements Runnable { + /** + * Client's listener that gets called back on events. + */ + private PushletClientListener listener; + + /** + * Receiver receiveThread. + */ + private Thread receiveThread = null; + private Reader reader; + private String refreshURL; + private String listenURL; + + public DataEventListener(PushletClientListener aListener, String aListenURL) { + listener = aListener; + listenURL = aListenURL; + } + + public void start() { + // All ok: start a receiver receiveThread + receiveThread = new Thread(this); + receiveThread.start(); + + } + + /** + * Stop listening; may restart later with start(). + */ + public void stop() { + p("In stop()"); + bailout(); + } + + /** + * Receive event objects from server and callback listener. + */ + public void run() { + p("Start run()"); + try { + while (receiveThread != null && receiveThread.isAlive()) { + // Connect to server + reader = openURL(listenURL); + + synchronized (this) { + // Inform the calling thread we're ready to receive events. + // Suggestion by Jeff Nowakowski 29.oct.2006 + this.notify(); + } + + // Get events while we're alive. + while (receiveThread != null && receiveThread.isAlive()) { + Event event = null; + try { + // p("Getting event..."); + // Get next event from server + event = EventParser.parse(reader); + p("Event received " + event); + } catch (Throwable t) { + + // Stop and report error. + // warn("Stop run() on exception", t); + if (listener != null) { + listener.onError("exception during receive: " + t); + } + + break; + } + + // Handle event by calling listener + if (event != null && listener != null) { + // p("received: " + event.toXML()); + String eventType = event.getEventType(); + if (eventType.equals(E_HEARTBEAT)) { + listener.onHeartbeat(event); + } else if (eventType.equals(E_DATA)) { + listener.onData(event); + } else if (eventType.equals(E_JOIN_LISTEN_ACK)) { + id = event.getField(P_ID); + } else if (eventType.equals(E_LISTEN_ACK)) { + p("Listen ack ok"); + } else if (eventType.equals(E_REFRESH_ACK)) { + // ignore + } else if (eventType.equals(E_ABORT)) { + listener.onAbort(event); + listener = null; + break; + } else if (eventType.equals(E_REFRESH)) { + refresh(event); + } else { + handleUnknownEventType(eventType, event, listener); + } + } + } + } + } catch (Throwable t) { + warn("Exception in run() ", t); + // bailout(); + } + } + + protected void disconnect() { + p("start disconnect()"); + if (reader != null) { + try { + // this blocks, find another way + // reader.close(); + p("Closed reader ok"); + } catch (Exception ignore) { + } finally { + reader = null; + } + } + p("end disconnect()"); + } + + /** + * Stop receiver receiveThread. + */ + public void stopThread() { + p("In stopThread()"); + + // Keep a reference such that we can kill it from here. + Thread targetThread = receiveThread; + + receiveThread = null; + + // This should stop the main loop for this receiveThread. + // Killing a receiveThread on a blcing read is tricky. + // See also http://gee.cs.oswego.edu/dl/cpj/cancel.html + if ((targetThread != null) && targetThread.isAlive()) { + + targetThread.interrupt(); + + try { + + // Wait for it to die + targetThread.join(500); + } catch (InterruptedException ignore) { + } + + // If current receiveThread refuses to die, + // take more rigorous methods. + if (targetThread.isAlive()) { + + // Not preferred but may be needed + // to stop during a blocking read. + targetThread.stop(); + + // Wait for it to die + try { + targetThread.join(500); + } catch (Throwable ignore) { + } + } + + p("Stopped receiveThread alive=" + targetThread.isAlive()); + + } + } + + /** + * Stop listening on stream from server. + */ + public void bailout() { + p("In bailout()"); + stopThread(); + disconnect(); + } + + /** + * Handle refresh, by pausing. + */ + protected void refresh(Event aRefreshEvent) throws PushletException { + try { + // Wait for specified time. + Thread.sleep(Long.parseLong(aRefreshEvent.getField(P_WAIT))); + } catch (Throwable t) { + warn("abort while refresing"); + refreshURL = null; + return; + } + + // If stopped during sleep, don't proceed + if (receiveThread == null) { + return; + } + + // Create url to refresh + refreshURL = pushletURL + + "?" + P_ID + "=" + id + + "&" + P_EVENT + "=" + E_REFRESH + ; + + if (reader != null) { + try { + reader.close(); + + } catch (IOException ignore) { + + } + reader = null; + } + + reader = openURL(refreshURL); + } + + /** + * Handle unknown Event (default behaviour). + */ + protected void handleUnknownEventType(String eventType, Event event, PushletClientListener listener) { + warn("unsupported event type received: " + eventType); + } + } + + /** + * Authenticator + */ + private static class HTTPAuthenticateProxy extends Authenticator { + + /** + * Contributed by Dele Olajide + * See http://groups.yahoo.com/group/pushlet/message/634 + */ + + private String thePassword = ""; + private String theUser = ""; + + public HTTPAuthenticateProxy(String username, String password) { + + thePassword = password; + theUser = username; + } + + protected PasswordAuthentication getPasswordAuthentication() { + // System.out.println("[HttpAuthenticateProxy] Username = " + theUser); + // System.out.println("[HttpAuthenticateProxy] Password = " + thePassword); + + return new PasswordAuthentication(theUser, thePassword.toCharArray()); + } + + } + +} + +/* + * $Log: PushletClient.java,v $ + * Revision 1.19 2009/06/04 12:46:35 justb + * PushletClient: add more hooks for extension (feat ID: 2799694 Craig M) + * + * Revision 1.18 2007/11/10 13:52:47 justb + * make startDataEventListener method protected to allow overriding + * + * Revision 1.17 2006/10/29 16:47:57 justb + * included patch from Jeff Nowakowski: wait until listener thread runs + * + * Revision 1.16 2005/05/06 20:08:20 justb + * client enhancements + * + * Revision 1.15 2005/03/27 17:42:27 justb + * enhancements + * + * Revision 1.14 2005/03/25 23:54:04 justb + * *** empty log message *** + * + * Revision 1.13 2005/02/28 16:59:40 justb + * fixes for leave and disconnect + * + * Revision 1.12 2005/02/28 15:57:54 justb + * added SimpleListener example + * + * Revision 1.11 2005/02/21 12:31:44 justb + * added proxy contribution from Dele Olajide + * + * Revision 1.10 2005/02/20 13:05:32 justb + * removed the Postlet (integrated in Pushlet protocol) + * + * Revision 1.9 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.8 2005/02/18 09:54:12 justb + * refactor: rename Publisher Dispatcher and single Subscriber class + * + * Revision 1.7 2005/02/15 15:46:30 justb + * client API improves + * + * Revision 1.6 2005/02/15 13:28:56 justb + * first quick rewrite adapt for v2 protocol + * + * Revision 1.5 2004/10/25 21:23:44 justb + * *** empty log message *** + * + * Revision 1.4 2004/10/24 13:52:51 justb + * small fixes in client lib + * + * Revision 1.3 2004/10/24 12:58:18 justb + * revised client and test classes for new protocol + * + * Revision 1.2 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.1 2004/03/10 20:14:17 justb + * renamed all *JavaPushletClient* to *PushletClient* + * + * Revision 1.10 2004/03/10 15:45:55 justb + * many cosmetic changes + * + * Revision 1.9 2003/08/17 20:30:20 justb + * cosmetic changes + * + * Revision 1.8 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * */ \ No newline at end of file diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/client/PushletClientListener.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/client/PushletClientListener.java index 74cee7b2b2..864e2ef7dd 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/client/PushletClientListener.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/client/PushletClientListener.java @@ -1,50 +1,50 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.client; - -import nl.justobjects.pushlet.core.Event; -import nl.justobjects.pushlet.core.Protocol; - -/** - * Interface for listener of the PushletClient object. - * - * @version $Id: PushletClientListener.java,v 1.5 2005/02/21 11:50:37 justb Exp $ - * @author Just van den Broecke - Just Objects © - **/ -public interface PushletClientListener extends Protocol { - /** Abort event from server. */ - public void onAbort(Event theEvent); - - /** Data event from server. */ - public void onData(Event theEvent); - - /** Heartbeat event from server. */ - public void onHeartbeat(Event theEvent); - - /** Error occurred. */ - public void onError(String message); -} - -/* +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.client; + +import nl.justobjects.pushlet.core.Event; +import nl.justobjects.pushlet.core.Protocol; + +/** + * Interface for listener of the PushletClient object. + * + * @version $Id: PushletClientListener.java,v 1.5 2005/02/21 11:50:37 justb Exp $ + * @author Just van den Broecke - Just Objects © + **/ +public interface PushletClientListener extends Protocol { + /** Abort event from server. */ + public void onAbort(Event theEvent); + + /** Data event from server. */ + public void onData(Event theEvent); + + /** Heartbeat event from server. */ + public void onHeartbeat(Event theEvent); + + /** Error occurred. */ + public void onError(String message); +} + +/* * $Log: PushletClientListener.java,v $ * Revision 1.5 2005/02/21 11:50:37 justb * ohase1 of refactoring Subscriber into Session/Controller/Subscriber -* -* Revision 1.4 2005/02/15 15:46:31 justb -* client API improves -* -* Revision 1.3 2004/10/24 12:58:18 justb -* revised client and test classes for new protocol -* -* Revision 1.2 2004/09/03 22:35:37 justb -* Almost complete rewrite, just checking in now -* -* Revision 1.1 2004/03/10 20:14:17 justb -* renamed all *JavaPushletClient* to *PushletClient* -* -* Revision 1.3 2003/08/15 08:37:40 justb -* fix/add Copyright+LGPL file headers and footers -* -* +* +* Revision 1.4 2005/02/15 15:46:31 justb +* client API improves +* +* Revision 1.3 2004/10/24 12:58:18 justb +* revised client and test classes for new protocol +* +* Revision 1.2 2004/09/03 22:35:37 justb +* Almost complete rewrite, just checking in now +* +* Revision 1.1 2004/03/10 20:14:17 justb +* renamed all *JavaPushletClient* to *PushletClient* +* +* Revision 1.3 2003/08/15 08:37:40 justb +* fix/add Copyright+LGPL file headers and footers +* +* */ \ No newline at end of file diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/BrowserAdapter.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/BrowserAdapter.java index 8aa226b659..d523882f49 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/BrowserAdapter.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/BrowserAdapter.java @@ -1,203 +1,203 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -import nl.justobjects.pushlet.util.Log; - -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.Iterator; - -/** - * Generic implementation of ClientAdapter for browser clients. - * - * @author Just van den Broecke - Just Objects © - * @version $Id: BrowserAdapter.java,v 1.6 2007/11/09 13:15:35 justb Exp $ - */ -public class BrowserAdapter implements ClientAdapter, Protocol { - - public static final String START_DOCUMENT = - "" - + "" - + "\n"; - public static final String END_DOCUMENT = ""; - - private PrintWriter servletOut; - private HttpServletResponse servletRsp; - private int bytesSent; - - /** - * Constructor. - */ - public BrowserAdapter(HttpServletResponse aServletResponse) { - servletRsp = aServletResponse; - } - - /** - * Generic init. - */ - public void start() throws IOException { - // Keep servlet request/response objects until page ends in stop() - // Content type as HTML - servletRsp.setStatus(HttpServletResponse.SC_OK); - servletRsp.setContentType("text/html;charset=UTF-8"); - - // http://www.junlu.com/msg/45902.html - // Log.debug("bufsize=" + aRsp.getBufferSize()); - servletOut = servletRsp.getWriter(); - send(START_DOCUMENT); - } - - /** - * Push Event to client. - */ - public void push(Event anEvent) throws IOException { - Log.debug("BCA event=" + anEvent.toXML()); - - // Check if we should refresh - if (anEvent.getEventType().equals(Protocol.E_REFRESH)) { - // Append refresh and tail of HTML document - // Construct the JS callback line to be sent as last line of doc. - // This will refresh the request using the unique id to determine - // the subscriber instance on the server. The client will wait for - // a number of milliseconds. - long refreshWaitMillis = Long.parseLong(anEvent.getField(P_WAIT)); - - // Create servlet request for requesting next events (refresh) - String url = anEvent.getField(P_URL); - String jsRefreshTrigger = "\n"; - - - send(jsRefreshTrigger + END_DOCUMENT); - } else { - send(event2JavaScript(anEvent)); - } - } - - /** - * End HTML page in client browser. - */ - public void stop() { - // To be garbage collected if adapter remains active - servletOut = null; - } - - /** - * Send any string to browser. - */ - protected void send(String s) throws IOException { - // Send string to browser. - // Log.debug("Adapter: sending: " + s); - if (servletOut == null) { - throw new IOException("Client adapter was stopped"); - } - - servletOut.print(s); - - servletOut.flush(); - - // Note: this doesn't seem to have effect - // in Tomcat 4/5 if the client already disconnected. - servletRsp.flushBuffer(); - - bytesSent += s.length(); - Log.debug("bytesSent= " + bytesSent); - // Log.debug("BCA sent event: " + s); - } - - /** - * Converts the Java Event to a JavaScript function call in browser page. - */ - protected String event2JavaScript(Event event) throws IOException { - - // Convert the event to a comma-separated string. - String jsArgs = ""; - for (Iterator iter = event.getFieldNames(); iter.hasNext();) { - String name = (String) iter.next(); - String value = event.getField(name); - String nextArgument = (jsArgs.equals("") ? "" : ",") + "'" + name + "'" + ", \"" + value + "\""; - jsArgs += nextArgument; - } - - // Construct and return the function call */ - return ""; - } - -} - -/* - * $Log: BrowserAdapter.java,v $ - * Revision 1.6 2007/11/09 13:15:35 justb - * add charset=UTF-8 in returned HTTP content types - * - * Revision 1.5 2006/05/15 11:52:53 justb - * updates mainly for AJAX client - * - * Revision 1.4 2006/05/06 00:10:11 justb - * various chgs but not too serious... - * - * Revision 1.3 2005/02/28 12:45:59 justb - * introduced Command class - * - * Revision 1.2 2005/02/21 11:50:44 justb - * ohase1 of refactoring Subscriber into Session/Controller/Subscriber - * - * Revision 1.1 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.12 2005/02/15 13:30:23 justb - * changes for Tomcat buffering (now working in tc4 and 5.0) - * - * Revision 1.11 2005/01/24 22:45:58 justb - * getting safari to work - * - * Revision 1.10 2005/01/18 16:46:27 justb - * buffer size setting ignored by tomcat workings - * - * Revision 1.9 2004/10/24 12:58:18 justb - * revised client and test classes for new protocol - * - * Revision 1.8 2004/09/20 22:01:38 justb - * more changes for new protocol - * - * Revision 1.7 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.6 2004/08/15 16:00:15 justb - * enhancements to pull mode - * - * Revision 1.5 2004/08/13 23:36:05 justb - * rewrite of Pullet into Pushlet "pull" mode - * - * Revision 1.4 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.3 2003/08/12 09:57:05 justb - * replaced all print statements to Log.*() calls - * - * Revision 1.2 2003/05/18 16:15:07 justb - * support for XML encoded Events - * - * Revision 1.1.1.1 2002/09/24 21:02:30 justb - * import to sourceforge - * - * Revision 1.1.1.1 2002/09/20 22:48:17 justb - * import to SF - * - * Revision 1.1.1.1 2002/09/20 14:19:02 justb - * first import into SF - * - * Revision 1.5 2002/04/15 20:42:41 just - * reformatting and renaming GuardedQueue to EventQueue - * - * Revision 1.4 2000/12/27 22:39:35 just - * no message - * - * Revision 1.3 2000/10/30 14:15:47 just - * no message - * - * - */ - +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +import nl.justobjects.pushlet.util.Log; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Iterator; + +/** + * Generic implementation of ClientAdapter for browser clients. + * + * @author Just van den Broecke - Just Objects © + * @version $Id: BrowserAdapter.java,v 1.6 2007/11/09 13:15:35 justb Exp $ + */ +public class BrowserAdapter implements ClientAdapter, Protocol { + + public static final String START_DOCUMENT = + "" + + "" + + "\n"; + public static final String END_DOCUMENT = ""; + + private PrintWriter servletOut; + private HttpServletResponse servletRsp; + private int bytesSent; + + /** + * Constructor. + */ + public BrowserAdapter(HttpServletResponse aServletResponse) { + servletRsp = aServletResponse; + } + + /** + * Generic init. + */ + public void start() throws IOException { + // Keep servlet request/response objects until page ends in stop() + // Content type as HTML + servletRsp.setStatus(HttpServletResponse.SC_OK); + servletRsp.setContentType("text/html;charset=UTF-8"); + + // http://www.junlu.com/msg/45902.html + // Log.debug("bufsize=" + aRsp.getBufferSize()); + servletOut = servletRsp.getWriter(); + send(START_DOCUMENT); + } + + /** + * Push Event to client. + */ + public void push(Event anEvent) throws IOException { + Log.debug("BCA event=" + anEvent.toXML()); + + // Check if we should refresh + if (anEvent.getEventType().equals(Protocol.E_REFRESH)) { + // Append refresh and tail of HTML document + // Construct the JS callback line to be sent as last line of doc. + // This will refresh the request using the unique id to determine + // the subscriber instance on the server. The client will wait for + // a number of milliseconds. + long refreshWaitMillis = Long.parseLong(anEvent.getField(P_WAIT)); + + // Create servlet request for requesting next events (refresh) + String url = anEvent.getField(P_URL); + String jsRefreshTrigger = "\n"; + + + send(jsRefreshTrigger + END_DOCUMENT); + } else { + send(event2JavaScript(anEvent)); + } + } + + /** + * End HTML page in client browser. + */ + public void stop() { + // To be garbage collected if adapter remains active + servletOut = null; + } + + /** + * Send any string to browser. + */ + protected void send(String s) throws IOException { + // Send string to browser. + // Log.debug("Adapter: sending: " + s); + if (servletOut == null) { + throw new IOException("Client adapter was stopped"); + } + + servletOut.print(s); + + servletOut.flush(); + + // Note: this doesn't seem to have effect + // in Tomcat 4/5 if the client already disconnected. + servletRsp.flushBuffer(); + + bytesSent += s.length(); + Log.debug("bytesSent= " + bytesSent); + // Log.debug("BCA sent event: " + s); + } + + /** + * Converts the Java Event to a JavaScript function call in browser page. + */ + protected String event2JavaScript(Event event) throws IOException { + + // Convert the event to a comma-separated string. + String jsArgs = ""; + for (Iterator iter = event.getFieldNames(); iter.hasNext();) { + String name = (String) iter.next(); + String value = event.getField(name); + String nextArgument = (jsArgs.equals("") ? "" : ",") + "'" + name + "'" + ", \"" + value + "\""; + jsArgs += nextArgument; + } + + // Construct and return the function call */ + return ""; + } + +} + +/* + * $Log: BrowserAdapter.java,v $ + * Revision 1.6 2007/11/09 13:15:35 justb + * add charset=UTF-8 in returned HTTP content types + * + * Revision 1.5 2006/05/15 11:52:53 justb + * updates mainly for AJAX client + * + * Revision 1.4 2006/05/06 00:10:11 justb + * various chgs but not too serious... + * + * Revision 1.3 2005/02/28 12:45:59 justb + * introduced Command class + * + * Revision 1.2 2005/02/21 11:50:44 justb + * ohase1 of refactoring Subscriber into Session/Controller/Subscriber + * + * Revision 1.1 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.12 2005/02/15 13:30:23 justb + * changes for Tomcat buffering (now working in tc4 and 5.0) + * + * Revision 1.11 2005/01/24 22:45:58 justb + * getting safari to work + * + * Revision 1.10 2005/01/18 16:46:27 justb + * buffer size setting ignored by tomcat workings + * + * Revision 1.9 2004/10/24 12:58:18 justb + * revised client and test classes for new protocol + * + * Revision 1.8 2004/09/20 22:01:38 justb + * more changes for new protocol + * + * Revision 1.7 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.6 2004/08/15 16:00:15 justb + * enhancements to pull mode + * + * Revision 1.5 2004/08/13 23:36:05 justb + * rewrite of Pullet into Pushlet "pull" mode + * + * Revision 1.4 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.3 2003/08/12 09:57:05 justb + * replaced all print statements to Log.*() calls + * + * Revision 1.2 2003/05/18 16:15:07 justb + * support for XML encoded Events + * + * Revision 1.1.1.1 2002/09/24 21:02:30 justb + * import to sourceforge + * + * Revision 1.1.1.1 2002/09/20 22:48:17 justb + * import to SF + * + * Revision 1.1.1.1 2002/09/20 14:19:02 justb + * first import into SF + * + * Revision 1.5 2002/04/15 20:42:41 just + * reformatting and renaming GuardedQueue to EventQueue + * + * Revision 1.4 2000/12/27 22:39:35 just + * no message + * + * Revision 1.3 2000/10/30 14:15:47 just + * no message + * + * + */ + diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/ClientAdapter.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/ClientAdapter.java index c7ea141fee..4b187325ef 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/ClientAdapter.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/ClientAdapter.java @@ -1,72 +1,72 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -import java.io.IOException; - -/** - * Adapter interface for encapsulation of specific HTTP clients. - * - * @author Just van den Broecke - Just Objects © - * @version $Id: ClientAdapter.java,v 1.8 2007/11/23 14:33:07 justb Exp $ - */ -public interface ClientAdapter { - - /** - * Start event push. - */ - public void start() throws IOException; - - /** - * Push single Event to client. - */ - public void push(Event anEvent) throws IOException; - - /** - * Stop event push. - */ - public void stop() throws IOException; -} - -/* - * $Log: ClientAdapter.java,v $ - * Revision 1.8 2007/11/23 14:33:07 justb - * core classes now configurable through factory - * - * Revision 1.7 2005/02/28 12:45:59 justb - * introduced Command class - * - * Revision 1.6 2005/02/21 11:50:45 justb - * ohase1 of refactoring Subscriber into Session/Controller/Subscriber - * - * Revision 1.5 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.4 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.3 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.2 2003/05/18 16:15:08 justb - * support for XML encoded Events - * - * Revision 1.1.1.1 2002/09/24 21:02:30 justb - * import to sourceforge - * - * Revision 1.1.1.1 2002/09/20 22:48:17 justb - * import to SF - * - * Revision 1.1.1.1 2002/09/20 14:19:03 justb - * first import into SF - * - * Revision 1.3 2002/04/15 20:42:41 just - * reformatting and renaming GuardedQueue to EventQueue - * - * Revision 1.2 2000/08/21 20:48:29 just - * added CVS log and id tags plus copyrights - * - * - */ - +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +import java.io.IOException; + +/** + * Adapter interface for encapsulation of specific HTTP clients. + * + * @author Just van den Broecke - Just Objects © + * @version $Id: ClientAdapter.java,v 1.8 2007/11/23 14:33:07 justb Exp $ + */ +public interface ClientAdapter { + + /** + * Start event push. + */ + public void start() throws IOException; + + /** + * Push single Event to client. + */ + public void push(Event anEvent) throws IOException; + + /** + * Stop event push. + */ + public void stop() throws IOException; +} + +/* + * $Log: ClientAdapter.java,v $ + * Revision 1.8 2007/11/23 14:33:07 justb + * core classes now configurable through factory + * + * Revision 1.7 2005/02/28 12:45:59 justb + * introduced Command class + * + * Revision 1.6 2005/02/21 11:50:45 justb + * ohase1 of refactoring Subscriber into Session/Controller/Subscriber + * + * Revision 1.5 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.4 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.3 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.2 2003/05/18 16:15:08 justb + * support for XML encoded Events + * + * Revision 1.1.1.1 2002/09/24 21:02:30 justb + * import to sourceforge + * + * Revision 1.1.1.1 2002/09/20 22:48:17 justb + * import to SF + * + * Revision 1.1.1.1 2002/09/20 14:19:03 justb + * first import into SF + * + * Revision 1.3 2002/04/15 20:42:41 just + * reformatting and renaming GuardedQueue to EventQueue + * + * Revision 1.2 2000/08/21 20:48:29 just + * added CVS log and id tags plus copyrights + * + * + */ + diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/Dispatcher.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/Dispatcher.java index 5cd739d5bd..83b402f693 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/Dispatcher.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/Dispatcher.java @@ -1,265 +1,265 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -import nl.justobjects.pushlet.util.Log; -import nl.justobjects.pushlet.util.PushletException; - -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; - -/** - * Routes Events to Subscribers. - * - * @author Just van den Broecke - Just Objects © - * @version $Id: Dispatcher.java,v 1.9 2007/12/04 13:55:53 justb Exp $ - */ -public class Dispatcher implements Protocol, ConfigDefs { - /** - * Singleton pattern: single instance. - */ - private static Dispatcher instance; - protected SessionManagerVisitor sessionManagerVisitor; - - static { - try { - instance = (Dispatcher) Config.getClass(DISPATCHER_CLASS, "nl.justobjects.pushlet.core.Dispatcher").newInstance(); - Log.info("Dispatcher created className=" + instance.getClass()); - } catch (Throwable t) { - Log.fatal("Cannot instantiate Dispatcher from config", t); - } - } - - /** - * Singleton pattern with factory method: protected constructor. - */ - protected Dispatcher() { - - } - - /** - * Singleton pattern: get single instance. - */ - public static Dispatcher getInstance() { - return instance; - } - - /** - * Send event to all subscribers. - */ - public synchronized void broadcast(Event anEvent) { - try { - // Let the SessionManager loop through Sessions, calling - // our Visitor Method for each Session. This is done to guard - // synchronization with SessionManager and to optimize by - // not getting an array of all sessions. - Object[] args = new Object[2]; - args[1] = anEvent; - Method method = sessionManagerVisitor.getMethod("visitBroadcast"); - SessionManager.getInstance().apply(sessionManagerVisitor, method, args); - } catch (Throwable t) { - Log.error("Error calling SessionManager.apply: ", t); - } - } - - /** - * Send event to subscribers matching Event subject. - */ - public synchronized void multicast(Event anEvent) { - try { - // Let the SessionManager loop through Sessions, calling - // our Visitor Method for each Session. This is done to guard - // synchronization with SessionManager and to optimize by - // not getting an array of all sessions. - Method method = sessionManagerVisitor.getMethod("visitMulticast"); - Object[] args = new Object[2]; - args[1] = anEvent; - SessionManager.getInstance().apply(sessionManagerVisitor, method, args); - } catch (Throwable t) { - Log.error("Error calling SessionManager.apply: ", t); - } - } - - - /** - * Send event to specific subscriber. - */ - public synchronized void unicast(Event event, String aSessionId) { - // Get subscriber to send event to - Session session = SessionManager.getInstance().getSession(aSessionId); - if (session == null) { - Log.warn("unicast: session with id=" + aSessionId + " does not exist"); - return; - } - - // Send Event to subscriber. - session.getSubscriber().onEvent((Event) event.clone()); - } - - /** - * Start Dispatcher. - */ - public void start() throws PushletException { - Log.info("Dispatcher started"); - - // Create callback for SessionManager visits. - sessionManagerVisitor = new SessionManagerVisitor(); - } - - /** - * Stop Dispatcher. - */ - public void stop() { - // Send abort control event to all subscribers. - Log.info("Dispatcher stopped: broadcast abort to all subscribers"); - broadcast(new Event(E_ABORT)); - } - - /** - * Supplies Visitor methods for callbacks from SessionManager. - */ - private class SessionManagerVisitor { - private final Map visitorMethods = new HashMap(2); - - SessionManagerVisitor() throws PushletException { - - try { - // Setup Visitor Methods for callback from SessionManager - // This is a slight opitmization over creating Method objects - // on each invokation. - Class[] argsClasses = {Session.class, Event.class}; - visitorMethods.put("visitMulticast", this.getClass().getMethod("visitMulticast", argsClasses)); - visitorMethods.put("visitBroadcast", this.getClass().getMethod("visitBroadcast", argsClasses)); - } catch (NoSuchMethodException e) { - throw new PushletException("Failed to setup SessionManagerVisitor", e); - } - } - - /** - * Return Visitor Method by name. - */ - public Method getMethod(String aName) { - return (Method) visitorMethods.get(aName); - - } - - /** - * Visitor method called by SessionManager. - */ - public void visitBroadcast(Session aSession, Event event) { - aSession.getSubscriber().onEvent((Event) event.clone()); - } - - /** - * Visitor method called by SessionManager. - */ - public void visitMulticast(Session aSession, Event event) { - Subscriber subscriber = aSession.getSubscriber(); - Event clonedEvent; - Subscription subscription; - - // Send only if the subscriber's criteria - // match the event. - if ((subscription = subscriber.match(event)) != null) { - // Personalize event - clonedEvent = (Event) event.clone(); - - // Set subscription id and optional label - clonedEvent.setField(P_SUBSCRIPTION_ID, subscription.getId()); - if (subscription.getLabel() != null) { - event.setField(P_SUBSCRIPTION_LABEL, subscription.getLabel()); - } - - subscriber.onEvent(clonedEvent); - } - } - } -} - -/* - * $Log: Dispatcher.java,v $ - * Revision 1.9 2007/12/04 13:55:53 justb - * reimplement SessionManager concurrency (prev version was not thread-safe!) - * - * Revision 1.8 2007/11/23 14:33:07 justb - * core classes now configurable through factory - * - * Revision 1.7 2005/02/28 12:45:59 justb - * introduced Command class - * - * Revision 1.6 2005/02/28 09:14:55 justb - * sessmgr/dispatcher factory/singleton support - * - * Revision 1.5 2005/02/21 16:59:06 justb - * SessionManager and session lease introduced - * - * Revision 1.4 2005/02/21 11:50:46 justb - * ohase1 of refactoring Subscriber into Session/Controller/Subscriber - * - * Revision 1.3 2005/02/18 12:36:47 justb - * changes for renaming and configurability - * - * Revision 1.2 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.1 2005/02/18 09:54:15 justb - * refactor: rename Publisher Dispatcher and single Subscriber class - * - * Revision 1.14 2005/02/16 14:39:34 justb - * fixed leave handling and added "poll" mode - * - * Revision 1.13 2004/10/24 20:50:35 justb - * refine subscription with label and sending sid and label on events - * - * Revision 1.12 2004/10/24 12:58:18 justb - * revised client and test classes for new protocol - * - * Revision 1.11 2004/09/26 21:39:43 justb - * allow multiple subscriptions and out-of-band requests - * - * Revision 1.10 2004/09/20 22:01:38 justb - * more changes for new protocol - * - * Revision 1.9 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.8 2004/08/13 23:36:05 justb - * rewrite of Pullet into Pushlet "pull" mode - * - * Revision 1.7 2004/08/12 13:18:54 justb - * cosmetic changes - * - * Revision 1.6 2004/03/10 15:45:55 justb - * many cosmetic changes - * - * Revision 1.5 2004/03/10 13:59:28 justb - * rewrite using Collection classes and finer synchronization - * - * Revision 1.4 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.3 2003/08/12 08:54:40 justb - * added getSubscriberCount() and use Log - * - * Revision 1.2 2003/05/18 16:15:08 justb - * support for XML encoded Events - * - * Revision 1.1.1.1 2002/09/24 21:02:31 justb - * import to sourceforge - * - * Revision 1.1.1.1 2002/09/20 22:48:18 justb - * import to SF - * - * Revision 1.1.1.1 2002/09/20 14:19:04 justb - * first import into SF - * - * Revision 1.3 2002/04/15 20:42:41 just - * reformatting and renaming GuardedQueue to EventQueue - * - * Revision 1.2 2000/08/21 20:48:29 just - * added CVS log and id tags plus copyrights - * - * - */ +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +import nl.justobjects.pushlet.util.Log; +import nl.justobjects.pushlet.util.PushletException; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +/** + * Routes Events to Subscribers. + * + * @author Just van den Broecke - Just Objects © + * @version $Id: Dispatcher.java,v 1.9 2007/12/04 13:55:53 justb Exp $ + */ +public class Dispatcher implements Protocol, ConfigDefs { + /** + * Singleton pattern: single instance. + */ + private static Dispatcher instance; + protected SessionManagerVisitor sessionManagerVisitor; + + static { + try { + instance = (Dispatcher) Config.getClass(DISPATCHER_CLASS, "nl.justobjects.pushlet.core.Dispatcher").newInstance(); + Log.info("Dispatcher created className=" + instance.getClass()); + } catch (Throwable t) { + Log.fatal("Cannot instantiate Dispatcher from config", t); + } + } + + /** + * Singleton pattern with factory method: protected constructor. + */ + protected Dispatcher() { + + } + + /** + * Singleton pattern: get single instance. + */ + public static Dispatcher getInstance() { + return instance; + } + + /** + * Send event to all subscribers. + */ + public synchronized void broadcast(Event anEvent) { + try { + // Let the SessionManager loop through Sessions, calling + // our Visitor Method for each Session. This is done to guard + // synchronization with SessionManager and to optimize by + // not getting an array of all sessions. + Object[] args = new Object[2]; + args[1] = anEvent; + Method method = sessionManagerVisitor.getMethod("visitBroadcast"); + SessionManager.getInstance().apply(sessionManagerVisitor, method, args); + } catch (Throwable t) { + Log.error("Error calling SessionManager.apply: ", t); + } + } + + /** + * Send event to subscribers matching Event subject. + */ + public synchronized void multicast(Event anEvent) { + try { + // Let the SessionManager loop through Sessions, calling + // our Visitor Method for each Session. This is done to guard + // synchronization with SessionManager and to optimize by + // not getting an array of all sessions. + Method method = sessionManagerVisitor.getMethod("visitMulticast"); + Object[] args = new Object[2]; + args[1] = anEvent; + SessionManager.getInstance().apply(sessionManagerVisitor, method, args); + } catch (Throwable t) { + Log.error("Error calling SessionManager.apply: ", t); + } + } + + + /** + * Send event to specific subscriber. + */ + public synchronized void unicast(Event event, String aSessionId) { + // Get subscriber to send event to + Session session = SessionManager.getInstance().getSession(aSessionId); + if (session == null) { + Log.warn("unicast: session with id=" + aSessionId + " does not exist"); + return; + } + + // Send Event to subscriber. + session.getSubscriber().onEvent((Event) event.clone()); + } + + /** + * Start Dispatcher. + */ + public void start() throws PushletException { + Log.info("Dispatcher started"); + + // Create callback for SessionManager visits. + sessionManagerVisitor = new SessionManagerVisitor(); + } + + /** + * Stop Dispatcher. + */ + public void stop() { + // Send abort control event to all subscribers. + Log.info("Dispatcher stopped: broadcast abort to all subscribers"); + broadcast(new Event(E_ABORT)); + } + + /** + * Supplies Visitor methods for callbacks from SessionManager. + */ + private class SessionManagerVisitor { + private final Map visitorMethods = new HashMap(2); + + SessionManagerVisitor() throws PushletException { + + try { + // Setup Visitor Methods for callback from SessionManager + // This is a slight opitmization over creating Method objects + // on each invokation. + Class[] argsClasses = {Session.class, Event.class}; + visitorMethods.put("visitMulticast", this.getClass().getMethod("visitMulticast", argsClasses)); + visitorMethods.put("visitBroadcast", this.getClass().getMethod("visitBroadcast", argsClasses)); + } catch (NoSuchMethodException e) { + throw new PushletException("Failed to setup SessionManagerVisitor", e); + } + } + + /** + * Return Visitor Method by name. + */ + public Method getMethod(String aName) { + return (Method) visitorMethods.get(aName); + + } + + /** + * Visitor method called by SessionManager. + */ + public void visitBroadcast(Session aSession, Event event) { + aSession.getSubscriber().onEvent((Event) event.clone()); + } + + /** + * Visitor method called by SessionManager. + */ + public void visitMulticast(Session aSession, Event event) { + Subscriber subscriber = aSession.getSubscriber(); + Event clonedEvent; + Subscription subscription; + + // Send only if the subscriber's criteria + // match the event. + if ((subscription = subscriber.match(event)) != null) { + // Personalize event + clonedEvent = (Event) event.clone(); + + // Set subscription id and optional label + clonedEvent.setField(P_SUBSCRIPTION_ID, subscription.getId()); + if (subscription.getLabel() != null) { + event.setField(P_SUBSCRIPTION_LABEL, subscription.getLabel()); + } + + subscriber.onEvent(clonedEvent); + } + } + } +} + +/* + * $Log: Dispatcher.java,v $ + * Revision 1.9 2007/12/04 13:55:53 justb + * reimplement SessionManager concurrency (prev version was not thread-safe!) + * + * Revision 1.8 2007/11/23 14:33:07 justb + * core classes now configurable through factory + * + * Revision 1.7 2005/02/28 12:45:59 justb + * introduced Command class + * + * Revision 1.6 2005/02/28 09:14:55 justb + * sessmgr/dispatcher factory/singleton support + * + * Revision 1.5 2005/02/21 16:59:06 justb + * SessionManager and session lease introduced + * + * Revision 1.4 2005/02/21 11:50:46 justb + * ohase1 of refactoring Subscriber into Session/Controller/Subscriber + * + * Revision 1.3 2005/02/18 12:36:47 justb + * changes for renaming and configurability + * + * Revision 1.2 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.1 2005/02/18 09:54:15 justb + * refactor: rename Publisher Dispatcher and single Subscriber class + * + * Revision 1.14 2005/02/16 14:39:34 justb + * fixed leave handling and added "poll" mode + * + * Revision 1.13 2004/10/24 20:50:35 justb + * refine subscription with label and sending sid and label on events + * + * Revision 1.12 2004/10/24 12:58:18 justb + * revised client and test classes for new protocol + * + * Revision 1.11 2004/09/26 21:39:43 justb + * allow multiple subscriptions and out-of-band requests + * + * Revision 1.10 2004/09/20 22:01:38 justb + * more changes for new protocol + * + * Revision 1.9 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.8 2004/08/13 23:36:05 justb + * rewrite of Pullet into Pushlet "pull" mode + * + * Revision 1.7 2004/08/12 13:18:54 justb + * cosmetic changes + * + * Revision 1.6 2004/03/10 15:45:55 justb + * many cosmetic changes + * + * Revision 1.5 2004/03/10 13:59:28 justb + * rewrite using Collection classes and finer synchronization + * + * Revision 1.4 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.3 2003/08/12 08:54:40 justb + * added getSubscriberCount() and use Log + * + * Revision 1.2 2003/05/18 16:15:08 justb + * support for XML encoded Events + * + * Revision 1.1.1.1 2002/09/24 21:02:31 justb + * import to sourceforge + * + * Revision 1.1.1.1 2002/09/20 22:48:18 justb + * import to SF + * + * Revision 1.1.1.1 2002/09/20 14:19:04 justb + * first import into SF + * + * Revision 1.3 2002/04/15 20:42:41 just + * reformatting and renaming GuardedQueue to EventQueue + * + * Revision 1.2 2000/08/21 20:48:29 just + * added CVS log and id tags plus copyrights + * + * + */ diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/Event.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/Event.java index e9a0aaa48b..b74d3c9bab 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/Event.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/Event.java @@ -1,184 +1,184 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -import nl.justobjects.pushlet.util.Sys; - -import java.io.Serializable; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -/** - * Represents the event data. - * - * @author Just van den Broecke - Just Objects © - * @version $Id: Event.java,v 1.13 2007/11/23 14:33:07 justb Exp $ - */ -public class Event implements Protocol, Serializable { - - protected Map attributes = new HashMap(3); - - public Event(String anEventType) { - this(anEventType, null); - } - - public Event(String anEventType, Map theAttributes) { - - if (theAttributes != null) { - setAttrs(theAttributes); - } - - // Set required field event type - setField(P_EVENT, anEventType); - - // Set time in seconds since 1970 - setField(P_TIME, System.currentTimeMillis() / 1000); - } - - public Event(Map theAttributes) { - if (!theAttributes.containsKey(P_EVENT)) { - throw new IllegalArgumentException(P_EVENT + " not found in attributes"); - } - setAttrs(theAttributes); - } - - public static Event createDataEvent(String aSubject) { - return createDataEvent(aSubject, null); - } - - public static Event createDataEvent(String aSubject, Map theAttributes) { - Event dataEvent = new Event(E_DATA, theAttributes); - dataEvent.setField(P_SUBJECT, aSubject); - return dataEvent; - } - - public String getEventType() { - return getField(P_EVENT); - } - - public String getSubject() { - return getField(P_SUBJECT); - } - - public void setField(String name, String value) { - attributes.put(name, value); - } - - public void setField(String name, int value) { - attributes.put(name, value + ""); - } - - public void setField(String name, long value) { - attributes.put(name, value + ""); - } - - public String getField(String name) { - return (String) attributes.get(name); - } - - /** - * Return field; if null return default. - */ - public String getField(String name, String aDefault) { - String result = getField(name); - return result == null ? aDefault : result; - } - - public Iterator getFieldNames() { - return attributes.keySet().iterator(); - } - - public String toString() { - return attributes.toString(); - } - - /** - * Convert to HTTP query string. - */ - public String toQueryString() { - String queryString = ""; - String amp = ""; - for (Iterator iter = getFieldNames(); iter.hasNext();) { - String nextAttrName = (String) iter.next(); - String nextAttrValue = getField(nextAttrName); - queryString = queryString + amp + nextAttrName + "=" + nextAttrValue; - // After first add "&". - amp = "&"; - } - - return queryString; - } - - public String toXML(boolean strict) { - String xmlString = " +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +import nl.justobjects.pushlet.util.Sys; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * Represents the event data. + * + * @author Just van den Broecke - Just Objects © + * @version $Id: Event.java,v 1.13 2007/11/23 14:33:07 justb Exp $ + */ +public class Event implements Protocol, Serializable { + + protected Map attributes = new HashMap(3); + + public Event(String anEventType) { + this(anEventType, null); + } + + public Event(String anEventType, Map theAttributes) { + + if (theAttributes != null) { + setAttrs(theAttributes); + } + + // Set required field event type + setField(P_EVENT, anEventType); + + // Set time in seconds since 1970 + setField(P_TIME, System.currentTimeMillis() / 1000); + } + + public Event(Map theAttributes) { + if (!theAttributes.containsKey(P_EVENT)) { + throw new IllegalArgumentException(P_EVENT + " not found in attributes"); + } + setAttrs(theAttributes); + } + + public static Event createDataEvent(String aSubject) { + return createDataEvent(aSubject, null); + } + + public static Event createDataEvent(String aSubject, Map theAttributes) { + Event dataEvent = new Event(E_DATA, theAttributes); + dataEvent.setField(P_SUBJECT, aSubject); + return dataEvent; + } + + public String getEventType() { + return getField(P_EVENT); + } + + public String getSubject() { + return getField(P_SUBJECT); + } + + public void setField(String name, String value) { + attributes.put(name, value); + } + + public void setField(String name, int value) { + attributes.put(name, value + ""); + } + + public void setField(String name, long value) { + attributes.put(name, value + ""); + } + + public String getField(String name) { + return (String) attributes.get(name); + } + + /** + * Return field; if null return default. + */ + public String getField(String name, String aDefault) { + String result = getField(name); + return result == null ? aDefault : result; + } + + public Iterator getFieldNames() { + return attributes.keySet().iterator(); + } + + public String toString() { + return attributes.toString(); + } + + /** + * Convert to HTTP query string. + */ + public String toQueryString() { + String queryString = ""; + String amp = ""; + for (Iterator iter = getFieldNames(); iter.hasNext();) { + String nextAttrName = (String) iter.next(); + String nextAttrValue = getField(nextAttrName); + queryString = queryString + amp + nextAttrName + "=" + nextAttrValue; + // After first add "&". + amp = "&"; + } + + return queryString; + } + + public String toXML(boolean strict) { + String xmlString = " -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -import nl.justobjects.pushlet.util.Log; - -/** - * Abstract Event source from which Events are pulled. - * - * @version $Id: EventPullSource.java,v 1.15 2007/11/23 14:33:07 justb Exp $ - * @author Just van den Broecke - Just Objects © - **/ - -/** - * ABC for specifc EventPullSources. - */ -abstract public class EventPullSource implements EventSource, Runnable { - private volatile boolean alive = false; - private volatile boolean active = false; - private static int threadNum = 0; - private Thread thread; - - public EventPullSource() { - } - - abstract protected long getSleepTime(); - - abstract protected Event pullEvent(); - - public void start() { - thread = new Thread(this, "EventPullSource-" + (++threadNum)); - thread.setDaemon(true); - thread.start(); - } - - public boolean isAlive() { - return alive; - } - - /** - * Stop the event generator thread. - */ - public void stop() { - alive = false; - - if (thread != null) { - thread.interrupt(); - thread = null; - } - - } - - /** - * Activate the event generator thread. - */ - synchronized public void activate() { - if (active) { - return; - } - active = true; - if (!alive) { - start(); - return; - } - Log.debug(getClass().getName() + ": notifying..."); - notifyAll(); - } - - /** - * Deactivate the event generator thread. - */ - public void passivate() { - if (!active) { - return; - } - active = false; - } - - /** - * Main loop: sleep, generate event and publish. - */ - public void run() { - Log.debug(getClass().getName() + ": starting..."); - alive = true; - while (alive) { - try { - - Thread.sleep(getSleepTime()); - - // Stopped during sleep: end loop. - if (!alive) { - break; - } - - // If passivated wait until we get - // get notify()-ied. If there are no subscribers - // it wasts CPU to remain producing events... - synchronized (this) { - while (!active) { - Log.debug(getClass().getName() + ": waiting..."); - wait(); - } - } - - } catch (InterruptedException e) { - break; - } - - try { - // Derived class should produce an event. - Event event = pullEvent(); - - // Let the publisher push it to subscribers. - Dispatcher.getInstance().multicast(event); - } catch (Throwable t) { - Log.warn("EventPullSource exception while multicasting ", t); - t.printStackTrace(); - } - } - Log.debug(getClass().getName() + ": stopped"); - } -} - -/* - * $Log: EventPullSource.java,v $ - * Revision 1.15 2007/11/23 14:33:07 justb - * core classes now configurable through factory - * - * Revision 1.14 2005/02/28 09:14:55 justb - * sessmgr/dispatcher factory/singleton support - * - * Revision 1.13 2005/02/21 16:59:08 justb - * SessionManager and session lease introduced - * - * Revision 1.12 2005/02/21 11:50:46 justb - * ohase1 of refactoring Subscriber into Session/Controller/Subscriber - * - * Revision 1.11 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.10 2005/02/18 09:54:15 justb - * refactor: rename Publisher Dispatcher and single Subscriber class - * - * Revision 1.9 2004/09/20 22:01:38 justb - * more changes for new protocol - * - * Revision 1.8 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.7 2004/08/15 16:00:15 justb - * enhancements to pull mode - * - * Revision 1.6 2004/08/13 23:36:05 justb - * rewrite of Pullet into Pushlet "pull" mode - * - * Revision 1.5 2004/03/10 14:01:55 justb - * formatting and *Subscriber refactoring - * - * Revision 1.4 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.3 2003/08/12 09:57:05 justb - * replaced all print statements to Log.*() calls - * - * Revision 1.2 2003/05/18 16:15:08 justb - * support for XML encoded Events - * - * Revision 1.1.1.1 2002/09/24 21:02:31 justb - * import to sourceforge - * - * Revision 1.1.1.1 2002/09/20 22:48:17 justb - * import to SF - * - * Revision 1.1.1.1 2002/09/20 14:19:03 justb - * first import into SF - * - * Revision 1.3 2002/04/15 20:42:41 just - * reformatting and renaming GuardedQueue to EventQueue - * - * Revision 1.2 2000/08/21 20:48:29 just - * added CVS log and id tags plus copyrights - * - * - */ +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +import nl.justobjects.pushlet.util.Log; + +/** + * Abstract Event source from which Events are pulled. + * + * @version $Id: EventPullSource.java,v 1.15 2007/11/23 14:33:07 justb Exp $ + * @author Just van den Broecke - Just Objects © + **/ + +/** + * ABC for specifc EventPullSources. + */ +abstract public class EventPullSource implements EventSource, Runnable { + private volatile boolean alive = false; + private volatile boolean active = false; + private static int threadNum = 0; + private Thread thread; + + public EventPullSource() { + } + + abstract protected long getSleepTime(); + + abstract protected Event pullEvent(); + + public void start() { + thread = new Thread(this, "EventPullSource-" + (++threadNum)); + thread.setDaemon(true); + thread.start(); + } + + public boolean isAlive() { + return alive; + } + + /** + * Stop the event generator thread. + */ + public void stop() { + alive = false; + + if (thread != null) { + thread.interrupt(); + thread = null; + } + + } + + /** + * Activate the event generator thread. + */ + synchronized public void activate() { + if (active) { + return; + } + active = true; + if (!alive) { + start(); + return; + } + Log.debug(getClass().getName() + ": notifying..."); + notifyAll(); + } + + /** + * Deactivate the event generator thread. + */ + public void passivate() { + if (!active) { + return; + } + active = false; + } + + /** + * Main loop: sleep, generate event and publish. + */ + public void run() { + Log.debug(getClass().getName() + ": starting..."); + alive = true; + while (alive) { + try { + + Thread.sleep(getSleepTime()); + + // Stopped during sleep: end loop. + if (!alive) { + break; + } + + // If passivated wait until we get + // get notify()-ied. If there are no subscribers + // it wasts CPU to remain producing events... + synchronized (this) { + while (!active) { + Log.debug(getClass().getName() + ": waiting..."); + wait(); + } + } + + } catch (InterruptedException e) { + break; + } + + try { + // Derived class should produce an event. + Event event = pullEvent(); + + // Let the publisher push it to subscribers. + Dispatcher.getInstance().multicast(event); + } catch (Throwable t) { + Log.warn("EventPullSource exception while multicasting ", t); + t.printStackTrace(); + } + } + Log.debug(getClass().getName() + ": stopped"); + } +} + +/* + * $Log: EventPullSource.java,v $ + * Revision 1.15 2007/11/23 14:33:07 justb + * core classes now configurable through factory + * + * Revision 1.14 2005/02/28 09:14:55 justb + * sessmgr/dispatcher factory/singleton support + * + * Revision 1.13 2005/02/21 16:59:08 justb + * SessionManager and session lease introduced + * + * Revision 1.12 2005/02/21 11:50:46 justb + * ohase1 of refactoring Subscriber into Session/Controller/Subscriber + * + * Revision 1.11 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.10 2005/02/18 09:54:15 justb + * refactor: rename Publisher Dispatcher and single Subscriber class + * + * Revision 1.9 2004/09/20 22:01:38 justb + * more changes for new protocol + * + * Revision 1.8 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.7 2004/08/15 16:00:15 justb + * enhancements to pull mode + * + * Revision 1.6 2004/08/13 23:36:05 justb + * rewrite of Pullet into Pushlet "pull" mode + * + * Revision 1.5 2004/03/10 14:01:55 justb + * formatting and *Subscriber refactoring + * + * Revision 1.4 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.3 2003/08/12 09:57:05 justb + * replaced all print statements to Log.*() calls + * + * Revision 1.2 2003/05/18 16:15:08 justb + * support for XML encoded Events + * + * Revision 1.1.1.1 2002/09/24 21:02:31 justb + * import to sourceforge + * + * Revision 1.1.1.1 2002/09/20 22:48:17 justb + * import to SF + * + * Revision 1.1.1.1 2002/09/20 14:19:03 justb + * first import into SF + * + * Revision 1.3 2002/04/15 20:42:41 just + * reformatting and renaming GuardedQueue to EventQueue + * + * Revision 1.2 2000/08/21 20:48:29 just + * added CVS log and id tags plus copyrights + * + * + */ diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/EventQueue.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/EventQueue.java index 85c730e2d7..18fd52318d 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/EventQueue.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/EventQueue.java @@ -1,269 +1,269 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -/** - * FIFO queue with guarded suspension. - * Purpose
- *

- * Implementation
- * FIFO queue class implemented with circular array. The enQueue() and - * deQueue() methods use guarded suspension according to a readers/writers - * pattern, implemented with java.lang.Object.wait()/notify(). - *

- * Examples
- *

- *
- * - * @author Just van den Broecke - Just Objects © - * @version $Id: EventQueue.java,v 1.3 2007/11/23 14:33:07 justb Exp $ - */ -public class EventQueue { - /** - * Defines maximum queue size - */ - private int capacity = 8; - private Event[] queue = null; - private int front, rear; - - /** - * Construct queue with default (8) capacity. - */ - public EventQueue() { - this(8); - } - - /** - * Construct queue with specified capacity. - */ - public EventQueue(int capacity) { - this.capacity = capacity; - queue = new Event[capacity]; - front = rear = 0; - } - - /** - * Put item in queue; waits() indefinitely if queue is full. - */ - public synchronized boolean enQueue(Event item) throws InterruptedException { - return enQueue(item, -1); - } - - /** - * Put item in queue; if full wait maxtime. - */ - public synchronized boolean enQueue(Event item, long maxWaitTime) throws InterruptedException { - - // Wait (optional maxtime) as long as the queue is full - while (isFull()) { - if (maxWaitTime > 0) { - // Wait at most maximum time - wait(maxWaitTime); - - // Timed out or woken; if still full we - // had bad luck and return failure. - if (isFull()) { - return false; - } - } else { - wait(); - } - } - - // Put item in queue - queue[rear] = item; - rear = next(rear); - - // Wake up waiters; NOTE: first waiter will eat item - notifyAll(); - return true; - } - - /** - * Get head; if empty wait until something in queue. - */ - public synchronized Event deQueue() throws InterruptedException { - return deQueue(-1); - } - - /** - * Get head; if empty wait for specified time at max. - */ - public synchronized Event deQueue(long maxWaitTime) throws InterruptedException { - while (isEmpty()) { - if (maxWaitTime >= 0) { - wait(maxWaitTime); - - // Timed out or woken; if still empty we - // had bad luck and return failure. - if (isEmpty()) { - return null; - } - } else { - // Wait indefinitely for something in queue. - wait(); - } - } - - // Dequeue item - Event result = fetchNext(); - - // Notify possible wait()-ing enQueue()-ers - notifyAll(); - - // Return dequeued item - return result; - } - - /** - * Get all queued Events. - */ - public synchronized Event[] deQueueAll(long maxWaitTime) throws InterruptedException { - while (isEmpty()) { - if (maxWaitTime >= 0) { - wait(maxWaitTime); - - // Timed out or woken; if still empty we - // had bad luck and return failure. - if (isEmpty()) { - return null; - } - } else { - // Wait indefinitely for something in queue. - wait(); - } - } - - // Dequeue all items item - Event[] events = new Event[getSize()]; - for (int i = 0; i < events.length; i++) { - events[i] = fetchNext(); - } - - // Notify possible wait()-ing enQueue()-ers - notifyAll(); - - // Return dequeued item - return events; - } - - public synchronized int getSize() { - return (rear >= front) ? (rear - front) : (capacity - front + rear); - } - - /** - * Is the queue empty ? - */ - public synchronized boolean isEmpty() { - return front == rear; - } - - /** - * Is the queue full ? - */ - public synchronized boolean isFull() { - return (next(rear) == front); - } - - /** - * Circular counter. - */ - private int next(int index) { - return (index + 1 < capacity ? index + 1 : 0); - } - - /** - * Circular counter. - */ - private Event fetchNext() { - Event temp = queue[front]; - queue[front] = null; - front = next(front); - return temp; - } - - public static void p(String s) { - System.out.println(s); - } - - public static void main(String[] args) { - EventQueue q = new EventQueue(8); - Event event = new Event("t"); - try { - q.enQueue(event); - p("(1) size = " + q.getSize()); - q.enQueue(event); - p("(2) size = " + q.getSize()); - q.deQueue(); - p("(1) size = " + q.getSize()); - q.deQueue(); - p("(0) size = " + q.getSize()); - - q.enQueue(event); - q.enQueue(event); - q.enQueue(event); - p("(3) size = " + q.getSize()); - q.deQueue(); - p("(2) size = " + q.getSize()); - q.enQueue(event); - q.enQueue(event); - q.enQueue(event); - p("(5) size = " + q.getSize()); - q.enQueue(event); - q.enQueue(event); - p("(7) size = " + q.getSize()); - q.deQueue(); - q.deQueue(); - q.deQueue(); - p("(4) size = " + q.getSize()); - q.deQueue(); - q.deQueue(); - q.deQueue(); - ; - q.deQueue(); - p("(0) size = " + q.getSize()); - - q.enQueue(event); - q.enQueue(event); - q.enQueue(event); - q.enQueue(event); - q.enQueue(event); - p("(5) size = " + q.getSize()); - - q.deQueue(); - q.deQueue(); - q.deQueue(); - ; - q.deQueue(); - p("(1) size = " + q.getSize()); - } catch (InterruptedException ie) { - } - } -} - -/* -* $Log: EventQueue.java,v $ -* Revision 1.3 2007/11/23 14:33:07 justb -* core classes now configurable through factory -* -* Revision 1.2 2005/02/21 11:50:46 justb -* ohase1 of refactoring Subscriber into Session/Controller/Subscriber -* -* Revision 1.1 2005/02/18 10:07:23 justb -* many renamings of classes (make names compact) -* -* Revision 1.6 2005/02/16 12:16:16 justb -* added support for "poll" mode -* -* Revision 1.5 2005/01/13 14:47:15 justb -* control evt: send response on same (control) connection -* -* Revision 1.4 2004/09/03 22:35:37 justb -* Almost complete rewrite, just checking in now -* -* Revision 1.3 2003/08/15 08:37:40 justb -* fix/add Copyright+LGPL file headers and footers -* -* -*/ +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +/** + * FIFO queue with guarded suspension. + * Purpose
+ *

+ * Implementation
+ * FIFO queue class implemented with circular array. The enQueue() and + * deQueue() methods use guarded suspension according to a readers/writers + * pattern, implemented with java.lang.Object.wait()/notify(). + *

+ * Examples
+ *

+ *
+ * + * @author Just van den Broecke - Just Objects © + * @version $Id: EventQueue.java,v 1.3 2007/11/23 14:33:07 justb Exp $ + */ +public class EventQueue { + /** + * Defines maximum queue size + */ + private int capacity = 8; + private Event[] queue = null; + private int front, rear; + + /** + * Construct queue with default (8) capacity. + */ + public EventQueue() { + this(8); + } + + /** + * Construct queue with specified capacity. + */ + public EventQueue(int capacity) { + this.capacity = capacity; + queue = new Event[capacity]; + front = rear = 0; + } + + /** + * Put item in queue; waits() indefinitely if queue is full. + */ + public synchronized boolean enQueue(Event item) throws InterruptedException { + return enQueue(item, -1); + } + + /** + * Put item in queue; if full wait maxtime. + */ + public synchronized boolean enQueue(Event item, long maxWaitTime) throws InterruptedException { + + // Wait (optional maxtime) as long as the queue is full + while (isFull()) { + if (maxWaitTime > 0) { + // Wait at most maximum time + wait(maxWaitTime); + + // Timed out or woken; if still full we + // had bad luck and return failure. + if (isFull()) { + return false; + } + } else { + wait(); + } + } + + // Put item in queue + queue[rear] = item; + rear = next(rear); + + // Wake up waiters; NOTE: first waiter will eat item + notifyAll(); + return true; + } + + /** + * Get head; if empty wait until something in queue. + */ + public synchronized Event deQueue() throws InterruptedException { + return deQueue(-1); + } + + /** + * Get head; if empty wait for specified time at max. + */ + public synchronized Event deQueue(long maxWaitTime) throws InterruptedException { + while (isEmpty()) { + if (maxWaitTime >= 0) { + wait(maxWaitTime); + + // Timed out or woken; if still empty we + // had bad luck and return failure. + if (isEmpty()) { + return null; + } + } else { + // Wait indefinitely for something in queue. + wait(); + } + } + + // Dequeue item + Event result = fetchNext(); + + // Notify possible wait()-ing enQueue()-ers + notifyAll(); + + // Return dequeued item + return result; + } + + /** + * Get all queued Events. + */ + public synchronized Event[] deQueueAll(long maxWaitTime) throws InterruptedException { + while (isEmpty()) { + if (maxWaitTime >= 0) { + wait(maxWaitTime); + + // Timed out or woken; if still empty we + // had bad luck and return failure. + if (isEmpty()) { + return null; + } + } else { + // Wait indefinitely for something in queue. + wait(); + } + } + + // Dequeue all items item + Event[] events = new Event[getSize()]; + for (int i = 0; i < events.length; i++) { + events[i] = fetchNext(); + } + + // Notify possible wait()-ing enQueue()-ers + notifyAll(); + + // Return dequeued item + return events; + } + + public synchronized int getSize() { + return (rear >= front) ? (rear - front) : (capacity - front + rear); + } + + /** + * Is the queue empty ? + */ + public synchronized boolean isEmpty() { + return front == rear; + } + + /** + * Is the queue full ? + */ + public synchronized boolean isFull() { + return (next(rear) == front); + } + + /** + * Circular counter. + */ + private int next(int index) { + return (index + 1 < capacity ? index + 1 : 0); + } + + /** + * Circular counter. + */ + private Event fetchNext() { + Event temp = queue[front]; + queue[front] = null; + front = next(front); + return temp; + } + + public static void p(String s) { + System.out.println(s); + } + + public static void main(String[] args) { + EventQueue q = new EventQueue(8); + Event event = new Event("t"); + try { + q.enQueue(event); + p("(1) size = " + q.getSize()); + q.enQueue(event); + p("(2) size = " + q.getSize()); + q.deQueue(); + p("(1) size = " + q.getSize()); + q.deQueue(); + p("(0) size = " + q.getSize()); + + q.enQueue(event); + q.enQueue(event); + q.enQueue(event); + p("(3) size = " + q.getSize()); + q.deQueue(); + p("(2) size = " + q.getSize()); + q.enQueue(event); + q.enQueue(event); + q.enQueue(event); + p("(5) size = " + q.getSize()); + q.enQueue(event); + q.enQueue(event); + p("(7) size = " + q.getSize()); + q.deQueue(); + q.deQueue(); + q.deQueue(); + p("(4) size = " + q.getSize()); + q.deQueue(); + q.deQueue(); + q.deQueue(); + ; + q.deQueue(); + p("(0) size = " + q.getSize()); + + q.enQueue(event); + q.enQueue(event); + q.enQueue(event); + q.enQueue(event); + q.enQueue(event); + p("(5) size = " + q.getSize()); + + q.deQueue(); + q.deQueue(); + q.deQueue(); + ; + q.deQueue(); + p("(1) size = " + q.getSize()); + } catch (InterruptedException ie) { + } + } +} + +/* +* $Log: EventQueue.java,v $ +* Revision 1.3 2007/11/23 14:33:07 justb +* core classes now configurable through factory +* +* Revision 1.2 2005/02/21 11:50:46 justb +* ohase1 of refactoring Subscriber into Session/Controller/Subscriber +* +* Revision 1.1 2005/02/18 10:07:23 justb +* many renamings of classes (make names compact) +* +* Revision 1.6 2005/02/16 12:16:16 justb +* added support for "poll" mode +* +* Revision 1.5 2005/01/13 14:47:15 justb +* control evt: send response on same (control) connection +* +* Revision 1.4 2004/09/03 22:35:37 justb +* Almost complete rewrite, just checking in now +* +* Revision 1.3 2003/08/15 08:37:40 justb +* fix/add Copyright+LGPL file headers and footers +* +* +*/ diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/EventSource.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/EventSource.java index afd34ed365..89f8b2cd4d 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/EventSource.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/EventSource.java @@ -1,70 +1,70 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -/** - * Abstract Event source from which Events are pulled. - * - * @version $Id: EventSource.java,v 1.7 2007/11/23 14:33:07 justb Exp $ - * @author Just van den Broecke - Just Objects © - **/ - -/** - * Interface for specifc Event(Pull/Push)Sources. - */ -public interface EventSource { - /** - * Activate the event source. - */ - public void activate(); - - /** - * Deactivate the event source. - */ - public void passivate(); - - /** - * Halt the event source. - */ - public void stop(); -} - -/* - * $Log: EventSource.java,v $ - * Revision 1.7 2007/11/23 14:33:07 justb - * core classes now configurable through factory - * - * Revision 1.6 2005/02/21 11:50:46 justb - * ohase1 of refactoring Subscriber into Session/Controller/Subscriber - * - * Revision 1.5 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.4 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.3 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.2 2003/05/18 16:15:08 justb - * support for XML encoded Events - * - * Revision 1.1.1.1 2002/09/24 21:02:31 justb - * import to sourceforge - * - * Revision 1.1.1.1 2002/09/20 22:48:17 justb - * import to SF - * - * Revision 1.1.1.1 2002/09/20 14:19:03 justb - * first import into SF - * - * Revision 1.3 2002/04/15 20:42:41 just - * reformatting and renaming GuardedQueue to EventQueue - * - * Revision 1.2 2000/08/21 20:48:29 just - * added CVS log and id tags plus copyrights - * - * - */ - +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +/** + * Abstract Event source from which Events are pulled. + * + * @version $Id: EventSource.java,v 1.7 2007/11/23 14:33:07 justb Exp $ + * @author Just van den Broecke - Just Objects © + **/ + +/** + * Interface for specifc Event(Pull/Push)Sources. + */ +public interface EventSource { + /** + * Activate the event source. + */ + public void activate(); + + /** + * Deactivate the event source. + */ + public void passivate(); + + /** + * Halt the event source. + */ + public void stop(); +} + +/* + * $Log: EventSource.java,v $ + * Revision 1.7 2007/11/23 14:33:07 justb + * core classes now configurable through factory + * + * Revision 1.6 2005/02/21 11:50:46 justb + * ohase1 of refactoring Subscriber into Session/Controller/Subscriber + * + * Revision 1.5 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.4 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.3 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.2 2003/05/18 16:15:08 justb + * support for XML encoded Events + * + * Revision 1.1.1.1 2002/09/24 21:02:31 justb + * import to sourceforge + * + * Revision 1.1.1.1 2002/09/20 22:48:17 justb + * import to SF + * + * Revision 1.1.1.1 2002/09/20 14:19:03 justb + * first import into SF + * + * Revision 1.3 2002/04/15 20:42:41 just + * reformatting and renaming GuardedQueue to EventQueue + * + * Revision 1.2 2000/08/21 20:48:29 just + * added CVS log and id tags plus copyrights + * + * + */ + diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/EventSourceManager.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/EventSourceManager.java index b6b496637a..835b774daa 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/EventSourceManager.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/EventSourceManager.java @@ -1,169 +1,169 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -import nl.justobjects.pushlet.util.Log; -import nl.justobjects.pushlet.util.Sys; - -import java.util.Enumeration; -import java.util.Properties; -import java.util.Vector; -import java.io.File; - -/** - * Maintains lifecycle of event sources. - * - * @author Just van den Broecke - Just Objects © - * @version $Id: EventSourceManager.java,v 1.14 2007/11/10 13:44:02 justb Exp $ - */ -public class EventSourceManager { - private static Vector eventSources = new Vector(0); - private static final String PROPERTIES_FILE = "sources.properties"; - - /** - * Initialize event sources from properties file. - */ - public static void start(String aDirPath) { - // Load Event sources using properties file. - Log.info("EventSourceManager: start"); - - Properties properties = null; - - try { - properties = Sys.loadPropertiesResource(PROPERTIES_FILE); - } catch (Throwable t) { - // Try from provided dir (e.g. WEB_INF/pushlet.properties) - String filePath = aDirPath + File.separator + PROPERTIES_FILE; - Log.info("EventSourceManager: cannot load " + PROPERTIES_FILE + " from classpath, will try from " + filePath); - - try { - properties = Sys.loadPropertiesFile(filePath); - } catch (Throwable t2) { - Log.fatal("EventSourceManager: cannot load properties file from " + filePath, t); - - // Give up - Log.warn("EventSourceManager: not starting local event sources (maybe that is what you want)"); - return; - } - } - - // Create event source collection - eventSources = new Vector(properties.size()); - - // Add the configured sources - for (Enumeration e = properties.keys(); e.hasMoreElements();) { - String nextKey = (String) e.nextElement(); - String nextClass = properties.getProperty(nextKey); - EventSource nextEventSource = null; - try { - nextEventSource = (EventSource) Class.forName(nextClass).newInstance(); - Log.info("created EventSource: key=" + nextKey + " class=" + nextClass); - eventSources.addElement(nextEventSource); - } catch (Exception ex) { - Log.warn("Cannot create EventSource: class=" + nextClass, ex); - } - } - - activate(); - } - - /** - * Activate all event sources. - */ - public static void activate() { - Log.info("Activating " + eventSources.size() + " EventSources"); - for (int i = 0; i < eventSources.size(); i++) { - ((EventSource) eventSources.elementAt(i)).activate(); - } - Log.info("EventSources activated"); - } - - /** - * Deactivate all event sources. - */ - public static void passivate() { - Log.info("Passivating " + eventSources.size() + " EventSources"); - for (int i = 0; i < eventSources.size(); i++) { - ((EventSource) eventSources.elementAt(i)).passivate(); - } - Log.info("EventSources passivated"); - } - - /** - * Halt event sources. - */ - public static void stop() { - Log.info("Stopping " + eventSources.size() + " EventSources..."); - for (int i = 0; i < eventSources.size(); i++) { - ((EventSource) eventSources.elementAt(i)).stop(); - } - Log.info("EventSources stopped"); - } - -} - -/* - * $Log: EventSourceManager.java,v $ - * Revision 1.14 2007/11/10 13:44:02 justb - * pushlet.properties and sources.properties can now also be put under WEB-INF - * - * Revision 1.13 2005/02/21 11:50:46 justb - * ohase1 of refactoring Subscriber into Session/Controller/Subscriber - * - * Revision 1.12 2005/02/18 12:36:47 justb - * changes for renaming and configurability - * - * Revision 1.11 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.10 2005/02/15 13:29:49 justb - * use Sys.loadPropertiesResource() - * - * Revision 1.9 2004/09/20 22:01:38 justb - * more changes for new protocol - * - * Revision 1.8 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.7 2004/08/15 16:00:15 justb - * enhancements to pull mode - * - * Revision 1.6 2004/08/13 23:36:05 justb - * rewrite of Pullet into Pushlet "pull" mode - * - * Revision 1.5 2004/08/12 13:18:54 justb - * cosmetic changes - * - * Revision 1.4 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.3 2003/08/12 09:41:35 justb - * replace static initalizer with explicit init() - * - * Revision 1.2 2003/05/18 16:15:08 justb - * support for XML encoded Events - * - * Revision 1.1.1.1 2002/09/24 21:02:31 justb - * import to sourceforge - * - * Revision 1.1.1.1 2002/09/20 22:48:17 justb - * import to SF - * - * Revision 1.1.1.1 2002/09/20 14:19:03 justb - * first import into SF - * - * Revision 1.5 2002/04/15 20:42:41 just - * reformatting and renaming GuardedQueue to EventQueue - * - * Revision 1.4 2000/10/30 14:15:47 just - * no message - * - * Revision 1.3 2000/08/31 08:26:54 just - * Changed classloader that loads eventsources.properties to use EventSourceManager's classloader - * - * Revision 1.2 2000/08/21 20:48:29 just - * added CVS log and id tags plus copyrights - * - * - */ +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +import nl.justobjects.pushlet.util.Log; +import nl.justobjects.pushlet.util.Sys; + +import java.util.Enumeration; +import java.util.Properties; +import java.util.Vector; +import java.io.File; + +/** + * Maintains lifecycle of event sources. + * + * @author Just van den Broecke - Just Objects © + * @version $Id: EventSourceManager.java,v 1.14 2007/11/10 13:44:02 justb Exp $ + */ +public class EventSourceManager { + private static Vector eventSources = new Vector(0); + private static final String PROPERTIES_FILE = "sources.properties"; + + /** + * Initialize event sources from properties file. + */ + public static void start(String aDirPath) { + // Load Event sources using properties file. + Log.info("EventSourceManager: start"); + + Properties properties = null; + + try { + properties = Sys.loadPropertiesResource(PROPERTIES_FILE); + } catch (Throwable t) { + // Try from provided dir (e.g. WEB_INF/pushlet.properties) + String filePath = aDirPath + File.separator + PROPERTIES_FILE; + Log.info("EventSourceManager: cannot load " + PROPERTIES_FILE + " from classpath, will try from " + filePath); + + try { + properties = Sys.loadPropertiesFile(filePath); + } catch (Throwable t2) { + Log.fatal("EventSourceManager: cannot load properties file from " + filePath, t); + + // Give up + Log.warn("EventSourceManager: not starting local event sources (maybe that is what you want)"); + return; + } + } + + // Create event source collection + eventSources = new Vector(properties.size()); + + // Add the configured sources + for (Enumeration e = properties.keys(); e.hasMoreElements();) { + String nextKey = (String) e.nextElement(); + String nextClass = properties.getProperty(nextKey); + EventSource nextEventSource = null; + try { + nextEventSource = (EventSource) Class.forName(nextClass).newInstance(); + Log.info("created EventSource: key=" + nextKey + " class=" + nextClass); + eventSources.addElement(nextEventSource); + } catch (Exception ex) { + Log.warn("Cannot create EventSource: class=" + nextClass, ex); + } + } + + activate(); + } + + /** + * Activate all event sources. + */ + public static void activate() { + Log.info("Activating " + eventSources.size() + " EventSources"); + for (int i = 0; i < eventSources.size(); i++) { + ((EventSource) eventSources.elementAt(i)).activate(); + } + Log.info("EventSources activated"); + } + + /** + * Deactivate all event sources. + */ + public static void passivate() { + Log.info("Passivating " + eventSources.size() + " EventSources"); + for (int i = 0; i < eventSources.size(); i++) { + ((EventSource) eventSources.elementAt(i)).passivate(); + } + Log.info("EventSources passivated"); + } + + /** + * Halt event sources. + */ + public static void stop() { + Log.info("Stopping " + eventSources.size() + " EventSources..."); + for (int i = 0; i < eventSources.size(); i++) { + ((EventSource) eventSources.elementAt(i)).stop(); + } + Log.info("EventSources stopped"); + } + +} + +/* + * $Log: EventSourceManager.java,v $ + * Revision 1.14 2007/11/10 13:44:02 justb + * pushlet.properties and sources.properties can now also be put under WEB-INF + * + * Revision 1.13 2005/02/21 11:50:46 justb + * ohase1 of refactoring Subscriber into Session/Controller/Subscriber + * + * Revision 1.12 2005/02/18 12:36:47 justb + * changes for renaming and configurability + * + * Revision 1.11 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.10 2005/02/15 13:29:49 justb + * use Sys.loadPropertiesResource() + * + * Revision 1.9 2004/09/20 22:01:38 justb + * more changes for new protocol + * + * Revision 1.8 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.7 2004/08/15 16:00:15 justb + * enhancements to pull mode + * + * Revision 1.6 2004/08/13 23:36:05 justb + * rewrite of Pullet into Pushlet "pull" mode + * + * Revision 1.5 2004/08/12 13:18:54 justb + * cosmetic changes + * + * Revision 1.4 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.3 2003/08/12 09:41:35 justb + * replace static initalizer with explicit init() + * + * Revision 1.2 2003/05/18 16:15:08 justb + * support for XML encoded Events + * + * Revision 1.1.1.1 2002/09/24 21:02:31 justb + * import to sourceforge + * + * Revision 1.1.1.1 2002/09/20 22:48:17 justb + * import to SF + * + * Revision 1.1.1.1 2002/09/20 14:19:03 justb + * first import into SF + * + * Revision 1.5 2002/04/15 20:42:41 just + * reformatting and renaming GuardedQueue to EventQueue + * + * Revision 1.4 2000/10/30 14:15:47 just + * no message + * + * Revision 1.3 2000/08/31 08:26:54 just + * Changed classloader that loads eventsources.properties to use EventSourceManager's classloader + * + * Revision 1.2 2000/08/21 20:48:29 just + * added CVS log and id tags plus copyrights + * + * + */ diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/SerializedAdapter.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/SerializedAdapter.java index 462a4dd5c2..501a6ba3ce 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/SerializedAdapter.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/SerializedAdapter.java @@ -1,99 +1,99 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.ObjectOutputStream; - -/** - * Implementation of ClientAdapter that sends Events as serialized objects. - *

- * NOTE: You are discouraged to use this adapter, since it is Java-only - * and may have JVM-specific problems. Far better choice is to use XML - * and the XMLAdapter. - * - * @author Just van den Broecke - Just Objects © - * @version $Id: SerializedAdapter.java,v 1.4 2007/11/23 14:33:07 justb Exp $ - */ -class SerializedAdapter implements ClientAdapter { - private ObjectOutputStream out = null; - public static final String CONTENT_TYPE = "application/x-java-serialized-object"; - private HttpServletResponse servletRsp; - - /** - * Initialize. - */ - public SerializedAdapter(HttpServletResponse aServletResponse) { - servletRsp = aServletResponse; - } - - public void start() throws IOException { - - servletRsp.setContentType(CONTENT_TYPE); - - // Use a serialized object output stream - out = new ObjectOutputStream(servletRsp.getOutputStream()); - - // Don't need this further - servletRsp = null; - } - - /** - * Push Event to client. - */ - public void push(Event anEvent) throws IOException { - out.writeObject(anEvent); - - out.flush(); - } - - - public void stop() throws IOException { - } -} - -/* - * $Log: SerializedAdapter.java,v $ - * Revision 1.4 2007/11/23 14:33:07 justb - * core classes now configurable through factory - * - * Revision 1.3 2005/02/28 12:45:59 justb - * introduced Command class - * - * Revision 1.2 2005/02/21 11:50:46 justb - * ohase1 of refactoring Subscriber into Session/Controller/Subscriber - * - * Revision 1.1 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.4 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.3 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.2 2003/05/18 16:13:48 justb - * fixed blocking for java.net.URL with HTTP/1.1 (JVMs > 1.1) - * - * Revision 1.1.1.1 2002/09/24 21:02:31 justb - * import to sourceforge - * - * Revision 1.1.1.1 2002/09/20 22:48:18 justb - * import to SF - * - * Revision 1.1.1.1 2002/09/20 14:19:03 justb - * first import into SF - * - * Revision 1.5 2002/04/15 20:42:41 just - * reformatting and renaming GuardedQueue to EventQueue - * - * Revision 1.4 2000/12/27 22:39:35 just - * no message - * - * Revision 1.3 2000/08/21 20:48:29 just - * added CVS log and id tags plus copyrights - * - * - */ +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.ObjectOutputStream; + +/** + * Implementation of ClientAdapter that sends Events as serialized objects. + *

+ * NOTE: You are discouraged to use this adapter, since it is Java-only + * and may have JVM-specific problems. Far better choice is to use XML + * and the XMLAdapter. + * + * @author Just van den Broecke - Just Objects © + * @version $Id: SerializedAdapter.java,v 1.4 2007/11/23 14:33:07 justb Exp $ + */ +class SerializedAdapter implements ClientAdapter { + private ObjectOutputStream out = null; + public static final String CONTENT_TYPE = "application/x-java-serialized-object"; + private HttpServletResponse servletRsp; + + /** + * Initialize. + */ + public SerializedAdapter(HttpServletResponse aServletResponse) { + servletRsp = aServletResponse; + } + + public void start() throws IOException { + + servletRsp.setContentType(CONTENT_TYPE); + + // Use a serialized object output stream + out = new ObjectOutputStream(servletRsp.getOutputStream()); + + // Don't need this further + servletRsp = null; + } + + /** + * Push Event to client. + */ + public void push(Event anEvent) throws IOException { + out.writeObject(anEvent); + + out.flush(); + } + + + public void stop() throws IOException { + } +} + +/* + * $Log: SerializedAdapter.java,v $ + * Revision 1.4 2007/11/23 14:33:07 justb + * core classes now configurable through factory + * + * Revision 1.3 2005/02/28 12:45:59 justb + * introduced Command class + * + * Revision 1.2 2005/02/21 11:50:46 justb + * ohase1 of refactoring Subscriber into Session/Controller/Subscriber + * + * Revision 1.1 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.4 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.3 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.2 2003/05/18 16:13:48 justb + * fixed blocking for java.net.URL with HTTP/1.1 (JVMs > 1.1) + * + * Revision 1.1.1.1 2002/09/24 21:02:31 justb + * import to sourceforge + * + * Revision 1.1.1.1 2002/09/20 22:48:18 justb + * import to SF + * + * Revision 1.1.1.1 2002/09/20 14:19:03 justb + * first import into SF + * + * Revision 1.5 2002/04/15 20:42:41 just + * reformatting and renaming GuardedQueue to EventQueue + * + * Revision 1.4 2000/12/27 22:39:35 just + * no message + * + * Revision 1.3 2000/08/21 20:48:29 just + * added CVS log and id tags plus copyrights + * + * + */ diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/Subscriber.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/Subscriber.java index 39f5ba0198..dca30b6bfd 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/Subscriber.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/Subscriber.java @@ -1,469 +1,469 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -import nl.justobjects.pushlet.util.PushletException; -import nl.justobjects.pushlet.util.Rand; -import nl.justobjects.pushlet.util.Sys; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.net.URLEncoder; - -/** - * Handles data channel between dispatcher and client. - * - * @author Just van den Broecke - Just Objects © - * @version $Id: Subscriber.java,v 1.26 2007/11/23 14:33:07 justb Exp $ - */ -public class Subscriber implements Protocol, ConfigDefs { - private Session session; - - /** - * Blocking queue. - */ - private EventQueue eventQueue = new EventQueue(Config.getIntProperty(QUEUE_SIZE)); - - /** - * URL to be used in refresh requests in pull/poll modes. - */ - private long queueReadTimeoutMillis = Config.getLongProperty(QUEUE_READ_TIMEOUT_MILLIS); - private long queueWriteTimeoutMillis = Config.getLongProperty(QUEUE_WRITE_TIMEOUT_MILLIS); - private long refreshTimeoutMillis = Config.getLongProperty(PULL_REFRESH_TIMEOUT_MILLIS); - volatile long lastAlive = Sys.now(); - - /** - * Map of active subscriptions, keyed by their subscription id. - */ - private Map subscriptions = Collections.synchronizedMap(new HashMap(3)); - - /** - * Are we able to accept/send events ?. - */ - private volatile boolean active; - - /** - * Transfer mode (stream, pull, poll). - */ - private String mode; - - - /** - * Protected constructor as we create through factory method. - */ - protected Subscriber() { - } - - /** - * Create instance through factory method. - * - * @param aSession the parent Session - * @return a Subscriber object (or derived) - * @throws PushletException exception, usually misconfiguration - */ - public static Subscriber create(Session aSession) throws PushletException { - Subscriber subscriber; - try { - subscriber = (Subscriber) Config.getClass(SUBSCRIBER_CLASS, "nl.justobjects.pushlet.core.Subscriber").newInstance(); - } catch (Throwable t) { - throw new PushletException("Cannot instantiate Subscriber from config", t); - } - - subscriber.session = aSession; - return subscriber; - } - - public void start() { - active = true; - } - - public void stop() { - removeSubscriptions(); - active = false; - } - - public void bailout() { - session.stop(); - } - - /** - * Are we still active to handle events. - */ - public boolean isActive() { - return active; - } - - /** - * Return client session. - */ - public Session getSession() { - return session; - } - - /** - * Get (session) id. - */ - public String getId() { - return session.getId(); - } - - /** - * Return subscriptions. - */ - public Subscription[] getSubscriptions() { - // todo: Optimize - return (Subscription[]) subscriptions.values().toArray(new Subscription[0]); - } - - /** - * Add a subscription. - */ - public Subscription addSubscription(String aSubject, String aLabel) throws PushletException { - Subscription subscription = Subscription.create(aSubject, aLabel); - subscriptions.put(subscription.getId(), subscription); - info("Subscription added subject=" + aSubject + " sid=" + subscription.getId() + " label=" + aLabel); - return subscription; - } - - /** - * Remove a subscription. - */ - public Subscription removeSubscription(String aSubscriptionId) { - Subscription subscription = (Subscription) subscriptions.remove(aSubscriptionId); - if (subscription == null) { - warn("No subscription found sid=" + aSubscriptionId); - return null; - } - info("Subscription removed subject=" + subscription.getSubject() + " sid=" + subscription.getId() + " label=" + subscription.getLabel()); - return subscription; - } - - /** - * Remove all subscriptions. - */ - public void removeSubscriptions() { - subscriptions.clear(); - } - - public String getMode() { - return mode; - } - - public void setMode(String aMode) { - mode = aMode; - } - - public long getRefreshTimeMillis() { - String minWaitProperty = PULL_REFRESH_WAIT_MIN_MILLIS; - String maxWaitProperty = PULL_REFRESH_WAIT_MAX_MILLIS; - if (mode.equals((MODE_POLL))) { - minWaitProperty = POLL_REFRESH_WAIT_MIN_MILLIS; - maxWaitProperty = POLL_REFRESH_WAIT_MAX_MILLIS; - - } - return Rand.randomLong(Config.getLongProperty(minWaitProperty), - Config.getLongProperty(maxWaitProperty)); - } - - /** - * Get events from queue and push to client. - */ - public void fetchEvents(Command aCommand) throws PushletException { - - String refreshURL = aCommand.httpReq.getRequestURI() + "?" + P_ID + "=" + session.getId() + "&" + P_EVENT + "=" + E_REFRESH; - - // This is the only thing required to support "poll" mode - if (mode.equals(MODE_POLL)) { - queueReadTimeoutMillis = 0; - refreshTimeoutMillis = Config.getLongProperty(POLL_REFRESH_TIMEOUT_MILLIS); - } - - // Required for fast bailout (tomcat) - aCommand.httpRsp.setBufferSize(128); - - // Try to prevent caching in any form. - aCommand.sendResponseHeaders(); - - // Let clientAdapter determine how to send event - ClientAdapter clientAdapter = aCommand.getClientAdapter(); - Event responseEvent = aCommand.getResponseEvent(); - try { - clientAdapter.start(); - - // Send first event (usually hb-ack or listen-ack) - clientAdapter.push(responseEvent); - - // In pull/poll mode and when response is listen-ack or join-listen-ack, - // return and force refresh immediately - // such that the client recieves response immediately over this channel. - // This is usually when loading the browser app for the first time - if ((mode.equals(MODE_POLL) || mode.equals(MODE_PULL)) - && responseEvent.getEventType().endsWith(Protocol.E_LISTEN_ACK)) { - sendRefresh(clientAdapter, refreshURL); - - // We should come back later with refresh event... - return; - } - } catch (Throwable t) { - bailout(); - return; - } - - - Event[] events = null; - - // Main loop: as long as connected, get events and push to client - long eventSeqNr = 1; - while (isActive()) { - // Indicate we are still alive - lastAlive = Sys.now(); - - // Update session time to live - session.kick(); - - // Get next events; blocks until timeout or entire contents - // of event queue is returned. Note that "poll" mode - // will return immediately when queue is empty. - try { - // Put heartbeat in queue when starting to listen in stream mode - // This speeds up the return of *_LISTEN_ACK - if (mode.equals(MODE_STREAM) && eventSeqNr == 1) { - eventQueue.enQueue(new Event(E_HEARTBEAT)); - } - - events = eventQueue.deQueueAll(queueReadTimeoutMillis); - } catch (InterruptedException ie) { - warn("interrupted"); - bailout(); - } - - // Send heartbeat when no events received - if (events == null) { - events = new Event[1]; - events[0] = new Event(E_HEARTBEAT); - } - - // ASSERT: one or more events available - - // Send events to client using adapter - // debug("received event count=" + events.length); - for (int i = 0; i < events.length; i++) { - // Check for abort event - if (events[i].getEventType().equals(E_ABORT)) { - warn("Aborting Subscriber"); - bailout(); - } - - // Push next Event to client - try { - // Set sequence number - events[i].setField(P_SEQ, eventSeqNr++); - - // Push to client through client adapter - clientAdapter.push(events[i]); - } catch (Throwable t) { - bailout(); - return; - } - } - - // Force client refresh request in pull or poll modes - if (mode.equals(MODE_PULL) || mode.equals(MODE_POLL)) { - sendRefresh(clientAdapter, refreshURL); - - // Always leave loop in pull/poll mode - break; - } - } - } - - /** - * Determine if we should receive event. - */ - public Subscription match(Event event) { - Subscription[] subscriptions = getSubscriptions(); - for (int i = 0; i < subscriptions.length; i++) { - if (subscriptions[i].match(event)) { - return subscriptions[i]; - } - } - return null; - } - - /** - * Event from Dispatcher: enqueue it. - */ - public void onEvent(Event theEvent) { - if (!isActive()) { - return; - } - - // p("send: queue event: "+theEvent.getSubject()); - - // Check if we had any active continuation for at - // least 'timeOut' millisecs. If the client has left this - // instance there would be no way of knowing otherwise. - long now = Sys.now(); - if (now - lastAlive > refreshTimeoutMillis) { - warn("not alive for at least: " + refreshTimeoutMillis + "ms, leaving..."); - bailout(); - return; - } - - // Put event in queue; leave if queue full - try { - if (!eventQueue.enQueue(theEvent, queueWriteTimeoutMillis)) { - warn("queue full, bailing out..."); - bailout(); - } - - // ASSERTION : Event in queue. - // see fetchEvents() where Events are dequeued and pushed to the client. - } catch (InterruptedException ie) { - bailout(); - } - - } - - /** - * Send refresh command to pull/poll clients. - */ - protected void sendRefresh(ClientAdapter aClientAdapter, String aRefreshURL) { - Event refreshEvent = new Event(E_REFRESH); - - // Set wait time and url for refresh - refreshEvent.setField(P_WAIT, "" + getRefreshTimeMillis()); - refreshEvent.setField(P_URL, aRefreshURL); - - try { - // Push to client through client adapter - aClientAdapter.push(refreshEvent); - - // Stop this round until refresh event - aClientAdapter.stop(); - } catch (Throwable t) { - // Leave on any exception - bailout(); - } - } - - /** - * Info. - */ - protected void info(String s) { - session.info("[Subscriber] " + s); - } - - /** - * Exceptional print util. - */ - protected void warn(String s) { - session.warn("[Subscriber] " + s); - } - - /** - * Exceptional print util. - */ - protected void debug(String s) { - session.debug("[Subscriber] " + s); - } - - - public String toString() { - return session.toString(); - } -} - -/* - * $Log: Subscriber.java,v $ - * Revision 1.26 2007/11/23 14:33:07 justb - * core classes now configurable through factory - * - * Revision 1.25 2007/11/10 15:53:15 justb - * put heartbeat in queue when start fetching events in stream-mode - * - * Revision 1.24 2006/10/19 12:33:40 justb - * add atomic join-listen support (one request) - * - * Revision 1.22 2006/05/06 00:06:28 justb - * first rough version AJAX client - * - * Revision 1.21 2005/02/28 12:45:59 justb - * introduced Command class - * - * Revision 1.20 2005/02/21 16:59:09 justb - * SessionManager and session lease introduced - * - * Revision 1.19 2005/02/21 12:32:28 justb - * fixed publish event in Controller - * - * Revision 1.18 2005/02/21 11:50:46 justb - * ohase1 of refactoring Subscriber into Session/Controller/Subscriber - * - * Revision 1.17 2005/02/20 13:05:32 justb - * removed the Postlet (integrated in Pushlet protocol) - * - * Revision 1.16 2005/02/18 12:36:47 justb - * changes for renaming and configurability - * - * Revision 1.15 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.14 2005/02/18 09:54:15 justb - * refactor: rename Publisher Dispatcher and single Subscriber class - * - * Revision 1.13 2005/02/16 14:39:34 justb - * fixed leave handling and added "poll" mode - * - * Revision 1.12 2005/01/24 13:42:00 justb - * new protocol changes (p_listen) - * - * Revision 1.11 2005/01/13 14:47:15 justb - * control evt: send response on same (control) connection - * - * Revision 1.10 2004/10/24 20:50:35 justb - * refine subscription with label and sending sid and label on events - * - * Revision 1.9 2004/10/24 12:58:18 justb - * revised client and test classes for new protocol - * - * Revision 1.8 2004/09/26 21:39:43 justb - * allow multiple subscriptions and out-of-band requests - * - * Revision 1.7 2004/09/20 22:01:38 justb - * more changes for new protocol - * - * Revision 1.6 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.5 2004/08/13 23:36:05 justb - * rewrite of Pullet into Pushlet "pull" mode - * - * Revision 1.4 2004/03/10 14:01:55 justb - * formatting and *Subscriber refactoring - * - * Revision 1.3 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.2 2003/05/18 16:15:08 justb - * support for XML encoded Events - * - * Revision 1.1.1.1 2002/09/24 21:02:32 justb - * import to sourceforge - * - * Revision 1.1.1.1 2002/09/20 22:48:18 justb - * import to SF - * - * Revision 1.1.1.1 2002/09/20 14:19:04 justb - * first import into SF - * - * Revision 1.3 2002/04/15 20:42:41 just - * reformatting and renaming GuardedQueue to EventQueue - * - * Revision 1.2 2000/08/21 20:48:29 just - * added CVS log and id tags plus copyrights - * - * - */ +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +import nl.justobjects.pushlet.util.PushletException; +import nl.justobjects.pushlet.util.Rand; +import nl.justobjects.pushlet.util.Sys; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.net.URLEncoder; + +/** + * Handles data channel between dispatcher and client. + * + * @author Just van den Broecke - Just Objects © + * @version $Id: Subscriber.java,v 1.26 2007/11/23 14:33:07 justb Exp $ + */ +public class Subscriber implements Protocol, ConfigDefs { + private Session session; + + /** + * Blocking queue. + */ + private EventQueue eventQueue = new EventQueue(Config.getIntProperty(QUEUE_SIZE)); + + /** + * URL to be used in refresh requests in pull/poll modes. + */ + private long queueReadTimeoutMillis = Config.getLongProperty(QUEUE_READ_TIMEOUT_MILLIS); + private long queueWriteTimeoutMillis = Config.getLongProperty(QUEUE_WRITE_TIMEOUT_MILLIS); + private long refreshTimeoutMillis = Config.getLongProperty(PULL_REFRESH_TIMEOUT_MILLIS); + volatile long lastAlive = Sys.now(); + + /** + * Map of active subscriptions, keyed by their subscription id. + */ + private Map subscriptions = Collections.synchronizedMap(new HashMap(3)); + + /** + * Are we able to accept/send events ?. + */ + private volatile boolean active; + + /** + * Transfer mode (stream, pull, poll). + */ + private String mode; + + + /** + * Protected constructor as we create through factory method. + */ + protected Subscriber() { + } + + /** + * Create instance through factory method. + * + * @param aSession the parent Session + * @return a Subscriber object (or derived) + * @throws PushletException exception, usually misconfiguration + */ + public static Subscriber create(Session aSession) throws PushletException { + Subscriber subscriber; + try { + subscriber = (Subscriber) Config.getClass(SUBSCRIBER_CLASS, "nl.justobjects.pushlet.core.Subscriber").newInstance(); + } catch (Throwable t) { + throw new PushletException("Cannot instantiate Subscriber from config", t); + } + + subscriber.session = aSession; + return subscriber; + } + + public void start() { + active = true; + } + + public void stop() { + removeSubscriptions(); + active = false; + } + + public void bailout() { + session.stop(); + } + + /** + * Are we still active to handle events. + */ + public boolean isActive() { + return active; + } + + /** + * Return client session. + */ + public Session getSession() { + return session; + } + + /** + * Get (session) id. + */ + public String getId() { + return session.getId(); + } + + /** + * Return subscriptions. + */ + public Subscription[] getSubscriptions() { + // todo: Optimize + return (Subscription[]) subscriptions.values().toArray(new Subscription[0]); + } + + /** + * Add a subscription. + */ + public Subscription addSubscription(String aSubject, String aLabel) throws PushletException { + Subscription subscription = Subscription.create(aSubject, aLabel); + subscriptions.put(subscription.getId(), subscription); + info("Subscription added subject=" + aSubject + " sid=" + subscription.getId() + " label=" + aLabel); + return subscription; + } + + /** + * Remove a subscription. + */ + public Subscription removeSubscription(String aSubscriptionId) { + Subscription subscription = (Subscription) subscriptions.remove(aSubscriptionId); + if (subscription == null) { + warn("No subscription found sid=" + aSubscriptionId); + return null; + } + info("Subscription removed subject=" + subscription.getSubject() + " sid=" + subscription.getId() + " label=" + subscription.getLabel()); + return subscription; + } + + /** + * Remove all subscriptions. + */ + public void removeSubscriptions() { + subscriptions.clear(); + } + + public String getMode() { + return mode; + } + + public void setMode(String aMode) { + mode = aMode; + } + + public long getRefreshTimeMillis() { + String minWaitProperty = PULL_REFRESH_WAIT_MIN_MILLIS; + String maxWaitProperty = PULL_REFRESH_WAIT_MAX_MILLIS; + if (mode.equals((MODE_POLL))) { + minWaitProperty = POLL_REFRESH_WAIT_MIN_MILLIS; + maxWaitProperty = POLL_REFRESH_WAIT_MAX_MILLIS; + + } + return Rand.randomLong(Config.getLongProperty(minWaitProperty), + Config.getLongProperty(maxWaitProperty)); + } + + /** + * Get events from queue and push to client. + */ + public void fetchEvents(Command aCommand) throws PushletException { + + String refreshURL = aCommand.httpReq.getRequestURI() + "?" + P_ID + "=" + session.getId() + "&" + P_EVENT + "=" + E_REFRESH; + + // This is the only thing required to support "poll" mode + if (mode.equals(MODE_POLL)) { + queueReadTimeoutMillis = 0; + refreshTimeoutMillis = Config.getLongProperty(POLL_REFRESH_TIMEOUT_MILLIS); + } + + // Required for fast bailout (tomcat) + aCommand.httpRsp.setBufferSize(128); + + // Try to prevent caching in any form. + aCommand.sendResponseHeaders(); + + // Let clientAdapter determine how to send event + ClientAdapter clientAdapter = aCommand.getClientAdapter(); + Event responseEvent = aCommand.getResponseEvent(); + try { + clientAdapter.start(); + + // Send first event (usually hb-ack or listen-ack) + clientAdapter.push(responseEvent); + + // In pull/poll mode and when response is listen-ack or join-listen-ack, + // return and force refresh immediately + // such that the client recieves response immediately over this channel. + // This is usually when loading the browser app for the first time + if ((mode.equals(MODE_POLL) || mode.equals(MODE_PULL)) + && responseEvent.getEventType().endsWith(Protocol.E_LISTEN_ACK)) { + sendRefresh(clientAdapter, refreshURL); + + // We should come back later with refresh event... + return; + } + } catch (Throwable t) { + bailout(); + return; + } + + + Event[] events = null; + + // Main loop: as long as connected, get events and push to client + long eventSeqNr = 1; + while (isActive()) { + // Indicate we are still alive + lastAlive = Sys.now(); + + // Update session time to live + session.kick(); + + // Get next events; blocks until timeout or entire contents + // of event queue is returned. Note that "poll" mode + // will return immediately when queue is empty. + try { + // Put heartbeat in queue when starting to listen in stream mode + // This speeds up the return of *_LISTEN_ACK + if (mode.equals(MODE_STREAM) && eventSeqNr == 1) { + eventQueue.enQueue(new Event(E_HEARTBEAT)); + } + + events = eventQueue.deQueueAll(queueReadTimeoutMillis); + } catch (InterruptedException ie) { + warn("interrupted"); + bailout(); + } + + // Send heartbeat when no events received + if (events == null) { + events = new Event[1]; + events[0] = new Event(E_HEARTBEAT); + } + + // ASSERT: one or more events available + + // Send events to client using adapter + // debug("received event count=" + events.length); + for (int i = 0; i < events.length; i++) { + // Check for abort event + if (events[i].getEventType().equals(E_ABORT)) { + warn("Aborting Subscriber"); + bailout(); + } + + // Push next Event to client + try { + // Set sequence number + events[i].setField(P_SEQ, eventSeqNr++); + + // Push to client through client adapter + clientAdapter.push(events[i]); + } catch (Throwable t) { + bailout(); + return; + } + } + + // Force client refresh request in pull or poll modes + if (mode.equals(MODE_PULL) || mode.equals(MODE_POLL)) { + sendRefresh(clientAdapter, refreshURL); + + // Always leave loop in pull/poll mode + break; + } + } + } + + /** + * Determine if we should receive event. + */ + public Subscription match(Event event) { + Subscription[] subscriptions = getSubscriptions(); + for (int i = 0; i < subscriptions.length; i++) { + if (subscriptions[i].match(event)) { + return subscriptions[i]; + } + } + return null; + } + + /** + * Event from Dispatcher: enqueue it. + */ + public void onEvent(Event theEvent) { + if (!isActive()) { + return; + } + + // p("send: queue event: "+theEvent.getSubject()); + + // Check if we had any active continuation for at + // least 'timeOut' millisecs. If the client has left this + // instance there would be no way of knowing otherwise. + long now = Sys.now(); + if (now - lastAlive > refreshTimeoutMillis) { + warn("not alive for at least: " + refreshTimeoutMillis + "ms, leaving..."); + bailout(); + return; + } + + // Put event in queue; leave if queue full + try { + if (!eventQueue.enQueue(theEvent, queueWriteTimeoutMillis)) { + warn("queue full, bailing out..."); + bailout(); + } + + // ASSERTION : Event in queue. + // see fetchEvents() where Events are dequeued and pushed to the client. + } catch (InterruptedException ie) { + bailout(); + } + + } + + /** + * Send refresh command to pull/poll clients. + */ + protected void sendRefresh(ClientAdapter aClientAdapter, String aRefreshURL) { + Event refreshEvent = new Event(E_REFRESH); + + // Set wait time and url for refresh + refreshEvent.setField(P_WAIT, "" + getRefreshTimeMillis()); + refreshEvent.setField(P_URL, aRefreshURL); + + try { + // Push to client through client adapter + aClientAdapter.push(refreshEvent); + + // Stop this round until refresh event + aClientAdapter.stop(); + } catch (Throwable t) { + // Leave on any exception + bailout(); + } + } + + /** + * Info. + */ + protected void info(String s) { + session.info("[Subscriber] " + s); + } + + /** + * Exceptional print util. + */ + protected void warn(String s) { + session.warn("[Subscriber] " + s); + } + + /** + * Exceptional print util. + */ + protected void debug(String s) { + session.debug("[Subscriber] " + s); + } + + + public String toString() { + return session.toString(); + } +} + +/* + * $Log: Subscriber.java,v $ + * Revision 1.26 2007/11/23 14:33:07 justb + * core classes now configurable through factory + * + * Revision 1.25 2007/11/10 15:53:15 justb + * put heartbeat in queue when start fetching events in stream-mode + * + * Revision 1.24 2006/10/19 12:33:40 justb + * add atomic join-listen support (one request) + * + * Revision 1.22 2006/05/06 00:06:28 justb + * first rough version AJAX client + * + * Revision 1.21 2005/02/28 12:45:59 justb + * introduced Command class + * + * Revision 1.20 2005/02/21 16:59:09 justb + * SessionManager and session lease introduced + * + * Revision 1.19 2005/02/21 12:32:28 justb + * fixed publish event in Controller + * + * Revision 1.18 2005/02/21 11:50:46 justb + * ohase1 of refactoring Subscriber into Session/Controller/Subscriber + * + * Revision 1.17 2005/02/20 13:05:32 justb + * removed the Postlet (integrated in Pushlet protocol) + * + * Revision 1.16 2005/02/18 12:36:47 justb + * changes for renaming and configurability + * + * Revision 1.15 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.14 2005/02/18 09:54:15 justb + * refactor: rename Publisher Dispatcher and single Subscriber class + * + * Revision 1.13 2005/02/16 14:39:34 justb + * fixed leave handling and added "poll" mode + * + * Revision 1.12 2005/01/24 13:42:00 justb + * new protocol changes (p_listen) + * + * Revision 1.11 2005/01/13 14:47:15 justb + * control evt: send response on same (control) connection + * + * Revision 1.10 2004/10/24 20:50:35 justb + * refine subscription with label and sending sid and label on events + * + * Revision 1.9 2004/10/24 12:58:18 justb + * revised client and test classes for new protocol + * + * Revision 1.8 2004/09/26 21:39:43 justb + * allow multiple subscriptions and out-of-band requests + * + * Revision 1.7 2004/09/20 22:01:38 justb + * more changes for new protocol + * + * Revision 1.6 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.5 2004/08/13 23:36:05 justb + * rewrite of Pullet into Pushlet "pull" mode + * + * Revision 1.4 2004/03/10 14:01:55 justb + * formatting and *Subscriber refactoring + * + * Revision 1.3 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.2 2003/05/18 16:15:08 justb + * support for XML encoded Events + * + * Revision 1.1.1.1 2002/09/24 21:02:32 justb + * import to sourceforge + * + * Revision 1.1.1.1 2002/09/20 22:48:18 justb + * import to SF + * + * Revision 1.1.1.1 2002/09/20 14:19:04 justb + * first import into SF + * + * Revision 1.3 2002/04/15 20:42:41 just + * reformatting and renaming GuardedQueue to EventQueue + * + * Revision 1.2 2000/08/21 20:48:29 just + * added CVS log and id tags plus copyrights + * + * + */ diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/XMLAdapter.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/XMLAdapter.java index 15d7096e59..70a9c3c47d 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/XMLAdapter.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/core/XMLAdapter.java @@ -1,137 +1,137 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -import nl.justobjects.pushlet.util.Log; - -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; - -/** - * ClientAdapter that sends Events as XML. - * - * @author Just van den Broecke - Just Objects © - * @version $Id: XMLAdapter.java,v 1.7 2007/11/09 13:15:35 justb Exp $ - */ -class XMLAdapter implements ClientAdapter { - /** - * Header for strict XML - */ - // public static final String XML_HEAD = "\n"; - private String contentType = "text/plain;charset=UTF-8"; - private ServletOutputStream out = null; - private HttpServletResponse servletRsp; - private boolean strictXML; - - /** - * Initialize. - */ - public XMLAdapter(HttpServletResponse aServletResponse) { - this(aServletResponse, false); - } - - /** - * Initialize. - */ - public XMLAdapter(HttpServletResponse aServletResponse, boolean useStrictXML) { - servletRsp = aServletResponse; - - // Strict XML implies returning a complete XML document - strictXML = useStrictXML; - if (strictXML) { - contentType = "text/xml;charset=UTF-8"; - } - } - - public void start() throws IOException { - - // If content type is plain text - // then this is not a complete XML document, but rather - // a stream of XML documents where each document is - // an Event. In strict XML mode a complete document is returned. - servletRsp.setContentType(contentType); - - out = servletRsp.getOutputStream(); - - // Don't need this further - servletRsp = null; - - // Start XML document if strict XML mode - if (strictXML) { - out.print(""); - } - } - - /** - * Force client to refresh the request. - */ - public void push(Event anEvent) throws IOException { - debug("event=" + anEvent); - - // Send the event as XML to the client and flush. - out.print(anEvent.toXML(strictXML)); - out.flush(); - } - - /** - * No action. - */ - public void stop() throws IOException { - // Close XML document if strict XML mode - if (strictXML) { - out.print(""); - out.flush(); - } - } - - private void debug(String s) { - Log.debug("[XMLAdapter]" + s); - } -} - -/* - * $Log: XMLAdapter.java,v $ - * Revision 1.7 2007/11/09 13:15:35 justb - * add charset=UTF-8 in returned HTTP content types - * - * Revision 1.6 2006/05/15 11:52:53 justb - * updates mainly for AJAX client - * - * Revision 1.5 2006/05/06 00:06:28 justb - * first rough version AJAX client - * - * Revision 1.4 2005/05/06 19:44:00 justb - * added xml-strict format - * - * Revision 1.3 2005/02/28 12:45:59 justb - * introduced Command class - * - * Revision 1.2 2005/02/21 11:50:47 justb - * ohase1 of refactoring Subscriber into Session/Controller/Subscriber - * - * Revision 1.1 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.7 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.6 2004/03/10 14:01:55 justb - * formatting and *Subscriber refactoring - * - * Revision 1.5 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.4 2003/08/13 14:00:00 justb - * some testing for applets; no real change - * - * Revision 1.3 2003/08/12 09:57:06 justb - * replaced all print statements to Log.*() calls - * - * Revision 1.2 2003/05/19 21:56:29 justb - * various fixes for applet clients - * - * Revision 1.1 2003/05/18 16:12:28 justb - * adding support for XML encoded Events - */ +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +import nl.justobjects.pushlet.util.Log; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * ClientAdapter that sends Events as XML. + * + * @author Just van den Broecke - Just Objects © + * @version $Id: XMLAdapter.java,v 1.7 2007/11/09 13:15:35 justb Exp $ + */ +class XMLAdapter implements ClientAdapter { + /** + * Header for strict XML + */ + // public static final String XML_HEAD = "\n"; + private String contentType = "text/plain;charset=UTF-8"; + private ServletOutputStream out = null; + private HttpServletResponse servletRsp; + private boolean strictXML; + + /** + * Initialize. + */ + public XMLAdapter(HttpServletResponse aServletResponse) { + this(aServletResponse, false); + } + + /** + * Initialize. + */ + public XMLAdapter(HttpServletResponse aServletResponse, boolean useStrictXML) { + servletRsp = aServletResponse; + + // Strict XML implies returning a complete XML document + strictXML = useStrictXML; + if (strictXML) { + contentType = "text/xml;charset=UTF-8"; + } + } + + public void start() throws IOException { + + // If content type is plain text + // then this is not a complete XML document, but rather + // a stream of XML documents where each document is + // an Event. In strict XML mode a complete document is returned. + servletRsp.setContentType(contentType); + + out = servletRsp.getOutputStream(); + + // Don't need this further + servletRsp = null; + + // Start XML document if strict XML mode + if (strictXML) { + out.print(""); + } + } + + /** + * Force client to refresh the request. + */ + public void push(Event anEvent) throws IOException { + debug("event=" + anEvent); + + // Send the event as XML to the client and flush. + out.print(anEvent.toXML(strictXML)); + out.flush(); + } + + /** + * No action. + */ + public void stop() throws IOException { + // Close XML document if strict XML mode + if (strictXML) { + out.print(""); + out.flush(); + } + } + + private void debug(String s) { + Log.debug("[XMLAdapter]" + s); + } +} + +/* + * $Log: XMLAdapter.java,v $ + * Revision 1.7 2007/11/09 13:15:35 justb + * add charset=UTF-8 in returned HTTP content types + * + * Revision 1.6 2006/05/15 11:52:53 justb + * updates mainly for AJAX client + * + * Revision 1.5 2006/05/06 00:06:28 justb + * first rough version AJAX client + * + * Revision 1.4 2005/05/06 19:44:00 justb + * added xml-strict format + * + * Revision 1.3 2005/02/28 12:45:59 justb + * introduced Command class + * + * Revision 1.2 2005/02/21 11:50:47 justb + * ohase1 of refactoring Subscriber into Session/Controller/Subscriber + * + * Revision 1.1 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.7 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.6 2004/03/10 14:01:55 justb + * formatting and *Subscriber refactoring + * + * Revision 1.5 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.4 2003/08/13 14:00:00 justb + * some testing for applets; no real change + * + * Revision 1.3 2003/08/12 09:57:06 justb + * replaced all print statements to Log.*() calls + * + * Revision 1.2 2003/05/19 21:56:29 justb + * various fixes for applet clients + * + * Revision 1.1 2003/05/18 16:12:28 justb + * adding support for XML encoded Events + */ diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/servlet/Pushlet.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/servlet/Pushlet.java index 5488733c8d..5177c5cc72 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/servlet/Pushlet.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/servlet/Pushlet.java @@ -1,293 +1,293 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.servlet; - -import nl.justobjects.pushlet.core.*; -import nl.justobjects.pushlet.util.Log; -import nl.justobjects.pushlet.util.Servlets; -import nl.justobjects.pushlet.util.PushletException; -import nl.justobjects.pushlet.Version; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.Enumeration; - -/** - * Servlet runs a Subscriber per request. - * - * @author Just van den Broecke - Just Objects © - * @version $Id: Pushlet.java,v 1.23 2007/12/04 13:55:53 justb Exp $ - */ -public class Pushlet extends HttpServlet implements Protocol { - - public void init() throws ServletException { - try { - // Load configuration (from classpath or WEB-INF root path) - String webInfPath = getServletContext().getRealPath("/") + "/WEB-INF"; - Config.load(webInfPath); - - Log.init(); - - // Start - Log.info("init() Pushlet Webapp - version=" + Version.SOFTWARE_VERSION + " built=" + Version.BUILD_DATE); - - // Start session manager - SessionManager.getInstance().start(); - - // Start event Dispatcher - Dispatcher.getInstance().start(); - - - if (Config.getBoolProperty(Config.SOURCES_ACTIVATE)) { - EventSourceManager.start(webInfPath); - } else { - Log.info("Not starting local event sources"); - } - } catch (Throwable t) { - throw new ServletException("Failed to initialize Pushlet framework " + t, t); - } - } - - public void destroy() { - Log.info("destroy(): Exit Pushlet webapp"); - - if (Config.getBoolProperty(Config.SOURCES_ACTIVATE)) { - // Stop local event sources - EventSourceManager.stop(); - } else { - Log.info("No local event sources to stop"); - } - - // Should abort all subscribers - Dispatcher.getInstance().stop(); - - // Should stop all sessions - SessionManager.getInstance().stop(); - } - - /** - * Servlet GET request: handles event requests. - */ - public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - Event event = null; - - try { - // Event parm identifies event type from the client - String eventType = Servlets.getParameter(request, P_EVENT); - - // Always must have an event type - if (eventType == null) { - Log.warn("Pushlet.doGet(): bad request, no event specified"); - response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No eventType specified"); - return; - } - - // Create Event and set attributes from parameters - event = new Event(eventType); - for (Enumeration e = request.getParameterNames(); e.hasMoreElements();) { - String nextAttribute = (String) e.nextElement(); - event.setField(nextAttribute, request.getParameter(nextAttribute)); - } - - - } catch (Throwable t) { - // Error creating event - Log.warn("Pushlet: Error creating event in doGet(): ", t); - response.setStatus(HttpServletResponse.SC_BAD_REQUEST); - return; - } - - // Handle parsed request - doRequest(event, request, response); - - } - - /** - * Servlet POST request: extracts event data from body. - */ - public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - Event event = null; - try { - // Create Event by parsing XML from input stream. - event = EventParser.parse(new InputStreamReader(request.getInputStream())); - - // Always must have an event type - if (event.getEventType() == null) { - Log.warn("Pushlet.doPost(): bad request, no event specified"); - response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No eventType specified"); - return; - } - - - } catch (Throwable t) { - // Error creating event - Log.warn("Pushlet: Error creating event in doPost(): ", t); - response.setStatus(HttpServletResponse.SC_BAD_REQUEST); - return; - } - - // Handle parsed request - doRequest(event, request, response); - - } - - /** - * Generic request handler (GET+POST). - */ - protected void doRequest(Event anEvent, HttpServletRequest request, HttpServletResponse response) { - // Must have valid event type. - String eventType = anEvent.getEventType(); - try { - - // Get Session: either by creating (on Join eventType) - // or by id (any other eventType, since client is supposed to have joined). - Session session = null; - if (eventType.startsWith(Protocol.E_JOIN)) { - // Join request: create new subscriber - session = SessionManager.getInstance().createSession(anEvent); - - String userAgent = request.getHeader("User-Agent"); - if (userAgent != null) { - userAgent = userAgent.toLowerCase(); - } else { - userAgent = "unknown"; - } - session.setUserAgent(userAgent); - - } else { - // Must be a request for existing Session - - // Get id - String id = anEvent.getField(P_ID); - - // We must have an id value - if (id == null) { - response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No id specified"); - Log.warn("Pushlet: bad request, no id specified event=" + eventType); - return; - } - - // We have an id: get the session object - session = SessionManager.getInstance().getSession(id); - - // Check for invalid id - if (session == null) { - response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid or expired id: " + id); - Log.warn("Pushlet: bad request, no session found id=" + id + " event=" + eventType); - return; - } - } - - // ASSERTION: we have a valid Session - - // Let Controller handle request further - // including exceptions - Command command = Command.create(session, anEvent, request, response); - session.getController().doCommand(command); - } catch (Throwable t) { - // Hmm we should never ever get here - Log.warn("Pushlet: Exception in doRequest() event=" + eventType, t); - t.printStackTrace(); - response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - } - - } -} - -/* - * $Log: Pushlet.java,v $ - * Revision 1.23 2007/12/04 13:55:53 justb - * reimplement SessionManager concurrency (prev version was not thread-safe!) - * - * Revision 1.22 2007/11/24 10:29:36 justb - * add hooks for custom logging (you can override DefaultLogger in pushlet.properties) - * - * Revision 1.21 2007/11/23 21:10:17 justb - * add hooks for custom logging (you can override DefaultLogger in pushlet.properties) - * - * Revision 1.20 2007/11/10 13:44:02 justb - * pushlet.properties and sources.properties can now also be put under WEB-INF - * - * Revision 1.19 2006/05/15 11:52:53 justb - * updates mainly for AJAX client - * - * Revision 1.18 2005/02/28 15:58:05 justb - * added SimpleListener example - * - * Revision 1.17 2005/02/28 13:06:01 justb - * introduced join-listen protocol service - * - * Revision 1.16 2005/02/28 12:45:59 justb - * introduced Command class - * - * Revision 1.15 2005/02/28 09:14:56 justb - * sessmgr/dispatcher factory/singleton support - * - * Revision 1.14 2005/02/25 15:13:04 justb - * session id generation more robust - * - * Revision 1.13 2005/02/21 17:19:21 justb - * move init()/destroy() to Pushlet servlet - * - * Revision 1.12 2005/02/21 16:59:17 justb - * SessionManager and session lease introduced - * - * Revision 1.11 2005/02/21 11:50:47 justb - * ohase1 of refactoring Subscriber into Session/Controller/Subscriber - * - * Revision 1.10 2005/02/20 13:05:32 justb - * removed the Postlet (integrated in Pushlet protocol) - * - * Revision 1.9 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.8 2005/01/13 14:47:15 justb - * control evt: send response on same (control) connection - * - * Revision 1.7 2004/10/24 12:58:18 justb - * revised client and test classes for new protocol - * - * Revision 1.6 2004/09/26 21:39:44 justb - * allow multiple subscriptions and out-of-band requests - * - * Revision 1.5 2004/09/20 22:01:40 justb - * more changes for new protocol - * - * Revision 1.4 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.3 2004/08/13 23:36:06 justb - * rewrite of Pullet into Pushlet "pull" mode - * - * Revision 1.2 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.1 2003/08/13 13:26:57 justb - * moved all servlets to servlet package - * - * Revision 1.2 2003/05/18 16:15:08 justb - * support for XML encoded Events - * - * Revision 1.1.1.1 2002/09/24 21:02:32 justb - * import to sourceforge - * - * Revision 1.1.1.1 2002/09/20 22:48:18 justb - * import to SF - * - * Revision 1.1.1.1 2002/09/20 14:19:04 justb - * first import into SF - * - * Revision 1.3 2002/04/15 20:42:41 just - * reformatting and renaming GuardedQueue to EventQueue - * - * Revision 1.2 2000/08/21 20:48:29 just - * added CVS log and id tags plus copyrights - * - * - */ - +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.servlet; + +import nl.justobjects.pushlet.core.*; +import nl.justobjects.pushlet.util.Log; +import nl.justobjects.pushlet.util.Servlets; +import nl.justobjects.pushlet.util.PushletException; +import nl.justobjects.pushlet.Version; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Enumeration; + +/** + * Servlet runs a Subscriber per request. + * + * @author Just van den Broecke - Just Objects © + * @version $Id: Pushlet.java,v 1.23 2007/12/04 13:55:53 justb Exp $ + */ +public class Pushlet extends HttpServlet implements Protocol { + + public void init() throws ServletException { + try { + // Load configuration (from classpath or WEB-INF root path) + String webInfPath = getServletContext().getRealPath("/") + "/WEB-INF"; + Config.load(webInfPath); + + Log.init(); + + // Start + Log.info("init() Pushlet Webapp - version=" + Version.SOFTWARE_VERSION + " built=" + Version.BUILD_DATE); + + // Start session manager + SessionManager.getInstance().start(); + + // Start event Dispatcher + Dispatcher.getInstance().start(); + + + if (Config.getBoolProperty(Config.SOURCES_ACTIVATE)) { + EventSourceManager.start(webInfPath); + } else { + Log.info("Not starting local event sources"); + } + } catch (Throwable t) { + throw new ServletException("Failed to initialize Pushlet framework " + t, t); + } + } + + public void destroy() { + Log.info("destroy(): Exit Pushlet webapp"); + + if (Config.getBoolProperty(Config.SOURCES_ACTIVATE)) { + // Stop local event sources + EventSourceManager.stop(); + } else { + Log.info("No local event sources to stop"); + } + + // Should abort all subscribers + Dispatcher.getInstance().stop(); + + // Should stop all sessions + SessionManager.getInstance().stop(); + } + + /** + * Servlet GET request: handles event requests. + */ + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + Event event = null; + + try { + // Event parm identifies event type from the client + String eventType = Servlets.getParameter(request, P_EVENT); + + // Always must have an event type + if (eventType == null) { + Log.warn("Pushlet.doGet(): bad request, no event specified"); + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No eventType specified"); + return; + } + + // Create Event and set attributes from parameters + event = new Event(eventType); + for (Enumeration e = request.getParameterNames(); e.hasMoreElements();) { + String nextAttribute = (String) e.nextElement(); + event.setField(nextAttribute, request.getParameter(nextAttribute)); + } + + + } catch (Throwable t) { + // Error creating event + Log.warn("Pushlet: Error creating event in doGet(): ", t); + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + return; + } + + // Handle parsed request + doRequest(event, request, response); + + } + + /** + * Servlet POST request: extracts event data from body. + */ + public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + Event event = null; + try { + // Create Event by parsing XML from input stream. + event = EventParser.parse(new InputStreamReader(request.getInputStream())); + + // Always must have an event type + if (event.getEventType() == null) { + Log.warn("Pushlet.doPost(): bad request, no event specified"); + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No eventType specified"); + return; + } + + + } catch (Throwable t) { + // Error creating event + Log.warn("Pushlet: Error creating event in doPost(): ", t); + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + return; + } + + // Handle parsed request + doRequest(event, request, response); + + } + + /** + * Generic request handler (GET+POST). + */ + protected void doRequest(Event anEvent, HttpServletRequest request, HttpServletResponse response) { + // Must have valid event type. + String eventType = anEvent.getEventType(); + try { + + // Get Session: either by creating (on Join eventType) + // or by id (any other eventType, since client is supposed to have joined). + Session session = null; + if (eventType.startsWith(Protocol.E_JOIN)) { + // Join request: create new subscriber + session = SessionManager.getInstance().createSession(anEvent); + + String userAgent = request.getHeader("User-Agent"); + if (userAgent != null) { + userAgent = userAgent.toLowerCase(); + } else { + userAgent = "unknown"; + } + session.setUserAgent(userAgent); + + } else { + // Must be a request for existing Session + + // Get id + String id = anEvent.getField(P_ID); + + // We must have an id value + if (id == null) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No id specified"); + Log.warn("Pushlet: bad request, no id specified event=" + eventType); + return; + } + + // We have an id: get the session object + session = SessionManager.getInstance().getSession(id); + + // Check for invalid id + if (session == null) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid or expired id: " + id); + Log.warn("Pushlet: bad request, no session found id=" + id + " event=" + eventType); + return; + } + } + + // ASSERTION: we have a valid Session + + // Let Controller handle request further + // including exceptions + Command command = Command.create(session, anEvent, request, response); + session.getController().doCommand(command); + } catch (Throwable t) { + // Hmm we should never ever get here + Log.warn("Pushlet: Exception in doRequest() event=" + eventType, t); + t.printStackTrace(); + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + + } +} + +/* + * $Log: Pushlet.java,v $ + * Revision 1.23 2007/12/04 13:55:53 justb + * reimplement SessionManager concurrency (prev version was not thread-safe!) + * + * Revision 1.22 2007/11/24 10:29:36 justb + * add hooks for custom logging (you can override DefaultLogger in pushlet.properties) + * + * Revision 1.21 2007/11/23 21:10:17 justb + * add hooks for custom logging (you can override DefaultLogger in pushlet.properties) + * + * Revision 1.20 2007/11/10 13:44:02 justb + * pushlet.properties and sources.properties can now also be put under WEB-INF + * + * Revision 1.19 2006/05/15 11:52:53 justb + * updates mainly for AJAX client + * + * Revision 1.18 2005/02/28 15:58:05 justb + * added SimpleListener example + * + * Revision 1.17 2005/02/28 13:06:01 justb + * introduced join-listen protocol service + * + * Revision 1.16 2005/02/28 12:45:59 justb + * introduced Command class + * + * Revision 1.15 2005/02/28 09:14:56 justb + * sessmgr/dispatcher factory/singleton support + * + * Revision 1.14 2005/02/25 15:13:04 justb + * session id generation more robust + * + * Revision 1.13 2005/02/21 17:19:21 justb + * move init()/destroy() to Pushlet servlet + * + * Revision 1.12 2005/02/21 16:59:17 justb + * SessionManager and session lease introduced + * + * Revision 1.11 2005/02/21 11:50:47 justb + * ohase1 of refactoring Subscriber into Session/Controller/Subscriber + * + * Revision 1.10 2005/02/20 13:05:32 justb + * removed the Postlet (integrated in Pushlet protocol) + * + * Revision 1.9 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.8 2005/01/13 14:47:15 justb + * control evt: send response on same (control) connection + * + * Revision 1.7 2004/10/24 12:58:18 justb + * revised client and test classes for new protocol + * + * Revision 1.6 2004/09/26 21:39:44 justb + * allow multiple subscriptions and out-of-band requests + * + * Revision 1.5 2004/09/20 22:01:40 justb + * more changes for new protocol + * + * Revision 1.4 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.3 2004/08/13 23:36:06 justb + * rewrite of Pullet into Pushlet "pull" mode + * + * Revision 1.2 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.1 2003/08/13 13:26:57 justb + * moved all servlets to servlet package + * + * Revision 1.2 2003/05/18 16:15:08 justb + * support for XML encoded Events + * + * Revision 1.1.1.1 2002/09/24 21:02:32 justb + * import to sourceforge + * + * Revision 1.1.1.1 2002/09/20 22:48:18 justb + * import to SF + * + * Revision 1.1.1.1 2002/09/20 14:19:04 justb + * first import into SF + * + * Revision 1.3 2002/04/15 20:42:41 just + * reformatting and renaming GuardedQueue to EventQueue + * + * Revision 1.2 2000/08/21 20:48:29 just + * added CVS log and id tags plus copyrights + * + * + */ + diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/test/PushletApplet.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/test/PushletApplet.java index 23fcc44671..5e06ba258c 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/test/PushletApplet.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/test/PushletApplet.java @@ -1,178 +1,178 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.test; - -import nl.justobjects.pushlet.client.PushletClient; -import nl.justobjects.pushlet.client.PushletClientListener; -import nl.justobjects.pushlet.core.Event; -import nl.justobjects.pushlet.core.Protocol; -import nl.justobjects.pushlet.util.PushletException; - -import java.applet.Applet; -import java.awt.*; - -/** - * Tester for applet clients; displays incoming events in text area. - * - * @version $Id: PushletApplet.java,v 1.16 2005/02/18 09:54:15 justb Exp $ - * @author Just van den Broecke - Just Objects © - **/ -public class PushletApplet extends Applet implements PushletClientListener, Protocol { - private TextArea textArea; - private String host = "localhost"; - private int port = 8080; - private String subject; - private PushletClient pushletClient; - private String VERSION = "15.feb.05 #5"; - private String PUSH_MODE = Protocol.MODE_PULL; - - /** One-time setup. */ - public void init() { - // Subject to subscribe to - subject = getParameter(P_SUBJECT); - - host = getDocumentBase().getHost(); - port = getDocumentBase().getPort(); - - // Hmm sometimes this value is -1...(Mozilla with Java 1.3.0 on Win) - if (port == -1) { - port = 80; - } - - setLayout(new GridLayout(1, 1)); - textArea = new TextArea(15, 40); - textArea.setForeground(Color.yellow); - textArea.setBackground(Color.gray); - textArea.setEditable(false); - add(textArea); - p("PushletApplet - " + VERSION); - } - - public void start() { - dbg("start()"); - bailout(); - - try { - pushletClient = new PushletClient(host, port); - p("Created PushletClient"); - - pushletClient.join(); - p("Joined server"); - - pushletClient.listen(this, PUSH_MODE); - p("Listening in mode=" + PUSH_MODE); - - pushletClient.subscribe(subject); - p("Subscribed to=" + subject); - } catch (PushletException pe) { - p("Error exception=" + pe); - bailout(); - } - } - - public void stop() { - dbg("stop()"); - bailout(); - } - - /** Abort event from server. */ - public void onAbort(Event theEvent) { - p(theEvent.toXML()); - bailout(); - } - - /** Data event from server. */ - public void onData(Event theEvent) { - p(theEvent.toXML()); - } - - /** Heartbeat event from server. */ - public void onHeartbeat(Event theEvent) { - p(theEvent.toXML()); - } - - /** Error occurred. */ - public void onError(String message) { - p(message); - bailout(); - } - - private void bailout() { - if (pushletClient != null) { - p("Stopping PushletClient"); - try { - pushletClient.leave(); - } catch (PushletException ignore) { - p("Error during leave pe=" + ignore); - - } - pushletClient = null; - } - } - - /** Generic print. */ - private void p(String s) { - dbg("event: " + s); - synchronized (textArea) { - textArea.append(s + "\n"); - } - } - - /** Generic print. */ - private void dbg(String s) { - System.out.println("[PushletApplet] " + s); - } -} - -/* +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.test; + +import nl.justobjects.pushlet.client.PushletClient; +import nl.justobjects.pushlet.client.PushletClientListener; +import nl.justobjects.pushlet.core.Event; +import nl.justobjects.pushlet.core.Protocol; +import nl.justobjects.pushlet.util.PushletException; + +import java.applet.Applet; +import java.awt.*; + +/** + * Tester for applet clients; displays incoming events in text area. + * + * @version $Id: PushletApplet.java,v 1.16 2005/02/18 09:54:15 justb Exp $ + * @author Just van den Broecke - Just Objects © + **/ +public class PushletApplet extends Applet implements PushletClientListener, Protocol { + private TextArea textArea; + private String host = "localhost"; + private int port = 8080; + private String subject; + private PushletClient pushletClient; + private String VERSION = "15.feb.05 #5"; + private String PUSH_MODE = Protocol.MODE_PULL; + + /** One-time setup. */ + public void init() { + // Subject to subscribe to + subject = getParameter(P_SUBJECT); + + host = getDocumentBase().getHost(); + port = getDocumentBase().getPort(); + + // Hmm sometimes this value is -1...(Mozilla with Java 1.3.0 on Win) + if (port == -1) { + port = 80; + } + + setLayout(new GridLayout(1, 1)); + textArea = new TextArea(15, 40); + textArea.setForeground(Color.yellow); + textArea.setBackground(Color.gray); + textArea.setEditable(false); + add(textArea); + p("PushletApplet - " + VERSION); + } + + public void start() { + dbg("start()"); + bailout(); + + try { + pushletClient = new PushletClient(host, port); + p("Created PushletClient"); + + pushletClient.join(); + p("Joined server"); + + pushletClient.listen(this, PUSH_MODE); + p("Listening in mode=" + PUSH_MODE); + + pushletClient.subscribe(subject); + p("Subscribed to=" + subject); + } catch (PushletException pe) { + p("Error exception=" + pe); + bailout(); + } + } + + public void stop() { + dbg("stop()"); + bailout(); + } + + /** Abort event from server. */ + public void onAbort(Event theEvent) { + p(theEvent.toXML()); + bailout(); + } + + /** Data event from server. */ + public void onData(Event theEvent) { + p(theEvent.toXML()); + } + + /** Heartbeat event from server. */ + public void onHeartbeat(Event theEvent) { + p(theEvent.toXML()); + } + + /** Error occurred. */ + public void onError(String message) { + p(message); + bailout(); + } + + private void bailout() { + if (pushletClient != null) { + p("Stopping PushletClient"); + try { + pushletClient.leave(); + } catch (PushletException ignore) { + p("Error during leave pe=" + ignore); + + } + pushletClient = null; + } + } + + /** Generic print. */ + private void p(String s) { + dbg("event: " + s); + synchronized (textArea) { + textArea.append(s + "\n"); + } + } + + /** Generic print. */ + private void dbg(String s) { + System.out.println("[PushletApplet] " + s); + } +} + +/* * $Log: PushletApplet.java,v $ * Revision 1.16 2005/02/18 09:54:15 justb * refactor: rename Publisher Dispatcher and single Subscriber class - * - * Revision 1.15 2005/02/15 15:46:36 justb - * client API improves - * - * Revision 1.14 2005/02/15 13:28:33 justb - * use new PushletClient lib - * - * Revision 1.13 2004/10/25 21:22:26 justb - * *** empty log message *** - * - * Revision 1.12 2004/10/24 13:52:52 justb - * small fixes in client lib - * - * Revision 1.11 2004/10/24 12:58:19 justb - * revised client and test classes for new protocol - * - * Revision 1.10 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.9 2004/08/12 13:18:54 justb - * cosmetic changes - * - * Revision 1.8 2003/08/17 21:06:37 justb - * version info change - * - * Revision 1.7 2003/08/15 08:37:41 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.6 2003/08/14 21:43:10 justb - * improved Java client lifecycle; notably stopping listener thread - * - * Revision 1.5 2003/08/13 14:00:00 justb - * some testing for applets; no real change - * - * Revision 1.4 2003/05/19 22:53:33 justb - * more fixes for applets - * - * Revision 1.3 2003/05/19 21:56:29 justb - * various fixes for applet clients - * - * Revision 1.2 2003/05/18 16:15:08 justb - * support for XML encoded Events - * - * Revision 1.1.1.1 2002/09/24 21:02:33 justb - * import to sourceforge - * - */ + * + * Revision 1.15 2005/02/15 15:46:36 justb + * client API improves + * + * Revision 1.14 2005/02/15 13:28:33 justb + * use new PushletClient lib + * + * Revision 1.13 2004/10/25 21:22:26 justb + * *** empty log message *** + * + * Revision 1.12 2004/10/24 13:52:52 justb + * small fixes in client lib + * + * Revision 1.11 2004/10/24 12:58:19 justb + * revised client and test classes for new protocol + * + * Revision 1.10 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.9 2004/08/12 13:18:54 justb + * cosmetic changes + * + * Revision 1.8 2003/08/17 21:06:37 justb + * version info change + * + * Revision 1.7 2003/08/15 08:37:41 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.6 2003/08/14 21:43:10 justb + * improved Java client lifecycle; notably stopping listener thread + * + * Revision 1.5 2003/08/13 14:00:00 justb + * some testing for applets; no real change + * + * Revision 1.4 2003/05/19 22:53:33 justb + * more fixes for applets + * + * Revision 1.3 2003/05/19 21:56:29 justb + * various fixes for applet clients + * + * Revision 1.2 2003/05/18 16:15:08 justb + * support for XML encoded Events + * + * Revision 1.1.1.1 2002/09/24 21:02:33 justb + * import to sourceforge + * + */ diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/test/PushletPingApplication.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/test/PushletPingApplication.java index 72f3dff0d9..eb47610715 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/test/PushletPingApplication.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/test/PushletPingApplication.java @@ -1,179 +1,179 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.test; - -import nl.justobjects.pushlet.client.PushletClient; -import nl.justobjects.pushlet.client.PushletClientListener; -import nl.justobjects.pushlet.core.Event; -import nl.justobjects.pushlet.core.Protocol; -import nl.justobjects.pushlet.util.PushletException; - -import java.util.HashMap; -import java.util.Map; - -/** - * Tester to demonstrate Pushlet use in Java applications. - * - * This program does two things: - * (1) it subscribes to the subject "test/ping" - * (2) it publishes an Event with subject "/test/ping" every few seconds. - * - * @version $Id: PushletPingApplication.java,v 1.15 2005/02/21 16:59:17 justb Exp $ - * @author Just van den Broecke - Just Objects © - **/ -public class PushletPingApplication extends Thread implements PushletClientListener, Protocol { - private PushletClient pushletClient; - private String host; - private int port; - private static final String SUBJECT = "/test/ping"; - private static final long PUBLISH_INTERVAL_MILLIS = 3000; - - public PushletPingApplication(String aHost, int aPort) { - host = aHost; - port = aPort; - } - - public void run() { - // Create and start a Pushlet client; we receive callbacks - // through onHeartbeat() and onData(). - try { - pushletClient = new PushletClient(host, port); - pushletClient.setDebug(true); - pushletClient.join(); - pushletClient.listen(this, Protocol.MODE_STREAM); - - // Test subscribe/unsubscribe - String subscriptionId = pushletClient.subscribe(SUBJECT); - pushletClient.unsubscribe(subscriptionId); - - // The real subscribe - pushletClient.subscribe(SUBJECT); - p("pushletClient started"); - } catch (PushletException pe) { - p("Error in setting up pushlet session pe=" + pe); - return; - } - - // Publish an event to the server every N seconds. - Map eventData = new HashMap(2); - int seqNr = 1; - while (true) { - try { - // Create event data - eventData.put("seqNr", "" + seqNr++); - eventData.put("time", "" + System.currentTimeMillis()); - - // POST event to pushlet server - pushletClient.publish(SUBJECT, eventData); - - p("published ping # " + (seqNr - 1) + " - sleeping..."); - Thread.sleep(PUBLISH_INTERVAL_MILLIS); - } catch (Exception e) { - p("Postlet exception: " + e); - System.exit(-1); - } - } - } - - /** Error occurred. */ - public void onError(String message) { - p(message); - } - - /** Abort event from server. */ - public void onAbort(Event theEvent) { - p("onAbort received: " + theEvent); - } - - /** Data event from server. */ - public void onData(Event theEvent) { - // Calculate round trip delay - long then = Long.parseLong(theEvent.getField("time")); - long delay = System.currentTimeMillis() - then; - p("onData: ping #" + theEvent.getField("seqNr") + " in " + delay + " ms"); - } - - /** Heartbeat event from server. */ - public void onHeartbeat(Event theEvent) { - p("onHeartbeat received: " + theEvent); - } - - /** Generic print. */ - public void p(String s) { - System.out.println("[PushletPing] " + s); - } - - /** Main program. */ - public static void main(String args[]) { - for (int i = 0; i < 1; i++) { - if (args.length == 0) { - new PushletPingApplication("localhost", 8080).start(); - } else { - // Supply a host and port - new PushletPingApplication(args[0], Integer.parseInt(args[1])).start(); - } - } - - } -} - - -/* +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.test; + +import nl.justobjects.pushlet.client.PushletClient; +import nl.justobjects.pushlet.client.PushletClientListener; +import nl.justobjects.pushlet.core.Event; +import nl.justobjects.pushlet.core.Protocol; +import nl.justobjects.pushlet.util.PushletException; + +import java.util.HashMap; +import java.util.Map; + +/** + * Tester to demonstrate Pushlet use in Java applications. + * + * This program does two things: + * (1) it subscribes to the subject "test/ping" + * (2) it publishes an Event with subject "/test/ping" every few seconds. + * + * @version $Id: PushletPingApplication.java,v 1.15 2005/02/21 16:59:17 justb Exp $ + * @author Just van den Broecke - Just Objects © + **/ +public class PushletPingApplication extends Thread implements PushletClientListener, Protocol { + private PushletClient pushletClient; + private String host; + private int port; + private static final String SUBJECT = "/test/ping"; + private static final long PUBLISH_INTERVAL_MILLIS = 3000; + + public PushletPingApplication(String aHost, int aPort) { + host = aHost; + port = aPort; + } + + public void run() { + // Create and start a Pushlet client; we receive callbacks + // through onHeartbeat() and onData(). + try { + pushletClient = new PushletClient(host, port); + pushletClient.setDebug(true); + pushletClient.join(); + pushletClient.listen(this, Protocol.MODE_STREAM); + + // Test subscribe/unsubscribe + String subscriptionId = pushletClient.subscribe(SUBJECT); + pushletClient.unsubscribe(subscriptionId); + + // The real subscribe + pushletClient.subscribe(SUBJECT); + p("pushletClient started"); + } catch (PushletException pe) { + p("Error in setting up pushlet session pe=" + pe); + return; + } + + // Publish an event to the server every N seconds. + Map eventData = new HashMap(2); + int seqNr = 1; + while (true) { + try { + // Create event data + eventData.put("seqNr", "" + seqNr++); + eventData.put("time", "" + System.currentTimeMillis()); + + // POST event to pushlet server + pushletClient.publish(SUBJECT, eventData); + + p("published ping # " + (seqNr - 1) + " - sleeping..."); + Thread.sleep(PUBLISH_INTERVAL_MILLIS); + } catch (Exception e) { + p("Postlet exception: " + e); + System.exit(-1); + } + } + } + + /** Error occurred. */ + public void onError(String message) { + p(message); + } + + /** Abort event from server. */ + public void onAbort(Event theEvent) { + p("onAbort received: " + theEvent); + } + + /** Data event from server. */ + public void onData(Event theEvent) { + // Calculate round trip delay + long then = Long.parseLong(theEvent.getField("time")); + long delay = System.currentTimeMillis() - then; + p("onData: ping #" + theEvent.getField("seqNr") + " in " + delay + " ms"); + } + + /** Heartbeat event from server. */ + public void onHeartbeat(Event theEvent) { + p("onHeartbeat received: " + theEvent); + } + + /** Generic print. */ + public void p(String s) { + System.out.println("[PushletPing] " + s); + } + + /** Main program. */ + public static void main(String args[]) { + for (int i = 0; i < 1; i++) { + if (args.length == 0) { + new PushletPingApplication("localhost", 8080).start(); + } else { + // Supply a host and port + new PushletPingApplication(args[0], Integer.parseInt(args[1])).start(); + } + } + + } +} + + +/* * $Log: PushletPingApplication.java,v $ * Revision 1.15 2005/02/21 16:59:17 justb * SessionManager and session lease introduced - * - * Revision 1.14 2005/02/21 11:50:48 justb - * ohase1 of refactoring Subscriber into Session/Controller/Subscriber - * - * Revision 1.13 2005/02/20 13:05:33 justb - * removed the Postlet (integrated in Pushlet protocol) - * - * Revision 1.12 2005/02/18 09:54:15 justb - * refactor: rename Publisher Dispatcher and single Subscriber class - * - * Revision 1.11 2005/02/15 15:46:37 justb - * client API improves - * - * Revision 1.10 2005/02/15 13:28:08 justb - * use new protocol lib and publish with PushletClient - * - * Revision 1.9 2004/10/24 13:52:52 justb - * small fixes in client lib - * - * Revision 1.8 2004/10/24 12:58:19 justb - * revised client and test classes for new protocol - * - * Revision 1.7 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.6 2004/08/12 13:18:54 justb - * cosmetic changes - * - * Revision 1.5 2004/03/10 14:53:10 justb - * new - * - * Revision 1.4 2003/08/17 20:30:20 justb - * cosmetic changes - * - * Revision 1.3 2003/08/15 08:37:41 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.2 2003/05/18 16:15:08 justb - * support for XML encoded Events - * - * Revision 1.1.1.1 2002/09/24 21:02:33 justb - * import to sourceforge - * - * Revision 1.1.1.1 2002/09/20 22:48:19 justb - * import to SF - * - * Revision 1.1.1.1 2002/09/20 14:19:02 justb - * first import into SF - * - * Revision 1.3 2000/08/31 12:49:50 just - * added CVS comment tags for log and copyright - * - * - */ + * + * Revision 1.14 2005/02/21 11:50:48 justb + * ohase1 of refactoring Subscriber into Session/Controller/Subscriber + * + * Revision 1.13 2005/02/20 13:05:33 justb + * removed the Postlet (integrated in Pushlet protocol) + * + * Revision 1.12 2005/02/18 09:54:15 justb + * refactor: rename Publisher Dispatcher and single Subscriber class + * + * Revision 1.11 2005/02/15 15:46:37 justb + * client API improves + * + * Revision 1.10 2005/02/15 13:28:08 justb + * use new protocol lib and publish with PushletClient + * + * Revision 1.9 2004/10/24 13:52:52 justb + * small fixes in client lib + * + * Revision 1.8 2004/10/24 12:58:19 justb + * revised client and test classes for new protocol + * + * Revision 1.7 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.6 2004/08/12 13:18:54 justb + * cosmetic changes + * + * Revision 1.5 2004/03/10 14:53:10 justb + * new + * + * Revision 1.4 2003/08/17 20:30:20 justb + * cosmetic changes + * + * Revision 1.3 2003/08/15 08:37:41 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.2 2003/05/18 16:15:08 justb + * support for XML encoded Events + * + * Revision 1.1.1.1 2002/09/24 21:02:33 justb + * import to sourceforge + * + * Revision 1.1.1.1 2002/09/20 22:48:19 justb + * import to SF + * + * Revision 1.1.1.1 2002/09/20 14:19:02 justb + * first import into SF + * + * Revision 1.3 2000/08/31 12:49:50 just + * added CVS comment tags for log and copyright + * + * + */ diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/test/TestEventPullSources.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/test/TestEventPullSources.java index 319c95550d..d9b4d7774e 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/test/TestEventPullSources.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/test/TestEventPullSources.java @@ -1,273 +1,273 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.test; - -import nl.justobjects.pushlet.core.Event; -import nl.justobjects.pushlet.core.EventPullSource; -import nl.justobjects.pushlet.core.SessionManager; -import nl.justobjects.pushlet.util.Rand; - - -/** - * Event sources for testing. - * - * @author Just van den Broecke - Just Objects © - * @version $Id: TestEventPullSources.java,v 1.10 2007/11/09 13:16:57 justb Exp $ - */ -public class TestEventPullSources { - - /** - * Produces a fake temparature event. - */ - static public class TemperatureEventPullSource extends EventPullSource { - String[] cities = {"amsterdam", null, "rotterdam", null, - "leeuwarden", null, "twente", null, "limburg", null}; - - public long getSleepTime() { - return Rand.randomLong(3000, 5000); - } - - public Event pullEvent() { - int cityNumber = Rand.randomInt(0, (cities.length) / 2 - 1); - int nextCityIndex = 2 * cityNumber; - - Event event = Event.createDataEvent("/temperature"); - - event.setField("number", "" + cityNumber); - event.setField("city", cities[nextCityIndex]); - if (cities[nextCityIndex + 1] == null) { - cities[nextCityIndex + 1] = "" + Rand.randomInt(5, 10); - } - int currentCityValue = new Integer(cities[nextCityIndex + 1]).intValue(); - int newCityValue = currentCityValue + Rand.randomInt(-2, 2); - - event.setField("value", "" + newCityValue); - return event; - } - } - - /** - * Produces a ping event. - */ - static public class PingEventPullSource extends EventPullSource { - public long getSleepTime() { - return 3000; - } - - public Event pullEvent() { - - return Event.createDataEvent("/pushlet/ping"); - } - } - - /** - * Produces an event related to the JVM status. - */ - static public class SystemStatusEventPullSource extends EventPullSource { - Runtime runtime = Runtime.getRuntime(); - - public long getSleepTime() { - return 4000; - } - - public Event pullEvent() { - Event event = Event.createDataEvent("/system/jvm"); - event.setField("totalMemory", "" + runtime.totalMemory()); - event.setField("freeMemory", "" + runtime.freeMemory()); - event.setField("maxMemory", "" + runtime.maxMemory()); - int activeCount = Thread.activeCount(); - event.setField("threads", "" + activeCount); - - return event; - } - } - - /** - * Produces an event related to the Dispatcher.getInstance(). status. - */ - static public class PushletStatusEventPullSource extends EventPullSource { - - public long getSleepTime() { - return 5000; - } - - public Event pullEvent() { - Event event = Event.createDataEvent("/system/pushlet"); - // p(Dispatcher.getStatus()); - event.setField("publisher", "" + SessionManager.getInstance().getStatus()); - return event; - } - } - - - /** - * Produces events simulating stocks from the AEX. - */ - static public class AEXStocksEventPullSource extends EventPullSource { - - String[] stocks = {"abn amro", "26", - "aegon", "38", - "ahold", "34", - "akzo nobel", "51", - "asm lith h", "26", - "corus plc", "2", - "dsm", "40", - "elsevier", "14", - "fortis (nl)", "32", - "getronics", "6", - "gucci", "94", - "hagemeyer", "25", - "heineken", "61", - "ing c", "78", - "klm", "66", - "kon olie", "66", - "kpn", "13", - "numico c", "44", - "philips, kon", "38", - "tnt", "26", - "unilever c", "62", - "vendex kbb", "16", - "vnu", "49", - "wolt-kluw c", "25"}; - - public long getSleepTime() { - return Rand.randomLong(2000, 4000); - } - - public Event pullEvent() { - Event event = Event.createDataEvent("/stocks/aex"); - int stockNumber = Rand.randomInt(0, (stocks.length) / 2 - 1); - int nextStockIndex = 2 * stockNumber; - - event.setField("number", "" + stockNumber); - event.setField("name", stocks[nextStockIndex]); - if (stocks[nextStockIndex + 1] == null) { - stocks[nextStockIndex + 1] = "" + Rand.randomInt(50, 150); - } - int currentStockValue = new Integer(stocks[nextStockIndex + 1]).intValue(); - int newStockValue = currentStockValue + Rand.randomInt(-2, 2); - - event.setField("rate", "" + newStockValue + "." + Rand.randomInt(0, 99)); - return event; - } - - } - - /** - * Produces an URL event for automatic webpresentation. - */ - static public class WebPresentationEventPullSource extends EventPullSource { - String slideRootDir = "http://www.justobjects.org/cowcatcher/browse/j2ee/slides/"; - String[] slideURLs = { - "ejb/j2ee/ejbover/slide.0.0.html", - "ejb/j2ee/ejbover/slide.0.1.html", - "ejb/j2ee/ejbover/slide.0.2.html", - "ejb/j2ee/ejbover/slide.0.3.html", - "ejb/j2ee/ejbover/slide.0.4.html" - }; - - int nextSlideNumber = 0; - - public long getSleepTime() { - return 5000; - } - - public Event pullEvent() { - Event event = Event.createDataEvent("/webpres/auto"); - event.setField("url", slideRootDir + slideURLs[nextSlideNumber++]); - if (nextSlideNumber == slideURLs.length) { - nextSlideNumber = 0; - } - // Log.debug("Sending next slide url=" + event.getField("url")); - return event; - } - } - - /** - * Produces an event related to the Dispatcher.getInstance(). status. - */ - static public class TestEventPullSource extends EventPullSource { - private int number = 0; - - public long getSleepTime() { - return 2000; - } - - public Event pullEvent() { - Event event = Event.createDataEvent("/system/test"); - // p(Dispatcher.getInstance()..getStatus()); - event.setField("nr", "" + (number++)); - event.setField("time", "" + System.currentTimeMillis()); - return event; - } - - } - - /** - * Util: stderr print method. - */ - public static void e(String s) { - System.out.println(s); - } - - /** - * Util: stdout print method. - */ - public static void p(String s) { - // System.out.println(s); - } -} - -/* - * $Log: TestEventPullSources.java,v $ - * Revision 1.10 2007/11/09 13:16:57 justb - * use Rand from util package (and and Rand.java to pushlet client jar - * - * Revision 1.9 2005/02/28 09:14:56 justb - * sessmgr/dispatcher factory/singleton support - * - * Revision 1.8 2005/02/21 16:59:17 justb - * SessionManager and session lease introduced - * - * Revision 1.7 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.6 2005/02/18 09:54:15 justb - * refactor: rename Publisher Dispatcher.getInstance(). and single Subscriber class - * - * Revision 1.5 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.4 2003/12/03 21:16:58 justb - * *** empty log message *** - * - * Revision 1.3 2003/08/15 08:37:41 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.2 2003/05/18 16:15:08 justb - * support for XML encoded Events - * - * Revision 1.1.1.1 2002/09/24 21:02:33 justb - * import to sourceforge - * - * Revision 1.1.1.1 2002/09/20 22:48:19 justb - * import to SF - * - * Revision 1.1.1.1 2002/09/20 14:19:01 justb - * first import into SF - * - * Revision 1.6 2002/07/29 10:17:22 just - * no message - * - * Revision 1.5 2001/02/18 23:45:13 just - * fixes for AEX - * - * Revision 1.4 2000/10/30 14:16:09 just - * no message - * - * Revision 1.3 2000/08/31 12:49:50 just - * added CVS comment tags for log and copyright - * - * - */ +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.test; + +import nl.justobjects.pushlet.core.Event; +import nl.justobjects.pushlet.core.EventPullSource; +import nl.justobjects.pushlet.core.SessionManager; +import nl.justobjects.pushlet.util.Rand; + + +/** + * Event sources for testing. + * + * @author Just van den Broecke - Just Objects © + * @version $Id: TestEventPullSources.java,v 1.10 2007/11/09 13:16:57 justb Exp $ + */ +public class TestEventPullSources { + + /** + * Produces a fake temparature event. + */ + static public class TemperatureEventPullSource extends EventPullSource { + String[] cities = {"amsterdam", null, "rotterdam", null, + "leeuwarden", null, "twente", null, "limburg", null}; + + public long getSleepTime() { + return Rand.randomLong(3000, 5000); + } + + public Event pullEvent() { + int cityNumber = Rand.randomInt(0, (cities.length) / 2 - 1); + int nextCityIndex = 2 * cityNumber; + + Event event = Event.createDataEvent("/temperature"); + + event.setField("number", "" + cityNumber); + event.setField("city", cities[nextCityIndex]); + if (cities[nextCityIndex + 1] == null) { + cities[nextCityIndex + 1] = "" + Rand.randomInt(5, 10); + } + int currentCityValue = new Integer(cities[nextCityIndex + 1]).intValue(); + int newCityValue = currentCityValue + Rand.randomInt(-2, 2); + + event.setField("value", "" + newCityValue); + return event; + } + } + + /** + * Produces a ping event. + */ + static public class PingEventPullSource extends EventPullSource { + public long getSleepTime() { + return 3000; + } + + public Event pullEvent() { + + return Event.createDataEvent("/pushlet/ping"); + } + } + + /** + * Produces an event related to the JVM status. + */ + static public class SystemStatusEventPullSource extends EventPullSource { + Runtime runtime = Runtime.getRuntime(); + + public long getSleepTime() { + return 4000; + } + + public Event pullEvent() { + Event event = Event.createDataEvent("/system/jvm"); + event.setField("totalMemory", "" + runtime.totalMemory()); + event.setField("freeMemory", "" + runtime.freeMemory()); + event.setField("maxMemory", "" + runtime.maxMemory()); + int activeCount = Thread.activeCount(); + event.setField("threads", "" + activeCount); + + return event; + } + } + + /** + * Produces an event related to the Dispatcher.getInstance(). status. + */ + static public class PushletStatusEventPullSource extends EventPullSource { + + public long getSleepTime() { + return 5000; + } + + public Event pullEvent() { + Event event = Event.createDataEvent("/system/pushlet"); + // p(Dispatcher.getStatus()); + event.setField("publisher", "" + SessionManager.getInstance().getStatus()); + return event; + } + } + + + /** + * Produces events simulating stocks from the AEX. + */ + static public class AEXStocksEventPullSource extends EventPullSource { + + String[] stocks = {"abn amro", "26", + "aegon", "38", + "ahold", "34", + "akzo nobel", "51", + "asm lith h", "26", + "corus plc", "2", + "dsm", "40", + "elsevier", "14", + "fortis (nl)", "32", + "getronics", "6", + "gucci", "94", + "hagemeyer", "25", + "heineken", "61", + "ing c", "78", + "klm", "66", + "kon olie", "66", + "kpn", "13", + "numico c", "44", + "philips, kon", "38", + "tnt", "26", + "unilever c", "62", + "vendex kbb", "16", + "vnu", "49", + "wolt-kluw c", "25"}; + + public long getSleepTime() { + return Rand.randomLong(2000, 4000); + } + + public Event pullEvent() { + Event event = Event.createDataEvent("/stocks/aex"); + int stockNumber = Rand.randomInt(0, (stocks.length) / 2 - 1); + int nextStockIndex = 2 * stockNumber; + + event.setField("number", "" + stockNumber); + event.setField("name", stocks[nextStockIndex]); + if (stocks[nextStockIndex + 1] == null) { + stocks[nextStockIndex + 1] = "" + Rand.randomInt(50, 150); + } + int currentStockValue = new Integer(stocks[nextStockIndex + 1]).intValue(); + int newStockValue = currentStockValue + Rand.randomInt(-2, 2); + + event.setField("rate", "" + newStockValue + "." + Rand.randomInt(0, 99)); + return event; + } + + } + + /** + * Produces an URL event for automatic webpresentation. + */ + static public class WebPresentationEventPullSource extends EventPullSource { + String slideRootDir = "http://www.justobjects.org/cowcatcher/browse/j2ee/slides/"; + String[] slideURLs = { + "ejb/j2ee/ejbover/slide.0.0.html", + "ejb/j2ee/ejbover/slide.0.1.html", + "ejb/j2ee/ejbover/slide.0.2.html", + "ejb/j2ee/ejbover/slide.0.3.html", + "ejb/j2ee/ejbover/slide.0.4.html" + }; + + int nextSlideNumber = 0; + + public long getSleepTime() { + return 5000; + } + + public Event pullEvent() { + Event event = Event.createDataEvent("/webpres/auto"); + event.setField("url", slideRootDir + slideURLs[nextSlideNumber++]); + if (nextSlideNumber == slideURLs.length) { + nextSlideNumber = 0; + } + // Log.debug("Sending next slide url=" + event.getField("url")); + return event; + } + } + + /** + * Produces an event related to the Dispatcher.getInstance(). status. + */ + static public class TestEventPullSource extends EventPullSource { + private int number = 0; + + public long getSleepTime() { + return 2000; + } + + public Event pullEvent() { + Event event = Event.createDataEvent("/system/test"); + // p(Dispatcher.getInstance()..getStatus()); + event.setField("nr", "" + (number++)); + event.setField("time", "" + System.currentTimeMillis()); + return event; + } + + } + + /** + * Util: stderr print method. + */ + public static void e(String s) { + System.out.println(s); + } + + /** + * Util: stdout print method. + */ + public static void p(String s) { + // System.out.println(s); + } +} + +/* + * $Log: TestEventPullSources.java,v $ + * Revision 1.10 2007/11/09 13:16:57 justb + * use Rand from util package (and and Rand.java to pushlet client jar + * + * Revision 1.9 2005/02/28 09:14:56 justb + * sessmgr/dispatcher factory/singleton support + * + * Revision 1.8 2005/02/21 16:59:17 justb + * SessionManager and session lease introduced + * + * Revision 1.7 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.6 2005/02/18 09:54:15 justb + * refactor: rename Publisher Dispatcher.getInstance(). and single Subscriber class + * + * Revision 1.5 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.4 2003/12/03 21:16:58 justb + * *** empty log message *** + * + * Revision 1.3 2003/08/15 08:37:41 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.2 2003/05/18 16:15:08 justb + * support for XML encoded Events + * + * Revision 1.1.1.1 2002/09/24 21:02:33 justb + * import to sourceforge + * + * Revision 1.1.1.1 2002/09/20 22:48:19 justb + * import to SF + * + * Revision 1.1.1.1 2002/09/20 14:19:01 justb + * first import into SF + * + * Revision 1.6 2002/07/29 10:17:22 just + * no message + * + * Revision 1.5 2001/02/18 23:45:13 just + * fixes for AEX + * + * Revision 1.4 2000/10/30 14:16:09 just + * no message + * + * Revision 1.3 2000/08/31 12:49:50 just + * added CVS comment tags for log and copyright + * + * + */ diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/test/TestEventPushSources.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/test/TestEventPushSources.java index 2130dd82a8..ba52d29c8f 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/test/TestEventPushSources.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/test/TestEventPushSources.java @@ -1,336 +1,336 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.test; - -import nl.justobjects.pushlet.core.Dispatcher; -import nl.justobjects.pushlet.core.Event; -import nl.justobjects.pushlet.core.EventSource; -import nl.justobjects.pushlet.util.Rand; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.URL; -import java.util.StringTokenizer; -import java.util.Vector; - -/** - * Event sources that push events (for testing). - * - * @author Just van den Broecke - Just Objects © - * @version $Id: TestEventPushSources.java,v 1.10 2007/11/09 13:16:57 justb Exp $ - */ -public class TestEventPushSources { - - static public class AEXStocksEventPushSourceABN { - String pageURL = "http://ri2.rois.com/E36msPtnZC0e15CVb4KT97JAGfGSfCcrvv6*FcyZIoNyh/CTIB/RI2APISNAP?RIC=0%23.AEX&FORMAT=XML"; - // This could be further expanded: getting the Reuters AEX stocks - // as XML from ABN with this URL, but we may get into legal problems... - } - - /** - * Produces events from REAL stocks from the AEX. - */ - static public class AEXStocksEventPushSource implements EventSource, Runnable { - /** - * Here we get our stocks from. - */ - String pageURL = "http://www.debeurs.nl/koersen/aex.asp"; - Thread thread = null; - volatile boolean active = false; - - // Since Baan has been thrown out... - public final static int NR_OF_STOCKS = 24; - - public final static String EMPTY = "wait..."; - private int restarts = 1; - - class Stock { - public String name = EMPTY; - public String rate = EMPTY; - volatile public boolean modified = false; - } - - Vector stocksCache = new Vector(NR_OF_STOCKS); - - public AEXStocksEventPushSource() { - for (int i = 0; i < NR_OF_STOCKS; i++) { - stocksCache.addElement(new Stock()); - } - // updateCache(); - } - - /** - * Activate the event source. - */ - synchronized public void activate() { - e("activating..."); - // Stop a possibly running thread - stopThread(); - - // Start new thread and - thread = new Thread(this, "AEXStocksPublisher-" + (restarts++)); - active = true; - thread.start(); - e("activated"); - } - - /** - * Deactivate the event source. - */ - synchronized public void passivate() { - e("passivating..."); - active = false; - stopThread(); - - // Mark the cache modified so we'll send the contents - // on the next activation. - for (int i = 0; i < NR_OF_STOCKS; i++) { - ((Stock) stocksCache.elementAt(i)).modified = true; - } - - e("passivated"); - } - - - /** - * Deactivate the event source. - */ - synchronized public void stop() { - } - - public void run() { - // Publish cache content (if any) first. - publishStocks(); - - int count = 5; // enforce update first - while (active) { - - // Only do work if active - // Update cache every 10 secs. - if (count == 5) { - updateCache(); - count = 0; - } - count++; - - // Do updates for changed stock rates - sendUpdates(); - - // If we were interrupted just return. - if (thread == null || thread.isInterrupted()) { - break; - } - - // Sleep 2 secs before sending next updates - try { - thread.sleep(2000); - } catch (InterruptedException ie) { - break; - } - } - - // Loop terminated: reset vars - thread = null; - active = false; - } - - private String getStocksLine() { - BufferedReader br = null; - InputStream is = null; - String nextLine = ""; - - // Read line from server - try { - is = new URL(pageURL).openStream(); - br = new BufferedReader(new InputStreamReader(is)); - boolean foundLine = false; - while (!foundLine) { - nextLine = br.readLine(); - if (nextLine == null) { - return ""; - } - foundLine = (nextLine.indexOf("details.asp?iid=14053&parent=aex") != -1); - } - } catch (Exception e) { - e("could not open or read URL pageURL=" + pageURL + " ex=" + e); - return ""; - } finally { - try { - if (is != null) is.close(); - } catch (IOException ignore) { - } - } - return nextLine; - } - - private void publishStocks() { - // Publish only modified stocks from the cache - for (int i = 0; i < NR_OF_STOCKS; i++) { - Stock nextStock = (Stock) stocksCache.elementAt(i); - - // Publish modified stocks - if (nextStock.modified) { - publishStock(i, nextStock.name, nextStock.rate); - nextStock.modified = false; - try { - Thread.sleep(400); - } catch (InterruptedException ie) { - return; - } - } - } - } - - private void publishStock(int index, String name, String rate) { - Event event = Event.createDataEvent("/stocks/aex"); - event.setField("number", index + ""); - event.setField("name", name); - event.setField("rate", rate); - p("publish: nr=" + index + " name=" + name + " rate=" + rate); - Dispatcher.getInstance().multicast(event); - } - - private void sendUpdates() { - p("sending updates"); - // In any case send a random stock value by - // making it modified, just to see something moving... - int randomIndex = Rand.randomInt(0, NR_OF_STOCKS - 1); - Stock randomStock = (Stock) stocksCache.elementAt(randomIndex); - randomStock.modified = true; - - publishStocks(); - } - - private void stopThread() { - if (thread != null) { - thread.interrupt(); - thread = null; - } - } - - private void updateCache() { - p("updating Cache"); - - // Get the line with all stocks from HTML page - String stocksLine = getStocksLine(); - if ("".equals(stocksLine)) { - e("updateCache: stocksLine == null"); - return; - } - - // Parse the stocksline and put in cache. - // Beware: this is the messy part!! - // We assume that stock/names and rates are located at - // regular positions in the line. - String delim = "<>"; - StringTokenizer st = new StringTokenizer(stocksLine, delim); - String nextToken = ""; - int count = 0; - String nextStock = ""; - String nextQuote = ""; - String currentQuote = null; - int index = -1; - while (st.hasMoreTokens()) { - nextToken = st.nextToken(); - count++; - // The with the stock name - if ((count - 5) % 57 == 0) { - p("c=" + count + " s=" + nextToken); - nextStock = nextToken; - } - - // The with the stock rate - if ((count - 10) % 57 == 0) { - nextQuote = nextToken; - index++; - p("c=" + count + " val=" + nextQuote); - Stock currentStock = (Stock) stocksCache.elementAt(index); - - // Only update new or modified stocks - if (EMPTY.equals(currentStock.rate) || !currentStock.rate.equals(nextQuote)) { - p("modified: " + nextStock); - currentStock.name = nextStock; - currentStock.rate = nextQuote; - currentStock.modified = true; - } - } - } - } - } - - - /** - * Util: stderr print method. - */ - public static void e(String s) { - System.out.println("AEXStocksEventPushSource: " + s); - } - - /** - * Util: stdout print method. - */ - public static void p(String s) { - // System.out.println(s); - } - - - public static void main(String[] args) { - // new TestEventPushSources$AEXStocksEventPushSource(); - } -} - -/* - * $Log: TestEventPushSources.java,v $ - * Revision 1.10 2007/11/09 13:16:57 justb - * use Rand from util package (and and Rand.java to pushlet client jar - * - * Revision 1.9 2005/02/28 09:14:56 justb - * sessmgr/dispatcher factory/singleton support - * - * Revision 1.8 2005/02/21 16:59:17 justb - * SessionManager and session lease introduced - * - * Revision 1.7 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.6 2005/02/18 09:54:15 justb - * refactor: rename Publisher Dispatcher and single Subscriber class - * - * Revision 1.5 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.4 2004/03/10 15:45:55 justb - * many cosmetic changes - * - * Revision 1.3 2003/08/15 08:37:41 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.2 2003/05/18 16:15:08 justb - * support for XML encoded Events - * - * Revision 1.1.1.1 2002/09/24 21:02:33 justb - * import to sourceforge - * - * Revision 1.1.1.1 2002/09/20 22:48:20 justb - * import to SF - * - * Revision 1.1.1.1 2002/09/20 14:19:02 justb - * first import into SF - * - * Revision 1.6 2001/02/18 23:45:13 just - * fixes for AEX - * - * Revision 1.5 2000/10/30 14:16:09 just - * no message - * - * Revision 1.4 2000/09/24 21:02:43 just - * chnages due to changed webpage in debeurs.nl - * - * Revision 1.3 2000/08/31 12:49:50 just - * added CVS comment tags for log and copyright - * - * - */ +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.test; + +import nl.justobjects.pushlet.core.Dispatcher; +import nl.justobjects.pushlet.core.Event; +import nl.justobjects.pushlet.core.EventSource; +import nl.justobjects.pushlet.util.Rand; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.util.StringTokenizer; +import java.util.Vector; + +/** + * Event sources that push events (for testing). + * + * @author Just van den Broecke - Just Objects © + * @version $Id: TestEventPushSources.java,v 1.10 2007/11/09 13:16:57 justb Exp $ + */ +public class TestEventPushSources { + + static public class AEXStocksEventPushSourceABN { + String pageURL = "http://ri2.rois.com/E36msPtnZC0e15CVb4KT97JAGfGSfCcrvv6*FcyZIoNyh/CTIB/RI2APISNAP?RIC=0%23.AEX&FORMAT=XML"; + // This could be further expanded: getting the Reuters AEX stocks + // as XML from ABN with this URL, but we may get into legal problems... + } + + /** + * Produces events from REAL stocks from the AEX. + */ + static public class AEXStocksEventPushSource implements EventSource, Runnable { + /** + * Here we get our stocks from. + */ + String pageURL = "http://www.debeurs.nl/koersen/aex.asp"; + Thread thread = null; + volatile boolean active = false; + + // Since Baan has been thrown out... + public final static int NR_OF_STOCKS = 24; + + public final static String EMPTY = "wait..."; + private int restarts = 1; + + class Stock { + public String name = EMPTY; + public String rate = EMPTY; + volatile public boolean modified = false; + } + + Vector stocksCache = new Vector(NR_OF_STOCKS); + + public AEXStocksEventPushSource() { + for (int i = 0; i < NR_OF_STOCKS; i++) { + stocksCache.addElement(new Stock()); + } + // updateCache(); + } + + /** + * Activate the event source. + */ + synchronized public void activate() { + e("activating..."); + // Stop a possibly running thread + stopThread(); + + // Start new thread and + thread = new Thread(this, "AEXStocksPublisher-" + (restarts++)); + active = true; + thread.start(); + e("activated"); + } + + /** + * Deactivate the event source. + */ + synchronized public void passivate() { + e("passivating..."); + active = false; + stopThread(); + + // Mark the cache modified so we'll send the contents + // on the next activation. + for (int i = 0; i < NR_OF_STOCKS; i++) { + ((Stock) stocksCache.elementAt(i)).modified = true; + } + + e("passivated"); + } + + + /** + * Deactivate the event source. + */ + synchronized public void stop() { + } + + public void run() { + // Publish cache content (if any) first. + publishStocks(); + + int count = 5; // enforce update first + while (active) { + + // Only do work if active + // Update cache every 10 secs. + if (count == 5) { + updateCache(); + count = 0; + } + count++; + + // Do updates for changed stock rates + sendUpdates(); + + // If we were interrupted just return. + if (thread == null || thread.isInterrupted()) { + break; + } + + // Sleep 2 secs before sending next updates + try { + thread.sleep(2000); + } catch (InterruptedException ie) { + break; + } + } + + // Loop terminated: reset vars + thread = null; + active = false; + } + + private String getStocksLine() { + BufferedReader br = null; + InputStream is = null; + String nextLine = ""; + + // Read line from server + try { + is = new URL(pageURL).openStream(); + br = new BufferedReader(new InputStreamReader(is)); + boolean foundLine = false; + while (!foundLine) { + nextLine = br.readLine(); + if (nextLine == null) { + return ""; + } + foundLine = (nextLine.indexOf("details.asp?iid=14053&parent=aex") != -1); + } + } catch (Exception e) { + e("could not open or read URL pageURL=" + pageURL + " ex=" + e); + return ""; + } finally { + try { + if (is != null) is.close(); + } catch (IOException ignore) { + } + } + return nextLine; + } + + private void publishStocks() { + // Publish only modified stocks from the cache + for (int i = 0; i < NR_OF_STOCKS; i++) { + Stock nextStock = (Stock) stocksCache.elementAt(i); + + // Publish modified stocks + if (nextStock.modified) { + publishStock(i, nextStock.name, nextStock.rate); + nextStock.modified = false; + try { + Thread.sleep(400); + } catch (InterruptedException ie) { + return; + } + } + } + } + + private void publishStock(int index, String name, String rate) { + Event event = Event.createDataEvent("/stocks/aex"); + event.setField("number", index + ""); + event.setField("name", name); + event.setField("rate", rate); + p("publish: nr=" + index + " name=" + name + " rate=" + rate); + Dispatcher.getInstance().multicast(event); + } + + private void sendUpdates() { + p("sending updates"); + // In any case send a random stock value by + // making it modified, just to see something moving... + int randomIndex = Rand.randomInt(0, NR_OF_STOCKS - 1); + Stock randomStock = (Stock) stocksCache.elementAt(randomIndex); + randomStock.modified = true; + + publishStocks(); + } + + private void stopThread() { + if (thread != null) { + thread.interrupt(); + thread = null; + } + } + + private void updateCache() { + p("updating Cache"); + + // Get the line with all stocks from HTML page + String stocksLine = getStocksLine(); + if ("".equals(stocksLine)) { + e("updateCache: stocksLine == null"); + return; + } + + // Parse the stocksline and put in cache. + // Beware: this is the messy part!! + // We assume that stock/names and rates are located at + // regular positions in the line. + String delim = "<>"; + StringTokenizer st = new StringTokenizer(stocksLine, delim); + String nextToken = ""; + int count = 0; + String nextStock = ""; + String nextQuote = ""; + String currentQuote = null; + int index = -1; + while (st.hasMoreTokens()) { + nextToken = st.nextToken(); + count++; + // The with the stock name + if ((count - 5) % 57 == 0) { + p("c=" + count + " s=" + nextToken); + nextStock = nextToken; + } + + // The with the stock rate + if ((count - 10) % 57 == 0) { + nextQuote = nextToken; + index++; + p("c=" + count + " val=" + nextQuote); + Stock currentStock = (Stock) stocksCache.elementAt(index); + + // Only update new or modified stocks + if (EMPTY.equals(currentStock.rate) || !currentStock.rate.equals(nextQuote)) { + p("modified: " + nextStock); + currentStock.name = nextStock; + currentStock.rate = nextQuote; + currentStock.modified = true; + } + } + } + } + } + + + /** + * Util: stderr print method. + */ + public static void e(String s) { + System.out.println("AEXStocksEventPushSource: " + s); + } + + /** + * Util: stdout print method. + */ + public static void p(String s) { + // System.out.println(s); + } + + + public static void main(String[] args) { + // new TestEventPushSources$AEXStocksEventPushSource(); + } +} + +/* + * $Log: TestEventPushSources.java,v $ + * Revision 1.10 2007/11/09 13:16:57 justb + * use Rand from util package (and and Rand.java to pushlet client jar + * + * Revision 1.9 2005/02/28 09:14:56 justb + * sessmgr/dispatcher factory/singleton support + * + * Revision 1.8 2005/02/21 16:59:17 justb + * SessionManager and session lease introduced + * + * Revision 1.7 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.6 2005/02/18 09:54:15 justb + * refactor: rename Publisher Dispatcher and single Subscriber class + * + * Revision 1.5 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.4 2004/03/10 15:45:55 justb + * many cosmetic changes + * + * Revision 1.3 2003/08/15 08:37:41 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.2 2003/05/18 16:15:08 justb + * support for XML encoded Events + * + * Revision 1.1.1.1 2002/09/24 21:02:33 justb + * import to sourceforge + * + * Revision 1.1.1.1 2002/09/20 22:48:20 justb + * import to SF + * + * Revision 1.1.1.1 2002/09/20 14:19:02 justb + * first import into SF + * + * Revision 1.6 2001/02/18 23:45:13 just + * fixes for AEX + * + * Revision 1.5 2000/10/30 14:16:09 just + * no message + * + * Revision 1.4 2000/09/24 21:02:43 just + * chnages due to changed webpage in debeurs.nl + * + * Revision 1.3 2000/08/31 12:49:50 just + * added CVS comment tags for log and copyright + * + * + */ diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/util/DefaultLogger.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/util/DefaultLogger.java index bec2d94f34..bc0648c9a1 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/util/DefaultLogger.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/util/DefaultLogger.java @@ -1,164 +1,164 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.util; - -/** - * Default logger. - *

- * Logs to stdout. Override this class by setting "logger.class" in pushlet.properties to your own logger - * to integrate your own logging library. - * - * @author Just van den Broecke - * @version $Id: DefaultLogger.java,v 1.2 2007/12/07 12:57:40 justb Exp $ - */ -public class DefaultLogger implements PushletLogger { - - - /** - * Level intialized with default. - */ - private int level = LOG_LEVEL_INFO; - - public DefaultLogger() { - } - - public void init() { - - } - - /** - * Log message for trace level. - * - * @param aMessage the message to be logged - */ - public void trace(String aMessage) { - if (level < LOG_LEVEL_TRACE) { - return; - } - print("TRACE", aMessage); - } - - /** - * Log message for debug level. - * - * @param aMessage the message to be logged - */ - public void debug(String aMessage) { - if (level < LOG_LEVEL_DEBUG) { - return; - } - print("DEBUG", aMessage); - } - - /** - * Log message for info level. - * - * @param aMessage the message to be logged - */ - public void info(String aMessage) { - if (level < LOG_LEVEL_INFO) { - return; - } - print("INFO", aMessage); - } - - /** - * Log message for warning level. - * - * @param aMessage the message to be logged - */ - public void warn(String aMessage) { - if (level < LOG_LEVEL_WARN) { - return; - } - print("WARN", aMessage); - } - - /** - * Log message for warning level with exception. - * - * @param aMessage the message to be logged - * @param aThrowable the exception - */ - public void warn(String aMessage, Throwable aThrowable) { - warn(aMessage + " exception=" + aThrowable); - } - - /** - * Log message for error level. - * - * @param aMessage the message to be logged - */ - public void error(String aMessage) { - if (level < LOG_LEVEL_ERROR) { - return; - } - print("FATAL", aMessage); - } - - /** - * Log message (error level with exception). - * - * @param aMessage the message to be logged - * @param aThrowable the exception - */ - public void error(String aMessage, Throwable aThrowable) { - error(aMessage + " exception=" + aThrowable); - } - - /** - * Log message for fatal level. - * - * @param aMessage the message to be logged - */ - public void fatal(String aMessage) { - if (level < LOG_LEVEL_FATAL) { - return; - } - print("FATAL", aMessage); - } - - /** - * Log message (fatal level with exception). - * - * @param aMessage the message to be logged - * @param aThrowable the exception - */ - public void fatal(String aMessage, Throwable aThrowable) { - fatal(aMessage + " exception=" + aThrowable); - } - - /** - * Set log level - * - * @param aLevel the message to be logged - */ - public void setLevel(int aLevel) { - level = aLevel; - } - - /** - * Print message. - * - * @param aTag the log type - * @param aMessage the message to be logged - */ - private void print(String aTag, String aMessage) { - // SImple std out e.g. to catalina.out in Tomcat - System.out.println("Pushlet[" + aTag + "] " + aMessage); - } - -} - -/* -* $Log: DefaultLogger.java,v $ -* Revision 1.2 2007/12/07 12:57:40 justb -* added log4j and make it the default logging method -* -* Revision 1.1 2007/11/23 21:10:17 justb -* add hooks for custom logging (you can override DefaultLogger in pushlet.properties) -* -* -* +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.util; + +/** + * Default logger. + *

+ * Logs to stdout. Override this class by setting "logger.class" in pushlet.properties to your own logger + * to integrate your own logging library. + * + * @author Just van den Broecke + * @version $Id: DefaultLogger.java,v 1.2 2007/12/07 12:57:40 justb Exp $ + */ +public class DefaultLogger implements PushletLogger { + + + /** + * Level intialized with default. + */ + private int level = LOG_LEVEL_INFO; + + public DefaultLogger() { + } + + public void init() { + + } + + /** + * Log message for trace level. + * + * @param aMessage the message to be logged + */ + public void trace(String aMessage) { + if (level < LOG_LEVEL_TRACE) { + return; + } + print("TRACE", aMessage); + } + + /** + * Log message for debug level. + * + * @param aMessage the message to be logged + */ + public void debug(String aMessage) { + if (level < LOG_LEVEL_DEBUG) { + return; + } + print("DEBUG", aMessage); + } + + /** + * Log message for info level. + * + * @param aMessage the message to be logged + */ + public void info(String aMessage) { + if (level < LOG_LEVEL_INFO) { + return; + } + print("INFO", aMessage); + } + + /** + * Log message for warning level. + * + * @param aMessage the message to be logged + */ + public void warn(String aMessage) { + if (level < LOG_LEVEL_WARN) { + return; + } + print("WARN", aMessage); + } + + /** + * Log message for warning level with exception. + * + * @param aMessage the message to be logged + * @param aThrowable the exception + */ + public void warn(String aMessage, Throwable aThrowable) { + warn(aMessage + " exception=" + aThrowable); + } + + /** + * Log message for error level. + * + * @param aMessage the message to be logged + */ + public void error(String aMessage) { + if (level < LOG_LEVEL_ERROR) { + return; + } + print("FATAL", aMessage); + } + + /** + * Log message (error level with exception). + * + * @param aMessage the message to be logged + * @param aThrowable the exception + */ + public void error(String aMessage, Throwable aThrowable) { + error(aMessage + " exception=" + aThrowable); + } + + /** + * Log message for fatal level. + * + * @param aMessage the message to be logged + */ + public void fatal(String aMessage) { + if (level < LOG_LEVEL_FATAL) { + return; + } + print("FATAL", aMessage); + } + + /** + * Log message (fatal level with exception). + * + * @param aMessage the message to be logged + * @param aThrowable the exception + */ + public void fatal(String aMessage, Throwable aThrowable) { + fatal(aMessage + " exception=" + aThrowable); + } + + /** + * Set log level + * + * @param aLevel the message to be logged + */ + public void setLevel(int aLevel) { + level = aLevel; + } + + /** + * Print message. + * + * @param aTag the log type + * @param aMessage the message to be logged + */ + private void print(String aTag, String aMessage) { + // SImple std out e.g. to catalina.out in Tomcat + System.out.println("Pushlet[" + aTag + "] " + aMessage); + } + +} + +/* +* $Log: DefaultLogger.java,v $ +* Revision 1.2 2007/12/07 12:57:40 justb +* added log4j and make it the default logging method +* +* Revision 1.1 2007/11/23 21:10:17 justb +* add hooks for custom logging (you can override DefaultLogger in pushlet.properties) +* +* +* */ \ No newline at end of file diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/util/Log.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/util/Log.java index 3ce40153e7..ee6bd254d4 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/util/Log.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/util/Log.java @@ -1,178 +1,178 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.util; - -import nl.justobjects.pushlet.core.Config; -import nl.justobjects.pushlet.core.ConfigDefs; - -/** - * Logging wrapper. - *

- * Provides a hook to direct logging to your own logging library. Override the DefaultLogger class by setting - * "logger.class" in pushlet.properties to your own logger - * to integrate your own logging library. - * - * @author Just van den Broecke - * @version $Id: Log.java,v 1.5 2007/12/07 12:57:40 justb Exp $ - */ -public class Log implements ConfigDefs { - /** - * Init with default to have at least some logging. - */ - private static PushletLogger logger = new DefaultLogger(); - - /** - * General purpose initialization. - */ - static public void init() { - try { - logger = (PushletLogger) Config.getClass(LOGGER_CLASS, "nl.justobjects.pushlet.util.DefaultLogger").newInstance(); - } catch (Throwable t) { - // Hmmm cannot log this since we don't have a log... - System.out.println("Cannot instantiate Logger from config ex=" + t); - return; - } - - logger.init(); - - // Set log level - logger.setLevel(Config.getIntProperty(Config.LOG_LEVEL)); - - logger.info("Logging intialized logger class=" + logger.getClass()); - } - - /** - * Log message for trace level. - * - * @param aMessage the message to be logged - */ - static public void trace(String aMessage) { - logger.debug(aMessage); - } - - /** - * Log message for debug level. - * - * @param aMessage the message to be logged - */ - static public void debug(String aMessage) { - logger.debug(aMessage); - } - - /** - * Log message for info level. - * - * @param aMessage the message to be logged - */ - static public void info(String aMessage) { - logger.info(aMessage); - } - - /** - * Log message for warning level. - * - * @param aMessage the message to be logged - */ - static public void warn(String aMessage) { - logger.warn(aMessage); - } - - /** - * Log message for warning level with exception. - * - * @param aMessage the message to be logged - * @param aThrowable the exception - */ - static public void warn(String aMessage, Throwable aThrowable) { - logger.warn(aMessage, aThrowable); - } - - /** - * Log message for error level. - * - * @param aMessage the message to be logged - */ - static public void error(String aMessage) { - logger.error(aMessage); - } - - /** - * Log message (error level with exception). - * - * @param aMessage the message to be logged - * @param aThrowable the exception - */ - static public void error(String aMessage, Throwable aThrowable) { - logger.error(aMessage, aThrowable); - } - - /** - * Log message for fatal level. - * - * @param aMessage the message to be logged - */ - static public void fatal(String aMessage) { - logger.fatal(aMessage); - } - - /** - * Log message (fatal level with exception). - * - * @param aMessage the message to be logged - * @param aThrowable the exception - */ - static public void fatal(String aMessage, Throwable aThrowable) { - logger.fatal(aMessage, aThrowable); - } - - /** - * Set log level - * - * @param aLevel the message to be logged - */ - static public void setLevel(int aLevel) { - logger.setLevel(aLevel); - } -} - -/* -* $Log: Log.java,v $ -* Revision 1.5 2007/12/07 12:57:40 justb -* added log4j and make it the default logging method -* -* Revision 1.4 2007/11/23 21:29:43 justb -* add hooks for custom logging (you can override DefaultLogger in pushlet.properties) -* -* Revision 1.3 2007/11/23 21:10:17 justb -* add hooks for custom logging (you can override DefaultLogger in pushlet.properties) -* -* Revision 1.2 2005/02/21 11:15:59 justb -* support log levels -* -* Revision 1.1 2005/02/18 10:07:23 justb -* many renamings of classes (make names compact) -* -* Revision 1.7 2004/09/03 22:35:37 justb -* Almost complete rewrite, just checking in now -* -* Revision 1.6 2004/08/12 13:16:08 justb -* make debug flag false -* -* Revision 1.5 2004/03/10 14:01:55 justb -* formatting and *Subscriber refactoring -* -* Revision 1.4 2003/08/15 09:54:46 justb -* fix javadoc warnings -* -* Revision 1.3 2003/08/15 08:37:40 justb -* fix/add Copyright+LGPL file headers and footers -* -* Revision 1.2 2003/08/12 09:42:47 justb -* enhancements -* -* Revision 1.1 2003/08/12 08:46:00 justb -* cvs comment tags added -* -* +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.util; + +import nl.justobjects.pushlet.core.Config; +import nl.justobjects.pushlet.core.ConfigDefs; + +/** + * Logging wrapper. + *

+ * Provides a hook to direct logging to your own logging library. Override the DefaultLogger class by setting + * "logger.class" in pushlet.properties to your own logger + * to integrate your own logging library. + * + * @author Just van den Broecke + * @version $Id: Log.java,v 1.5 2007/12/07 12:57:40 justb Exp $ + */ +public class Log implements ConfigDefs { + /** + * Init with default to have at least some logging. + */ + private static PushletLogger logger = new DefaultLogger(); + + /** + * General purpose initialization. + */ + static public void init() { + try { + logger = (PushletLogger) Config.getClass(LOGGER_CLASS, "nl.justobjects.pushlet.util.DefaultLogger").newInstance(); + } catch (Throwable t) { + // Hmmm cannot log this since we don't have a log... + System.out.println("Cannot instantiate Logger from config ex=" + t); + return; + } + + logger.init(); + + // Set log level + logger.setLevel(Config.getIntProperty(Config.LOG_LEVEL)); + + logger.info("Logging intialized logger class=" + logger.getClass()); + } + + /** + * Log message for trace level. + * + * @param aMessage the message to be logged + */ + static public void trace(String aMessage) { + logger.debug(aMessage); + } + + /** + * Log message for debug level. + * + * @param aMessage the message to be logged + */ + static public void debug(String aMessage) { + logger.debug(aMessage); + } + + /** + * Log message for info level. + * + * @param aMessage the message to be logged + */ + static public void info(String aMessage) { + logger.info(aMessage); + } + + /** + * Log message for warning level. + * + * @param aMessage the message to be logged + */ + static public void warn(String aMessage) { + logger.warn(aMessage); + } + + /** + * Log message for warning level with exception. + * + * @param aMessage the message to be logged + * @param aThrowable the exception + */ + static public void warn(String aMessage, Throwable aThrowable) { + logger.warn(aMessage, aThrowable); + } + + /** + * Log message for error level. + * + * @param aMessage the message to be logged + */ + static public void error(String aMessage) { + logger.error(aMessage); + } + + /** + * Log message (error level with exception). + * + * @param aMessage the message to be logged + * @param aThrowable the exception + */ + static public void error(String aMessage, Throwable aThrowable) { + logger.error(aMessage, aThrowable); + } + + /** + * Log message for fatal level. + * + * @param aMessage the message to be logged + */ + static public void fatal(String aMessage) { + logger.fatal(aMessage); + } + + /** + * Log message (fatal level with exception). + * + * @param aMessage the message to be logged + * @param aThrowable the exception + */ + static public void fatal(String aMessage, Throwable aThrowable) { + logger.fatal(aMessage, aThrowable); + } + + /** + * Set log level + * + * @param aLevel the message to be logged + */ + static public void setLevel(int aLevel) { + logger.setLevel(aLevel); + } +} + +/* +* $Log: Log.java,v $ +* Revision 1.5 2007/12/07 12:57:40 justb +* added log4j and make it the default logging method +* +* Revision 1.4 2007/11/23 21:29:43 justb +* add hooks for custom logging (you can override DefaultLogger in pushlet.properties) +* +* Revision 1.3 2007/11/23 21:10:17 justb +* add hooks for custom logging (you can override DefaultLogger in pushlet.properties) +* +* Revision 1.2 2005/02/21 11:15:59 justb +* support log levels +* +* Revision 1.1 2005/02/18 10:07:23 justb +* many renamings of classes (make names compact) +* +* Revision 1.7 2004/09/03 22:35:37 justb +* Almost complete rewrite, just checking in now +* +* Revision 1.6 2004/08/12 13:16:08 justb +* make debug flag false +* +* Revision 1.5 2004/03/10 14:01:55 justb +* formatting and *Subscriber refactoring +* +* Revision 1.4 2003/08/15 09:54:46 justb +* fix javadoc warnings +* +* Revision 1.3 2003/08/15 08:37:40 justb +* fix/add Copyright+LGPL file headers and footers +* +* Revision 1.2 2003/08/12 09:42:47 justb +* enhancements +* +* Revision 1.1 2003/08/12 08:46:00 justb +* cvs comment tags added +* +* */ \ No newline at end of file diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/util/Log4jLogger.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/util/Log4jLogger.java index d7ee1df832..ca96762621 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/util/Log4jLogger.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/util/Log4jLogger.java @@ -1,134 +1,134 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.util; - -import org.apache.log4j.Level; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; - -/** - * Logger to use Log4j for logging. - *

- * Logs using Log4j. - * This class will require a log4j library in the classpath of the Pushlet. - * - * @author Uli Romahn - * @version $Id: Log4jLogger.java,v 1.1 2007/12/07 12:57:40 justb Exp $ - */ -public class Log4jLogger implements PushletLogger { - - /** - * Level intialized with default. - */ - private Logger logger = LogManager.getLogger("pushlet"); - - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#init() - */ - public void init() { - setLevel(LOG_LEVEL_INFO); - } - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#debug(java.lang.String) - */ - public void debug(String aMessage) { - if (!logger.isDebugEnabled()) { - return; - } - logger.debug(aMessage); - } - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#error(java.lang.String) - */ - public void error(String aMessage) { - logger.error(aMessage); - } - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#error(java.lang.String, java.lang.Throwable) - */ - public void error(String aMessage, Throwable aThrowable) { - logger.error(aMessage, aThrowable); - } - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#fatal(java.lang.String) - */ - public void fatal(String aMessage) { - logger.fatal(aMessage); - } - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#fatal(java.lang.String, java.lang.Throwable) - */ - public void fatal(String aMessage, Throwable aThrowable) { - logger.fatal(aMessage, aThrowable); - } - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#info(java.lang.String) - */ - public void info(String aMessage) { - if (!logger.isInfoEnabled()) { - return; - } - logger.info(aMessage); - } - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#trace(java.lang.String) - */ - public void trace(String aMessage) { - logger.trace(aMessage); - } - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#warn(java.lang.String) - */ - public void warn(String aMessage) { - logger.warn(aMessage); - } - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#warn(java.lang.String, java.lang.Throwable) - */ - public void warn(String aMessage, Throwable aThrowable) { - logger.warn(aMessage, aThrowable); - } - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#setLevel(int) - */ - public void setLevel(int aLevel) { - if (aLevel < LOG_LEVEL_FATAL) { - logger.setLevel(Level.OFF); - } else { - switch (aLevel) { - case LOG_LEVEL_FATAL: - logger.setLevel(Level.FATAL); - break; - case LOG_LEVEL_ERROR: - logger.setLevel(Level.ERROR); - break; - case LOG_LEVEL_WARN: - logger.setLevel(Level.WARN); - break; - case LOG_LEVEL_INFO: - logger.setLevel(Level.INFO); - break; - case LOG_LEVEL_DEBUG: - logger.setLevel(Level.DEBUG); - break; - case LOG_LEVEL_TRACE: - logger.setLevel(Level.TRACE); - break; - default: - logger.setLevel(Level.INFO); - } - } - } -} +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.util; + +import org.apache.log4j.Level; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; + +/** + * Logger to use Log4j for logging. + *

+ * Logs using Log4j. + * This class will require a log4j library in the classpath of the Pushlet. + * + * @author Uli Romahn + * @version $Id: Log4jLogger.java,v 1.1 2007/12/07 12:57:40 justb Exp $ + */ +public class Log4jLogger implements PushletLogger { + + /** + * Level intialized with default. + */ + private Logger logger = LogManager.getLogger("pushlet"); + + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#init() + */ + public void init() { + setLevel(LOG_LEVEL_INFO); + } + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#debug(java.lang.String) + */ + public void debug(String aMessage) { + if (!logger.isDebugEnabled()) { + return; + } + logger.debug(aMessage); + } + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#error(java.lang.String) + */ + public void error(String aMessage) { + logger.error(aMessage); + } + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#error(java.lang.String, java.lang.Throwable) + */ + public void error(String aMessage, Throwable aThrowable) { + logger.error(aMessage, aThrowable); + } + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#fatal(java.lang.String) + */ + public void fatal(String aMessage) { + logger.fatal(aMessage); + } + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#fatal(java.lang.String, java.lang.Throwable) + */ + public void fatal(String aMessage, Throwable aThrowable) { + logger.fatal(aMessage, aThrowable); + } + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#info(java.lang.String) + */ + public void info(String aMessage) { + if (!logger.isInfoEnabled()) { + return; + } + logger.info(aMessage); + } + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#trace(java.lang.String) + */ + public void trace(String aMessage) { + logger.trace(aMessage); + } + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#warn(java.lang.String) + */ + public void warn(String aMessage) { + logger.warn(aMessage); + } + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#warn(java.lang.String, java.lang.Throwable) + */ + public void warn(String aMessage, Throwable aThrowable) { + logger.warn(aMessage, aThrowable); + } + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#setLevel(int) + */ + public void setLevel(int aLevel) { + if (aLevel < LOG_LEVEL_FATAL) { + logger.setLevel(Level.OFF); + } else { + switch (aLevel) { + case LOG_LEVEL_FATAL: + logger.setLevel(Level.FATAL); + break; + case LOG_LEVEL_ERROR: + logger.setLevel(Level.ERROR); + break; + case LOG_LEVEL_WARN: + logger.setLevel(Level.WARN); + break; + case LOG_LEVEL_INFO: + logger.setLevel(Level.INFO); + break; + case LOG_LEVEL_DEBUG: + logger.setLevel(Level.DEBUG); + break; + case LOG_LEVEL_TRACE: + logger.setLevel(Level.TRACE); + break; + default: + logger.setLevel(Level.INFO); + } + } + } +} diff --git a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/util/PushletLogger.java b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/util/PushletLogger.java index c3853369ba..e70bc68703 100755 --- a/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/util/PushletLogger.java +++ b/sw/in_progress/pow/ServletPow/eclipse ServletPow/users/genin/pushlet-2.0.4/src/nl/justobjects/pushlet/util/PushletLogger.java @@ -1,94 +1,94 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.util; - -import nl.justobjects.pushlet.core.ConfigDefs; - -/** - * Logger interface to allow different logging providers. - *

- * - * @author Ulrich Romahn - * @version $Id: PushletLogger.java,v 1.1 2007/12/07 12:57:40 justb Exp $ - */ -public interface PushletLogger extends ConfigDefs { - - /** - * Method allowing to initialize our logger - */ - public void init(); - - /** - * Log message for trace level. - * - * @param aMessage the message to be logged - */ - public void trace(String aMessage); - - /** - * Log message for debug level. - * - * @param aMessage the message to be logged - */ - public void debug(String aMessage); - - /** - * Log message for info level. - * - * @param aMessage the message to be logged - */ - public void info(String aMessage); - - /** - * Log message for warning level. - * - * @param aMessage the message to be logged - */ - public void warn(String aMessage); - - /** - * Log message for warning level with exception. - * - * @param aMessage the message to be logged - * @param aThrowable the exception - */ - public void warn(String aMessage, Throwable aThrowable); - - /** - * Log message for error level. - * - * @param aMessage the message to be logged - */ - public void error(String aMessage); - - /** - * Log message (error level with exception). - * - * @param aMessage the message to be logged - * @param aThrowable the exception - */ - public void error(String aMessage, Throwable aThrowable); - - /** - * Log message for fatal level. - * - * @param aMessage the message to be logged - */ - public void fatal(String aMessage); - - /** - * Log message (fatal level with exception). - * - * @param aMessage the message to be logged - * @param aThrowable the exception - */ - public void fatal(String aMessage, Throwable aThrowable); - - /** - * Set log level - * - * @param aLevel a valid Level from ConfigDefs - */ - public void setLevel(int aLevel); -} +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.util; + +import nl.justobjects.pushlet.core.ConfigDefs; + +/** + * Logger interface to allow different logging providers. + *

+ * + * @author Ulrich Romahn + * @version $Id: PushletLogger.java,v 1.1 2007/12/07 12:57:40 justb Exp $ + */ +public interface PushletLogger extends ConfigDefs { + + /** + * Method allowing to initialize our logger + */ + public void init(); + + /** + * Log message for trace level. + * + * @param aMessage the message to be logged + */ + public void trace(String aMessage); + + /** + * Log message for debug level. + * + * @param aMessage the message to be logged + */ + public void debug(String aMessage); + + /** + * Log message for info level. + * + * @param aMessage the message to be logged + */ + public void info(String aMessage); + + /** + * Log message for warning level. + * + * @param aMessage the message to be logged + */ + public void warn(String aMessage); + + /** + * Log message for warning level with exception. + * + * @param aMessage the message to be logged + * @param aThrowable the exception + */ + public void warn(String aMessage, Throwable aThrowable); + + /** + * Log message for error level. + * + * @param aMessage the message to be logged + */ + public void error(String aMessage); + + /** + * Log message (error level with exception). + * + * @param aMessage the message to be logged + * @param aThrowable the exception + */ + public void error(String aMessage, Throwable aThrowable); + + /** + * Log message for fatal level. + * + * @param aMessage the message to be logged + */ + public void fatal(String aMessage); + + /** + * Log message (fatal level with exception). + * + * @param aMessage the message to be logged + * @param aThrowable the exception + */ + public void fatal(String aMessage, Throwable aThrowable); + + /** + * Set log level + * + * @param aLevel a valid Level from ConfigDefs + */ + public void setLevel(int aLevel); +} diff --git a/sw/in_progress/pow/pow/WebContent/CSS/design.css b/sw/in_progress/pow/pow/WebContent/CSS/design.css index 124c98ec46..42197afc7f 100644 --- a/sw/in_progress/pow/pow/WebContent/CSS/design.css +++ b/sw/in_progress/pow/pow/WebContent/CSS/design.css @@ -1,44 +1,44 @@ -body -{ - background-color: #CCFFCC; - margin: 0%; - padding: 0%; - outline: 0%; - height: 100%; - overflow:hidden; - max-width:2048px; - font-size : 11; -} - -select{ - font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; - font-size: 11px; - vertical-align: middle; - background-color: #F5F5DC; -} -input { - background-color:#F5F5DC; - font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; - font-size: 10px; -} - -label { - font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; - font-size: 11px; -} - -#welcome -{ - position:absolute; - top:0; - left:0; - height:3%; - width: 100%; - background-color: #EEEEEE; - text-align: center; - font-weight:bold; - font-size : 12; -} +body +{ + background-color: #CCFFCC; + margin: 0%; + padding: 0%; + outline: 0%; + height: 100%; + overflow:hidden; + max-width:2048px; + font-size : 11; +} + +select{ + font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; + font-size: 11px; + vertical-align: middle; + background-color: #F5F5DC; +} +input { + background-color:#F5F5DC; + font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; + font-size: 10px; +} + +label { + font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; + font-size: 11px; +} + +#welcome +{ + position:absolute; + top:0; + left:0; + height:3%; + width: 100%; + background-color: #EEEEEE; + text-align: center; + font-weight:bold; + font-size : 12; +} #usr { position:absolute; @@ -46,165 +46,165 @@ label { right:6%; height:3%; width:25%; - background-color: #EEEEEE; - text-align: right; + background-color: #EEEEEE; + text-align: right; white-space:nowrap; -} -#page -{ -position:absolute; -top:3%; -left:0; -height:97%; -width: 100%; -} - - -#choicePanel{ - position:absolute; - top:0%; - left:0%; - height: 13%; - width : 15%; - background-color: #EEEEEE; - border: 1px solid black; -} - -#aircraftSelector -{ - text-align: center; - background-color: #EEEEEE; -} - -#trackdiv -{ - text-align: center; - background-color: #EEEEEE; -} - -#active_block -{ - font-size:11; - text-align: center; -} - -#FlightPlan -{ - overflow:auto; - position:absolute; - top:0%; - left:15%; - height: 40%; - width : 14.9%; - background-color: #EEEEEE; - border: 1px solid black; -} - -#FlightParams -{ - position:absolute; - top:13%; - left :0% - text-align: center; - height: 27%; - width : 14.9%; - border: 1px solid black; - background-color: #EEEEEE; -} - -#map_canvas -{ - position:absolute; - top:0; - left:30%; - width:70%; +} +#page +{ +position:absolute; +top:3%; +left:0; +height:97%; +width: 100%; +} + + +#choicePanel{ + position:absolute; + top:0%; + left:0%; + height: 13%; + width : 15%; + background-color: #EEEEEE; + border: 1px solid black; +} + +#aircraftSelector +{ + text-align: center; + background-color: #EEEEEE; +} + +#trackdiv +{ + text-align: center; + background-color: #EEEEEE; +} + +#active_block +{ + font-size:11; + text-align: center; +} + +#FlightPlan +{ + overflow:auto; + position:absolute; + top:0%; + left:15%; + height: 40%; + width : 14.9%; + background-color: #EEEEEE; + border: 1px solid black; +} + +#FlightParams +{ + position:absolute; + top:13%; + left :0% + text-align: center; + height: 27%; + width : 14.9%; + border: 1px solid black; + background-color: #EEEEEE; +} + +#map_canvas +{ + position:absolute; + top:0; + left:30%; + width:70%; height: 95%; - border:1px solid black; -} - - -#Settings -{ - overflow:auto; - position:absolute; + border:1px solid black; +} + + +#Settings +{ + overflow:auto; + position:absolute; left:0%; - top:40%; - text-align: left; - height: 55%; - width: 29.9%; - background-color: #EEEEEE; - border: 1px solid black; -} - -#page_setting { - -} - -#setting { - width: 400px; - height: 250px; - padding: 0.5em; - font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; - font-size: 8; -} -#param -{ - overflow:auto; -} - -#NewsDiv -{ - position:absolute; - overflow:auto; - left:0%; - top:95%; - height: 5%; - width: 100%; - text-align: left; - vertical-align:top; - background-color: #EEEEEE; - border: 1px solid black; -} - -#info -{ - text-align: left; - font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; - font-size: 11px; -} - -#Debug -{ - overflow:auto; - position:absolute; - left:65%; - top:50%; - text-align: center; - height: 50%; - width: 35%; - background-color: #EEEEEE; - border: 1px solid black; - padding-top:20px; - font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; - font-size: 11px; -} - -#title{ - font-weight:bold; - font-size:18; - text-align:center; -} - -table.param { -border:3px solid #6495ed; -border-collapse:collapse; -width:90%; -margin:auto; -} -td.param { -font-family:sans-serif; -font-size:11px; -border:1px solid #6495ed; -padding:5px; -text-align:left; -} + top:40%; + text-align: left; + height: 55%; + width: 29.9%; + background-color: #EEEEEE; + border: 1px solid black; +} + +#page_setting { + +} + +#setting { + width: 400px; + height: 250px; + padding: 0.5em; + font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; + font-size: 8; +} +#param +{ + overflow:auto; +} + +#NewsDiv +{ + position:absolute; + overflow:auto; + left:0%; + top:95%; + height: 5%; + width: 100%; + text-align: left; + vertical-align:top; + background-color: #EEEEEE; + border: 1px solid black; +} + +#info +{ + text-align: left; + font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; + font-size: 11px; +} + +#Debug +{ + overflow:auto; + position:absolute; + left:65%; + top:50%; + text-align: center; + height: 50%; + width: 35%; + background-color: #EEEEEE; + border: 1px solid black; + padding-top:20px; + font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; + font-size: 11px; +} + +#title{ + font-weight:bold; + font-size:18; + text-align:center; +} + +table.param { +border:3px solid #6495ed; +border-collapse:collapse; +width:90%; +margin:auto; +} +td.param { +font-family:sans-serif; +font-size:11px; +border:1px solid #6495ed; +padding:5px; +text-align:left; +} diff --git a/sw/in_progress/pow/pow/WebContent/CSS/designHelp.css b/sw/in_progress/pow/pow/WebContent/CSS/designHelp.css index df08745f31..e8fcfd7a3d 100644 --- a/sw/in_progress/pow/pow/WebContent/CSS/designHelp.css +++ b/sw/in_progress/pow/pow/WebContent/CSS/designHelp.css @@ -1,12 +1,12 @@ -body -{ - width: 90%; - margin-top: 5px; +body +{ + width: 90%; + margin-top: 5px; margin-bottom: 5px; margin-left:5%; - margin-reight:5%; + margin-reight:5%; background-color: #CCFFCC; - text-align:justify; + text-align:justify; } h3,h2 diff --git a/sw/in_progress/pow/pow/WebContent/CSS/designLogOut.css b/sw/in_progress/pow/pow/WebContent/CSS/designLogOut.css index 02a1a63f3f..c6ce91f1e9 100644 --- a/sw/in_progress/pow/pow/WebContent/CSS/designLogOut.css +++ b/sw/in_progress/pow/pow/WebContent/CSS/designLogOut.css @@ -1,12 +1,12 @@ -body -{ - background-color: #CCFFCC; - margin-top: 2%; - padding: 0%; - outline: 0%; - height: 100%; - overflow:hidden; - max-width:2048px; - text-align:center; - font-size:24px; +body +{ + background-color: #CCFFCC; + margin-top: 2%; + padding: 0%; + outline: 0%; + height: 100%; + overflow:hidden; + max-width:2048px; + text-align:center; + font-size:24px; } \ No newline at end of file diff --git a/sw/in_progress/pow/pow/WebContent/CSS/designWelcome.css b/sw/in_progress/pow/pow/WebContent/CSS/designWelcome.css index e6cd8076f0..fe096f7074 100644 --- a/sw/in_progress/pow/pow/WebContent/CSS/designWelcome.css +++ b/sw/in_progress/pow/pow/WebContent/CSS/designWelcome.css @@ -1,30 +1,30 @@ -body -{ - width: 960px; - margin-top: 100px; +body +{ + width: 960px; + margin-top: 100px; margin-bottom: 5px; background-image: url("Icons/logo.png"); - background-repeat:no-repeat; + background-repeat:no-repeat; background-color: #CCFFCC; - -} - -#signIn -{ - margin: auto; - width: 300px; - height: 140px; - border: 1px solid black; -} - -#log -{ - margin-left: 30px; -} - -a + +} + +#signIn { - position:absolute; + margin: auto; + width: 300px; + height: 140px; + border: 1px solid black; +} + +#log +{ + margin-left: 30px; +} + +a +{ + position:absolute; right:1%; - top:80%; + top:80%; } \ No newline at end of file diff --git a/sw/in_progress/pow/pow/WebContent/CSS/designbackup.css b/sw/in_progress/pow/pow/WebContent/CSS/designbackup.css index b9ea91607d..b00585c71d 100644 --- a/sw/in_progress/pow/pow/WebContent/CSS/designbackup.css +++ b/sw/in_progress/pow/pow/WebContent/CSS/designbackup.css @@ -1,87 +1,87 @@ -body -{ - background-color: #CCFFCC; - margin: 0%; - padding: 0%; - outline: 0%; - height: 95%; -} -#page -{ - width: 100%; - height: 95%; -} - -#logo -{ - width: 960px; - height: 100px; - background-image: url("banniere.jpg"); - background-repeat: repeat-x; - margin-bottom: 10px; -} - -#leftmenu -{ - /* float: left; /* Le menu flottera à gauche */ - /* width: 120px; *//* Très important : donner une taille au menu */ -} -#welcome -{ - text-align: center; - background-color: #EEEEEE; - border: 2px solid black; - margin-bottom: 10px; /* Pour éviter que les éléments du menu ne soient trop collés */ -} -#choice -{ -float: left; - text-align: center; - background-color: #EEEEEE; - border: 2px solid black; - height: 190px; - width: 20px; -} -#map_canvas -{ - width: 690px; - height: 350px; - margin-left: 125px; -} - -#FlightPlan -{ - float: right; - width: 135px; /* Très important : donner une taille au menu */ - height: 345px; - border: 2px solid black; - background-color: #EEEEEE; -} - - - -#ControlPanel -{ - float: left; - text-align: center; - height: 150px; - width: 600px; - border: 2px solid black; - background-color: #EEEEEE; -} -#FlightParams -{ - text-align: center; - float: right; - height: 150px; - width: 350px; - border: 2px solid black; - background-color: #EEEEEE; -} -table -{ - margin-left: 20px; - margin-bottom: 20px; -} - +body +{ + background-color: #CCFFCC; + margin: 0%; + padding: 0%; + outline: 0%; + height: 95%; +} +#page +{ + width: 100%; + height: 95%; +} + +#logo +{ + width: 960px; + height: 100px; + background-image: url("banniere.jpg"); + background-repeat: repeat-x; + margin-bottom: 10px; +} + +#leftmenu +{ + /* float: left; /* Le menu flottera à gauche */ + /* width: 120px; *//* Très important : donner une taille au menu */ +} +#welcome +{ + text-align: center; + background-color: #EEEEEE; + border: 2px solid black; + margin-bottom: 10px; /* Pour éviter que les éléments du menu ne soient trop collés */ +} +#choice +{ +float: left; + text-align: center; + background-color: #EEEEEE; + border: 2px solid black; + height: 190px; + width: 20px; +} +#map_canvas +{ + width: 690px; + height: 350px; + margin-left: 125px; +} + +#FlightPlan +{ + float: right; + width: 135px; /* Très important : donner une taille au menu */ + height: 345px; + border: 2px solid black; + background-color: #EEEEEE; +} + + + +#ControlPanel +{ + float: left; + text-align: center; + height: 150px; + width: 600px; + border: 2px solid black; + background-color: #EEEEEE; +} +#FlightParams +{ + text-align: center; + float: right; + height: 150px; + width: 350px; + border: 2px solid black; + background-color: #EEEEEE; +} +table +{ + margin-left: 20px; + margin-bottom: 20px; +} + \ No newline at end of file diff --git a/sw/in_progress/pow/pow/WebContent/CSS/dtree.css b/sw/in_progress/pow/pow/WebContent/CSS/dtree.css index ccc20f8c35..b201c2fd60 100644 --- a/sw/in_progress/pow/pow/WebContent/CSS/dtree.css +++ b/sw/in_progress/pow/pow/WebContent/CSS/dtree.css @@ -1,34 +1,34 @@ -/*--------------------------------------------------| -| dTree 2.05 | www.destroydrop.com/javascript/tree/ | -|---------------------------------------------------| -| Copyright (c) 2002-2003 Geir Landrö | -|--------------------------------------------------*/ - -.dtree { - font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; - font-size: 11px; - color: #666; - white-space: nowrap; -} -.dtree img { - border: 0px; - vertical-align: middle; -} -.dtree a { - color: #333; - text-decoration: none; -} -.dtree a.node, .dtree a.nodeSel { - white-space: nowrap; - padding: 1px 2px 1px 2px; -} -.dtree a.node:hover, .dtree a.nodeSel:hover { - color: #333; - text-decoration: underline; -} -.dtree a.nodeSel { - background-color: #c0d2ec; -} -.dtree .clip { - overflow: hidden; +/*--------------------------------------------------| +| dTree 2.05 | www.destroydrop.com/javascript/tree/ | +|---------------------------------------------------| +| Copyright (c) 2002-2003 Geir Landrö | +|--------------------------------------------------*/ + +.dtree { + font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; + font-size: 11px; + color: #666; + white-space: nowrap; +} +.dtree img { + border: 0px; + vertical-align: middle; +} +.dtree a { + color: #333; + text-decoration: none; +} +.dtree a.node, .dtree a.nodeSel { + white-space: nowrap; + padding: 1px 2px 1px 2px; +} +.dtree a.node:hover, .dtree a.nodeSel:hover { + color: #333; + text-decoration: underline; +} +.dtree a.nodeSel { + background-color: #c0d2ec; +} +.dtree .clip { + overflow: hidden; } \ No newline at end of file diff --git a/sw/in_progress/pow/pow/WebContent/META-INF/MANIFEST.MF b/sw/in_progress/pow/pow/WebContent/META-INF/MANIFEST.MF index 5e9495128c..254272e1c0 100644 --- a/sw/in_progress/pow/pow/WebContent/META-INF/MANIFEST.MF +++ b/sw/in_progress/pow/pow/WebContent/META-INF/MANIFEST.MF @@ -1,3 +1,3 @@ -Manifest-Version: 1.0 -Class-Path: - +Manifest-Version: 1.0 +Class-Path: + diff --git a/sw/in_progress/pow/pow/WebContent/conf/pow.conf b/sw/in_progress/pow/pow/WebContent/conf/pow.conf index 3fc60b177c..dfcfb615e6 100644 --- a/sw/in_progress/pow/pow/WebContent/conf/pow.conf +++ b/sw/in_progress/pow/pow/WebContent/conf/pow.conf @@ -1,41 +1,41 @@ -########################################## -########## PAPARAZZI ON THE WEB ########## -########################################## - -#Beginning of configuration file : - -###################################### - -# The port on which msg from ivy are sended to web server - +########################################## +########## PAPARAZZI ON THE WEB ########## +########################################## -# The port in which msg from web server are sended to ivy +#Beginning of configuration file : + +###################################### + +# The port on which msg from ivy are sended to web server + + +# The port in which msg from web server are sended to ivy - -# The size of the udp datagram (1024 recommanded) - - -# The name of the dataBase - - -# The userName used in the dataBase on the server - - -# The password of the dataBase on the server - - -# The timeout of the udp connection (in millisecond) - - -# The location of the flightPlan Repertory (finish it with "/") - -# The administrator's login of POW WEB site +# The size of the udp datagram (1024 recommanded) + + +# The name of the dataBase + + +# The userName used in the dataBase on the server + + +# The password of the dataBase on the server + + +# The timeout of the udp connection (in millisecond) + + +# The location of the flightPlan Repertory (finish it with "/") + + +# The administrator's login of POW WEB site -# The administrator's mail of POW WEB site +# The administrator's mail of POW WEB site - -###################################### - + +###################################### + diff --git a/sw/in_progress/pow/pow/WebContent/js/DOMImplementation.js b/sw/in_progress/pow/pow/WebContent/js/DOMImplementation.js index 5e94107932..75c17e11d6 100644 --- a/sw/in_progress/pow/pow/WebContent/js/DOMImplementation.js +++ b/sw/in_progress/pow/pow/WebContent/js/DOMImplementation.js @@ -1,24 +1,24 @@ -function DOMImplementation(sUrl, fCallback) { - var dom; - if(window.ActiveXObject) { - dom = new ActiveXObject("Microsoft.XMLDOM"); - dom.onreadystatechange = function() { - if(dom.readyState == 4) { - //alert("win "+sUrl+" loaded"); - fCallback(dom); - } - }; - } - else if(document.implementation && document.implementation.createDocument) { - dom = document.implementation.createDocument("", "", null); - dom.onload = function() { - //alert("other "+sUrl+" loaded"); - fCallback(dom); - } - } - else { - alert("Votre navigateur ne gère pas l'importation de fichiers XML"); - return; - } - dom.load(sUrl); -} +function DOMImplementation(sUrl, fCallback) { + var dom; + if(window.ActiveXObject) { + dom = new ActiveXObject("Microsoft.XMLDOM"); + dom.onreadystatechange = function() { + if(dom.readyState == 4) { + //alert("win "+sUrl+" loaded"); + fCallback(dom); + } + }; + } + else if(document.implementation && document.implementation.createDocument) { + dom = document.implementation.createDocument("", "", null); + dom.onload = function() { + //alert("other "+sUrl+" loaded"); + fCallback(dom); + } + } + else { + alert("Votre navigateur ne gère pas l'importation de fichiers XML"); + return; + } + dom.load(sUrl); +} diff --git a/sw/in_progress/pow/pow/WebContent/js/XHR_object.js b/sw/in_progress/pow/pow/WebContent/js/XHR_object.js index 544a2b1a2e..8f3f022733 100644 --- a/sw/in_progress/pow/pow/WebContent/js/XHR_object.js +++ b/sw/in_progress/pow/pow/WebContent/js/XHR_object.js @@ -1,20 +1,20 @@ -function getXMLHttpRequest() { - var xhr = null; - - if (window.XMLHttpRequest || window.ActiveXObject) { - if (window.ActiveXObject) { - try { - xhr = new ActiveXObject("Msxml2.XMLHTTP"); - } catch(e) { - xhr = new ActiveXObject("Microsoft.XMLHTTP"); - } - } else { - xhr = new XMLHttpRequest(); - } - } else { - alert("Votre navigateur ne supporte pas l'objet XMLHTTPRequest..."); - return null; - } - - return xhr; -} +function getXMLHttpRequest() { + var xhr = null; + + if (window.XMLHttpRequest || window.ActiveXObject) { + if (window.ActiveXObject) { + try { + xhr = new ActiveXObject("Msxml2.XMLHTTP"); + } catch(e) { + xhr = new ActiveXObject("Microsoft.XMLHTTP"); + } + } else { + xhr = new XMLHttpRequest(); + } + } else { + alert("Votre navigateur ne supporte pas l'objet XMLHTTPRequest..."); + return null; + } + + return xhr; +} diff --git a/sw/in_progress/pow/pow/WebContent/js/browserdetect.js b/sw/in_progress/pow/pow/WebContent/js/browserdetect.js index 1e0b64da62..a8674db57f 100644 --- a/sw/in_progress/pow/pow/WebContent/js/browserdetect.js +++ b/sw/in_progress/pow/pow/WebContent/js/browserdetect.js @@ -1,97 +1,97 @@ -// Browser Detect Lite v2.1.4 -// http://www.dithered.com/javascript/browser_detect/index.html -// modified by Chris Nott (chris@NOSPAMdithered.com - remove NOSPAM) - - -function BrowserDetectLite() { - var ua = navigator.userAgent.toLowerCase(); - - // browser name - this.isGecko = (ua.indexOf('gecko') != -1 && ua.indexOf('safari') == -1); - this.isMozilla = (this.isGecko && ua.indexOf('gecko/') + 14 == ua.length); - this.isNS = ( (this.isGecko) ? (ua.indexOf('netscape') != -1) : ( (ua.indexOf('mozilla') != -1) && (ua.indexOf('spoofer') == -1) && (ua.indexOf('compatible') == -1) && (ua.indexOf('opera') == -1) && (ua.indexOf('webtv') == -1) && (ua.indexOf('hotjava') == -1) ) ); - this.isIE = ( (ua.indexOf('msie') != -1) && (ua.indexOf('opera') == -1) && (ua.indexOf('webtv') == -1) ); - this.isSafari = (ua.indexOf('safari') != - 1); - this.isOpera = (ua.indexOf('opera') != -1); - this.isKonqueror = (ua.indexOf('konqueror') != -1 && !this.isSafari); - this.isIcab = (ua.indexOf('icab') != -1); - this.isAol = (ua.indexOf('aol') != -1); - - // spoofing and compatible browsers - this.isIECompatible = ( (ua.indexOf('msie') != -1) && !this.isIE); - this.isNSCompatible = ( (ua.indexOf('mozilla') != -1) && !this.isNS && !this.isMozilla); - - // browser version - this.versionMinor = parseFloat(navigator.appVersion); - - // correct version number - if (this.isNS && this.isGecko) { - this.versionMinor = parseFloat( ua.substring( ua.lastIndexOf('/') + 1 ) ); - } - else if (this.isIE && this.versionMinor >= 4) { - this.versionMinor = parseFloat( ua.substring( ua.indexOf('msie ') + 5 ) ); - } - else if (this.isMozilla) { - this.versionMinor = parseFloat( ua.substring( ua.indexOf('rv:') + 3 ) ); - } - else if (this.isSafari) { - this.versionMinor = parseFloat( ua.substring( ua.lastIndexOf('/') + 1 ) ); - } - else if (this.isOpera) { - if (ua.indexOf('opera/') != -1) { - this.versionMinor = parseFloat( ua.substring( ua.indexOf('opera/') + 6 ) ); - } - else { - this.versionMinor = parseFloat( ua.substring( ua.indexOf('opera ') + 6 ) ); - } - } - else if (this.isKonqueror) { - this.versionMinor = parseFloat( ua.substring( ua.indexOf('konqueror/') + 10 ) ); - } - else if (this.isIcab) { - if (ua.indexOf('icab/') != -1) { - this.versionMinor = parseFloat( ua.substring( ua.indexOf('icab/') + 6 ) ); - } - else { - this.versionMinor = parseFloat( ua.substring( ua.indexOf('icab ') + 6 ) ); - } - } - - this.versionMajor = parseInt(this.versionMinor); - this.geckoVersion = ( (this.isGecko) ? ua.substring( (ua.lastIndexOf('gecko/') + 6), (ua.lastIndexOf('gecko/') + 14) ) : -1 ); - - // dom support - this.isDOM1 = (document.getElementById); - this.isDOM2Event = (document.addEventListener && document.removeEventListener); - - // css compatibility mode - this.mode = document.compatMode ? document.compatMode : 'BackCompat'; - - // platform - this.isWin = (ua.indexOf('win') != -1); - this.isWin32 = (this.isWin && ( ua.indexOf('95') != -1 || ua.indexOf('98') != -1 || ua.indexOf('nt') != -1 || ua.indexOf('win32') != -1 || ua.indexOf('32bit') != -1 || ua.indexOf('xp') != -1) ); - this.isMac = (ua.indexOf('mac') != -1); - this.isUnix = (ua.indexOf('unix') != -1 || ua.indexOf('sunos') != -1 || ua.indexOf('bsd') != -1 || ua.indexOf('x11') != -1) - this.isLinux = (ua.indexOf('linux') != -1); - - // specific browser shortcuts - this.isNS4x = (this.isNS && this.versionMajor == 4); - this.isNS40x = (this.isNS4x && this.versionMinor < 4.5); - this.isNS47x = (this.isNS4x && this.versionMinor >= 4.7); - this.isNS4up = (this.isNS && this.versionMinor >= 4); - this.isNS6x = (this.isNS && this.versionMajor == 6); - this.isNS6up = (this.isNS && this.versionMajor >= 6); - this.isNS7x = (this.isNS && this.versionMajor == 7); - this.isNS7up = (this.isNS && this.versionMajor >= 7); - - this.isIE4x = (this.isIE && this.versionMajor == 4); - this.isIE4up = (this.isIE && this.versionMajor >= 4); - this.isIE5x = (this.isIE && this.versionMajor == 5); - this.isIE55 = (this.isIE && this.versionMinor == 5.5); - this.isIE5up = (this.isIE && this.versionMajor >= 5); - this.isIE6x = (this.isIE && this.versionMajor == 6); - this.isIE6up = (this.isIE && this.versionMajor >= 6); - - this.isIE4xMac = (this.isIE4x && this.isMac); -} -var browser = new BrowserDetectLite(); +// Browser Detect Lite v2.1.4 +// http://www.dithered.com/javascript/browser_detect/index.html +// modified by Chris Nott (chris@NOSPAMdithered.com - remove NOSPAM) + + +function BrowserDetectLite() { + var ua = navigator.userAgent.toLowerCase(); + + // browser name + this.isGecko = (ua.indexOf('gecko') != -1 && ua.indexOf('safari') == -1); + this.isMozilla = (this.isGecko && ua.indexOf('gecko/') + 14 == ua.length); + this.isNS = ( (this.isGecko) ? (ua.indexOf('netscape') != -1) : ( (ua.indexOf('mozilla') != -1) && (ua.indexOf('spoofer') == -1) && (ua.indexOf('compatible') == -1) && (ua.indexOf('opera') == -1) && (ua.indexOf('webtv') == -1) && (ua.indexOf('hotjava') == -1) ) ); + this.isIE = ( (ua.indexOf('msie') != -1) && (ua.indexOf('opera') == -1) && (ua.indexOf('webtv') == -1) ); + this.isSafari = (ua.indexOf('safari') != - 1); + this.isOpera = (ua.indexOf('opera') != -1); + this.isKonqueror = (ua.indexOf('konqueror') != -1 && !this.isSafari); + this.isIcab = (ua.indexOf('icab') != -1); + this.isAol = (ua.indexOf('aol') != -1); + + // spoofing and compatible browsers + this.isIECompatible = ( (ua.indexOf('msie') != -1) && !this.isIE); + this.isNSCompatible = ( (ua.indexOf('mozilla') != -1) && !this.isNS && !this.isMozilla); + + // browser version + this.versionMinor = parseFloat(navigator.appVersion); + + // correct version number + if (this.isNS && this.isGecko) { + this.versionMinor = parseFloat( ua.substring( ua.lastIndexOf('/') + 1 ) ); + } + else if (this.isIE && this.versionMinor >= 4) { + this.versionMinor = parseFloat( ua.substring( ua.indexOf('msie ') + 5 ) ); + } + else if (this.isMozilla) { + this.versionMinor = parseFloat( ua.substring( ua.indexOf('rv:') + 3 ) ); + } + else if (this.isSafari) { + this.versionMinor = parseFloat( ua.substring( ua.lastIndexOf('/') + 1 ) ); + } + else if (this.isOpera) { + if (ua.indexOf('opera/') != -1) { + this.versionMinor = parseFloat( ua.substring( ua.indexOf('opera/') + 6 ) ); + } + else { + this.versionMinor = parseFloat( ua.substring( ua.indexOf('opera ') + 6 ) ); + } + } + else if (this.isKonqueror) { + this.versionMinor = parseFloat( ua.substring( ua.indexOf('konqueror/') + 10 ) ); + } + else if (this.isIcab) { + if (ua.indexOf('icab/') != -1) { + this.versionMinor = parseFloat( ua.substring( ua.indexOf('icab/') + 6 ) ); + } + else { + this.versionMinor = parseFloat( ua.substring( ua.indexOf('icab ') + 6 ) ); + } + } + + this.versionMajor = parseInt(this.versionMinor); + this.geckoVersion = ( (this.isGecko) ? ua.substring( (ua.lastIndexOf('gecko/') + 6), (ua.lastIndexOf('gecko/') + 14) ) : -1 ); + + // dom support + this.isDOM1 = (document.getElementById); + this.isDOM2Event = (document.addEventListener && document.removeEventListener); + + // css compatibility mode + this.mode = document.compatMode ? document.compatMode : 'BackCompat'; + + // platform + this.isWin = (ua.indexOf('win') != -1); + this.isWin32 = (this.isWin && ( ua.indexOf('95') != -1 || ua.indexOf('98') != -1 || ua.indexOf('nt') != -1 || ua.indexOf('win32') != -1 || ua.indexOf('32bit') != -1 || ua.indexOf('xp') != -1) ); + this.isMac = (ua.indexOf('mac') != -1); + this.isUnix = (ua.indexOf('unix') != -1 || ua.indexOf('sunos') != -1 || ua.indexOf('bsd') != -1 || ua.indexOf('x11') != -1) + this.isLinux = (ua.indexOf('linux') != -1); + + // specific browser shortcuts + this.isNS4x = (this.isNS && this.versionMajor == 4); + this.isNS40x = (this.isNS4x && this.versionMinor < 4.5); + this.isNS47x = (this.isNS4x && this.versionMinor >= 4.7); + this.isNS4up = (this.isNS && this.versionMinor >= 4); + this.isNS6x = (this.isNS && this.versionMajor == 6); + this.isNS6up = (this.isNS && this.versionMajor >= 6); + this.isNS7x = (this.isNS && this.versionMajor == 7); + this.isNS7up = (this.isNS && this.versionMajor >= 7); + + this.isIE4x = (this.isIE && this.versionMajor == 4); + this.isIE4up = (this.isIE && this.versionMajor >= 4); + this.isIE5x = (this.isIE && this.versionMajor == 5); + this.isIE55 = (this.isIE && this.versionMinor == 5.5); + this.isIE5up = (this.isIE && this.versionMajor >= 5); + this.isIE6x = (this.isIE && this.versionMajor == 6); + this.isIE6up = (this.isIE && this.versionMajor >= 6); + + this.isIE4xMac = (this.isIE4x && this.isMac); +} +var browser = new BrowserDetectLite(); diff --git a/sw/in_progress/pow/pow/WebContent/js/menu1.js b/sw/in_progress/pow/pow/WebContent/js/menu1.js index 5f87f66421..74abcbc61a 100644 --- a/sw/in_progress/pow/pow/WebContent/js/menu1.js +++ b/sw/in_progress/pow/pow/WebContent/js/menu1.js @@ -1,155 +1,155 @@ -/* -Author : bieler batiste -Company : doSimple : http://www.dosimple.ch -send me a mail for more informations : faden@PASDEPOURRIELaltern.org - remove ( PASDEPOURRIEL ) - -Short javascript function to create and handle a CSS navigation menu - -Copyright (C) 2004 Bieler Batiste - -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.1 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 USA -*/ - -// the timeout for the menu -var timeout = 100; - -// not very clean but simple -// the function can be run in the HTML for faster display -// window.onload=initMenu; - -// creat timeout variables for list item -// it's for avoid some warning with IE -for( var i = 0; i < 100; i++ ) -{ - eval("var timeoutli" + i + " = false;"); -} - -// this fonction apply the CSS style and the event -function initMenu() -{ - // a test to avoid some browser like IE4, Opera 6, and IE Mac - if ( browser.isDOM1 - && !( browser.isMac && browser.isIE ) - && !( browser.isOpera && browser.versionMajor < 7 ) - && !( browser.isIE && browser.versionMajor < 5 ) ) - { - // get some element - var menu = document.getElementById('menu'); // the root element - var lis = menu.getElementsByTagName('li'); // all the li - - // change the class name of the menu, - // it's usefull for compatibility with old browser - menu.className='menu'; - // i am searching for ul element in li element - for ( var i=0; i 0 ) - { - // improve IE key navigation - if ( browser.isIE ) - { - addAnEvent(lis.item(i),'keyup',show); - } - // link events to list item - addAnEvent(lis.item(i),'mouseover',show); - addAnEvent(lis.item(i),'mouseout',timeoutHide); - addAnEvent(lis.item(i),'blur',timeoutHide); - addAnEvent(lis.item(i),'focus',show); - - // add an id to list item - lis.item(i).setAttribute( 'id', "li"+i ); - } - } - } -} +/* +Author : bieler batiste +Company : doSimple : http://www.dosimple.ch +send me a mail for more informations : faden@PASDEPOURRIELaltern.org - remove ( PASDEPOURRIEL ) - +Short javascript function to create and handle a CSS navigation menu - -function addAnEvent( target, eventName, functionName ) -{ - // apply the method to IE - if ( browser.isIE ) - { - //attachEvent dont work properly with this - eval('target.on'+eventName+'=functionName'); - } - // apply the method to DOM compliant browsers - else - { - target.addEventListener( eventName , functionName , true ); // true is important for Opera7 - } -} - -// hide the first ul element of the current element -function timeoutHide() -{ - // start the timeout - eval( "timeout" + this.id + " = window.setTimeout('hideUlUnder( \"" + this.id + "\" )', " + timeout + " );"); -} - -// hide the ul elements under the element identified by id -function hideUlUnder( id ) -{ - document.getElementById(id).getElementsByTagName('ul')[0].style['visibility'] = 'hidden'; -} - -// show the first ul element found under this element -function show() -{ - // show the sub menu - this.getElementsByTagName('ul')[0].style['visibility'] = 'visible'; - var currentNode=this; - while(currentNode) - { - if( currentNode.nodeName=='LI') - { - // currentNode.getElementsByTagName('a')[0].className = 'linkOver'; - } - currentNode=currentNode.parentNode; - } - // clear the timeout - eval ( "clearTimeout( timeout"+ this.id +");" ); - hideAllOthersUls( this ); -} - -// hide all ul on the same level of this list item -function hideAllOthersUls( currentLi ) -{ - var lis = currentLi.parentNode; - for ( var i=0; i 0 ) + { + // improve IE key navigation + if ( browser.isIE ) + { + addAnEvent(lis.item(i),'keyup',show); + } + // link events to list item + addAnEvent(lis.item(i),'mouseover',show); + addAnEvent(lis.item(i),'mouseout',timeoutHide); + addAnEvent(lis.item(i),'blur',timeoutHide); + addAnEvent(lis.item(i),'focus',show); + + // add an id to list item + lis.item(i).setAttribute( 'id', "li"+i ); + } + } + } +} + + + + +function addAnEvent( target, eventName, functionName ) +{ + // apply the method to IE + if ( browser.isIE ) + { + //attachEvent dont work properly with this + eval('target.on'+eventName+'=functionName'); + } + // apply the method to DOM compliant browsers + else + { + target.addEventListener( eventName , functionName , true ); // true is important for Opera7 + } +} + +// hide the first ul element of the current element +function timeoutHide() +{ + // start the timeout + eval( "timeout" + this.id + " = window.setTimeout('hideUlUnder( \"" + this.id + "\" )', " + timeout + " );"); +} + +// hide the ul elements under the element identified by id +function hideUlUnder( id ) +{ + document.getElementById(id).getElementsByTagName('ul')[0].style['visibility'] = 'hidden'; +} + +// show the first ul element found under this element +function show() +{ + // show the sub menu + this.getElementsByTagName('ul')[0].style['visibility'] = 'visible'; + var currentNode=this; + while(currentNode) + { + if( currentNode.nodeName=='LI') + { + // currentNode.getElementsByTagName('a')[0].className = 'linkOver'; + } + currentNode=currentNode.parentNode; + } + // clear the timeout + eval ( "clearTimeout( timeout"+ this.id +");" ); + hideAllOthersUls( this ); +} + +// hide all ul on the same level of this list item +function hideAllOthersUls( currentLi ) +{ + var lis = currentLi.parentNode; + for ( var i=0; i 0 ) + menu2.className='menu2'; + for ( var i=0; i 0 ) { - if ( browser.isIE ) - { - addAnEvent(lis2.item(i),'keyup',show); - } - - addAnEvent(lis2.item(i),'mouseover',show); - addAnEvent(lis2.item(i),'mouseout',timeoutHide); - addAnEvent(lis2.item(i),'blur',timeoutHide); - addAnEvent(lis2.item(i),'focus',show); - - lis2.item(i).setAttribute( 'id', "li2"+i ); - } - } - } + if ( browser.isIE ) + { + addAnEvent(lis2.item(i),'keyup',show); + } + + addAnEvent(lis2.item(i),'mouseover',show); + addAnEvent(lis2.item(i),'mouseout',timeoutHide); + addAnEvent(lis2.item(i),'blur',timeoutHide); + addAnEvent(lis2.item(i),'focus',show); + + lis2.item(i).setAttribute( 'id', "li2"+i ); + } + } + } } - -function addAnEvent( target, eventName, functionName ) + +function addAnEvent( target, eventName, functionName ) { - if ( browser.isIE ) + if ( browser.isIE ) + { + eval('target.on'+eventName+'=functionName'); + } + else { - eval('target.on'+eventName+'=functionName'); - } - else - { target.addEventListener( eventName , functionName , true ); - } -} - -function timeoutHide() + } +} + +function timeoutHide() { - eval( "timeout" + this.id + " = window.setTimeout('hideUlUnder( \"" + this.id + "\" )', " + timeout + " );"); -} - -// hide the ul elements under the element identified by id -function hideUlUnder( id ) -{ - document.getElementById(id).getElementsByTagName('ul')[0].style['visibility'] = 'hidden'; -} - -// show the first ul element found under this element -function show() -{ - // show the sub menu - this.getElementsByTagName('ul')[0].style['visibility'] = 'visible'; - var currentNode=this; - while(currentNode) - { - if( currentNode.nodeName=='LI') - { - // currentNode.getElementsByTagName('a')[0].className = 'linkOver'; - } - currentNode=currentNode.parentNode; - } - // clear the timeout - eval ( "clearTimeout( timeout"+ this.id +");" ); - hideAllOthersUls( this ); -} - -// hide all ul on the same level of this list item -function hideAllOthersUls( currentLi ) -{ - var lis = currentLi.parentNode; - for ( var i=0; i -1, - Gecko: ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1, - MobileSafari: /Apple.*Mobile.*Safari/.test(ua) - } - })(), - - BrowserFeatures: { - XPath: !!document.evaluate, - SelectorsAPI: !!document.querySelector, - ElementExtensions: (function() { - var constructor = window.Element || window.HTMLElement; - return !!(constructor && constructor.prototype); - })(), - SpecificElementExtensions: (function() { - if (typeof window.HTMLDivElement !== 'undefined') - return true; - - var div = document.createElement('div'); - var form = document.createElement('form'); - var isSupported = false; - - if (div['__proto__'] && (div['__proto__'] !== form['__proto__'])) { - isSupported = true; - } - - div = form = null; - - return isSupported; - })() - }, - - ScriptFragment: ']*>([\\S\\s]*?)<\/script>', - JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, - - emptyFunction: function() { }, - K: function(x) { return x } -}; - -if (Prototype.Browser.MobileSafari) - Prototype.BrowserFeatures.SpecificElementExtensions = false; - - -var Abstract = { }; - - -var Try = { - these: function() { - var returnValue; - - for (var i = 0, length = arguments.length; i < length; i++) { - var lambda = arguments[i]; - try { - returnValue = lambda(); - break; - } catch (e) { } - } - - return returnValue; - } -}; - -/* Based on Alex Arnell's inheritance implementation. */ - -var Class = (function() { - function subclass() {}; - function create() { - var parent = null, properties = $A(arguments); - if (Object.isFunction(properties[0])) - parent = properties.shift(); - - function klass() { - this.initialize.apply(this, arguments); - } - - Object.extend(klass, Class.Methods); - klass.superclass = parent; - klass.subclasses = []; - - if (parent) { - subclass.prototype = parent.prototype; - klass.prototype = new subclass; - parent.subclasses.push(klass); - } - - for (var i = 0; i < properties.length; i++) - klass.addMethods(properties[i]); - - if (!klass.prototype.initialize) - klass.prototype.initialize = Prototype.emptyFunction; - - klass.prototype.constructor = klass; - return klass; - } - - function addMethods(source) { - var ancestor = this.superclass && this.superclass.prototype; - var properties = Object.keys(source); - - if (!Object.keys({ toString: true }).length) { - if (source.toString != Object.prototype.toString) - properties.push("toString"); - if (source.valueOf != Object.prototype.valueOf) - properties.push("valueOf"); - } - - for (var i = 0, length = properties.length; i < length; i++) { - var property = properties[i], value = source[property]; - if (ancestor && Object.isFunction(value) && - value.argumentNames().first() == "$super") { - var method = value; - value = (function(m) { - return function() { return ancestor[m].apply(this, arguments); }; - })(property).wrap(method); - - value.valueOf = method.valueOf.bind(method); - value.toString = method.toString.bind(method); - } - this.prototype[property] = value; - } - - return this; - } - - return { - create: create, - Methods: { - addMethods: addMethods - } - }; -})(); -(function() { - - var _toString = Object.prototype.toString; - - function extend(destination, source) { - for (var property in source) - destination[property] = source[property]; - return destination; - } - - function inspect(object) { - try { - if (isUndefined(object)) return 'undefined'; - if (object === null) return 'null'; - return object.inspect ? object.inspect() : String(object); - } catch (e) { - if (e instanceof RangeError) return '...'; - throw e; - } - } - - function toJSON(object) { - var type = typeof object; - switch (type) { - case 'undefined': - case 'function': - case 'unknown': return; - case 'boolean': return object.toString(); - } - - if (object === null) return 'null'; - if (object.toJSON) return object.toJSON(); - if (isElement(object)) return; - - var results = []; - for (var property in object) { - var value = toJSON(object[property]); - if (!isUndefined(value)) - results.push(property.toJSON() + ': ' + value); - } - - return '{' + results.join(', ') + '}'; - } - - function toQueryString(object) { - return $H(object).toQueryString(); - } - - function toHTML(object) { - return object && object.toHTML ? object.toHTML() : String.interpret(object); - } - - function keys(object) { - var results = []; - for (var property in object) - results.push(property); - return results; - } - - function values(object) { - var results = []; - for (var property in object) - results.push(object[property]); - return results; - } - - function clone(object) { - return extend({ }, object); - } - - function isElement(object) { - return !!(object && object.nodeType == 1); - } - - function isArray(object) { - return _toString.call(object) == "[object Array]"; - } - - - function isHash(object) { - return object instanceof Hash; - } - - function isFunction(object) { - return typeof object === "function"; - } - - function isString(object) { - return _toString.call(object) == "[object String]"; - } - - function isNumber(object) { - return _toString.call(object) == "[object Number]"; - } - - function isUndefined(object) { - return typeof object === "undefined"; - } - - extend(Object, { - extend: extend, - inspect: inspect, - toJSON: toJSON, - toQueryString: toQueryString, - toHTML: toHTML, - keys: keys, - values: values, - clone: clone, - isElement: isElement, - isArray: isArray, - isHash: isHash, - isFunction: isFunction, - isString: isString, - isNumber: isNumber, - isUndefined: isUndefined - }); -})(); -Object.extend(Function.prototype, (function() { - var slice = Array.prototype.slice; - - function update(array, args) { - var arrayLength = array.length, length = args.length; - while (length--) array[arrayLength + length] = args[length]; - return array; - } - - function merge(array, args) { - array = slice.call(array, 0); - return update(array, args); - } - - function argumentNames() { - var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1] - .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '') - .replace(/\s+/g, '').split(','); - return names.length == 1 && !names[0] ? [] : names; - } - - function bind(context) { - if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this; - var __method = this, args = slice.call(arguments, 1); - return function() { - var a = merge(args, arguments); - return __method.apply(context, a); - } - } - - function bindAsEventListener(context) { - var __method = this, args = slice.call(arguments, 1); - return function(event) { - var a = update([event || window.event], args); - return __method.apply(context, a); - } - } - - function curry() { - if (!arguments.length) return this; - var __method = this, args = slice.call(arguments, 0); - return function() { - var a = merge(args, arguments); - return __method.apply(this, a); - } - } - - function delay(timeout) { - var __method = this, args = slice.call(arguments, 1); - timeout = timeout * 1000 - return window.setTimeout(function() { - return __method.apply(__method, args); - }, timeout); - } - - function defer() { - var args = update([0.01], arguments); - return this.delay.apply(this, args); - } - - function wrap(wrapper) { - var __method = this; - return function() { - var a = update([__method.bind(this)], arguments); - return wrapper.apply(this, a); - } - } - - function methodize() { - if (this._methodized) return this._methodized; - var __method = this; - return this._methodized = function() { - var a = update([this], arguments); - return __method.apply(null, a); - }; - } - - return { - argumentNames: argumentNames, - bind: bind, - bindAsEventListener: bindAsEventListener, - curry: curry, - delay: delay, - defer: defer, - wrap: wrap, - methodize: methodize - } -})()); - - -Date.prototype.toJSON = function() { - return '"' + this.getUTCFullYear() + '-' + - (this.getUTCMonth() + 1).toPaddedString(2) + '-' + - this.getUTCDate().toPaddedString(2) + 'T' + - this.getUTCHours().toPaddedString(2) + ':' + - this.getUTCMinutes().toPaddedString(2) + ':' + - this.getUTCSeconds().toPaddedString(2) + 'Z"'; -}; - - -RegExp.prototype.match = RegExp.prototype.test; - -RegExp.escape = function(str) { - return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); -}; -var PeriodicalExecuter = Class.create({ - initialize: function(callback, frequency) { - this.callback = callback; - this.frequency = frequency; - this.currentlyExecuting = false; - - this.registerCallback(); - }, - - registerCallback: function() { - this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); - }, - - execute: function() { - this.callback(this); - }, - - stop: function() { - if (!this.timer) return; - clearInterval(this.timer); - this.timer = null; - }, - - onTimerEvent: function() { - if (!this.currentlyExecuting) { - try { - this.currentlyExecuting = true; - this.execute(); - this.currentlyExecuting = false; - } catch(e) { - this.currentlyExecuting = false; - throw e; - } - } - } -}); -Object.extend(String, { - interpret: function(value) { - return value == null ? '' : String(value); - }, - specialChar: { - '\b': '\\b', - '\t': '\\t', - '\n': '\\n', - '\f': '\\f', - '\r': '\\r', - '\\': '\\\\' - } -}); - -Object.extend(String.prototype, (function() { - - function prepareReplacement(replacement) { - if (Object.isFunction(replacement)) return replacement; - var template = new Template(replacement); - return function(match) { return template.evaluate(match) }; - } - - function gsub(pattern, replacement) { - var result = '', source = this, match; - replacement = prepareReplacement(replacement); - - if (Object.isString(pattern)) - pattern = RegExp.escape(pattern); - - if (!(pattern.length || pattern.source)) { - replacement = replacement(''); - return replacement + source.split('').join(replacement) + replacement; - } - - while (source.length > 0) { - if (match = source.match(pattern)) { - result += source.slice(0, match.index); - result += String.interpret(replacement(match)); - source = source.slice(match.index + match[0].length); - } else { - result += source, source = ''; - } - } - return result; - } - - function sub(pattern, replacement, count) { - replacement = prepareReplacement(replacement); - count = Object.isUndefined(count) ? 1 : count; - - return this.gsub(pattern, function(match) { - if (--count < 0) return match[0]; - return replacement(match); - }); - } - - function scan(pattern, iterator) { - this.gsub(pattern, iterator); - return String(this); - } - - function truncate(length, truncation) { - length = length || 30; - truncation = Object.isUndefined(truncation) ? '...' : truncation; - return this.length > length ? - this.slice(0, length - truncation.length) + truncation : String(this); - } - - function strip() { - return this.replace(/^\s+/, '').replace(/\s+$/, ''); - } - - function stripTags() { - return this.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?>|<\/\w+>/gi, ''); - } - - function stripScripts() { - return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); - } - - function extractScripts() { - var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); - var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); - return (this.match(matchAll) || []).map(function(scriptTag) { - return (scriptTag.match(matchOne) || ['', ''])[1]; - }); - } - - function evalScripts() { - return this.extractScripts().map(function(script) { return eval(script) }); - } - - function escapeHTML() { - return this.replace(/&/g,'&').replace(//g,'>'); - } - - function unescapeHTML() { - return this.stripTags().replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&'); - } - - - function toQueryParams(separator) { - var match = this.strip().match(/([^?#]*)(#.*)?$/); - if (!match) return { }; - - return match[1].split(separator || '&').inject({ }, function(hash, pair) { - if ((pair = pair.split('='))[0]) { - var key = decodeURIComponent(pair.shift()); - var value = pair.length > 1 ? pair.join('=') : pair[0]; - if (value != undefined) value = decodeURIComponent(value); - - if (key in hash) { - if (!Object.isArray(hash[key])) hash[key] = [hash[key]]; - hash[key].push(value); - } - else hash[key] = value; - } - return hash; - }); - } - - function toArray() { - return this.split(''); - } - - function succ() { - return this.slice(0, this.length - 1) + - String.fromCharCode(this.charCodeAt(this.length - 1) + 1); - } - - function times(count) { - return count < 1 ? '' : new Array(count + 1).join(this); - } - - function camelize() { - var parts = this.split('-'), len = parts.length; - if (len == 1) return parts[0]; - - var camelized = this.charAt(0) == '-' - ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) - : parts[0]; - - for (var i = 1; i < len; i++) - camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); - - return camelized; - } - - function capitalize() { - return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); - } - - function underscore() { - return this.replace(/::/g, '/') - .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2') - .replace(/([a-z\d])([A-Z])/g, '$1_$2') - .replace(/-/g, '_') - .toLowerCase(); - } - - function dasherize() { - return this.replace(/_/g, '-'); - } - - function inspect(useDoubleQuotes) { - var escapedString = this.replace(/[\x00-\x1f\\]/g, function(character) { - if (character in String.specialChar) { - return String.specialChar[character]; - } - return '\\u00' + character.charCodeAt().toPaddedString(2, 16); - }); - if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; - return "'" + escapedString.replace(/'/g, '\\\'') + "'"; - } - - function toJSON() { - return this.inspect(true); - } - - function unfilterJSON(filter) { - return this.replace(filter || Prototype.JSONFilter, '$1'); - } - - function isJSON() { - var str = this; - if (str.blank()) return false; - str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''); - return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str); - } - - function evalJSON(sanitize) { - var json = this.unfilterJSON(); - try { - if (!sanitize || json.isJSON()) return eval('(' + json + ')'); - } catch (e) { } - throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); - } - - function include(pattern) { - return this.indexOf(pattern) > -1; - } - - function startsWith(pattern) { - return this.indexOf(pattern) === 0; - } - - function endsWith(pattern) { - var d = this.length - pattern.length; - return d >= 0 && this.lastIndexOf(pattern) === d; - } - - function empty() { - return this == ''; - } - - function blank() { - return /^\s*$/.test(this); - } - - function interpolate(object, pattern) { - return new Template(this, pattern).evaluate(object); - } - - return { - gsub: gsub, - sub: sub, - scan: scan, - truncate: truncate, - strip: String.prototype.trim ? String.prototype.trim : strip, - stripTags: stripTags, - stripScripts: stripScripts, - extractScripts: extractScripts, - evalScripts: evalScripts, - escapeHTML: escapeHTML, - unescapeHTML: unescapeHTML, - toQueryParams: toQueryParams, - parseQuery: toQueryParams, - toArray: toArray, - succ: succ, - times: times, - camelize: camelize, - capitalize: capitalize, - underscore: underscore, - dasherize: dasherize, - inspect: inspect, - toJSON: toJSON, - unfilterJSON: unfilterJSON, - isJSON: isJSON, - evalJSON: evalJSON, - include: include, - startsWith: startsWith, - endsWith: endsWith, - empty: empty, - blank: blank, - interpolate: interpolate - }; -})()); - -var Template = Class.create({ - initialize: function(template, pattern) { - this.template = template.toString(); - this.pattern = pattern || Template.Pattern; - }, - - evaluate: function(object) { - if (object && Object.isFunction(object.toTemplateReplacements)) - object = object.toTemplateReplacements(); - - return this.template.gsub(this.pattern, function(match) { - if (object == null) return (match[1] + ''); - - var before = match[1] || ''; - if (before == '\\') return match[2]; - - var ctx = object, expr = match[3]; - var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/; - match = pattern.exec(expr); - if (match == null) return before; - - while (match != null) { - var comp = match[1].startsWith('[') ? match[2].replace(/\\\\]/g, ']') : match[1]; - ctx = ctx[comp]; - if (null == ctx || '' == match[3]) break; - expr = expr.substring('[' == match[3] ? match[1].length : match[0].length); - match = pattern.exec(expr); - } - - return before + String.interpret(ctx); - }); - } -}); -Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; - -var $break = { }; - -var Enumerable = (function() { - function each(iterator, context) { - var index = 0; - try { - this._each(function(value) { - iterator.call(context, value, index++); - }); - } catch (e) { - if (e != $break) throw e; - } - return this; - } - - function eachSlice(number, iterator, context) { - var index = -number, slices = [], array = this.toArray(); - if (number < 1) return array; - while ((index += number) < array.length) - slices.push(array.slice(index, index+number)); - return slices.collect(iterator, context); - } - - function all(iterator, context) { - iterator = iterator || Prototype.K; - var result = true; - this.each(function(value, index) { - result = result && !!iterator.call(context, value, index); - if (!result) throw $break; - }); - return result; - } - - function any(iterator, context) { - iterator = iterator || Prototype.K; - var result = false; - this.each(function(value, index) { - if (result = !!iterator.call(context, value, index)) - throw $break; - }); - return result; - } - - function collect(iterator, context) { - iterator = iterator || Prototype.K; - var results = []; - this.each(function(value, index) { - results.push(iterator.call(context, value, index)); - }); - return results; - } - - function detect(iterator, context) { - var result; - this.each(function(value, index) { - if (iterator.call(context, value, index)) { - result = value; - throw $break; - } - }); - return result; - } - - function findAll(iterator, context) { - var results = []; - this.each(function(value, index) { - if (iterator.call(context, value, index)) - results.push(value); - }); - return results; - } - - function grep(filter, iterator, context) { - iterator = iterator || Prototype.K; - var results = []; - - if (Object.isString(filter)) - filter = new RegExp(RegExp.escape(filter)); - - this.each(function(value, index) { - if (filter.match(value)) - results.push(iterator.call(context, value, index)); - }); - return results; - } - - function include(object) { - if (Object.isFunction(this.indexOf)) - if (this.indexOf(object) != -1) return true; - - var found = false; - this.each(function(value) { - if (value == object) { - found = true; - throw $break; - } - }); - return found; - } - - function inGroupsOf(number, fillWith) { - fillWith = Object.isUndefined(fillWith) ? null : fillWith; - return this.eachSlice(number, function(slice) { - while(slice.length < number) slice.push(fillWith); - return slice; - }); - } - - function inject(memo, iterator, context) { - this.each(function(value, index) { - memo = iterator.call(context, memo, value, index); - }); - return memo; - } - - function invoke(method) { - var args = $A(arguments).slice(1); - return this.map(function(value) { - return value[method].apply(value, args); - }); - } - - function max(iterator, context) { - iterator = iterator || Prototype.K; - var result; - this.each(function(value, index) { - value = iterator.call(context, value, index); - if (result == null || value >= result) - result = value; - }); - return result; - } - - function min(iterator, context) { - iterator = iterator || Prototype.K; - var result; - this.each(function(value, index) { - value = iterator.call(context, value, index); - if (result == null || value < result) - result = value; - }); - return result; - } - - function partition(iterator, context) { - iterator = iterator || Prototype.K; - var trues = [], falses = []; - this.each(function(value, index) { - (iterator.call(context, value, index) ? - trues : falses).push(value); - }); - return [trues, falses]; - } - - function pluck(property) { - var results = []; - this.each(function(value) { - results.push(value[property]); - }); - return results; - } - - function reject(iterator, context) { - var results = []; - this.each(function(value, index) { - if (!iterator.call(context, value, index)) - results.push(value); - }); - return results; - } - - function sortBy(iterator, context) { - return this.map(function(value, index) { - return { - value: value, - criteria: iterator.call(context, value, index) - }; - }).sort(function(left, right) { - var a = left.criteria, b = right.criteria; - return a < b ? -1 : a > b ? 1 : 0; - }).pluck('value'); - } - - function toArray() { - return this.map(); - } - - function zip() { - var iterator = Prototype.K, args = $A(arguments); - if (Object.isFunction(args.last())) - iterator = args.pop(); - - var collections = [this].concat(args).map($A); - return this.map(function(value, index) { - return iterator(collections.pluck(index)); - }); - } - - function size() { - return this.toArray().length; - } - - function inspect() { - return '#'; - } - - - - - - - - - - return { - each: each, - eachSlice: eachSlice, - all: all, - every: all, - any: any, - some: any, - collect: collect, - map: collect, - detect: detect, - findAll: findAll, - select: findAll, - filter: findAll, - grep: grep, - include: include, - member: include, - inGroupsOf: inGroupsOf, - inject: inject, - invoke: invoke, - max: max, - min: min, - partition: partition, - pluck: pluck, - reject: reject, - sortBy: sortBy, - toArray: toArray, - entries: toArray, - zip: zip, - size: size, - inspect: inspect, - find: detect - }; -})(); -function $A(iterable) { - if (!iterable) return []; - if ('toArray' in Object(iterable)) return iterable.toArray(); - var length = iterable.length || 0, results = new Array(length); - while (length--) results[length] = iterable[length]; - return results; -} - -function $w(string) { - if (!Object.isString(string)) return []; - string = string.strip(); - return string ? string.split(/\s+/) : []; -} - -Array.from = $A; - - -(function() { - var arrayProto = Array.prototype, - slice = arrayProto.slice, - _each = arrayProto.forEach; // use native browser JS 1.6 implementation if available - - function each(iterator) { - for (var i = 0, length = this.length; i < length; i++) - iterator(this[i]); - } - if (!_each) _each = each; - - function clear() { - this.length = 0; - return this; - } - - function first() { - return this[0]; - } - - function last() { - return this[this.length - 1]; - } - - function compact() { - return this.select(function(value) { - return value != null; - }); - } - - function flatten() { - return this.inject([], function(array, value) { - if (Object.isArray(value)) - return array.concat(value.flatten()); - array.push(value); - return array; - }); - } - - function without() { - var values = slice.call(arguments, 0); - return this.select(function(value) { - return !values.include(value); - }); - } - - function reverse(inline) { - return (inline !== false ? this : this.toArray())._reverse(); - } - - function uniq(sorted) { - return this.inject([], function(array, value, index) { - if (0 == index || (sorted ? array.last() != value : !array.include(value))) - array.push(value); - return array; - }); - } - - function intersect(array) { - return this.uniq().findAll(function(item) { - return array.detect(function(value) { return item === value }); - }); - } - - - function clone() { - return slice.call(this, 0); - } - - function size() { - return this.length; - } - - function inspect() { - return '[' + this.map(Object.inspect).join(', ') + ']'; - } - - function toJSON() { - var results = []; - this.each(function(object) { - var value = Object.toJSON(object); - if (!Object.isUndefined(value)) results.push(value); - }); - return '[' + results.join(', ') + ']'; - } - - function indexOf(item, i) { - i || (i = 0); - var length = this.length; - if (i < 0) i = length + i; - for (; i < length; i++) - if (this[i] === item) return i; - return -1; - } - - function lastIndexOf(item, i) { - i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1; - var n = this.slice(0, i).reverse().indexOf(item); - return (n < 0) ? n : i - n - 1; - } - - function concat() { - var array = slice.call(this, 0), item; - for (var i = 0, length = arguments.length; i < length; i++) { - item = arguments[i]; - if (Object.isArray(item) && !('callee' in item)) { - for (var j = 0, arrayLength = item.length; j < arrayLength; j++) - array.push(item[j]); - } else { - array.push(item); - } - } - return array; - } - - Object.extend(arrayProto, Enumerable); - - if (!arrayProto._reverse) - arrayProto._reverse = arrayProto.reverse; - - Object.extend(arrayProto, { - _each: _each, - clear: clear, - first: first, - last: last, - compact: compact, - flatten: flatten, - without: without, - reverse: reverse, - uniq: uniq, - intersect: intersect, - clone: clone, - toArray: clone, - size: size, - inspect: inspect, - toJSON: toJSON - }); - - var CONCAT_ARGUMENTS_BUGGY = (function() { - return [].concat(arguments)[0][0] !== 1; - })(1,2) - - if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat; - - if (!arrayProto.indexOf) arrayProto.indexOf = indexOf; - if (!arrayProto.lastIndexOf) arrayProto.lastIndexOf = lastIndexOf; -})(); -function $H(object) { - return new Hash(object); -}; - -var Hash = Class.create(Enumerable, (function() { - function initialize(object) { - this._object = Object.isHash(object) ? object.toObject() : Object.clone(object); - } - - function _each(iterator) { - for (var key in this._object) { - var value = this._object[key], pair = [key, value]; - pair.key = key; - pair.value = value; - iterator(pair); - } - } - - function set(key, value) { - return this._object[key] = value; - } - - function get(key) { - if (this._object[key] !== Object.prototype[key]) - return this._object[key]; - } - - function unset(key) { - var value = this._object[key]; - delete this._object[key]; - return value; - } - - function toObject() { - return Object.clone(this._object); - } - - function keys() { - return this.pluck('key'); - } - - function values() { - return this.pluck('value'); - } - - function index(value) { - var match = this.detect(function(pair) { - return pair.value === value; - }); - return match && match.key; - } - - function merge(object) { - return this.clone().update(object); - } - - function update(object) { - return new Hash(object).inject(this, function(result, pair) { - result.set(pair.key, pair.value); - return result; - }); - } - - function toQueryPair(key, value) { - if (Object.isUndefined(value)) return key; - return key + '=' + encodeURIComponent(String.interpret(value)); - } - - function toQueryString() { - return this.inject([], function(results, pair) { - var key = encodeURIComponent(pair.key), values = pair.value; - - if (values && typeof values == 'object') { - if (Object.isArray(values)) - return results.concat(values.map(toQueryPair.curry(key))); - } else results.push(toQueryPair(key, values)); - return results; - }).join('&'); - } - - function inspect() { - return '#'; - } - - function toJSON() { - return Object.toJSON(this.toObject()); - } - - function clone() { - return new Hash(this); - } - - return { - initialize: initialize, - _each: _each, - set: set, - get: get, - unset: unset, - toObject: toObject, - toTemplateReplacements: toObject, - keys: keys, - values: values, - index: index, - merge: merge, - update: update, - toQueryString: toQueryString, - inspect: inspect, - toJSON: toJSON, - clone: clone - }; -})()); - -Hash.from = $H; -Object.extend(Number.prototype, (function() { - function toColorPart() { - return this.toPaddedString(2, 16); - } - - function succ() { - return this + 1; - } - - function times(iterator, context) { - $R(0, this, true).each(iterator, context); - return this; - } - - function toPaddedString(length, radix) { - var string = this.toString(radix || 10); - return '0'.times(length - string.length) + string; - } - - function toJSON() { - return isFinite(this) ? this.toString() : 'null'; - } - - function abs() { - return Math.abs(this); - } - - function round() { - return Math.round(this); - } - - function ceil() { - return Math.ceil(this); - } - - function floor() { - return Math.floor(this); - } - - return { - toColorPart: toColorPart, - succ: succ, - times: times, - toPaddedString: toPaddedString, - toJSON: toJSON, - abs: abs, - round: round, - ceil: ceil, - floor: floor - }; -})()); - -function $R(start, end, exclusive) { - return new ObjectRange(start, end, exclusive); -} - -var ObjectRange = Class.create(Enumerable, (function() { - function initialize(start, end, exclusive) { - this.start = start; - this.end = end; - this.exclusive = exclusive; - } - - function _each(iterator) { - var value = this.start; - while (this.include(value)) { - iterator(value); - value = value.succ(); - } - } - - function include(value) { - if (value < this.start) - return false; - if (this.exclusive) - return value < this.end; - return value <= this.end; - } - - return { - initialize: initialize, - _each: _each, - include: include - }; -})()); - - - -var Ajax = { - getTransport: function() { - return Try.these( - function() {return new XMLHttpRequest()}, - function() {return new ActiveXObject('Msxml2.XMLHTTP')}, - function() {return new ActiveXObject('Microsoft.XMLHTTP')} - ) || false; - }, - - activeRequestCount: 0 -}; - -Ajax.Responders = { - responders: [], - - _each: function(iterator) { - this.responders._each(iterator); - }, - - register: function(responder) { - if (!this.include(responder)) - this.responders.push(responder); - }, - - unregister: function(responder) { - this.responders = this.responders.without(responder); - }, - - dispatch: function(callback, request, transport, json) { - this.each(function(responder) { - if (Object.isFunction(responder[callback])) { - try { - responder[callback].apply(responder, [request, transport, json]); - } catch (e) { } - } - }); - } -}; - -Object.extend(Ajax.Responders, Enumerable); - -Ajax.Responders.register({ - onCreate: function() { Ajax.activeRequestCount++ }, - onComplete: function() { Ajax.activeRequestCount-- } -}); -Ajax.Base = Class.create({ - initialize: function(options) { - this.options = { - method: 'post', - asynchronous: true, - contentType: 'application/x-www-form-urlencoded', - encoding: 'UTF-8', - parameters: '', - evalJSON: true, - evalJS: true - }; - Object.extend(this.options, options || { }); - - this.options.method = this.options.method.toLowerCase(); - - if (Object.isString(this.options.parameters)) - this.options.parameters = this.options.parameters.toQueryParams(); - else if (Object.isHash(this.options.parameters)) - this.options.parameters = this.options.parameters.toObject(); - } -}); -Ajax.Request = Class.create(Ajax.Base, { - _complete: false, - - initialize: function($super, url, options) { - $super(options); - this.transport = Ajax.getTransport(); - this.request(url); - }, - - request: function(url) { - this.url = url; - this.method = this.options.method; - var params = Object.clone(this.options.parameters); - - if (!['get', 'post'].include(this.method)) { - params['_method'] = this.method; - this.method = 'post'; - } - - this.parameters = params; - - if (params = Object.toQueryString(params)) { - if (this.method == 'get') - this.url += (this.url.include('?') ? '&' : '?') + params; - else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) - params += '&_='; - } - - try { - var response = new Ajax.Response(this); - if (this.options.onCreate) this.options.onCreate(response); - Ajax.Responders.dispatch('onCreate', this, response); - - this.transport.open(this.method.toUpperCase(), this.url, - this.options.asynchronous); - - if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1); - - this.transport.onreadystatechange = this.onStateChange.bind(this); - this.setRequestHeaders(); - - this.body = this.method == 'post' ? (this.options.postBody || params) : null; - this.transport.send(this.body); - - /* Force Firefox to handle ready state 4 for synchronous requests */ - if (!this.options.asynchronous && this.transport.overrideMimeType) - this.onStateChange(); - - } - catch (e) { - this.dispatchException(e); - } - }, - - onStateChange: function() { - var readyState = this.transport.readyState; - if (readyState > 1 && !((readyState == 4) && this._complete)) - this.respondToReadyState(this.transport.readyState); - }, - - setRequestHeaders: function() { - var headers = { - 'X-Requested-With': 'XMLHttpRequest', - 'X-Prototype-Version': Prototype.Version, - 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' - }; - - if (this.method == 'post') { - headers['Content-type'] = this.options.contentType + - (this.options.encoding ? '; charset=' + this.options.encoding : ''); - - /* Force "Connection: close" for older Mozilla browsers to work - * around a bug where XMLHttpRequest sends an incorrect - * Content-length header. See Mozilla Bugzilla #246651. - */ - if (this.transport.overrideMimeType && - (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) - headers['Connection'] = 'close'; - } - - if (typeof this.options.requestHeaders == 'object') { - var extras = this.options.requestHeaders; - - if (Object.isFunction(extras.push)) - for (var i = 0, length = extras.length; i < length; i += 2) - headers[extras[i]] = extras[i+1]; - else - $H(extras).each(function(pair) { headers[pair.key] = pair.value }); - } - - for (var name in headers) - this.transport.setRequestHeader(name, headers[name]); - }, - - success: function() { - var status = this.getStatus(); - return !status || (status >= 200 && status < 300); - }, - - getStatus: function() { - try { - return this.transport.status || 0; - } catch (e) { return 0 } - }, - - respondToReadyState: function(readyState) { - var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this); - - if (state == 'Complete') { - try { - this._complete = true; - (this.options['on' + response.status] - || this.options['on' + (this.success() ? 'Success' : 'Failure')] - || Prototype.emptyFunction)(response, response.headerJSON); - } catch (e) { - this.dispatchException(e); - } - - var contentType = response.getHeader('Content-type'); - if (this.options.evalJS == 'force' - || (this.options.evalJS && this.isSameOrigin() && contentType - && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i))) - this.evalResponse(); - } - - try { - (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON); - Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON); - } catch (e) { - this.dispatchException(e); - } - - if (state == 'Complete') { - this.transport.onreadystatechange = Prototype.emptyFunction; - } - }, - - isSameOrigin: function() { - var m = this.url.match(/^\s*https?:\/\/[^\/]*/); - return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({ - protocol: location.protocol, - domain: document.domain, - port: location.port ? ':' + location.port : '' - })); - }, - - getHeader: function(name) { - try { - return this.transport.getResponseHeader(name) || null; - } catch (e) { return null; } - }, - - evalResponse: function() { - try { - return eval((this.transport.responseText || '').unfilterJSON()); - } catch (e) { - this.dispatchException(e); - } - }, - - dispatchException: function(exception) { - (this.options.onException || Prototype.emptyFunction)(this, exception); - Ajax.Responders.dispatch('onException', this, exception); - } -}); - -Ajax.Request.Events = - ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; - - - - - - - - -Ajax.Response = Class.create({ - initialize: function(request){ - this.request = request; - var transport = this.transport = request.transport, - readyState = this.readyState = transport.readyState; - - if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) { - this.status = this.getStatus(); - this.statusText = this.getStatusText(); - this.responseText = String.interpret(transport.responseText); - this.headerJSON = this._getHeaderJSON(); - } - - if(readyState == 4) { - var xml = transport.responseXML; - this.responseXML = Object.isUndefined(xml) ? null : xml; - this.responseJSON = this._getResponseJSON(); - } - }, - - status: 0, - - statusText: '', - - getStatus: Ajax.Request.prototype.getStatus, - - getStatusText: function() { - try { - return this.transport.statusText || ''; - } catch (e) { return '' } - }, - - getHeader: Ajax.Request.prototype.getHeader, - - getAllHeaders: function() { - try { - return this.getAllResponseHeaders(); - } catch (e) { return null } - }, - - getResponseHeader: function(name) { - return this.transport.getResponseHeader(name); - }, - - getAllResponseHeaders: function() { - return this.transport.getAllResponseHeaders(); - }, - - _getHeaderJSON: function() { - var json = this.getHeader('X-JSON'); - if (!json) return null; - json = decodeURIComponent(escape(json)); - try { - return json.evalJSON(this.request.options.sanitizeJSON || - !this.request.isSameOrigin()); - } catch (e) { - this.request.dispatchException(e); - } - }, - - _getResponseJSON: function() { - var options = this.request.options; - if (!options.evalJSON || (options.evalJSON != 'force' && - !(this.getHeader('Content-type') || '').include('application/json')) || - this.responseText.blank()) - return null; - try { - return this.responseText.evalJSON(options.sanitizeJSON || - !this.request.isSameOrigin()); - } catch (e) { - this.request.dispatchException(e); - } - } -}); - -Ajax.Updater = Class.create(Ajax.Request, { - initialize: function($super, container, url, options) { - this.container = { - success: (container.success || container), - failure: (container.failure || (container.success ? null : container)) - }; - - options = Object.clone(options); - var onComplete = options.onComplete; - options.onComplete = (function(response, json) { - this.updateContent(response.responseText); - if (Object.isFunction(onComplete)) onComplete(response, json); - }).bind(this); - - $super(url, options); - }, - - updateContent: function(responseText) { - var receiver = this.container[this.success() ? 'success' : 'failure'], - options = this.options; - - if (!options.evalScripts) responseText = responseText.stripScripts(); - - if (receiver = $(receiver)) { - if (options.insertion) { - if (Object.isString(options.insertion)) { - var insertion = { }; insertion[options.insertion] = responseText; - receiver.insert(insertion); - } - else options.insertion(receiver, responseText); - } - else receiver.update(responseText); - } - } -}); - -Ajax.PeriodicalUpdater = Class.create(Ajax.Base, { - initialize: function($super, container, url, options) { - $super(options); - this.onComplete = this.options.onComplete; - - this.frequency = (this.options.frequency || 2); - this.decay = (this.options.decay || 1); - - this.updater = { }; - this.container = container; - this.url = url; - - this.start(); - }, - - start: function() { - this.options.onComplete = this.updateComplete.bind(this); - this.onTimerEvent(); - }, - - stop: function() { - this.updater.options.onComplete = undefined; - clearTimeout(this.timer); - (this.onComplete || Prototype.emptyFunction).apply(this, arguments); - }, - - updateComplete: function(response) { - if (this.options.decay) { - this.decay = (response.responseText == this.lastText ? - this.decay * this.options.decay : 1); - - this.lastText = response.responseText; - } - this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency); - }, - - onTimerEvent: function() { - this.updater = new Ajax.Updater(this.container, this.url, this.options); - } -}); - - - -function $(element) { - if (arguments.length > 1) { - for (var i = 0, elements = [], length = arguments.length; i < length; i++) - elements.push($(arguments[i])); - return elements; - } - if (Object.isString(element)) - element = document.getElementById(element); - return Element.extend(element); -} - -if (Prototype.BrowserFeatures.XPath) { - document._getElementsByXPath = function(expression, parentElement) { - var results = []; - var query = document.evaluate(expression, $(parentElement) || document, - null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); - for (var i = 0, length = query.snapshotLength; i < length; i++) - results.push(Element.extend(query.snapshotItem(i))); - return results; - }; -} - -/*--------------------------------------------------------------------------*/ - -if (!window.Node) var Node = { }; - -if (!Node.ELEMENT_NODE) { - Object.extend(Node, { - ELEMENT_NODE: 1, - ATTRIBUTE_NODE: 2, - TEXT_NODE: 3, - CDATA_SECTION_NODE: 4, - ENTITY_REFERENCE_NODE: 5, - ENTITY_NODE: 6, - PROCESSING_INSTRUCTION_NODE: 7, - COMMENT_NODE: 8, - DOCUMENT_NODE: 9, - DOCUMENT_TYPE_NODE: 10, - DOCUMENT_FRAGMENT_NODE: 11, - NOTATION_NODE: 12 - }); -} - - -(function(global) { - - var SETATTRIBUTE_IGNORES_NAME = (function(){ - var elForm = document.createElement("form"); - var elInput = document.createElement("input"); - var root = document.documentElement; - elInput.setAttribute("name", "test"); - elForm.appendChild(elInput); - root.appendChild(elForm); - var isBuggy = elForm.elements - ? (typeof elForm.elements.test == "undefined") - : null; - root.removeChild(elForm); - elForm = elInput = null; - return isBuggy; - })(); - - var element = global.Element; - global.Element = function(tagName, attributes) { - attributes = attributes || { }; - tagName = tagName.toLowerCase(); - var cache = Element.cache; - if (SETATTRIBUTE_IGNORES_NAME && attributes.name) { - tagName = '<' + tagName + ' name="' + attributes.name + '">'; - delete attributes.name; - return Element.writeAttribute(document.createElement(tagName), attributes); - } - if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName)); - return Element.writeAttribute(cache[tagName].cloneNode(false), attributes); - }; - Object.extend(global.Element, element || { }); - if (element) global.Element.prototype = element.prototype; -})(this); - -Element.cache = { }; -Element.idCounter = 1; - -Element.Methods = { - visible: function(element) { - return $(element).style.display != 'none'; - }, - - toggle: function(element) { - element = $(element); - Element[Element.visible(element) ? 'hide' : 'show'](element); - return element; - }, - - - hide: function(element) { - element = $(element); - element.style.display = 'none'; - return element; - }, - - show: function(element) { - element = $(element); - element.style.display = ''; - return element; - }, - - remove: function(element) { - element = $(element); - element.parentNode.removeChild(element); - return element; - }, - - update: (function(){ - - var SELECT_ELEMENT_INNERHTML_BUGGY = (function(){ - var el = document.createElement("select"), - isBuggy = true; - el.innerHTML = ""; - if (el.options && el.options[0]) { - isBuggy = el.options[0].nodeName.toUpperCase() !== "OPTION"; - } - el = null; - return isBuggy; - })(); - - var TABLE_ELEMENT_INNERHTML_BUGGY = (function(){ - try { - var el = document.createElement("table"); - if (el && el.tBodies) { - el.innerHTML = "test"; - var isBuggy = typeof el.tBodies[0] == "undefined"; - el = null; - return isBuggy; - } - } catch (e) { - return true; - } - })(); - - var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () { - var s = document.createElement("script"), - isBuggy = false; - try { - s.appendChild(document.createTextNode("")); - isBuggy = !s.firstChild || - s.firstChild && s.firstChild.nodeType !== 3; - } catch (e) { - isBuggy = true; - } - s = null; - return isBuggy; - })(); - - function update(element, content) { - element = $(element); - - if (content && content.toElement) - content = content.toElement(); - - if (Object.isElement(content)) - return element.update().insert(content); - - content = Object.toHTML(content); - - var tagName = element.tagName.toUpperCase(); - - if (tagName === 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING) { - element.text = content; - return element; - } - - if (SELECT_ELEMENT_INNERHTML_BUGGY || TABLE_ELEMENT_INNERHTML_BUGGY) { - if (tagName in Element._insertionTranslations.tags) { - while (element.firstChild) { - element.removeChild(element.firstChild); - } - Element._getContentFromAnonymousElement(tagName, content.stripScripts()) - .each(function(node) { - element.appendChild(node) - }); - } - else { - element.innerHTML = content.stripScripts(); - } - } - else { - element.innerHTML = content.stripScripts(); - } - - content.evalScripts.bind(content).defer(); - return element; - } - - return update; - })(), - - replace: function(element, content) { - element = $(element); - if (content && content.toElement) content = content.toElement(); - else if (!Object.isElement(content)) { - content = Object.toHTML(content); - var range = element.ownerDocument.createRange(); - range.selectNode(element); - content.evalScripts.bind(content).defer(); - content = range.createContextualFragment(content.stripScripts()); - } - element.parentNode.replaceChild(content, element); - return element; - }, - - insert: function(element, insertions) { - element = $(element); - - if (Object.isString(insertions) || Object.isNumber(insertions) || - Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML))) - insertions = {bottom:insertions}; - - var content, insert, tagName, childNodes; - - for (var position in insertions) { - content = insertions[position]; - position = position.toLowerCase(); - insert = Element._insertionTranslations[position]; - - if (content && content.toElement) content = content.toElement(); - if (Object.isElement(content)) { - insert(element, content); - continue; - } - - content = Object.toHTML(content); - - tagName = ((position == 'before' || position == 'after') - ? element.parentNode : element).tagName.toUpperCase(); - - childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); - - if (position == 'top' || position == 'after') childNodes.reverse(); - childNodes.each(insert.curry(element)); - - content.evalScripts.bind(content).defer(); - } - - return element; - }, - - wrap: function(element, wrapper, attributes) { - element = $(element); - if (Object.isElement(wrapper)) - $(wrapper).writeAttribute(attributes || { }); - else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes); - else wrapper = new Element('div', wrapper); - if (element.parentNode) - element.parentNode.replaceChild(wrapper, element); - wrapper.appendChild(element); - return wrapper; - }, - - inspect: function(element) { - element = $(element); - var result = '<' + element.tagName.toLowerCase(); - $H({'id': 'id', 'className': 'class'}).each(function(pair) { - var property = pair.first(), attribute = pair.last(); - var value = (element[property] || '').toString(); - if (value) result += ' ' + attribute + '=' + value.inspect(true); - }); - return result + '>'; - }, - - recursivelyCollect: function(element, property) { - element = $(element); - var elements = []; - while (element = element[property]) - if (element.nodeType == 1) - elements.push(Element.extend(element)); - return elements; - }, - - ancestors: function(element) { - return Element.recursivelyCollect(element, 'parentNode'); - }, - - descendants: function(element) { - return Element.select(element, "*"); - }, - - firstDescendant: function(element) { - element = $(element).firstChild; - while (element && element.nodeType != 1) element = element.nextSibling; - return $(element); - }, - - immediateDescendants: function(element) { - if (!(element = $(element).firstChild)) return []; - while (element && element.nodeType != 1) element = element.nextSibling; - if (element) return [element].concat($(element).nextSiblings()); - return []; - }, - - previousSiblings: function(element) { - return Element.recursivelyCollect(element, 'previousSibling'); - }, - - nextSiblings: function(element) { - return Element.recursivelyCollect(element, 'nextSibling'); - }, - - siblings: function(element) { - element = $(element); - return Element.previousSiblings(element).reverse() - .concat(Element.nextSiblings(element)); - }, - - match: function(element, selector) { - if (Object.isString(selector)) - selector = new Selector(selector); - return selector.match($(element)); - }, - - up: function(element, expression, index) { - element = $(element); - if (arguments.length == 1) return $(element.parentNode); - var ancestors = Element.ancestors(element); - return Object.isNumber(expression) ? ancestors[expression] : - Selector.findElement(ancestors, expression, index); - }, - - down: function(element, expression, index) { - element = $(element); - if (arguments.length == 1) return Element.firstDescendant(element); - return Object.isNumber(expression) ? Element.descendants(element)[expression] : - Element.select(element, expression)[index || 0]; - }, - - previous: function(element, expression, index) { - element = $(element); - if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element)); - var previousSiblings = Element.previousSiblings(element); - return Object.isNumber(expression) ? previousSiblings[expression] : - Selector.findElement(previousSiblings, expression, index); - }, - - next: function(element, expression, index) { - element = $(element); - if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element)); - var nextSiblings = Element.nextSiblings(element); - return Object.isNumber(expression) ? nextSiblings[expression] : - Selector.findElement(nextSiblings, expression, index); - }, - - - select: function(element) { - var args = Array.prototype.slice.call(arguments, 1); - return Selector.findChildElements(element, args); - }, - - adjacent: function(element) { - var args = Array.prototype.slice.call(arguments, 1); - return Selector.findChildElements(element.parentNode, args).without(element); - }, - - identify: function(element) { - element = $(element); - var id = Element.readAttribute(element, 'id'); - if (id) return id; - do { id = 'anonymous_element_' + Element.idCounter++ } while ($(id)); - Element.writeAttribute(element, 'id', id); - return id; - }, - - readAttribute: function(element, name) { - element = $(element); - if (Prototype.Browser.IE) { - var t = Element._attributeTranslations.read; - if (t.values[name]) return t.values[name](element, name); - if (t.names[name]) name = t.names[name]; - if (name.include(':')) { - return (!element.attributes || !element.attributes[name]) ? null : - element.attributes[name].value; - } - } - return element.getAttribute(name); - }, - - writeAttribute: function(element, name, value) { - element = $(element); - var attributes = { }, t = Element._attributeTranslations.write; - - if (typeof name == 'object') attributes = name; - else attributes[name] = Object.isUndefined(value) ? true : value; - - for (var attr in attributes) { - name = t.names[attr] || attr; - value = attributes[attr]; - if (t.values[attr]) name = t.values[attr](element, value); - if (value === false || value === null) - element.removeAttribute(name); - else if (value === true) - element.setAttribute(name, name); - else element.setAttribute(name, value); - } - return element; - }, - - getHeight: function(element) { - return Element.getDimensions(element).height; - }, - - getWidth: function(element) { - return Element.getDimensions(element).width; - }, - - classNames: function(element) { - return new Element.ClassNames(element); - }, - - hasClassName: function(element, className) { - if (!(element = $(element))) return; - var elementClassName = element.className; - return (elementClassName.length > 0 && (elementClassName == className || - new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName))); - }, - - addClassName: function(element, className) { - if (!(element = $(element))) return; - if (!Element.hasClassName(element, className)) - element.className += (element.className ? ' ' : '') + className; - return element; - }, - - removeClassName: function(element, className) { - if (!(element = $(element))) return; - element.className = element.className.replace( - new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip(); - return element; - }, - - toggleClassName: function(element, className) { - if (!(element = $(element))) return; - return Element[Element.hasClassName(element, className) ? - 'removeClassName' : 'addClassName'](element, className); - }, - - cleanWhitespace: function(element) { - element = $(element); - var node = element.firstChild; - while (node) { - var nextNode = node.nextSibling; - if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) - element.removeChild(node); - node = nextNode; - } - return element; - }, - - empty: function(element) { - return $(element).innerHTML.blank(); - }, - - descendantOf: function(element, ancestor) { - element = $(element), ancestor = $(ancestor); - - if (element.compareDocumentPosition) - return (element.compareDocumentPosition(ancestor) & 8) === 8; - - if (ancestor.contains) - return ancestor.contains(element) && ancestor !== element; - - while (element = element.parentNode) - if (element == ancestor) return true; - - return false; - }, - - scrollTo: function(element) { - element = $(element); - var pos = Element.cumulativeOffset(element); - window.scrollTo(pos[0], pos[1]); - return element; - }, - - getStyle: function(element, style) { - element = $(element); - style = style == 'float' ? 'cssFloat' : style.camelize(); - var value = element.style[style]; - if (!value || value == 'auto') { - var css = document.defaultView.getComputedStyle(element, null); - value = css ? css[style] : null; - } - if (style == 'opacity') return value ? parseFloat(value) : 1.0; - return value == 'auto' ? null : value; - }, - - getOpacity: function(element) { - return $(element).getStyle('opacity'); - }, - - setStyle: function(element, styles) { - element = $(element); - var elementStyle = element.style, match; - if (Object.isString(styles)) { - element.style.cssText += ';' + styles; - return styles.include('opacity') ? - element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element; - } - for (var property in styles) - if (property == 'opacity') element.setOpacity(styles[property]); - else - elementStyle[(property == 'float' || property == 'cssFloat') ? - (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') : - property] = styles[property]; - - return element; - }, - - setOpacity: function(element, value) { - element = $(element); - element.style.opacity = (value == 1 || value === '') ? '' : - (value < 0.00001) ? 0 : value; - return element; - }, - - getDimensions: function(element) { - element = $(element); - var display = Element.getStyle(element, 'display'); - if (display != 'none' && display != null) // Safari bug - return {width: element.offsetWidth, height: element.offsetHeight}; - - var els = element.style; - var originalVisibility = els.visibility; - var originalPosition = els.position; - var originalDisplay = els.display; - els.visibility = 'hidden'; - if (originalPosition != 'fixed') // Switching fixed to absolute causes issues in Safari - els.position = 'absolute'; - els.display = 'block'; - var originalWidth = element.clientWidth; - var originalHeight = element.clientHeight; - els.display = originalDisplay; - els.position = originalPosition; - els.visibility = originalVisibility; - return {width: originalWidth, height: originalHeight}; - }, - - makePositioned: function(element) { - element = $(element); - var pos = Element.getStyle(element, 'position'); - if (pos == 'static' || !pos) { - element._madePositioned = true; - element.style.position = 'relative'; - if (Prototype.Browser.Opera) { - element.style.top = 0; - element.style.left = 0; - } - } - return element; - }, - - undoPositioned: function(element) { - element = $(element); - if (element._madePositioned) { - element._madePositioned = undefined; - element.style.position = - element.style.top = - element.style.left = - element.style.bottom = - element.style.right = ''; - } - return element; - }, - - makeClipping: function(element) { - element = $(element); - if (element._overflow) return element; - element._overflow = Element.getStyle(element, 'overflow') || 'auto'; - if (element._overflow !== 'hidden') - element.style.overflow = 'hidden'; - return element; - }, - - undoClipping: function(element) { - element = $(element); - if (!element._overflow) return element; - element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; - element._overflow = null; - return element; - }, - - cumulativeOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - } while (element); - return Element._returnOffset(valueL, valueT); - }, - - positionedOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - if (element) { - if (element.tagName.toUpperCase() == 'BODY') break; - var p = Element.getStyle(element, 'position'); - if (p !== 'static') break; - } - } while (element); - return Element._returnOffset(valueL, valueT); - }, - - absolutize: function(element) { - element = $(element); - if (Element.getStyle(element, 'position') == 'absolute') return element; - - var offsets = Element.positionedOffset(element); - var top = offsets[1]; - var left = offsets[0]; - var width = element.clientWidth; - var height = element.clientHeight; - - element._originalLeft = left - parseFloat(element.style.left || 0); - element._originalTop = top - parseFloat(element.style.top || 0); - element._originalWidth = element.style.width; - element._originalHeight = element.style.height; - - element.style.position = 'absolute'; - element.style.top = top + 'px'; - element.style.left = left + 'px'; - element.style.width = width + 'px'; - element.style.height = height + 'px'; - return element; - }, - - relativize: function(element) { - element = $(element); - if (Element.getStyle(element, 'position') == 'relative') return element; - - element.style.position = 'relative'; - var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); - var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); - - element.style.top = top + 'px'; - element.style.left = left + 'px'; - element.style.height = element._originalHeight; - element.style.width = element._originalWidth; - return element; - }, - - cumulativeScrollOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.scrollTop || 0; - valueL += element.scrollLeft || 0; - element = element.parentNode; - } while (element); - return Element._returnOffset(valueL, valueT); - }, - - getOffsetParent: function(element) { - if (element.offsetParent) return $(element.offsetParent); - if (element == document.body) return $(element); - - while ((element = element.parentNode) && element != document.body) - if (Element.getStyle(element, 'position') != 'static') - return $(element); - - return $(document.body); - }, - - viewportOffset: function(forElement) { - var valueT = 0, valueL = 0; - - var element = forElement; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - - if (element.offsetParent == document.body && - Element.getStyle(element, 'position') == 'absolute') break; - - } while (element = element.offsetParent); - - element = forElement; - do { - if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) { - valueT -= element.scrollTop || 0; - valueL -= element.scrollLeft || 0; - } - } while (element = element.parentNode); - - return Element._returnOffset(valueL, valueT); - }, - - clonePosition: function(element, source) { - var options = Object.extend({ - setLeft: true, - setTop: true, - setWidth: true, - setHeight: true, - offsetTop: 0, - offsetLeft: 0 - }, arguments[2] || { }); - - source = $(source); - var p = Element.viewportOffset(source); - - element = $(element); - var delta = [0, 0]; - var parent = null; - if (Element.getStyle(element, 'position') == 'absolute') { - parent = Element.getOffsetParent(element); - delta = Element.viewportOffset(parent); - } - - if (parent == document.body) { - delta[0] -= document.body.offsetLeft; - delta[1] -= document.body.offsetTop; - } - - if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; - if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; - if (options.setWidth) element.style.width = source.offsetWidth + 'px'; - if (options.setHeight) element.style.height = source.offsetHeight + 'px'; - return element; - } -}; - -Object.extend(Element.Methods, { - getElementsBySelector: Element.Methods.select, - - childElements: Element.Methods.immediateDescendants -}); - -Element._attributeTranslations = { - write: { - names: { - className: 'class', - htmlFor: 'for' - }, - values: { } - } -}; - -if (Prototype.Browser.Opera) { - Element.Methods.getStyle = Element.Methods.getStyle.wrap( - function(proceed, element, style) { - switch (style) { - case 'left': case 'top': case 'right': case 'bottom': - if (proceed(element, 'position') === 'static') return null; - case 'height': case 'width': - if (!Element.visible(element)) return null; - - var dim = parseInt(proceed(element, style), 10); - - if (dim !== element['offset' + style.capitalize()]) - return dim + 'px'; - - var properties; - if (style === 'height') { - properties = ['border-top-width', 'padding-top', - 'padding-bottom', 'border-bottom-width']; - } - else { - properties = ['border-left-width', 'padding-left', - 'padding-right', 'border-right-width']; - } - return properties.inject(dim, function(memo, property) { - var val = proceed(element, property); - return val === null ? memo : memo - parseInt(val, 10); - }) + 'px'; - default: return proceed(element, style); - } - } - ); - - Element.Methods.readAttribute = Element.Methods.readAttribute.wrap( - function(proceed, element, attribute) { - if (attribute === 'title') return element.title; - return proceed(element, attribute); - } - ); -} - -else if (Prototype.Browser.IE) { - Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap( - function(proceed, element) { - element = $(element); - try { element.offsetParent } - catch(e) { return $(document.body) } - var position = element.getStyle('position'); - if (position !== 'static') return proceed(element); - element.setStyle({ position: 'relative' }); - var value = proceed(element); - element.setStyle({ position: position }); - return value; - } - ); - - $w('positionedOffset viewportOffset').each(function(method) { - Element.Methods[method] = Element.Methods[method].wrap( - function(proceed, element) { - element = $(element); - try { element.offsetParent } - catch(e) { return Element._returnOffset(0,0) } - var position = element.getStyle('position'); - if (position !== 'static') return proceed(element); - var offsetParent = element.getOffsetParent(); - if (offsetParent && offsetParent.getStyle('position') === 'fixed') - offsetParent.setStyle({ zoom: 1 }); - element.setStyle({ position: 'relative' }); - var value = proceed(element); - element.setStyle({ position: position }); - return value; - } - ); - }); - - Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap( - function(proceed, element) { - try { element.offsetParent } - catch(e) { return Element._returnOffset(0,0) } - return proceed(element); - } - ); - - Element.Methods.getStyle = function(element, style) { - element = $(element); - style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); - var value = element.style[style]; - if (!value && element.currentStyle) value = element.currentStyle[style]; - - if (style == 'opacity') { - if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) - if (value[1]) return parseFloat(value[1]) / 100; - return 1.0; - } - - if (value == 'auto') { - if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none')) - return element['offset' + style.capitalize()] + 'px'; - return null; - } - return value; - }; - - Element.Methods.setOpacity = function(element, value) { - function stripAlpha(filter){ - return filter.replace(/alpha\([^\)]*\)/gi,''); - } - element = $(element); - var currentStyle = element.currentStyle; - if ((currentStyle && !currentStyle.hasLayout) || - (!currentStyle && element.style.zoom == 'normal')) - element.style.zoom = 1; - - var filter = element.getStyle('filter'), style = element.style; - if (value == 1 || value === '') { - (filter = stripAlpha(filter)) ? - style.filter = filter : style.removeAttribute('filter'); - return element; - } else if (value < 0.00001) value = 0; - style.filter = stripAlpha(filter) + - 'alpha(opacity=' + (value * 100) + ')'; - return element; - }; - - Element._attributeTranslations = (function(){ - - var classProp = 'className'; - var forProp = 'for'; - - var el = document.createElement('div'); - - el.setAttribute(classProp, 'x'); - - if (el.className !== 'x') { - el.setAttribute('class', 'x'); - if (el.className === 'x') { - classProp = 'class'; - } - } - el = null; - - el = document.createElement('label'); - el.setAttribute(forProp, 'x'); - if (el.htmlFor !== 'x') { - el.setAttribute('htmlFor', 'x'); - if (el.htmlFor === 'x') { - forProp = 'htmlFor'; - } - } - el = null; - - return { - read: { - names: { - 'class': classProp, - 'className': classProp, - 'for': forProp, - 'htmlFor': forProp - }, - values: { - _getAttr: function(element, attribute) { - return element.getAttribute(attribute); - }, - _getAttr2: function(element, attribute) { - return element.getAttribute(attribute, 2); - }, - _getAttrNode: function(element, attribute) { - var node = element.getAttributeNode(attribute); - return node ? node.value : ""; - }, - _getEv: (function(){ - - var el = document.createElement('div'); - el.onclick = Prototype.emptyFunction; - var value = el.getAttribute('onclick'); - var f; - - if (String(value).indexOf('{') > -1) { - f = function(element, attribute) { - attribute = element.getAttribute(attribute); - if (!attribute) return null; - attribute = attribute.toString(); - attribute = attribute.split('{')[1]; - attribute = attribute.split('}')[0]; - return attribute.strip(); - }; - } - else if (value === '') { - f = function(element, attribute) { - attribute = element.getAttribute(attribute); - if (!attribute) return null; - return attribute.strip(); - }; - } - el = null; - return f; - })(), - _flag: function(element, attribute) { - return $(element).hasAttribute(attribute) ? attribute : null; - }, - style: function(element) { - return element.style.cssText.toLowerCase(); - }, - title: function(element) { - return element.title; - } - } - } - } - })(); - - Element._attributeTranslations.write = { - names: Object.extend({ - cellpadding: 'cellPadding', - cellspacing: 'cellSpacing' - }, Element._attributeTranslations.read.names), - values: { - checked: function(element, value) { - element.checked = !!value; - }, - - style: function(element, value) { - element.style.cssText = value ? value : ''; - } - } - }; - - Element._attributeTranslations.has = {}; - - $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' + - 'encType maxLength readOnly longDesc frameBorder').each(function(attr) { - Element._attributeTranslations.write.names[attr.toLowerCase()] = attr; - Element._attributeTranslations.has[attr.toLowerCase()] = attr; - }); - - (function(v) { - Object.extend(v, { - href: v._getAttr2, - src: v._getAttr2, - type: v._getAttr, - action: v._getAttrNode, - disabled: v._flag, - checked: v._flag, - readonly: v._flag, - multiple: v._flag, - onload: v._getEv, - onunload: v._getEv, - onclick: v._getEv, - ondblclick: v._getEv, - onmousedown: v._getEv, - onmouseup: v._getEv, - onmouseover: v._getEv, - onmousemove: v._getEv, - onmouseout: v._getEv, - onfocus: v._getEv, - onblur: v._getEv, - onkeypress: v._getEv, - onkeydown: v._getEv, - onkeyup: v._getEv, - onsubmit: v._getEv, - onreset: v._getEv, - onselect: v._getEv, - onchange: v._getEv - }); - })(Element._attributeTranslations.read.values); - - if (Prototype.BrowserFeatures.ElementExtensions) { - (function() { - function _descendants(element) { - var nodes = element.getElementsByTagName('*'), results = []; - for (var i = 0, node; node = nodes[i]; i++) - if (node.tagName !== "!") // Filter out comment nodes. - results.push(node); - return results; - } - - Element.Methods.down = function(element, expression, index) { - element = $(element); - if (arguments.length == 1) return element.firstDescendant(); - return Object.isNumber(expression) ? _descendants(element)[expression] : - Element.select(element, expression)[index || 0]; - } - })(); - } - -} - -else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) { - Element.Methods.setOpacity = function(element, value) { - element = $(element); - element.style.opacity = (value == 1) ? 0.999999 : - (value === '') ? '' : (value < 0.00001) ? 0 : value; - return element; - }; -} - -else if (Prototype.Browser.WebKit) { - Element.Methods.setOpacity = function(element, value) { - element = $(element); - element.style.opacity = (value == 1 || value === '') ? '' : - (value < 0.00001) ? 0 : value; - - if (value == 1) - if(element.tagName.toUpperCase() == 'IMG' && element.width) { - element.width++; element.width--; - } else try { - var n = document.createTextNode(' '); - element.appendChild(n); - element.removeChild(n); - } catch (e) { } - - return element; - }; - - Element.Methods.cumulativeOffset = function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - if (element.offsetParent == document.body) - if (Element.getStyle(element, 'position') == 'absolute') break; - - element = element.offsetParent; - } while (element); - - return Element._returnOffset(valueL, valueT); - }; -} - -if ('outerHTML' in document.documentElement) { - Element.Methods.replace = function(element, content) { - element = $(element); - - if (content && content.toElement) content = content.toElement(); - if (Object.isElement(content)) { - element.parentNode.replaceChild(content, element); - return element; - } - - content = Object.toHTML(content); - var parent = element.parentNode, tagName = parent.tagName.toUpperCase(); - - if (Element._insertionTranslations.tags[tagName]) { - var nextSibling = element.next(); - var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); - parent.removeChild(element); - if (nextSibling) - fragments.each(function(node) { parent.insertBefore(node, nextSibling) }); - else - fragments.each(function(node) { parent.appendChild(node) }); - } - else element.outerHTML = content.stripScripts(); - - content.evalScripts.bind(content).defer(); - return element; - }; -} - -Element._returnOffset = function(l, t) { - var result = [l, t]; - result.left = l; - result.top = t; - return result; -}; - -Element._getContentFromAnonymousElement = function(tagName, html) { - var div = new Element('div'), t = Element._insertionTranslations.tags[tagName]; - if (t) { - div.innerHTML = t[0] + html + t[1]; - t[2].times(function() { div = div.firstChild }); - } else div.innerHTML = html; - return $A(div.childNodes); -}; - -Element._insertionTranslations = { - before: function(element, node) { - element.parentNode.insertBefore(node, element); - }, - top: function(element, node) { - element.insertBefore(node, element.firstChild); - }, - bottom: function(element, node) { - element.appendChild(node); - }, - after: function(element, node) { - element.parentNode.insertBefore(node, element.nextSibling); - }, - tags: { - TABLE: ['', '
', 1], - TBODY: ['', '
', 2], - TR: ['', '
', 3], - TD: ['
', '
', 4], - SELECT: ['', 1] - } -}; - -(function() { - var tags = Element._insertionTranslations.tags; - Object.extend(tags, { - THEAD: tags.TBODY, - TFOOT: tags.TBODY, - TH: tags.TD - }); -})(); - -Element.Methods.Simulated = { - hasAttribute: function(element, attribute) { - attribute = Element._attributeTranslations.has[attribute] || attribute; - var node = $(element).getAttributeNode(attribute); - return !!(node && node.specified); - } -}; - -Element.Methods.ByTag = { }; - -Object.extend(Element, Element.Methods); - -(function(div) { - - if (!Prototype.BrowserFeatures.ElementExtensions && div['__proto__']) { - window.HTMLElement = { }; - window.HTMLElement.prototype = div['__proto__']; - Prototype.BrowserFeatures.ElementExtensions = true; - } - - div = null; - -})(document.createElement('div')) - -Element.extend = (function() { - - function checkDeficiency(tagName) { - if (typeof window.Element != 'undefined') { - var proto = window.Element.prototype; - if (proto) { - var id = '_' + (Math.random()+'').slice(2); - var el = document.createElement(tagName); - proto[id] = 'x'; - var isBuggy = (el[id] !== 'x'); - delete proto[id]; - el = null; - return isBuggy; - } - } - return false; - } - - function extendElementWith(element, methods) { - for (var property in methods) { - var value = methods[property]; - if (Object.isFunction(value) && !(property in element)) - element[property] = value.methodize(); - } - } - - var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY = checkDeficiency('object'); - - if (Prototype.BrowserFeatures.SpecificElementExtensions) { - if (HTMLOBJECTELEMENT_PROTOTYPE_BUGGY) { - return function(element) { - if (element && typeof element._extendedByPrototype == 'undefined') { - var t = element.tagName; - if (t && (/^(?:object|applet|embed)$/i.test(t))) { - extendElementWith(element, Element.Methods); - extendElementWith(element, Element.Methods.Simulated); - extendElementWith(element, Element.Methods.ByTag[t.toUpperCase()]); - } - } - return element; - } - } - return Prototype.K; - } - - var Methods = { }, ByTag = Element.Methods.ByTag; - - var extend = Object.extend(function(element) { - if (!element || typeof element._extendedByPrototype != 'undefined' || - element.nodeType != 1 || element == window) return element; - - var methods = Object.clone(Methods), - tagName = element.tagName.toUpperCase(); - - if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]); - - extendElementWith(element, methods); - - element._extendedByPrototype = Prototype.emptyFunction; - return element; - - }, { - refresh: function() { - if (!Prototype.BrowserFeatures.ElementExtensions) { - Object.extend(Methods, Element.Methods); - Object.extend(Methods, Element.Methods.Simulated); - } - } - }); - - extend.refresh(); - return extend; -})(); - -Element.hasAttribute = function(element, attribute) { - if (element.hasAttribute) return element.hasAttribute(attribute); - return Element.Methods.Simulated.hasAttribute(element, attribute); -}; - -Element.addMethods = function(methods) { - var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag; - - if (!methods) { - Object.extend(Form, Form.Methods); - Object.extend(Form.Element, Form.Element.Methods); - Object.extend(Element.Methods.ByTag, { - "FORM": Object.clone(Form.Methods), - "INPUT": Object.clone(Form.Element.Methods), - "SELECT": Object.clone(Form.Element.Methods), - "TEXTAREA": Object.clone(Form.Element.Methods) - }); - } - - if (arguments.length == 2) { - var tagName = methods; - methods = arguments[1]; - } - - if (!tagName) Object.extend(Element.Methods, methods || { }); - else { - if (Object.isArray(tagName)) tagName.each(extend); - else extend(tagName); - } - - function extend(tagName) { - tagName = tagName.toUpperCase(); - if (!Element.Methods.ByTag[tagName]) - Element.Methods.ByTag[tagName] = { }; - Object.extend(Element.Methods.ByTag[tagName], methods); - } - - function copy(methods, destination, onlyIfAbsent) { - onlyIfAbsent = onlyIfAbsent || false; - for (var property in methods) { - var value = methods[property]; - if (!Object.isFunction(value)) continue; - if (!onlyIfAbsent || !(property in destination)) - destination[property] = value.methodize(); - } - } - - function findDOMClass(tagName) { - var klass; - var trans = { - "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph", - "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList", - "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading", - "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote", - "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION": - "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD": - "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR": - "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET": - "FrameSet", "IFRAME": "IFrame" - }; - if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element'; - if (window[klass]) return window[klass]; - klass = 'HTML' + tagName + 'Element'; - if (window[klass]) return window[klass]; - klass = 'HTML' + tagName.capitalize() + 'Element'; - if (window[klass]) return window[klass]; - - var element = document.createElement(tagName); - var proto = element['__proto__'] || element.constructor.prototype; - element = null; - return proto; - } - - var elementPrototype = window.HTMLElement ? HTMLElement.prototype : - Element.prototype; - - if (F.ElementExtensions) { - copy(Element.Methods, elementPrototype); - copy(Element.Methods.Simulated, elementPrototype, true); - } - - if (F.SpecificElementExtensions) { - for (var tag in Element.Methods.ByTag) { - var klass = findDOMClass(tag); - if (Object.isUndefined(klass)) continue; - copy(T[tag], klass.prototype); - } - } - - Object.extend(Element, Element.Methods); - delete Element.ByTag; - - if (Element.extend.refresh) Element.extend.refresh(); - Element.cache = { }; -}; - - -document.viewport = { - - getDimensions: function() { - return { width: this.getWidth(), height: this.getHeight() }; - }, - - getScrollOffsets: function() { - return Element._returnOffset( - window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft, - window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); - } -}; - -(function(viewport) { - var B = Prototype.Browser, doc = document, element, property = {}; - - function getRootElement() { - if (B.WebKit && !doc.evaluate) - return document; - - if (B.Opera && window.parseFloat(window.opera.version()) < 9.5) - return document.body; - - return document.documentElement; - } - - function define(D) { - if (!element) element = getRootElement(); - - property[D] = 'client' + D; - - viewport['get' + D] = function() { return element[property[D]] }; - return viewport['get' + D](); - } - - viewport.getWidth = define.curry('Width'); - - viewport.getHeight = define.curry('Height'); -})(document.viewport); - - -Element.Storage = { - UID: 1 -}; - -Element.addMethods({ - getStorage: function(element) { - if (!(element = $(element))) return; - - var uid; - if (element === window) { - uid = 0; - } else { - if (typeof element._prototypeUID === "undefined") - element._prototypeUID = [Element.Storage.UID++]; - uid = element._prototypeUID[0]; - } - - if (!Element.Storage[uid]) - Element.Storage[uid] = $H(); - - return Element.Storage[uid]; - }, - - store: function(element, key, value) { - if (!(element = $(element))) return; - - if (arguments.length === 2) { - Element.getStorage(element).update(key); - } else { - Element.getStorage(element).set(key, value); - } - - return element; - }, - - retrieve: function(element, key, defaultValue) { - if (!(element = $(element))) return; - var hash = Element.getStorage(element), value = hash.get(key); - - if (Object.isUndefined(value)) { - hash.set(key, defaultValue); - value = defaultValue; - } - - return value; - }, - - clone: function(element, deep) { - if (!(element = $(element))) return; - var clone = element.cloneNode(deep); - clone._prototypeUID = void 0; - if (deep) { - var descendants = Element.select(clone, '*'), - i = descendants.length; - while (i--) { - descendants[i]._prototypeUID = void 0; - } - } - return Element.extend(clone); - } -}); -/* Portions of the Selector class are derived from Jack Slocum's DomQuery, - * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style - * license. Please see http://www.yui-ext.com/ for more information. */ - -var Selector = Class.create({ - initialize: function(expression) { - this.expression = expression.strip(); - - if (this.shouldUseSelectorsAPI()) { - this.mode = 'selectorsAPI'; - } else if (this.shouldUseXPath()) { - this.mode = 'xpath'; - this.compileXPathMatcher(); - } else { - this.mode = "normal"; - this.compileMatcher(); - } - - }, - - shouldUseXPath: (function() { - - var IS_DESCENDANT_SELECTOR_BUGGY = (function(){ - var isBuggy = false; - if (document.evaluate && window.XPathResult) { - var el = document.createElement('div'); - el.innerHTML = '

'; - - var xpath = ".//*[local-name()='ul' or local-name()='UL']" + - "//*[local-name()='li' or local-name()='LI']"; - - var result = document.evaluate(xpath, el, null, - XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); - - isBuggy = (result.snapshotLength !== 2); - el = null; - } - return isBuggy; - })(); - - return function() { - if (!Prototype.BrowserFeatures.XPath) return false; - - var e = this.expression; - - if (Prototype.Browser.WebKit && - (e.include("-of-type") || e.include(":empty"))) - return false; - - if ((/(\[[\w-]*?:|:checked)/).test(e)) - return false; - - if (IS_DESCENDANT_SELECTOR_BUGGY) return false; - - return true; - } - - })(), - - shouldUseSelectorsAPI: function() { - if (!Prototype.BrowserFeatures.SelectorsAPI) return false; - - if (Selector.CASE_INSENSITIVE_CLASS_NAMES) return false; - - if (!Selector._div) Selector._div = new Element('div'); - - try { - Selector._div.querySelector(this.expression); - } catch(e) { - return false; - } - - return true; - }, - - compileMatcher: function() { - var e = this.expression, ps = Selector.patterns, h = Selector.handlers, - c = Selector.criteria, le, p, m, len = ps.length, name; - - if (Selector._cache[e]) { - this.matcher = Selector._cache[e]; - return; - } - - this.matcher = ["this.matcher = function(root) {", - "var r = root, h = Selector.handlers, c = false, n;"]; - - while (e && le != e && (/\S/).test(e)) { - le = e; - for (var i = 0; i"; - } -}); - -if (Prototype.BrowserFeatures.SelectorsAPI && - document.compatMode === 'BackCompat') { - Selector.CASE_INSENSITIVE_CLASS_NAMES = (function(){ - var div = document.createElement('div'), - span = document.createElement('span'); - - div.id = "prototype_test_id"; - span.className = 'Test'; - div.appendChild(span); - var isIgnored = (div.querySelector('#prototype_test_id .test') !== null); - div = span = null; - return isIgnored; - })(); -} - -Object.extend(Selector, { - _cache: { }, - - xpath: { - descendant: "//*", - child: "/*", - adjacent: "/following-sibling::*[1]", - laterSibling: '/following-sibling::*', - tagName: function(m) { - if (m[1] == '*') return ''; - return "[local-name()='" + m[1].toLowerCase() + - "' or local-name()='" + m[1].toUpperCase() + "']"; - }, - className: "[contains(concat(' ', @class, ' '), ' #{1} ')]", - id: "[@id='#{1}']", - attrPresence: function(m) { - m[1] = m[1].toLowerCase(); - return new Template("[@#{1}]").evaluate(m); - }, - attr: function(m) { - m[1] = m[1].toLowerCase(); - m[3] = m[5] || m[6]; - return new Template(Selector.xpath.operators[m[2]]).evaluate(m); - }, - pseudo: function(m) { - var h = Selector.xpath.pseudos[m[1]]; - if (!h) return ''; - if (Object.isFunction(h)) return h(m); - return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m); - }, - operators: { - '=': "[@#{1}='#{3}']", - '!=': "[@#{1}!='#{3}']", - '^=': "[starts-with(@#{1}, '#{3}')]", - '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']", - '*=': "[contains(@#{1}, '#{3}')]", - '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]", - '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]" - }, - pseudos: { - 'first-child': '[not(preceding-sibling::*)]', - 'last-child': '[not(following-sibling::*)]', - 'only-child': '[not(preceding-sibling::* or following-sibling::*)]', - 'empty': "[count(*) = 0 and (count(text()) = 0)]", - 'checked': "[@checked]", - 'disabled': "[(@disabled) and (@type!='hidden')]", - 'enabled': "[not(@disabled) and (@type!='hidden')]", - 'not': function(m) { - var e = m[6], p = Selector.patterns, - x = Selector.xpath, le, v, len = p.length, name; - - var exclusion = []; - while (e && le != e && (/\S/).test(e)) { - le = e; - for (var i = 0; i= 0)]"; - return new Template(predicate).evaluate({ - fragment: fragment, a: a, b: b }); - } - } - } - }, - - criteria: { - tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;', - className: 'n = h.className(n, r, "#{1}", c); c = false;', - id: 'n = h.id(n, r, "#{1}", c); c = false;', - attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;', - attr: function(m) { - m[3] = (m[5] || m[6]); - return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m); - }, - pseudo: function(m) { - if (m[6]) m[6] = m[6].replace(/"/g, '\\"'); - return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m); - }, - descendant: 'c = "descendant";', - child: 'c = "child";', - adjacent: 'c = "adjacent";', - laterSibling: 'c = "laterSibling";' - }, - - patterns: [ - { name: 'laterSibling', re: /^\s*~\s*/ }, - { name: 'child', re: /^\s*>\s*/ }, - { name: 'adjacent', re: /^\s*\+\s*/ }, - { name: 'descendant', re: /^\s/ }, - - { name: 'tagName', re: /^\s*(\*|[\w\-]+)(\b|$)?/ }, - { name: 'id', re: /^#([\w\-\*]+)(\b|$)/ }, - { name: 'className', re: /^\.([\w\-\*]+)(\b|$)/ }, - { name: 'pseudo', re: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/ }, - { name: 'attrPresence', re: /^\[((?:[\w-]+:)?[\w-]+)\]/ }, - { name: 'attr', re: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/ } - ], - - assertions: { - tagName: function(element, matches) { - return matches[1].toUpperCase() == element.tagName.toUpperCase(); - }, - - className: function(element, matches) { - return Element.hasClassName(element, matches[1]); - }, - - id: function(element, matches) { - return element.id === matches[1]; - }, - - attrPresence: function(element, matches) { - return Element.hasAttribute(element, matches[1]); - }, - - attr: function(element, matches) { - var nodeValue = Element.readAttribute(element, matches[1]); - return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]); - } - }, - - handlers: { - concat: function(a, b) { - for (var i = 0, node; node = b[i]; i++) - a.push(node); - return a; - }, - - mark: function(nodes) { - var _true = Prototype.emptyFunction; - for (var i = 0, node; node = nodes[i]; i++) - node._countedByPrototype = _true; - return nodes; - }, - - unmark: (function(){ - - var PROPERTIES_ATTRIBUTES_MAP = (function(){ - var el = document.createElement('div'), - isBuggy = false, - propName = '_countedByPrototype', - value = 'x' - el[propName] = value; - isBuggy = (el.getAttribute(propName) === value); - el = null; - return isBuggy; - })(); - - return PROPERTIES_ATTRIBUTES_MAP ? - function(nodes) { - for (var i = 0, node; node = nodes[i]; i++) - node.removeAttribute('_countedByPrototype'); - return nodes; - } : - function(nodes) { - for (var i = 0, node; node = nodes[i]; i++) - node._countedByPrototype = void 0; - return nodes; - } - })(), - - index: function(parentNode, reverse, ofType) { - parentNode._countedByPrototype = Prototype.emptyFunction; - if (reverse) { - for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) { - var node = nodes[i]; - if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; - } - } else { - for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++) - if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; - } - }, - - unique: function(nodes) { - if (nodes.length == 0) return nodes; - var results = [], n; - for (var i = 0, l = nodes.length; i < l; i++) - if (typeof (n = nodes[i])._countedByPrototype == 'undefined') { - n._countedByPrototype = Prototype.emptyFunction; - results.push(Element.extend(n)); - } - return Selector.handlers.unmark(results); - }, - - descendant: function(nodes) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) - h.concat(results, node.getElementsByTagName('*')); - return results; - }, - - child: function(nodes) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) { - for (var j = 0, child; child = node.childNodes[j]; j++) - if (child.nodeType == 1 && child.tagName != '!') results.push(child); - } - return results; - }, - - adjacent: function(nodes) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - var next = this.nextElementSibling(node); - if (next) results.push(next); - } - return results; - }, - - laterSibling: function(nodes) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) - h.concat(results, Element.nextSiblings(node)); - return results; - }, - - nextElementSibling: function(node) { - while (node = node.nextSibling) - if (node.nodeType == 1) return node; - return null; - }, - - previousElementSibling: function(node) { - while (node = node.previousSibling) - if (node.nodeType == 1) return node; - return null; - }, - - tagName: function(nodes, root, tagName, combinator) { - var uTagName = tagName.toUpperCase(); - var results = [], h = Selector.handlers; - if (nodes) { - if (combinator) { - if (combinator == "descendant") { - for (var i = 0, node; node = nodes[i]; i++) - h.concat(results, node.getElementsByTagName(tagName)); - return results; - } else nodes = this[combinator](nodes); - if (tagName == "*") return nodes; - } - for (var i = 0, node; node = nodes[i]; i++) - if (node.tagName.toUpperCase() === uTagName) results.push(node); - return results; - } else return root.getElementsByTagName(tagName); - }, - - id: function(nodes, root, id, combinator) { - var targetNode = $(id), h = Selector.handlers; - - if (root == document) { - if (!targetNode) return []; - if (!nodes) return [targetNode]; - } else { - if (!root.sourceIndex || root.sourceIndex < 1) { - var nodes = root.getElementsByTagName('*'); - for (var j = 0, node; node = nodes[j]; j++) { - if (node.id === id) return [node]; - } - } - } - - if (nodes) { - if (combinator) { - if (combinator == 'child') { - for (var i = 0, node; node = nodes[i]; i++) - if (targetNode.parentNode == node) return [targetNode]; - } else if (combinator == 'descendant') { - for (var i = 0, node; node = nodes[i]; i++) - if (Element.descendantOf(targetNode, node)) return [targetNode]; - } else if (combinator == 'adjacent') { - for (var i = 0, node; node = nodes[i]; i++) - if (Selector.handlers.previousElementSibling(targetNode) == node) - return [targetNode]; - } else nodes = h[combinator](nodes); - } - for (var i = 0, node; node = nodes[i]; i++) - if (node == targetNode) return [targetNode]; - return []; - } - return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : []; - }, - - className: function(nodes, root, className, combinator) { - if (nodes && combinator) nodes = this[combinator](nodes); - return Selector.handlers.byClassName(nodes, root, className); - }, - - byClassName: function(nodes, root, className) { - if (!nodes) nodes = Selector.handlers.descendant([root]); - var needle = ' ' + className + ' '; - for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) { - nodeClassName = node.className; - if (nodeClassName.length == 0) continue; - if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle)) - results.push(node); - } - return results; - }, - - attrPresence: function(nodes, root, attr, combinator) { - if (!nodes) nodes = root.getElementsByTagName("*"); - if (nodes && combinator) nodes = this[combinator](nodes); - var results = []; - for (var i = 0, node; node = nodes[i]; i++) - if (Element.hasAttribute(node, attr)) results.push(node); - return results; - }, - - attr: function(nodes, root, attr, value, operator, combinator) { - if (!nodes) nodes = root.getElementsByTagName("*"); - if (nodes && combinator) nodes = this[combinator](nodes); - var handler = Selector.operators[operator], results = []; - for (var i = 0, node; node = nodes[i]; i++) { - var nodeValue = Element.readAttribute(node, attr); - if (nodeValue === null) continue; - if (handler(nodeValue, value)) results.push(node); - } - return results; - }, - - pseudo: function(nodes, name, value, root, combinator) { - if (nodes && combinator) nodes = this[combinator](nodes); - if (!nodes) nodes = root.getElementsByTagName("*"); - return Selector.pseudos[name](nodes, value, root); - } - }, - - pseudos: { - 'first-child': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - if (Selector.handlers.previousElementSibling(node)) continue; - results.push(node); - } - return results; - }, - 'last-child': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - if (Selector.handlers.nextElementSibling(node)) continue; - results.push(node); - } - return results; - }, - 'only-child': function(nodes, value, root) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (!h.previousElementSibling(node) && !h.nextElementSibling(node)) - results.push(node); - return results; - }, - 'nth-child': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root); - }, - 'nth-last-child': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root, true); - }, - 'nth-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root, false, true); - }, - 'nth-last-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root, true, true); - }, - 'first-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, "1", root, false, true); - }, - 'last-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, "1", root, true, true); - }, - 'only-of-type': function(nodes, formula, root) { - var p = Selector.pseudos; - return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root); - }, - - getIndices: function(a, b, total) { - if (a == 0) return b > 0 ? [b] : []; - return $R(1, total).inject([], function(memo, i) { - if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i); - return memo; - }); - }, - - nth: function(nodes, formula, root, reverse, ofType) { - if (nodes.length == 0) return []; - if (formula == 'even') formula = '2n+0'; - if (formula == 'odd') formula = '2n+1'; - var h = Selector.handlers, results = [], indexed = [], m; - h.mark(nodes); - for (var i = 0, node; node = nodes[i]; i++) { - if (!node.parentNode._countedByPrototype) { - h.index(node.parentNode, reverse, ofType); - indexed.push(node.parentNode); - } - } - if (formula.match(/^\d+$/)) { // just a number - formula = Number(formula); - for (var i = 0, node; node = nodes[i]; i++) - if (node.nodeIndex == formula) results.push(node); - } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b - if (m[1] == "-") m[1] = -1; - var a = m[1] ? Number(m[1]) : 1; - var b = m[2] ? Number(m[2]) : 0; - var indices = Selector.pseudos.getIndices(a, b, nodes.length); - for (var i = 0, node, l = indices.length; node = nodes[i]; i++) { - for (var j = 0; j < l; j++) - if (node.nodeIndex == indices[j]) results.push(node); - } - } - h.unmark(nodes); - h.unmark(indexed); - return results; - }, - - 'empty': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - if (node.tagName == '!' || node.firstChild) continue; - results.push(node); - } - return results; - }, - - 'not': function(nodes, selector, root) { - var h = Selector.handlers, selectorType, m; - var exclusions = new Selector(selector).findElements(root); - h.mark(exclusions); - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (!node._countedByPrototype) results.push(node); - h.unmark(exclusions); - return results; - }, - - 'enabled': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (!node.disabled && (!node.type || node.type !== 'hidden')) - results.push(node); - return results; - }, - - 'disabled': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (node.disabled) results.push(node); - return results; - }, - - 'checked': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (node.checked) results.push(node); - return results; - } - }, - - operators: { - '=': function(nv, v) { return nv == v; }, - '!=': function(nv, v) { return nv != v; }, - '^=': function(nv, v) { return nv == v || nv && nv.startsWith(v); }, - '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); }, - '*=': function(nv, v) { return nv == v || nv && nv.include(v); }, - '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); }, - '|=': function(nv, v) { return ('-' + (nv || "").toUpperCase() + - '-').include('-' + (v || "").toUpperCase() + '-'); } - }, - - split: function(expression) { - var expressions = []; - expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) { - expressions.push(m[1].strip()); - }); - return expressions; - }, - - matchElements: function(elements, expression) { - var matches = $$(expression), h = Selector.handlers; - h.mark(matches); - for (var i = 0, results = [], element; element = elements[i]; i++) - if (element._countedByPrototype) results.push(element); - h.unmark(matches); - return results; - }, - - findElement: function(elements, expression, index) { - if (Object.isNumber(expression)) { - index = expression; expression = false; - } - return Selector.matchElements(elements, expression || '*')[index || 0]; - }, - - findChildElements: function(element, expressions) { - expressions = Selector.split(expressions.join(',')); - var results = [], h = Selector.handlers; - for (var i = 0, l = expressions.length, selector; i < l; i++) { - selector = new Selector(expressions[i].strip()); - h.concat(results, selector.findElements(element)); - } - return (l > 1) ? h.unique(results) : results; - } -}); - -if (Prototype.Browser.IE) { - Object.extend(Selector.handlers, { - concat: function(a, b) { - for (var i = 0, node; node = b[i]; i++) - if (node.tagName !== "!") a.push(node); - return a; - } - }); -} - -function $$() { - return Selector.findChildElements(document, $A(arguments)); -} - -var Form = { - reset: function(form) { - form = $(form); - form.reset(); - return form; - }, - - serializeElements: function(elements, options) { - if (typeof options != 'object') options = { hash: !!options }; - else if (Object.isUndefined(options.hash)) options.hash = true; - var key, value, submitted = false, submit = options.submit; - - var data = elements.inject({ }, function(result, element) { - if (!element.disabled && element.name) { - key = element.name; value = $(element).getValue(); - if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted && - submit !== false && (!submit || key == submit) && (submitted = true)))) { - if (key in result) { - if (!Object.isArray(result[key])) result[key] = [result[key]]; - result[key].push(value); - } - else result[key] = value; - } - } - return result; - }); - - return options.hash ? data : Object.toQueryString(data); - } -}; - -Form.Methods = { - serialize: function(form, options) { - return Form.serializeElements(Form.getElements(form), options); - }, - - getElements: function(form) { - var elements = $(form).getElementsByTagName('*'), - element, - arr = [ ], - serializers = Form.Element.Serializers; - for (var i = 0; element = elements[i]; i++) { - arr.push(element); - } - return arr.inject([], function(elements, child) { - if (serializers[child.tagName.toLowerCase()]) - elements.push(Element.extend(child)); - return elements; - }) - }, - - getInputs: function(form, typeName, name) { - form = $(form); - var inputs = form.getElementsByTagName('input'); - - if (!typeName && !name) return $A(inputs).map(Element.extend); - - for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { - var input = inputs[i]; - if ((typeName && input.type != typeName) || (name && input.name != name)) - continue; - matchingInputs.push(Element.extend(input)); - } - - return matchingInputs; - }, - - disable: function(form) { - form = $(form); - Form.getElements(form).invoke('disable'); - return form; - }, - - enable: function(form) { - form = $(form); - Form.getElements(form).invoke('enable'); - return form; - }, - - findFirstElement: function(form) { - var elements = $(form).getElements().findAll(function(element) { - return 'hidden' != element.type && !element.disabled; - }); - var firstByIndex = elements.findAll(function(element) { - return element.hasAttribute('tabIndex') && element.tabIndex >= 0; - }).sortBy(function(element) { return element.tabIndex }).first(); - - return firstByIndex ? firstByIndex : elements.find(function(element) { - return /^(?:input|select|textarea)$/i.test(element.tagName); - }); - }, - - focusFirstElement: function(form) { - form = $(form); - form.findFirstElement().activate(); - return form; - }, - - request: function(form, options) { - form = $(form), options = Object.clone(options || { }); - - var params = options.parameters, action = form.readAttribute('action') || ''; - if (action.blank()) action = window.location.href; - options.parameters = form.serialize(true); - - if (params) { - if (Object.isString(params)) params = params.toQueryParams(); - Object.extend(options.parameters, params); - } - - if (form.hasAttribute('method') && !options.method) - options.method = form.method; - - return new Ajax.Request(action, options); - } -}; - -/*--------------------------------------------------------------------------*/ - - -Form.Element = { - focus: function(element) { - $(element).focus(); - return element; - }, - - select: function(element) { - $(element).select(); - return element; - } -}; - -Form.Element.Methods = { - - serialize: function(element) { - element = $(element); - if (!element.disabled && element.name) { - var value = element.getValue(); - if (value != undefined) { - var pair = { }; - pair[element.name] = value; - return Object.toQueryString(pair); - } - } - return ''; - }, - - getValue: function(element) { - element = $(element); - var method = element.tagName.toLowerCase(); - return Form.Element.Serializers[method](element); - }, - - setValue: function(element, value) { - element = $(element); - var method = element.tagName.toLowerCase(); - Form.Element.Serializers[method](element, value); - return element; - }, - - clear: function(element) { - $(element).value = ''; - return element; - }, - - present: function(element) { - return $(element).value != ''; - }, - - activate: function(element) { - element = $(element); - try { - element.focus(); - if (element.select && (element.tagName.toLowerCase() != 'input' || - !(/^(?:button|reset|submit)$/i.test(element.type)))) - element.select(); - } catch (e) { } - return element; - }, - - disable: function(element) { - element = $(element); - element.disabled = true; - return element; - }, - - enable: function(element) { - element = $(element); - element.disabled = false; - return element; - } -}; - -/*--------------------------------------------------------------------------*/ - -var Field = Form.Element; - -var $F = Form.Element.Methods.getValue; - -/*--------------------------------------------------------------------------*/ - -Form.Element.Serializers = { - input: function(element, value) { - switch (element.type.toLowerCase()) { - case 'checkbox': - case 'radio': - return Form.Element.Serializers.inputSelector(element, value); - default: - return Form.Element.Serializers.textarea(element, value); - } - }, - - inputSelector: function(element, value) { - if (Object.isUndefined(value)) return element.checked ? element.value : null; - else element.checked = !!value; - }, - - textarea: function(element, value) { - if (Object.isUndefined(value)) return element.value; - else element.value = value; - }, - - select: function(element, value) { - if (Object.isUndefined(value)) - return this[element.type == 'select-one' ? - 'selectOne' : 'selectMany'](element); - else { - var opt, currentValue, single = !Object.isArray(value); - for (var i = 0, length = element.length; i < length; i++) { - opt = element.options[i]; - currentValue = this.optionValue(opt); - if (single) { - if (currentValue == value) { - opt.selected = true; - return; - } - } - else opt.selected = value.include(currentValue); - } - } - }, - - selectOne: function(element) { - var index = element.selectedIndex; - return index >= 0 ? this.optionValue(element.options[index]) : null; - }, - - selectMany: function(element) { - var values, length = element.length; - if (!length) return null; - - for (var i = 0, values = []; i < length; i++) { - var opt = element.options[i]; - if (opt.selected) values.push(this.optionValue(opt)); - } - return values; - }, - - optionValue: function(opt) { - return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; - } -}; - -/*--------------------------------------------------------------------------*/ - - -Abstract.TimedObserver = Class.create(PeriodicalExecuter, { - initialize: function($super, element, frequency, callback) { - $super(callback, frequency); - this.element = $(element); - this.lastValue = this.getValue(); - }, - - execute: function() { - var value = this.getValue(); - if (Object.isString(this.lastValue) && Object.isString(value) ? - this.lastValue != value : String(this.lastValue) != String(value)) { - this.callback(this.element, value); - this.lastValue = value; - } - } -}); - -Form.Element.Observer = Class.create(Abstract.TimedObserver, { - getValue: function() { - return Form.Element.getValue(this.element); - } -}); - -Form.Observer = Class.create(Abstract.TimedObserver, { - getValue: function() { - return Form.serialize(this.element); - } -}); - -/*--------------------------------------------------------------------------*/ - -Abstract.EventObserver = Class.create({ - initialize: function(element, callback) { - this.element = $(element); - this.callback = callback; - - this.lastValue = this.getValue(); - if (this.element.tagName.toLowerCase() == 'form') - this.registerFormCallbacks(); - else - this.registerCallback(this.element); - }, - - onElementEvent: function() { - var value = this.getValue(); - if (this.lastValue != value) { - this.callback(this.element, value); - this.lastValue = value; - } - }, - - registerFormCallbacks: function() { - Form.getElements(this.element).each(this.registerCallback, this); - }, - - registerCallback: function(element) { - if (element.type) { - switch (element.type.toLowerCase()) { - case 'checkbox': - case 'radio': - Event.observe(element, 'click', this.onElementEvent.bind(this)); - break; - default: - Event.observe(element, 'change', this.onElementEvent.bind(this)); - break; - } - } - } -}); - -Form.Element.EventObserver = Class.create(Abstract.EventObserver, { - getValue: function() { - return Form.Element.getValue(this.element); - } -}); - -Form.EventObserver = Class.create(Abstract.EventObserver, { - getValue: function() { - return Form.serialize(this.element); - } -}); -(function() { - - var Event = { - KEY_BACKSPACE: 8, - KEY_TAB: 9, - KEY_RETURN: 13, - KEY_ESC: 27, - KEY_LEFT: 37, - KEY_UP: 38, - KEY_RIGHT: 39, - KEY_DOWN: 40, - KEY_DELETE: 46, - KEY_HOME: 36, - KEY_END: 35, - KEY_PAGEUP: 33, - KEY_PAGEDOWN: 34, - KEY_INSERT: 45, - - cache: {} - }; - - var docEl = document.documentElement; - var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl - && 'onmouseleave' in docEl; - - var _isButton; - if (Prototype.Browser.IE) { - var buttonMap = { 0: 1, 1: 4, 2: 2 }; - _isButton = function(event, code) { - return event.button === buttonMap[code]; - }; - } else if (Prototype.Browser.WebKit) { - _isButton = function(event, code) { - switch (code) { - case 0: return event.which == 1 && !event.metaKey; - case 1: return event.which == 1 && event.metaKey; - default: return false; - } - }; - } else { - _isButton = function(event, code) { - return event.which ? (event.which === code + 1) : (event.button === code); - }; - } - - function isLeftClick(event) { return _isButton(event, 0) } - - function isMiddleClick(event) { return _isButton(event, 1) } - - function isRightClick(event) { return _isButton(event, 2) } - - function element(event) { - event = Event.extend(event); - - var node = event.target, type = event.type, - currentTarget = event.currentTarget; - - if (currentTarget && currentTarget.tagName) { - if (type === 'load' || type === 'error' || - (type === 'click' && currentTarget.tagName.toLowerCase() === 'input' - && currentTarget.type === 'radio')) - node = currentTarget; - } - - if (node.nodeType == Node.TEXT_NODE) - node = node.parentNode; - - return Element.extend(node); - } - - function findElement(event, expression) { - var element = Event.element(event); - if (!expression) return element; - var elements = [element].concat(element.ancestors()); - return Selector.findElement(elements, expression, 0); - } - - function pointer(event) { - return { x: pointerX(event), y: pointerY(event) }; - } - - function pointerX(event) { - var docElement = document.documentElement, - body = document.body || { scrollLeft: 0 }; - - return event.pageX || (event.clientX + - (docElement.scrollLeft || body.scrollLeft) - - (docElement.clientLeft || 0)); - } - - function pointerY(event) { - var docElement = document.documentElement, - body = document.body || { scrollTop: 0 }; - - return event.pageY || (event.clientY + - (docElement.scrollTop || body.scrollTop) - - (docElement.clientTop || 0)); - } - - - function stop(event) { - Event.extend(event); - event.preventDefault(); - event.stopPropagation(); - - event.stopped = true; - } - - Event.Methods = { - isLeftClick: isLeftClick, - isMiddleClick: isMiddleClick, - isRightClick: isRightClick, - - element: element, - findElement: findElement, - - pointer: pointer, - pointerX: pointerX, - pointerY: pointerY, - - stop: stop - }; - - - var methods = Object.keys(Event.Methods).inject({ }, function(m, name) { - m[name] = Event.Methods[name].methodize(); - return m; - }); - - if (Prototype.Browser.IE) { - function _relatedTarget(event) { - var element; - switch (event.type) { - case 'mouseover': element = event.fromElement; break; - case 'mouseout': element = event.toElement; break; - default: return null; - } - return Element.extend(element); - } - - Object.extend(methods, { - stopPropagation: function() { this.cancelBubble = true }, - preventDefault: function() { this.returnValue = false }, - inspect: function() { return '[object Event]' } - }); - - Event.extend = function(event, element) { - if (!event) return false; - if (event._extendedByPrototype) return event; - - event._extendedByPrototype = Prototype.emptyFunction; - var pointer = Event.pointer(event); - - Object.extend(event, { - target: event.srcElement || element, - relatedTarget: _relatedTarget(event), - pageX: pointer.x, - pageY: pointer.y - }); - - return Object.extend(event, methods); - }; - } else { - Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__; - Object.extend(Event.prototype, methods); - Event.extend = Prototype.K; - } - - function _createResponder(element, eventName, handler) { - var registry = Element.retrieve(element, 'prototype_event_registry'); - - if (Object.isUndefined(registry)) { - CACHE.push(element); - registry = Element.retrieve(element, 'prototype_event_registry', $H()); - } - - var respondersForEvent = registry.get(eventName); - if (Object.isUndefined(respondersForEvent)) { - respondersForEvent = []; - registry.set(eventName, respondersForEvent); - } - - if (respondersForEvent.pluck('handler').include(handler)) return false; - - var responder; - if (eventName.include(":")) { - responder = function(event) { - if (Object.isUndefined(event.eventName)) - return false; - - if (event.eventName !== eventName) - return false; - - Event.extend(event, element); - handler.call(element, event); - }; - } else { - if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED && - (eventName === "mouseenter" || eventName === "mouseleave")) { - if (eventName === "mouseenter" || eventName === "mouseleave") { - responder = function(event) { - Event.extend(event, element); - - var parent = event.relatedTarget; - while (parent && parent !== element) { - try { parent = parent.parentNode; } - catch(e) { parent = element; } - } - - if (parent === element) return; - - handler.call(element, event); - }; - } - } else { - responder = function(event) { - Event.extend(event, element); - handler.call(element, event); - }; - } - } - - responder.handler = handler; - respondersForEvent.push(responder); - return responder; - } - - function _destroyCache() { - for (var i = 0, length = CACHE.length; i < length; i++) { - Event.stopObserving(CACHE[i]); - CACHE[i] = null; - } - } - - var CACHE = []; - - if (Prototype.Browser.IE) - window.attachEvent('onunload', _destroyCache); - - if (Prototype.Browser.WebKit) - window.addEventListener('unload', Prototype.emptyFunction, false); - - - var _getDOMEventName = Prototype.K; - - if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED) { - _getDOMEventName = function(eventName) { - var translations = { mouseenter: "mouseover", mouseleave: "mouseout" }; - return eventName in translations ? translations[eventName] : eventName; - }; - } - - function observe(element, eventName, handler) { - element = $(element); - - var responder = _createResponder(element, eventName, handler); - - if (!responder) return element; - - if (eventName.include(':')) { - if (element.addEventListener) - element.addEventListener("dataavailable", responder, false); - else { - element.attachEvent("ondataavailable", responder); - element.attachEvent("onfilterchange", responder); - } - } else { - var actualEventName = _getDOMEventName(eventName); - - if (element.addEventListener) - element.addEventListener(actualEventName, responder, false); - else - element.attachEvent("on" + actualEventName, responder); - } - - return element; - } - - function stopObserving(element, eventName, handler) { - element = $(element); - - var registry = Element.retrieve(element, 'prototype_event_registry'); - - if (Object.isUndefined(registry)) return element; - - if (eventName && !handler) { - var responders = registry.get(eventName); - - if (Object.isUndefined(responders)) return element; - - responders.each( function(r) { - Element.stopObserving(element, eventName, r.handler); - }); - return element; - } else if (!eventName) { - registry.each( function(pair) { - var eventName = pair.key, responders = pair.value; - - responders.each( function(r) { - Element.stopObserving(element, eventName, r.handler); - }); - }); - return element; - } - - var responders = registry.get(eventName); - - if (!responders) return; - - var responder = responders.find( function(r) { return r.handler === handler; }); - if (!responder) return element; - - var actualEventName = _getDOMEventName(eventName); - - if (eventName.include(':')) { - if (element.removeEventListener) - element.removeEventListener("dataavailable", responder, false); - else { - element.detachEvent("ondataavailable", responder); - element.detachEvent("onfilterchange", responder); - } - } else { - if (element.removeEventListener) - element.removeEventListener(actualEventName, responder, false); - else - element.detachEvent('on' + actualEventName, responder); - } - - registry.set(eventName, responders.without(responder)); - - return element; - } - - function fire(element, eventName, memo, bubble) { - element = $(element); - - if (Object.isUndefined(bubble)) - bubble = true; - - if (element == document && document.createEvent && !element.dispatchEvent) - element = document.documentElement; - - var event; - if (document.createEvent) { - event = document.createEvent('HTMLEvents'); - event.initEvent('dataavailable', true, true); - } else { - event = document.createEventObject(); - event.eventType = bubble ? 'ondataavailable' : 'onfilterchange'; - } - - event.eventName = eventName; - event.memo = memo || { }; - - if (document.createEvent) - element.dispatchEvent(event); - else - element.fireEvent(event.eventType, event); - - return Event.extend(event); - } - - - Object.extend(Event, Event.Methods); - - Object.extend(Event, { - fire: fire, - observe: observe, - stopObserving: stopObserving - }); - - Element.addMethods({ - fire: fire, - - observe: observe, - - stopObserving: stopObserving - }); - - Object.extend(document, { - fire: fire.methodize(), - - observe: observe.methodize(), - - stopObserving: stopObserving.methodize(), - - loaded: false - }); - - if (window.Event) Object.extend(window.Event, Event); - else window.Event = Event; -})(); - -(function() { - /* Support for the DOMContentLoaded event is based on work by Dan Webb, - Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */ - - var timer; - - function fireContentLoadedEvent() { - if (document.loaded) return; - if (timer) window.clearTimeout(timer); - document.loaded = true; - document.fire('dom:loaded'); - } - - function checkReadyState() { - if (document.readyState === 'complete') { - document.stopObserving('readystatechange', checkReadyState); - fireContentLoadedEvent(); - } - } - - function pollDoScroll() { - try { document.documentElement.doScroll('left'); } - catch(e) { - timer = pollDoScroll.defer(); - return; - } - fireContentLoadedEvent(); - } - - if (document.addEventListener) { - document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false); - } else { - document.observe('readystatechange', checkReadyState); - if (window == top) - timer = pollDoScroll.defer(); - } - - Event.observe(window, 'load', fireContentLoadedEvent); -})(); - -Element.addMethods(); - -/*------------------------------- DEPRECATED -------------------------------*/ - -Hash.toQueryString = Object.toQueryString; - -var Toggle = { display: Element.toggle }; - -Element.Methods.childOf = Element.Methods.descendantOf; - -var Insertion = { - Before: function(element, content) { - return Element.insert(element, {before:content}); - }, - - Top: function(element, content) { - return Element.insert(element, {top:content}); - }, - - Bottom: function(element, content) { - return Element.insert(element, {bottom:content}); - }, - - After: function(element, content) { - return Element.insert(element, {after:content}); - } -}; - -var $continue = new Error('"throw $continue" is deprecated, use "return" instead'); - -var Position = { - includeScrollOffsets: false, - - prepare: function() { - this.deltaX = window.pageXOffset - || document.documentElement.scrollLeft - || document.body.scrollLeft - || 0; - this.deltaY = window.pageYOffset - || document.documentElement.scrollTop - || document.body.scrollTop - || 0; - }, - - within: function(element, x, y) { - if (this.includeScrollOffsets) - return this.withinIncludingScrolloffsets(element, x, y); - this.xcomp = x; - this.ycomp = y; - this.offset = Element.cumulativeOffset(element); - - return (y >= this.offset[1] && - y < this.offset[1] + element.offsetHeight && - x >= this.offset[0] && - x < this.offset[0] + element.offsetWidth); - }, - - withinIncludingScrolloffsets: function(element, x, y) { - var offsetcache = Element.cumulativeScrollOffset(element); - - this.xcomp = x + offsetcache[0] - this.deltaX; - this.ycomp = y + offsetcache[1] - this.deltaY; - this.offset = Element.cumulativeOffset(element); - - return (this.ycomp >= this.offset[1] && - this.ycomp < this.offset[1] + element.offsetHeight && - this.xcomp >= this.offset[0] && - this.xcomp < this.offset[0] + element.offsetWidth); - }, - - overlap: function(mode, element) { - if (!mode) return 0; - if (mode == 'vertical') - return ((this.offset[1] + element.offsetHeight) - this.ycomp) / - element.offsetHeight; - if (mode == 'horizontal') - return ((this.offset[0] + element.offsetWidth) - this.xcomp) / - element.offsetWidth; - }, - - - cumulativeOffset: Element.Methods.cumulativeOffset, - - positionedOffset: Element.Methods.positionedOffset, - - absolutize: function(element) { - Position.prepare(); - return Element.absolutize(element); - }, - - relativize: function(element) { - Position.prepare(); - return Element.relativize(element); - }, - - realOffset: Element.Methods.cumulativeScrollOffset, - - offsetParent: Element.Methods.getOffsetParent, - - page: Element.Methods.viewportOffset, - - clone: function(source, target, options) { - options = options || { }; - return Element.clonePosition(target, source, options); - } -}; - -/*--------------------------------------------------------------------------*/ - -if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){ - function iter(name) { - return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]"; - } - - instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ? - function(element, className) { - className = className.toString().strip(); - var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className); - return cond ? document._getElementsByXPath('.//*' + cond, element) : []; - } : function(element, className) { - className = className.toString().strip(); - var elements = [], classNames = (/\s/.test(className) ? $w(className) : null); - if (!classNames && !className) return elements; - - var nodes = $(element).getElementsByTagName('*'); - className = ' ' + className + ' '; - - for (var i = 0, child, cn; child = nodes[i]; i++) { - if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) || - (classNames && classNames.all(function(name) { - return !name.toString().blank() && cn.include(' ' + name + ' '); - })))) - elements.push(Element.extend(child)); - } - return elements; - }; - - return function(className, parentElement) { - return $(parentElement || document.body).getElementsByClassName(className); - }; -}(Element.Methods); - -/*--------------------------------------------------------------------------*/ - -Element.ClassNames = Class.create(); -Element.ClassNames.prototype = { - initialize: function(element) { - this.element = $(element); - }, - - _each: function(iterator) { - this.element.className.split(/\s+/).select(function(name) { - return name.length > 0; - })._each(iterator); - }, - - set: function(className) { - this.element.className = className; - }, - - add: function(classNameToAdd) { - if (this.include(classNameToAdd)) return; - this.set($A(this).concat(classNameToAdd).join(' ')); - }, - - remove: function(classNameToRemove) { - if (!this.include(classNameToRemove)) return; - this.set($A(this).without(classNameToRemove).join(' ')); - }, - - toString: function() { - return $A(this).join(' '); - } -}; - -Object.extend(Element.ClassNames.prototype, Enumerable); - -/*--------------------------------------------------------------------------*/ +/* Prototype JavaScript framework, version 1.6.1 + * (c) 2005-2009 Sam Stephenson + * + * Prototype is freely distributable under the terms of an MIT-style license. + * For details, see the Prototype web site: http://www.prototypejs.org/ + * + *--------------------------------------------------------------------------*/ + +var Prototype = { + Version: '1.6.1', + + Browser: (function(){ + var ua = navigator.userAgent; + var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]'; + return { + IE: !!window.attachEvent && !isOpera, + Opera: isOpera, + WebKit: ua.indexOf('AppleWebKit/') > -1, + Gecko: ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1, + MobileSafari: /Apple.*Mobile.*Safari/.test(ua) + } + })(), + + BrowserFeatures: { + XPath: !!document.evaluate, + SelectorsAPI: !!document.querySelector, + ElementExtensions: (function() { + var constructor = window.Element || window.HTMLElement; + return !!(constructor && constructor.prototype); + })(), + SpecificElementExtensions: (function() { + if (typeof window.HTMLDivElement !== 'undefined') + return true; + + var div = document.createElement('div'); + var form = document.createElement('form'); + var isSupported = false; + + if (div['__proto__'] && (div['__proto__'] !== form['__proto__'])) { + isSupported = true; + } + + div = form = null; + + return isSupported; + })() + }, + + ScriptFragment: ']*>([\\S\\s]*?)<\/script>', + JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, + + emptyFunction: function() { }, + K: function(x) { return x } +}; + +if (Prototype.Browser.MobileSafari) + Prototype.BrowserFeatures.SpecificElementExtensions = false; + + +var Abstract = { }; + + +var Try = { + these: function() { + var returnValue; + + for (var i = 0, length = arguments.length; i < length; i++) { + var lambda = arguments[i]; + try { + returnValue = lambda(); + break; + } catch (e) { } + } + + return returnValue; + } +}; + +/* Based on Alex Arnell's inheritance implementation. */ + +var Class = (function() { + function subclass() {}; + function create() { + var parent = null, properties = $A(arguments); + if (Object.isFunction(properties[0])) + parent = properties.shift(); + + function klass() { + this.initialize.apply(this, arguments); + } + + Object.extend(klass, Class.Methods); + klass.superclass = parent; + klass.subclasses = []; + + if (parent) { + subclass.prototype = parent.prototype; + klass.prototype = new subclass; + parent.subclasses.push(klass); + } + + for (var i = 0; i < properties.length; i++) + klass.addMethods(properties[i]); + + if (!klass.prototype.initialize) + klass.prototype.initialize = Prototype.emptyFunction; + + klass.prototype.constructor = klass; + return klass; + } + + function addMethods(source) { + var ancestor = this.superclass && this.superclass.prototype; + var properties = Object.keys(source); + + if (!Object.keys({ toString: true }).length) { + if (source.toString != Object.prototype.toString) + properties.push("toString"); + if (source.valueOf != Object.prototype.valueOf) + properties.push("valueOf"); + } + + for (var i = 0, length = properties.length; i < length; i++) { + var property = properties[i], value = source[property]; + if (ancestor && Object.isFunction(value) && + value.argumentNames().first() == "$super") { + var method = value; + value = (function(m) { + return function() { return ancestor[m].apply(this, arguments); }; + })(property).wrap(method); + + value.valueOf = method.valueOf.bind(method); + value.toString = method.toString.bind(method); + } + this.prototype[property] = value; + } + + return this; + } + + return { + create: create, + Methods: { + addMethods: addMethods + } + }; +})(); +(function() { + + var _toString = Object.prototype.toString; + + function extend(destination, source) { + for (var property in source) + destination[property] = source[property]; + return destination; + } + + function inspect(object) { + try { + if (isUndefined(object)) return 'undefined'; + if (object === null) return 'null'; + return object.inspect ? object.inspect() : String(object); + } catch (e) { + if (e instanceof RangeError) return '...'; + throw e; + } + } + + function toJSON(object) { + var type = typeof object; + switch (type) { + case 'undefined': + case 'function': + case 'unknown': return; + case 'boolean': return object.toString(); + } + + if (object === null) return 'null'; + if (object.toJSON) return object.toJSON(); + if (isElement(object)) return; + + var results = []; + for (var property in object) { + var value = toJSON(object[property]); + if (!isUndefined(value)) + results.push(property.toJSON() + ': ' + value); + } + + return '{' + results.join(', ') + '}'; + } + + function toQueryString(object) { + return $H(object).toQueryString(); + } + + function toHTML(object) { + return object && object.toHTML ? object.toHTML() : String.interpret(object); + } + + function keys(object) { + var results = []; + for (var property in object) + results.push(property); + return results; + } + + function values(object) { + var results = []; + for (var property in object) + results.push(object[property]); + return results; + } + + function clone(object) { + return extend({ }, object); + } + + function isElement(object) { + return !!(object && object.nodeType == 1); + } + + function isArray(object) { + return _toString.call(object) == "[object Array]"; + } + + + function isHash(object) { + return object instanceof Hash; + } + + function isFunction(object) { + return typeof object === "function"; + } + + function isString(object) { + return _toString.call(object) == "[object String]"; + } + + function isNumber(object) { + return _toString.call(object) == "[object Number]"; + } + + function isUndefined(object) { + return typeof object === "undefined"; + } + + extend(Object, { + extend: extend, + inspect: inspect, + toJSON: toJSON, + toQueryString: toQueryString, + toHTML: toHTML, + keys: keys, + values: values, + clone: clone, + isElement: isElement, + isArray: isArray, + isHash: isHash, + isFunction: isFunction, + isString: isString, + isNumber: isNumber, + isUndefined: isUndefined + }); +})(); +Object.extend(Function.prototype, (function() { + var slice = Array.prototype.slice; + + function update(array, args) { + var arrayLength = array.length, length = args.length; + while (length--) array[arrayLength + length] = args[length]; + return array; + } + + function merge(array, args) { + array = slice.call(array, 0); + return update(array, args); + } + + function argumentNames() { + var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1] + .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '') + .replace(/\s+/g, '').split(','); + return names.length == 1 && !names[0] ? [] : names; + } + + function bind(context) { + if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this; + var __method = this, args = slice.call(arguments, 1); + return function() { + var a = merge(args, arguments); + return __method.apply(context, a); + } + } + + function bindAsEventListener(context) { + var __method = this, args = slice.call(arguments, 1); + return function(event) { + var a = update([event || window.event], args); + return __method.apply(context, a); + } + } + + function curry() { + if (!arguments.length) return this; + var __method = this, args = slice.call(arguments, 0); + return function() { + var a = merge(args, arguments); + return __method.apply(this, a); + } + } + + function delay(timeout) { + var __method = this, args = slice.call(arguments, 1); + timeout = timeout * 1000 + return window.setTimeout(function() { + return __method.apply(__method, args); + }, timeout); + } + + function defer() { + var args = update([0.01], arguments); + return this.delay.apply(this, args); + } + + function wrap(wrapper) { + var __method = this; + return function() { + var a = update([__method.bind(this)], arguments); + return wrapper.apply(this, a); + } + } + + function methodize() { + if (this._methodized) return this._methodized; + var __method = this; + return this._methodized = function() { + var a = update([this], arguments); + return __method.apply(null, a); + }; + } + + return { + argumentNames: argumentNames, + bind: bind, + bindAsEventListener: bindAsEventListener, + curry: curry, + delay: delay, + defer: defer, + wrap: wrap, + methodize: methodize + } +})()); + + +Date.prototype.toJSON = function() { + return '"' + this.getUTCFullYear() + '-' + + (this.getUTCMonth() + 1).toPaddedString(2) + '-' + + this.getUTCDate().toPaddedString(2) + 'T' + + this.getUTCHours().toPaddedString(2) + ':' + + this.getUTCMinutes().toPaddedString(2) + ':' + + this.getUTCSeconds().toPaddedString(2) + 'Z"'; +}; + + +RegExp.prototype.match = RegExp.prototype.test; + +RegExp.escape = function(str) { + return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); +}; +var PeriodicalExecuter = Class.create({ + initialize: function(callback, frequency) { + this.callback = callback; + this.frequency = frequency; + this.currentlyExecuting = false; + + this.registerCallback(); + }, + + registerCallback: function() { + this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + execute: function() { + this.callback(this); + }, + + stop: function() { + if (!this.timer) return; + clearInterval(this.timer); + this.timer = null; + }, + + onTimerEvent: function() { + if (!this.currentlyExecuting) { + try { + this.currentlyExecuting = true; + this.execute(); + this.currentlyExecuting = false; + } catch(e) { + this.currentlyExecuting = false; + throw e; + } + } + } +}); +Object.extend(String, { + interpret: function(value) { + return value == null ? '' : String(value); + }, + specialChar: { + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '\\': '\\\\' + } +}); + +Object.extend(String.prototype, (function() { + + function prepareReplacement(replacement) { + if (Object.isFunction(replacement)) return replacement; + var template = new Template(replacement); + return function(match) { return template.evaluate(match) }; + } + + function gsub(pattern, replacement) { + var result = '', source = this, match; + replacement = prepareReplacement(replacement); + + if (Object.isString(pattern)) + pattern = RegExp.escape(pattern); + + if (!(pattern.length || pattern.source)) { + replacement = replacement(''); + return replacement + source.split('').join(replacement) + replacement; + } + + while (source.length > 0) { + if (match = source.match(pattern)) { + result += source.slice(0, match.index); + result += String.interpret(replacement(match)); + source = source.slice(match.index + match[0].length); + } else { + result += source, source = ''; + } + } + return result; + } + + function sub(pattern, replacement, count) { + replacement = prepareReplacement(replacement); + count = Object.isUndefined(count) ? 1 : count; + + return this.gsub(pattern, function(match) { + if (--count < 0) return match[0]; + return replacement(match); + }); + } + + function scan(pattern, iterator) { + this.gsub(pattern, iterator); + return String(this); + } + + function truncate(length, truncation) { + length = length || 30; + truncation = Object.isUndefined(truncation) ? '...' : truncation; + return this.length > length ? + this.slice(0, length - truncation.length) + truncation : String(this); + } + + function strip() { + return this.replace(/^\s+/, '').replace(/\s+$/, ''); + } + + function stripTags() { + return this.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?>|<\/\w+>/gi, ''); + } + + function stripScripts() { + return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); + } + + function extractScripts() { + var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); + var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); + return (this.match(matchAll) || []).map(function(scriptTag) { + return (scriptTag.match(matchOne) || ['', ''])[1]; + }); + } + + function evalScripts() { + return this.extractScripts().map(function(script) { return eval(script) }); + } + + function escapeHTML() { + return this.replace(/&/g,'&').replace(//g,'>'); + } + + function unescapeHTML() { + return this.stripTags().replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&'); + } + + + function toQueryParams(separator) { + var match = this.strip().match(/([^?#]*)(#.*)?$/); + if (!match) return { }; + + return match[1].split(separator || '&').inject({ }, function(hash, pair) { + if ((pair = pair.split('='))[0]) { + var key = decodeURIComponent(pair.shift()); + var value = pair.length > 1 ? pair.join('=') : pair[0]; + if (value != undefined) value = decodeURIComponent(value); + + if (key in hash) { + if (!Object.isArray(hash[key])) hash[key] = [hash[key]]; + hash[key].push(value); + } + else hash[key] = value; + } + return hash; + }); + } + + function toArray() { + return this.split(''); + } + + function succ() { + return this.slice(0, this.length - 1) + + String.fromCharCode(this.charCodeAt(this.length - 1) + 1); + } + + function times(count) { + return count < 1 ? '' : new Array(count + 1).join(this); + } + + function camelize() { + var parts = this.split('-'), len = parts.length; + if (len == 1) return parts[0]; + + var camelized = this.charAt(0) == '-' + ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) + : parts[0]; + + for (var i = 1; i < len; i++) + camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); + + return camelized; + } + + function capitalize() { + return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); + } + + function underscore() { + return this.replace(/::/g, '/') + .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2') + .replace(/([a-z\d])([A-Z])/g, '$1_$2') + .replace(/-/g, '_') + .toLowerCase(); + } + + function dasherize() { + return this.replace(/_/g, '-'); + } + + function inspect(useDoubleQuotes) { + var escapedString = this.replace(/[\x00-\x1f\\]/g, function(character) { + if (character in String.specialChar) { + return String.specialChar[character]; + } + return '\\u00' + character.charCodeAt().toPaddedString(2, 16); + }); + if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; + return "'" + escapedString.replace(/'/g, '\\\'') + "'"; + } + + function toJSON() { + return this.inspect(true); + } + + function unfilterJSON(filter) { + return this.replace(filter || Prototype.JSONFilter, '$1'); + } + + function isJSON() { + var str = this; + if (str.blank()) return false; + str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''); + return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str); + } + + function evalJSON(sanitize) { + var json = this.unfilterJSON(); + try { + if (!sanitize || json.isJSON()) return eval('(' + json + ')'); + } catch (e) { } + throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); + } + + function include(pattern) { + return this.indexOf(pattern) > -1; + } + + function startsWith(pattern) { + return this.indexOf(pattern) === 0; + } + + function endsWith(pattern) { + var d = this.length - pattern.length; + return d >= 0 && this.lastIndexOf(pattern) === d; + } + + function empty() { + return this == ''; + } + + function blank() { + return /^\s*$/.test(this); + } + + function interpolate(object, pattern) { + return new Template(this, pattern).evaluate(object); + } + + return { + gsub: gsub, + sub: sub, + scan: scan, + truncate: truncate, + strip: String.prototype.trim ? String.prototype.trim : strip, + stripTags: stripTags, + stripScripts: stripScripts, + extractScripts: extractScripts, + evalScripts: evalScripts, + escapeHTML: escapeHTML, + unescapeHTML: unescapeHTML, + toQueryParams: toQueryParams, + parseQuery: toQueryParams, + toArray: toArray, + succ: succ, + times: times, + camelize: camelize, + capitalize: capitalize, + underscore: underscore, + dasherize: dasherize, + inspect: inspect, + toJSON: toJSON, + unfilterJSON: unfilterJSON, + isJSON: isJSON, + evalJSON: evalJSON, + include: include, + startsWith: startsWith, + endsWith: endsWith, + empty: empty, + blank: blank, + interpolate: interpolate + }; +})()); + +var Template = Class.create({ + initialize: function(template, pattern) { + this.template = template.toString(); + this.pattern = pattern || Template.Pattern; + }, + + evaluate: function(object) { + if (object && Object.isFunction(object.toTemplateReplacements)) + object = object.toTemplateReplacements(); + + return this.template.gsub(this.pattern, function(match) { + if (object == null) return (match[1] + ''); + + var before = match[1] || ''; + if (before == '\\') return match[2]; + + var ctx = object, expr = match[3]; + var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/; + match = pattern.exec(expr); + if (match == null) return before; + + while (match != null) { + var comp = match[1].startsWith('[') ? match[2].replace(/\\\\]/g, ']') : match[1]; + ctx = ctx[comp]; + if (null == ctx || '' == match[3]) break; + expr = expr.substring('[' == match[3] ? match[1].length : match[0].length); + match = pattern.exec(expr); + } + + return before + String.interpret(ctx); + }); + } +}); +Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; + +var $break = { }; + +var Enumerable = (function() { + function each(iterator, context) { + var index = 0; + try { + this._each(function(value) { + iterator.call(context, value, index++); + }); + } catch (e) { + if (e != $break) throw e; + } + return this; + } + + function eachSlice(number, iterator, context) { + var index = -number, slices = [], array = this.toArray(); + if (number < 1) return array; + while ((index += number) < array.length) + slices.push(array.slice(index, index+number)); + return slices.collect(iterator, context); + } + + function all(iterator, context) { + iterator = iterator || Prototype.K; + var result = true; + this.each(function(value, index) { + result = result && !!iterator.call(context, value, index); + if (!result) throw $break; + }); + return result; + } + + function any(iterator, context) { + iterator = iterator || Prototype.K; + var result = false; + this.each(function(value, index) { + if (result = !!iterator.call(context, value, index)) + throw $break; + }); + return result; + } + + function collect(iterator, context) { + iterator = iterator || Prototype.K; + var results = []; + this.each(function(value, index) { + results.push(iterator.call(context, value, index)); + }); + return results; + } + + function detect(iterator, context) { + var result; + this.each(function(value, index) { + if (iterator.call(context, value, index)) { + result = value; + throw $break; + } + }); + return result; + } + + function findAll(iterator, context) { + var results = []; + this.each(function(value, index) { + if (iterator.call(context, value, index)) + results.push(value); + }); + return results; + } + + function grep(filter, iterator, context) { + iterator = iterator || Prototype.K; + var results = []; + + if (Object.isString(filter)) + filter = new RegExp(RegExp.escape(filter)); + + this.each(function(value, index) { + if (filter.match(value)) + results.push(iterator.call(context, value, index)); + }); + return results; + } + + function include(object) { + if (Object.isFunction(this.indexOf)) + if (this.indexOf(object) != -1) return true; + + var found = false; + this.each(function(value) { + if (value == object) { + found = true; + throw $break; + } + }); + return found; + } + + function inGroupsOf(number, fillWith) { + fillWith = Object.isUndefined(fillWith) ? null : fillWith; + return this.eachSlice(number, function(slice) { + while(slice.length < number) slice.push(fillWith); + return slice; + }); + } + + function inject(memo, iterator, context) { + this.each(function(value, index) { + memo = iterator.call(context, memo, value, index); + }); + return memo; + } + + function invoke(method) { + var args = $A(arguments).slice(1); + return this.map(function(value) { + return value[method].apply(value, args); + }); + } + + function max(iterator, context) { + iterator = iterator || Prototype.K; + var result; + this.each(function(value, index) { + value = iterator.call(context, value, index); + if (result == null || value >= result) + result = value; + }); + return result; + } + + function min(iterator, context) { + iterator = iterator || Prototype.K; + var result; + this.each(function(value, index) { + value = iterator.call(context, value, index); + if (result == null || value < result) + result = value; + }); + return result; + } + + function partition(iterator, context) { + iterator = iterator || Prototype.K; + var trues = [], falses = []; + this.each(function(value, index) { + (iterator.call(context, value, index) ? + trues : falses).push(value); + }); + return [trues, falses]; + } + + function pluck(property) { + var results = []; + this.each(function(value) { + results.push(value[property]); + }); + return results; + } + + function reject(iterator, context) { + var results = []; + this.each(function(value, index) { + if (!iterator.call(context, value, index)) + results.push(value); + }); + return results; + } + + function sortBy(iterator, context) { + return this.map(function(value, index) { + return { + value: value, + criteria: iterator.call(context, value, index) + }; + }).sort(function(left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }).pluck('value'); + } + + function toArray() { + return this.map(); + } + + function zip() { + var iterator = Prototype.K, args = $A(arguments); + if (Object.isFunction(args.last())) + iterator = args.pop(); + + var collections = [this].concat(args).map($A); + return this.map(function(value, index) { + return iterator(collections.pluck(index)); + }); + } + + function size() { + return this.toArray().length; + } + + function inspect() { + return '#'; + } + + + + + + + + + + return { + each: each, + eachSlice: eachSlice, + all: all, + every: all, + any: any, + some: any, + collect: collect, + map: collect, + detect: detect, + findAll: findAll, + select: findAll, + filter: findAll, + grep: grep, + include: include, + member: include, + inGroupsOf: inGroupsOf, + inject: inject, + invoke: invoke, + max: max, + min: min, + partition: partition, + pluck: pluck, + reject: reject, + sortBy: sortBy, + toArray: toArray, + entries: toArray, + zip: zip, + size: size, + inspect: inspect, + find: detect + }; +})(); +function $A(iterable) { + if (!iterable) return []; + if ('toArray' in Object(iterable)) return iterable.toArray(); + var length = iterable.length || 0, results = new Array(length); + while (length--) results[length] = iterable[length]; + return results; +} + +function $w(string) { + if (!Object.isString(string)) return []; + string = string.strip(); + return string ? string.split(/\s+/) : []; +} + +Array.from = $A; + + +(function() { + var arrayProto = Array.prototype, + slice = arrayProto.slice, + _each = arrayProto.forEach; // use native browser JS 1.6 implementation if available + + function each(iterator) { + for (var i = 0, length = this.length; i < length; i++) + iterator(this[i]); + } + if (!_each) _each = each; + + function clear() { + this.length = 0; + return this; + } + + function first() { + return this[0]; + } + + function last() { + return this[this.length - 1]; + } + + function compact() { + return this.select(function(value) { + return value != null; + }); + } + + function flatten() { + return this.inject([], function(array, value) { + if (Object.isArray(value)) + return array.concat(value.flatten()); + array.push(value); + return array; + }); + } + + function without() { + var values = slice.call(arguments, 0); + return this.select(function(value) { + return !values.include(value); + }); + } + + function reverse(inline) { + return (inline !== false ? this : this.toArray())._reverse(); + } + + function uniq(sorted) { + return this.inject([], function(array, value, index) { + if (0 == index || (sorted ? array.last() != value : !array.include(value))) + array.push(value); + return array; + }); + } + + function intersect(array) { + return this.uniq().findAll(function(item) { + return array.detect(function(value) { return item === value }); + }); + } + + + function clone() { + return slice.call(this, 0); + } + + function size() { + return this.length; + } + + function inspect() { + return '[' + this.map(Object.inspect).join(', ') + ']'; + } + + function toJSON() { + var results = []; + this.each(function(object) { + var value = Object.toJSON(object); + if (!Object.isUndefined(value)) results.push(value); + }); + return '[' + results.join(', ') + ']'; + } + + function indexOf(item, i) { + i || (i = 0); + var length = this.length; + if (i < 0) i = length + i; + for (; i < length; i++) + if (this[i] === item) return i; + return -1; + } + + function lastIndexOf(item, i) { + i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1; + var n = this.slice(0, i).reverse().indexOf(item); + return (n < 0) ? n : i - n - 1; + } + + function concat() { + var array = slice.call(this, 0), item; + for (var i = 0, length = arguments.length; i < length; i++) { + item = arguments[i]; + if (Object.isArray(item) && !('callee' in item)) { + for (var j = 0, arrayLength = item.length; j < arrayLength; j++) + array.push(item[j]); + } else { + array.push(item); + } + } + return array; + } + + Object.extend(arrayProto, Enumerable); + + if (!arrayProto._reverse) + arrayProto._reverse = arrayProto.reverse; + + Object.extend(arrayProto, { + _each: _each, + clear: clear, + first: first, + last: last, + compact: compact, + flatten: flatten, + without: without, + reverse: reverse, + uniq: uniq, + intersect: intersect, + clone: clone, + toArray: clone, + size: size, + inspect: inspect, + toJSON: toJSON + }); + + var CONCAT_ARGUMENTS_BUGGY = (function() { + return [].concat(arguments)[0][0] !== 1; + })(1,2) + + if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat; + + if (!arrayProto.indexOf) arrayProto.indexOf = indexOf; + if (!arrayProto.lastIndexOf) arrayProto.lastIndexOf = lastIndexOf; +})(); +function $H(object) { + return new Hash(object); +}; + +var Hash = Class.create(Enumerable, (function() { + function initialize(object) { + this._object = Object.isHash(object) ? object.toObject() : Object.clone(object); + } + + function _each(iterator) { + for (var key in this._object) { + var value = this._object[key], pair = [key, value]; + pair.key = key; + pair.value = value; + iterator(pair); + } + } + + function set(key, value) { + return this._object[key] = value; + } + + function get(key) { + if (this._object[key] !== Object.prototype[key]) + return this._object[key]; + } + + function unset(key) { + var value = this._object[key]; + delete this._object[key]; + return value; + } + + function toObject() { + return Object.clone(this._object); + } + + function keys() { + return this.pluck('key'); + } + + function values() { + return this.pluck('value'); + } + + function index(value) { + var match = this.detect(function(pair) { + return pair.value === value; + }); + return match && match.key; + } + + function merge(object) { + return this.clone().update(object); + } + + function update(object) { + return new Hash(object).inject(this, function(result, pair) { + result.set(pair.key, pair.value); + return result; + }); + } + + function toQueryPair(key, value) { + if (Object.isUndefined(value)) return key; + return key + '=' + encodeURIComponent(String.interpret(value)); + } + + function toQueryString() { + return this.inject([], function(results, pair) { + var key = encodeURIComponent(pair.key), values = pair.value; + + if (values && typeof values == 'object') { + if (Object.isArray(values)) + return results.concat(values.map(toQueryPair.curry(key))); + } else results.push(toQueryPair(key, values)); + return results; + }).join('&'); + } + + function inspect() { + return '#'; + } + + function toJSON() { + return Object.toJSON(this.toObject()); + } + + function clone() { + return new Hash(this); + } + + return { + initialize: initialize, + _each: _each, + set: set, + get: get, + unset: unset, + toObject: toObject, + toTemplateReplacements: toObject, + keys: keys, + values: values, + index: index, + merge: merge, + update: update, + toQueryString: toQueryString, + inspect: inspect, + toJSON: toJSON, + clone: clone + }; +})()); + +Hash.from = $H; +Object.extend(Number.prototype, (function() { + function toColorPart() { + return this.toPaddedString(2, 16); + } + + function succ() { + return this + 1; + } + + function times(iterator, context) { + $R(0, this, true).each(iterator, context); + return this; + } + + function toPaddedString(length, radix) { + var string = this.toString(radix || 10); + return '0'.times(length - string.length) + string; + } + + function toJSON() { + return isFinite(this) ? this.toString() : 'null'; + } + + function abs() { + return Math.abs(this); + } + + function round() { + return Math.round(this); + } + + function ceil() { + return Math.ceil(this); + } + + function floor() { + return Math.floor(this); + } + + return { + toColorPart: toColorPart, + succ: succ, + times: times, + toPaddedString: toPaddedString, + toJSON: toJSON, + abs: abs, + round: round, + ceil: ceil, + floor: floor + }; +})()); + +function $R(start, end, exclusive) { + return new ObjectRange(start, end, exclusive); +} + +var ObjectRange = Class.create(Enumerable, (function() { + function initialize(start, end, exclusive) { + this.start = start; + this.end = end; + this.exclusive = exclusive; + } + + function _each(iterator) { + var value = this.start; + while (this.include(value)) { + iterator(value); + value = value.succ(); + } + } + + function include(value) { + if (value < this.start) + return false; + if (this.exclusive) + return value < this.end; + return value <= this.end; + } + + return { + initialize: initialize, + _each: _each, + include: include + }; +})()); + + + +var Ajax = { + getTransport: function() { + return Try.these( + function() {return new XMLHttpRequest()}, + function() {return new ActiveXObject('Msxml2.XMLHTTP')}, + function() {return new ActiveXObject('Microsoft.XMLHTTP')} + ) || false; + }, + + activeRequestCount: 0 +}; + +Ajax.Responders = { + responders: [], + + _each: function(iterator) { + this.responders._each(iterator); + }, + + register: function(responder) { + if (!this.include(responder)) + this.responders.push(responder); + }, + + unregister: function(responder) { + this.responders = this.responders.without(responder); + }, + + dispatch: function(callback, request, transport, json) { + this.each(function(responder) { + if (Object.isFunction(responder[callback])) { + try { + responder[callback].apply(responder, [request, transport, json]); + } catch (e) { } + } + }); + } +}; + +Object.extend(Ajax.Responders, Enumerable); + +Ajax.Responders.register({ + onCreate: function() { Ajax.activeRequestCount++ }, + onComplete: function() { Ajax.activeRequestCount-- } +}); +Ajax.Base = Class.create({ + initialize: function(options) { + this.options = { + method: 'post', + asynchronous: true, + contentType: 'application/x-www-form-urlencoded', + encoding: 'UTF-8', + parameters: '', + evalJSON: true, + evalJS: true + }; + Object.extend(this.options, options || { }); + + this.options.method = this.options.method.toLowerCase(); + + if (Object.isString(this.options.parameters)) + this.options.parameters = this.options.parameters.toQueryParams(); + else if (Object.isHash(this.options.parameters)) + this.options.parameters = this.options.parameters.toObject(); + } +}); +Ajax.Request = Class.create(Ajax.Base, { + _complete: false, + + initialize: function($super, url, options) { + $super(options); + this.transport = Ajax.getTransport(); + this.request(url); + }, + + request: function(url) { + this.url = url; + this.method = this.options.method; + var params = Object.clone(this.options.parameters); + + if (!['get', 'post'].include(this.method)) { + params['_method'] = this.method; + this.method = 'post'; + } + + this.parameters = params; + + if (params = Object.toQueryString(params)) { + if (this.method == 'get') + this.url += (this.url.include('?') ? '&' : '?') + params; + else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) + params += '&_='; + } + + try { + var response = new Ajax.Response(this); + if (this.options.onCreate) this.options.onCreate(response); + Ajax.Responders.dispatch('onCreate', this, response); + + this.transport.open(this.method.toUpperCase(), this.url, + this.options.asynchronous); + + if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1); + + this.transport.onreadystatechange = this.onStateChange.bind(this); + this.setRequestHeaders(); + + this.body = this.method == 'post' ? (this.options.postBody || params) : null; + this.transport.send(this.body); + + /* Force Firefox to handle ready state 4 for synchronous requests */ + if (!this.options.asynchronous && this.transport.overrideMimeType) + this.onStateChange(); + + } + catch (e) { + this.dispatchException(e); + } + }, + + onStateChange: function() { + var readyState = this.transport.readyState; + if (readyState > 1 && !((readyState == 4) && this._complete)) + this.respondToReadyState(this.transport.readyState); + }, + + setRequestHeaders: function() { + var headers = { + 'X-Requested-With': 'XMLHttpRequest', + 'X-Prototype-Version': Prototype.Version, + 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' + }; + + if (this.method == 'post') { + headers['Content-type'] = this.options.contentType + + (this.options.encoding ? '; charset=' + this.options.encoding : ''); + + /* Force "Connection: close" for older Mozilla browsers to work + * around a bug where XMLHttpRequest sends an incorrect + * Content-length header. See Mozilla Bugzilla #246651. + */ + if (this.transport.overrideMimeType && + (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) + headers['Connection'] = 'close'; + } + + if (typeof this.options.requestHeaders == 'object') { + var extras = this.options.requestHeaders; + + if (Object.isFunction(extras.push)) + for (var i = 0, length = extras.length; i < length; i += 2) + headers[extras[i]] = extras[i+1]; + else + $H(extras).each(function(pair) { headers[pair.key] = pair.value }); + } + + for (var name in headers) + this.transport.setRequestHeader(name, headers[name]); + }, + + success: function() { + var status = this.getStatus(); + return !status || (status >= 200 && status < 300); + }, + + getStatus: function() { + try { + return this.transport.status || 0; + } catch (e) { return 0 } + }, + + respondToReadyState: function(readyState) { + var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this); + + if (state == 'Complete') { + try { + this._complete = true; + (this.options['on' + response.status] + || this.options['on' + (this.success() ? 'Success' : 'Failure')] + || Prototype.emptyFunction)(response, response.headerJSON); + } catch (e) { + this.dispatchException(e); + } + + var contentType = response.getHeader('Content-type'); + if (this.options.evalJS == 'force' + || (this.options.evalJS && this.isSameOrigin() && contentType + && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i))) + this.evalResponse(); + } + + try { + (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON); + Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON); + } catch (e) { + this.dispatchException(e); + } + + if (state == 'Complete') { + this.transport.onreadystatechange = Prototype.emptyFunction; + } + }, + + isSameOrigin: function() { + var m = this.url.match(/^\s*https?:\/\/[^\/]*/); + return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({ + protocol: location.protocol, + domain: document.domain, + port: location.port ? ':' + location.port : '' + })); + }, + + getHeader: function(name) { + try { + return this.transport.getResponseHeader(name) || null; + } catch (e) { return null; } + }, + + evalResponse: function() { + try { + return eval((this.transport.responseText || '').unfilterJSON()); + } catch (e) { + this.dispatchException(e); + } + }, + + dispatchException: function(exception) { + (this.options.onException || Prototype.emptyFunction)(this, exception); + Ajax.Responders.dispatch('onException', this, exception); + } +}); + +Ajax.Request.Events = + ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; + + + + + + + + +Ajax.Response = Class.create({ + initialize: function(request){ + this.request = request; + var transport = this.transport = request.transport, + readyState = this.readyState = transport.readyState; + + if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) { + this.status = this.getStatus(); + this.statusText = this.getStatusText(); + this.responseText = String.interpret(transport.responseText); + this.headerJSON = this._getHeaderJSON(); + } + + if(readyState == 4) { + var xml = transport.responseXML; + this.responseXML = Object.isUndefined(xml) ? null : xml; + this.responseJSON = this._getResponseJSON(); + } + }, + + status: 0, + + statusText: '', + + getStatus: Ajax.Request.prototype.getStatus, + + getStatusText: function() { + try { + return this.transport.statusText || ''; + } catch (e) { return '' } + }, + + getHeader: Ajax.Request.prototype.getHeader, + + getAllHeaders: function() { + try { + return this.getAllResponseHeaders(); + } catch (e) { return null } + }, + + getResponseHeader: function(name) { + return this.transport.getResponseHeader(name); + }, + + getAllResponseHeaders: function() { + return this.transport.getAllResponseHeaders(); + }, + + _getHeaderJSON: function() { + var json = this.getHeader('X-JSON'); + if (!json) return null; + json = decodeURIComponent(escape(json)); + try { + return json.evalJSON(this.request.options.sanitizeJSON || + !this.request.isSameOrigin()); + } catch (e) { + this.request.dispatchException(e); + } + }, + + _getResponseJSON: function() { + var options = this.request.options; + if (!options.evalJSON || (options.evalJSON != 'force' && + !(this.getHeader('Content-type') || '').include('application/json')) || + this.responseText.blank()) + return null; + try { + return this.responseText.evalJSON(options.sanitizeJSON || + !this.request.isSameOrigin()); + } catch (e) { + this.request.dispatchException(e); + } + } +}); + +Ajax.Updater = Class.create(Ajax.Request, { + initialize: function($super, container, url, options) { + this.container = { + success: (container.success || container), + failure: (container.failure || (container.success ? null : container)) + }; + + options = Object.clone(options); + var onComplete = options.onComplete; + options.onComplete = (function(response, json) { + this.updateContent(response.responseText); + if (Object.isFunction(onComplete)) onComplete(response, json); + }).bind(this); + + $super(url, options); + }, + + updateContent: function(responseText) { + var receiver = this.container[this.success() ? 'success' : 'failure'], + options = this.options; + + if (!options.evalScripts) responseText = responseText.stripScripts(); + + if (receiver = $(receiver)) { + if (options.insertion) { + if (Object.isString(options.insertion)) { + var insertion = { }; insertion[options.insertion] = responseText; + receiver.insert(insertion); + } + else options.insertion(receiver, responseText); + } + else receiver.update(responseText); + } + } +}); + +Ajax.PeriodicalUpdater = Class.create(Ajax.Base, { + initialize: function($super, container, url, options) { + $super(options); + this.onComplete = this.options.onComplete; + + this.frequency = (this.options.frequency || 2); + this.decay = (this.options.decay || 1); + + this.updater = { }; + this.container = container; + this.url = url; + + this.start(); + }, + + start: function() { + this.options.onComplete = this.updateComplete.bind(this); + this.onTimerEvent(); + }, + + stop: function() { + this.updater.options.onComplete = undefined; + clearTimeout(this.timer); + (this.onComplete || Prototype.emptyFunction).apply(this, arguments); + }, + + updateComplete: function(response) { + if (this.options.decay) { + this.decay = (response.responseText == this.lastText ? + this.decay * this.options.decay : 1); + + this.lastText = response.responseText; + } + this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency); + }, + + onTimerEvent: function() { + this.updater = new Ajax.Updater(this.container, this.url, this.options); + } +}); + + + +function $(element) { + if (arguments.length > 1) { + for (var i = 0, elements = [], length = arguments.length; i < length; i++) + elements.push($(arguments[i])); + return elements; + } + if (Object.isString(element)) + element = document.getElementById(element); + return Element.extend(element); +} + +if (Prototype.BrowserFeatures.XPath) { + document._getElementsByXPath = function(expression, parentElement) { + var results = []; + var query = document.evaluate(expression, $(parentElement) || document, + null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); + for (var i = 0, length = query.snapshotLength; i < length; i++) + results.push(Element.extend(query.snapshotItem(i))); + return results; + }; +} + +/*--------------------------------------------------------------------------*/ + +if (!window.Node) var Node = { }; + +if (!Node.ELEMENT_NODE) { + Object.extend(Node, { + ELEMENT_NODE: 1, + ATTRIBUTE_NODE: 2, + TEXT_NODE: 3, + CDATA_SECTION_NODE: 4, + ENTITY_REFERENCE_NODE: 5, + ENTITY_NODE: 6, + PROCESSING_INSTRUCTION_NODE: 7, + COMMENT_NODE: 8, + DOCUMENT_NODE: 9, + DOCUMENT_TYPE_NODE: 10, + DOCUMENT_FRAGMENT_NODE: 11, + NOTATION_NODE: 12 + }); +} + + +(function(global) { + + var SETATTRIBUTE_IGNORES_NAME = (function(){ + var elForm = document.createElement("form"); + var elInput = document.createElement("input"); + var root = document.documentElement; + elInput.setAttribute("name", "test"); + elForm.appendChild(elInput); + root.appendChild(elForm); + var isBuggy = elForm.elements + ? (typeof elForm.elements.test == "undefined") + : null; + root.removeChild(elForm); + elForm = elInput = null; + return isBuggy; + })(); + + var element = global.Element; + global.Element = function(tagName, attributes) { + attributes = attributes || { }; + tagName = tagName.toLowerCase(); + var cache = Element.cache; + if (SETATTRIBUTE_IGNORES_NAME && attributes.name) { + tagName = '<' + tagName + ' name="' + attributes.name + '">'; + delete attributes.name; + return Element.writeAttribute(document.createElement(tagName), attributes); + } + if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName)); + return Element.writeAttribute(cache[tagName].cloneNode(false), attributes); + }; + Object.extend(global.Element, element || { }); + if (element) global.Element.prototype = element.prototype; +})(this); + +Element.cache = { }; +Element.idCounter = 1; + +Element.Methods = { + visible: function(element) { + return $(element).style.display != 'none'; + }, + + toggle: function(element) { + element = $(element); + Element[Element.visible(element) ? 'hide' : 'show'](element); + return element; + }, + + + hide: function(element) { + element = $(element); + element.style.display = 'none'; + return element; + }, + + show: function(element) { + element = $(element); + element.style.display = ''; + return element; + }, + + remove: function(element) { + element = $(element); + element.parentNode.removeChild(element); + return element; + }, + + update: (function(){ + + var SELECT_ELEMENT_INNERHTML_BUGGY = (function(){ + var el = document.createElement("select"), + isBuggy = true; + el.innerHTML = ""; + if (el.options && el.options[0]) { + isBuggy = el.options[0].nodeName.toUpperCase() !== "OPTION"; + } + el = null; + return isBuggy; + })(); + + var TABLE_ELEMENT_INNERHTML_BUGGY = (function(){ + try { + var el = document.createElement("table"); + if (el && el.tBodies) { + el.innerHTML = "test"; + var isBuggy = typeof el.tBodies[0] == "undefined"; + el = null; + return isBuggy; + } + } catch (e) { + return true; + } + })(); + + var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () { + var s = document.createElement("script"), + isBuggy = false; + try { + s.appendChild(document.createTextNode("")); + isBuggy = !s.firstChild || + s.firstChild && s.firstChild.nodeType !== 3; + } catch (e) { + isBuggy = true; + } + s = null; + return isBuggy; + })(); + + function update(element, content) { + element = $(element); + + if (content && content.toElement) + content = content.toElement(); + + if (Object.isElement(content)) + return element.update().insert(content); + + content = Object.toHTML(content); + + var tagName = element.tagName.toUpperCase(); + + if (tagName === 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING) { + element.text = content; + return element; + } + + if (SELECT_ELEMENT_INNERHTML_BUGGY || TABLE_ELEMENT_INNERHTML_BUGGY) { + if (tagName in Element._insertionTranslations.tags) { + while (element.firstChild) { + element.removeChild(element.firstChild); + } + Element._getContentFromAnonymousElement(tagName, content.stripScripts()) + .each(function(node) { + element.appendChild(node) + }); + } + else { + element.innerHTML = content.stripScripts(); + } + } + else { + element.innerHTML = content.stripScripts(); + } + + content.evalScripts.bind(content).defer(); + return element; + } + + return update; + })(), + + replace: function(element, content) { + element = $(element); + if (content && content.toElement) content = content.toElement(); + else if (!Object.isElement(content)) { + content = Object.toHTML(content); + var range = element.ownerDocument.createRange(); + range.selectNode(element); + content.evalScripts.bind(content).defer(); + content = range.createContextualFragment(content.stripScripts()); + } + element.parentNode.replaceChild(content, element); + return element; + }, + + insert: function(element, insertions) { + element = $(element); + + if (Object.isString(insertions) || Object.isNumber(insertions) || + Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML))) + insertions = {bottom:insertions}; + + var content, insert, tagName, childNodes; + + for (var position in insertions) { + content = insertions[position]; + position = position.toLowerCase(); + insert = Element._insertionTranslations[position]; + + if (content && content.toElement) content = content.toElement(); + if (Object.isElement(content)) { + insert(element, content); + continue; + } + + content = Object.toHTML(content); + + tagName = ((position == 'before' || position == 'after') + ? element.parentNode : element).tagName.toUpperCase(); + + childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); + + if (position == 'top' || position == 'after') childNodes.reverse(); + childNodes.each(insert.curry(element)); + + content.evalScripts.bind(content).defer(); + } + + return element; + }, + + wrap: function(element, wrapper, attributes) { + element = $(element); + if (Object.isElement(wrapper)) + $(wrapper).writeAttribute(attributes || { }); + else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes); + else wrapper = new Element('div', wrapper); + if (element.parentNode) + element.parentNode.replaceChild(wrapper, element); + wrapper.appendChild(element); + return wrapper; + }, + + inspect: function(element) { + element = $(element); + var result = '<' + element.tagName.toLowerCase(); + $H({'id': 'id', 'className': 'class'}).each(function(pair) { + var property = pair.first(), attribute = pair.last(); + var value = (element[property] || '').toString(); + if (value) result += ' ' + attribute + '=' + value.inspect(true); + }); + return result + '>'; + }, + + recursivelyCollect: function(element, property) { + element = $(element); + var elements = []; + while (element = element[property]) + if (element.nodeType == 1) + elements.push(Element.extend(element)); + return elements; + }, + + ancestors: function(element) { + return Element.recursivelyCollect(element, 'parentNode'); + }, + + descendants: function(element) { + return Element.select(element, "*"); + }, + + firstDescendant: function(element) { + element = $(element).firstChild; + while (element && element.nodeType != 1) element = element.nextSibling; + return $(element); + }, + + immediateDescendants: function(element) { + if (!(element = $(element).firstChild)) return []; + while (element && element.nodeType != 1) element = element.nextSibling; + if (element) return [element].concat($(element).nextSiblings()); + return []; + }, + + previousSiblings: function(element) { + return Element.recursivelyCollect(element, 'previousSibling'); + }, + + nextSiblings: function(element) { + return Element.recursivelyCollect(element, 'nextSibling'); + }, + + siblings: function(element) { + element = $(element); + return Element.previousSiblings(element).reverse() + .concat(Element.nextSiblings(element)); + }, + + match: function(element, selector) { + if (Object.isString(selector)) + selector = new Selector(selector); + return selector.match($(element)); + }, + + up: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return $(element.parentNode); + var ancestors = Element.ancestors(element); + return Object.isNumber(expression) ? ancestors[expression] : + Selector.findElement(ancestors, expression, index); + }, + + down: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return Element.firstDescendant(element); + return Object.isNumber(expression) ? Element.descendants(element)[expression] : + Element.select(element, expression)[index || 0]; + }, + + previous: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element)); + var previousSiblings = Element.previousSiblings(element); + return Object.isNumber(expression) ? previousSiblings[expression] : + Selector.findElement(previousSiblings, expression, index); + }, + + next: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element)); + var nextSiblings = Element.nextSiblings(element); + return Object.isNumber(expression) ? nextSiblings[expression] : + Selector.findElement(nextSiblings, expression, index); + }, + + + select: function(element) { + var args = Array.prototype.slice.call(arguments, 1); + return Selector.findChildElements(element, args); + }, + + adjacent: function(element) { + var args = Array.prototype.slice.call(arguments, 1); + return Selector.findChildElements(element.parentNode, args).without(element); + }, + + identify: function(element) { + element = $(element); + var id = Element.readAttribute(element, 'id'); + if (id) return id; + do { id = 'anonymous_element_' + Element.idCounter++ } while ($(id)); + Element.writeAttribute(element, 'id', id); + return id; + }, + + readAttribute: function(element, name) { + element = $(element); + if (Prototype.Browser.IE) { + var t = Element._attributeTranslations.read; + if (t.values[name]) return t.values[name](element, name); + if (t.names[name]) name = t.names[name]; + if (name.include(':')) { + return (!element.attributes || !element.attributes[name]) ? null : + element.attributes[name].value; + } + } + return element.getAttribute(name); + }, + + writeAttribute: function(element, name, value) { + element = $(element); + var attributes = { }, t = Element._attributeTranslations.write; + + if (typeof name == 'object') attributes = name; + else attributes[name] = Object.isUndefined(value) ? true : value; + + for (var attr in attributes) { + name = t.names[attr] || attr; + value = attributes[attr]; + if (t.values[attr]) name = t.values[attr](element, value); + if (value === false || value === null) + element.removeAttribute(name); + else if (value === true) + element.setAttribute(name, name); + else element.setAttribute(name, value); + } + return element; + }, + + getHeight: function(element) { + return Element.getDimensions(element).height; + }, + + getWidth: function(element) { + return Element.getDimensions(element).width; + }, + + classNames: function(element) { + return new Element.ClassNames(element); + }, + + hasClassName: function(element, className) { + if (!(element = $(element))) return; + var elementClassName = element.className; + return (elementClassName.length > 0 && (elementClassName == className || + new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName))); + }, + + addClassName: function(element, className) { + if (!(element = $(element))) return; + if (!Element.hasClassName(element, className)) + element.className += (element.className ? ' ' : '') + className; + return element; + }, + + removeClassName: function(element, className) { + if (!(element = $(element))) return; + element.className = element.className.replace( + new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip(); + return element; + }, + + toggleClassName: function(element, className) { + if (!(element = $(element))) return; + return Element[Element.hasClassName(element, className) ? + 'removeClassName' : 'addClassName'](element, className); + }, + + cleanWhitespace: function(element) { + element = $(element); + var node = element.firstChild; + while (node) { + var nextNode = node.nextSibling; + if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) + element.removeChild(node); + node = nextNode; + } + return element; + }, + + empty: function(element) { + return $(element).innerHTML.blank(); + }, + + descendantOf: function(element, ancestor) { + element = $(element), ancestor = $(ancestor); + + if (element.compareDocumentPosition) + return (element.compareDocumentPosition(ancestor) & 8) === 8; + + if (ancestor.contains) + return ancestor.contains(element) && ancestor !== element; + + while (element = element.parentNode) + if (element == ancestor) return true; + + return false; + }, + + scrollTo: function(element) { + element = $(element); + var pos = Element.cumulativeOffset(element); + window.scrollTo(pos[0], pos[1]); + return element; + }, + + getStyle: function(element, style) { + element = $(element); + style = style == 'float' ? 'cssFloat' : style.camelize(); + var value = element.style[style]; + if (!value || value == 'auto') { + var css = document.defaultView.getComputedStyle(element, null); + value = css ? css[style] : null; + } + if (style == 'opacity') return value ? parseFloat(value) : 1.0; + return value == 'auto' ? null : value; + }, + + getOpacity: function(element) { + return $(element).getStyle('opacity'); + }, + + setStyle: function(element, styles) { + element = $(element); + var elementStyle = element.style, match; + if (Object.isString(styles)) { + element.style.cssText += ';' + styles; + return styles.include('opacity') ? + element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element; + } + for (var property in styles) + if (property == 'opacity') element.setOpacity(styles[property]); + else + elementStyle[(property == 'float' || property == 'cssFloat') ? + (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') : + property] = styles[property]; + + return element; + }, + + setOpacity: function(element, value) { + element = $(element); + element.style.opacity = (value == 1 || value === '') ? '' : + (value < 0.00001) ? 0 : value; + return element; + }, + + getDimensions: function(element) { + element = $(element); + var display = Element.getStyle(element, 'display'); + if (display != 'none' && display != null) // Safari bug + return {width: element.offsetWidth, height: element.offsetHeight}; + + var els = element.style; + var originalVisibility = els.visibility; + var originalPosition = els.position; + var originalDisplay = els.display; + els.visibility = 'hidden'; + if (originalPosition != 'fixed') // Switching fixed to absolute causes issues in Safari + els.position = 'absolute'; + els.display = 'block'; + var originalWidth = element.clientWidth; + var originalHeight = element.clientHeight; + els.display = originalDisplay; + els.position = originalPosition; + els.visibility = originalVisibility; + return {width: originalWidth, height: originalHeight}; + }, + + makePositioned: function(element) { + element = $(element); + var pos = Element.getStyle(element, 'position'); + if (pos == 'static' || !pos) { + element._madePositioned = true; + element.style.position = 'relative'; + if (Prototype.Browser.Opera) { + element.style.top = 0; + element.style.left = 0; + } + } + return element; + }, + + undoPositioned: function(element) { + element = $(element); + if (element._madePositioned) { + element._madePositioned = undefined; + element.style.position = + element.style.top = + element.style.left = + element.style.bottom = + element.style.right = ''; + } + return element; + }, + + makeClipping: function(element) { + element = $(element); + if (element._overflow) return element; + element._overflow = Element.getStyle(element, 'overflow') || 'auto'; + if (element._overflow !== 'hidden') + element.style.overflow = 'hidden'; + return element; + }, + + undoClipping: function(element) { + element = $(element); + if (!element._overflow) return element; + element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; + element._overflow = null; + return element; + }, + + cumulativeOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + } while (element); + return Element._returnOffset(valueL, valueT); + }, + + positionedOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + if (element) { + if (element.tagName.toUpperCase() == 'BODY') break; + var p = Element.getStyle(element, 'position'); + if (p !== 'static') break; + } + } while (element); + return Element._returnOffset(valueL, valueT); + }, + + absolutize: function(element) { + element = $(element); + if (Element.getStyle(element, 'position') == 'absolute') return element; + + var offsets = Element.positionedOffset(element); + var top = offsets[1]; + var left = offsets[0]; + var width = element.clientWidth; + var height = element.clientHeight; + + element._originalLeft = left - parseFloat(element.style.left || 0); + element._originalTop = top - parseFloat(element.style.top || 0); + element._originalWidth = element.style.width; + element._originalHeight = element.style.height; + + element.style.position = 'absolute'; + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.width = width + 'px'; + element.style.height = height + 'px'; + return element; + }, + + relativize: function(element) { + element = $(element); + if (Element.getStyle(element, 'position') == 'relative') return element; + + element.style.position = 'relative'; + var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); + var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); + + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.height = element._originalHeight; + element.style.width = element._originalWidth; + return element; + }, + + cumulativeScrollOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.scrollTop || 0; + valueL += element.scrollLeft || 0; + element = element.parentNode; + } while (element); + return Element._returnOffset(valueL, valueT); + }, + + getOffsetParent: function(element) { + if (element.offsetParent) return $(element.offsetParent); + if (element == document.body) return $(element); + + while ((element = element.parentNode) && element != document.body) + if (Element.getStyle(element, 'position') != 'static') + return $(element); + + return $(document.body); + }, + + viewportOffset: function(forElement) { + var valueT = 0, valueL = 0; + + var element = forElement; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + + if (element.offsetParent == document.body && + Element.getStyle(element, 'position') == 'absolute') break; + + } while (element = element.offsetParent); + + element = forElement; + do { + if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) { + valueT -= element.scrollTop || 0; + valueL -= element.scrollLeft || 0; + } + } while (element = element.parentNode); + + return Element._returnOffset(valueL, valueT); + }, + + clonePosition: function(element, source) { + var options = Object.extend({ + setLeft: true, + setTop: true, + setWidth: true, + setHeight: true, + offsetTop: 0, + offsetLeft: 0 + }, arguments[2] || { }); + + source = $(source); + var p = Element.viewportOffset(source); + + element = $(element); + var delta = [0, 0]; + var parent = null; + if (Element.getStyle(element, 'position') == 'absolute') { + parent = Element.getOffsetParent(element); + delta = Element.viewportOffset(parent); + } + + if (parent == document.body) { + delta[0] -= document.body.offsetLeft; + delta[1] -= document.body.offsetTop; + } + + if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; + if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; + if (options.setWidth) element.style.width = source.offsetWidth + 'px'; + if (options.setHeight) element.style.height = source.offsetHeight + 'px'; + return element; + } +}; + +Object.extend(Element.Methods, { + getElementsBySelector: Element.Methods.select, + + childElements: Element.Methods.immediateDescendants +}); + +Element._attributeTranslations = { + write: { + names: { + className: 'class', + htmlFor: 'for' + }, + values: { } + } +}; + +if (Prototype.Browser.Opera) { + Element.Methods.getStyle = Element.Methods.getStyle.wrap( + function(proceed, element, style) { + switch (style) { + case 'left': case 'top': case 'right': case 'bottom': + if (proceed(element, 'position') === 'static') return null; + case 'height': case 'width': + if (!Element.visible(element)) return null; + + var dim = parseInt(proceed(element, style), 10); + + if (dim !== element['offset' + style.capitalize()]) + return dim + 'px'; + + var properties; + if (style === 'height') { + properties = ['border-top-width', 'padding-top', + 'padding-bottom', 'border-bottom-width']; + } + else { + properties = ['border-left-width', 'padding-left', + 'padding-right', 'border-right-width']; + } + return properties.inject(dim, function(memo, property) { + var val = proceed(element, property); + return val === null ? memo : memo - parseInt(val, 10); + }) + 'px'; + default: return proceed(element, style); + } + } + ); + + Element.Methods.readAttribute = Element.Methods.readAttribute.wrap( + function(proceed, element, attribute) { + if (attribute === 'title') return element.title; + return proceed(element, attribute); + } + ); +} + +else if (Prototype.Browser.IE) { + Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap( + function(proceed, element) { + element = $(element); + try { element.offsetParent } + catch(e) { return $(document.body) } + var position = element.getStyle('position'); + if (position !== 'static') return proceed(element); + element.setStyle({ position: 'relative' }); + var value = proceed(element); + element.setStyle({ position: position }); + return value; + } + ); + + $w('positionedOffset viewportOffset').each(function(method) { + Element.Methods[method] = Element.Methods[method].wrap( + function(proceed, element) { + element = $(element); + try { element.offsetParent } + catch(e) { return Element._returnOffset(0,0) } + var position = element.getStyle('position'); + if (position !== 'static') return proceed(element); + var offsetParent = element.getOffsetParent(); + if (offsetParent && offsetParent.getStyle('position') === 'fixed') + offsetParent.setStyle({ zoom: 1 }); + element.setStyle({ position: 'relative' }); + var value = proceed(element); + element.setStyle({ position: position }); + return value; + } + ); + }); + + Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap( + function(proceed, element) { + try { element.offsetParent } + catch(e) { return Element._returnOffset(0,0) } + return proceed(element); + } + ); + + Element.Methods.getStyle = function(element, style) { + element = $(element); + style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); + var value = element.style[style]; + if (!value && element.currentStyle) value = element.currentStyle[style]; + + if (style == 'opacity') { + if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) + if (value[1]) return parseFloat(value[1]) / 100; + return 1.0; + } + + if (value == 'auto') { + if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none')) + return element['offset' + style.capitalize()] + 'px'; + return null; + } + return value; + }; + + Element.Methods.setOpacity = function(element, value) { + function stripAlpha(filter){ + return filter.replace(/alpha\([^\)]*\)/gi,''); + } + element = $(element); + var currentStyle = element.currentStyle; + if ((currentStyle && !currentStyle.hasLayout) || + (!currentStyle && element.style.zoom == 'normal')) + element.style.zoom = 1; + + var filter = element.getStyle('filter'), style = element.style; + if (value == 1 || value === '') { + (filter = stripAlpha(filter)) ? + style.filter = filter : style.removeAttribute('filter'); + return element; + } else if (value < 0.00001) value = 0; + style.filter = stripAlpha(filter) + + 'alpha(opacity=' + (value * 100) + ')'; + return element; + }; + + Element._attributeTranslations = (function(){ + + var classProp = 'className'; + var forProp = 'for'; + + var el = document.createElement('div'); + + el.setAttribute(classProp, 'x'); + + if (el.className !== 'x') { + el.setAttribute('class', 'x'); + if (el.className === 'x') { + classProp = 'class'; + } + } + el = null; + + el = document.createElement('label'); + el.setAttribute(forProp, 'x'); + if (el.htmlFor !== 'x') { + el.setAttribute('htmlFor', 'x'); + if (el.htmlFor === 'x') { + forProp = 'htmlFor'; + } + } + el = null; + + return { + read: { + names: { + 'class': classProp, + 'className': classProp, + 'for': forProp, + 'htmlFor': forProp + }, + values: { + _getAttr: function(element, attribute) { + return element.getAttribute(attribute); + }, + _getAttr2: function(element, attribute) { + return element.getAttribute(attribute, 2); + }, + _getAttrNode: function(element, attribute) { + var node = element.getAttributeNode(attribute); + return node ? node.value : ""; + }, + _getEv: (function(){ + + var el = document.createElement('div'); + el.onclick = Prototype.emptyFunction; + var value = el.getAttribute('onclick'); + var f; + + if (String(value).indexOf('{') > -1) { + f = function(element, attribute) { + attribute = element.getAttribute(attribute); + if (!attribute) return null; + attribute = attribute.toString(); + attribute = attribute.split('{')[1]; + attribute = attribute.split('}')[0]; + return attribute.strip(); + }; + } + else if (value === '') { + f = function(element, attribute) { + attribute = element.getAttribute(attribute); + if (!attribute) return null; + return attribute.strip(); + }; + } + el = null; + return f; + })(), + _flag: function(element, attribute) { + return $(element).hasAttribute(attribute) ? attribute : null; + }, + style: function(element) { + return element.style.cssText.toLowerCase(); + }, + title: function(element) { + return element.title; + } + } + } + } + })(); + + Element._attributeTranslations.write = { + names: Object.extend({ + cellpadding: 'cellPadding', + cellspacing: 'cellSpacing' + }, Element._attributeTranslations.read.names), + values: { + checked: function(element, value) { + element.checked = !!value; + }, + + style: function(element, value) { + element.style.cssText = value ? value : ''; + } + } + }; + + Element._attributeTranslations.has = {}; + + $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' + + 'encType maxLength readOnly longDesc frameBorder').each(function(attr) { + Element._attributeTranslations.write.names[attr.toLowerCase()] = attr; + Element._attributeTranslations.has[attr.toLowerCase()] = attr; + }); + + (function(v) { + Object.extend(v, { + href: v._getAttr2, + src: v._getAttr2, + type: v._getAttr, + action: v._getAttrNode, + disabled: v._flag, + checked: v._flag, + readonly: v._flag, + multiple: v._flag, + onload: v._getEv, + onunload: v._getEv, + onclick: v._getEv, + ondblclick: v._getEv, + onmousedown: v._getEv, + onmouseup: v._getEv, + onmouseover: v._getEv, + onmousemove: v._getEv, + onmouseout: v._getEv, + onfocus: v._getEv, + onblur: v._getEv, + onkeypress: v._getEv, + onkeydown: v._getEv, + onkeyup: v._getEv, + onsubmit: v._getEv, + onreset: v._getEv, + onselect: v._getEv, + onchange: v._getEv + }); + })(Element._attributeTranslations.read.values); + + if (Prototype.BrowserFeatures.ElementExtensions) { + (function() { + function _descendants(element) { + var nodes = element.getElementsByTagName('*'), results = []; + for (var i = 0, node; node = nodes[i]; i++) + if (node.tagName !== "!") // Filter out comment nodes. + results.push(node); + return results; + } + + Element.Methods.down = function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return element.firstDescendant(); + return Object.isNumber(expression) ? _descendants(element)[expression] : + Element.select(element, expression)[index || 0]; + } + })(); + } + +} + +else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) { + Element.Methods.setOpacity = function(element, value) { + element = $(element); + element.style.opacity = (value == 1) ? 0.999999 : + (value === '') ? '' : (value < 0.00001) ? 0 : value; + return element; + }; +} + +else if (Prototype.Browser.WebKit) { + Element.Methods.setOpacity = function(element, value) { + element = $(element); + element.style.opacity = (value == 1 || value === '') ? '' : + (value < 0.00001) ? 0 : value; + + if (value == 1) + if(element.tagName.toUpperCase() == 'IMG' && element.width) { + element.width++; element.width--; + } else try { + var n = document.createTextNode(' '); + element.appendChild(n); + element.removeChild(n); + } catch (e) { } + + return element; + }; + + Element.Methods.cumulativeOffset = function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + if (element.offsetParent == document.body) + if (Element.getStyle(element, 'position') == 'absolute') break; + + element = element.offsetParent; + } while (element); + + return Element._returnOffset(valueL, valueT); + }; +} + +if ('outerHTML' in document.documentElement) { + Element.Methods.replace = function(element, content) { + element = $(element); + + if (content && content.toElement) content = content.toElement(); + if (Object.isElement(content)) { + element.parentNode.replaceChild(content, element); + return element; + } + + content = Object.toHTML(content); + var parent = element.parentNode, tagName = parent.tagName.toUpperCase(); + + if (Element._insertionTranslations.tags[tagName]) { + var nextSibling = element.next(); + var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); + parent.removeChild(element); + if (nextSibling) + fragments.each(function(node) { parent.insertBefore(node, nextSibling) }); + else + fragments.each(function(node) { parent.appendChild(node) }); + } + else element.outerHTML = content.stripScripts(); + + content.evalScripts.bind(content).defer(); + return element; + }; +} + +Element._returnOffset = function(l, t) { + var result = [l, t]; + result.left = l; + result.top = t; + return result; +}; + +Element._getContentFromAnonymousElement = function(tagName, html) { + var div = new Element('div'), t = Element._insertionTranslations.tags[tagName]; + if (t) { + div.innerHTML = t[0] + html + t[1]; + t[2].times(function() { div = div.firstChild }); + } else div.innerHTML = html; + return $A(div.childNodes); +}; + +Element._insertionTranslations = { + before: function(element, node) { + element.parentNode.insertBefore(node, element); + }, + top: function(element, node) { + element.insertBefore(node, element.firstChild); + }, + bottom: function(element, node) { + element.appendChild(node); + }, + after: function(element, node) { + element.parentNode.insertBefore(node, element.nextSibling); + }, + tags: { + TABLE: ['', '
', 1], + TBODY: ['', '
', 2], + TR: ['', '
', 3], + TD: ['
', '
', 4], + SELECT: ['', 1] + } +}; + +(function() { + var tags = Element._insertionTranslations.tags; + Object.extend(tags, { + THEAD: tags.TBODY, + TFOOT: tags.TBODY, + TH: tags.TD + }); +})(); + +Element.Methods.Simulated = { + hasAttribute: function(element, attribute) { + attribute = Element._attributeTranslations.has[attribute] || attribute; + var node = $(element).getAttributeNode(attribute); + return !!(node && node.specified); + } +}; + +Element.Methods.ByTag = { }; + +Object.extend(Element, Element.Methods); + +(function(div) { + + if (!Prototype.BrowserFeatures.ElementExtensions && div['__proto__']) { + window.HTMLElement = { }; + window.HTMLElement.prototype = div['__proto__']; + Prototype.BrowserFeatures.ElementExtensions = true; + } + + div = null; + +})(document.createElement('div')) + +Element.extend = (function() { + + function checkDeficiency(tagName) { + if (typeof window.Element != 'undefined') { + var proto = window.Element.prototype; + if (proto) { + var id = '_' + (Math.random()+'').slice(2); + var el = document.createElement(tagName); + proto[id] = 'x'; + var isBuggy = (el[id] !== 'x'); + delete proto[id]; + el = null; + return isBuggy; + } + } + return false; + } + + function extendElementWith(element, methods) { + for (var property in methods) { + var value = methods[property]; + if (Object.isFunction(value) && !(property in element)) + element[property] = value.methodize(); + } + } + + var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY = checkDeficiency('object'); + + if (Prototype.BrowserFeatures.SpecificElementExtensions) { + if (HTMLOBJECTELEMENT_PROTOTYPE_BUGGY) { + return function(element) { + if (element && typeof element._extendedByPrototype == 'undefined') { + var t = element.tagName; + if (t && (/^(?:object|applet|embed)$/i.test(t))) { + extendElementWith(element, Element.Methods); + extendElementWith(element, Element.Methods.Simulated); + extendElementWith(element, Element.Methods.ByTag[t.toUpperCase()]); + } + } + return element; + } + } + return Prototype.K; + } + + var Methods = { }, ByTag = Element.Methods.ByTag; + + var extend = Object.extend(function(element) { + if (!element || typeof element._extendedByPrototype != 'undefined' || + element.nodeType != 1 || element == window) return element; + + var methods = Object.clone(Methods), + tagName = element.tagName.toUpperCase(); + + if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]); + + extendElementWith(element, methods); + + element._extendedByPrototype = Prototype.emptyFunction; + return element; + + }, { + refresh: function() { + if (!Prototype.BrowserFeatures.ElementExtensions) { + Object.extend(Methods, Element.Methods); + Object.extend(Methods, Element.Methods.Simulated); + } + } + }); + + extend.refresh(); + return extend; +})(); + +Element.hasAttribute = function(element, attribute) { + if (element.hasAttribute) return element.hasAttribute(attribute); + return Element.Methods.Simulated.hasAttribute(element, attribute); +}; + +Element.addMethods = function(methods) { + var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag; + + if (!methods) { + Object.extend(Form, Form.Methods); + Object.extend(Form.Element, Form.Element.Methods); + Object.extend(Element.Methods.ByTag, { + "FORM": Object.clone(Form.Methods), + "INPUT": Object.clone(Form.Element.Methods), + "SELECT": Object.clone(Form.Element.Methods), + "TEXTAREA": Object.clone(Form.Element.Methods) + }); + } + + if (arguments.length == 2) { + var tagName = methods; + methods = arguments[1]; + } + + if (!tagName) Object.extend(Element.Methods, methods || { }); + else { + if (Object.isArray(tagName)) tagName.each(extend); + else extend(tagName); + } + + function extend(tagName) { + tagName = tagName.toUpperCase(); + if (!Element.Methods.ByTag[tagName]) + Element.Methods.ByTag[tagName] = { }; + Object.extend(Element.Methods.ByTag[tagName], methods); + } + + function copy(methods, destination, onlyIfAbsent) { + onlyIfAbsent = onlyIfAbsent || false; + for (var property in methods) { + var value = methods[property]; + if (!Object.isFunction(value)) continue; + if (!onlyIfAbsent || !(property in destination)) + destination[property] = value.methodize(); + } + } + + function findDOMClass(tagName) { + var klass; + var trans = { + "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph", + "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList", + "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading", + "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote", + "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION": + "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD": + "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR": + "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET": + "FrameSet", "IFRAME": "IFrame" + }; + if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element'; + if (window[klass]) return window[klass]; + klass = 'HTML' + tagName + 'Element'; + if (window[klass]) return window[klass]; + klass = 'HTML' + tagName.capitalize() + 'Element'; + if (window[klass]) return window[klass]; + + var element = document.createElement(tagName); + var proto = element['__proto__'] || element.constructor.prototype; + element = null; + return proto; + } + + var elementPrototype = window.HTMLElement ? HTMLElement.prototype : + Element.prototype; + + if (F.ElementExtensions) { + copy(Element.Methods, elementPrototype); + copy(Element.Methods.Simulated, elementPrototype, true); + } + + if (F.SpecificElementExtensions) { + for (var tag in Element.Methods.ByTag) { + var klass = findDOMClass(tag); + if (Object.isUndefined(klass)) continue; + copy(T[tag], klass.prototype); + } + } + + Object.extend(Element, Element.Methods); + delete Element.ByTag; + + if (Element.extend.refresh) Element.extend.refresh(); + Element.cache = { }; +}; + + +document.viewport = { + + getDimensions: function() { + return { width: this.getWidth(), height: this.getHeight() }; + }, + + getScrollOffsets: function() { + return Element._returnOffset( + window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft, + window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); + } +}; + +(function(viewport) { + var B = Prototype.Browser, doc = document, element, property = {}; + + function getRootElement() { + if (B.WebKit && !doc.evaluate) + return document; + + if (B.Opera && window.parseFloat(window.opera.version()) < 9.5) + return document.body; + + return document.documentElement; + } + + function define(D) { + if (!element) element = getRootElement(); + + property[D] = 'client' + D; + + viewport['get' + D] = function() { return element[property[D]] }; + return viewport['get' + D](); + } + + viewport.getWidth = define.curry('Width'); + + viewport.getHeight = define.curry('Height'); +})(document.viewport); + + +Element.Storage = { + UID: 1 +}; + +Element.addMethods({ + getStorage: function(element) { + if (!(element = $(element))) return; + + var uid; + if (element === window) { + uid = 0; + } else { + if (typeof element._prototypeUID === "undefined") + element._prototypeUID = [Element.Storage.UID++]; + uid = element._prototypeUID[0]; + } + + if (!Element.Storage[uid]) + Element.Storage[uid] = $H(); + + return Element.Storage[uid]; + }, + + store: function(element, key, value) { + if (!(element = $(element))) return; + + if (arguments.length === 2) { + Element.getStorage(element).update(key); + } else { + Element.getStorage(element).set(key, value); + } + + return element; + }, + + retrieve: function(element, key, defaultValue) { + if (!(element = $(element))) return; + var hash = Element.getStorage(element), value = hash.get(key); + + if (Object.isUndefined(value)) { + hash.set(key, defaultValue); + value = defaultValue; + } + + return value; + }, + + clone: function(element, deep) { + if (!(element = $(element))) return; + var clone = element.cloneNode(deep); + clone._prototypeUID = void 0; + if (deep) { + var descendants = Element.select(clone, '*'), + i = descendants.length; + while (i--) { + descendants[i]._prototypeUID = void 0; + } + } + return Element.extend(clone); + } +}); +/* Portions of the Selector class are derived from Jack Slocum's DomQuery, + * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style + * license. Please see http://www.yui-ext.com/ for more information. */ + +var Selector = Class.create({ + initialize: function(expression) { + this.expression = expression.strip(); + + if (this.shouldUseSelectorsAPI()) { + this.mode = 'selectorsAPI'; + } else if (this.shouldUseXPath()) { + this.mode = 'xpath'; + this.compileXPathMatcher(); + } else { + this.mode = "normal"; + this.compileMatcher(); + } + + }, + + shouldUseXPath: (function() { + + var IS_DESCENDANT_SELECTOR_BUGGY = (function(){ + var isBuggy = false; + if (document.evaluate && window.XPathResult) { + var el = document.createElement('div'); + el.innerHTML = '
'; + + var xpath = ".//*[local-name()='ul' or local-name()='UL']" + + "//*[local-name()='li' or local-name()='LI']"; + + var result = document.evaluate(xpath, el, null, + XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); + + isBuggy = (result.snapshotLength !== 2); + el = null; + } + return isBuggy; + })(); + + return function() { + if (!Prototype.BrowserFeatures.XPath) return false; + + var e = this.expression; + + if (Prototype.Browser.WebKit && + (e.include("-of-type") || e.include(":empty"))) + return false; + + if ((/(\[[\w-]*?:|:checked)/).test(e)) + return false; + + if (IS_DESCENDANT_SELECTOR_BUGGY) return false; + + return true; + } + + })(), + + shouldUseSelectorsAPI: function() { + if (!Prototype.BrowserFeatures.SelectorsAPI) return false; + + if (Selector.CASE_INSENSITIVE_CLASS_NAMES) return false; + + if (!Selector._div) Selector._div = new Element('div'); + + try { + Selector._div.querySelector(this.expression); + } catch(e) { + return false; + } + + return true; + }, + + compileMatcher: function() { + var e = this.expression, ps = Selector.patterns, h = Selector.handlers, + c = Selector.criteria, le, p, m, len = ps.length, name; + + if (Selector._cache[e]) { + this.matcher = Selector._cache[e]; + return; + } + + this.matcher = ["this.matcher = function(root) {", + "var r = root, h = Selector.handlers, c = false, n;"]; + + while (e && le != e && (/\S/).test(e)) { + le = e; + for (var i = 0; i"; + } +}); + +if (Prototype.BrowserFeatures.SelectorsAPI && + document.compatMode === 'BackCompat') { + Selector.CASE_INSENSITIVE_CLASS_NAMES = (function(){ + var div = document.createElement('div'), + span = document.createElement('span'); + + div.id = "prototype_test_id"; + span.className = 'Test'; + div.appendChild(span); + var isIgnored = (div.querySelector('#prototype_test_id .test') !== null); + div = span = null; + return isIgnored; + })(); +} + +Object.extend(Selector, { + _cache: { }, + + xpath: { + descendant: "//*", + child: "/*", + adjacent: "/following-sibling::*[1]", + laterSibling: '/following-sibling::*', + tagName: function(m) { + if (m[1] == '*') return ''; + return "[local-name()='" + m[1].toLowerCase() + + "' or local-name()='" + m[1].toUpperCase() + "']"; + }, + className: "[contains(concat(' ', @class, ' '), ' #{1} ')]", + id: "[@id='#{1}']", + attrPresence: function(m) { + m[1] = m[1].toLowerCase(); + return new Template("[@#{1}]").evaluate(m); + }, + attr: function(m) { + m[1] = m[1].toLowerCase(); + m[3] = m[5] || m[6]; + return new Template(Selector.xpath.operators[m[2]]).evaluate(m); + }, + pseudo: function(m) { + var h = Selector.xpath.pseudos[m[1]]; + if (!h) return ''; + if (Object.isFunction(h)) return h(m); + return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m); + }, + operators: { + '=': "[@#{1}='#{3}']", + '!=': "[@#{1}!='#{3}']", + '^=': "[starts-with(@#{1}, '#{3}')]", + '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']", + '*=': "[contains(@#{1}, '#{3}')]", + '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]", + '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]" + }, + pseudos: { + 'first-child': '[not(preceding-sibling::*)]', + 'last-child': '[not(following-sibling::*)]', + 'only-child': '[not(preceding-sibling::* or following-sibling::*)]', + 'empty': "[count(*) = 0 and (count(text()) = 0)]", + 'checked': "[@checked]", + 'disabled': "[(@disabled) and (@type!='hidden')]", + 'enabled': "[not(@disabled) and (@type!='hidden')]", + 'not': function(m) { + var e = m[6], p = Selector.patterns, + x = Selector.xpath, le, v, len = p.length, name; + + var exclusion = []; + while (e && le != e && (/\S/).test(e)) { + le = e; + for (var i = 0; i= 0)]"; + return new Template(predicate).evaluate({ + fragment: fragment, a: a, b: b }); + } + } + } + }, + + criteria: { + tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;', + className: 'n = h.className(n, r, "#{1}", c); c = false;', + id: 'n = h.id(n, r, "#{1}", c); c = false;', + attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;', + attr: function(m) { + m[3] = (m[5] || m[6]); + return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m); + }, + pseudo: function(m) { + if (m[6]) m[6] = m[6].replace(/"/g, '\\"'); + return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m); + }, + descendant: 'c = "descendant";', + child: 'c = "child";', + adjacent: 'c = "adjacent";', + laterSibling: 'c = "laterSibling";' + }, + + patterns: [ + { name: 'laterSibling', re: /^\s*~\s*/ }, + { name: 'child', re: /^\s*>\s*/ }, + { name: 'adjacent', re: /^\s*\+\s*/ }, + { name: 'descendant', re: /^\s/ }, + + { name: 'tagName', re: /^\s*(\*|[\w\-]+)(\b|$)?/ }, + { name: 'id', re: /^#([\w\-\*]+)(\b|$)/ }, + { name: 'className', re: /^\.([\w\-\*]+)(\b|$)/ }, + { name: 'pseudo', re: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/ }, + { name: 'attrPresence', re: /^\[((?:[\w-]+:)?[\w-]+)\]/ }, + { name: 'attr', re: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/ } + ], + + assertions: { + tagName: function(element, matches) { + return matches[1].toUpperCase() == element.tagName.toUpperCase(); + }, + + className: function(element, matches) { + return Element.hasClassName(element, matches[1]); + }, + + id: function(element, matches) { + return element.id === matches[1]; + }, + + attrPresence: function(element, matches) { + return Element.hasAttribute(element, matches[1]); + }, + + attr: function(element, matches) { + var nodeValue = Element.readAttribute(element, matches[1]); + return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]); + } + }, + + handlers: { + concat: function(a, b) { + for (var i = 0, node; node = b[i]; i++) + a.push(node); + return a; + }, + + mark: function(nodes) { + var _true = Prototype.emptyFunction; + for (var i = 0, node; node = nodes[i]; i++) + node._countedByPrototype = _true; + return nodes; + }, + + unmark: (function(){ + + var PROPERTIES_ATTRIBUTES_MAP = (function(){ + var el = document.createElement('div'), + isBuggy = false, + propName = '_countedByPrototype', + value = 'x' + el[propName] = value; + isBuggy = (el.getAttribute(propName) === value); + el = null; + return isBuggy; + })(); + + return PROPERTIES_ATTRIBUTES_MAP ? + function(nodes) { + for (var i = 0, node; node = nodes[i]; i++) + node.removeAttribute('_countedByPrototype'); + return nodes; + } : + function(nodes) { + for (var i = 0, node; node = nodes[i]; i++) + node._countedByPrototype = void 0; + return nodes; + } + })(), + + index: function(parentNode, reverse, ofType) { + parentNode._countedByPrototype = Prototype.emptyFunction; + if (reverse) { + for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) { + var node = nodes[i]; + if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; + } + } else { + for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++) + if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; + } + }, + + unique: function(nodes) { + if (nodes.length == 0) return nodes; + var results = [], n; + for (var i = 0, l = nodes.length; i < l; i++) + if (typeof (n = nodes[i])._countedByPrototype == 'undefined') { + n._countedByPrototype = Prototype.emptyFunction; + results.push(Element.extend(n)); + } + return Selector.handlers.unmark(results); + }, + + descendant: function(nodes) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) + h.concat(results, node.getElementsByTagName('*')); + return results; + }, + + child: function(nodes) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) { + for (var j = 0, child; child = node.childNodes[j]; j++) + if (child.nodeType == 1 && child.tagName != '!') results.push(child); + } + return results; + }, + + adjacent: function(nodes) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + var next = this.nextElementSibling(node); + if (next) results.push(next); + } + return results; + }, + + laterSibling: function(nodes) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) + h.concat(results, Element.nextSiblings(node)); + return results; + }, + + nextElementSibling: function(node) { + while (node = node.nextSibling) + if (node.nodeType == 1) return node; + return null; + }, + + previousElementSibling: function(node) { + while (node = node.previousSibling) + if (node.nodeType == 1) return node; + return null; + }, + + tagName: function(nodes, root, tagName, combinator) { + var uTagName = tagName.toUpperCase(); + var results = [], h = Selector.handlers; + if (nodes) { + if (combinator) { + if (combinator == "descendant") { + for (var i = 0, node; node = nodes[i]; i++) + h.concat(results, node.getElementsByTagName(tagName)); + return results; + } else nodes = this[combinator](nodes); + if (tagName == "*") return nodes; + } + for (var i = 0, node; node = nodes[i]; i++) + if (node.tagName.toUpperCase() === uTagName) results.push(node); + return results; + } else return root.getElementsByTagName(tagName); + }, + + id: function(nodes, root, id, combinator) { + var targetNode = $(id), h = Selector.handlers; + + if (root == document) { + if (!targetNode) return []; + if (!nodes) return [targetNode]; + } else { + if (!root.sourceIndex || root.sourceIndex < 1) { + var nodes = root.getElementsByTagName('*'); + for (var j = 0, node; node = nodes[j]; j++) { + if (node.id === id) return [node]; + } + } + } + + if (nodes) { + if (combinator) { + if (combinator == 'child') { + for (var i = 0, node; node = nodes[i]; i++) + if (targetNode.parentNode == node) return [targetNode]; + } else if (combinator == 'descendant') { + for (var i = 0, node; node = nodes[i]; i++) + if (Element.descendantOf(targetNode, node)) return [targetNode]; + } else if (combinator == 'adjacent') { + for (var i = 0, node; node = nodes[i]; i++) + if (Selector.handlers.previousElementSibling(targetNode) == node) + return [targetNode]; + } else nodes = h[combinator](nodes); + } + for (var i = 0, node; node = nodes[i]; i++) + if (node == targetNode) return [targetNode]; + return []; + } + return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : []; + }, + + className: function(nodes, root, className, combinator) { + if (nodes && combinator) nodes = this[combinator](nodes); + return Selector.handlers.byClassName(nodes, root, className); + }, + + byClassName: function(nodes, root, className) { + if (!nodes) nodes = Selector.handlers.descendant([root]); + var needle = ' ' + className + ' '; + for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) { + nodeClassName = node.className; + if (nodeClassName.length == 0) continue; + if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle)) + results.push(node); + } + return results; + }, + + attrPresence: function(nodes, root, attr, combinator) { + if (!nodes) nodes = root.getElementsByTagName("*"); + if (nodes && combinator) nodes = this[combinator](nodes); + var results = []; + for (var i = 0, node; node = nodes[i]; i++) + if (Element.hasAttribute(node, attr)) results.push(node); + return results; + }, + + attr: function(nodes, root, attr, value, operator, combinator) { + if (!nodes) nodes = root.getElementsByTagName("*"); + if (nodes && combinator) nodes = this[combinator](nodes); + var handler = Selector.operators[operator], results = []; + for (var i = 0, node; node = nodes[i]; i++) { + var nodeValue = Element.readAttribute(node, attr); + if (nodeValue === null) continue; + if (handler(nodeValue, value)) results.push(node); + } + return results; + }, + + pseudo: function(nodes, name, value, root, combinator) { + if (nodes && combinator) nodes = this[combinator](nodes); + if (!nodes) nodes = root.getElementsByTagName("*"); + return Selector.pseudos[name](nodes, value, root); + } + }, + + pseudos: { + 'first-child': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + if (Selector.handlers.previousElementSibling(node)) continue; + results.push(node); + } + return results; + }, + 'last-child': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + if (Selector.handlers.nextElementSibling(node)) continue; + results.push(node); + } + return results; + }, + 'only-child': function(nodes, value, root) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (!h.previousElementSibling(node) && !h.nextElementSibling(node)) + results.push(node); + return results; + }, + 'nth-child': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root); + }, + 'nth-last-child': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root, true); + }, + 'nth-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root, false, true); + }, + 'nth-last-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root, true, true); + }, + 'first-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, "1", root, false, true); + }, + 'last-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, "1", root, true, true); + }, + 'only-of-type': function(nodes, formula, root) { + var p = Selector.pseudos; + return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root); + }, + + getIndices: function(a, b, total) { + if (a == 0) return b > 0 ? [b] : []; + return $R(1, total).inject([], function(memo, i) { + if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i); + return memo; + }); + }, + + nth: function(nodes, formula, root, reverse, ofType) { + if (nodes.length == 0) return []; + if (formula == 'even') formula = '2n+0'; + if (formula == 'odd') formula = '2n+1'; + var h = Selector.handlers, results = [], indexed = [], m; + h.mark(nodes); + for (var i = 0, node; node = nodes[i]; i++) { + if (!node.parentNode._countedByPrototype) { + h.index(node.parentNode, reverse, ofType); + indexed.push(node.parentNode); + } + } + if (formula.match(/^\d+$/)) { // just a number + formula = Number(formula); + for (var i = 0, node; node = nodes[i]; i++) + if (node.nodeIndex == formula) results.push(node); + } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b + if (m[1] == "-") m[1] = -1; + var a = m[1] ? Number(m[1]) : 1; + var b = m[2] ? Number(m[2]) : 0; + var indices = Selector.pseudos.getIndices(a, b, nodes.length); + for (var i = 0, node, l = indices.length; node = nodes[i]; i++) { + for (var j = 0; j < l; j++) + if (node.nodeIndex == indices[j]) results.push(node); + } + } + h.unmark(nodes); + h.unmark(indexed); + return results; + }, + + 'empty': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + if (node.tagName == '!' || node.firstChild) continue; + results.push(node); + } + return results; + }, + + 'not': function(nodes, selector, root) { + var h = Selector.handlers, selectorType, m; + var exclusions = new Selector(selector).findElements(root); + h.mark(exclusions); + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (!node._countedByPrototype) results.push(node); + h.unmark(exclusions); + return results; + }, + + 'enabled': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (!node.disabled && (!node.type || node.type !== 'hidden')) + results.push(node); + return results; + }, + + 'disabled': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (node.disabled) results.push(node); + return results; + }, + + 'checked': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (node.checked) results.push(node); + return results; + } + }, + + operators: { + '=': function(nv, v) { return nv == v; }, + '!=': function(nv, v) { return nv != v; }, + '^=': function(nv, v) { return nv == v || nv && nv.startsWith(v); }, + '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); }, + '*=': function(nv, v) { return nv == v || nv && nv.include(v); }, + '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); }, + '|=': function(nv, v) { return ('-' + (nv || "").toUpperCase() + + '-').include('-' + (v || "").toUpperCase() + '-'); } + }, + + split: function(expression) { + var expressions = []; + expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) { + expressions.push(m[1].strip()); + }); + return expressions; + }, + + matchElements: function(elements, expression) { + var matches = $$(expression), h = Selector.handlers; + h.mark(matches); + for (var i = 0, results = [], element; element = elements[i]; i++) + if (element._countedByPrototype) results.push(element); + h.unmark(matches); + return results; + }, + + findElement: function(elements, expression, index) { + if (Object.isNumber(expression)) { + index = expression; expression = false; + } + return Selector.matchElements(elements, expression || '*')[index || 0]; + }, + + findChildElements: function(element, expressions) { + expressions = Selector.split(expressions.join(',')); + var results = [], h = Selector.handlers; + for (var i = 0, l = expressions.length, selector; i < l; i++) { + selector = new Selector(expressions[i].strip()); + h.concat(results, selector.findElements(element)); + } + return (l > 1) ? h.unique(results) : results; + } +}); + +if (Prototype.Browser.IE) { + Object.extend(Selector.handlers, { + concat: function(a, b) { + for (var i = 0, node; node = b[i]; i++) + if (node.tagName !== "!") a.push(node); + return a; + } + }); +} + +function $$() { + return Selector.findChildElements(document, $A(arguments)); +} + +var Form = { + reset: function(form) { + form = $(form); + form.reset(); + return form; + }, + + serializeElements: function(elements, options) { + if (typeof options != 'object') options = { hash: !!options }; + else if (Object.isUndefined(options.hash)) options.hash = true; + var key, value, submitted = false, submit = options.submit; + + var data = elements.inject({ }, function(result, element) { + if (!element.disabled && element.name) { + key = element.name; value = $(element).getValue(); + if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted && + submit !== false && (!submit || key == submit) && (submitted = true)))) { + if (key in result) { + if (!Object.isArray(result[key])) result[key] = [result[key]]; + result[key].push(value); + } + else result[key] = value; + } + } + return result; + }); + + return options.hash ? data : Object.toQueryString(data); + } +}; + +Form.Methods = { + serialize: function(form, options) { + return Form.serializeElements(Form.getElements(form), options); + }, + + getElements: function(form) { + var elements = $(form).getElementsByTagName('*'), + element, + arr = [ ], + serializers = Form.Element.Serializers; + for (var i = 0; element = elements[i]; i++) { + arr.push(element); + } + return arr.inject([], function(elements, child) { + if (serializers[child.tagName.toLowerCase()]) + elements.push(Element.extend(child)); + return elements; + }) + }, + + getInputs: function(form, typeName, name) { + form = $(form); + var inputs = form.getElementsByTagName('input'); + + if (!typeName && !name) return $A(inputs).map(Element.extend); + + for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { + var input = inputs[i]; + if ((typeName && input.type != typeName) || (name && input.name != name)) + continue; + matchingInputs.push(Element.extend(input)); + } + + return matchingInputs; + }, + + disable: function(form) { + form = $(form); + Form.getElements(form).invoke('disable'); + return form; + }, + + enable: function(form) { + form = $(form); + Form.getElements(form).invoke('enable'); + return form; + }, + + findFirstElement: function(form) { + var elements = $(form).getElements().findAll(function(element) { + return 'hidden' != element.type && !element.disabled; + }); + var firstByIndex = elements.findAll(function(element) { + return element.hasAttribute('tabIndex') && element.tabIndex >= 0; + }).sortBy(function(element) { return element.tabIndex }).first(); + + return firstByIndex ? firstByIndex : elements.find(function(element) { + return /^(?:input|select|textarea)$/i.test(element.tagName); + }); + }, + + focusFirstElement: function(form) { + form = $(form); + form.findFirstElement().activate(); + return form; + }, + + request: function(form, options) { + form = $(form), options = Object.clone(options || { }); + + var params = options.parameters, action = form.readAttribute('action') || ''; + if (action.blank()) action = window.location.href; + options.parameters = form.serialize(true); + + if (params) { + if (Object.isString(params)) params = params.toQueryParams(); + Object.extend(options.parameters, params); + } + + if (form.hasAttribute('method') && !options.method) + options.method = form.method; + + return new Ajax.Request(action, options); + } +}; + +/*--------------------------------------------------------------------------*/ + + +Form.Element = { + focus: function(element) { + $(element).focus(); + return element; + }, + + select: function(element) { + $(element).select(); + return element; + } +}; + +Form.Element.Methods = { + + serialize: function(element) { + element = $(element); + if (!element.disabled && element.name) { + var value = element.getValue(); + if (value != undefined) { + var pair = { }; + pair[element.name] = value; + return Object.toQueryString(pair); + } + } + return ''; + }, + + getValue: function(element) { + element = $(element); + var method = element.tagName.toLowerCase(); + return Form.Element.Serializers[method](element); + }, + + setValue: function(element, value) { + element = $(element); + var method = element.tagName.toLowerCase(); + Form.Element.Serializers[method](element, value); + return element; + }, + + clear: function(element) { + $(element).value = ''; + return element; + }, + + present: function(element) { + return $(element).value != ''; + }, + + activate: function(element) { + element = $(element); + try { + element.focus(); + if (element.select && (element.tagName.toLowerCase() != 'input' || + !(/^(?:button|reset|submit)$/i.test(element.type)))) + element.select(); + } catch (e) { } + return element; + }, + + disable: function(element) { + element = $(element); + element.disabled = true; + return element; + }, + + enable: function(element) { + element = $(element); + element.disabled = false; + return element; + } +}; + +/*--------------------------------------------------------------------------*/ + +var Field = Form.Element; + +var $F = Form.Element.Methods.getValue; + +/*--------------------------------------------------------------------------*/ + +Form.Element.Serializers = { + input: function(element, value) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + return Form.Element.Serializers.inputSelector(element, value); + default: + return Form.Element.Serializers.textarea(element, value); + } + }, + + inputSelector: function(element, value) { + if (Object.isUndefined(value)) return element.checked ? element.value : null; + else element.checked = !!value; + }, + + textarea: function(element, value) { + if (Object.isUndefined(value)) return element.value; + else element.value = value; + }, + + select: function(element, value) { + if (Object.isUndefined(value)) + return this[element.type == 'select-one' ? + 'selectOne' : 'selectMany'](element); + else { + var opt, currentValue, single = !Object.isArray(value); + for (var i = 0, length = element.length; i < length; i++) { + opt = element.options[i]; + currentValue = this.optionValue(opt); + if (single) { + if (currentValue == value) { + opt.selected = true; + return; + } + } + else opt.selected = value.include(currentValue); + } + } + }, + + selectOne: function(element) { + var index = element.selectedIndex; + return index >= 0 ? this.optionValue(element.options[index]) : null; + }, + + selectMany: function(element) { + var values, length = element.length; + if (!length) return null; + + for (var i = 0, values = []; i < length; i++) { + var opt = element.options[i]; + if (opt.selected) values.push(this.optionValue(opt)); + } + return values; + }, + + optionValue: function(opt) { + return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; + } +}; + +/*--------------------------------------------------------------------------*/ + + +Abstract.TimedObserver = Class.create(PeriodicalExecuter, { + initialize: function($super, element, frequency, callback) { + $super(callback, frequency); + this.element = $(element); + this.lastValue = this.getValue(); + }, + + execute: function() { + var value = this.getValue(); + if (Object.isString(this.lastValue) && Object.isString(value) ? + this.lastValue != value : String(this.lastValue) != String(value)) { + this.callback(this.element, value); + this.lastValue = value; + } + } +}); + +Form.Element.Observer = Class.create(Abstract.TimedObserver, { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.Observer = Class.create(Abstract.TimedObserver, { + getValue: function() { + return Form.serialize(this.element); + } +}); + +/*--------------------------------------------------------------------------*/ + +Abstract.EventObserver = Class.create({ + initialize: function(element, callback) { + this.element = $(element); + this.callback = callback; + + this.lastValue = this.getValue(); + if (this.element.tagName.toLowerCase() == 'form') + this.registerFormCallbacks(); + else + this.registerCallback(this.element); + }, + + onElementEvent: function() { + var value = this.getValue(); + if (this.lastValue != value) { + this.callback(this.element, value); + this.lastValue = value; + } + }, + + registerFormCallbacks: function() { + Form.getElements(this.element).each(this.registerCallback, this); + }, + + registerCallback: function(element) { + if (element.type) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + Event.observe(element, 'click', this.onElementEvent.bind(this)); + break; + default: + Event.observe(element, 'change', this.onElementEvent.bind(this)); + break; + } + } + } +}); + +Form.Element.EventObserver = Class.create(Abstract.EventObserver, { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.EventObserver = Class.create(Abstract.EventObserver, { + getValue: function() { + return Form.serialize(this.element); + } +}); +(function() { + + var Event = { + KEY_BACKSPACE: 8, + KEY_TAB: 9, + KEY_RETURN: 13, + KEY_ESC: 27, + KEY_LEFT: 37, + KEY_UP: 38, + KEY_RIGHT: 39, + KEY_DOWN: 40, + KEY_DELETE: 46, + KEY_HOME: 36, + KEY_END: 35, + KEY_PAGEUP: 33, + KEY_PAGEDOWN: 34, + KEY_INSERT: 45, + + cache: {} + }; + + var docEl = document.documentElement; + var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl + && 'onmouseleave' in docEl; + + var _isButton; + if (Prototype.Browser.IE) { + var buttonMap = { 0: 1, 1: 4, 2: 2 }; + _isButton = function(event, code) { + return event.button === buttonMap[code]; + }; + } else if (Prototype.Browser.WebKit) { + _isButton = function(event, code) { + switch (code) { + case 0: return event.which == 1 && !event.metaKey; + case 1: return event.which == 1 && event.metaKey; + default: return false; + } + }; + } else { + _isButton = function(event, code) { + return event.which ? (event.which === code + 1) : (event.button === code); + }; + } + + function isLeftClick(event) { return _isButton(event, 0) } + + function isMiddleClick(event) { return _isButton(event, 1) } + + function isRightClick(event) { return _isButton(event, 2) } + + function element(event) { + event = Event.extend(event); + + var node = event.target, type = event.type, + currentTarget = event.currentTarget; + + if (currentTarget && currentTarget.tagName) { + if (type === 'load' || type === 'error' || + (type === 'click' && currentTarget.tagName.toLowerCase() === 'input' + && currentTarget.type === 'radio')) + node = currentTarget; + } + + if (node.nodeType == Node.TEXT_NODE) + node = node.parentNode; + + return Element.extend(node); + } + + function findElement(event, expression) { + var element = Event.element(event); + if (!expression) return element; + var elements = [element].concat(element.ancestors()); + return Selector.findElement(elements, expression, 0); + } + + function pointer(event) { + return { x: pointerX(event), y: pointerY(event) }; + } + + function pointerX(event) { + var docElement = document.documentElement, + body = document.body || { scrollLeft: 0 }; + + return event.pageX || (event.clientX + + (docElement.scrollLeft || body.scrollLeft) - + (docElement.clientLeft || 0)); + } + + function pointerY(event) { + var docElement = document.documentElement, + body = document.body || { scrollTop: 0 }; + + return event.pageY || (event.clientY + + (docElement.scrollTop || body.scrollTop) - + (docElement.clientTop || 0)); + } + + + function stop(event) { + Event.extend(event); + event.preventDefault(); + event.stopPropagation(); + + event.stopped = true; + } + + Event.Methods = { + isLeftClick: isLeftClick, + isMiddleClick: isMiddleClick, + isRightClick: isRightClick, + + element: element, + findElement: findElement, + + pointer: pointer, + pointerX: pointerX, + pointerY: pointerY, + + stop: stop + }; + + + var methods = Object.keys(Event.Methods).inject({ }, function(m, name) { + m[name] = Event.Methods[name].methodize(); + return m; + }); + + if (Prototype.Browser.IE) { + function _relatedTarget(event) { + var element; + switch (event.type) { + case 'mouseover': element = event.fromElement; break; + case 'mouseout': element = event.toElement; break; + default: return null; + } + return Element.extend(element); + } + + Object.extend(methods, { + stopPropagation: function() { this.cancelBubble = true }, + preventDefault: function() { this.returnValue = false }, + inspect: function() { return '[object Event]' } + }); + + Event.extend = function(event, element) { + if (!event) return false; + if (event._extendedByPrototype) return event; + + event._extendedByPrototype = Prototype.emptyFunction; + var pointer = Event.pointer(event); + + Object.extend(event, { + target: event.srcElement || element, + relatedTarget: _relatedTarget(event), + pageX: pointer.x, + pageY: pointer.y + }); + + return Object.extend(event, methods); + }; + } else { + Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__; + Object.extend(Event.prototype, methods); + Event.extend = Prototype.K; + } + + function _createResponder(element, eventName, handler) { + var registry = Element.retrieve(element, 'prototype_event_registry'); + + if (Object.isUndefined(registry)) { + CACHE.push(element); + registry = Element.retrieve(element, 'prototype_event_registry', $H()); + } + + var respondersForEvent = registry.get(eventName); + if (Object.isUndefined(respondersForEvent)) { + respondersForEvent = []; + registry.set(eventName, respondersForEvent); + } + + if (respondersForEvent.pluck('handler').include(handler)) return false; + + var responder; + if (eventName.include(":")) { + responder = function(event) { + if (Object.isUndefined(event.eventName)) + return false; + + if (event.eventName !== eventName) + return false; + + Event.extend(event, element); + handler.call(element, event); + }; + } else { + if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED && + (eventName === "mouseenter" || eventName === "mouseleave")) { + if (eventName === "mouseenter" || eventName === "mouseleave") { + responder = function(event) { + Event.extend(event, element); + + var parent = event.relatedTarget; + while (parent && parent !== element) { + try { parent = parent.parentNode; } + catch(e) { parent = element; } + } + + if (parent === element) return; + + handler.call(element, event); + }; + } + } else { + responder = function(event) { + Event.extend(event, element); + handler.call(element, event); + }; + } + } + + responder.handler = handler; + respondersForEvent.push(responder); + return responder; + } + + function _destroyCache() { + for (var i = 0, length = CACHE.length; i < length; i++) { + Event.stopObserving(CACHE[i]); + CACHE[i] = null; + } + } + + var CACHE = []; + + if (Prototype.Browser.IE) + window.attachEvent('onunload', _destroyCache); + + if (Prototype.Browser.WebKit) + window.addEventListener('unload', Prototype.emptyFunction, false); + + + var _getDOMEventName = Prototype.K; + + if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED) { + _getDOMEventName = function(eventName) { + var translations = { mouseenter: "mouseover", mouseleave: "mouseout" }; + return eventName in translations ? translations[eventName] : eventName; + }; + } + + function observe(element, eventName, handler) { + element = $(element); + + var responder = _createResponder(element, eventName, handler); + + if (!responder) return element; + + if (eventName.include(':')) { + if (element.addEventListener) + element.addEventListener("dataavailable", responder, false); + else { + element.attachEvent("ondataavailable", responder); + element.attachEvent("onfilterchange", responder); + } + } else { + var actualEventName = _getDOMEventName(eventName); + + if (element.addEventListener) + element.addEventListener(actualEventName, responder, false); + else + element.attachEvent("on" + actualEventName, responder); + } + + return element; + } + + function stopObserving(element, eventName, handler) { + element = $(element); + + var registry = Element.retrieve(element, 'prototype_event_registry'); + + if (Object.isUndefined(registry)) return element; + + if (eventName && !handler) { + var responders = registry.get(eventName); + + if (Object.isUndefined(responders)) return element; + + responders.each( function(r) { + Element.stopObserving(element, eventName, r.handler); + }); + return element; + } else if (!eventName) { + registry.each( function(pair) { + var eventName = pair.key, responders = pair.value; + + responders.each( function(r) { + Element.stopObserving(element, eventName, r.handler); + }); + }); + return element; + } + + var responders = registry.get(eventName); + + if (!responders) return; + + var responder = responders.find( function(r) { return r.handler === handler; }); + if (!responder) return element; + + var actualEventName = _getDOMEventName(eventName); + + if (eventName.include(':')) { + if (element.removeEventListener) + element.removeEventListener("dataavailable", responder, false); + else { + element.detachEvent("ondataavailable", responder); + element.detachEvent("onfilterchange", responder); + } + } else { + if (element.removeEventListener) + element.removeEventListener(actualEventName, responder, false); + else + element.detachEvent('on' + actualEventName, responder); + } + + registry.set(eventName, responders.without(responder)); + + return element; + } + + function fire(element, eventName, memo, bubble) { + element = $(element); + + if (Object.isUndefined(bubble)) + bubble = true; + + if (element == document && document.createEvent && !element.dispatchEvent) + element = document.documentElement; + + var event; + if (document.createEvent) { + event = document.createEvent('HTMLEvents'); + event.initEvent('dataavailable', true, true); + } else { + event = document.createEventObject(); + event.eventType = bubble ? 'ondataavailable' : 'onfilterchange'; + } + + event.eventName = eventName; + event.memo = memo || { }; + + if (document.createEvent) + element.dispatchEvent(event); + else + element.fireEvent(event.eventType, event); + + return Event.extend(event); + } + + + Object.extend(Event, Event.Methods); + + Object.extend(Event, { + fire: fire, + observe: observe, + stopObserving: stopObserving + }); + + Element.addMethods({ + fire: fire, + + observe: observe, + + stopObserving: stopObserving + }); + + Object.extend(document, { + fire: fire.methodize(), + + observe: observe.methodize(), + + stopObserving: stopObserving.methodize(), + + loaded: false + }); + + if (window.Event) Object.extend(window.Event, Event); + else window.Event = Event; +})(); + +(function() { + /* Support for the DOMContentLoaded event is based on work by Dan Webb, + Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */ + + var timer; + + function fireContentLoadedEvent() { + if (document.loaded) return; + if (timer) window.clearTimeout(timer); + document.loaded = true; + document.fire('dom:loaded'); + } + + function checkReadyState() { + if (document.readyState === 'complete') { + document.stopObserving('readystatechange', checkReadyState); + fireContentLoadedEvent(); + } + } + + function pollDoScroll() { + try { document.documentElement.doScroll('left'); } + catch(e) { + timer = pollDoScroll.defer(); + return; + } + fireContentLoadedEvent(); + } + + if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false); + } else { + document.observe('readystatechange', checkReadyState); + if (window == top) + timer = pollDoScroll.defer(); + } + + Event.observe(window, 'load', fireContentLoadedEvent); +})(); + +Element.addMethods(); + +/*------------------------------- DEPRECATED -------------------------------*/ + +Hash.toQueryString = Object.toQueryString; + +var Toggle = { display: Element.toggle }; + +Element.Methods.childOf = Element.Methods.descendantOf; + +var Insertion = { + Before: function(element, content) { + return Element.insert(element, {before:content}); + }, + + Top: function(element, content) { + return Element.insert(element, {top:content}); + }, + + Bottom: function(element, content) { + return Element.insert(element, {bottom:content}); + }, + + After: function(element, content) { + return Element.insert(element, {after:content}); + } +}; + +var $continue = new Error('"throw $continue" is deprecated, use "return" instead'); + +var Position = { + includeScrollOffsets: false, + + prepare: function() { + this.deltaX = window.pageXOffset + || document.documentElement.scrollLeft + || document.body.scrollLeft + || 0; + this.deltaY = window.pageYOffset + || document.documentElement.scrollTop + || document.body.scrollTop + || 0; + }, + + within: function(element, x, y) { + if (this.includeScrollOffsets) + return this.withinIncludingScrolloffsets(element, x, y); + this.xcomp = x; + this.ycomp = y; + this.offset = Element.cumulativeOffset(element); + + return (y >= this.offset[1] && + y < this.offset[1] + element.offsetHeight && + x >= this.offset[0] && + x < this.offset[0] + element.offsetWidth); + }, + + withinIncludingScrolloffsets: function(element, x, y) { + var offsetcache = Element.cumulativeScrollOffset(element); + + this.xcomp = x + offsetcache[0] - this.deltaX; + this.ycomp = y + offsetcache[1] - this.deltaY; + this.offset = Element.cumulativeOffset(element); + + return (this.ycomp >= this.offset[1] && + this.ycomp < this.offset[1] + element.offsetHeight && + this.xcomp >= this.offset[0] && + this.xcomp < this.offset[0] + element.offsetWidth); + }, + + overlap: function(mode, element) { + if (!mode) return 0; + if (mode == 'vertical') + return ((this.offset[1] + element.offsetHeight) - this.ycomp) / + element.offsetHeight; + if (mode == 'horizontal') + return ((this.offset[0] + element.offsetWidth) - this.xcomp) / + element.offsetWidth; + }, + + + cumulativeOffset: Element.Methods.cumulativeOffset, + + positionedOffset: Element.Methods.positionedOffset, + + absolutize: function(element) { + Position.prepare(); + return Element.absolutize(element); + }, + + relativize: function(element) { + Position.prepare(); + return Element.relativize(element); + }, + + realOffset: Element.Methods.cumulativeScrollOffset, + + offsetParent: Element.Methods.getOffsetParent, + + page: Element.Methods.viewportOffset, + + clone: function(source, target, options) { + options = options || { }; + return Element.clonePosition(target, source, options); + } +}; + +/*--------------------------------------------------------------------------*/ + +if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){ + function iter(name) { + return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]"; + } + + instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ? + function(element, className) { + className = className.toString().strip(); + var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className); + return cond ? document._getElementsByXPath('.//*' + cond, element) : []; + } : function(element, className) { + className = className.toString().strip(); + var elements = [], classNames = (/\s/.test(className) ? $w(className) : null); + if (!classNames && !className) return elements; + + var nodes = $(element).getElementsByTagName('*'); + className = ' ' + className + ' '; + + for (var i = 0, child, cn; child = nodes[i]; i++) { + if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) || + (classNames && classNames.all(function(name) { + return !name.toString().blank() && cn.include(' ' + name + ' '); + })))) + elements.push(Element.extend(child)); + } + return elements; + }; + + return function(className, parentElement) { + return $(parentElement || document.body).getElementsByClassName(className); + }; +}(Element.Methods); + +/*--------------------------------------------------------------------------*/ + +Element.ClassNames = Class.create(); +Element.ClassNames.prototype = { + initialize: function(element) { + this.element = $(element); + }, + + _each: function(iterator) { + this.element.className.split(/\s+/).select(function(name) { + return name.length > 0; + })._each(iterator); + }, + + set: function(className) { + this.element.className = className; + }, + + add: function(classNameToAdd) { + if (this.include(classNameToAdd)) return; + this.set($A(this).concat(classNameToAdd).join(' ')); + }, + + remove: function(classNameToRemove) { + if (!this.include(classNameToRemove)) return; + this.set($A(this).without(classNameToRemove).join(' ')); + }, + + toString: function() { + return $A(this).join(' '); + } +}; + +Object.extend(Element.ClassNames.prototype, Enumerable); + +/*--------------------------------------------------------------------------*/ diff --git a/sw/in_progress/pow/pow/WebContent/js/tabber.js b/sw/in_progress/pow/pow/WebContent/js/tabber.js index a53b1b3060..9700c97a81 100644 --- a/sw/in_progress/pow/pow/WebContent/js/tabber.js +++ b/sw/in_progress/pow/pow/WebContent/js/tabber.js @@ -1,536 +1,536 @@ -/*================================================== - $Id: tabber.js,v 1.9 2006/04/27 20:51:51 pat Exp $ - tabber.js by Patrick Fitzgerald pat@barelyfitz.com - - Documentation can be found at the following URL: - http://www.barelyfitz.com/projects/tabber/ - - License (http://www.opensource.org/licenses/mit-license.php) - - Copyright (c) 2006 Patrick Fitzgerald - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - ==================================================*/ - -function tabberObj(argsObj) -{ - var arg; /* name of an argument to override */ - - /* Element for the main tabber div. If you supply this in argsObj, - then the init() method will be called. - */ - this.div = null; - - /* Class of the main tabber div */ - this.classMain = "tabber"; - - /* Rename classMain to classMainLive after tabifying - (so a different style can be applied) - */ - this.classMainLive = "tabberlive"; - - /* Class of each DIV that contains a tab */ - this.classTab = "tabbertab"; - - /* Class to indicate which tab should be active on startup */ - this.classTabDefault = "tabbertabdefault"; - - /* Class for the navigation UL */ - this.classNav = "tabbernav"; - - /* When a tab is to be hidden, instead of setting display='none', we - set the class of the div to classTabHide. In your screen - stylesheet you should set classTabHide to display:none. In your - print stylesheet you should set display:block to ensure that all - the information is printed. - */ - this.classTabHide = "tabbertabhide"; - - /* Class to set the navigation LI when the tab is active, so you can - use a different style on the active tab. - */ - this.classNavActive = "tabberactive"; - - /* Elements that might contain the title for the tab, only used if a - title is not specified in the TITLE attribute of DIV classTab. - */ - this.titleElements = ['h2','h3','h4','h5','h6']; - - /* Should we strip out the HTML from the innerHTML of the title elements? - This should usually be true. - */ - this.titleElementsStripHTML = true; - - /* If the user specified the tab names using a TITLE attribute on - the DIV, then the browser will display a tooltip whenever the - mouse is over the DIV. To prevent this tooltip, we can remove the - TITLE attribute after getting the tab name. - */ - this.removeTitle = true; - - /* If you want to add an id to each link set this to true */ - this.addLinkId = false; - - /* If addIds==true, then you can set a format for the ids. - will be replaced with the id of the main tabber div. - will be replaced with the tab number - (tab numbers starting at zero) - will be replaced with the tab number - (tab numbers starting at one) - will be replaced by the tab title - (with all non-alphanumeric characters removed) - */ - this.linkIdFormat = 'nav'; - - /* You can override the defaults listed above by passing in an object: - var mytab = new tabber({property:value,property:value}); - */ - for (arg in argsObj) { this[arg] = argsObj[arg]; } - - /* Create regular expressions for the class names; Note: if you - change the class names after a new object is created you must - also change these regular expressions. - */ - this.REclassMain = new RegExp('\\b' + this.classMain + '\\b', 'gi'); - this.REclassMainLive = new RegExp('\\b' + this.classMainLive + '\\b', 'gi'); - this.REclassTab = new RegExp('\\b' + this.classTab + '\\b', 'gi'); - this.REclassTabDefault = new RegExp('\\b' + this.classTabDefault + '\\b', 'gi'); - this.REclassTabHide = new RegExp('\\b' + this.classTabHide + '\\b', 'gi'); - - /* Array of objects holding info about each tab */ - this.tabs = new Array(); - - /* If the main tabber div was specified, call init() now */ - if (this.div) { - - this.init(this.div); - - /* We don't need the main div anymore, and to prevent a memory leak - in IE, we must remove the circular reference between the div - and the tabber object. */ - this.div = null; - } -} - - -/*-------------------------------------------------- - Methods for tabberObj - --------------------------------------------------*/ - - -tabberObj.prototype.init = function(e) -{ - /* Set up the tabber interface. - - e = element (the main containing div) - - Example: - init(document.getElementById('mytabberdiv')) - */ - - var - childNodes, /* child nodes of the tabber div */ - i, i2, /* loop indices */ - t, /* object to store info about a single tab */ - defaultTab=0, /* which tab to select by default */ - DOM_ul, /* tabbernav list */ - DOM_li, /* tabbernav list item */ - DOM_a, /* tabbernav link */ - aId, /* A unique id for DOM_a */ - headingElement; /* searching for text to use in the tab */ - - /* Verify that the browser supports DOM scripting */ - if (!document.getElementsByTagName) { return false; } - - /* If the main DIV has an ID then save it. */ - if (e.id) { - this.id = e.id; - } - - /* Clear the tabs array (but it should normally be empty) */ - this.tabs.length = 0; - - /* Loop through an array of all the child nodes within our tabber element. */ - childNodes = e.childNodes; - for(i=0; i < childNodes.length; i++) { - - /* Find the nodes where class="tabbertab" */ - if(childNodes[i].className && - childNodes[i].className.match(this.REclassTab)) { - - /* Create a new object to save info about this tab */ - t = new Object(); - - /* Save a pointer to the div for this tab */ - t.div = childNodes[i]; - - /* Add the new object to the array of tabs */ - this.tabs[this.tabs.length] = t; - - /* If the class name contains classTabDefault, - then select this tab by default. - */ - if (childNodes[i].className.match(this.REclassTabDefault)) { - defaultTab = this.tabs.length-1; - } - } - } - - /* Create a new UL list to hold the tab headings */ - DOM_ul = document.createElement("ul"); - DOM_ul.className = this.classNav; - - /* Loop through each tab we found */ - for (i=0; i < this.tabs.length; i++) { - - t = this.tabs[i]; - - /* Get the label to use for this tab: - From the title attribute on the DIV, - Or from one of the this.titleElements[] elements, - Or use an automatically generated number. - */ - t.headingText = t.div.title; - - /* Remove the title attribute to prevent a tooltip from appearing */ - if (this.removeTitle) { t.div.title = ''; } - - if (!t.headingText) { - - /* Title was not defined in the title of the DIV, - So try to get the title from an element within the DIV. - Go through the list of elements in this.titleElements - (typically heading elements ['h2','h3','h4']) - */ - for (i2=0; i2/gi," "); - t.headingText = t.headingText.replace(/<[^>]+>/g,""); - } - break; - } - } - } - - if (!t.headingText) { - /* Title was not found (or is blank) so automatically generate a - number for the tab. - */ - t.headingText = i + 1; - } - - /* Create a list element for the tab */ - DOM_li = document.createElement("li"); - - /* Save a reference to this list item so we can later change it to - the "active" class */ - t.li = DOM_li; - - /* Create a link to activate the tab */ - DOM_a = document.createElement("a"); - DOM_a.appendChild(document.createTextNode(t.headingText)); - DOM_a.href = "javascript:void(null);"; - DOM_a.title = t.headingText; - DOM_a.onclick = this.navClick; - - /* Add some properties to the link so we can identify which tab - was clicked. Later the navClick method will need this. - */ - DOM_a.tabber = this; - DOM_a.tabberIndex = i; - - /* Do we need to add an id to DOM_a? */ - if (this.addLinkId && this.linkIdFormat) { - - /* Determine the id name */ - aId = this.linkIdFormat; - aId = aId.replace(//gi, this.id); - aId = aId.replace(//gi, i); - aId = aId.replace(//gi, i+1); - aId = aId.replace(//gi, t.headingText.replace(/[^a-zA-Z0-9\-]/gi, '')); - - DOM_a.id = aId; - } - - /* Add the link to the list element */ - DOM_li.appendChild(DOM_a); - - /* Add the list element to the list */ - DOM_ul.appendChild(DOM_li); - } - - /* Add the UL list to the beginning of the tabber div */ - e.insertBefore(DOM_ul, e.firstChild); - - /* Make the tabber div "live" so different CSS can be applied */ - e.className = e.className.replace(this.REclassMain, this.classMainLive); - - /* Activate the default tab, and do not call the onclick handler */ - this.tabShow(defaultTab); - - /* If the user specified an onLoad function, call it now. */ - if (typeof this.onLoad == 'function') { - this.onLoad({tabber:this}); - } - - return this; -}; - - -tabberObj.prototype.navClick = function(event) -{ - /* This method should only be called by the onClick event of an
- element, in which case we will determine which tab was clicked by - examining a property that we previously attached to the - element. - - Since this was triggered from an onClick event, the variable - "this" refers to the element that triggered the onClick - event (and not to the tabberObj). - - When tabberObj was initialized, we added some extra properties - to the element, for the purpose of retrieving them now. Get - the tabberObj object, plus the tab number that was clicked. - */ - - var - rVal, /* Return value from the user onclick function */ - a, /* element that triggered the onclick event */ - self, /* the tabber object */ - tabberIndex, /* index of the tab that triggered the event */ - onClickArgs; /* args to send the onclick function */ - - a = this; - if (!a.tabber) { return false; } - - self = a.tabber; - tabberIndex = a.tabberIndex; - - /* Remove focus from the link because it looks ugly. - I don't know if this is a good idea... - */ - a.blur(); - - /* If the user specified an onClick function, call it now. - If the function returns false then do not continue. - */ - if (typeof self.onClick == 'function') { - - onClickArgs = {'tabber':self, 'index':tabberIndex, 'event':event}; - - /* IE uses a different way to access the event object */ - if (!event) { onClickArgs.event = window.event; } - - rVal = self.onClick(onClickArgs); - if (rVal === false) { return false; } - } - - self.tabShow(tabberIndex); - - return false; -}; - - -tabberObj.prototype.tabHideAll = function() -{ - var i; /* counter */ - - /* Hide all tabs and make all navigation links inactive */ - for (i = 0; i < this.tabs.length; i++) { - this.tabHide(i); - } -}; - - -tabberObj.prototype.tabHide = function(tabberIndex) -{ - var div; - - if (!this.tabs[tabberIndex]) { return false; } - - /* Hide a single tab and make its navigation link inactive */ - div = this.tabs[tabberIndex].div; - - /* Hide the tab contents by adding classTabHide to the div */ - if (!div.className.match(this.REclassTabHide)) { - div.className += ' ' + this.classTabHide; - } - this.navClearActive(tabberIndex); - - return this; -}; - - -tabberObj.prototype.tabShow = function(tabberIndex) -{ - /* Show the tabberIndex tab and hide all the other tabs */ - - var div; - - if (!this.tabs[tabberIndex]) { return false; } - - /* Hide all the tabs first */ - this.tabHideAll(); - - /* Get the div that holds this tab */ - div = this.tabs[tabberIndex].div; - - /* Remove classTabHide from the div */ - div.className = div.className.replace(this.REclassTabHide, ''); - - /* Mark this tab navigation link as "active" */ - this.navSetActive(tabberIndex); - - /* If the user specified an onTabDisplay function, call it now. */ - if (typeof this.onTabDisplay == 'function') { - this.onTabDisplay({'tabber':this, 'index':tabberIndex}); - } - - return this; -}; - -tabberObj.prototype.navSetActive = function(tabberIndex) -{ - /* Note: this method does *not* enforce the rule - that only one nav item can be active at a time. - */ - - /* Set classNavActive for the navigation list item */ - this.tabs[tabberIndex].li.className = this.classNavActive; - - return this; -}; - - -tabberObj.prototype.navClearActive = function(tabberIndex) -{ - /* Note: this method does *not* enforce the rule - that one nav should always be active. - */ - - /* Remove classNavActive from the navigation list item */ - this.tabs[tabberIndex].li.className = ''; - - return this; -}; - - -/*==================================================*/ - - -function tabberAutomatic(tabberArgs) -{ - /* This function finds all DIV elements in the document where - class=tabber.classMain, then converts them to use the tabber - interface. - - tabberArgs = an object to send to "new tabber()" - */ - var - tempObj, /* Temporary tabber object */ - divs, /* Array of all divs on the page */ - i; /* Loop index */ - - if (!tabberArgs) { tabberArgs = {}; } - - /* Create a tabber object so we can get the value of classMain */ - tempObj = new tabberObj(tabberArgs); - - /* Find all DIV elements in the document that have class=tabber */ - - /* First get an array of all DIV elements and loop through them */ - divs = document.getElementsByTagName("div"); - for (i=0; i < divs.length; i++) { - - /* Is this DIV the correct class? */ - if (divs[i].className && - divs[i].className.match(tempObj.REclassMain)) { - - /* Now tabify the DIV */ - tabberArgs.div = divs[i]; - divs[i].tabber = new tabberObj(tabberArgs); - } - } - - return this; -} - - -/*==================================================*/ - - -function tabberAutomaticOnLoad(tabberArgs) -{ - /* This function adds tabberAutomatic to the window.onload event, - so it will run after the document has finished loading. - */ - var oldOnLoad; - - if (!tabberArgs) { tabberArgs = {}; } - - /* Taken from: http://simon.incutio.com/archive/2004/05/26/addLoadEvent */ - - oldOnLoad = window.onload; - if (typeof window.onload != 'function') { - window.onload = function() { - tabberAutomatic(tabberArgs); - - }; - } else { - window.onload = function() { - oldOnLoad(); - tabberAutomatic(tabberArgs); - - }; - } -} - - -/*==================================================*/ -function init_tabs(){ - if (typeof tabberOptions == 'undefined') { - tabberAutomatic({}); - } - else - {if (!tabberOptions['manualStartup']) { - tabberAutomatic(tabberOptions); - } - } -} - -function init_autotabber(){ -/* Run tabberAutomaticOnload() unless the "manualStartup" option was specified */ - - if (typeof tabberOptions == 'undefined') { - - tabberAutomaticOnLoad(); - - } else { - - if (!tabberOptions['manualStartup']) { - tabberAutomaticOnLoad(tabberOptions); - } - - } +/*================================================== + $Id: tabber.js,v 1.9 2006/04/27 20:51:51 pat Exp $ + tabber.js by Patrick Fitzgerald pat@barelyfitz.com + + Documentation can be found at the following URL: + http://www.barelyfitz.com/projects/tabber/ + + License (http://www.opensource.org/licenses/mit-license.php) + + Copyright (c) 2006 Patrick Fitzgerald + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + ==================================================*/ + +function tabberObj(argsObj) +{ + var arg; /* name of an argument to override */ + + /* Element for the main tabber div. If you supply this in argsObj, + then the init() method will be called. + */ + this.div = null; + + /* Class of the main tabber div */ + this.classMain = "tabber"; + + /* Rename classMain to classMainLive after tabifying + (so a different style can be applied) + */ + this.classMainLive = "tabberlive"; + + /* Class of each DIV that contains a tab */ + this.classTab = "tabbertab"; + + /* Class to indicate which tab should be active on startup */ + this.classTabDefault = "tabbertabdefault"; + + /* Class for the navigation UL */ + this.classNav = "tabbernav"; + + /* When a tab is to be hidden, instead of setting display='none', we + set the class of the div to classTabHide. In your screen + stylesheet you should set classTabHide to display:none. In your + print stylesheet you should set display:block to ensure that all + the information is printed. + */ + this.classTabHide = "tabbertabhide"; + + /* Class to set the navigation LI when the tab is active, so you can + use a different style on the active tab. + */ + this.classNavActive = "tabberactive"; + + /* Elements that might contain the title for the tab, only used if a + title is not specified in the TITLE attribute of DIV classTab. + */ + this.titleElements = ['h2','h3','h4','h5','h6']; + + /* Should we strip out the HTML from the innerHTML of the title elements? + This should usually be true. + */ + this.titleElementsStripHTML = true; + + /* If the user specified the tab names using a TITLE attribute on + the DIV, then the browser will display a tooltip whenever the + mouse is over the DIV. To prevent this tooltip, we can remove the + TITLE attribute after getting the tab name. + */ + this.removeTitle = true; + + /* If you want to add an id to each link set this to true */ + this.addLinkId = false; + + /* If addIds==true, then you can set a format for the ids. + will be replaced with the id of the main tabber div. + will be replaced with the tab number + (tab numbers starting at zero) + will be replaced with the tab number + (tab numbers starting at one) + will be replaced by the tab title + (with all non-alphanumeric characters removed) + */ + this.linkIdFormat = 'nav'; + + /* You can override the defaults listed above by passing in an object: + var mytab = new tabber({property:value,property:value}); + */ + for (arg in argsObj) { this[arg] = argsObj[arg]; } + + /* Create regular expressions for the class names; Note: if you + change the class names after a new object is created you must + also change these regular expressions. + */ + this.REclassMain = new RegExp('\\b' + this.classMain + '\\b', 'gi'); + this.REclassMainLive = new RegExp('\\b' + this.classMainLive + '\\b', 'gi'); + this.REclassTab = new RegExp('\\b' + this.classTab + '\\b', 'gi'); + this.REclassTabDefault = new RegExp('\\b' + this.classTabDefault + '\\b', 'gi'); + this.REclassTabHide = new RegExp('\\b' + this.classTabHide + '\\b', 'gi'); + + /* Array of objects holding info about each tab */ + this.tabs = new Array(); + + /* If the main tabber div was specified, call init() now */ + if (this.div) { + + this.init(this.div); + + /* We don't need the main div anymore, and to prevent a memory leak + in IE, we must remove the circular reference between the div + and the tabber object. */ + this.div = null; + } +} + + +/*-------------------------------------------------- + Methods for tabberObj + --------------------------------------------------*/ + + +tabberObj.prototype.init = function(e) +{ + /* Set up the tabber interface. + + e = element (the main containing div) + + Example: + init(document.getElementById('mytabberdiv')) + */ + + var + childNodes, /* child nodes of the tabber div */ + i, i2, /* loop indices */ + t, /* object to store info about a single tab */ + defaultTab=0, /* which tab to select by default */ + DOM_ul, /* tabbernav list */ + DOM_li, /* tabbernav list item */ + DOM_a, /* tabbernav link */ + aId, /* A unique id for DOM_a */ + headingElement; /* searching for text to use in the tab */ + + /* Verify that the browser supports DOM scripting */ + if (!document.getElementsByTagName) { return false; } + + /* If the main DIV has an ID then save it. */ + if (e.id) { + this.id = e.id; + } + + /* Clear the tabs array (but it should normally be empty) */ + this.tabs.length = 0; + + /* Loop through an array of all the child nodes within our tabber element. */ + childNodes = e.childNodes; + for(i=0; i < childNodes.length; i++) { + + /* Find the nodes where class="tabbertab" */ + if(childNodes[i].className && + childNodes[i].className.match(this.REclassTab)) { + + /* Create a new object to save info about this tab */ + t = new Object(); + + /* Save a pointer to the div for this tab */ + t.div = childNodes[i]; + + /* Add the new object to the array of tabs */ + this.tabs[this.tabs.length] = t; + + /* If the class name contains classTabDefault, + then select this tab by default. + */ + if (childNodes[i].className.match(this.REclassTabDefault)) { + defaultTab = this.tabs.length-1; + } + } + } + + /* Create a new UL list to hold the tab headings */ + DOM_ul = document.createElement("ul"); + DOM_ul.className = this.classNav; + + /* Loop through each tab we found */ + for (i=0; i < this.tabs.length; i++) { + + t = this.tabs[i]; + + /* Get the label to use for this tab: + From the title attribute on the DIV, + Or from one of the this.titleElements[] elements, + Or use an automatically generated number. + */ + t.headingText = t.div.title; + + /* Remove the title attribute to prevent a tooltip from appearing */ + if (this.removeTitle) { t.div.title = ''; } + + if (!t.headingText) { + + /* Title was not defined in the title of the DIV, + So try to get the title from an element within the DIV. + Go through the list of elements in this.titleElements + (typically heading elements ['h2','h3','h4']) + */ + for (i2=0; i2/gi," "); + t.headingText = t.headingText.replace(/<[^>]+>/g,""); + } + break; + } + } + } + + if (!t.headingText) { + /* Title was not found (or is blank) so automatically generate a + number for the tab. + */ + t.headingText = i + 1; + } + + /* Create a list element for the tab */ + DOM_li = document.createElement("li"); + + /* Save a reference to this list item so we can later change it to + the "active" class */ + t.li = DOM_li; + + /* Create a link to activate the tab */ + DOM_a = document.createElement("a"); + DOM_a.appendChild(document.createTextNode(t.headingText)); + DOM_a.href = "javascript:void(null);"; + DOM_a.title = t.headingText; + DOM_a.onclick = this.navClick; + + /* Add some properties to the link so we can identify which tab + was clicked. Later the navClick method will need this. + */ + DOM_a.tabber = this; + DOM_a.tabberIndex = i; + + /* Do we need to add an id to DOM_a? */ + if (this.addLinkId && this.linkIdFormat) { + + /* Determine the id name */ + aId = this.linkIdFormat; + aId = aId.replace(//gi, this.id); + aId = aId.replace(//gi, i); + aId = aId.replace(//gi, i+1); + aId = aId.replace(//gi, t.headingText.replace(/[^a-zA-Z0-9\-]/gi, '')); + + DOM_a.id = aId; + } + + /* Add the link to the list element */ + DOM_li.appendChild(DOM_a); + + /* Add the list element to the list */ + DOM_ul.appendChild(DOM_li); + } + + /* Add the UL list to the beginning of the tabber div */ + e.insertBefore(DOM_ul, e.firstChild); + + /* Make the tabber div "live" so different CSS can be applied */ + e.className = e.className.replace(this.REclassMain, this.classMainLive); + + /* Activate the default tab, and do not call the onclick handler */ + this.tabShow(defaultTab); + + /* If the user specified an onLoad function, call it now. */ + if (typeof this.onLoad == 'function') { + this.onLoad({tabber:this}); + } + + return this; +}; + + +tabberObj.prototype.navClick = function(event) +{ + /* This method should only be called by the onClick event of an + element, in which case we will determine which tab was clicked by + examining a property that we previously attached to the + element. + + Since this was triggered from an onClick event, the variable + "this" refers to the element that triggered the onClick + event (and not to the tabberObj). + + When tabberObj was initialized, we added some extra properties + to the element, for the purpose of retrieving them now. Get + the tabberObj object, plus the tab number that was clicked. + */ + + var + rVal, /* Return value from the user onclick function */ + a, /* element that triggered the onclick event */ + self, /* the tabber object */ + tabberIndex, /* index of the tab that triggered the event */ + onClickArgs; /* args to send the onclick function */ + + a = this; + if (!a.tabber) { return false; } + + self = a.tabber; + tabberIndex = a.tabberIndex; + + /* Remove focus from the link because it looks ugly. + I don't know if this is a good idea... + */ + a.blur(); + + /* If the user specified an onClick function, call it now. + If the function returns false then do not continue. + */ + if (typeof self.onClick == 'function') { + + onClickArgs = {'tabber':self, 'index':tabberIndex, 'event':event}; + + /* IE uses a different way to access the event object */ + if (!event) { onClickArgs.event = window.event; } + + rVal = self.onClick(onClickArgs); + if (rVal === false) { return false; } + } + + self.tabShow(tabberIndex); + + return false; +}; + + +tabberObj.prototype.tabHideAll = function() +{ + var i; /* counter */ + + /* Hide all tabs and make all navigation links inactive */ + for (i = 0; i < this.tabs.length; i++) { + this.tabHide(i); + } +}; + + +tabberObj.prototype.tabHide = function(tabberIndex) +{ + var div; + + if (!this.tabs[tabberIndex]) { return false; } + + /* Hide a single tab and make its navigation link inactive */ + div = this.tabs[tabberIndex].div; + + /* Hide the tab contents by adding classTabHide to the div */ + if (!div.className.match(this.REclassTabHide)) { + div.className += ' ' + this.classTabHide; + } + this.navClearActive(tabberIndex); + + return this; +}; + + +tabberObj.prototype.tabShow = function(tabberIndex) +{ + /* Show the tabberIndex tab and hide all the other tabs */ + + var div; + + if (!this.tabs[tabberIndex]) { return false; } + + /* Hide all the tabs first */ + this.tabHideAll(); + + /* Get the div that holds this tab */ + div = this.tabs[tabberIndex].div; + + /* Remove classTabHide from the div */ + div.className = div.className.replace(this.REclassTabHide, ''); + + /* Mark this tab navigation link as "active" */ + this.navSetActive(tabberIndex); + + /* If the user specified an onTabDisplay function, call it now. */ + if (typeof this.onTabDisplay == 'function') { + this.onTabDisplay({'tabber':this, 'index':tabberIndex}); + } + + return this; +}; + +tabberObj.prototype.navSetActive = function(tabberIndex) +{ + /* Note: this method does *not* enforce the rule + that only one nav item can be active at a time. + */ + + /* Set classNavActive for the navigation list item */ + this.tabs[tabberIndex].li.className = this.classNavActive; + + return this; +}; + + +tabberObj.prototype.navClearActive = function(tabberIndex) +{ + /* Note: this method does *not* enforce the rule + that one nav should always be active. + */ + + /* Remove classNavActive from the navigation list item */ + this.tabs[tabberIndex].li.className = ''; + + return this; +}; + + +/*==================================================*/ + + +function tabberAutomatic(tabberArgs) +{ + /* This function finds all DIV elements in the document where + class=tabber.classMain, then converts them to use the tabber + interface. + + tabberArgs = an object to send to "new tabber()" + */ + var + tempObj, /* Temporary tabber object */ + divs, /* Array of all divs on the page */ + i; /* Loop index */ + + if (!tabberArgs) { tabberArgs = {}; } + + /* Create a tabber object so we can get the value of classMain */ + tempObj = new tabberObj(tabberArgs); + + /* Find all DIV elements in the document that have class=tabber */ + + /* First get an array of all DIV elements and loop through them */ + divs = document.getElementsByTagName("div"); + for (i=0; i < divs.length; i++) { + + /* Is this DIV the correct class? */ + if (divs[i].className && + divs[i].className.match(tempObj.REclassMain)) { + + /* Now tabify the DIV */ + tabberArgs.div = divs[i]; + divs[i].tabber = new tabberObj(tabberArgs); + } + } + + return this; +} + + +/*==================================================*/ + + +function tabberAutomaticOnLoad(tabberArgs) +{ + /* This function adds tabberAutomatic to the window.onload event, + so it will run after the document has finished loading. + */ + var oldOnLoad; + + if (!tabberArgs) { tabberArgs = {}; } + + /* Taken from: http://simon.incutio.com/archive/2004/05/26/addLoadEvent */ + + oldOnLoad = window.onload; + if (typeof window.onload != 'function') { + window.onload = function() { + tabberAutomatic(tabberArgs); + + }; + } else { + window.onload = function() { + oldOnLoad(); + tabberAutomatic(tabberArgs); + + }; + } +} + + +/*==================================================*/ +function init_tabs(){ + if (typeof tabberOptions == 'undefined') { + tabberAutomatic({}); + } + else + {if (!tabberOptions['manualStartup']) { + tabberAutomatic(tabberOptions); + } + } +} + +function init_autotabber(){ +/* Run tabberAutomaticOnload() unless the "manualStartup" option was specified */ + + if (typeof tabberOptions == 'undefined') { + + tabberAutomaticOnLoad(); + + } else { + + if (!tabberOptions['manualStartup']) { + tabberAutomaticOnLoad(tabberOptions); + } + + } } \ No newline at end of file diff --git a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/client/PushletClient.java b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/client/PushletClient.java index f2dc390f26..e1c77ebcfa 100644 --- a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/client/PushletClient.java +++ b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/client/PushletClient.java @@ -1,699 +1,699 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.client; - -import nl.justobjects.pushlet.core.Event; -import nl.justobjects.pushlet.core.EventParser; -import nl.justobjects.pushlet.core.Protocol; -import nl.justobjects.pushlet.util.PushletException; - -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Reader; -import java.io.OutputStream; -import java.net.*; -import java.util.Map; - -/** - * Client API for Java HTTP client applets or apps. - *

- * Use this class within Java client applications or applets. - * Implement a PushletClientListener to receive callbacks for - * data-related Event objects pushed by the server. - *

- * This class may also be used as a base class and be extended - * for custom clients, hence the presence of many proteced methods. - * - * @author Just van den Broecke - Just Objects © - * @version $Id: PushletClient.java,v 1.19 2009/06/04 12:46:35 justb Exp $ - * @see PushletClientListener - * @see nl.justobjects.pushlet.test.PushletApplet - * @see nl.justobjects.pushlet.test.PushletPingApplication - */ -public class PushletClient implements Protocol { - /** - * Pushlet URL. - */ - private String pushletURL; - - /** - * Debug flag for verbose output. - */ - private boolean debug; - - /** - * Id gotten on join ack - */ - private String id; - - /** - * Internal listener for data events pushed by server. - */ - protected DataEventListener dataEventListener; - - /** - * Constructor with full pushlet URL. - */ - public PushletClient(String aPushletURL) { - pushletURL = aPushletURL; - } - - /** - * Constructor with host and port using default URI. - */ - public PushletClient(String aHost, int aPort) { - this("http://" + aHost + ":" + aPort + DEFAULT_SERVLET_URI); - } - - /** - * Set proxy options and optional proxy authentication. - *

- * Contributed by Dele Olajide - * See http://groups.yahoo.com/group/pushlet/message/634 - *

- * Usage: - * PushletClient pushletClient = new PushletClient("http:://www.domain.com/pushlet"); - * pushletClient.setProxyOptions("proxy.bla.com", "8080", ....); - *

- * use pushletClient further as normal - */ - public void setProxyOptions(String aProxyHost, - String aProxyPort, String theNonProxyHosts, - String aUserName, String aPassword, String anNTLMDomain) { - - // Enable proxying - System.setProperty("http.proxySet", "true"); - System.setProperty("http.proxyHost", aProxyHost); - System.setProperty("http.proxyPort", aProxyPort); - - // Set optional non-proxy hosts - if (theNonProxyHosts != null) { - System.setProperty("http.nonProxyHosts", theNonProxyHosts); - } - - // If user name specified configure proxy authentication - if (aUserName != null) { - System.setProperty("http.proxyUser", aUserName); - System.setProperty("http.proxyPassword", aPassword); - - // See inner class below - Authenticator.setDefault(new HTTPAuthenticateProxy(aUserName, aPassword)); - - // Optional NT domain - if (anNTLMDomain != null) { - System.setProperty("http.auth.ntlm.domain", anNTLMDomain); - } - } - } - - /** - * Join server, starts session. - */ - public void join() throws PushletException { - Event event = new Event(E_JOIN); - event.setField(P_FORMAT, FORMAT_XML); - Event response = doControl(event); - throwOnNack(response); - - // Join Ack received - id = response.getField(P_ID); - } - - /** - * Leave server, stops session. - */ - public void leave() throws PushletException { - stopListen(); - throwOnInvalidSession(); - Event event = new Event(E_LEAVE); - event.setField(P_ID, id); - Event response = doControl(event); - - throwOnNack(response); - id = null; - } - - /** - * Open data channel. - */ - public void listen(PushletClientListener aListener) throws PushletException { - listen(aListener, MODE_STREAM); - } - - /** - * Open data channel in stream or push mode. - */ - public void listen(PushletClientListener aListener, String aMode) throws PushletException { - listen(aListener, aMode, null); - } - - /** - * Open data channel in stream or push mode with a subject. - */ - public void listen(PushletClientListener aListener, String aMode, String aSubject) throws PushletException { - throwOnInvalidSession(); - stopListen(); - - String listenURL = pushletURL - + "?" + P_EVENT + "=" + E_LISTEN - + "&" + P_ID + "=" + id - + "&" + P_MODE + "=" + aMode; - if (aSubject != null) { - listenURL = listenURL + "&" + P_SUBJECT + "=" + aSubject; - } - - // Start listener thread (sync call). - startDataEventListener(aListener, listenURL); - } - - /** - * Immediate listener: joins/subscribes and listens in one action. - */ - public void joinListen(PushletClientListener aListener, String aMode, String aSubject) throws PushletException { - stopListen(); - - String listenURL = pushletURL - + "?" + P_EVENT + "=" + E_JOIN_LISTEN - + "&" + P_FORMAT + "=" + FORMAT_XML - + "&" + P_MODE + "=" + aMode - + "&" + P_SUBJECT + "=" + aSubject; - - // Start listener thread (sync call). - startDataEventListener(aListener, listenURL); - } - - /** - * Publish an event through server. - */ - public void publish(String aSubject, Map theAttributes) throws PushletException { - throwOnInvalidSession(); - Event event = new Event(E_PUBLISH, theAttributes); - event.setField(P_SUBJECT, aSubject); - event.setField(P_ID, id); - Event response = doControl(event); - throwOnNack(response); - } - - /** - * Subscribes, returning subscription id. - */ - public String subscribe(String aSubject, String aLabel) throws PushletException { - throwOnInvalidSession(); - Event event = new Event(E_SUBSCRIBE); - event.setField(P_ID, id); - event.setField(P_SUBJECT, aSubject); - - // Optional label, is returned in data events - if (aLabel != null) { - event.setField(P_SUBSCRIPTION_LABEL, aLabel); - } - - // Send request - Event response = doControl(event); - throwOnNack(response); - - return response.getField(P_SUBSCRIPTION_ID); - } - - /** - * Subscribes, returning subscription id. - */ - public String subscribe(String aSubject) throws PushletException { - return subscribe(aSubject, null); - } - - /** - * Unsubscribes with subscription id. - */ - public void unsubscribe(String aSubscriptionId) throws PushletException { - throwOnInvalidSession(); - Event event = new Event(E_UNSUBSCRIBE); - event.setField(P_ID, id); - - // Optional subscription id - if (aSubscriptionId != null) { - event.setField(P_SUBSCRIPTION_ID, aSubscriptionId); - } - - Event response = doControl(event); - throwOnNack(response); - } - - /** - * Unsubscribes from all subjects. - */ - public void unsubscribe() throws PushletException { - unsubscribe(null); - } - - /** - * Stop the listener. - */ - public void stopListen() throws PushletException { - if (dataEventListener != null) { - unsubscribe(); - dataEventListener.stop(); - dataEventListener = null; - } - } - - public void setDebug(boolean b) { - debug = b; - } - - /** - * Starts default DataEventListener and waits for its thread to start. - */ - protected void startDataEventListener(PushletClientListener aListener, String aListenURL) { - // Suggestion by Jeff Nowakowski 29.oct.2006 - dataEventListener = new DataEventListener(aListener, aListenURL); - - synchronized (dataEventListener) { - dataEventListener.start(); - try { - // Wait for data event listener (thread) to start - dataEventListener.wait(); - } catch (InterruptedException e) { - } - } - } - - protected void throwOnNack(Event anEvent) throws PushletException { - if (anEvent.getEventType().equals(E_NACK)) { - throw new PushletException("Negative response: reason=" + anEvent.getField(P_REASON)); - } - } - - protected void throwOnInvalidSession() throws PushletException { - if (id == null) { - throw new PushletException("Invalid pushlet session"); - } - } - - protected Reader openURL(String aURL) throws PushletException { - // Open URL connection with server - try { - p("Connecting to " + aURL); - URL url = new URL(aURL); - URLConnection urlConnection = url.openConnection(); - - // Disable any kind of caching. - urlConnection.setUseCaches(false); - urlConnection.setDefaultUseCaches(false); - - // TODO: later version may use POST - // Enable HTTP POST - // urlConnection.setDoOutput(true); - - // Do the POST with Event in XML in body - // OutputStream os = urlConnection.getOutputStream(); - // os.write(anEvent.toXML().getBytes()); - // os.flush(); - // os.close(); - - // Get the stream from the server. - // reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); - // Note: somehow the client does not work with some JVMs when using - // BufferedInputStream... So do unbuffered input. - // p("Opening urlConnection inputstream"); - return new InputStreamReader(urlConnection.getInputStream()); - - } catch (Throwable t) { - warn("openURL() could not open " + aURL, t); - throw new PushletException(" could not open " + aURL, t); - } - } - - - /** - * Send control events to server and return response. - */ - protected Event doControl(Event aControlEvent) throws PushletException { - String controlURL = pushletURL + "?" + aControlEvent.toQueryString(); - - p("doControl to " + controlURL); - - // Open URL connection with server - Reader reader = openURL(controlURL); - - // Get Pushlet event from stream - Event event = null; - try { - p("Getting event..."); - // Get next event from server - event = EventParser.parse(reader); - p("Event received " + event); - return event; - } catch (Throwable t) { - // Stop and report error. - warn("doControl() exception", t); - throw new PushletException(" error parsing response from" + controlURL, t); - } - } - - /** - * Util: print. - */ - protected void p(String s) { - if (debug) { - System.out.println("[PushletClient] " + s); - } - } - - /** - * Util: warn. - */ - protected void warn(String s) { - warn(s, null); - } - - /** - * Util: warn with exception. - */ - protected void warn(String s, Throwable t) { - System.err.println("[PushletClient] - WARN - " + s + " ex=" + t); - - if (t != null) { - t.printStackTrace(); - } - } - - /** - * Internal (default) listener for the Pushlet data channel. - */ - protected class DataEventListener implements Runnable { - /** - * Client's listener that gets called back on events. - */ - private PushletClientListener listener; - - /** - * Receiver receiveThread. - */ - private Thread receiveThread = null; - private Reader reader; - private String refreshURL; - private String listenURL; - - public DataEventListener(PushletClientListener aListener, String aListenURL) { - listener = aListener; - listenURL = aListenURL; - } - - public void start() { - // All ok: start a receiver receiveThread - receiveThread = new Thread(this); - receiveThread.start(); - - } - - /** - * Stop listening; may restart later with start(). - */ - public void stop() { - p("In stop()"); - bailout(); - } - - /** - * Receive event objects from server and callback listener. - */ - public void run() { - p("Start run()"); - try { - while (receiveThread != null && receiveThread.isAlive()) { - // Connect to server - reader = openURL(listenURL); - - synchronized (this) { - // Inform the calling thread we're ready to receive events. - // Suggestion by Jeff Nowakowski 29.oct.2006 - this.notify(); - } - - // Get events while we're alive. - while (receiveThread != null && receiveThread.isAlive()) { - Event event = null; - try { - // p("Getting event..."); - // Get next event from server - event = EventParser.parse(reader); - p("Event received " + event); - } catch (Throwable t) { - - // Stop and report error. - // warn("Stop run() on exception", t); - if (listener != null) { - listener.onError("exception during receive: " + t); - } - - break; - } - - // Handle event by calling listener - if (event != null && listener != null) { - // p("received: " + event.toXML()); - String eventType = event.getEventType(); - if (eventType.equals(E_HEARTBEAT)) { - listener.onHeartbeat(event); - } else if (eventType.equals(E_DATA)) { - listener.onData(event); - } else if (eventType.equals(E_JOIN_LISTEN_ACK)) { - id = event.getField(P_ID); - } else if (eventType.equals(E_LISTEN_ACK)) { - p("Listen ack ok"); - } else if (eventType.equals(E_REFRESH_ACK)) { - // ignore - } else if (eventType.equals(E_ABORT)) { - listener.onAbort(event); - listener = null; - break; - } else if (eventType.equals(E_REFRESH)) { - refresh(event); - } else { - handleUnknownEventType(eventType, event, listener); - } - } - } - } - } catch (Throwable t) { - warn("Exception in run() ", t); - // bailout(); - } - } - - protected void disconnect() { - p("start disconnect()"); - if (reader != null) { - try { - // this blocks, find another way - // reader.close(); - p("Closed reader ok"); - } catch (Exception ignore) { - } finally { - reader = null; - } - } - p("end disconnect()"); - } - - /** - * Stop receiver receiveThread. - */ - public void stopThread() { - p("In stopThread()"); - - // Keep a reference such that we can kill it from here. - Thread targetThread = receiveThread; - - receiveThread = null; - - // This should stop the main loop for this receiveThread. - // Killing a receiveThread on a blcing read is tricky. - // See also http://gee.cs.oswego.edu/dl/cpj/cancel.html - if ((targetThread != null) && targetThread.isAlive()) { - - targetThread.interrupt(); - - try { - - // Wait for it to die - targetThread.join(500); - } catch (InterruptedException ignore) { - } - - // If current receiveThread refuses to die, - // take more rigorous methods. - if (targetThread.isAlive()) { - - // Not preferred but may be needed - // to stop during a blocking read. - targetThread.stop(); - - // Wait for it to die - try { - targetThread.join(500); - } catch (Throwable ignore) { - } - } - - p("Stopped receiveThread alive=" + targetThread.isAlive()); - - } - } - - /** - * Stop listening on stream from server. - */ - public void bailout() { - p("In bailout()"); - stopThread(); - disconnect(); - } - - /** - * Handle refresh, by pausing. - */ - protected void refresh(Event aRefreshEvent) throws PushletException { - try { - // Wait for specified time. - Thread.sleep(Long.parseLong(aRefreshEvent.getField(P_WAIT))); - } catch (Throwable t) { - warn("abort while refresing"); - refreshURL = null; - return; - } - - // If stopped during sleep, don't proceed - if (receiveThread == null) { - return; - } - - // Create url to refresh - refreshURL = pushletURL - + "?" + P_ID + "=" + id - + "&" + P_EVENT + "=" + E_REFRESH - ; - - if (reader != null) { - try { - reader.close(); - - } catch (IOException ignore) { - - } - reader = null; - } - - reader = openURL(refreshURL); - } - - /** - * Handle unknown Event (default behaviour). - */ - protected void handleUnknownEventType(String eventType, Event event, PushletClientListener listener) { - warn("unsupported event type received: " + eventType); - } - } - - /** - * Authenticator - */ - private static class HTTPAuthenticateProxy extends Authenticator { - - /** - * Contributed by Dele Olajide - * See http://groups.yahoo.com/group/pushlet/message/634 - */ - - private String thePassword = ""; - private String theUser = ""; - - public HTTPAuthenticateProxy(String username, String password) { - - thePassword = password; - theUser = username; - } - - protected PasswordAuthentication getPasswordAuthentication() { - // System.out.println("[HttpAuthenticateProxy] Username = " + theUser); - // System.out.println("[HttpAuthenticateProxy] Password = " + thePassword); - - return new PasswordAuthentication(theUser, thePassword.toCharArray()); - } - - } - -} - -/* - * $Log: PushletClient.java,v $ - * Revision 1.19 2009/06/04 12:46:35 justb - * PushletClient: add more hooks for extension (feat ID: 2799694 Craig M) - * - * Revision 1.18 2007/11/10 13:52:47 justb - * make startDataEventListener method protected to allow overriding - * - * Revision 1.17 2006/10/29 16:47:57 justb - * included patch from Jeff Nowakowski: wait until listener thread runs - * - * Revision 1.16 2005/05/06 20:08:20 justb - * client enhancements - * - * Revision 1.15 2005/03/27 17:42:27 justb - * enhancements - * - * Revision 1.14 2005/03/25 23:54:04 justb - * *** empty log message *** - * - * Revision 1.13 2005/02/28 16:59:40 justb - * fixes for leave and disconnect - * - * Revision 1.12 2005/02/28 15:57:54 justb - * added SimpleListener example - * - * Revision 1.11 2005/02/21 12:31:44 justb - * added proxy contribution from Dele Olajide - * - * Revision 1.10 2005/02/20 13:05:32 justb - * removed the Postlet (integrated in Pushlet protocol) - * - * Revision 1.9 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.8 2005/02/18 09:54:12 justb - * refactor: rename Publisher Dispatcher and single Subscriber class - * - * Revision 1.7 2005/02/15 15:46:30 justb - * client API improves - * - * Revision 1.6 2005/02/15 13:28:56 justb - * first quick rewrite adapt for v2 protocol - * - * Revision 1.5 2004/10/25 21:23:44 justb - * *** empty log message *** - * - * Revision 1.4 2004/10/24 13:52:51 justb - * small fixes in client lib - * - * Revision 1.3 2004/10/24 12:58:18 justb - * revised client and test classes for new protocol - * - * Revision 1.2 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.1 2004/03/10 20:14:17 justb - * renamed all *JavaPushletClient* to *PushletClient* - * - * Revision 1.10 2004/03/10 15:45:55 justb - * many cosmetic changes - * - * Revision 1.9 2003/08/17 20:30:20 justb - * cosmetic changes - * - * Revision 1.8 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.client; + +import nl.justobjects.pushlet.core.Event; +import nl.justobjects.pushlet.core.EventParser; +import nl.justobjects.pushlet.core.Protocol; +import nl.justobjects.pushlet.util.PushletException; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.OutputStream; +import java.net.*; +import java.util.Map; + +/** + * Client API for Java HTTP client applets or apps. + *

+ * Use this class within Java client applications or applets. + * Implement a PushletClientListener to receive callbacks for + * data-related Event objects pushed by the server. + *

+ * This class may also be used as a base class and be extended + * for custom clients, hence the presence of many proteced methods. + * + * @author Just van den Broecke - Just Objects © + * @version $Id: PushletClient.java,v 1.19 2009/06/04 12:46:35 justb Exp $ + * @see PushletClientListener + * @see nl.justobjects.pushlet.test.PushletApplet + * @see nl.justobjects.pushlet.test.PushletPingApplication + */ +public class PushletClient implements Protocol { + /** + * Pushlet URL. + */ + private String pushletURL; + + /** + * Debug flag for verbose output. + */ + private boolean debug; + + /** + * Id gotten on join ack + */ + private String id; + + /** + * Internal listener for data events pushed by server. + */ + protected DataEventListener dataEventListener; + + /** + * Constructor with full pushlet URL. + */ + public PushletClient(String aPushletURL) { + pushletURL = aPushletURL; + } + + /** + * Constructor with host and port using default URI. + */ + public PushletClient(String aHost, int aPort) { + this("http://" + aHost + ":" + aPort + DEFAULT_SERVLET_URI); + } + + /** + * Set proxy options and optional proxy authentication. + *

+ * Contributed by Dele Olajide + * See http://groups.yahoo.com/group/pushlet/message/634 + *

+ * Usage: + * PushletClient pushletClient = new PushletClient("http:://www.domain.com/pushlet"); + * pushletClient.setProxyOptions("proxy.bla.com", "8080", ....); + *

+ * use pushletClient further as normal + */ + public void setProxyOptions(String aProxyHost, + String aProxyPort, String theNonProxyHosts, + String aUserName, String aPassword, String anNTLMDomain) { + + // Enable proxying + System.setProperty("http.proxySet", "true"); + System.setProperty("http.proxyHost", aProxyHost); + System.setProperty("http.proxyPort", aProxyPort); + + // Set optional non-proxy hosts + if (theNonProxyHosts != null) { + System.setProperty("http.nonProxyHosts", theNonProxyHosts); + } + + // If user name specified configure proxy authentication + if (aUserName != null) { + System.setProperty("http.proxyUser", aUserName); + System.setProperty("http.proxyPassword", aPassword); + + // See inner class below + Authenticator.setDefault(new HTTPAuthenticateProxy(aUserName, aPassword)); + + // Optional NT domain + if (anNTLMDomain != null) { + System.setProperty("http.auth.ntlm.domain", anNTLMDomain); + } + } + } + + /** + * Join server, starts session. + */ + public void join() throws PushletException { + Event event = new Event(E_JOIN); + event.setField(P_FORMAT, FORMAT_XML); + Event response = doControl(event); + throwOnNack(response); + + // Join Ack received + id = response.getField(P_ID); + } + + /** + * Leave server, stops session. + */ + public void leave() throws PushletException { + stopListen(); + throwOnInvalidSession(); + Event event = new Event(E_LEAVE); + event.setField(P_ID, id); + Event response = doControl(event); + + throwOnNack(response); + id = null; + } + + /** + * Open data channel. + */ + public void listen(PushletClientListener aListener) throws PushletException { + listen(aListener, MODE_STREAM); + } + + /** + * Open data channel in stream or push mode. + */ + public void listen(PushletClientListener aListener, String aMode) throws PushletException { + listen(aListener, aMode, null); + } + + /** + * Open data channel in stream or push mode with a subject. + */ + public void listen(PushletClientListener aListener, String aMode, String aSubject) throws PushletException { + throwOnInvalidSession(); + stopListen(); + + String listenURL = pushletURL + + "?" + P_EVENT + "=" + E_LISTEN + + "&" + P_ID + "=" + id + + "&" + P_MODE + "=" + aMode; + if (aSubject != null) { + listenURL = listenURL + "&" + P_SUBJECT + "=" + aSubject; + } + + // Start listener thread (sync call). + startDataEventListener(aListener, listenURL); + } + + /** + * Immediate listener: joins/subscribes and listens in one action. + */ + public void joinListen(PushletClientListener aListener, String aMode, String aSubject) throws PushletException { + stopListen(); + + String listenURL = pushletURL + + "?" + P_EVENT + "=" + E_JOIN_LISTEN + + "&" + P_FORMAT + "=" + FORMAT_XML + + "&" + P_MODE + "=" + aMode + + "&" + P_SUBJECT + "=" + aSubject; + + // Start listener thread (sync call). + startDataEventListener(aListener, listenURL); + } + + /** + * Publish an event through server. + */ + public void publish(String aSubject, Map theAttributes) throws PushletException { + throwOnInvalidSession(); + Event event = new Event(E_PUBLISH, theAttributes); + event.setField(P_SUBJECT, aSubject); + event.setField(P_ID, id); + Event response = doControl(event); + throwOnNack(response); + } + + /** + * Subscribes, returning subscription id. + */ + public String subscribe(String aSubject, String aLabel) throws PushletException { + throwOnInvalidSession(); + Event event = new Event(E_SUBSCRIBE); + event.setField(P_ID, id); + event.setField(P_SUBJECT, aSubject); + + // Optional label, is returned in data events + if (aLabel != null) { + event.setField(P_SUBSCRIPTION_LABEL, aLabel); + } + + // Send request + Event response = doControl(event); + throwOnNack(response); + + return response.getField(P_SUBSCRIPTION_ID); + } + + /** + * Subscribes, returning subscription id. + */ + public String subscribe(String aSubject) throws PushletException { + return subscribe(aSubject, null); + } + + /** + * Unsubscribes with subscription id. + */ + public void unsubscribe(String aSubscriptionId) throws PushletException { + throwOnInvalidSession(); + Event event = new Event(E_UNSUBSCRIBE); + event.setField(P_ID, id); + + // Optional subscription id + if (aSubscriptionId != null) { + event.setField(P_SUBSCRIPTION_ID, aSubscriptionId); + } + + Event response = doControl(event); + throwOnNack(response); + } + + /** + * Unsubscribes from all subjects. + */ + public void unsubscribe() throws PushletException { + unsubscribe(null); + } + + /** + * Stop the listener. + */ + public void stopListen() throws PushletException { + if (dataEventListener != null) { + unsubscribe(); + dataEventListener.stop(); + dataEventListener = null; + } + } + + public void setDebug(boolean b) { + debug = b; + } + + /** + * Starts default DataEventListener and waits for its thread to start. + */ + protected void startDataEventListener(PushletClientListener aListener, String aListenURL) { + // Suggestion by Jeff Nowakowski 29.oct.2006 + dataEventListener = new DataEventListener(aListener, aListenURL); + + synchronized (dataEventListener) { + dataEventListener.start(); + try { + // Wait for data event listener (thread) to start + dataEventListener.wait(); + } catch (InterruptedException e) { + } + } + } + + protected void throwOnNack(Event anEvent) throws PushletException { + if (anEvent.getEventType().equals(E_NACK)) { + throw new PushletException("Negative response: reason=" + anEvent.getField(P_REASON)); + } + } + + protected void throwOnInvalidSession() throws PushletException { + if (id == null) { + throw new PushletException("Invalid pushlet session"); + } + } + + protected Reader openURL(String aURL) throws PushletException { + // Open URL connection with server + try { + p("Connecting to " + aURL); + URL url = new URL(aURL); + URLConnection urlConnection = url.openConnection(); + + // Disable any kind of caching. + urlConnection.setUseCaches(false); + urlConnection.setDefaultUseCaches(false); + + // TODO: later version may use POST + // Enable HTTP POST + // urlConnection.setDoOutput(true); + + // Do the POST with Event in XML in body + // OutputStream os = urlConnection.getOutputStream(); + // os.write(anEvent.toXML().getBytes()); + // os.flush(); + // os.close(); + + // Get the stream from the server. + // reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); + // Note: somehow the client does not work with some JVMs when using + // BufferedInputStream... So do unbuffered input. + // p("Opening urlConnection inputstream"); + return new InputStreamReader(urlConnection.getInputStream()); + + } catch (Throwable t) { + warn("openURL() could not open " + aURL, t); + throw new PushletException(" could not open " + aURL, t); + } + } + + + /** + * Send control events to server and return response. + */ + protected Event doControl(Event aControlEvent) throws PushletException { + String controlURL = pushletURL + "?" + aControlEvent.toQueryString(); + + p("doControl to " + controlURL); + + // Open URL connection with server + Reader reader = openURL(controlURL); + + // Get Pushlet event from stream + Event event = null; + try { + p("Getting event..."); + // Get next event from server + event = EventParser.parse(reader); + p("Event received " + event); + return event; + } catch (Throwable t) { + // Stop and report error. + warn("doControl() exception", t); + throw new PushletException(" error parsing response from" + controlURL, t); + } + } + + /** + * Util: print. + */ + protected void p(String s) { + if (debug) { + System.out.println("[PushletClient] " + s); + } + } + + /** + * Util: warn. + */ + protected void warn(String s) { + warn(s, null); + } + + /** + * Util: warn with exception. + */ + protected void warn(String s, Throwable t) { + System.err.println("[PushletClient] - WARN - " + s + " ex=" + t); + + if (t != null) { + t.printStackTrace(); + } + } + + /** + * Internal (default) listener for the Pushlet data channel. + */ + protected class DataEventListener implements Runnable { + /** + * Client's listener that gets called back on events. + */ + private PushletClientListener listener; + + /** + * Receiver receiveThread. + */ + private Thread receiveThread = null; + private Reader reader; + private String refreshURL; + private String listenURL; + + public DataEventListener(PushletClientListener aListener, String aListenURL) { + listener = aListener; + listenURL = aListenURL; + } + + public void start() { + // All ok: start a receiver receiveThread + receiveThread = new Thread(this); + receiveThread.start(); + + } + + /** + * Stop listening; may restart later with start(). + */ + public void stop() { + p("In stop()"); + bailout(); + } + + /** + * Receive event objects from server and callback listener. + */ + public void run() { + p("Start run()"); + try { + while (receiveThread != null && receiveThread.isAlive()) { + // Connect to server + reader = openURL(listenURL); + + synchronized (this) { + // Inform the calling thread we're ready to receive events. + // Suggestion by Jeff Nowakowski 29.oct.2006 + this.notify(); + } + + // Get events while we're alive. + while (receiveThread != null && receiveThread.isAlive()) { + Event event = null; + try { + // p("Getting event..."); + // Get next event from server + event = EventParser.parse(reader); + p("Event received " + event); + } catch (Throwable t) { + + // Stop and report error. + // warn("Stop run() on exception", t); + if (listener != null) { + listener.onError("exception during receive: " + t); + } + + break; + } + + // Handle event by calling listener + if (event != null && listener != null) { + // p("received: " + event.toXML()); + String eventType = event.getEventType(); + if (eventType.equals(E_HEARTBEAT)) { + listener.onHeartbeat(event); + } else if (eventType.equals(E_DATA)) { + listener.onData(event); + } else if (eventType.equals(E_JOIN_LISTEN_ACK)) { + id = event.getField(P_ID); + } else if (eventType.equals(E_LISTEN_ACK)) { + p("Listen ack ok"); + } else if (eventType.equals(E_REFRESH_ACK)) { + // ignore + } else if (eventType.equals(E_ABORT)) { + listener.onAbort(event); + listener = null; + break; + } else if (eventType.equals(E_REFRESH)) { + refresh(event); + } else { + handleUnknownEventType(eventType, event, listener); + } + } + } + } + } catch (Throwable t) { + warn("Exception in run() ", t); + // bailout(); + } + } + + protected void disconnect() { + p("start disconnect()"); + if (reader != null) { + try { + // this blocks, find another way + // reader.close(); + p("Closed reader ok"); + } catch (Exception ignore) { + } finally { + reader = null; + } + } + p("end disconnect()"); + } + + /** + * Stop receiver receiveThread. + */ + public void stopThread() { + p("In stopThread()"); + + // Keep a reference such that we can kill it from here. + Thread targetThread = receiveThread; + + receiveThread = null; + + // This should stop the main loop for this receiveThread. + // Killing a receiveThread on a blcing read is tricky. + // See also http://gee.cs.oswego.edu/dl/cpj/cancel.html + if ((targetThread != null) && targetThread.isAlive()) { + + targetThread.interrupt(); + + try { + + // Wait for it to die + targetThread.join(500); + } catch (InterruptedException ignore) { + } + + // If current receiveThread refuses to die, + // take more rigorous methods. + if (targetThread.isAlive()) { + + // Not preferred but may be needed + // to stop during a blocking read. + targetThread.stop(); + + // Wait for it to die + try { + targetThread.join(500); + } catch (Throwable ignore) { + } + } + + p("Stopped receiveThread alive=" + targetThread.isAlive()); + + } + } + + /** + * Stop listening on stream from server. + */ + public void bailout() { + p("In bailout()"); + stopThread(); + disconnect(); + } + + /** + * Handle refresh, by pausing. + */ + protected void refresh(Event aRefreshEvent) throws PushletException { + try { + // Wait for specified time. + Thread.sleep(Long.parseLong(aRefreshEvent.getField(P_WAIT))); + } catch (Throwable t) { + warn("abort while refresing"); + refreshURL = null; + return; + } + + // If stopped during sleep, don't proceed + if (receiveThread == null) { + return; + } + + // Create url to refresh + refreshURL = pushletURL + + "?" + P_ID + "=" + id + + "&" + P_EVENT + "=" + E_REFRESH + ; + + if (reader != null) { + try { + reader.close(); + + } catch (IOException ignore) { + + } + reader = null; + } + + reader = openURL(refreshURL); + } + + /** + * Handle unknown Event (default behaviour). + */ + protected void handleUnknownEventType(String eventType, Event event, PushletClientListener listener) { + warn("unsupported event type received: " + eventType); + } + } + + /** + * Authenticator + */ + private static class HTTPAuthenticateProxy extends Authenticator { + + /** + * Contributed by Dele Olajide + * See http://groups.yahoo.com/group/pushlet/message/634 + */ + + private String thePassword = ""; + private String theUser = ""; + + public HTTPAuthenticateProxy(String username, String password) { + + thePassword = password; + theUser = username; + } + + protected PasswordAuthentication getPasswordAuthentication() { + // System.out.println("[HttpAuthenticateProxy] Username = " + theUser); + // System.out.println("[HttpAuthenticateProxy] Password = " + thePassword); + + return new PasswordAuthentication(theUser, thePassword.toCharArray()); + } + + } + +} + +/* + * $Log: PushletClient.java,v $ + * Revision 1.19 2009/06/04 12:46:35 justb + * PushletClient: add more hooks for extension (feat ID: 2799694 Craig M) + * + * Revision 1.18 2007/11/10 13:52:47 justb + * make startDataEventListener method protected to allow overriding + * + * Revision 1.17 2006/10/29 16:47:57 justb + * included patch from Jeff Nowakowski: wait until listener thread runs + * + * Revision 1.16 2005/05/06 20:08:20 justb + * client enhancements + * + * Revision 1.15 2005/03/27 17:42:27 justb + * enhancements + * + * Revision 1.14 2005/03/25 23:54:04 justb + * *** empty log message *** + * + * Revision 1.13 2005/02/28 16:59:40 justb + * fixes for leave and disconnect + * + * Revision 1.12 2005/02/28 15:57:54 justb + * added SimpleListener example + * + * Revision 1.11 2005/02/21 12:31:44 justb + * added proxy contribution from Dele Olajide + * + * Revision 1.10 2005/02/20 13:05:32 justb + * removed the Postlet (integrated in Pushlet protocol) + * + * Revision 1.9 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.8 2005/02/18 09:54:12 justb + * refactor: rename Publisher Dispatcher and single Subscriber class + * + * Revision 1.7 2005/02/15 15:46:30 justb + * client API improves + * + * Revision 1.6 2005/02/15 13:28:56 justb + * first quick rewrite adapt for v2 protocol + * + * Revision 1.5 2004/10/25 21:23:44 justb + * *** empty log message *** + * + * Revision 1.4 2004/10/24 13:52:51 justb + * small fixes in client lib + * + * Revision 1.3 2004/10/24 12:58:18 justb + * revised client and test classes for new protocol + * + * Revision 1.2 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.1 2004/03/10 20:14:17 justb + * renamed all *JavaPushletClient* to *PushletClient* + * + * Revision 1.10 2004/03/10 15:45:55 justb + * many cosmetic changes + * + * Revision 1.9 2003/08/17 20:30:20 justb + * cosmetic changes + * + * Revision 1.8 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * */ \ No newline at end of file diff --git a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/client/PushletClientListener.java b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/client/PushletClientListener.java index 74cee7b2b2..864e2ef7dd 100644 --- a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/client/PushletClientListener.java +++ b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/client/PushletClientListener.java @@ -1,50 +1,50 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.client; - -import nl.justobjects.pushlet.core.Event; -import nl.justobjects.pushlet.core.Protocol; - -/** - * Interface for listener of the PushletClient object. - * - * @version $Id: PushletClientListener.java,v 1.5 2005/02/21 11:50:37 justb Exp $ - * @author Just van den Broecke - Just Objects © - **/ -public interface PushletClientListener extends Protocol { - /** Abort event from server. */ - public void onAbort(Event theEvent); - - /** Data event from server. */ - public void onData(Event theEvent); - - /** Heartbeat event from server. */ - public void onHeartbeat(Event theEvent); - - /** Error occurred. */ - public void onError(String message); -} - -/* +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.client; + +import nl.justobjects.pushlet.core.Event; +import nl.justobjects.pushlet.core.Protocol; + +/** + * Interface for listener of the PushletClient object. + * + * @version $Id: PushletClientListener.java,v 1.5 2005/02/21 11:50:37 justb Exp $ + * @author Just van den Broecke - Just Objects © + **/ +public interface PushletClientListener extends Protocol { + /** Abort event from server. */ + public void onAbort(Event theEvent); + + /** Data event from server. */ + public void onData(Event theEvent); + + /** Heartbeat event from server. */ + public void onHeartbeat(Event theEvent); + + /** Error occurred. */ + public void onError(String message); +} + +/* * $Log: PushletClientListener.java,v $ * Revision 1.5 2005/02/21 11:50:37 justb * ohase1 of refactoring Subscriber into Session/Controller/Subscriber -* -* Revision 1.4 2005/02/15 15:46:31 justb -* client API improves -* -* Revision 1.3 2004/10/24 12:58:18 justb -* revised client and test classes for new protocol -* -* Revision 1.2 2004/09/03 22:35:37 justb -* Almost complete rewrite, just checking in now -* -* Revision 1.1 2004/03/10 20:14:17 justb -* renamed all *JavaPushletClient* to *PushletClient* -* -* Revision 1.3 2003/08/15 08:37:40 justb -* fix/add Copyright+LGPL file headers and footers -* -* +* +* Revision 1.4 2005/02/15 15:46:31 justb +* client API improves +* +* Revision 1.3 2004/10/24 12:58:18 justb +* revised client and test classes for new protocol +* +* Revision 1.2 2004/09/03 22:35:37 justb +* Almost complete rewrite, just checking in now +* +* Revision 1.1 2004/03/10 20:14:17 justb +* renamed all *JavaPushletClient* to *PushletClient* +* +* Revision 1.3 2003/08/15 08:37:40 justb +* fix/add Copyright+LGPL file headers and footers +* +* */ \ No newline at end of file diff --git a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/BrowserAdapter.java b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/BrowserAdapter.java index 8aa226b659..d523882f49 100644 --- a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/BrowserAdapter.java +++ b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/BrowserAdapter.java @@ -1,203 +1,203 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -import nl.justobjects.pushlet.util.Log; - -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.Iterator; - -/** - * Generic implementation of ClientAdapter for browser clients. - * - * @author Just van den Broecke - Just Objects © - * @version $Id: BrowserAdapter.java,v 1.6 2007/11/09 13:15:35 justb Exp $ - */ -public class BrowserAdapter implements ClientAdapter, Protocol { - - public static final String START_DOCUMENT = - "" - + "" - + "\n"; - public static final String END_DOCUMENT = ""; - - private PrintWriter servletOut; - private HttpServletResponse servletRsp; - private int bytesSent; - - /** - * Constructor. - */ - public BrowserAdapter(HttpServletResponse aServletResponse) { - servletRsp = aServletResponse; - } - - /** - * Generic init. - */ - public void start() throws IOException { - // Keep servlet request/response objects until page ends in stop() - // Content type as HTML - servletRsp.setStatus(HttpServletResponse.SC_OK); - servletRsp.setContentType("text/html;charset=UTF-8"); - - // http://www.junlu.com/msg/45902.html - // Log.debug("bufsize=" + aRsp.getBufferSize()); - servletOut = servletRsp.getWriter(); - send(START_DOCUMENT); - } - - /** - * Push Event to client. - */ - public void push(Event anEvent) throws IOException { - Log.debug("BCA event=" + anEvent.toXML()); - - // Check if we should refresh - if (anEvent.getEventType().equals(Protocol.E_REFRESH)) { - // Append refresh and tail of HTML document - // Construct the JS callback line to be sent as last line of doc. - // This will refresh the request using the unique id to determine - // the subscriber instance on the server. The client will wait for - // a number of milliseconds. - long refreshWaitMillis = Long.parseLong(anEvent.getField(P_WAIT)); - - // Create servlet request for requesting next events (refresh) - String url = anEvent.getField(P_URL); - String jsRefreshTrigger = "\n"; - - - send(jsRefreshTrigger + END_DOCUMENT); - } else { - send(event2JavaScript(anEvent)); - } - } - - /** - * End HTML page in client browser. - */ - public void stop() { - // To be garbage collected if adapter remains active - servletOut = null; - } - - /** - * Send any string to browser. - */ - protected void send(String s) throws IOException { - // Send string to browser. - // Log.debug("Adapter: sending: " + s); - if (servletOut == null) { - throw new IOException("Client adapter was stopped"); - } - - servletOut.print(s); - - servletOut.flush(); - - // Note: this doesn't seem to have effect - // in Tomcat 4/5 if the client already disconnected. - servletRsp.flushBuffer(); - - bytesSent += s.length(); - Log.debug("bytesSent= " + bytesSent); - // Log.debug("BCA sent event: " + s); - } - - /** - * Converts the Java Event to a JavaScript function call in browser page. - */ - protected String event2JavaScript(Event event) throws IOException { - - // Convert the event to a comma-separated string. - String jsArgs = ""; - for (Iterator iter = event.getFieldNames(); iter.hasNext();) { - String name = (String) iter.next(); - String value = event.getField(name); - String nextArgument = (jsArgs.equals("") ? "" : ",") + "'" + name + "'" + ", \"" + value + "\""; - jsArgs += nextArgument; - } - - // Construct and return the function call */ - return ""; - } - -} - -/* - * $Log: BrowserAdapter.java,v $ - * Revision 1.6 2007/11/09 13:15:35 justb - * add charset=UTF-8 in returned HTTP content types - * - * Revision 1.5 2006/05/15 11:52:53 justb - * updates mainly for AJAX client - * - * Revision 1.4 2006/05/06 00:10:11 justb - * various chgs but not too serious... - * - * Revision 1.3 2005/02/28 12:45:59 justb - * introduced Command class - * - * Revision 1.2 2005/02/21 11:50:44 justb - * ohase1 of refactoring Subscriber into Session/Controller/Subscriber - * - * Revision 1.1 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.12 2005/02/15 13:30:23 justb - * changes for Tomcat buffering (now working in tc4 and 5.0) - * - * Revision 1.11 2005/01/24 22:45:58 justb - * getting safari to work - * - * Revision 1.10 2005/01/18 16:46:27 justb - * buffer size setting ignored by tomcat workings - * - * Revision 1.9 2004/10/24 12:58:18 justb - * revised client and test classes for new protocol - * - * Revision 1.8 2004/09/20 22:01:38 justb - * more changes for new protocol - * - * Revision 1.7 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.6 2004/08/15 16:00:15 justb - * enhancements to pull mode - * - * Revision 1.5 2004/08/13 23:36:05 justb - * rewrite of Pullet into Pushlet "pull" mode - * - * Revision 1.4 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.3 2003/08/12 09:57:05 justb - * replaced all print statements to Log.*() calls - * - * Revision 1.2 2003/05/18 16:15:07 justb - * support for XML encoded Events - * - * Revision 1.1.1.1 2002/09/24 21:02:30 justb - * import to sourceforge - * - * Revision 1.1.1.1 2002/09/20 22:48:17 justb - * import to SF - * - * Revision 1.1.1.1 2002/09/20 14:19:02 justb - * first import into SF - * - * Revision 1.5 2002/04/15 20:42:41 just - * reformatting and renaming GuardedQueue to EventQueue - * - * Revision 1.4 2000/12/27 22:39:35 just - * no message - * - * Revision 1.3 2000/10/30 14:15:47 just - * no message - * - * - */ - +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +import nl.justobjects.pushlet.util.Log; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Iterator; + +/** + * Generic implementation of ClientAdapter for browser clients. + * + * @author Just van den Broecke - Just Objects © + * @version $Id: BrowserAdapter.java,v 1.6 2007/11/09 13:15:35 justb Exp $ + */ +public class BrowserAdapter implements ClientAdapter, Protocol { + + public static final String START_DOCUMENT = + "" + + "" + + "\n"; + public static final String END_DOCUMENT = ""; + + private PrintWriter servletOut; + private HttpServletResponse servletRsp; + private int bytesSent; + + /** + * Constructor. + */ + public BrowserAdapter(HttpServletResponse aServletResponse) { + servletRsp = aServletResponse; + } + + /** + * Generic init. + */ + public void start() throws IOException { + // Keep servlet request/response objects until page ends in stop() + // Content type as HTML + servletRsp.setStatus(HttpServletResponse.SC_OK); + servletRsp.setContentType("text/html;charset=UTF-8"); + + // http://www.junlu.com/msg/45902.html + // Log.debug("bufsize=" + aRsp.getBufferSize()); + servletOut = servletRsp.getWriter(); + send(START_DOCUMENT); + } + + /** + * Push Event to client. + */ + public void push(Event anEvent) throws IOException { + Log.debug("BCA event=" + anEvent.toXML()); + + // Check if we should refresh + if (anEvent.getEventType().equals(Protocol.E_REFRESH)) { + // Append refresh and tail of HTML document + // Construct the JS callback line to be sent as last line of doc. + // This will refresh the request using the unique id to determine + // the subscriber instance on the server. The client will wait for + // a number of milliseconds. + long refreshWaitMillis = Long.parseLong(anEvent.getField(P_WAIT)); + + // Create servlet request for requesting next events (refresh) + String url = anEvent.getField(P_URL); + String jsRefreshTrigger = "\n"; + + + send(jsRefreshTrigger + END_DOCUMENT); + } else { + send(event2JavaScript(anEvent)); + } + } + + /** + * End HTML page in client browser. + */ + public void stop() { + // To be garbage collected if adapter remains active + servletOut = null; + } + + /** + * Send any string to browser. + */ + protected void send(String s) throws IOException { + // Send string to browser. + // Log.debug("Adapter: sending: " + s); + if (servletOut == null) { + throw new IOException("Client adapter was stopped"); + } + + servletOut.print(s); + + servletOut.flush(); + + // Note: this doesn't seem to have effect + // in Tomcat 4/5 if the client already disconnected. + servletRsp.flushBuffer(); + + bytesSent += s.length(); + Log.debug("bytesSent= " + bytesSent); + // Log.debug("BCA sent event: " + s); + } + + /** + * Converts the Java Event to a JavaScript function call in browser page. + */ + protected String event2JavaScript(Event event) throws IOException { + + // Convert the event to a comma-separated string. + String jsArgs = ""; + for (Iterator iter = event.getFieldNames(); iter.hasNext();) { + String name = (String) iter.next(); + String value = event.getField(name); + String nextArgument = (jsArgs.equals("") ? "" : ",") + "'" + name + "'" + ", \"" + value + "\""; + jsArgs += nextArgument; + } + + // Construct and return the function call */ + return ""; + } + +} + +/* + * $Log: BrowserAdapter.java,v $ + * Revision 1.6 2007/11/09 13:15:35 justb + * add charset=UTF-8 in returned HTTP content types + * + * Revision 1.5 2006/05/15 11:52:53 justb + * updates mainly for AJAX client + * + * Revision 1.4 2006/05/06 00:10:11 justb + * various chgs but not too serious... + * + * Revision 1.3 2005/02/28 12:45:59 justb + * introduced Command class + * + * Revision 1.2 2005/02/21 11:50:44 justb + * ohase1 of refactoring Subscriber into Session/Controller/Subscriber + * + * Revision 1.1 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.12 2005/02/15 13:30:23 justb + * changes for Tomcat buffering (now working in tc4 and 5.0) + * + * Revision 1.11 2005/01/24 22:45:58 justb + * getting safari to work + * + * Revision 1.10 2005/01/18 16:46:27 justb + * buffer size setting ignored by tomcat workings + * + * Revision 1.9 2004/10/24 12:58:18 justb + * revised client and test classes for new protocol + * + * Revision 1.8 2004/09/20 22:01:38 justb + * more changes for new protocol + * + * Revision 1.7 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.6 2004/08/15 16:00:15 justb + * enhancements to pull mode + * + * Revision 1.5 2004/08/13 23:36:05 justb + * rewrite of Pullet into Pushlet "pull" mode + * + * Revision 1.4 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.3 2003/08/12 09:57:05 justb + * replaced all print statements to Log.*() calls + * + * Revision 1.2 2003/05/18 16:15:07 justb + * support for XML encoded Events + * + * Revision 1.1.1.1 2002/09/24 21:02:30 justb + * import to sourceforge + * + * Revision 1.1.1.1 2002/09/20 22:48:17 justb + * import to SF + * + * Revision 1.1.1.1 2002/09/20 14:19:02 justb + * first import into SF + * + * Revision 1.5 2002/04/15 20:42:41 just + * reformatting and renaming GuardedQueue to EventQueue + * + * Revision 1.4 2000/12/27 22:39:35 just + * no message + * + * Revision 1.3 2000/10/30 14:15:47 just + * no message + * + * + */ + diff --git a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/ClientAdapter.java b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/ClientAdapter.java index c7ea141fee..4b187325ef 100644 --- a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/ClientAdapter.java +++ b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/ClientAdapter.java @@ -1,72 +1,72 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -import java.io.IOException; - -/** - * Adapter interface for encapsulation of specific HTTP clients. - * - * @author Just van den Broecke - Just Objects © - * @version $Id: ClientAdapter.java,v 1.8 2007/11/23 14:33:07 justb Exp $ - */ -public interface ClientAdapter { - - /** - * Start event push. - */ - public void start() throws IOException; - - /** - * Push single Event to client. - */ - public void push(Event anEvent) throws IOException; - - /** - * Stop event push. - */ - public void stop() throws IOException; -} - -/* - * $Log: ClientAdapter.java,v $ - * Revision 1.8 2007/11/23 14:33:07 justb - * core classes now configurable through factory - * - * Revision 1.7 2005/02/28 12:45:59 justb - * introduced Command class - * - * Revision 1.6 2005/02/21 11:50:45 justb - * ohase1 of refactoring Subscriber into Session/Controller/Subscriber - * - * Revision 1.5 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.4 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.3 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.2 2003/05/18 16:15:08 justb - * support for XML encoded Events - * - * Revision 1.1.1.1 2002/09/24 21:02:30 justb - * import to sourceforge - * - * Revision 1.1.1.1 2002/09/20 22:48:17 justb - * import to SF - * - * Revision 1.1.1.1 2002/09/20 14:19:03 justb - * first import into SF - * - * Revision 1.3 2002/04/15 20:42:41 just - * reformatting and renaming GuardedQueue to EventQueue - * - * Revision 1.2 2000/08/21 20:48:29 just - * added CVS log and id tags plus copyrights - * - * - */ - +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +import java.io.IOException; + +/** + * Adapter interface for encapsulation of specific HTTP clients. + * + * @author Just van den Broecke - Just Objects © + * @version $Id: ClientAdapter.java,v 1.8 2007/11/23 14:33:07 justb Exp $ + */ +public interface ClientAdapter { + + /** + * Start event push. + */ + public void start() throws IOException; + + /** + * Push single Event to client. + */ + public void push(Event anEvent) throws IOException; + + /** + * Stop event push. + */ + public void stop() throws IOException; +} + +/* + * $Log: ClientAdapter.java,v $ + * Revision 1.8 2007/11/23 14:33:07 justb + * core classes now configurable through factory + * + * Revision 1.7 2005/02/28 12:45:59 justb + * introduced Command class + * + * Revision 1.6 2005/02/21 11:50:45 justb + * ohase1 of refactoring Subscriber into Session/Controller/Subscriber + * + * Revision 1.5 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.4 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.3 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.2 2003/05/18 16:15:08 justb + * support for XML encoded Events + * + * Revision 1.1.1.1 2002/09/24 21:02:30 justb + * import to sourceforge + * + * Revision 1.1.1.1 2002/09/20 22:48:17 justb + * import to SF + * + * Revision 1.1.1.1 2002/09/20 14:19:03 justb + * first import into SF + * + * Revision 1.3 2002/04/15 20:42:41 just + * reformatting and renaming GuardedQueue to EventQueue + * + * Revision 1.2 2000/08/21 20:48:29 just + * added CVS log and id tags plus copyrights + * + * + */ + diff --git a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/Dispatcher.java b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/Dispatcher.java index 5cd739d5bd..83b402f693 100644 --- a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/Dispatcher.java +++ b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/Dispatcher.java @@ -1,265 +1,265 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -import nl.justobjects.pushlet.util.Log; -import nl.justobjects.pushlet.util.PushletException; - -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; - -/** - * Routes Events to Subscribers. - * - * @author Just van den Broecke - Just Objects © - * @version $Id: Dispatcher.java,v 1.9 2007/12/04 13:55:53 justb Exp $ - */ -public class Dispatcher implements Protocol, ConfigDefs { - /** - * Singleton pattern: single instance. - */ - private static Dispatcher instance; - protected SessionManagerVisitor sessionManagerVisitor; - - static { - try { - instance = (Dispatcher) Config.getClass(DISPATCHER_CLASS, "nl.justobjects.pushlet.core.Dispatcher").newInstance(); - Log.info("Dispatcher created className=" + instance.getClass()); - } catch (Throwable t) { - Log.fatal("Cannot instantiate Dispatcher from config", t); - } - } - - /** - * Singleton pattern with factory method: protected constructor. - */ - protected Dispatcher() { - - } - - /** - * Singleton pattern: get single instance. - */ - public static Dispatcher getInstance() { - return instance; - } - - /** - * Send event to all subscribers. - */ - public synchronized void broadcast(Event anEvent) { - try { - // Let the SessionManager loop through Sessions, calling - // our Visitor Method for each Session. This is done to guard - // synchronization with SessionManager and to optimize by - // not getting an array of all sessions. - Object[] args = new Object[2]; - args[1] = anEvent; - Method method = sessionManagerVisitor.getMethod("visitBroadcast"); - SessionManager.getInstance().apply(sessionManagerVisitor, method, args); - } catch (Throwable t) { - Log.error("Error calling SessionManager.apply: ", t); - } - } - - /** - * Send event to subscribers matching Event subject. - */ - public synchronized void multicast(Event anEvent) { - try { - // Let the SessionManager loop through Sessions, calling - // our Visitor Method for each Session. This is done to guard - // synchronization with SessionManager and to optimize by - // not getting an array of all sessions. - Method method = sessionManagerVisitor.getMethod("visitMulticast"); - Object[] args = new Object[2]; - args[1] = anEvent; - SessionManager.getInstance().apply(sessionManagerVisitor, method, args); - } catch (Throwable t) { - Log.error("Error calling SessionManager.apply: ", t); - } - } - - - /** - * Send event to specific subscriber. - */ - public synchronized void unicast(Event event, String aSessionId) { - // Get subscriber to send event to - Session session = SessionManager.getInstance().getSession(aSessionId); - if (session == null) { - Log.warn("unicast: session with id=" + aSessionId + " does not exist"); - return; - } - - // Send Event to subscriber. - session.getSubscriber().onEvent((Event) event.clone()); - } - - /** - * Start Dispatcher. - */ - public void start() throws PushletException { - Log.info("Dispatcher started"); - - // Create callback for SessionManager visits. - sessionManagerVisitor = new SessionManagerVisitor(); - } - - /** - * Stop Dispatcher. - */ - public void stop() { - // Send abort control event to all subscribers. - Log.info("Dispatcher stopped: broadcast abort to all subscribers"); - broadcast(new Event(E_ABORT)); - } - - /** - * Supplies Visitor methods for callbacks from SessionManager. - */ - private class SessionManagerVisitor { - private final Map visitorMethods = new HashMap(2); - - SessionManagerVisitor() throws PushletException { - - try { - // Setup Visitor Methods for callback from SessionManager - // This is a slight opitmization over creating Method objects - // on each invokation. - Class[] argsClasses = {Session.class, Event.class}; - visitorMethods.put("visitMulticast", this.getClass().getMethod("visitMulticast", argsClasses)); - visitorMethods.put("visitBroadcast", this.getClass().getMethod("visitBroadcast", argsClasses)); - } catch (NoSuchMethodException e) { - throw new PushletException("Failed to setup SessionManagerVisitor", e); - } - } - - /** - * Return Visitor Method by name. - */ - public Method getMethod(String aName) { - return (Method) visitorMethods.get(aName); - - } - - /** - * Visitor method called by SessionManager. - */ - public void visitBroadcast(Session aSession, Event event) { - aSession.getSubscriber().onEvent((Event) event.clone()); - } - - /** - * Visitor method called by SessionManager. - */ - public void visitMulticast(Session aSession, Event event) { - Subscriber subscriber = aSession.getSubscriber(); - Event clonedEvent; - Subscription subscription; - - // Send only if the subscriber's criteria - // match the event. - if ((subscription = subscriber.match(event)) != null) { - // Personalize event - clonedEvent = (Event) event.clone(); - - // Set subscription id and optional label - clonedEvent.setField(P_SUBSCRIPTION_ID, subscription.getId()); - if (subscription.getLabel() != null) { - event.setField(P_SUBSCRIPTION_LABEL, subscription.getLabel()); - } - - subscriber.onEvent(clonedEvent); - } - } - } -} - -/* - * $Log: Dispatcher.java,v $ - * Revision 1.9 2007/12/04 13:55:53 justb - * reimplement SessionManager concurrency (prev version was not thread-safe!) - * - * Revision 1.8 2007/11/23 14:33:07 justb - * core classes now configurable through factory - * - * Revision 1.7 2005/02/28 12:45:59 justb - * introduced Command class - * - * Revision 1.6 2005/02/28 09:14:55 justb - * sessmgr/dispatcher factory/singleton support - * - * Revision 1.5 2005/02/21 16:59:06 justb - * SessionManager and session lease introduced - * - * Revision 1.4 2005/02/21 11:50:46 justb - * ohase1 of refactoring Subscriber into Session/Controller/Subscriber - * - * Revision 1.3 2005/02/18 12:36:47 justb - * changes for renaming and configurability - * - * Revision 1.2 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.1 2005/02/18 09:54:15 justb - * refactor: rename Publisher Dispatcher and single Subscriber class - * - * Revision 1.14 2005/02/16 14:39:34 justb - * fixed leave handling and added "poll" mode - * - * Revision 1.13 2004/10/24 20:50:35 justb - * refine subscription with label and sending sid and label on events - * - * Revision 1.12 2004/10/24 12:58:18 justb - * revised client and test classes for new protocol - * - * Revision 1.11 2004/09/26 21:39:43 justb - * allow multiple subscriptions and out-of-band requests - * - * Revision 1.10 2004/09/20 22:01:38 justb - * more changes for new protocol - * - * Revision 1.9 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.8 2004/08/13 23:36:05 justb - * rewrite of Pullet into Pushlet "pull" mode - * - * Revision 1.7 2004/08/12 13:18:54 justb - * cosmetic changes - * - * Revision 1.6 2004/03/10 15:45:55 justb - * many cosmetic changes - * - * Revision 1.5 2004/03/10 13:59:28 justb - * rewrite using Collection classes and finer synchronization - * - * Revision 1.4 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.3 2003/08/12 08:54:40 justb - * added getSubscriberCount() and use Log - * - * Revision 1.2 2003/05/18 16:15:08 justb - * support for XML encoded Events - * - * Revision 1.1.1.1 2002/09/24 21:02:31 justb - * import to sourceforge - * - * Revision 1.1.1.1 2002/09/20 22:48:18 justb - * import to SF - * - * Revision 1.1.1.1 2002/09/20 14:19:04 justb - * first import into SF - * - * Revision 1.3 2002/04/15 20:42:41 just - * reformatting and renaming GuardedQueue to EventQueue - * - * Revision 1.2 2000/08/21 20:48:29 just - * added CVS log and id tags plus copyrights - * - * - */ +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +import nl.justobjects.pushlet.util.Log; +import nl.justobjects.pushlet.util.PushletException; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +/** + * Routes Events to Subscribers. + * + * @author Just van den Broecke - Just Objects © + * @version $Id: Dispatcher.java,v 1.9 2007/12/04 13:55:53 justb Exp $ + */ +public class Dispatcher implements Protocol, ConfigDefs { + /** + * Singleton pattern: single instance. + */ + private static Dispatcher instance; + protected SessionManagerVisitor sessionManagerVisitor; + + static { + try { + instance = (Dispatcher) Config.getClass(DISPATCHER_CLASS, "nl.justobjects.pushlet.core.Dispatcher").newInstance(); + Log.info("Dispatcher created className=" + instance.getClass()); + } catch (Throwable t) { + Log.fatal("Cannot instantiate Dispatcher from config", t); + } + } + + /** + * Singleton pattern with factory method: protected constructor. + */ + protected Dispatcher() { + + } + + /** + * Singleton pattern: get single instance. + */ + public static Dispatcher getInstance() { + return instance; + } + + /** + * Send event to all subscribers. + */ + public synchronized void broadcast(Event anEvent) { + try { + // Let the SessionManager loop through Sessions, calling + // our Visitor Method for each Session. This is done to guard + // synchronization with SessionManager and to optimize by + // not getting an array of all sessions. + Object[] args = new Object[2]; + args[1] = anEvent; + Method method = sessionManagerVisitor.getMethod("visitBroadcast"); + SessionManager.getInstance().apply(sessionManagerVisitor, method, args); + } catch (Throwable t) { + Log.error("Error calling SessionManager.apply: ", t); + } + } + + /** + * Send event to subscribers matching Event subject. + */ + public synchronized void multicast(Event anEvent) { + try { + // Let the SessionManager loop through Sessions, calling + // our Visitor Method for each Session. This is done to guard + // synchronization with SessionManager and to optimize by + // not getting an array of all sessions. + Method method = sessionManagerVisitor.getMethod("visitMulticast"); + Object[] args = new Object[2]; + args[1] = anEvent; + SessionManager.getInstance().apply(sessionManagerVisitor, method, args); + } catch (Throwable t) { + Log.error("Error calling SessionManager.apply: ", t); + } + } + + + /** + * Send event to specific subscriber. + */ + public synchronized void unicast(Event event, String aSessionId) { + // Get subscriber to send event to + Session session = SessionManager.getInstance().getSession(aSessionId); + if (session == null) { + Log.warn("unicast: session with id=" + aSessionId + " does not exist"); + return; + } + + // Send Event to subscriber. + session.getSubscriber().onEvent((Event) event.clone()); + } + + /** + * Start Dispatcher. + */ + public void start() throws PushletException { + Log.info("Dispatcher started"); + + // Create callback for SessionManager visits. + sessionManagerVisitor = new SessionManagerVisitor(); + } + + /** + * Stop Dispatcher. + */ + public void stop() { + // Send abort control event to all subscribers. + Log.info("Dispatcher stopped: broadcast abort to all subscribers"); + broadcast(new Event(E_ABORT)); + } + + /** + * Supplies Visitor methods for callbacks from SessionManager. + */ + private class SessionManagerVisitor { + private final Map visitorMethods = new HashMap(2); + + SessionManagerVisitor() throws PushletException { + + try { + // Setup Visitor Methods for callback from SessionManager + // This is a slight opitmization over creating Method objects + // on each invokation. + Class[] argsClasses = {Session.class, Event.class}; + visitorMethods.put("visitMulticast", this.getClass().getMethod("visitMulticast", argsClasses)); + visitorMethods.put("visitBroadcast", this.getClass().getMethod("visitBroadcast", argsClasses)); + } catch (NoSuchMethodException e) { + throw new PushletException("Failed to setup SessionManagerVisitor", e); + } + } + + /** + * Return Visitor Method by name. + */ + public Method getMethod(String aName) { + return (Method) visitorMethods.get(aName); + + } + + /** + * Visitor method called by SessionManager. + */ + public void visitBroadcast(Session aSession, Event event) { + aSession.getSubscriber().onEvent((Event) event.clone()); + } + + /** + * Visitor method called by SessionManager. + */ + public void visitMulticast(Session aSession, Event event) { + Subscriber subscriber = aSession.getSubscriber(); + Event clonedEvent; + Subscription subscription; + + // Send only if the subscriber's criteria + // match the event. + if ((subscription = subscriber.match(event)) != null) { + // Personalize event + clonedEvent = (Event) event.clone(); + + // Set subscription id and optional label + clonedEvent.setField(P_SUBSCRIPTION_ID, subscription.getId()); + if (subscription.getLabel() != null) { + event.setField(P_SUBSCRIPTION_LABEL, subscription.getLabel()); + } + + subscriber.onEvent(clonedEvent); + } + } + } +} + +/* + * $Log: Dispatcher.java,v $ + * Revision 1.9 2007/12/04 13:55:53 justb + * reimplement SessionManager concurrency (prev version was not thread-safe!) + * + * Revision 1.8 2007/11/23 14:33:07 justb + * core classes now configurable through factory + * + * Revision 1.7 2005/02/28 12:45:59 justb + * introduced Command class + * + * Revision 1.6 2005/02/28 09:14:55 justb + * sessmgr/dispatcher factory/singleton support + * + * Revision 1.5 2005/02/21 16:59:06 justb + * SessionManager and session lease introduced + * + * Revision 1.4 2005/02/21 11:50:46 justb + * ohase1 of refactoring Subscriber into Session/Controller/Subscriber + * + * Revision 1.3 2005/02/18 12:36:47 justb + * changes for renaming and configurability + * + * Revision 1.2 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.1 2005/02/18 09:54:15 justb + * refactor: rename Publisher Dispatcher and single Subscriber class + * + * Revision 1.14 2005/02/16 14:39:34 justb + * fixed leave handling and added "poll" mode + * + * Revision 1.13 2004/10/24 20:50:35 justb + * refine subscription with label and sending sid and label on events + * + * Revision 1.12 2004/10/24 12:58:18 justb + * revised client and test classes for new protocol + * + * Revision 1.11 2004/09/26 21:39:43 justb + * allow multiple subscriptions and out-of-band requests + * + * Revision 1.10 2004/09/20 22:01:38 justb + * more changes for new protocol + * + * Revision 1.9 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.8 2004/08/13 23:36:05 justb + * rewrite of Pullet into Pushlet "pull" mode + * + * Revision 1.7 2004/08/12 13:18:54 justb + * cosmetic changes + * + * Revision 1.6 2004/03/10 15:45:55 justb + * many cosmetic changes + * + * Revision 1.5 2004/03/10 13:59:28 justb + * rewrite using Collection classes and finer synchronization + * + * Revision 1.4 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.3 2003/08/12 08:54:40 justb + * added getSubscriberCount() and use Log + * + * Revision 1.2 2003/05/18 16:15:08 justb + * support for XML encoded Events + * + * Revision 1.1.1.1 2002/09/24 21:02:31 justb + * import to sourceforge + * + * Revision 1.1.1.1 2002/09/20 22:48:18 justb + * import to SF + * + * Revision 1.1.1.1 2002/09/20 14:19:04 justb + * first import into SF + * + * Revision 1.3 2002/04/15 20:42:41 just + * reformatting and renaming GuardedQueue to EventQueue + * + * Revision 1.2 2000/08/21 20:48:29 just + * added CVS log and id tags plus copyrights + * + * + */ diff --git a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/Event.java b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/Event.java index e9a0aaa48b..b74d3c9bab 100644 --- a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/Event.java +++ b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/Event.java @@ -1,184 +1,184 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -import nl.justobjects.pushlet.util.Sys; - -import java.io.Serializable; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -/** - * Represents the event data. - * - * @author Just van den Broecke - Just Objects © - * @version $Id: Event.java,v 1.13 2007/11/23 14:33:07 justb Exp $ - */ -public class Event implements Protocol, Serializable { - - protected Map attributes = new HashMap(3); - - public Event(String anEventType) { - this(anEventType, null); - } - - public Event(String anEventType, Map theAttributes) { - - if (theAttributes != null) { - setAttrs(theAttributes); - } - - // Set required field event type - setField(P_EVENT, anEventType); - - // Set time in seconds since 1970 - setField(P_TIME, System.currentTimeMillis() / 1000); - } - - public Event(Map theAttributes) { - if (!theAttributes.containsKey(P_EVENT)) { - throw new IllegalArgumentException(P_EVENT + " not found in attributes"); - } - setAttrs(theAttributes); - } - - public static Event createDataEvent(String aSubject) { - return createDataEvent(aSubject, null); - } - - public static Event createDataEvent(String aSubject, Map theAttributes) { - Event dataEvent = new Event(E_DATA, theAttributes); - dataEvent.setField(P_SUBJECT, aSubject); - return dataEvent; - } - - public String getEventType() { - return getField(P_EVENT); - } - - public String getSubject() { - return getField(P_SUBJECT); - } - - public void setField(String name, String value) { - attributes.put(name, value); - } - - public void setField(String name, int value) { - attributes.put(name, value + ""); - } - - public void setField(String name, long value) { - attributes.put(name, value + ""); - } - - public String getField(String name) { - return (String) attributes.get(name); - } - - /** - * Return field; if null return default. - */ - public String getField(String name, String aDefault) { - String result = getField(name); - return result == null ? aDefault : result; - } - - public Iterator getFieldNames() { - return attributes.keySet().iterator(); - } - - public String toString() { - return attributes.toString(); - } - - /** - * Convert to HTTP query string. - */ - public String toQueryString() { - String queryString = ""; - String amp = ""; - for (Iterator iter = getFieldNames(); iter.hasNext();) { - String nextAttrName = (String) iter.next(); - String nextAttrValue = getField(nextAttrName); - queryString = queryString + amp + nextAttrName + "=" + nextAttrValue; - // After first add "&". - amp = "&"; - } - - return queryString; - } - - public String toXML(boolean strict) { - String xmlString = " +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +import nl.justobjects.pushlet.util.Sys; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * Represents the event data. + * + * @author Just van den Broecke - Just Objects © + * @version $Id: Event.java,v 1.13 2007/11/23 14:33:07 justb Exp $ + */ +public class Event implements Protocol, Serializable { + + protected Map attributes = new HashMap(3); + + public Event(String anEventType) { + this(anEventType, null); + } + + public Event(String anEventType, Map theAttributes) { + + if (theAttributes != null) { + setAttrs(theAttributes); + } + + // Set required field event type + setField(P_EVENT, anEventType); + + // Set time in seconds since 1970 + setField(P_TIME, System.currentTimeMillis() / 1000); + } + + public Event(Map theAttributes) { + if (!theAttributes.containsKey(P_EVENT)) { + throw new IllegalArgumentException(P_EVENT + " not found in attributes"); + } + setAttrs(theAttributes); + } + + public static Event createDataEvent(String aSubject) { + return createDataEvent(aSubject, null); + } + + public static Event createDataEvent(String aSubject, Map theAttributes) { + Event dataEvent = new Event(E_DATA, theAttributes); + dataEvent.setField(P_SUBJECT, aSubject); + return dataEvent; + } + + public String getEventType() { + return getField(P_EVENT); + } + + public String getSubject() { + return getField(P_SUBJECT); + } + + public void setField(String name, String value) { + attributes.put(name, value); + } + + public void setField(String name, int value) { + attributes.put(name, value + ""); + } + + public void setField(String name, long value) { + attributes.put(name, value + ""); + } + + public String getField(String name) { + return (String) attributes.get(name); + } + + /** + * Return field; if null return default. + */ + public String getField(String name, String aDefault) { + String result = getField(name); + return result == null ? aDefault : result; + } + + public Iterator getFieldNames() { + return attributes.keySet().iterator(); + } + + public String toString() { + return attributes.toString(); + } + + /** + * Convert to HTTP query string. + */ + public String toQueryString() { + String queryString = ""; + String amp = ""; + for (Iterator iter = getFieldNames(); iter.hasNext();) { + String nextAttrName = (String) iter.next(); + String nextAttrValue = getField(nextAttrName); + queryString = queryString + amp + nextAttrName + "=" + nextAttrValue; + // After first add "&". + amp = "&"; + } + + return queryString; + } + + public String toXML(boolean strict) { + String xmlString = " -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -import nl.justobjects.pushlet.util.Log; - -/** - * Abstract Event source from which Events are pulled. - * - * @version $Id: EventPullSource.java,v 1.15 2007/11/23 14:33:07 justb Exp $ - * @author Just van den Broecke - Just Objects © - **/ - -/** - * ABC for specifc EventPullSources. - */ -abstract public class EventPullSource implements EventSource, Runnable { - private volatile boolean alive = false; - private volatile boolean active = false; - private static int threadNum = 0; - private Thread thread; - - public EventPullSource() { - } - - abstract protected long getSleepTime(); - - abstract protected Event pullEvent(); - - public void start() { - thread = new Thread(this, "EventPullSource-" + (++threadNum)); - thread.setDaemon(true); - thread.start(); - } - - public boolean isAlive() { - return alive; - } - - /** - * Stop the event generator thread. - */ - public void stop() { - alive = false; - - if (thread != null) { - thread.interrupt(); - thread = null; - } - - } - - /** - * Activate the event generator thread. - */ - synchronized public void activate() { - if (active) { - return; - } - active = true; - if (!alive) { - start(); - return; - } - Log.debug(getClass().getName() + ": notifying..."); - notifyAll(); - } - - /** - * Deactivate the event generator thread. - */ - public void passivate() { - if (!active) { - return; - } - active = false; - } - - /** - * Main loop: sleep, generate event and publish. - */ - public void run() { - Log.debug(getClass().getName() + ": starting..."); - alive = true; - while (alive) { - try { - - Thread.sleep(getSleepTime()); - - // Stopped during sleep: end loop. - if (!alive) { - break; - } - - // If passivated wait until we get - // get notify()-ied. If there are no subscribers - // it wasts CPU to remain producing events... - synchronized (this) { - while (!active) { - Log.debug(getClass().getName() + ": waiting..."); - wait(); - } - } - - } catch (InterruptedException e) { - break; - } - - try { - // Derived class should produce an event. - Event event = pullEvent(); - - // Let the publisher push it to subscribers. - Dispatcher.getInstance().multicast(event); - } catch (Throwable t) { - Log.warn("EventPullSource exception while multicasting ", t); - t.printStackTrace(); - } - } - Log.debug(getClass().getName() + ": stopped"); - } -} - -/* - * $Log: EventPullSource.java,v $ - * Revision 1.15 2007/11/23 14:33:07 justb - * core classes now configurable through factory - * - * Revision 1.14 2005/02/28 09:14:55 justb - * sessmgr/dispatcher factory/singleton support - * - * Revision 1.13 2005/02/21 16:59:08 justb - * SessionManager and session lease introduced - * - * Revision 1.12 2005/02/21 11:50:46 justb - * ohase1 of refactoring Subscriber into Session/Controller/Subscriber - * - * Revision 1.11 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.10 2005/02/18 09:54:15 justb - * refactor: rename Publisher Dispatcher and single Subscriber class - * - * Revision 1.9 2004/09/20 22:01:38 justb - * more changes for new protocol - * - * Revision 1.8 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.7 2004/08/15 16:00:15 justb - * enhancements to pull mode - * - * Revision 1.6 2004/08/13 23:36:05 justb - * rewrite of Pullet into Pushlet "pull" mode - * - * Revision 1.5 2004/03/10 14:01:55 justb - * formatting and *Subscriber refactoring - * - * Revision 1.4 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.3 2003/08/12 09:57:05 justb - * replaced all print statements to Log.*() calls - * - * Revision 1.2 2003/05/18 16:15:08 justb - * support for XML encoded Events - * - * Revision 1.1.1.1 2002/09/24 21:02:31 justb - * import to sourceforge - * - * Revision 1.1.1.1 2002/09/20 22:48:17 justb - * import to SF - * - * Revision 1.1.1.1 2002/09/20 14:19:03 justb - * first import into SF - * - * Revision 1.3 2002/04/15 20:42:41 just - * reformatting and renaming GuardedQueue to EventQueue - * - * Revision 1.2 2000/08/21 20:48:29 just - * added CVS log and id tags plus copyrights - * - * - */ +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +import nl.justobjects.pushlet.util.Log; + +/** + * Abstract Event source from which Events are pulled. + * + * @version $Id: EventPullSource.java,v 1.15 2007/11/23 14:33:07 justb Exp $ + * @author Just van den Broecke - Just Objects © + **/ + +/** + * ABC for specifc EventPullSources. + */ +abstract public class EventPullSource implements EventSource, Runnable { + private volatile boolean alive = false; + private volatile boolean active = false; + private static int threadNum = 0; + private Thread thread; + + public EventPullSource() { + } + + abstract protected long getSleepTime(); + + abstract protected Event pullEvent(); + + public void start() { + thread = new Thread(this, "EventPullSource-" + (++threadNum)); + thread.setDaemon(true); + thread.start(); + } + + public boolean isAlive() { + return alive; + } + + /** + * Stop the event generator thread. + */ + public void stop() { + alive = false; + + if (thread != null) { + thread.interrupt(); + thread = null; + } + + } + + /** + * Activate the event generator thread. + */ + synchronized public void activate() { + if (active) { + return; + } + active = true; + if (!alive) { + start(); + return; + } + Log.debug(getClass().getName() + ": notifying..."); + notifyAll(); + } + + /** + * Deactivate the event generator thread. + */ + public void passivate() { + if (!active) { + return; + } + active = false; + } + + /** + * Main loop: sleep, generate event and publish. + */ + public void run() { + Log.debug(getClass().getName() + ": starting..."); + alive = true; + while (alive) { + try { + + Thread.sleep(getSleepTime()); + + // Stopped during sleep: end loop. + if (!alive) { + break; + } + + // If passivated wait until we get + // get notify()-ied. If there are no subscribers + // it wasts CPU to remain producing events... + synchronized (this) { + while (!active) { + Log.debug(getClass().getName() + ": waiting..."); + wait(); + } + } + + } catch (InterruptedException e) { + break; + } + + try { + // Derived class should produce an event. + Event event = pullEvent(); + + // Let the publisher push it to subscribers. + Dispatcher.getInstance().multicast(event); + } catch (Throwable t) { + Log.warn("EventPullSource exception while multicasting ", t); + t.printStackTrace(); + } + } + Log.debug(getClass().getName() + ": stopped"); + } +} + +/* + * $Log: EventPullSource.java,v $ + * Revision 1.15 2007/11/23 14:33:07 justb + * core classes now configurable through factory + * + * Revision 1.14 2005/02/28 09:14:55 justb + * sessmgr/dispatcher factory/singleton support + * + * Revision 1.13 2005/02/21 16:59:08 justb + * SessionManager and session lease introduced + * + * Revision 1.12 2005/02/21 11:50:46 justb + * ohase1 of refactoring Subscriber into Session/Controller/Subscriber + * + * Revision 1.11 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.10 2005/02/18 09:54:15 justb + * refactor: rename Publisher Dispatcher and single Subscriber class + * + * Revision 1.9 2004/09/20 22:01:38 justb + * more changes for new protocol + * + * Revision 1.8 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.7 2004/08/15 16:00:15 justb + * enhancements to pull mode + * + * Revision 1.6 2004/08/13 23:36:05 justb + * rewrite of Pullet into Pushlet "pull" mode + * + * Revision 1.5 2004/03/10 14:01:55 justb + * formatting and *Subscriber refactoring + * + * Revision 1.4 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.3 2003/08/12 09:57:05 justb + * replaced all print statements to Log.*() calls + * + * Revision 1.2 2003/05/18 16:15:08 justb + * support for XML encoded Events + * + * Revision 1.1.1.1 2002/09/24 21:02:31 justb + * import to sourceforge + * + * Revision 1.1.1.1 2002/09/20 22:48:17 justb + * import to SF + * + * Revision 1.1.1.1 2002/09/20 14:19:03 justb + * first import into SF + * + * Revision 1.3 2002/04/15 20:42:41 just + * reformatting and renaming GuardedQueue to EventQueue + * + * Revision 1.2 2000/08/21 20:48:29 just + * added CVS log and id tags plus copyrights + * + * + */ diff --git a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/EventQueue.java b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/EventQueue.java index 85c730e2d7..18fd52318d 100644 --- a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/EventQueue.java +++ b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/EventQueue.java @@ -1,269 +1,269 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -/** - * FIFO queue with guarded suspension. - * Purpose
- *

- * Implementation
- * FIFO queue class implemented with circular array. The enQueue() and - * deQueue() methods use guarded suspension according to a readers/writers - * pattern, implemented with java.lang.Object.wait()/notify(). - *

- * Examples
- *

- *
- * - * @author Just van den Broecke - Just Objects © - * @version $Id: EventQueue.java,v 1.3 2007/11/23 14:33:07 justb Exp $ - */ -public class EventQueue { - /** - * Defines maximum queue size - */ - private int capacity = 8; - private Event[] queue = null; - private int front, rear; - - /** - * Construct queue with default (8) capacity. - */ - public EventQueue() { - this(8); - } - - /** - * Construct queue with specified capacity. - */ - public EventQueue(int capacity) { - this.capacity = capacity; - queue = new Event[capacity]; - front = rear = 0; - } - - /** - * Put item in queue; waits() indefinitely if queue is full. - */ - public synchronized boolean enQueue(Event item) throws InterruptedException { - return enQueue(item, -1); - } - - /** - * Put item in queue; if full wait maxtime. - */ - public synchronized boolean enQueue(Event item, long maxWaitTime) throws InterruptedException { - - // Wait (optional maxtime) as long as the queue is full - while (isFull()) { - if (maxWaitTime > 0) { - // Wait at most maximum time - wait(maxWaitTime); - - // Timed out or woken; if still full we - // had bad luck and return failure. - if (isFull()) { - return false; - } - } else { - wait(); - } - } - - // Put item in queue - queue[rear] = item; - rear = next(rear); - - // Wake up waiters; NOTE: first waiter will eat item - notifyAll(); - return true; - } - - /** - * Get head; if empty wait until something in queue. - */ - public synchronized Event deQueue() throws InterruptedException { - return deQueue(-1); - } - - /** - * Get head; if empty wait for specified time at max. - */ - public synchronized Event deQueue(long maxWaitTime) throws InterruptedException { - while (isEmpty()) { - if (maxWaitTime >= 0) { - wait(maxWaitTime); - - // Timed out or woken; if still empty we - // had bad luck and return failure. - if (isEmpty()) { - return null; - } - } else { - // Wait indefinitely for something in queue. - wait(); - } - } - - // Dequeue item - Event result = fetchNext(); - - // Notify possible wait()-ing enQueue()-ers - notifyAll(); - - // Return dequeued item - return result; - } - - /** - * Get all queued Events. - */ - public synchronized Event[] deQueueAll(long maxWaitTime) throws InterruptedException { - while (isEmpty()) { - if (maxWaitTime >= 0) { - wait(maxWaitTime); - - // Timed out or woken; if still empty we - // had bad luck and return failure. - if (isEmpty()) { - return null; - } - } else { - // Wait indefinitely for something in queue. - wait(); - } - } - - // Dequeue all items item - Event[] events = new Event[getSize()]; - for (int i = 0; i < events.length; i++) { - events[i] = fetchNext(); - } - - // Notify possible wait()-ing enQueue()-ers - notifyAll(); - - // Return dequeued item - return events; - } - - public synchronized int getSize() { - return (rear >= front) ? (rear - front) : (capacity - front + rear); - } - - /** - * Is the queue empty ? - */ - public synchronized boolean isEmpty() { - return front == rear; - } - - /** - * Is the queue full ? - */ - public synchronized boolean isFull() { - return (next(rear) == front); - } - - /** - * Circular counter. - */ - private int next(int index) { - return (index + 1 < capacity ? index + 1 : 0); - } - - /** - * Circular counter. - */ - private Event fetchNext() { - Event temp = queue[front]; - queue[front] = null; - front = next(front); - return temp; - } - - public static void p(String s) { - System.out.println(s); - } - - public static void main(String[] args) { - EventQueue q = new EventQueue(8); - Event event = new Event("t"); - try { - q.enQueue(event); - p("(1) size = " + q.getSize()); - q.enQueue(event); - p("(2) size = " + q.getSize()); - q.deQueue(); - p("(1) size = " + q.getSize()); - q.deQueue(); - p("(0) size = " + q.getSize()); - - q.enQueue(event); - q.enQueue(event); - q.enQueue(event); - p("(3) size = " + q.getSize()); - q.deQueue(); - p("(2) size = " + q.getSize()); - q.enQueue(event); - q.enQueue(event); - q.enQueue(event); - p("(5) size = " + q.getSize()); - q.enQueue(event); - q.enQueue(event); - p("(7) size = " + q.getSize()); - q.deQueue(); - q.deQueue(); - q.deQueue(); - p("(4) size = " + q.getSize()); - q.deQueue(); - q.deQueue(); - q.deQueue(); - ; - q.deQueue(); - p("(0) size = " + q.getSize()); - - q.enQueue(event); - q.enQueue(event); - q.enQueue(event); - q.enQueue(event); - q.enQueue(event); - p("(5) size = " + q.getSize()); - - q.deQueue(); - q.deQueue(); - q.deQueue(); - ; - q.deQueue(); - p("(1) size = " + q.getSize()); - } catch (InterruptedException ie) { - } - } -} - -/* -* $Log: EventQueue.java,v $ -* Revision 1.3 2007/11/23 14:33:07 justb -* core classes now configurable through factory -* -* Revision 1.2 2005/02/21 11:50:46 justb -* ohase1 of refactoring Subscriber into Session/Controller/Subscriber -* -* Revision 1.1 2005/02/18 10:07:23 justb -* many renamings of classes (make names compact) -* -* Revision 1.6 2005/02/16 12:16:16 justb -* added support for "poll" mode -* -* Revision 1.5 2005/01/13 14:47:15 justb -* control evt: send response on same (control) connection -* -* Revision 1.4 2004/09/03 22:35:37 justb -* Almost complete rewrite, just checking in now -* -* Revision 1.3 2003/08/15 08:37:40 justb -* fix/add Copyright+LGPL file headers and footers -* -* -*/ +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +/** + * FIFO queue with guarded suspension. + * Purpose
+ *

+ * Implementation
+ * FIFO queue class implemented with circular array. The enQueue() and + * deQueue() methods use guarded suspension according to a readers/writers + * pattern, implemented with java.lang.Object.wait()/notify(). + *

+ * Examples
+ *

+ *
+ * + * @author Just van den Broecke - Just Objects © + * @version $Id: EventQueue.java,v 1.3 2007/11/23 14:33:07 justb Exp $ + */ +public class EventQueue { + /** + * Defines maximum queue size + */ + private int capacity = 8; + private Event[] queue = null; + private int front, rear; + + /** + * Construct queue with default (8) capacity. + */ + public EventQueue() { + this(8); + } + + /** + * Construct queue with specified capacity. + */ + public EventQueue(int capacity) { + this.capacity = capacity; + queue = new Event[capacity]; + front = rear = 0; + } + + /** + * Put item in queue; waits() indefinitely if queue is full. + */ + public synchronized boolean enQueue(Event item) throws InterruptedException { + return enQueue(item, -1); + } + + /** + * Put item in queue; if full wait maxtime. + */ + public synchronized boolean enQueue(Event item, long maxWaitTime) throws InterruptedException { + + // Wait (optional maxtime) as long as the queue is full + while (isFull()) { + if (maxWaitTime > 0) { + // Wait at most maximum time + wait(maxWaitTime); + + // Timed out or woken; if still full we + // had bad luck and return failure. + if (isFull()) { + return false; + } + } else { + wait(); + } + } + + // Put item in queue + queue[rear] = item; + rear = next(rear); + + // Wake up waiters; NOTE: first waiter will eat item + notifyAll(); + return true; + } + + /** + * Get head; if empty wait until something in queue. + */ + public synchronized Event deQueue() throws InterruptedException { + return deQueue(-1); + } + + /** + * Get head; if empty wait for specified time at max. + */ + public synchronized Event deQueue(long maxWaitTime) throws InterruptedException { + while (isEmpty()) { + if (maxWaitTime >= 0) { + wait(maxWaitTime); + + // Timed out or woken; if still empty we + // had bad luck and return failure. + if (isEmpty()) { + return null; + } + } else { + // Wait indefinitely for something in queue. + wait(); + } + } + + // Dequeue item + Event result = fetchNext(); + + // Notify possible wait()-ing enQueue()-ers + notifyAll(); + + // Return dequeued item + return result; + } + + /** + * Get all queued Events. + */ + public synchronized Event[] deQueueAll(long maxWaitTime) throws InterruptedException { + while (isEmpty()) { + if (maxWaitTime >= 0) { + wait(maxWaitTime); + + // Timed out or woken; if still empty we + // had bad luck and return failure. + if (isEmpty()) { + return null; + } + } else { + // Wait indefinitely for something in queue. + wait(); + } + } + + // Dequeue all items item + Event[] events = new Event[getSize()]; + for (int i = 0; i < events.length; i++) { + events[i] = fetchNext(); + } + + // Notify possible wait()-ing enQueue()-ers + notifyAll(); + + // Return dequeued item + return events; + } + + public synchronized int getSize() { + return (rear >= front) ? (rear - front) : (capacity - front + rear); + } + + /** + * Is the queue empty ? + */ + public synchronized boolean isEmpty() { + return front == rear; + } + + /** + * Is the queue full ? + */ + public synchronized boolean isFull() { + return (next(rear) == front); + } + + /** + * Circular counter. + */ + private int next(int index) { + return (index + 1 < capacity ? index + 1 : 0); + } + + /** + * Circular counter. + */ + private Event fetchNext() { + Event temp = queue[front]; + queue[front] = null; + front = next(front); + return temp; + } + + public static void p(String s) { + System.out.println(s); + } + + public static void main(String[] args) { + EventQueue q = new EventQueue(8); + Event event = new Event("t"); + try { + q.enQueue(event); + p("(1) size = " + q.getSize()); + q.enQueue(event); + p("(2) size = " + q.getSize()); + q.deQueue(); + p("(1) size = " + q.getSize()); + q.deQueue(); + p("(0) size = " + q.getSize()); + + q.enQueue(event); + q.enQueue(event); + q.enQueue(event); + p("(3) size = " + q.getSize()); + q.deQueue(); + p("(2) size = " + q.getSize()); + q.enQueue(event); + q.enQueue(event); + q.enQueue(event); + p("(5) size = " + q.getSize()); + q.enQueue(event); + q.enQueue(event); + p("(7) size = " + q.getSize()); + q.deQueue(); + q.deQueue(); + q.deQueue(); + p("(4) size = " + q.getSize()); + q.deQueue(); + q.deQueue(); + q.deQueue(); + ; + q.deQueue(); + p("(0) size = " + q.getSize()); + + q.enQueue(event); + q.enQueue(event); + q.enQueue(event); + q.enQueue(event); + q.enQueue(event); + p("(5) size = " + q.getSize()); + + q.deQueue(); + q.deQueue(); + q.deQueue(); + ; + q.deQueue(); + p("(1) size = " + q.getSize()); + } catch (InterruptedException ie) { + } + } +} + +/* +* $Log: EventQueue.java,v $ +* Revision 1.3 2007/11/23 14:33:07 justb +* core classes now configurable through factory +* +* Revision 1.2 2005/02/21 11:50:46 justb +* ohase1 of refactoring Subscriber into Session/Controller/Subscriber +* +* Revision 1.1 2005/02/18 10:07:23 justb +* many renamings of classes (make names compact) +* +* Revision 1.6 2005/02/16 12:16:16 justb +* added support for "poll" mode +* +* Revision 1.5 2005/01/13 14:47:15 justb +* control evt: send response on same (control) connection +* +* Revision 1.4 2004/09/03 22:35:37 justb +* Almost complete rewrite, just checking in now +* +* Revision 1.3 2003/08/15 08:37:40 justb +* fix/add Copyright+LGPL file headers and footers +* +* +*/ diff --git a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/EventSource.java b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/EventSource.java index 1de0c4a985..0975bde10e 100644 --- a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/EventSource.java +++ b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/EventSource.java @@ -1,79 +1,79 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -import javax.servlet.ServletContext; - -/** - * Abstract Event source from which Events are pulled. - * - * @version $Id: EventSource.java,v 1.7 2007/11/23 14:33:07 justb Exp $ - * @author Just van den Broecke - Just Objects © - **/ - -/** - * Interface for specifc Event(Pull/Push)Sources. - */ -public interface EventSource { - /** - * Activate the event source. - */ - public void activate(); - - /** - * Deactivate the event source. - */ - public void passivate(); - - /** - * Halt the event source. - */ - public void stop(); - - /** - * @author thomas genin - * gives access to the servlet context of pushlet to the source class - */ - public void setServletContext(ServletContext srvCtxt); - -} - -/* - * $Log: EventSource.java,v $ - * Revision 1.7 2007/11/23 14:33:07 justb - * core classes now configurable through factory - * - * Revision 1.6 2005/02/21 11:50:46 justb - * ohase1 of refactoring Subscriber into Session/Controller/Subscriber - * - * Revision 1.5 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.4 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.3 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.2 2003/05/18 16:15:08 justb - * support for XML encoded Events - * - * Revision 1.1.1.1 2002/09/24 21:02:31 justb - * import to sourceforge - * - * Revision 1.1.1.1 2002/09/20 22:48:17 justb - * import to SF - * - * Revision 1.1.1.1 2002/09/20 14:19:03 justb - * first import into SF - * - * Revision 1.3 2002/04/15 20:42:41 just - * reformatting and renaming GuardedQueue to EventQueue - * - * Revision 1.2 2000/08/21 20:48:29 just - * added CVS log and id tags plus copyrights - * - * - */ - +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +import javax.servlet.ServletContext; + +/** + * Abstract Event source from which Events are pulled. + * + * @version $Id: EventSource.java,v 1.7 2007/11/23 14:33:07 justb Exp $ + * @author Just van den Broecke - Just Objects © + **/ + +/** + * Interface for specifc Event(Pull/Push)Sources. + */ +public interface EventSource { + /** + * Activate the event source. + */ + public void activate(); + + /** + * Deactivate the event source. + */ + public void passivate(); + + /** + * Halt the event source. + */ + public void stop(); + + /** + * @author thomas genin + * gives access to the servlet context of pushlet to the source class + */ + public void setServletContext(ServletContext srvCtxt); + +} + +/* + * $Log: EventSource.java,v $ + * Revision 1.7 2007/11/23 14:33:07 justb + * core classes now configurable through factory + * + * Revision 1.6 2005/02/21 11:50:46 justb + * ohase1 of refactoring Subscriber into Session/Controller/Subscriber + * + * Revision 1.5 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.4 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.3 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.2 2003/05/18 16:15:08 justb + * support for XML encoded Events + * + * Revision 1.1.1.1 2002/09/24 21:02:31 justb + * import to sourceforge + * + * Revision 1.1.1.1 2002/09/20 22:48:17 justb + * import to SF + * + * Revision 1.1.1.1 2002/09/20 14:19:03 justb + * first import into SF + * + * Revision 1.3 2002/04/15 20:42:41 just + * reformatting and renaming GuardedQueue to EventQueue + * + * Revision 1.2 2000/08/21 20:48:29 just + * added CVS log and id tags plus copyrights + * + * + */ + diff --git a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/EventSourceManager.java b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/EventSourceManager.java index 472b4290cc..119c95fb58 100644 --- a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/EventSourceManager.java +++ b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/EventSourceManager.java @@ -1,175 +1,175 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -import nl.justobjects.pushlet.util.Log; -import nl.justobjects.pushlet.util.Sys; - -import java.util.Enumeration; -import java.util.Properties; -import java.util.Vector; -import java.io.File; - -import javax.servlet.ServletContext; - -/** - * Maintains lifecycle of event sources. - * - * @author Just van den Broecke - Just Objects © - * @version $Id: EventSourceManager.java,v 1.14 2007/11/10 13:44:02 justb Exp $ - */ -public class EventSourceManager { - private static Vector eventSources = new Vector(0); - private static final String PROPERTIES_FILE = "sources.properties"; - - /** - * Initialize event sources from properties file. - */ - public static void start(String aDirPath,ServletContext srvCtxt) { - // Load Event sources using properties file. - Log.info("EventSourceManager: start"); - - Properties properties = null; - - try { - properties = Sys.loadPropertiesResource(PROPERTIES_FILE); - } catch (Throwable t) { - // Try from provided dir (e.g. WEB_INF/pushlet.properties) - String filePath = aDirPath + File.separator + PROPERTIES_FILE; - Log.info("EventSourceManager: cannot load " + PROPERTIES_FILE + " from classpath, will try from " + filePath); - - try { - properties = Sys.loadPropertiesFile(filePath); - } catch (Throwable t2) { - Log.fatal("EventSourceManager: cannot load properties file from " + filePath, t); - - // Give up - Log.warn("EventSourceManager: not starting local event sources (maybe that is what you want)"); - return; - } - } - - // Create event source collection - eventSources = new Vector(properties.size()); - - // Add the configured sources - for (Enumeration e = properties.keys(); e.hasMoreElements();) { - String nextKey = (String) e.nextElement(); - String nextClass = properties.getProperty(nextKey); - EventSource nextEventSource = null; - try { - nextEventSource = (EventSource) Class.forName(nextClass).newInstance(); - //rajout thomas genin - nextEventSource.setServletContext(srvCtxt); - ////////////////////// - Log.info("created EventSource: key=" + nextKey + " class=" + nextClass); - eventSources.addElement(nextEventSource); - - } catch (Exception ex) { - Log.warn("Cannot create EventSource: class=" + nextClass, ex); - } - } - - activate(); - } - - /** - * Activate all event sources. - */ - public static void activate() { - Log.info("Activating " + eventSources.size() + " EventSources"); - for (int i = 0; i < eventSources.size(); i++) { - ((EventSource) eventSources.elementAt(i)).activate(); - } - Log.info("EventSources activated"); - } - - /** - * Deactivate all event sources. - */ - public static void passivate() { - Log.info("Passivating " + eventSources.size() + " EventSources"); - for (int i = 0; i < eventSources.size(); i++) { - ((EventSource) eventSources.elementAt(i)).passivate(); - } - Log.info("EventSources passivated"); - } - - /** - * Halt event sources. - */ - public static void stop() { - Log.info("Stopping " + eventSources.size() + " EventSources..."); - for (int i = 0; i < eventSources.size(); i++) { - ((EventSource) eventSources.elementAt(i)).stop(); - } - Log.info("EventSources stopped"); - } - -} - -/* - * $Log: EventSourceManager.java,v $ - * Revision 1.14 2007/11/10 13:44:02 justb - * pushlet.properties and sources.properties can now also be put under WEB-INF - * - * Revision 1.13 2005/02/21 11:50:46 justb - * ohase1 of refactoring Subscriber into Session/Controller/Subscriber - * - * Revision 1.12 2005/02/18 12:36:47 justb - * changes for renaming and configurability - * - * Revision 1.11 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.10 2005/02/15 13:29:49 justb - * use Sys.loadPropertiesResource() - * - * Revision 1.9 2004/09/20 22:01:38 justb - * more changes for new protocol - * - * Revision 1.8 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.7 2004/08/15 16:00:15 justb - * enhancements to pull mode - * - * Revision 1.6 2004/08/13 23:36:05 justb - * rewrite of Pullet into Pushlet "pull" mode - * - * Revision 1.5 2004/08/12 13:18:54 justb - * cosmetic changes - * - * Revision 1.4 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.3 2003/08/12 09:41:35 justb - * replace static initalizer with explicit init() - * - * Revision 1.2 2003/05/18 16:15:08 justb - * support for XML encoded Events - * - * Revision 1.1.1.1 2002/09/24 21:02:31 justb - * import to sourceforge - * - * Revision 1.1.1.1 2002/09/20 22:48:17 justb - * import to SF - * - * Revision 1.1.1.1 2002/09/20 14:19:03 justb - * first import into SF - * - * Revision 1.5 2002/04/15 20:42:41 just - * reformatting and renaming GuardedQueue to EventQueue - * - * Revision 1.4 2000/10/30 14:15:47 just - * no message - * - * Revision 1.3 2000/08/31 08:26:54 just - * Changed classloader that loads eventsources.properties to use EventSourceManager's classloader - * - * Revision 1.2 2000/08/21 20:48:29 just - * added CVS log and id tags plus copyrights - * - * - */ +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +import nl.justobjects.pushlet.util.Log; +import nl.justobjects.pushlet.util.Sys; + +import java.util.Enumeration; +import java.util.Properties; +import java.util.Vector; +import java.io.File; + +import javax.servlet.ServletContext; + +/** + * Maintains lifecycle of event sources. + * + * @author Just van den Broecke - Just Objects © + * @version $Id: EventSourceManager.java,v 1.14 2007/11/10 13:44:02 justb Exp $ + */ +public class EventSourceManager { + private static Vector eventSources = new Vector(0); + private static final String PROPERTIES_FILE = "sources.properties"; + + /** + * Initialize event sources from properties file. + */ + public static void start(String aDirPath,ServletContext srvCtxt) { + // Load Event sources using properties file. + Log.info("EventSourceManager: start"); + + Properties properties = null; + + try { + properties = Sys.loadPropertiesResource(PROPERTIES_FILE); + } catch (Throwable t) { + // Try from provided dir (e.g. WEB_INF/pushlet.properties) + String filePath = aDirPath + File.separator + PROPERTIES_FILE; + Log.info("EventSourceManager: cannot load " + PROPERTIES_FILE + " from classpath, will try from " + filePath); + + try { + properties = Sys.loadPropertiesFile(filePath); + } catch (Throwable t2) { + Log.fatal("EventSourceManager: cannot load properties file from " + filePath, t); + + // Give up + Log.warn("EventSourceManager: not starting local event sources (maybe that is what you want)"); + return; + } + } + + // Create event source collection + eventSources = new Vector(properties.size()); + + // Add the configured sources + for (Enumeration e = properties.keys(); e.hasMoreElements();) { + String nextKey = (String) e.nextElement(); + String nextClass = properties.getProperty(nextKey); + EventSource nextEventSource = null; + try { + nextEventSource = (EventSource) Class.forName(nextClass).newInstance(); + //rajout thomas genin + nextEventSource.setServletContext(srvCtxt); + ////////////////////// + Log.info("created EventSource: key=" + nextKey + " class=" + nextClass); + eventSources.addElement(nextEventSource); + + } catch (Exception ex) { + Log.warn("Cannot create EventSource: class=" + nextClass, ex); + } + } + + activate(); + } + + /** + * Activate all event sources. + */ + public static void activate() { + Log.info("Activating " + eventSources.size() + " EventSources"); + for (int i = 0; i < eventSources.size(); i++) { + ((EventSource) eventSources.elementAt(i)).activate(); + } + Log.info("EventSources activated"); + } + + /** + * Deactivate all event sources. + */ + public static void passivate() { + Log.info("Passivating " + eventSources.size() + " EventSources"); + for (int i = 0; i < eventSources.size(); i++) { + ((EventSource) eventSources.elementAt(i)).passivate(); + } + Log.info("EventSources passivated"); + } + + /** + * Halt event sources. + */ + public static void stop() { + Log.info("Stopping " + eventSources.size() + " EventSources..."); + for (int i = 0; i < eventSources.size(); i++) { + ((EventSource) eventSources.elementAt(i)).stop(); + } + Log.info("EventSources stopped"); + } + +} + +/* + * $Log: EventSourceManager.java,v $ + * Revision 1.14 2007/11/10 13:44:02 justb + * pushlet.properties and sources.properties can now also be put under WEB-INF + * + * Revision 1.13 2005/02/21 11:50:46 justb + * ohase1 of refactoring Subscriber into Session/Controller/Subscriber + * + * Revision 1.12 2005/02/18 12:36:47 justb + * changes for renaming and configurability + * + * Revision 1.11 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.10 2005/02/15 13:29:49 justb + * use Sys.loadPropertiesResource() + * + * Revision 1.9 2004/09/20 22:01:38 justb + * more changes for new protocol + * + * Revision 1.8 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.7 2004/08/15 16:00:15 justb + * enhancements to pull mode + * + * Revision 1.6 2004/08/13 23:36:05 justb + * rewrite of Pullet into Pushlet "pull" mode + * + * Revision 1.5 2004/08/12 13:18:54 justb + * cosmetic changes + * + * Revision 1.4 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.3 2003/08/12 09:41:35 justb + * replace static initalizer with explicit init() + * + * Revision 1.2 2003/05/18 16:15:08 justb + * support for XML encoded Events + * + * Revision 1.1.1.1 2002/09/24 21:02:31 justb + * import to sourceforge + * + * Revision 1.1.1.1 2002/09/20 22:48:17 justb + * import to SF + * + * Revision 1.1.1.1 2002/09/20 14:19:03 justb + * first import into SF + * + * Revision 1.5 2002/04/15 20:42:41 just + * reformatting and renaming GuardedQueue to EventQueue + * + * Revision 1.4 2000/10/30 14:15:47 just + * no message + * + * Revision 1.3 2000/08/31 08:26:54 just + * Changed classloader that loads eventsources.properties to use EventSourceManager's classloader + * + * Revision 1.2 2000/08/21 20:48:29 just + * added CVS log and id tags plus copyrights + * + * + */ diff --git a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/SerializedAdapter.java b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/SerializedAdapter.java index 462a4dd5c2..501a6ba3ce 100644 --- a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/SerializedAdapter.java +++ b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/SerializedAdapter.java @@ -1,99 +1,99 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.ObjectOutputStream; - -/** - * Implementation of ClientAdapter that sends Events as serialized objects. - *

- * NOTE: You are discouraged to use this adapter, since it is Java-only - * and may have JVM-specific problems. Far better choice is to use XML - * and the XMLAdapter. - * - * @author Just van den Broecke - Just Objects © - * @version $Id: SerializedAdapter.java,v 1.4 2007/11/23 14:33:07 justb Exp $ - */ -class SerializedAdapter implements ClientAdapter { - private ObjectOutputStream out = null; - public static final String CONTENT_TYPE = "application/x-java-serialized-object"; - private HttpServletResponse servletRsp; - - /** - * Initialize. - */ - public SerializedAdapter(HttpServletResponse aServletResponse) { - servletRsp = aServletResponse; - } - - public void start() throws IOException { - - servletRsp.setContentType(CONTENT_TYPE); - - // Use a serialized object output stream - out = new ObjectOutputStream(servletRsp.getOutputStream()); - - // Don't need this further - servletRsp = null; - } - - /** - * Push Event to client. - */ - public void push(Event anEvent) throws IOException { - out.writeObject(anEvent); - - out.flush(); - } - - - public void stop() throws IOException { - } -} - -/* - * $Log: SerializedAdapter.java,v $ - * Revision 1.4 2007/11/23 14:33:07 justb - * core classes now configurable through factory - * - * Revision 1.3 2005/02/28 12:45:59 justb - * introduced Command class - * - * Revision 1.2 2005/02/21 11:50:46 justb - * ohase1 of refactoring Subscriber into Session/Controller/Subscriber - * - * Revision 1.1 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.4 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.3 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.2 2003/05/18 16:13:48 justb - * fixed blocking for java.net.URL with HTTP/1.1 (JVMs > 1.1) - * - * Revision 1.1.1.1 2002/09/24 21:02:31 justb - * import to sourceforge - * - * Revision 1.1.1.1 2002/09/20 22:48:18 justb - * import to SF - * - * Revision 1.1.1.1 2002/09/20 14:19:03 justb - * first import into SF - * - * Revision 1.5 2002/04/15 20:42:41 just - * reformatting and renaming GuardedQueue to EventQueue - * - * Revision 1.4 2000/12/27 22:39:35 just - * no message - * - * Revision 1.3 2000/08/21 20:48:29 just - * added CVS log and id tags plus copyrights - * - * - */ +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.ObjectOutputStream; + +/** + * Implementation of ClientAdapter that sends Events as serialized objects. + *

+ * NOTE: You are discouraged to use this adapter, since it is Java-only + * and may have JVM-specific problems. Far better choice is to use XML + * and the XMLAdapter. + * + * @author Just van den Broecke - Just Objects © + * @version $Id: SerializedAdapter.java,v 1.4 2007/11/23 14:33:07 justb Exp $ + */ +class SerializedAdapter implements ClientAdapter { + private ObjectOutputStream out = null; + public static final String CONTENT_TYPE = "application/x-java-serialized-object"; + private HttpServletResponse servletRsp; + + /** + * Initialize. + */ + public SerializedAdapter(HttpServletResponse aServletResponse) { + servletRsp = aServletResponse; + } + + public void start() throws IOException { + + servletRsp.setContentType(CONTENT_TYPE); + + // Use a serialized object output stream + out = new ObjectOutputStream(servletRsp.getOutputStream()); + + // Don't need this further + servletRsp = null; + } + + /** + * Push Event to client. + */ + public void push(Event anEvent) throws IOException { + out.writeObject(anEvent); + + out.flush(); + } + + + public void stop() throws IOException { + } +} + +/* + * $Log: SerializedAdapter.java,v $ + * Revision 1.4 2007/11/23 14:33:07 justb + * core classes now configurable through factory + * + * Revision 1.3 2005/02/28 12:45:59 justb + * introduced Command class + * + * Revision 1.2 2005/02/21 11:50:46 justb + * ohase1 of refactoring Subscriber into Session/Controller/Subscriber + * + * Revision 1.1 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.4 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.3 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.2 2003/05/18 16:13:48 justb + * fixed blocking for java.net.URL with HTTP/1.1 (JVMs > 1.1) + * + * Revision 1.1.1.1 2002/09/24 21:02:31 justb + * import to sourceforge + * + * Revision 1.1.1.1 2002/09/20 22:48:18 justb + * import to SF + * + * Revision 1.1.1.1 2002/09/20 14:19:03 justb + * first import into SF + * + * Revision 1.5 2002/04/15 20:42:41 just + * reformatting and renaming GuardedQueue to EventQueue + * + * Revision 1.4 2000/12/27 22:39:35 just + * no message + * + * Revision 1.3 2000/08/21 20:48:29 just + * added CVS log and id tags plus copyrights + * + * + */ diff --git a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/Subscriber.java b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/Subscriber.java index 39f5ba0198..dca30b6bfd 100644 --- a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/Subscriber.java +++ b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/Subscriber.java @@ -1,469 +1,469 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -import nl.justobjects.pushlet.util.PushletException; -import nl.justobjects.pushlet.util.Rand; -import nl.justobjects.pushlet.util.Sys; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.net.URLEncoder; - -/** - * Handles data channel between dispatcher and client. - * - * @author Just van den Broecke - Just Objects © - * @version $Id: Subscriber.java,v 1.26 2007/11/23 14:33:07 justb Exp $ - */ -public class Subscriber implements Protocol, ConfigDefs { - private Session session; - - /** - * Blocking queue. - */ - private EventQueue eventQueue = new EventQueue(Config.getIntProperty(QUEUE_SIZE)); - - /** - * URL to be used in refresh requests in pull/poll modes. - */ - private long queueReadTimeoutMillis = Config.getLongProperty(QUEUE_READ_TIMEOUT_MILLIS); - private long queueWriteTimeoutMillis = Config.getLongProperty(QUEUE_WRITE_TIMEOUT_MILLIS); - private long refreshTimeoutMillis = Config.getLongProperty(PULL_REFRESH_TIMEOUT_MILLIS); - volatile long lastAlive = Sys.now(); - - /** - * Map of active subscriptions, keyed by their subscription id. - */ - private Map subscriptions = Collections.synchronizedMap(new HashMap(3)); - - /** - * Are we able to accept/send events ?. - */ - private volatile boolean active; - - /** - * Transfer mode (stream, pull, poll). - */ - private String mode; - - - /** - * Protected constructor as we create through factory method. - */ - protected Subscriber() { - } - - /** - * Create instance through factory method. - * - * @param aSession the parent Session - * @return a Subscriber object (or derived) - * @throws PushletException exception, usually misconfiguration - */ - public static Subscriber create(Session aSession) throws PushletException { - Subscriber subscriber; - try { - subscriber = (Subscriber) Config.getClass(SUBSCRIBER_CLASS, "nl.justobjects.pushlet.core.Subscriber").newInstance(); - } catch (Throwable t) { - throw new PushletException("Cannot instantiate Subscriber from config", t); - } - - subscriber.session = aSession; - return subscriber; - } - - public void start() { - active = true; - } - - public void stop() { - removeSubscriptions(); - active = false; - } - - public void bailout() { - session.stop(); - } - - /** - * Are we still active to handle events. - */ - public boolean isActive() { - return active; - } - - /** - * Return client session. - */ - public Session getSession() { - return session; - } - - /** - * Get (session) id. - */ - public String getId() { - return session.getId(); - } - - /** - * Return subscriptions. - */ - public Subscription[] getSubscriptions() { - // todo: Optimize - return (Subscription[]) subscriptions.values().toArray(new Subscription[0]); - } - - /** - * Add a subscription. - */ - public Subscription addSubscription(String aSubject, String aLabel) throws PushletException { - Subscription subscription = Subscription.create(aSubject, aLabel); - subscriptions.put(subscription.getId(), subscription); - info("Subscription added subject=" + aSubject + " sid=" + subscription.getId() + " label=" + aLabel); - return subscription; - } - - /** - * Remove a subscription. - */ - public Subscription removeSubscription(String aSubscriptionId) { - Subscription subscription = (Subscription) subscriptions.remove(aSubscriptionId); - if (subscription == null) { - warn("No subscription found sid=" + aSubscriptionId); - return null; - } - info("Subscription removed subject=" + subscription.getSubject() + " sid=" + subscription.getId() + " label=" + subscription.getLabel()); - return subscription; - } - - /** - * Remove all subscriptions. - */ - public void removeSubscriptions() { - subscriptions.clear(); - } - - public String getMode() { - return mode; - } - - public void setMode(String aMode) { - mode = aMode; - } - - public long getRefreshTimeMillis() { - String minWaitProperty = PULL_REFRESH_WAIT_MIN_MILLIS; - String maxWaitProperty = PULL_REFRESH_WAIT_MAX_MILLIS; - if (mode.equals((MODE_POLL))) { - minWaitProperty = POLL_REFRESH_WAIT_MIN_MILLIS; - maxWaitProperty = POLL_REFRESH_WAIT_MAX_MILLIS; - - } - return Rand.randomLong(Config.getLongProperty(minWaitProperty), - Config.getLongProperty(maxWaitProperty)); - } - - /** - * Get events from queue and push to client. - */ - public void fetchEvents(Command aCommand) throws PushletException { - - String refreshURL = aCommand.httpReq.getRequestURI() + "?" + P_ID + "=" + session.getId() + "&" + P_EVENT + "=" + E_REFRESH; - - // This is the only thing required to support "poll" mode - if (mode.equals(MODE_POLL)) { - queueReadTimeoutMillis = 0; - refreshTimeoutMillis = Config.getLongProperty(POLL_REFRESH_TIMEOUT_MILLIS); - } - - // Required for fast bailout (tomcat) - aCommand.httpRsp.setBufferSize(128); - - // Try to prevent caching in any form. - aCommand.sendResponseHeaders(); - - // Let clientAdapter determine how to send event - ClientAdapter clientAdapter = aCommand.getClientAdapter(); - Event responseEvent = aCommand.getResponseEvent(); - try { - clientAdapter.start(); - - // Send first event (usually hb-ack or listen-ack) - clientAdapter.push(responseEvent); - - // In pull/poll mode and when response is listen-ack or join-listen-ack, - // return and force refresh immediately - // such that the client recieves response immediately over this channel. - // This is usually when loading the browser app for the first time - if ((mode.equals(MODE_POLL) || mode.equals(MODE_PULL)) - && responseEvent.getEventType().endsWith(Protocol.E_LISTEN_ACK)) { - sendRefresh(clientAdapter, refreshURL); - - // We should come back later with refresh event... - return; - } - } catch (Throwable t) { - bailout(); - return; - } - - - Event[] events = null; - - // Main loop: as long as connected, get events and push to client - long eventSeqNr = 1; - while (isActive()) { - // Indicate we are still alive - lastAlive = Sys.now(); - - // Update session time to live - session.kick(); - - // Get next events; blocks until timeout or entire contents - // of event queue is returned. Note that "poll" mode - // will return immediately when queue is empty. - try { - // Put heartbeat in queue when starting to listen in stream mode - // This speeds up the return of *_LISTEN_ACK - if (mode.equals(MODE_STREAM) && eventSeqNr == 1) { - eventQueue.enQueue(new Event(E_HEARTBEAT)); - } - - events = eventQueue.deQueueAll(queueReadTimeoutMillis); - } catch (InterruptedException ie) { - warn("interrupted"); - bailout(); - } - - // Send heartbeat when no events received - if (events == null) { - events = new Event[1]; - events[0] = new Event(E_HEARTBEAT); - } - - // ASSERT: one or more events available - - // Send events to client using adapter - // debug("received event count=" + events.length); - for (int i = 0; i < events.length; i++) { - // Check for abort event - if (events[i].getEventType().equals(E_ABORT)) { - warn("Aborting Subscriber"); - bailout(); - } - - // Push next Event to client - try { - // Set sequence number - events[i].setField(P_SEQ, eventSeqNr++); - - // Push to client through client adapter - clientAdapter.push(events[i]); - } catch (Throwable t) { - bailout(); - return; - } - } - - // Force client refresh request in pull or poll modes - if (mode.equals(MODE_PULL) || mode.equals(MODE_POLL)) { - sendRefresh(clientAdapter, refreshURL); - - // Always leave loop in pull/poll mode - break; - } - } - } - - /** - * Determine if we should receive event. - */ - public Subscription match(Event event) { - Subscription[] subscriptions = getSubscriptions(); - for (int i = 0; i < subscriptions.length; i++) { - if (subscriptions[i].match(event)) { - return subscriptions[i]; - } - } - return null; - } - - /** - * Event from Dispatcher: enqueue it. - */ - public void onEvent(Event theEvent) { - if (!isActive()) { - return; - } - - // p("send: queue event: "+theEvent.getSubject()); - - // Check if we had any active continuation for at - // least 'timeOut' millisecs. If the client has left this - // instance there would be no way of knowing otherwise. - long now = Sys.now(); - if (now - lastAlive > refreshTimeoutMillis) { - warn("not alive for at least: " + refreshTimeoutMillis + "ms, leaving..."); - bailout(); - return; - } - - // Put event in queue; leave if queue full - try { - if (!eventQueue.enQueue(theEvent, queueWriteTimeoutMillis)) { - warn("queue full, bailing out..."); - bailout(); - } - - // ASSERTION : Event in queue. - // see fetchEvents() where Events are dequeued and pushed to the client. - } catch (InterruptedException ie) { - bailout(); - } - - } - - /** - * Send refresh command to pull/poll clients. - */ - protected void sendRefresh(ClientAdapter aClientAdapter, String aRefreshURL) { - Event refreshEvent = new Event(E_REFRESH); - - // Set wait time and url for refresh - refreshEvent.setField(P_WAIT, "" + getRefreshTimeMillis()); - refreshEvent.setField(P_URL, aRefreshURL); - - try { - // Push to client through client adapter - aClientAdapter.push(refreshEvent); - - // Stop this round until refresh event - aClientAdapter.stop(); - } catch (Throwable t) { - // Leave on any exception - bailout(); - } - } - - /** - * Info. - */ - protected void info(String s) { - session.info("[Subscriber] " + s); - } - - /** - * Exceptional print util. - */ - protected void warn(String s) { - session.warn("[Subscriber] " + s); - } - - /** - * Exceptional print util. - */ - protected void debug(String s) { - session.debug("[Subscriber] " + s); - } - - - public String toString() { - return session.toString(); - } -} - -/* - * $Log: Subscriber.java,v $ - * Revision 1.26 2007/11/23 14:33:07 justb - * core classes now configurable through factory - * - * Revision 1.25 2007/11/10 15:53:15 justb - * put heartbeat in queue when start fetching events in stream-mode - * - * Revision 1.24 2006/10/19 12:33:40 justb - * add atomic join-listen support (one request) - * - * Revision 1.22 2006/05/06 00:06:28 justb - * first rough version AJAX client - * - * Revision 1.21 2005/02/28 12:45:59 justb - * introduced Command class - * - * Revision 1.20 2005/02/21 16:59:09 justb - * SessionManager and session lease introduced - * - * Revision 1.19 2005/02/21 12:32:28 justb - * fixed publish event in Controller - * - * Revision 1.18 2005/02/21 11:50:46 justb - * ohase1 of refactoring Subscriber into Session/Controller/Subscriber - * - * Revision 1.17 2005/02/20 13:05:32 justb - * removed the Postlet (integrated in Pushlet protocol) - * - * Revision 1.16 2005/02/18 12:36:47 justb - * changes for renaming and configurability - * - * Revision 1.15 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.14 2005/02/18 09:54:15 justb - * refactor: rename Publisher Dispatcher and single Subscriber class - * - * Revision 1.13 2005/02/16 14:39:34 justb - * fixed leave handling and added "poll" mode - * - * Revision 1.12 2005/01/24 13:42:00 justb - * new protocol changes (p_listen) - * - * Revision 1.11 2005/01/13 14:47:15 justb - * control evt: send response on same (control) connection - * - * Revision 1.10 2004/10/24 20:50:35 justb - * refine subscription with label and sending sid and label on events - * - * Revision 1.9 2004/10/24 12:58:18 justb - * revised client and test classes for new protocol - * - * Revision 1.8 2004/09/26 21:39:43 justb - * allow multiple subscriptions and out-of-band requests - * - * Revision 1.7 2004/09/20 22:01:38 justb - * more changes for new protocol - * - * Revision 1.6 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.5 2004/08/13 23:36:05 justb - * rewrite of Pullet into Pushlet "pull" mode - * - * Revision 1.4 2004/03/10 14:01:55 justb - * formatting and *Subscriber refactoring - * - * Revision 1.3 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.2 2003/05/18 16:15:08 justb - * support for XML encoded Events - * - * Revision 1.1.1.1 2002/09/24 21:02:32 justb - * import to sourceforge - * - * Revision 1.1.1.1 2002/09/20 22:48:18 justb - * import to SF - * - * Revision 1.1.1.1 2002/09/20 14:19:04 justb - * first import into SF - * - * Revision 1.3 2002/04/15 20:42:41 just - * reformatting and renaming GuardedQueue to EventQueue - * - * Revision 1.2 2000/08/21 20:48:29 just - * added CVS log and id tags plus copyrights - * - * - */ +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +import nl.justobjects.pushlet.util.PushletException; +import nl.justobjects.pushlet.util.Rand; +import nl.justobjects.pushlet.util.Sys; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.net.URLEncoder; + +/** + * Handles data channel between dispatcher and client. + * + * @author Just van den Broecke - Just Objects © + * @version $Id: Subscriber.java,v 1.26 2007/11/23 14:33:07 justb Exp $ + */ +public class Subscriber implements Protocol, ConfigDefs { + private Session session; + + /** + * Blocking queue. + */ + private EventQueue eventQueue = new EventQueue(Config.getIntProperty(QUEUE_SIZE)); + + /** + * URL to be used in refresh requests in pull/poll modes. + */ + private long queueReadTimeoutMillis = Config.getLongProperty(QUEUE_READ_TIMEOUT_MILLIS); + private long queueWriteTimeoutMillis = Config.getLongProperty(QUEUE_WRITE_TIMEOUT_MILLIS); + private long refreshTimeoutMillis = Config.getLongProperty(PULL_REFRESH_TIMEOUT_MILLIS); + volatile long lastAlive = Sys.now(); + + /** + * Map of active subscriptions, keyed by their subscription id. + */ + private Map subscriptions = Collections.synchronizedMap(new HashMap(3)); + + /** + * Are we able to accept/send events ?. + */ + private volatile boolean active; + + /** + * Transfer mode (stream, pull, poll). + */ + private String mode; + + + /** + * Protected constructor as we create through factory method. + */ + protected Subscriber() { + } + + /** + * Create instance through factory method. + * + * @param aSession the parent Session + * @return a Subscriber object (or derived) + * @throws PushletException exception, usually misconfiguration + */ + public static Subscriber create(Session aSession) throws PushletException { + Subscriber subscriber; + try { + subscriber = (Subscriber) Config.getClass(SUBSCRIBER_CLASS, "nl.justobjects.pushlet.core.Subscriber").newInstance(); + } catch (Throwable t) { + throw new PushletException("Cannot instantiate Subscriber from config", t); + } + + subscriber.session = aSession; + return subscriber; + } + + public void start() { + active = true; + } + + public void stop() { + removeSubscriptions(); + active = false; + } + + public void bailout() { + session.stop(); + } + + /** + * Are we still active to handle events. + */ + public boolean isActive() { + return active; + } + + /** + * Return client session. + */ + public Session getSession() { + return session; + } + + /** + * Get (session) id. + */ + public String getId() { + return session.getId(); + } + + /** + * Return subscriptions. + */ + public Subscription[] getSubscriptions() { + // todo: Optimize + return (Subscription[]) subscriptions.values().toArray(new Subscription[0]); + } + + /** + * Add a subscription. + */ + public Subscription addSubscription(String aSubject, String aLabel) throws PushletException { + Subscription subscription = Subscription.create(aSubject, aLabel); + subscriptions.put(subscription.getId(), subscription); + info("Subscription added subject=" + aSubject + " sid=" + subscription.getId() + " label=" + aLabel); + return subscription; + } + + /** + * Remove a subscription. + */ + public Subscription removeSubscription(String aSubscriptionId) { + Subscription subscription = (Subscription) subscriptions.remove(aSubscriptionId); + if (subscription == null) { + warn("No subscription found sid=" + aSubscriptionId); + return null; + } + info("Subscription removed subject=" + subscription.getSubject() + " sid=" + subscription.getId() + " label=" + subscription.getLabel()); + return subscription; + } + + /** + * Remove all subscriptions. + */ + public void removeSubscriptions() { + subscriptions.clear(); + } + + public String getMode() { + return mode; + } + + public void setMode(String aMode) { + mode = aMode; + } + + public long getRefreshTimeMillis() { + String minWaitProperty = PULL_REFRESH_WAIT_MIN_MILLIS; + String maxWaitProperty = PULL_REFRESH_WAIT_MAX_MILLIS; + if (mode.equals((MODE_POLL))) { + minWaitProperty = POLL_REFRESH_WAIT_MIN_MILLIS; + maxWaitProperty = POLL_REFRESH_WAIT_MAX_MILLIS; + + } + return Rand.randomLong(Config.getLongProperty(minWaitProperty), + Config.getLongProperty(maxWaitProperty)); + } + + /** + * Get events from queue and push to client. + */ + public void fetchEvents(Command aCommand) throws PushletException { + + String refreshURL = aCommand.httpReq.getRequestURI() + "?" + P_ID + "=" + session.getId() + "&" + P_EVENT + "=" + E_REFRESH; + + // This is the only thing required to support "poll" mode + if (mode.equals(MODE_POLL)) { + queueReadTimeoutMillis = 0; + refreshTimeoutMillis = Config.getLongProperty(POLL_REFRESH_TIMEOUT_MILLIS); + } + + // Required for fast bailout (tomcat) + aCommand.httpRsp.setBufferSize(128); + + // Try to prevent caching in any form. + aCommand.sendResponseHeaders(); + + // Let clientAdapter determine how to send event + ClientAdapter clientAdapter = aCommand.getClientAdapter(); + Event responseEvent = aCommand.getResponseEvent(); + try { + clientAdapter.start(); + + // Send first event (usually hb-ack or listen-ack) + clientAdapter.push(responseEvent); + + // In pull/poll mode and when response is listen-ack or join-listen-ack, + // return and force refresh immediately + // such that the client recieves response immediately over this channel. + // This is usually when loading the browser app for the first time + if ((mode.equals(MODE_POLL) || mode.equals(MODE_PULL)) + && responseEvent.getEventType().endsWith(Protocol.E_LISTEN_ACK)) { + sendRefresh(clientAdapter, refreshURL); + + // We should come back later with refresh event... + return; + } + } catch (Throwable t) { + bailout(); + return; + } + + + Event[] events = null; + + // Main loop: as long as connected, get events and push to client + long eventSeqNr = 1; + while (isActive()) { + // Indicate we are still alive + lastAlive = Sys.now(); + + // Update session time to live + session.kick(); + + // Get next events; blocks until timeout or entire contents + // of event queue is returned. Note that "poll" mode + // will return immediately when queue is empty. + try { + // Put heartbeat in queue when starting to listen in stream mode + // This speeds up the return of *_LISTEN_ACK + if (mode.equals(MODE_STREAM) && eventSeqNr == 1) { + eventQueue.enQueue(new Event(E_HEARTBEAT)); + } + + events = eventQueue.deQueueAll(queueReadTimeoutMillis); + } catch (InterruptedException ie) { + warn("interrupted"); + bailout(); + } + + // Send heartbeat when no events received + if (events == null) { + events = new Event[1]; + events[0] = new Event(E_HEARTBEAT); + } + + // ASSERT: one or more events available + + // Send events to client using adapter + // debug("received event count=" + events.length); + for (int i = 0; i < events.length; i++) { + // Check for abort event + if (events[i].getEventType().equals(E_ABORT)) { + warn("Aborting Subscriber"); + bailout(); + } + + // Push next Event to client + try { + // Set sequence number + events[i].setField(P_SEQ, eventSeqNr++); + + // Push to client through client adapter + clientAdapter.push(events[i]); + } catch (Throwable t) { + bailout(); + return; + } + } + + // Force client refresh request in pull or poll modes + if (mode.equals(MODE_PULL) || mode.equals(MODE_POLL)) { + sendRefresh(clientAdapter, refreshURL); + + // Always leave loop in pull/poll mode + break; + } + } + } + + /** + * Determine if we should receive event. + */ + public Subscription match(Event event) { + Subscription[] subscriptions = getSubscriptions(); + for (int i = 0; i < subscriptions.length; i++) { + if (subscriptions[i].match(event)) { + return subscriptions[i]; + } + } + return null; + } + + /** + * Event from Dispatcher: enqueue it. + */ + public void onEvent(Event theEvent) { + if (!isActive()) { + return; + } + + // p("send: queue event: "+theEvent.getSubject()); + + // Check if we had any active continuation for at + // least 'timeOut' millisecs. If the client has left this + // instance there would be no way of knowing otherwise. + long now = Sys.now(); + if (now - lastAlive > refreshTimeoutMillis) { + warn("not alive for at least: " + refreshTimeoutMillis + "ms, leaving..."); + bailout(); + return; + } + + // Put event in queue; leave if queue full + try { + if (!eventQueue.enQueue(theEvent, queueWriteTimeoutMillis)) { + warn("queue full, bailing out..."); + bailout(); + } + + // ASSERTION : Event in queue. + // see fetchEvents() where Events are dequeued and pushed to the client. + } catch (InterruptedException ie) { + bailout(); + } + + } + + /** + * Send refresh command to pull/poll clients. + */ + protected void sendRefresh(ClientAdapter aClientAdapter, String aRefreshURL) { + Event refreshEvent = new Event(E_REFRESH); + + // Set wait time and url for refresh + refreshEvent.setField(P_WAIT, "" + getRefreshTimeMillis()); + refreshEvent.setField(P_URL, aRefreshURL); + + try { + // Push to client through client adapter + aClientAdapter.push(refreshEvent); + + // Stop this round until refresh event + aClientAdapter.stop(); + } catch (Throwable t) { + // Leave on any exception + bailout(); + } + } + + /** + * Info. + */ + protected void info(String s) { + session.info("[Subscriber] " + s); + } + + /** + * Exceptional print util. + */ + protected void warn(String s) { + session.warn("[Subscriber] " + s); + } + + /** + * Exceptional print util. + */ + protected void debug(String s) { + session.debug("[Subscriber] " + s); + } + + + public String toString() { + return session.toString(); + } +} + +/* + * $Log: Subscriber.java,v $ + * Revision 1.26 2007/11/23 14:33:07 justb + * core classes now configurable through factory + * + * Revision 1.25 2007/11/10 15:53:15 justb + * put heartbeat in queue when start fetching events in stream-mode + * + * Revision 1.24 2006/10/19 12:33:40 justb + * add atomic join-listen support (one request) + * + * Revision 1.22 2006/05/06 00:06:28 justb + * first rough version AJAX client + * + * Revision 1.21 2005/02/28 12:45:59 justb + * introduced Command class + * + * Revision 1.20 2005/02/21 16:59:09 justb + * SessionManager and session lease introduced + * + * Revision 1.19 2005/02/21 12:32:28 justb + * fixed publish event in Controller + * + * Revision 1.18 2005/02/21 11:50:46 justb + * ohase1 of refactoring Subscriber into Session/Controller/Subscriber + * + * Revision 1.17 2005/02/20 13:05:32 justb + * removed the Postlet (integrated in Pushlet protocol) + * + * Revision 1.16 2005/02/18 12:36:47 justb + * changes for renaming and configurability + * + * Revision 1.15 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.14 2005/02/18 09:54:15 justb + * refactor: rename Publisher Dispatcher and single Subscriber class + * + * Revision 1.13 2005/02/16 14:39:34 justb + * fixed leave handling and added "poll" mode + * + * Revision 1.12 2005/01/24 13:42:00 justb + * new protocol changes (p_listen) + * + * Revision 1.11 2005/01/13 14:47:15 justb + * control evt: send response on same (control) connection + * + * Revision 1.10 2004/10/24 20:50:35 justb + * refine subscription with label and sending sid and label on events + * + * Revision 1.9 2004/10/24 12:58:18 justb + * revised client and test classes for new protocol + * + * Revision 1.8 2004/09/26 21:39:43 justb + * allow multiple subscriptions and out-of-band requests + * + * Revision 1.7 2004/09/20 22:01:38 justb + * more changes for new protocol + * + * Revision 1.6 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.5 2004/08/13 23:36:05 justb + * rewrite of Pullet into Pushlet "pull" mode + * + * Revision 1.4 2004/03/10 14:01:55 justb + * formatting and *Subscriber refactoring + * + * Revision 1.3 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.2 2003/05/18 16:15:08 justb + * support for XML encoded Events + * + * Revision 1.1.1.1 2002/09/24 21:02:32 justb + * import to sourceforge + * + * Revision 1.1.1.1 2002/09/20 22:48:18 justb + * import to SF + * + * Revision 1.1.1.1 2002/09/20 14:19:04 justb + * first import into SF + * + * Revision 1.3 2002/04/15 20:42:41 just + * reformatting and renaming GuardedQueue to EventQueue + * + * Revision 1.2 2000/08/21 20:48:29 just + * added CVS log and id tags plus copyrights + * + * + */ diff --git a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/XMLAdapter.java b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/XMLAdapter.java index 15d7096e59..70a9c3c47d 100644 --- a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/XMLAdapter.java +++ b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/core/XMLAdapter.java @@ -1,137 +1,137 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.core; - -import nl.justobjects.pushlet.util.Log; - -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; - -/** - * ClientAdapter that sends Events as XML. - * - * @author Just van den Broecke - Just Objects © - * @version $Id: XMLAdapter.java,v 1.7 2007/11/09 13:15:35 justb Exp $ - */ -class XMLAdapter implements ClientAdapter { - /** - * Header for strict XML - */ - // public static final String XML_HEAD = "\n"; - private String contentType = "text/plain;charset=UTF-8"; - private ServletOutputStream out = null; - private HttpServletResponse servletRsp; - private boolean strictXML; - - /** - * Initialize. - */ - public XMLAdapter(HttpServletResponse aServletResponse) { - this(aServletResponse, false); - } - - /** - * Initialize. - */ - public XMLAdapter(HttpServletResponse aServletResponse, boolean useStrictXML) { - servletRsp = aServletResponse; - - // Strict XML implies returning a complete XML document - strictXML = useStrictXML; - if (strictXML) { - contentType = "text/xml;charset=UTF-8"; - } - } - - public void start() throws IOException { - - // If content type is plain text - // then this is not a complete XML document, but rather - // a stream of XML documents where each document is - // an Event. In strict XML mode a complete document is returned. - servletRsp.setContentType(contentType); - - out = servletRsp.getOutputStream(); - - // Don't need this further - servletRsp = null; - - // Start XML document if strict XML mode - if (strictXML) { - out.print(""); - } - } - - /** - * Force client to refresh the request. - */ - public void push(Event anEvent) throws IOException { - debug("event=" + anEvent); - - // Send the event as XML to the client and flush. - out.print(anEvent.toXML(strictXML)); - out.flush(); - } - - /** - * No action. - */ - public void stop() throws IOException { - // Close XML document if strict XML mode - if (strictXML) { - out.print(""); - out.flush(); - } - } - - private void debug(String s) { - Log.debug("[XMLAdapter]" + s); - } -} - -/* - * $Log: XMLAdapter.java,v $ - * Revision 1.7 2007/11/09 13:15:35 justb - * add charset=UTF-8 in returned HTTP content types - * - * Revision 1.6 2006/05/15 11:52:53 justb - * updates mainly for AJAX client - * - * Revision 1.5 2006/05/06 00:06:28 justb - * first rough version AJAX client - * - * Revision 1.4 2005/05/06 19:44:00 justb - * added xml-strict format - * - * Revision 1.3 2005/02/28 12:45:59 justb - * introduced Command class - * - * Revision 1.2 2005/02/21 11:50:47 justb - * ohase1 of refactoring Subscriber into Session/Controller/Subscriber - * - * Revision 1.1 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.7 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.6 2004/03/10 14:01:55 justb - * formatting and *Subscriber refactoring - * - * Revision 1.5 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.4 2003/08/13 14:00:00 justb - * some testing for applets; no real change - * - * Revision 1.3 2003/08/12 09:57:06 justb - * replaced all print statements to Log.*() calls - * - * Revision 1.2 2003/05/19 21:56:29 justb - * various fixes for applet clients - * - * Revision 1.1 2003/05/18 16:12:28 justb - * adding support for XML encoded Events - */ +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.core; + +import nl.justobjects.pushlet.util.Log; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * ClientAdapter that sends Events as XML. + * + * @author Just van den Broecke - Just Objects © + * @version $Id: XMLAdapter.java,v 1.7 2007/11/09 13:15:35 justb Exp $ + */ +class XMLAdapter implements ClientAdapter { + /** + * Header for strict XML + */ + // public static final String XML_HEAD = "\n"; + private String contentType = "text/plain;charset=UTF-8"; + private ServletOutputStream out = null; + private HttpServletResponse servletRsp; + private boolean strictXML; + + /** + * Initialize. + */ + public XMLAdapter(HttpServletResponse aServletResponse) { + this(aServletResponse, false); + } + + /** + * Initialize. + */ + public XMLAdapter(HttpServletResponse aServletResponse, boolean useStrictXML) { + servletRsp = aServletResponse; + + // Strict XML implies returning a complete XML document + strictXML = useStrictXML; + if (strictXML) { + contentType = "text/xml;charset=UTF-8"; + } + } + + public void start() throws IOException { + + // If content type is plain text + // then this is not a complete XML document, but rather + // a stream of XML documents where each document is + // an Event. In strict XML mode a complete document is returned. + servletRsp.setContentType(contentType); + + out = servletRsp.getOutputStream(); + + // Don't need this further + servletRsp = null; + + // Start XML document if strict XML mode + if (strictXML) { + out.print(""); + } + } + + /** + * Force client to refresh the request. + */ + public void push(Event anEvent) throws IOException { + debug("event=" + anEvent); + + // Send the event as XML to the client and flush. + out.print(anEvent.toXML(strictXML)); + out.flush(); + } + + /** + * No action. + */ + public void stop() throws IOException { + // Close XML document if strict XML mode + if (strictXML) { + out.print(""); + out.flush(); + } + } + + private void debug(String s) { + Log.debug("[XMLAdapter]" + s); + } +} + +/* + * $Log: XMLAdapter.java,v $ + * Revision 1.7 2007/11/09 13:15:35 justb + * add charset=UTF-8 in returned HTTP content types + * + * Revision 1.6 2006/05/15 11:52:53 justb + * updates mainly for AJAX client + * + * Revision 1.5 2006/05/06 00:06:28 justb + * first rough version AJAX client + * + * Revision 1.4 2005/05/06 19:44:00 justb + * added xml-strict format + * + * Revision 1.3 2005/02/28 12:45:59 justb + * introduced Command class + * + * Revision 1.2 2005/02/21 11:50:47 justb + * ohase1 of refactoring Subscriber into Session/Controller/Subscriber + * + * Revision 1.1 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.7 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.6 2004/03/10 14:01:55 justb + * formatting and *Subscriber refactoring + * + * Revision 1.5 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.4 2003/08/13 14:00:00 justb + * some testing for applets; no real change + * + * Revision 1.3 2003/08/12 09:57:06 justb + * replaced all print statements to Log.*() calls + * + * Revision 1.2 2003/05/19 21:56:29 justb + * various fixes for applet clients + * + * Revision 1.1 2003/05/18 16:12:28 justb + * adding support for XML encoded Events + */ diff --git a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/servlet/Pushlet.java b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/servlet/Pushlet.java index 0c19494dd3..33bbde24c0 100644 --- a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/servlet/Pushlet.java +++ b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/servlet/Pushlet.java @@ -1,293 +1,293 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.servlet; - -import nl.justobjects.pushlet.core.*; -import nl.justobjects.pushlet.util.Log; -import nl.justobjects.pushlet.util.Servlets; -import nl.justobjects.pushlet.util.PushletException; -import nl.justobjects.pushlet.Version; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.Enumeration; - -/** - * Servlet runs a Subscriber per request. - * - * @author Just van den Broecke - Just Objects © - * @version $Id: Pushlet.java,v 1.23 2007/12/04 13:55:53 justb Exp $ - */ -public class Pushlet extends HttpServlet implements Protocol { - - public void init() throws ServletException { - try { - // Load configuration (from classpath or WEB-INF root path) - String webInfPath = getServletContext().getRealPath("/") + "/WEB-INF"; - Config.load(webInfPath); - - Log.init(); - - // Start - Log.info("init() Pushlet Webapp - version=" + Version.SOFTWARE_VERSION + " built=" + Version.BUILD_DATE); - - // Start session manager - SessionManager.getInstance().start(); - - // Start event Dispatcher - Dispatcher.getInstance().start(); - - - if (Config.getBoolProperty(Config.SOURCES_ACTIVATE)) { - EventSourceManager.start(webInfPath,getServletContext());// changed by thomas genin - } else { - Log.info("Not starting local event sources"); - } - } catch (Throwable t) { - throw new ServletException("Failed to initialize Pushlet framework " + t, t); - } - } - - public void destroy() { - Log.info("destroy(): Exit Pushlet webapp"); - - if (Config.getBoolProperty(Config.SOURCES_ACTIVATE)) { - // Stop local event sources - EventSourceManager.stop(); - } else { - Log.info("No local event sources to stop"); - } - - // Should abort all subscribers - Dispatcher.getInstance().stop(); - - // Should stop all sessions - SessionManager.getInstance().stop(); - } - - /** - * Servlet GET request: handles event requests. - */ - public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - Event event = null; - - try { - // Event parm identifies event type from the client - String eventType = Servlets.getParameter(request, P_EVENT); - - // Always must have an event type - if (eventType == null) { - Log.warn("Pushlet.doGet(): bad request, no event specified"); - response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No eventType specified"); - return; - } - - // Create Event and set attributes from parameters - event = new Event(eventType); - for (Enumeration e = request.getParameterNames(); e.hasMoreElements();) { - String nextAttribute = (String) e.nextElement(); - event.setField(nextAttribute, request.getParameter(nextAttribute)); - } - - - } catch (Throwable t) { - // Error creating event - Log.warn("Pushlet: Error creating event in doGet(): ", t); - response.setStatus(HttpServletResponse.SC_BAD_REQUEST); - return; - } - - // Handle parsed request - doRequest(event, request, response); - - } - - /** - * Servlet POST request: extracts event data from body. - */ - public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - Event event = null; - try { - // Create Event by parsing XML from input stream. - event = EventParser.parse(new InputStreamReader(request.getInputStream())); - - // Always must have an event type - if (event.getEventType() == null) { - Log.warn("Pushlet.doPost(): bad request, no event specified"); - response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No eventType specified"); - return; - } - - - } catch (Throwable t) { - // Error creating event - Log.warn("Pushlet: Error creating event in doPost(): ", t); - response.setStatus(HttpServletResponse.SC_BAD_REQUEST); - return; - } - - // Handle parsed request - doRequest(event, request, response); - - } - - /** - * Generic request handler (GET+POST). - */ - protected void doRequest(Event anEvent, HttpServletRequest request, HttpServletResponse response) { - // Must have valid event type. - String eventType = anEvent.getEventType(); - try { - - // Get Session: either by creating (on Join eventType) - // or by id (any other eventType, since client is supposed to have joined). - Session session = null; - if (eventType.startsWith(Protocol.E_JOIN)) { - // Join request: create new subscriber - session = SessionManager.getInstance().createSession(anEvent); - - String userAgent = request.getHeader("User-Agent"); - if (userAgent != null) { - userAgent = userAgent.toLowerCase(); - } else { - userAgent = "unknown"; - } - session.setUserAgent(userAgent); - - } else { - // Must be a request for existing Session - - // Get id - String id = anEvent.getField(P_ID); - - // We must have an id value - if (id == null) { - response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No id specified"); - Log.warn("Pushlet: bad request, no id specified event=" + eventType); - return; - } - - // We have an id: get the session object - session = SessionManager.getInstance().getSession(id); - - // Check for invalid id - if (session == null) { - response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid or expired id: " + id); - Log.warn("Pushlet: bad request, no session found id=" + id + " event=" + eventType); - return; - } - } - - // ASSERTION: we have a valid Session - - // Let Controller handle request further - // including exceptions - Command command = Command.create(session, anEvent, request, response); - session.getController().doCommand(command); - } catch (Throwable t) { - // Hmm we should never ever get here - Log.warn("Pushlet: Exception in doRequest() event=" + eventType, t); - t.printStackTrace(); - response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - } - - } -} - -/* - * $Log: Pushlet.java,v $ - * Revision 1.23 2007/12/04 13:55:53 justb - * reimplement SessionManager concurrency (prev version was not thread-safe!) - * - * Revision 1.22 2007/11/24 10:29:36 justb - * add hooks for custom logging (you can override DefaultLogger in pushlet.properties) - * - * Revision 1.21 2007/11/23 21:10:17 justb - * add hooks for custom logging (you can override DefaultLogger in pushlet.properties) - * - * Revision 1.20 2007/11/10 13:44:02 justb - * pushlet.properties and sources.properties can now also be put under WEB-INF - * - * Revision 1.19 2006/05/15 11:52:53 justb - * updates mainly for AJAX client - * - * Revision 1.18 2005/02/28 15:58:05 justb - * added SimpleListener example - * - * Revision 1.17 2005/02/28 13:06:01 justb - * introduced join-listen protocol service - * - * Revision 1.16 2005/02/28 12:45:59 justb - * introduced Command class - * - * Revision 1.15 2005/02/28 09:14:56 justb - * sessmgr/dispatcher factory/singleton support - * - * Revision 1.14 2005/02/25 15:13:04 justb - * session id generation more robust - * - * Revision 1.13 2005/02/21 17:19:21 justb - * move init()/destroy() to Pushlet servlet - * - * Revision 1.12 2005/02/21 16:59:17 justb - * SessionManager and session lease introduced - * - * Revision 1.11 2005/02/21 11:50:47 justb - * ohase1 of refactoring Subscriber into Session/Controller/Subscriber - * - * Revision 1.10 2005/02/20 13:05:32 justb - * removed the Postlet (integrated in Pushlet protocol) - * - * Revision 1.9 2005/02/18 10:07:23 justb - * many renamings of classes (make names compact) - * - * Revision 1.8 2005/01/13 14:47:15 justb - * control evt: send response on same (control) connection - * - * Revision 1.7 2004/10/24 12:58:18 justb - * revised client and test classes for new protocol - * - * Revision 1.6 2004/09/26 21:39:44 justb - * allow multiple subscriptions and out-of-band requests - * - * Revision 1.5 2004/09/20 22:01:40 justb - * more changes for new protocol - * - * Revision 1.4 2004/09/03 22:35:37 justb - * Almost complete rewrite, just checking in now - * - * Revision 1.3 2004/08/13 23:36:06 justb - * rewrite of Pullet into Pushlet "pull" mode - * - * Revision 1.2 2003/08/15 08:37:40 justb - * fix/add Copyright+LGPL file headers and footers - * - * Revision 1.1 2003/08/13 13:26:57 justb - * moved all servlets to servlet package - * - * Revision 1.2 2003/05/18 16:15:08 justb - * support for XML encoded Events - * - * Revision 1.1.1.1 2002/09/24 21:02:32 justb - * import to sourceforge - * - * Revision 1.1.1.1 2002/09/20 22:48:18 justb - * import to SF - * - * Revision 1.1.1.1 2002/09/20 14:19:04 justb - * first import into SF - * - * Revision 1.3 2002/04/15 20:42:41 just - * reformatting and renaming GuardedQueue to EventQueue - * - * Revision 1.2 2000/08/21 20:48:29 just - * added CVS log and id tags plus copyrights - * - * - */ - +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.servlet; + +import nl.justobjects.pushlet.core.*; +import nl.justobjects.pushlet.util.Log; +import nl.justobjects.pushlet.util.Servlets; +import nl.justobjects.pushlet.util.PushletException; +import nl.justobjects.pushlet.Version; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Enumeration; + +/** + * Servlet runs a Subscriber per request. + * + * @author Just van den Broecke - Just Objects © + * @version $Id: Pushlet.java,v 1.23 2007/12/04 13:55:53 justb Exp $ + */ +public class Pushlet extends HttpServlet implements Protocol { + + public void init() throws ServletException { + try { + // Load configuration (from classpath or WEB-INF root path) + String webInfPath = getServletContext().getRealPath("/") + "/WEB-INF"; + Config.load(webInfPath); + + Log.init(); + + // Start + Log.info("init() Pushlet Webapp - version=" + Version.SOFTWARE_VERSION + " built=" + Version.BUILD_DATE); + + // Start session manager + SessionManager.getInstance().start(); + + // Start event Dispatcher + Dispatcher.getInstance().start(); + + + if (Config.getBoolProperty(Config.SOURCES_ACTIVATE)) { + EventSourceManager.start(webInfPath,getServletContext());// changed by thomas genin + } else { + Log.info("Not starting local event sources"); + } + } catch (Throwable t) { + throw new ServletException("Failed to initialize Pushlet framework " + t, t); + } + } + + public void destroy() { + Log.info("destroy(): Exit Pushlet webapp"); + + if (Config.getBoolProperty(Config.SOURCES_ACTIVATE)) { + // Stop local event sources + EventSourceManager.stop(); + } else { + Log.info("No local event sources to stop"); + } + + // Should abort all subscribers + Dispatcher.getInstance().stop(); + + // Should stop all sessions + SessionManager.getInstance().stop(); + } + + /** + * Servlet GET request: handles event requests. + */ + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + Event event = null; + + try { + // Event parm identifies event type from the client + String eventType = Servlets.getParameter(request, P_EVENT); + + // Always must have an event type + if (eventType == null) { + Log.warn("Pushlet.doGet(): bad request, no event specified"); + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No eventType specified"); + return; + } + + // Create Event and set attributes from parameters + event = new Event(eventType); + for (Enumeration e = request.getParameterNames(); e.hasMoreElements();) { + String nextAttribute = (String) e.nextElement(); + event.setField(nextAttribute, request.getParameter(nextAttribute)); + } + + + } catch (Throwable t) { + // Error creating event + Log.warn("Pushlet: Error creating event in doGet(): ", t); + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + return; + } + + // Handle parsed request + doRequest(event, request, response); + + } + + /** + * Servlet POST request: extracts event data from body. + */ + public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + Event event = null; + try { + // Create Event by parsing XML from input stream. + event = EventParser.parse(new InputStreamReader(request.getInputStream())); + + // Always must have an event type + if (event.getEventType() == null) { + Log.warn("Pushlet.doPost(): bad request, no event specified"); + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No eventType specified"); + return; + } + + + } catch (Throwable t) { + // Error creating event + Log.warn("Pushlet: Error creating event in doPost(): ", t); + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + return; + } + + // Handle parsed request + doRequest(event, request, response); + + } + + /** + * Generic request handler (GET+POST). + */ + protected void doRequest(Event anEvent, HttpServletRequest request, HttpServletResponse response) { + // Must have valid event type. + String eventType = anEvent.getEventType(); + try { + + // Get Session: either by creating (on Join eventType) + // or by id (any other eventType, since client is supposed to have joined). + Session session = null; + if (eventType.startsWith(Protocol.E_JOIN)) { + // Join request: create new subscriber + session = SessionManager.getInstance().createSession(anEvent); + + String userAgent = request.getHeader("User-Agent"); + if (userAgent != null) { + userAgent = userAgent.toLowerCase(); + } else { + userAgent = "unknown"; + } + session.setUserAgent(userAgent); + + } else { + // Must be a request for existing Session + + // Get id + String id = anEvent.getField(P_ID); + + // We must have an id value + if (id == null) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No id specified"); + Log.warn("Pushlet: bad request, no id specified event=" + eventType); + return; + } + + // We have an id: get the session object + session = SessionManager.getInstance().getSession(id); + + // Check for invalid id + if (session == null) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid or expired id: " + id); + Log.warn("Pushlet: bad request, no session found id=" + id + " event=" + eventType); + return; + } + } + + // ASSERTION: we have a valid Session + + // Let Controller handle request further + // including exceptions + Command command = Command.create(session, anEvent, request, response); + session.getController().doCommand(command); + } catch (Throwable t) { + // Hmm we should never ever get here + Log.warn("Pushlet: Exception in doRequest() event=" + eventType, t); + t.printStackTrace(); + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + + } +} + +/* + * $Log: Pushlet.java,v $ + * Revision 1.23 2007/12/04 13:55:53 justb + * reimplement SessionManager concurrency (prev version was not thread-safe!) + * + * Revision 1.22 2007/11/24 10:29:36 justb + * add hooks for custom logging (you can override DefaultLogger in pushlet.properties) + * + * Revision 1.21 2007/11/23 21:10:17 justb + * add hooks for custom logging (you can override DefaultLogger in pushlet.properties) + * + * Revision 1.20 2007/11/10 13:44:02 justb + * pushlet.properties and sources.properties can now also be put under WEB-INF + * + * Revision 1.19 2006/05/15 11:52:53 justb + * updates mainly for AJAX client + * + * Revision 1.18 2005/02/28 15:58:05 justb + * added SimpleListener example + * + * Revision 1.17 2005/02/28 13:06:01 justb + * introduced join-listen protocol service + * + * Revision 1.16 2005/02/28 12:45:59 justb + * introduced Command class + * + * Revision 1.15 2005/02/28 09:14:56 justb + * sessmgr/dispatcher factory/singleton support + * + * Revision 1.14 2005/02/25 15:13:04 justb + * session id generation more robust + * + * Revision 1.13 2005/02/21 17:19:21 justb + * move init()/destroy() to Pushlet servlet + * + * Revision 1.12 2005/02/21 16:59:17 justb + * SessionManager and session lease introduced + * + * Revision 1.11 2005/02/21 11:50:47 justb + * ohase1 of refactoring Subscriber into Session/Controller/Subscriber + * + * Revision 1.10 2005/02/20 13:05:32 justb + * removed the Postlet (integrated in Pushlet protocol) + * + * Revision 1.9 2005/02/18 10:07:23 justb + * many renamings of classes (make names compact) + * + * Revision 1.8 2005/01/13 14:47:15 justb + * control evt: send response on same (control) connection + * + * Revision 1.7 2004/10/24 12:58:18 justb + * revised client and test classes for new protocol + * + * Revision 1.6 2004/09/26 21:39:44 justb + * allow multiple subscriptions and out-of-band requests + * + * Revision 1.5 2004/09/20 22:01:40 justb + * more changes for new protocol + * + * Revision 1.4 2004/09/03 22:35:37 justb + * Almost complete rewrite, just checking in now + * + * Revision 1.3 2004/08/13 23:36:06 justb + * rewrite of Pullet into Pushlet "pull" mode + * + * Revision 1.2 2003/08/15 08:37:40 justb + * fix/add Copyright+LGPL file headers and footers + * + * Revision 1.1 2003/08/13 13:26:57 justb + * moved all servlets to servlet package + * + * Revision 1.2 2003/05/18 16:15:08 justb + * support for XML encoded Events + * + * Revision 1.1.1.1 2002/09/24 21:02:32 justb + * import to sourceforge + * + * Revision 1.1.1.1 2002/09/20 22:48:18 justb + * import to SF + * + * Revision 1.1.1.1 2002/09/20 14:19:04 justb + * first import into SF + * + * Revision 1.3 2002/04/15 20:42:41 just + * reformatting and renaming GuardedQueue to EventQueue + * + * Revision 1.2 2000/08/21 20:48:29 just + * added CVS log and id tags plus copyrights + * + * + */ + diff --git a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/util/DefaultLogger.java b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/util/DefaultLogger.java index bec2d94f34..bc0648c9a1 100644 --- a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/util/DefaultLogger.java +++ b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/util/DefaultLogger.java @@ -1,164 +1,164 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.util; - -/** - * Default logger. - *

- * Logs to stdout. Override this class by setting "logger.class" in pushlet.properties to your own logger - * to integrate your own logging library. - * - * @author Just van den Broecke - * @version $Id: DefaultLogger.java,v 1.2 2007/12/07 12:57:40 justb Exp $ - */ -public class DefaultLogger implements PushletLogger { - - - /** - * Level intialized with default. - */ - private int level = LOG_LEVEL_INFO; - - public DefaultLogger() { - } - - public void init() { - - } - - /** - * Log message for trace level. - * - * @param aMessage the message to be logged - */ - public void trace(String aMessage) { - if (level < LOG_LEVEL_TRACE) { - return; - } - print("TRACE", aMessage); - } - - /** - * Log message for debug level. - * - * @param aMessage the message to be logged - */ - public void debug(String aMessage) { - if (level < LOG_LEVEL_DEBUG) { - return; - } - print("DEBUG", aMessage); - } - - /** - * Log message for info level. - * - * @param aMessage the message to be logged - */ - public void info(String aMessage) { - if (level < LOG_LEVEL_INFO) { - return; - } - print("INFO", aMessage); - } - - /** - * Log message for warning level. - * - * @param aMessage the message to be logged - */ - public void warn(String aMessage) { - if (level < LOG_LEVEL_WARN) { - return; - } - print("WARN", aMessage); - } - - /** - * Log message for warning level with exception. - * - * @param aMessage the message to be logged - * @param aThrowable the exception - */ - public void warn(String aMessage, Throwable aThrowable) { - warn(aMessage + " exception=" + aThrowable); - } - - /** - * Log message for error level. - * - * @param aMessage the message to be logged - */ - public void error(String aMessage) { - if (level < LOG_LEVEL_ERROR) { - return; - } - print("FATAL", aMessage); - } - - /** - * Log message (error level with exception). - * - * @param aMessage the message to be logged - * @param aThrowable the exception - */ - public void error(String aMessage, Throwable aThrowable) { - error(aMessage + " exception=" + aThrowable); - } - - /** - * Log message for fatal level. - * - * @param aMessage the message to be logged - */ - public void fatal(String aMessage) { - if (level < LOG_LEVEL_FATAL) { - return; - } - print("FATAL", aMessage); - } - - /** - * Log message (fatal level with exception). - * - * @param aMessage the message to be logged - * @param aThrowable the exception - */ - public void fatal(String aMessage, Throwable aThrowable) { - fatal(aMessage + " exception=" + aThrowable); - } - - /** - * Set log level - * - * @param aLevel the message to be logged - */ - public void setLevel(int aLevel) { - level = aLevel; - } - - /** - * Print message. - * - * @param aTag the log type - * @param aMessage the message to be logged - */ - private void print(String aTag, String aMessage) { - // SImple std out e.g. to catalina.out in Tomcat - System.out.println("Pushlet[" + aTag + "] " + aMessage); - } - -} - -/* -* $Log: DefaultLogger.java,v $ -* Revision 1.2 2007/12/07 12:57:40 justb -* added log4j and make it the default logging method -* -* Revision 1.1 2007/11/23 21:10:17 justb -* add hooks for custom logging (you can override DefaultLogger in pushlet.properties) -* -* -* +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.util; + +/** + * Default logger. + *

+ * Logs to stdout. Override this class by setting "logger.class" in pushlet.properties to your own logger + * to integrate your own logging library. + * + * @author Just van den Broecke + * @version $Id: DefaultLogger.java,v 1.2 2007/12/07 12:57:40 justb Exp $ + */ +public class DefaultLogger implements PushletLogger { + + + /** + * Level intialized with default. + */ + private int level = LOG_LEVEL_INFO; + + public DefaultLogger() { + } + + public void init() { + + } + + /** + * Log message for trace level. + * + * @param aMessage the message to be logged + */ + public void trace(String aMessage) { + if (level < LOG_LEVEL_TRACE) { + return; + } + print("TRACE", aMessage); + } + + /** + * Log message for debug level. + * + * @param aMessage the message to be logged + */ + public void debug(String aMessage) { + if (level < LOG_LEVEL_DEBUG) { + return; + } + print("DEBUG", aMessage); + } + + /** + * Log message for info level. + * + * @param aMessage the message to be logged + */ + public void info(String aMessage) { + if (level < LOG_LEVEL_INFO) { + return; + } + print("INFO", aMessage); + } + + /** + * Log message for warning level. + * + * @param aMessage the message to be logged + */ + public void warn(String aMessage) { + if (level < LOG_LEVEL_WARN) { + return; + } + print("WARN", aMessage); + } + + /** + * Log message for warning level with exception. + * + * @param aMessage the message to be logged + * @param aThrowable the exception + */ + public void warn(String aMessage, Throwable aThrowable) { + warn(aMessage + " exception=" + aThrowable); + } + + /** + * Log message for error level. + * + * @param aMessage the message to be logged + */ + public void error(String aMessage) { + if (level < LOG_LEVEL_ERROR) { + return; + } + print("FATAL", aMessage); + } + + /** + * Log message (error level with exception). + * + * @param aMessage the message to be logged + * @param aThrowable the exception + */ + public void error(String aMessage, Throwable aThrowable) { + error(aMessage + " exception=" + aThrowable); + } + + /** + * Log message for fatal level. + * + * @param aMessage the message to be logged + */ + public void fatal(String aMessage) { + if (level < LOG_LEVEL_FATAL) { + return; + } + print("FATAL", aMessage); + } + + /** + * Log message (fatal level with exception). + * + * @param aMessage the message to be logged + * @param aThrowable the exception + */ + public void fatal(String aMessage, Throwable aThrowable) { + fatal(aMessage + " exception=" + aThrowable); + } + + /** + * Set log level + * + * @param aLevel the message to be logged + */ + public void setLevel(int aLevel) { + level = aLevel; + } + + /** + * Print message. + * + * @param aTag the log type + * @param aMessage the message to be logged + */ + private void print(String aTag, String aMessage) { + // SImple std out e.g. to catalina.out in Tomcat + System.out.println("Pushlet[" + aTag + "] " + aMessage); + } + +} + +/* +* $Log: DefaultLogger.java,v $ +* Revision 1.2 2007/12/07 12:57:40 justb +* added log4j and make it the default logging method +* +* Revision 1.1 2007/11/23 21:10:17 justb +* add hooks for custom logging (you can override DefaultLogger in pushlet.properties) +* +* +* */ \ No newline at end of file diff --git a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/util/Log.java b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/util/Log.java index 3ce40153e7..ee6bd254d4 100644 --- a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/util/Log.java +++ b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/util/Log.java @@ -1,178 +1,178 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.util; - -import nl.justobjects.pushlet.core.Config; -import nl.justobjects.pushlet.core.ConfigDefs; - -/** - * Logging wrapper. - *

- * Provides a hook to direct logging to your own logging library. Override the DefaultLogger class by setting - * "logger.class" in pushlet.properties to your own logger - * to integrate your own logging library. - * - * @author Just van den Broecke - * @version $Id: Log.java,v 1.5 2007/12/07 12:57:40 justb Exp $ - */ -public class Log implements ConfigDefs { - /** - * Init with default to have at least some logging. - */ - private static PushletLogger logger = new DefaultLogger(); - - /** - * General purpose initialization. - */ - static public void init() { - try { - logger = (PushletLogger) Config.getClass(LOGGER_CLASS, "nl.justobjects.pushlet.util.DefaultLogger").newInstance(); - } catch (Throwable t) { - // Hmmm cannot log this since we don't have a log... - System.out.println("Cannot instantiate Logger from config ex=" + t); - return; - } - - logger.init(); - - // Set log level - logger.setLevel(Config.getIntProperty(Config.LOG_LEVEL)); - - logger.info("Logging intialized logger class=" + logger.getClass()); - } - - /** - * Log message for trace level. - * - * @param aMessage the message to be logged - */ - static public void trace(String aMessage) { - logger.debug(aMessage); - } - - /** - * Log message for debug level. - * - * @param aMessage the message to be logged - */ - static public void debug(String aMessage) { - logger.debug(aMessage); - } - - /** - * Log message for info level. - * - * @param aMessage the message to be logged - */ - static public void info(String aMessage) { - logger.info(aMessage); - } - - /** - * Log message for warning level. - * - * @param aMessage the message to be logged - */ - static public void warn(String aMessage) { - logger.warn(aMessage); - } - - /** - * Log message for warning level with exception. - * - * @param aMessage the message to be logged - * @param aThrowable the exception - */ - static public void warn(String aMessage, Throwable aThrowable) { - logger.warn(aMessage, aThrowable); - } - - /** - * Log message for error level. - * - * @param aMessage the message to be logged - */ - static public void error(String aMessage) { - logger.error(aMessage); - } - - /** - * Log message (error level with exception). - * - * @param aMessage the message to be logged - * @param aThrowable the exception - */ - static public void error(String aMessage, Throwable aThrowable) { - logger.error(aMessage, aThrowable); - } - - /** - * Log message for fatal level. - * - * @param aMessage the message to be logged - */ - static public void fatal(String aMessage) { - logger.fatal(aMessage); - } - - /** - * Log message (fatal level with exception). - * - * @param aMessage the message to be logged - * @param aThrowable the exception - */ - static public void fatal(String aMessage, Throwable aThrowable) { - logger.fatal(aMessage, aThrowable); - } - - /** - * Set log level - * - * @param aLevel the message to be logged - */ - static public void setLevel(int aLevel) { - logger.setLevel(aLevel); - } -} - -/* -* $Log: Log.java,v $ -* Revision 1.5 2007/12/07 12:57:40 justb -* added log4j and make it the default logging method -* -* Revision 1.4 2007/11/23 21:29:43 justb -* add hooks for custom logging (you can override DefaultLogger in pushlet.properties) -* -* Revision 1.3 2007/11/23 21:10:17 justb -* add hooks for custom logging (you can override DefaultLogger in pushlet.properties) -* -* Revision 1.2 2005/02/21 11:15:59 justb -* support log levels -* -* Revision 1.1 2005/02/18 10:07:23 justb -* many renamings of classes (make names compact) -* -* Revision 1.7 2004/09/03 22:35:37 justb -* Almost complete rewrite, just checking in now -* -* Revision 1.6 2004/08/12 13:16:08 justb -* make debug flag false -* -* Revision 1.5 2004/03/10 14:01:55 justb -* formatting and *Subscriber refactoring -* -* Revision 1.4 2003/08/15 09:54:46 justb -* fix javadoc warnings -* -* Revision 1.3 2003/08/15 08:37:40 justb -* fix/add Copyright+LGPL file headers and footers -* -* Revision 1.2 2003/08/12 09:42:47 justb -* enhancements -* -* Revision 1.1 2003/08/12 08:46:00 justb -* cvs comment tags added -* -* +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.util; + +import nl.justobjects.pushlet.core.Config; +import nl.justobjects.pushlet.core.ConfigDefs; + +/** + * Logging wrapper. + *

+ * Provides a hook to direct logging to your own logging library. Override the DefaultLogger class by setting + * "logger.class" in pushlet.properties to your own logger + * to integrate your own logging library. + * + * @author Just van den Broecke + * @version $Id: Log.java,v 1.5 2007/12/07 12:57:40 justb Exp $ + */ +public class Log implements ConfigDefs { + /** + * Init with default to have at least some logging. + */ + private static PushletLogger logger = new DefaultLogger(); + + /** + * General purpose initialization. + */ + static public void init() { + try { + logger = (PushletLogger) Config.getClass(LOGGER_CLASS, "nl.justobjects.pushlet.util.DefaultLogger").newInstance(); + } catch (Throwable t) { + // Hmmm cannot log this since we don't have a log... + System.out.println("Cannot instantiate Logger from config ex=" + t); + return; + } + + logger.init(); + + // Set log level + logger.setLevel(Config.getIntProperty(Config.LOG_LEVEL)); + + logger.info("Logging intialized logger class=" + logger.getClass()); + } + + /** + * Log message for trace level. + * + * @param aMessage the message to be logged + */ + static public void trace(String aMessage) { + logger.debug(aMessage); + } + + /** + * Log message for debug level. + * + * @param aMessage the message to be logged + */ + static public void debug(String aMessage) { + logger.debug(aMessage); + } + + /** + * Log message for info level. + * + * @param aMessage the message to be logged + */ + static public void info(String aMessage) { + logger.info(aMessage); + } + + /** + * Log message for warning level. + * + * @param aMessage the message to be logged + */ + static public void warn(String aMessage) { + logger.warn(aMessage); + } + + /** + * Log message for warning level with exception. + * + * @param aMessage the message to be logged + * @param aThrowable the exception + */ + static public void warn(String aMessage, Throwable aThrowable) { + logger.warn(aMessage, aThrowable); + } + + /** + * Log message for error level. + * + * @param aMessage the message to be logged + */ + static public void error(String aMessage) { + logger.error(aMessage); + } + + /** + * Log message (error level with exception). + * + * @param aMessage the message to be logged + * @param aThrowable the exception + */ + static public void error(String aMessage, Throwable aThrowable) { + logger.error(aMessage, aThrowable); + } + + /** + * Log message for fatal level. + * + * @param aMessage the message to be logged + */ + static public void fatal(String aMessage) { + logger.fatal(aMessage); + } + + /** + * Log message (fatal level with exception). + * + * @param aMessage the message to be logged + * @param aThrowable the exception + */ + static public void fatal(String aMessage, Throwable aThrowable) { + logger.fatal(aMessage, aThrowable); + } + + /** + * Set log level + * + * @param aLevel the message to be logged + */ + static public void setLevel(int aLevel) { + logger.setLevel(aLevel); + } +} + +/* +* $Log: Log.java,v $ +* Revision 1.5 2007/12/07 12:57:40 justb +* added log4j and make it the default logging method +* +* Revision 1.4 2007/11/23 21:29:43 justb +* add hooks for custom logging (you can override DefaultLogger in pushlet.properties) +* +* Revision 1.3 2007/11/23 21:10:17 justb +* add hooks for custom logging (you can override DefaultLogger in pushlet.properties) +* +* Revision 1.2 2005/02/21 11:15:59 justb +* support log levels +* +* Revision 1.1 2005/02/18 10:07:23 justb +* many renamings of classes (make names compact) +* +* Revision 1.7 2004/09/03 22:35:37 justb +* Almost complete rewrite, just checking in now +* +* Revision 1.6 2004/08/12 13:16:08 justb +* make debug flag false +* +* Revision 1.5 2004/03/10 14:01:55 justb +* formatting and *Subscriber refactoring +* +* Revision 1.4 2003/08/15 09:54:46 justb +* fix javadoc warnings +* +* Revision 1.3 2003/08/15 08:37:40 justb +* fix/add Copyright+LGPL file headers and footers +* +* Revision 1.2 2003/08/12 09:42:47 justb +* enhancements +* +* Revision 1.1 2003/08/12 08:46:00 justb +* cvs comment tags added +* +* */ \ No newline at end of file diff --git a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/util/Log4jLogger.java b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/util/Log4jLogger.java index d7ee1df832..ca96762621 100644 --- a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/util/Log4jLogger.java +++ b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/util/Log4jLogger.java @@ -1,134 +1,134 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.util; - -import org.apache.log4j.Level; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; - -/** - * Logger to use Log4j for logging. - *

- * Logs using Log4j. - * This class will require a log4j library in the classpath of the Pushlet. - * - * @author Uli Romahn - * @version $Id: Log4jLogger.java,v 1.1 2007/12/07 12:57:40 justb Exp $ - */ -public class Log4jLogger implements PushletLogger { - - /** - * Level intialized with default. - */ - private Logger logger = LogManager.getLogger("pushlet"); - - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#init() - */ - public void init() { - setLevel(LOG_LEVEL_INFO); - } - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#debug(java.lang.String) - */ - public void debug(String aMessage) { - if (!logger.isDebugEnabled()) { - return; - } - logger.debug(aMessage); - } - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#error(java.lang.String) - */ - public void error(String aMessage) { - logger.error(aMessage); - } - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#error(java.lang.String, java.lang.Throwable) - */ - public void error(String aMessage, Throwable aThrowable) { - logger.error(aMessage, aThrowable); - } - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#fatal(java.lang.String) - */ - public void fatal(String aMessage) { - logger.fatal(aMessage); - } - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#fatal(java.lang.String, java.lang.Throwable) - */ - public void fatal(String aMessage, Throwable aThrowable) { - logger.fatal(aMessage, aThrowable); - } - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#info(java.lang.String) - */ - public void info(String aMessage) { - if (!logger.isInfoEnabled()) { - return; - } - logger.info(aMessage); - } - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#trace(java.lang.String) - */ - public void trace(String aMessage) { - logger.trace(aMessage); - } - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#warn(java.lang.String) - */ - public void warn(String aMessage) { - logger.warn(aMessage); - } - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#warn(java.lang.String, java.lang.Throwable) - */ - public void warn(String aMessage, Throwable aThrowable) { - logger.warn(aMessage, aThrowable); - } - - /* (non-Javadoc) - * @see nl.justobjects.pushlet.util.PushletLogger#setLevel(int) - */ - public void setLevel(int aLevel) { - if (aLevel < LOG_LEVEL_FATAL) { - logger.setLevel(Level.OFF); - } else { - switch (aLevel) { - case LOG_LEVEL_FATAL: - logger.setLevel(Level.FATAL); - break; - case LOG_LEVEL_ERROR: - logger.setLevel(Level.ERROR); - break; - case LOG_LEVEL_WARN: - logger.setLevel(Level.WARN); - break; - case LOG_LEVEL_INFO: - logger.setLevel(Level.INFO); - break; - case LOG_LEVEL_DEBUG: - logger.setLevel(Level.DEBUG); - break; - case LOG_LEVEL_TRACE: - logger.setLevel(Level.TRACE); - break; - default: - logger.setLevel(Level.INFO); - } - } - } -} +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.util; + +import org.apache.log4j.Level; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; + +/** + * Logger to use Log4j for logging. + *

+ * Logs using Log4j. + * This class will require a log4j library in the classpath of the Pushlet. + * + * @author Uli Romahn + * @version $Id: Log4jLogger.java,v 1.1 2007/12/07 12:57:40 justb Exp $ + */ +public class Log4jLogger implements PushletLogger { + + /** + * Level intialized with default. + */ + private Logger logger = LogManager.getLogger("pushlet"); + + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#init() + */ + public void init() { + setLevel(LOG_LEVEL_INFO); + } + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#debug(java.lang.String) + */ + public void debug(String aMessage) { + if (!logger.isDebugEnabled()) { + return; + } + logger.debug(aMessage); + } + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#error(java.lang.String) + */ + public void error(String aMessage) { + logger.error(aMessage); + } + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#error(java.lang.String, java.lang.Throwable) + */ + public void error(String aMessage, Throwable aThrowable) { + logger.error(aMessage, aThrowable); + } + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#fatal(java.lang.String) + */ + public void fatal(String aMessage) { + logger.fatal(aMessage); + } + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#fatal(java.lang.String, java.lang.Throwable) + */ + public void fatal(String aMessage, Throwable aThrowable) { + logger.fatal(aMessage, aThrowable); + } + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#info(java.lang.String) + */ + public void info(String aMessage) { + if (!logger.isInfoEnabled()) { + return; + } + logger.info(aMessage); + } + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#trace(java.lang.String) + */ + public void trace(String aMessage) { + logger.trace(aMessage); + } + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#warn(java.lang.String) + */ + public void warn(String aMessage) { + logger.warn(aMessage); + } + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#warn(java.lang.String, java.lang.Throwable) + */ + public void warn(String aMessage, Throwable aThrowable) { + logger.warn(aMessage, aThrowable); + } + + /* (non-Javadoc) + * @see nl.justobjects.pushlet.util.PushletLogger#setLevel(int) + */ + public void setLevel(int aLevel) { + if (aLevel < LOG_LEVEL_FATAL) { + logger.setLevel(Level.OFF); + } else { + switch (aLevel) { + case LOG_LEVEL_FATAL: + logger.setLevel(Level.FATAL); + break; + case LOG_LEVEL_ERROR: + logger.setLevel(Level.ERROR); + break; + case LOG_LEVEL_WARN: + logger.setLevel(Level.WARN); + break; + case LOG_LEVEL_INFO: + logger.setLevel(Level.INFO); + break; + case LOG_LEVEL_DEBUG: + logger.setLevel(Level.DEBUG); + break; + case LOG_LEVEL_TRACE: + logger.setLevel(Level.TRACE); + break; + default: + logger.setLevel(Level.INFO); + } + } + } +} diff --git a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/util/PushletLogger.java b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/util/PushletLogger.java index c3853369ba..e70bc68703 100644 --- a/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/util/PushletLogger.java +++ b/sw/in_progress/pow/pow/src/nl/justobjects/pushlet/util/PushletLogger.java @@ -1,94 +1,94 @@ -// Copyright (c) 2000 Just Objects B.V. -// Distributable under LGPL license. See terms of license at gnu.org. - -package nl.justobjects.pushlet.util; - -import nl.justobjects.pushlet.core.ConfigDefs; - -/** - * Logger interface to allow different logging providers. - *

- * - * @author Ulrich Romahn - * @version $Id: PushletLogger.java,v 1.1 2007/12/07 12:57:40 justb Exp $ - */ -public interface PushletLogger extends ConfigDefs { - - /** - * Method allowing to initialize our logger - */ - public void init(); - - /** - * Log message for trace level. - * - * @param aMessage the message to be logged - */ - public void trace(String aMessage); - - /** - * Log message for debug level. - * - * @param aMessage the message to be logged - */ - public void debug(String aMessage); - - /** - * Log message for info level. - * - * @param aMessage the message to be logged - */ - public void info(String aMessage); - - /** - * Log message for warning level. - * - * @param aMessage the message to be logged - */ - public void warn(String aMessage); - - /** - * Log message for warning level with exception. - * - * @param aMessage the message to be logged - * @param aThrowable the exception - */ - public void warn(String aMessage, Throwable aThrowable); - - /** - * Log message for error level. - * - * @param aMessage the message to be logged - */ - public void error(String aMessage); - - /** - * Log message (error level with exception). - * - * @param aMessage the message to be logged - * @param aThrowable the exception - */ - public void error(String aMessage, Throwable aThrowable); - - /** - * Log message for fatal level. - * - * @param aMessage the message to be logged - */ - public void fatal(String aMessage); - - /** - * Log message (fatal level with exception). - * - * @param aMessage the message to be logged - * @param aThrowable the exception - */ - public void fatal(String aMessage, Throwable aThrowable); - - /** - * Set log level - * - * @param aLevel a valid Level from ConfigDefs - */ - public void setLevel(int aLevel); -} +// Copyright (c) 2000 Just Objects B.V. +// Distributable under LGPL license. See terms of license at gnu.org. + +package nl.justobjects.pushlet.util; + +import nl.justobjects.pushlet.core.ConfigDefs; + +/** + * Logger interface to allow different logging providers. + *

+ * + * @author Ulrich Romahn + * @version $Id: PushletLogger.java,v 1.1 2007/12/07 12:57:40 justb Exp $ + */ +public interface PushletLogger extends ConfigDefs { + + /** + * Method allowing to initialize our logger + */ + public void init(); + + /** + * Log message for trace level. + * + * @param aMessage the message to be logged + */ + public void trace(String aMessage); + + /** + * Log message for debug level. + * + * @param aMessage the message to be logged + */ + public void debug(String aMessage); + + /** + * Log message for info level. + * + * @param aMessage the message to be logged + */ + public void info(String aMessage); + + /** + * Log message for warning level. + * + * @param aMessage the message to be logged + */ + public void warn(String aMessage); + + /** + * Log message for warning level with exception. + * + * @param aMessage the message to be logged + * @param aThrowable the exception + */ + public void warn(String aMessage, Throwable aThrowable); + + /** + * Log message for error level. + * + * @param aMessage the message to be logged + */ + public void error(String aMessage); + + /** + * Log message (error level with exception). + * + * @param aMessage the message to be logged + * @param aThrowable the exception + */ + public void error(String aMessage, Throwable aThrowable); + + /** + * Log message for fatal level. + * + * @param aMessage the message to be logged + */ + public void fatal(String aMessage); + + /** + * Log message (fatal level with exception). + * + * @param aMessage the message to be logged + * @param aThrowable the exception + */ + public void fatal(String aMessage, Throwable aThrowable); + + /** + * Set log level + * + * @param aLevel a valid Level from ConfigDefs + */ + public void setLevel(int aLevel); +} diff --git a/sw/in_progress/pow/pow/src/pow/BusIvy_.java b/sw/in_progress/pow/pow/src/pow/BusIvy_.java index af35fb6f00..9d32edf17f 100644 --- a/sw/in_progress/pow/pow/src/pow/BusIvy_.java +++ b/sw/in_progress/pow/pow/src/pow/BusIvy_.java @@ -1,61 +1,61 @@ -package pow; -import java.io.*; -import java.net.*; -import java.util.*; -import java.util.Calendar; -/** - * - * inner representation of an ivy bus - * store the drones' information about the drones which belong to this ivy bus - * store the IP adresse of the machine where the ivy bus is working - */ -public class BusIvy_ -{ - private Calendar oCalendar; - private long oTime; - private InetAddress busAddress; - private ArrayList DronesId = new ArrayList(); - - public void setAddress(InetAddress myInetAddress) - { - busAddress = myInetAddress; - } - public void updateTime() - { - oCalendar=Calendar.getInstance(); - oTime = oCalendar.getTimeInMillis(); - } - public void addDrones(int newDroneId) - { - DronesId.add(newDroneId); - } - public ArrayList getDrones() - { - return DronesId; - } - public void displayDrones() - { - System.out.println("Bus Ivy : "); - System.out.println(busAddress); - System.out.println("Drones : "); - for(Integer myDrone : DronesId) - { - System.out.println(DronesId); - } - } - public InetAddress getAddress() - { - return busAddress; - } - public boolean isOwnBy(int myDroneId) - { - return DronesId.contains(myDroneId); - } - public boolean isAlive() - { - Calendar iCalendar = Calendar.getInstance(); - long iTime = iCalendar.getTimeInMillis(); - - return ((iTime - oTime)<10000); // 10 secondes - } +package pow; +import java.io.*; +import java.net.*; +import java.util.*; +import java.util.Calendar; +/** + * + * inner representation of an ivy bus + * store the drones' information about the drones which belong to this ivy bus + * store the IP adresse of the machine where the ivy bus is working + */ +public class BusIvy_ +{ + private Calendar oCalendar; + private long oTime; + private InetAddress busAddress; + private ArrayList DronesId = new ArrayList(); + + public void setAddress(InetAddress myInetAddress) + { + busAddress = myInetAddress; + } + public void updateTime() + { + oCalendar=Calendar.getInstance(); + oTime = oCalendar.getTimeInMillis(); + } + public void addDrones(int newDroneId) + { + DronesId.add(newDroneId); + } + public ArrayList getDrones() + { + return DronesId; + } + public void displayDrones() + { + System.out.println("Bus Ivy : "); + System.out.println(busAddress); + System.out.println("Drones : "); + for(Integer myDrone : DronesId) + { + System.out.println(DronesId); + } + } + public InetAddress getAddress() + { + return busAddress; + } + public boolean isOwnBy(int myDroneId) + { + return DronesId.contains(myDroneId); + } + public boolean isAlive() + { + Calendar iCalendar = Calendar.getInstance(); + long iTime = iCalendar.getTimeInMillis(); + + return ((iTime - oTime)<10000); // 10 secondes + } } \ No newline at end of file diff --git a/sw/in_progress/pow/pow/src/pow/Conf.java b/sw/in_progress/pow/pow/src/pow/Conf.java index c3932d7c23..4724511868 100644 --- a/sw/in_progress/pow/pow/src/pow/Conf.java +++ b/sw/in_progress/pow/pow/src/pow/Conf.java @@ -1,231 +1,231 @@ -package pow; -import java.io.*; -/** - * - * store usefull datas about the server configuration - * reading a specific file on the tomcat server - */ -public class Conf { - - - private String mailAdmin; - private String adminLogin; - /** - * The port in which the module listen. - */ - private int port; - /** - * The dimension of the datagrams received. - */ - private int taille; - /** - * The passWord of the database - */ - private String passWord; - /** - * The userName of the dataBase - */ - private String userName; - /** - * The Name of the dataBase - */ - private String dataBaseName; - /** - * The timeout of the connection - */ - private int timeout; - /** - * The repertory of configuration files - */ - private String flightPlanRep; - /** - * The port in which msg from web are sended to ivy - */ - private int portWebToIvy ; - - public Conf() - { - File oFile = null; - FileReader oFileReader = null; - BufferedReader oBufferedReader = null; - String fileName = "pow.conf"; - - String line; - - try - { - - oFile = new File("./conf/" + fileName); - //oFile = new File("./" + fileName); - oFileReader = new FileReader(oFile); - oBufferedReader = new BufferedReader(oFileReader); - - while((line = oBufferedReader.readLine())!=null) - { - if( (!(line.startsWith("#")))&&(line.length()!= 0) ) - { - if(line.startsWith(""))); - } - if(line.startsWith(""))); - } - if(line.startsWith("")); - } - if(line.startsWith("")); - } - if(line.startsWith("")); - } - if(line.startsWith(""))); - } - if(line.startsWith("")); - } - if(line.startsWith("")); - } - if(line.startsWith("")); - } - if(line.startsWith(""))); - } - } - } - } - catch(IOException ex) - { - System.out.println("No conf file detected"); - ex.printStackTrace(); - } - - } - - public Conf(String default_folder,String conf_filename) - { - File oFile = null; - FileReader oFileReader = null; - BufferedReader oBufferedReader = null; - String fileName = conf_filename; - - String line; - - try - { - - oFile = new File(default_folder+"/conf/" + fileName); - //oFile = new File("./" + fileName); - oFileReader = new FileReader(oFile); - oBufferedReader = new BufferedReader(oFileReader); - - while((line = oBufferedReader.readLine())!=null) - { - if( (!(line.startsWith("#")))&&(line.length()!= 0) ) - { - if(line.startsWith(""))); - } - if(line.startsWith(""))); - } - if(line.startsWith("")); - } - if(line.startsWith("")); - } - if(line.startsWith("")); - } - if(line.startsWith(""))); - } - if(line.startsWith("")); - } - if(line.startsWith("")); - } - if(line.startsWith("")); - } - if(line.startsWith(""))); - } - } - } - } - catch(IOException ex) - { - System.out.println("No conf file detected"); - ex.printStackTrace(); - } - } - - public int port() - { - return port; - } - - public int portWebToIvy() - { - return portWebToIvy; - } - public int taille() - { - return taille; - } - public String passWord() - { - return passWord; - } - public String userName() - { - return userName; - } - public String dataBaseName() - { - return dataBaseName; - } - public int timeout() - { - return timeout; - } - public String flightPlanRep() - { - return flightPlanRep; - } - - public String mailAdmin() - { - return mailAdmin; - } - - public String adminLogin(){ - return adminLogin; - } +package pow; +import java.io.*; +/** + * + * store usefull datas about the server configuration + * reading a specific file on the tomcat server + */ +public class Conf { + + + private String mailAdmin; + private String adminLogin; + /** + * The port in which the module listen. + */ + private int port; + /** + * The dimension of the datagrams received. + */ + private int taille; + /** + * The passWord of the database + */ + private String passWord; + /** + * The userName of the dataBase + */ + private String userName; + /** + * The Name of the dataBase + */ + private String dataBaseName; + /** + * The timeout of the connection + */ + private int timeout; + /** + * The repertory of configuration files + */ + private String flightPlanRep; + /** + * The port in which msg from web are sended to ivy + */ + private int portWebToIvy ; + + public Conf() + { + File oFile = null; + FileReader oFileReader = null; + BufferedReader oBufferedReader = null; + String fileName = "pow.conf"; + + String line; + + try + { + + oFile = new File("./conf/" + fileName); + //oFile = new File("./" + fileName); + oFileReader = new FileReader(oFile); + oBufferedReader = new BufferedReader(oFileReader); + + while((line = oBufferedReader.readLine())!=null) + { + if( (!(line.startsWith("#")))&&(line.length()!= 0) ) + { + if(line.startsWith(""))); + } + if(line.startsWith(""))); + } + if(line.startsWith("")); + } + if(line.startsWith("")); + } + if(line.startsWith("")); + } + if(line.startsWith(""))); + } + if(line.startsWith("")); + } + if(line.startsWith("")); + } + if(line.startsWith("")); + } + if(line.startsWith(""))); + } + } + } + } + catch(IOException ex) + { + System.out.println("No conf file detected"); + ex.printStackTrace(); + } + + } + + public Conf(String default_folder,String conf_filename) + { + File oFile = null; + FileReader oFileReader = null; + BufferedReader oBufferedReader = null; + String fileName = conf_filename; + + String line; + + try + { + + oFile = new File(default_folder+"/conf/" + fileName); + //oFile = new File("./" + fileName); + oFileReader = new FileReader(oFile); + oBufferedReader = new BufferedReader(oFileReader); + + while((line = oBufferedReader.readLine())!=null) + { + if( (!(line.startsWith("#")))&&(line.length()!= 0) ) + { + if(line.startsWith(""))); + } + if(line.startsWith(""))); + } + if(line.startsWith("")); + } + if(line.startsWith("")); + } + if(line.startsWith("")); + } + if(line.startsWith(""))); + } + if(line.startsWith("")); + } + if(line.startsWith("")); + } + if(line.startsWith("")); + } + if(line.startsWith(""))); + } + } + } + } + catch(IOException ex) + { + System.out.println("No conf file detected"); + ex.printStackTrace(); + } + } + + public int port() + { + return port; + } + + public int portWebToIvy() + { + return portWebToIvy; + } + public int taille() + { + return taille; + } + public String passWord() + { + return passWord; + } + public String userName() + { + return userName; + } + public String dataBaseName() + { + return dataBaseName; + } + public int timeout() + { + return timeout; + } + public String flightPlanRep() + { + return flightPlanRep; + } + + public String mailAdmin() + { + return mailAdmin; + } + + public String adminLogin(){ + return adminLogin; + } } \ No newline at end of file diff --git a/sw/in_progress/pow/pow/src/pow/log.java b/sw/in_progress/pow/pow/src/pow/log.java index 3d93e5a685..c9696309a0 100644 --- a/sw/in_progress/pow/pow/src/pow/log.java +++ b/sw/in_progress/pow/pow/src/pow/log.java @@ -1,69 +1,69 @@ -package pow; -import java.io.*; -import java.util.Calendar; -/** - * Handles the writing of a log in a file - * @author genin - * - */ -public class log { - - private File oFile = null; - private FileWriter oFileWriter = null; - private BufferedWriter oBufferedWriter = null; - - public log(String path) - { - Calendar Today = Calendar.getInstance(); - String fileName = String.valueOf(Today.get(Calendar.DAY_OF_MONTH)) + - String.valueOf(Today.get(Calendar.MONTH)) + - String.valueOf(Today.get(Calendar.YEAR)) + - String.valueOf(Today.get(Calendar.HOUR_OF_DAY)) + - String.valueOf(Today.get(Calendar.MINUTE)) + - String.valueOf(Today.get(Calendar.SECOND)) + - ".log"; - - try - { - oFile = new File(path+"/log/" + fileName); - //System.out.println("log file to be created "); - oFile.createNewFile(); - //System.out.println("log file created "); - oFileWriter = new FileWriter(oFile); - oBufferedWriter = new BufferedWriter(oFileWriter); - - oBufferedWriter.write("##########################################"); oBufferedWriter.newLine(); - oBufferedWriter.write("########## PAPARAZZI ON THE WEB ##########"); oBufferedWriter.newLine(); - oBufferedWriter.write("##########################################"); oBufferedWriter.newLine(); - oBufferedWriter.newLine(); - oBufferedWriter.write("Beginning of log : "); oBufferedWriter.newLine(); - oBufferedWriter.newLine(); - oBufferedWriter.flush(); - } - catch(IOException ex) - { - System.out.println("No log file created "); - ex.printStackTrace(); - } - } - - public void write(String writing) - { - Calendar Now = Calendar.getInstance(); - String Time = String.valueOf(Now.get(Calendar.HOUR_OF_DAY)) + ":" + - String.valueOf(Now.get(Calendar.MINUTE)) + ":" + - String.valueOf(Now.get(Calendar.SECOND)); - writing = writing.trim(); - try - { - oBufferedWriter.write(Time + " -> " + writing); oBufferedWriter.newLine(); - oBufferedWriter.flush(); - System.out.println("log at : " + Time + " -> " + writing); - } - catch(IOException ex) - { - System.out.println(ex.getMessage()); - } - - } +package pow; +import java.io.*; +import java.util.Calendar; +/** + * Handles the writing of a log in a file + * @author genin + * + */ +public class log { + + private File oFile = null; + private FileWriter oFileWriter = null; + private BufferedWriter oBufferedWriter = null; + + public log(String path) + { + Calendar Today = Calendar.getInstance(); + String fileName = String.valueOf(Today.get(Calendar.DAY_OF_MONTH)) + + String.valueOf(Today.get(Calendar.MONTH)) + + String.valueOf(Today.get(Calendar.YEAR)) + + String.valueOf(Today.get(Calendar.HOUR_OF_DAY)) + + String.valueOf(Today.get(Calendar.MINUTE)) + + String.valueOf(Today.get(Calendar.SECOND)) + + ".log"; + + try + { + oFile = new File(path+"/log/" + fileName); + //System.out.println("log file to be created "); + oFile.createNewFile(); + //System.out.println("log file created "); + oFileWriter = new FileWriter(oFile); + oBufferedWriter = new BufferedWriter(oFileWriter); + + oBufferedWriter.write("##########################################"); oBufferedWriter.newLine(); + oBufferedWriter.write("########## PAPARAZZI ON THE WEB ##########"); oBufferedWriter.newLine(); + oBufferedWriter.write("##########################################"); oBufferedWriter.newLine(); + oBufferedWriter.newLine(); + oBufferedWriter.write("Beginning of log : "); oBufferedWriter.newLine(); + oBufferedWriter.newLine(); + oBufferedWriter.flush(); + } + catch(IOException ex) + { + System.out.println("No log file created "); + ex.printStackTrace(); + } + } + + public void write(String writing) + { + Calendar Now = Calendar.getInstance(); + String Time = String.valueOf(Now.get(Calendar.HOUR_OF_DAY)) + ":" + + String.valueOf(Now.get(Calendar.MINUTE)) + ":" + + String.valueOf(Now.get(Calendar.SECOND)); + writing = writing.trim(); + try + { + oBufferedWriter.write(Time + " -> " + writing); oBufferedWriter.newLine(); + oBufferedWriter.flush(); + System.out.println("log at : " + Time + " -> " + writing); + } + catch(IOException ex) + { + System.out.println(ex.getMessage()); + } + + } } \ No newline at end of file