commit 69e0600052551c8b23b6cf0790a283b9cd00f107 Author: moparisthebest Date: Tue Apr 15 13:40:50 2014 -0400 Initial import of https://svn.apache.org/repos/asf/beehive/tags/v1.0.2 diff --git a/BUILDING.txt b/BUILDING.txt new file mode 100644 index 0000000..1149cf3 --- /dev/null +++ b/BUILDING.txt @@ -0,0 +1,177 @@ + +Welcome to Beehive +================== + +To build Beehive, you will first need to check the source out from +Apache SVN and then install / configure required external software and +your shell environment. + +Checkout Beehive from SVN +========================= + +To do this, run the command: + + svn checkout https://svn.apache.org/repos/asf/beehive/trunk + +After running this command, you should have a directory "trunk/" which +contains the current Beehive source. If you ran this command in: + + d:\java\beehive + +you should have the directory: + + d:\java\beehive\trunk + +In the following steps, we'll refer to this as ${beehive.home}. + +Install / configure external software and setup your shell +========================================================== + +1) Java 5 + + Download: http://java.sun.com/j2se/1.5.0/download.jsp + + Install Java 5 and set the JAVA_HOME environment variable to +refernce the JDK install directory. Ensure that $JAVA_HOME/bin is +available in your $PATH. + +2) Ant 1.6.2+ + + Download: http://ant.apache.org/bindownload.cgi + + Ant 1.6.2 is the minimum version required to build Beehive. Install +Ant 1.6.2 and set the ANT_HOME environment variable to reference the +Ant install directory. Ensure that $ANT_HOME/bin is available in your +$PATH. Copy junit.jar (in external/junit/) to $ANT_HOME/lib. This step is +required in order for the Ant tasks to work correctly. + +3) Tomcat 5.0.x + + Download: http://jakarta.apache.org/site/binindex.cgi#tomcat + + Tomcat is used as the default test environment for Beehive. Install +Tomcat and set the CATALINA_HOME environment variable to reference the +Tomcat install directory. If you're installing Tomcat on Linux, +be sure to set the execute bit on the shell scripts in $CATALINA_HOME/bin. + + If you installed these into d:\java, your environment variables +might look something like: + + JAVA_HOME=d:\java\jdk1.5.0 + CATALINA_HOME=d:\java\jakarta-tomcat-5.0.25 + ANT_HOME=d:\java\apache-ant-1.6.2 + +Configure installed products + +In order to run the Beehive tests, ensure that Tomcat has the the +"manager" role is defined in ${CATALINA_HOME}/conf/tomcat-users.xml +with a "manager" role and manager username/password of manager/manager. +This step is required in order to use the Tomcat Ant tasks to deploy +applications to Tomcat. An example of this file is available here: + + ${beehive.home}/test/conf/tomcat-users.xml + +In the following examples, '$>' is your propmpt at $BEEHIVE_HOME, so if +you see '$>ant', type 'ant' (without the quotes) and press [enter]. + +In addition to the external software installed above, Beehive requires +one additional JAR to provide JSR 173 support for StAX, which is +required by XMLBeans. This JAR is downloaded from the network when +running Beehive's "bootstrap" target, so be sure to have a network +connection for your first build. A network connection is not required +for any subsequent builds. To install the JSR 173 API, run: + + $>ant bootstrap + +To check your Beehive build setup, run: + + $>ant check.setup + +This should end with "BUILD SUCCESSFUL" if you see any failures, be +sure to re-check your setup steps above. + +To build Beehive, run: + + $>ant clean deploy + +To run the Beehive tests, run: + + $>ant drt + +Using Proxies With a Beehive Build +==================================== + +If you need to use proxies you can setup additional environment variables +so that the Ant "bootstrap" target is successful in downloading the +JSR 173 API JAR file. + +PROXYHOST= +PROXYPORT= +PROXYUSER= +PROXYPASSWORD= +NONPROXYHOSTS= +SOCKSPROXYHOST= +SOCKSPROXYPORT= + +At a minimum, you will need to set PROXYHOST and PROXYPORT if your +network environment requires a proxy connection. To set these +environment variables in your shell, run: + + set PROXYHOST= + +in a Windows shell and + + export PROXYHOST= + +in a UNIX shell. + +For information on proxy support using the task, please +visit http://ant.apache.org/manual/OptionalTasks/setproxy.html + +Building Beehive documentation +============================= +The following documentation-related targets in +beehive/trunk/build.xml require that you have +Apache Forrest installed locally: + + $>ant docs + $>ant build.dist + +Before running these targets, complete the following steps. + +1) Download and install Forrest 0.7 on your machine. +A list of available download locations is available at: + + http://forrest.apache.org/mirrors.cgi + + +2) Copy the JAR file + + apache-forrest-0.7/lib/core/xml-commons-resolver-1.1.jar + +into + + $ANT_HOME/lib + +(This allows the Ant targets to call Forrest tasks.) + +3) Ensure that FORREST_HOME is set to the following path. + + On Windows machines: + set FORREST_HOME=C:\MyApacheStuff\apache-forrest-0.7 + + On Unix machines: + export FORREST_HOME=/MyApacheStuff/apache-forrest-0.7 + +4) Set the PATH as follows: + + On Windows machines: + set PATH=%FORREST_HOME%\bin;%PATH% + + On Unix machines: + export PATH=$FORREST_HOME/bin:$PATH + +You are now ready to run these targets: + + $>ant docs + $>ant build.dist diff --git a/DEVELOPING.txt b/DEVELOPING.txt new file mode 100644 index 0000000..5305f28 --- /dev/null +++ b/DEVELOPING.txt @@ -0,0 +1,83 @@ + +Developing in Beehive +===================== + +Hey; we're glad you're here! If you're interested in developing Beehive, the +information below is for you. First, make sure you've read the introduction +for Beehive contributors here: + + http://wiki.apache.org/beehive/For_Beehive_Developers + +This should help you get started setting up Beehive in your IDE and navigating +what code is where. + +You'll also need to configure your Subversion client to handle end-of-line styles +correctly. To do this, follow the directions below. + +Configuring your Subversion client +================================== + +Every text file must have the svn:eol-style property set to 'native'. This +causes ends-of-line to be translated to the correct format for the local +operating system when files are checked out (e.g., LF on linux, CR/LF on +Windows). You can do this on a per-file basis using the 'svn propset' command: + + svn propset svn:eol-style native + +An easier way to ensure that all added files have the right properties set is +to use the "auto-props" feature in the SVN client configuration file. The +location of this file varies depending on the operating system (see +http://svnbook.red-bean.com/svnbook/book.html#svn-ch-7-sect-1). +On Linux/UNIX it is located: + + ~/.subversion/config + +On Windows, it is typically located in a hidden directory: + + %SYSROOT%\Documents and Settings\\Application Data\Subversion +If you have problems locating this, make sure you can view hidden directory +contents. + +Confirm the "header" named [miscellany] is uncommented. + +Then, add (uncomment) the following line under the "[miscellany]" section: + + enable-auto-props = yes + +Then, add (uncomment) an "[auto-props]" section (include the [auto-props] +header as well) with a list of file extensions that will automatically +trigger the svn:eol-style=native property: + +[auto-props] +*.txt = svn:eol-style=native +*.java = svn:eol-style=native +*.jj = svn:eol-style=native +*.xml = svn:eol-style=native +*.xsd = svn:eol-style=native +*.xsdconfig = svn:eol-style=native +*.dtd = svn:eol-style=native +*.properties = svn:eol-style=native +*.jcs = svn:eol-style=native +*.jcx = svn:eol-style=native +*.jpf = svn:eol-style=native +*.jpfs = svn:eol-style=native +Global.app = svn:eol-style=native +*.jsp* = svn:eol-style=native +*.jspx = svn:eol-style=native +*.jspf = svn:eol-style=native +*.jsf = svn:eol-style=native +*.jsfb = svn:eol-style=native +*.faces = svn:eol-style=native +*.tld = svn:eol-style=native +*.tldx = svn:eol-style=native +*.tag = svn:eol-style=native +*.tagf = svn:eol-style=native +*.html = svn:eol-style=native +*.css = svn:eol-style=native +*.js = svn:eol-style=native +*.inc = svn:eol-style=native +*.sh = svn:eol-style=native;svn:executable +*.cmd = svn:eol-style=native +*.pl = svn:eol-style=native +*.py = svn:eol-style=native +*.beaninfo = svn:eol-style=native \ No newline at end of file diff --git a/LICENSE.jsr173-api b/LICENSE.jsr173-api new file mode 100644 index 0000000..76890a9 --- /dev/null +++ b/LICENSE.jsr173-api @@ -0,0 +1,43 @@ +BEA Systems, Inc. ("BEA") +Binary Code License Agreement +JSR 173 "Streaming API for XML" - Reference Implementation + +READ THE TERMS OF THIS AGREEMENT AND ANY PROVIDED SUPPLEMENTAL LICENSE TERMS (COLLECTIVELY "AGREEMENT") CAREFULLY BEFORE OPENING THE SOFTWARE MEDIA PACKAGE.  BY OPENING THE SOFTWARE MEDIA PACKAGE, YOU AGREE TO THE TERMS OF THIS AGREEMENT.  IF YOU ARE ACCESSING THE SOFTWARE ELECTRONICALLY, INDICATE YOUR ACCEPTANCE OF THESE TERMS BY SELECTING THE "ACCEPT" BUTTON AT THE END OF THIS AGREEMENT.  IF YOU DO NOT AGREE TO ALL THESE TERMS, PROMPTLY RETURN THE UNUSED SOFTWARE TO YOUR PLACE OF PURCHASE FOR A REFUND OR, IF THE SOFTWARE IS ACCESSED ELECTRONICALLY, SELECT THE "DECLINE" BUTTON AT THE END OF THIS AGREEMENT. + +1.  LICENSE TO USE.  BEA grants you a non-exclusive and non-transferable, royalty-free license for the internal use only of the accompanying software and documentation and any error corrections provided by BEA (collectively "Software"). + +2.  RESTRICTIONS.  Software is confidential and copyrighted. Title to Software and all associated intellectual property rights is retained by BEA and/or its licensors.  Except as specifically authorized in any Supplemental License Terms, you may not make copies of Software, other than a single copy of Software for archival purposes.  Unless enforcement is prohibited by applicable law, you may not modify, decompile, or reverse engineer Software.  Licensee acknowledges that Licensed Software is not designed or intended for use in the design, construction, operation or maintenance of any nuclear facility. BEA disclaims any express or implied warranty of fitness for such uses.   No right, title or interest in or to any trademark, service mark, logo or trade name of BEA or its licensors is granted under this Agreement. + +3. LIMITED WARRANTY.  BEA warrants to you that for a period of ninety (90) days from the date of purchase, as evidenced by a copy of the receipt, the media on which Software is furnished (if any) will be free of defects in materials and workmanship under normal use.  Except for the foregoing, Software is provided "AS IS".  Your exclusive remedy and BEA's entire liability under this limited warranty will be at BEA's option to replace Software media or refund the fee paid for Software. + +4.  DISCLAIMER OF WARRANTY.  UNLESS SPECIFIED IN THIS AGREEMENT, ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT ARE DISCLAIMED, EXCEPT TO THE EXTENT THAT THESE DISCLAIMERS ARE HELD TO BE LEGALLY INVALID. + +5.  LIMITATION OF LIABILITY.  TO THE EXTENT NOT PROHIBITED BY LAW, IN NO EVENT WILL BEA OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR SPECIAL, INDIRECT, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF OR RELATED TO THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF BEA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.  In no event will BEA's liability to you, whether in contract, tort (including negligence), or otherwise, exceed the amount paid by you for Software under this Agreement.  The foregoing limitations will apply even if the above stated warranty fails of its essential purpose. + +6.  Termination.  This Agreement is effective until terminated.  You may terminate this Agreement at any time by destroying all copies of Software.  This Agreement will terminate immediately without notice from BEA if you fail to comply with any provision of this Agreement.  Upon Termination, you must destroy all copies of Software. + +7. Export Regulations. All Software and technical data delivered under this Agreement are subject to US export control laws and may be subject to export or import regulations in other countries.  You agree to comply strictly with all such laws and regulations and acknowledge that you have the responsibility to obtain such licenses to export, re-export, or import as may be required after delivery to you. + +8.  U.S. Government Restricted Rights.  If Software is being acquired by or on behalf of the U.S. Government or by a U.S. Government prime contractor or subcontractor (at any tier), then the Government's rights in Software and accompanying documentation will be only as set forth in this Agreement; this is in accordance with 48 CFR 227.7201 through 227.7202-4 (for Department of Defense (DOD) acquisitions) and with 48 CFR 2.101 and 12.212 (for non-DOD acquisitions). + +9.  Governing Law.  Any action related to this Agreement will be governed by California law and controlling U.S. federal law.  No choice of law rules of any jurisdiction will apply. + +10. Severability. If any provision of this Agreement is held to be unenforceable, this Agreement will remain in effect with the provision omitted, unless omission would frustrate the intent of the parties, in which case this Agreement will immediately terminate. + +11. Integration.  This Agreement is the entire agreement between you and BEA relating to its subject matter.  It supersedes all prior or contemporaneous oral or written communications, proposals, representations and warranties and prevails over any conflicting or additional terms of any quote, order, acknowledgment, or other communication between the parties relating to its subject matter during the term of this Agreement.  No modification of this Agreement will be binding, unless in writing and signed by an authorized representative of each party. + +JSR 173, REFERENCE IMPLEMENTATION +SUPPLEMENTAL LICENSE TERMS + +These supplemental license terms ("Supplemental Terms") add to or modify the terms of the Binary Code License Agreement (collectively, the "Agreement"). Capitalized terms not defined in these Supplemental Terms shall have the same meanings ascribed to them in the Agreement. These Supplemental Terms shall supersede any inconsistent or conflicting terms in the Agreement, or in any license contained within the Software. + +1. Software Internal Use and Development License Grant. Subject to the terms and conditions of this Agreement, BEA grants you a non-exclusive, non-transferable, limited license to reproduce internally and use internally the binary form of the Software, complete and unmodified, for the sole purpose of designing, developing and testing your Java applets and applications ("Programs"). + +2. License to Distribute Software.  In addition to the license granted in Section 1 (Software Internal Use and Development License Grant) of these Supplemental Terms, subject to the terms and conditions of this Agreement, BEA grants you a non-exclusive, non-transferable, limited license to reproduce and distribute the Software in binary form only, provided that you (i) distribute the Software complete and unmodified and only bundled as part of your Programs, (ii) do not distribute additional software intended to replace any component(s) of the Software, (iii) do not remove or alter any proprietary legends or notices contained in the Software, (iv) only distribute the Software subject to a license agreement that protects BEA's and its licensor� interests consistent with the terms contained in this Agreement, and (v) agree to defend and indemnify BEA and its licensors from and against any damages, costs, liabilities, settlement amounts and/or expenses (including attorneys' fees) incurred in connection with any claim, lawsuit or action by any third party that arises or results from the use or distribution of any and all Programs and/or Software. + +3. Source Code. Software may contain source code that is provided solely for reference purposes pursuant to the terms of this Agreement.  Such source code may not be redistributed unless expressly provided for in this Agreement. + +4. Termination for Infringement.  Either party may terminate this Agreement immediately should any Software become, or in either party's opinion be likely to become, the subject of a claim of infringement of any intellectual property right. + +For inquiries please contact: BEA Systems, Inc., 2315 North First Street, San Jose, CA 95131. + diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..5adf2ca --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,252 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +============================================ + Licenses for Included Dependencies +============================================ + +The exceptions are as follows: + +============================================ + org/apache/beehive/netui/util/internal/concurrent/** +============================================ + + "Sun hereby grants you a non-exclusive, worldwide, non-transferrable + license to use and distribute the Java Software technologies as part + of a larger work in source and binary forms, with or without + modification, provided that the following conditions are met: + + -Neither the name of or trademarks of Sun may be used to endorse or + promote products derived from the Java Software technology without + specific prior written permission. + + -Redistributions of source or binary code must be accompanied by the + following notice and disclaimers: + + Portions copyright Sun Microsystems, Inc. Used with kind permission. + + This software is provided AS IS, without a warranty of any kind. ALL + EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PUPOSE OR + NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + MICROSYSTEMS, INC. AND ITS LICENSORS SHALL NOT BE LIABLE + FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + USING, MODIFYING OR DISTRIBUTING THE SOFTWARE OR ITS + DERIVATIVES. IN NO EVENT WILL SUN MICROSYSTEMS, INC. OR + ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR + DATA, OR FOR DIRECT, INDIRECT,CONSQUENTIAL, INCIDENTAL + OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF + THE THEORY OR LIABILITY, ARISING OUT OF THE USE OF OR + INABILITY TO USE SOFTWARE, EVEN IF SUN MICROSYSTEMS, INC. + HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + + You acknowledge that Software is not designed, licensed or intended for + use in the design, construction, operation or maintenance of any nuclear + facility." + +============================================ + Spring Framework 1.1.5 +============================================ + + Licensed under terms of the Apache Software License (ASL) 2.0, provided above. \ No newline at end of file diff --git a/NOTICE.txt b/NOTICE.txt new file mode 100644 index 0000000..0469c6f --- /dev/null +++ b/NOTICE.txt @@ -0,0 +1,34 @@ +========================================================================= +== NOTICE file corresponding to section 4(d) of the Apache License, == +== Version 2.0, in this case for the Apache Beehive distribution. == +========================================================================= + +This product includes software developed by +The Apache Software Foundation (http://www.apache.org/). + +Portions of this software were originally based on the following: + + * software copyright (c) 2000-2003, BEA Systems, . +and are licensed to the Apache Software Foundation under the +"Software Grant and Corporate Contribution License Agreement" + +Aside from contributions to the Apache Beehive project, this +software also includes: + + * One or more JARs from the Jakarta Commons, Jakarta ORO, Log4J, + Struts, and Velocity Apache projects, Copyright (c) 1999-2006 + Apache Software Foundation + + * One or more JARs from the Spring Framework Project + +See the LICENSE.txt file for information on all licenses associated with +this software. + +COPYRIGHT NOTICES: + +* Apache Beehive is bundled with source and binaries from the JSR-166 + implementation licensed under the relevant license in LICENSE.txt. + The source code and license are avaialble at: + http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/main/readme + +* Apache Beehive is bundled with binaries from The Spring Framework Project \ No newline at end of file diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..c3b3960 --- /dev/null +++ b/README.txt @@ -0,0 +1,21 @@ +Welcome to Beehive! + +If you've come here to learn more about Beehive, here are a few +starting points: + +BUILDING.txt: How to build Beehive on your machine. +DEVELOPING.txt Technical notes on contributing/committing files. +LICENSE.txt: The Apache License and any other relevant licenses for this software. +NOTICE.txt: Attribution notices required by various contributions. + +The Apache Beehive website is located at: + + http://beehive.apache.org + +And, the Beehive wiki is located at: + + http://wiki.apache.org/beehive + +Both of these contain additionl resources for getting started +with developing or using Beehive. + diff --git a/ant/axis-import.xml b/ant/axis-import.xml new file mode 100644 index 0000000..35101c0 --- /dev/null +++ b/ant/axis-import.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ant/beehive-runtime.xml b/ant/beehive-runtime.xml new file mode 100644 index 0000000..9841a07 --- /dev/null +++ b/ant/beehive-runtime.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ant/beehive-tools.xml b/ant/beehive-tools.xml new file mode 100644 index 0000000..e9199a1 --- /dev/null +++ b/ant/beehive-tools.xml @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + srcdir: @{srcdir} + classpath: ${_pageflow.build.classpath} + sourcepath: ${_pageflow.build.sourcepath} + webcontentdir: @{webcontentdir} + destdir: @{destdir} + tempdir: @{tempdir} + + + + + + + + + + + + +The beehive-tools.xml file contains Ant macros which can be used +to build Beehive related source artifacts such as Controls, Page Flows, +and XML Schemas. For examples of how to use these macros, see the +Beehive samples. + +Note, this build file does not contain targets that can be called +directly on the command line. + + + + diff --git a/ant/geronimo-imports.xml b/ant/geronimo-imports.xml new file mode 100644 index 0000000..2017935 --- /dev/null +++ b/ant/geronimo-imports.xml @@ -0,0 +1,158 @@ + + + + + + + + + + + + + + + + + deploy webapp from ${_url} with context path ${context.path} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + startup.dir: ${geronimo.home}/bin + cmdline.options: ${cmdline.options} + java.options: ${java.options} + + Starting Geronimo + + + + + + + + + Pausing for 30 seconds while geronimo starts.... + + + + + + + + + + + + + + startup.dir: ${geronimo.home}/bin + cmdline.options: ${cmdline.options} + java.options: ${java.options} + + Starting Geronimo with jpda + + + + + + + + + Pausing for 30 seconds while geronimo starts.... + + + + + Stop Geronimo in: ${geronimo.home} + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ant/jonas-imports.xml b/ant/jonas-imports.xml new file mode 100644 index 0000000..d40d62b --- /dev/null +++ b/ant/jonas-imports.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + deploy webapp from ${webapp.dir} with context path ${context.path} + + + + deploying via jonas admin + + + + + + + + + + + + + + + undeploying via jonas admin + + + + + + + + + + + + + + + + + + + + + + + + + + + + startup.dir: ${jonas.root} + cmdline.options: ${cmdline.options} + java.options: ${java.options} + + Start Jonas + + + + + + + + + + + + + + shmem is not an option for JOnAS. starting normally... + + + + + Stop Jonas in: ${jonas.root} + + + + + + + + + + + \ No newline at end of file diff --git a/ant/nightly.xml b/ant/nightly.xml new file mode 100644 index 0000000..ff01f63 --- /dev/null +++ b/ant/nightly.xml @@ -0,0 +1,137 @@ + + + + + + + + + + Get SVN revision + + + + + + + + + + + + Date: ${date} + Beehive SVN revision: ${beehive.svn.revision} + Beehive distribution name: ${dist.name} + FTP URL: ${url} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FTP to Beehive distribution to Apache + + + + + + + + + + +chdir /www/cvs.apache.org/dist/beehive/nightlies/ +mkdir ${date} +put /home/eko/dev/oss/beehive-nightly/trunk/build/dist/archives/apache-beehive-${date}-${beehive.svn.revision}.tar.gz +put /home/eko/dev/oss/beehive-nightly/trunk/build/dist/archives/apache-beehive-${date}-${beehive.svn.revision}.zip +put /home/eko/dev/oss/beehive-nightly/trunk/build/dist/archives/README.txt + + + + + + + + + + + + + + + + + + + diff --git a/ant/tomcat-imports.xml b/ant/tomcat-imports.xml new file mode 100644 index 0000000..ce8cefb --- /dev/null +++ b/ant/tomcat-imports.xml @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + deploy webapp from ${_url} with context path ${context.path} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + startup.dir: ${tomcat.home}/bin + cmdline.options: ${cmdline.options} + java.options: ${java.options} + + Start Tomcat + + + + + + + + + + + + + + + + + + + + + startup.dir: ${tomcat.home}/bin + cmdline.options: ${cmdline.options} + java.options: ${java.options} + + Start Tomcat + + + + + + + + + + + + Stop Tomcat in: ${tomcat.home} + + + + + + + + + + + + + + + + diff --git a/beehive-imports.xml b/beehive-imports.xml new file mode 100644 index 0000000..582e53e --- /dev/null +++ b/beehive-imports.xml @@ -0,0 +1,374 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Deploy NetUI to webapp @{webappDir} + + + + + + + + + + Deploy Controls to directory @{destDir} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + XMLBean build classpath: ${curr.classpath} + + + + + + + + + + + + + + + + + + + + + +Newer JDK required. + +Building the project requires JDK ${required.jdk.version} + +You are currently using the following JDK: + +java.home = ${java.home} +java.version = ${java.version} +java.vendor = ${java.vendor} + +You may obtain a newer version of the JDK from + +http://java.sun.com/ + +If you have JDK ${required.jdk.version} installed on your system, you may need to +adjust your JAVA_HOME environment variable. + + + + + + + + + + + + + + + +Newer Ant required. + +Building the project required Apache Ant 1.6. + +You are currently using the following apache-ant: + +ant.home = ${ant.home} +ant.version = ${ant.version} + +You may obtain a newer version of ant from + +http://ant.apache.org/ + +If you have Ant 1.6 installed on your system, you may need to +adjust your ANT_HOME environment variable. + + + + + + + + + + + + + + + diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..e059f68 --- /dev/null +++ b/build.xml @@ -0,0 +1,321 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + JSR 173 API JAR not found in directory: ${beehive.installed.dir} + + + + + + + + + + + + + + + + Check to see if proxy setup is required + + + + + + + + + + + + + + + + + + Proxy setup needed. + Proxy host: ${os.PROXYHOST} + Proxy port: ${os.PROXYPORT} + Proxy user: ${os.PROXYUSER} + Proxy password: ${os.PROXYPASSWORD} + Non proxy hosts: ${os.NONPROXYHOSTS} + + + + + + Socks Proxy setup needed. + + + + + + + + + + Ensuring Forrest present in directory: ${forrest.dir} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +java.home = ${java.home} +ant.home = ${ant.home} +beehive.home = ${beehive.home} +beehive.version = ${beehive.version} + + + + + JSR 173 is installed correctly as ${jsr173.jar} + + + + + junit.jar appears to be available since the class "junit.framework.TestCase" was successfully loaded + + + + + + Tomcat appears to be available in ${os.CATALINA_HOME} + + + + + + + + + + + + manager role appears to be defined in ${os.CATALINA_HOME}/conf/tomcat-users.xml + + + diff --git a/controls/README.txt b/controls/README.txt new file mode 100644 index 0000000..f80e123 --- /dev/null +++ b/controls/README.txt @@ -0,0 +1,98 @@ +This directory contains the Beehive Controls source and test files. This +README provides an overview of the basic directory structure, and describes +some of the useful ant targets for building, generating javadoc, and running +tests for the Controls runtime. + +SOURCE DIRECTORY STRUCTURE: + +./src: + +Contains all of the source files for the Beehive Controls runtime. When the +runtime is built, all of the generated classes end up in +build/jars/controls.jar. + +./src/api: + +Contains all of the source files for Controls public APIs used by Control +authors or clients. All annotation type, interfaces, and classes in the public +API set live within the org.apache.beehive.controls.api.* package space. + +./src/spi: + +Contains a small set of service provider interfaces used to adapt or +extend the Controls runtime for a specific environment. The audience for +the SPI set is primary system developers who want to integrate the runtime +into a specific container or application server environment, implement a +specific type of interceptor or instantiation factory, etc. All of the +classes in the SPI set live within the org.apache.beehive.controls.spi.* +package space. + +./src/runtime: + +Contains the Control runtime implementation classes. There are several +base classes used for code-generated ControlBeans as well as supporting +runtime classes for properties, contextual services, container integration, +etc. Control authors or clients should never reference any of these +runtime classes directly. All of the runtime classes live within the +org.apache.beehive.controls.runtime.* package space. + +SOURCE DEPENDENCIES: + +The dependencies across the various types of Control sources are: + +api -> spi : API public factory classes depend upon some SPI interfaces +spi -> api : the SPI classes often consume public classes +runtime -> api, spi : the runtime classes reference both API and SPI types + +Note: there are *no* dependencies from public interfaces to runtime classes. +This relationship is enforced by actually having them compile separately +(api + spi first, then runtime). + +SOURCE ANT TARGETS + +This section describes some of the available ant targets from the Controls +root directory. + +ant build: + +Compiles all annotation type, interface, and class files in the API, SPI, and +runtime directory and creates build/jars/controls.jar to contain them. + +ant docs: + +Generates javadoc documention for all API, SPI, and runtime classes and puts +them in build/docs. After running this target, you can browse to +file:build/docs/apidocs/classref_controls/index.html to view them. + +ant clean: + +Removes all generated output files from any of the build targets in the top +level or test directories. + +TEST INFRASTRUCTURE: + +The Controls runtime test infrastructure lives under the test subdirectory. It +includes a variety of test for Controls running in different context, from +vanilla Junit/java tests to running Controls inside of the various containers +that are part of the Beehive programming model: JWS, JPF, and nesting inside +of other controls. More details about the Controls runtime test tools +can be found at http://wiki.apache.org/beehive/Controls/TestingControls. + +CONTROLS TEST TARGETS: + +There are two main test targets for running Controls tests. These should be run +from within the controls/test directory: + +ant checkin.tests: + +These are a set of checkin tests that do shallow testing of a broad range of +functionality. These should be run and pass 100% before a committer submits +any Controls runtime changes. + +ant detailed.tests: + +This runs all control tests. Since some of them are test cases that are the +basis of open JIRA issues, THESE TESTS ARE NOT EXPECTED TO PASS 100%. Currently, +there is no good filter for running the detailed tests that are expected to +pass, but it has been suggested that this would be a good thing (to enable +deeper testing of larger changes). diff --git a/controls/build.xml b/controls/build.xml new file mode 100644 index 0000000..f4a0b2a --- /dev/null +++ b/controls/build.xml @@ -0,0 +1,265 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/controls/src/api/org/apache/beehive/controls/api/ControlException.java b/controls/src/api/org/apache/beehive/controls/api/ControlException.java new file mode 100644 index 0000000..ad62d73 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/ControlException.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api; + +/** + * The ControlException class declares an unchecked exception that is thrown by the Controls + * runtime under certain failure conditions. + */ +public class ControlException extends RuntimeException +{ + /** + * Default constructor. + */ + public ControlException() { + super(); + } + + /** + * Constructs a ControlException object with the specified String as a message. + * + * @param message The message to use. + */ + public ControlException(String message) + { + super(message); + } + + /** + * Constructs a ControlException with the specified cause. + * @param t the cause + */ + public ControlException(Throwable t) { + super(t); + } + + /** + * Constructs a ControlException object using the specified String as a message, and the + * specified Throwable as a nested exception. + * + * @param message The message to use. + * @param t The exception to nest within this exception. + */ + public ControlException(String message, Throwable t) + { + super(message + "[" + t + "]", t); + } +} diff --git a/controls/src/api/org/apache/beehive/controls/api/assembly/ControlAssembler.java b/controls/src/api/org/apache/beehive/controls/api/assembly/ControlAssembler.java new file mode 100644 index 0000000..64163c1 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/assembly/ControlAssembler.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.assembly; + +/** + * Control implementations may need to do build-time work on or impacted by + * their control client(s), such as side-effecting their client's deployment + * descriptors, or generating additional files that are implementation- + * specific. + * + * The build phase where this work is done is called assembly, and occurs + * at the granularity level of the J2EE module. + * The control author participates in this phase by authoring classes that + * implement the ControlAssembler interface, and associating such classes + * with control implementations. Instances of ControlAssembler are then + * called at assembly-time by build tools. + */ +public interface ControlAssembler +{ + /** + * A ControlAssembler implementation's assemble method is called once + * per control assembler per module per assembly-time pass. The call + * passes a ControlAssemblyContext, from which information such as the + * list of client classes in the module that use the control can be + * obtained. + */ + void assemble(ControlAssemblyContext cac) throws ControlAssemblyException; +} + diff --git a/controls/src/api/org/apache/beehive/controls/api/assembly/ControlAssemblyContext.java b/controls/src/api/org/apache/beehive/controls/api/assembly/ControlAssemblyContext.java new file mode 100644 index 0000000..a1c3198 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/assembly/ControlAssemblyContext.java @@ -0,0 +1,171 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.assembly; + +import java.io.File; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.Map; +import java.util.Set; + +import com.sun.mirror.apt.Messager; + +/** + * Control assemblers are passed a ControlAssemblyContext at the time they are + * invoked; the context allows the assemblers to interact with their external + * environment (checking files, side-effecting deployment descriptors, emitting + * code parameterized by the specifics of the control extension, etc). + * + * Beehive provides ControlAssemblyContext implementations that expose the + * standard environments of J2EE applications and modules. Vendor-specific + * implementations may provide access to their specific environment information, + * such as vendor-specific descriptors, via definition and implementation + * of additional interfaces. ControlAssemblers should use reflection to + * determine if the ControlAssemblyContext implementation they are passed + * supports a particular set of environment features. + */ +public interface ControlAssemblyContext +{ + /** + * Providers of ControlAssemblyContext implementations MUST implement + * Factory and newInstance to return their implementation. + */ + interface Factory + { + /** + * Creates a new instance of a ControlAssemblyContext implementation. + * + * @param controlIntfOrExt public interface/extension of the control + * type being assembled + * @param bindings map of control implementation bindings, null + * means use defaults. + * @param clients set of clients that use this control type. + * @param moduleRoot file root of the J2EE module containing the + * control clients to be assembled + * @param moduleName name of the J2EE module containing the + * control clients to be assembled + * @param srcOutputRoot file root of a location where assemblers + * should output any sources they create that + * may need further processing before use. + * @return a new instance of a ControlAssemblyContext implementation + */ + ControlAssemblyContext newInstance( Class controlIntfOrExt, + Map bindings, + Set clients, + File moduleRoot, + String moduleName, + File srcOutputRoot ) + throws ControlAssemblyException; + } + + /** + * Providers of ControlAssemblyContext implementations may implement + * EJBModule to provide access to an EJB module environment. + */ + interface EJBModule + { + // TODO: Provide more abstract helpers for common tasks. + // E.g. addResourceRef(). + + File getEjbJarXml(); + } + + /** + * Providers of ControlAssemblyContext implementations may implement + * WebAppModule to provide access to a webapp module environment. + */ + interface WebAppModule + { + File getWebXml(); + } + + /** + * Providers of ControlAssemblyContext implementations may implement + * EntAppModule to provide access to an enterprise application module + * environment. + */ + interface EntAppModule + { + File getApplicationXml(); + } + + /** + * @return the interface type of the control being assembled (annotated + * w/ ControlExtension or ControlInterface) + */ + Class getControlType(); + + /** + * @return the most derived interface of the control being assembled that + * is annotated with ControlInterface (may return the same as + * getControlType() if the control type is non-extended) + */ + Class getMostDerivedControlInterface(); + + /** + * @return an annotation on the interface returned by + * getControlType() + */ + T + getControlAnnotation(Class annotationClass); + + /** + * @return an annotation on a method on the interface + * returned by getControlType() + */ + T + getControlMethodAnnotation(Class annotationClass, Method m) + throws NoSuchMethodException; + + /** + * @return the defaultBinding member of the ControlInterface + */ + String getDefaultImplClassName(); + + /** + * @return the output directory into which "compilable" source should be output. + */ + File getSrcOutputDir(); + + /** + * @return the root of the module for which assembly is taking place. + */ + File getModuleDir(); + + /** + * @return the name of the module for which assembly is taking place. + */ + String getModuleName(); + + /** + * @return the set of clients (by class name) which use the control type + */ + Set getClients(); + + /** + * @return a Messager implementation that can be used to emit diagnostics during the + * assembly process. + */ + Messager getMessager(); + + /** + * @return true if the assembly process reported errors via the Messager + */ + boolean hasErrors(); +} diff --git a/controls/src/api/org/apache/beehive/controls/api/assembly/ControlAssemblyException.java b/controls/src/api/org/apache/beehive/controls/api/assembly/ControlAssemblyException.java new file mode 100644 index 0000000..b5b5f83 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/assembly/ControlAssemblyException.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.assembly; + +/** + * Checked exceptions thrown during the assembly process. ControlAssembler + * implementations may throw this exception in their assemble() method, which + * will halt the assembly process. + */ +public class ControlAssemblyException extends Exception +{ + public ControlAssemblyException(String msg) + { + super(msg); + } + + public ControlAssemblyException(String msg, Throwable cause) + { + super(msg, cause); + } +} diff --git a/controls/src/api/org/apache/beehive/controls/api/assembly/DefaultControlAssembler.java b/controls/src/api/org/apache/beehive/controls/api/assembly/DefaultControlAssembler.java new file mode 100644 index 0000000..4fa9817 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/assembly/DefaultControlAssembler.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.assembly; + +/** + * The default or "empty" control assembler that's assigned to an @ControlImplementation's + * assembler attribute if none is provided. + */ +public final class DefaultControlAssembler implements ControlAssembler +{ + public void assemble(ControlAssemblyContext cac) throws ControlAssemblyException { }; +} diff --git a/controls/src/api/org/apache/beehive/controls/api/bean/AnnotationConstraints.java b/controls/src/api/org/apache/beehive/controls/api/bean/AnnotationConstraints.java new file mode 100644 index 0000000..b8b8ec4 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/bean/AnnotationConstraints.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.bean; + +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Retention; +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + +/** + * AnnotationConstraints defines meta-annotations that allow + * specification of additional constraints that aren't + * expressible using J2SE 5.0 meta-annotations. + * + * Actual enforcement of these semantics is implementation dependent. + * An apt-based reference implementation is provided by + * {@link org.apache.beehive.controls.runtime.bean.AnnotationConstraintValidator}. + * + * @see org.apache.beehive.controls.runtime.bean.AnnotationConstraintValidator + */ +public interface AnnotationConstraints +{ + /** + * Defines a number of simple constraints on the way annotation members + * can be used together. + * + * @see MembershipRule + */ + public enum MembershipRuleValues + { + AT_LEAST_ONE, + AT_MOST_ONE, + EXACTLY_ONE, + ALL_IF_ANY + } + + /** + * Provides a mechanism for enforcing constraints between members of + * an annotation (such a mechanism is absent from J2SE 5.0; for example, + * given an annotation with members 'a' and 'b' there is no way to say + * that they are mutually exclusive). + * + * @see MembershipRuleValues + */ + @Target({ElementType.ANNOTATION_TYPE}) + @Retention(RetentionPolicy.RUNTIME) + public @interface MembershipRule + { + /** Required, the membership rule.*/ + MembershipRuleValues value(); + /** Optional list of member names to apply rule against. Empty array implies all members. */ + String[] memberNames() default {}; + } + + /** + * Defines whether the annotation decorated by this + * annotation can overriden externally (a marker interface). + */ + @Target({ElementType.ANNOTATION_TYPE}) + @Retention(RetentionPolicy.RUNTIME) + public @interface AllowExternalOverride + { + } + + /** + * Specifies the version of the control runtime required by this annotation. + */ + @Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD}) + @Retention(RetentionPolicy.RUNTIME) + public @interface RequiredRuntimeVersion + { + String value(); // no default + } +} diff --git a/controls/src/api/org/apache/beehive/controls/api/bean/AnnotationMemberTypes.java b/controls/src/api/org/apache/beehive/controls/api/bean/AnnotationMemberTypes.java new file mode 100644 index 0000000..994343e --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/bean/AnnotationMemberTypes.java @@ -0,0 +1,214 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.bean; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + *

AnnotationMemberTypes defines a set of annotations meant to used on + * annotation members to specify additional syntatic and semantic behaviour + * or constraints.

+ * + *

J2SE 5 annotation members provide a very weak level of syntactic and + * semantic enforcement. Annotation members may only be a certain type + * (mostly primitives, arrays, plus java.lang.String and a few other classes); + * it is often useful to be more specific than those types permit.

+ * + *

Consider the following example:

+ * + *
+ * public @interface LastChanged
+ * {
+ *     @AnnotationMemberTypes.Date()
+ *     public String date();
+ * }
+ * 
+ * + *

The use of @AnnotationMemberTypes.Date means that the + * value of the date string must be a date in some standard + * form.

+ * + *

AnnotationMemberTypes defines a set of annotations and their semantics, + * but actual enforcement of those semantics is implementation dependent. + * An apt-based reference implementation is provided by + * {@link org.apache.beehive.controls.runtime.bean.AnnotationConstraintValidator}.

+ * + * @see org.apache.beehive.controls.runtime.bean.AnnotationConstraintValidator + */ +public interface AnnotationMemberTypes +{ + public final static String OPTIONAL_STRING = ""; + public final static double OPTIONAL_DOUBLE = Double.MIN_VALUE; + public final static float OPTIONAL_FLOAT = Float.MIN_VALUE; + public final static int OPTIONAL_INT = Integer.MIN_VALUE; + public final static long OPTIONAL_LONG = Long.MIN_VALUE; + public final static short OPTIONAL_SHORT = Short.MIN_VALUE; + public final static char OPTIONAL_CHAR = Character.MIN_VALUE; + public final static byte OPTIONAL_BYTE = Byte.MIN_VALUE; + public final static int UNLIMITED_PLACES = -1; + + /** + * Marks a member as optional. Member must have + * a default value. + */ + @Target({ElementType.METHOD}) + @Retention(RetentionPolicy.RUNTIME) + public @interface Optional + { + } + + /** + * Member must be a String value. + */ + @Target({ElementType.METHOD}) + @Retention(RetentionPolicy.RUNTIME) + public @interface Text + { + boolean isLong() default false; + int maxLength() default Integer.MAX_VALUE; + } + + /** + * Member is a Decimal Value. + * Can be applied to a member that returns float, double or String. + */ + @Target({ElementType.METHOD}) + @Retention(RetentionPolicy.RUNTIME) + public @interface Decimal + { + int places() default UNLIMITED_PLACES; + double minValue() default Double.MIN_VALUE; + double maxValue() default Double.MAX_VALUE; + } + + /** + * Member is an Integer value. + * Can be applied to a member that returns String or int. + */ + @Target({ElementType.METHOD}) + @Retention(RetentionPolicy.RUNTIME) + public @interface Int + { + int minValue() default Integer.MIN_VALUE; + int maxValue() default Integer.MAX_VALUE; + } + + /** + * Member is a Date in the format specified (default is YYYY/MM/DD) + * Only valid on a member that returns String + * @see java.text.SimpleDateFormat when selecting another date format. + * Note: JSR175 does not allow java.util.Date as + * a member type. + */ + @Target({ElementType.METHOD}) + @Retention(RetentionPolicy.RUNTIME) + public @interface Date + { + String format() default "yyyy/MM/dd"; + String minValue() default ""; + String maxValue() default ""; + } + + /** + * Member is a URI + * Only valid on a member that returns String + */ + @Target({ElementType.METHOD}) + @Retention(RetentionPolicy.RUNTIME) + public @interface URI + { + } + + /** + * Member is a URN + * Only valid on a member that returns String + */ + @Target({ElementType.METHOD}) + @Retention(RetentionPolicy.RUNTIME) + public @interface URN + { + } + + /** + * Member is a URL + * Only valid on a member that returns String + */ + @Target({ElementType.METHOD}) + @Retention(RetentionPolicy.RUNTIME) + public @interface URL + { + } + + /** + * Member is a QName + * Only valid on a member that returns String + */ + @Target({ElementType.METHOD}) + @Retention(RetentionPolicy.RUNTIME) + public @interface QName + { + } + + /** + * Member contains well formed XML + * Only valid on a member that returns String + */ + @Target({ElementType.METHOD}) + @Retention(RetentionPolicy.RUNTIME) + public @interface XML + { + } + + /** + * Member is a File Path + * Compiler MUST validate that value points + * to a readable file. + * Only valid on a member that returns String. + */ + @Target({ElementType.METHOD}) + @Retention(RetentionPolicy.RUNTIME) + public @interface FilePath + { + } + + /** + * Member is a JNDI name. + */ + @Target({ElementType.METHOD}) + @Retention(RetentionPolicy.RUNTIME) + public @interface JndiName + { + /** + * Defines the type of JNDI resource reference by a member. + */ + public enum ResourceType + { + DATASOURCE, + EJB, + JMS_TOPIC, + JMS_QUEUE , + OTHER + } + + ResourceType resourceType(); + } +} diff --git a/controls/src/api/org/apache/beehive/controls/api/bean/Control.java b/controls/src/api/org/apache/beehive/controls/api/bean/Control.java new file mode 100644 index 0000000..5c16dc6 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/bean/Control.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.bean; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * The Control annotation type is used to annotate a field within a control + * client source file that is a control reference. It is the declarative + * mechanism for instantiating controls in Java clients. Java Controls + * runtime implementations will automatically initialize such annotated field + * references to an appropriate Java Control Bean of the requested type, + * and perform event listener hookup etc. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD}) +public @interface Control +{ + /** + * Optional member used to specify the control interface class. + * Typically only necessary to resolve ambiguities when multiple + * control interfaces with same name but different packages are present. + */ + Class interfaceHint() default Object.class; +} diff --git a/controls/src/api/org/apache/beehive/controls/api/bean/ControlBean.java b/controls/src/api/org/apache/beehive/controls/api/bean/ControlBean.java new file mode 100644 index 0000000..8239f54 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/bean/ControlBean.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.bean; + +import java.beans.beancontext.BeanContext; +import java.beans.beancontext.BeanContextProxy; + +import org.apache.beehive.controls.api.context.ControlBeanContext; + +/** + * The ControlBean interface defines a base set of methods that are implemented by all + * JavaBeans that host Java Controls. + *

+ * A ControlBean will implement the java.beans.beancontext.BeanContextProxy + * interface to provide a way to get the BeanContext directly associated + * with the Java Control. The getBeanContext() API on the interface will + * return the parent (containing) context. + * + * @see java.beans.beancontext.BeanContextProxy + */ +public interface ControlBean extends BeanContextProxy, java.io.Serializable +{ + /** + * The IDSeparator character is used to separated individual control IDs in nesting + * scenarios whether the identifier is actually a composite path that represents + * a nesting relationship. + */ + public static final char IDSeparator = '/'; + + /** + * Returns the java.beans.beancontext.BeanContext that provides the parent + * context for the Java Control. + * @return the containing BeanContext for the Java ControlBean. + * + * @see java.beans.beancontext.BeanContext + */ + BeanContext getBeanContext(); + + /** + * Returns the org.apache.beehive.controls.api.context.ControlBeanContext instance + * that provides the local context for this control bean. This is not the parent + * context for the control. It is the context that would be the parent context for + * any nested controls hosted by this control. + */ + ControlBeanContext getControlBeanContext(); + + /** + * Returns the unique control ID associated with the Java ControlBean. This control ID + * is guaranteed to be unique within the containing BeanContext + * @return the control ID + */ + String getControlID(); + + /** + * Returns the Java Control public interface for the ControlBean. This interface defines + * the operations and events exposed by the Java Control to its clients. + * @return the control public interface + */ + Class getControlInterface(); +} diff --git a/controls/src/api/org/apache/beehive/controls/api/bean/ControlChecker.java b/controls/src/api/org/apache/beehive/controls/api/bean/ControlChecker.java new file mode 100644 index 0000000..a5fc91a --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/bean/ControlChecker.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.bean; + +import com.sun.mirror.apt.AnnotationProcessorEnvironment; +import com.sun.mirror.declaration.Declaration; + +/** + * The ControlChecker interface is implemented by control authors wishing to + * enforce rich semantic validation on extension and field instance declarations of + * their controls. By supplying a ControlChecker implementation (a "checker") + * and associating it with your control's public interface, when an extension (.jcx) + * of your control is processed at build-time, the checker will be invoked and + * can do rich validation of the jcx type and field instances via introspection and + * analysis of the jcx's type structure, signatures and annotations. + *

+ * Checkers are instantiated by, and required to implement, a no-arg constructor. + * They are provided with type information and context via the Sun mirror API. + */ +public interface ControlChecker +{ + /** + * Invoked by the control build-time infrastructure to process a declaration of + * a control extension (ie, an interface annotated with @ControlExtension), or + * a field instance of a control type. + */ + public void check(Declaration decl, AnnotationProcessorEnvironment env); +} diff --git a/controls/src/api/org/apache/beehive/controls/api/bean/ControlExtension.java b/controls/src/api/org/apache/beehive/controls/api/bean/ControlExtension.java new file mode 100644 index 0000000..114f19e --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/bean/ControlExtension.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.bean; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * The ControlExtension annotation type is used to annotate a control extension interface. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +public @interface ControlExtension +{ + // Members parameterizing the control extension will be added here +} diff --git a/controls/src/api/org/apache/beehive/controls/api/bean/ControlImplementation.java b/controls/src/api/org/apache/beehive/controls/api/bean/ControlImplementation.java new file mode 100644 index 0000000..0e92f82 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/bean/ControlImplementation.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.bean; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apache.beehive.controls.api.assembly.ControlAssembler; +import org.apache.beehive.controls.api.assembly.DefaultControlAssembler; + +/** + * The ControlImplementation annotation type is used to annotate the implementation class for a + * Java Control. It marks the class as a control implementation and (in the future) parameterizes + * it. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +public @interface ControlImplementation +{ + /** class name for the Class (which implements + * com.bea.control.assembly.ControlAssembler) whose assemble() + * method is called at assembly time - if left Void then no + * special assembly is needed + */ + Class assemblyHelperClass() default java.lang.Void.class; // DEPRECATED + + /** + * Class that implements ControlAssembler, which gets called at assembly time. + * Default implementation does nothing. + */ + Class assembler() default DefaultControlAssembler.class; + + /** + * Specifies whether the control implementation class contains state that should be + * serialized as part of the containing Control/JavaBean or is fully stateless/transient. + */ + boolean isTransient() default false; // default to assuming stateful +} diff --git a/controls/src/api/org/apache/beehive/controls/api/bean/ControlInterface.java b/controls/src/api/org/apache/beehive/controls/api/bean/ControlInterface.java new file mode 100644 index 0000000..409d19b --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/bean/ControlInterface.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.bean; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * The ControlInterface annotation type is used to annotate a control public interface. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +public @interface ControlInterface +{ + /** + * Placeholder string used in defaultBinding attr. Tools and runtime should replace + * instances of INTERFACE_NAME found in values of defaultBinding with the fully + * qualified name of the interface annotated with @ControlInterface. + */ + static final String INTERFACE_NAME = ""; + + /** + * Specify the fully qualified name of the control implementation for this control interface. + * If no value is specified the implementation will be the name of the interface with 'Impl' appended. + * */ + String defaultBinding() default INTERFACE_NAME + "Impl"; + + /** + * @deprecated Replaced by checker() element. + */ + Class checkerClass() default DefaultControlChecker.class; + + /** + * Used by control authors wishing to enforce rich semantic validation on extension and field + * instance declarations of their controls. By supplying a ControlChecker implementation + * (a "checker") and associating it with your control's public interface, when an + * extension of your control is processed at build-time, the checker will be invoked and + * can do rich validation of the extension type and field instances via introspection and + * analysis of the control extension's type structure, signatures and annotations. + * @see org.apache.beehive.controls.api.bean.ControlChecker + */ + Class checker() default DefaultControlChecker.class; +} diff --git a/controls/src/api/org/apache/beehive/controls/api/bean/ControlReferences.java b/controls/src/api/org/apache/beehive/controls/api/bean/ControlReferences.java new file mode 100644 index 0000000..3447236 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/bean/ControlReferences.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.bean; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * The ControlReferences annotation type is used to annotate a control client + * type, listing any control types that the client uses purely programmatically + * (and not declaratively). Tools will treat the union of the set of types + * annotated w/ @Control and the types listed in @ControlReferences as the + * complete set of controls used by a client. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +public @interface ControlReferences +{ + Class[] value() default {}; +} diff --git a/controls/src/api/org/apache/beehive/controls/api/bean/Controls.java b/controls/src/api/org/apache/beehive/controls/api/bean/Controls.java new file mode 100644 index 0000000..21dd7c9 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/bean/Controls.java @@ -0,0 +1,153 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.bean; + +import java.lang.reflect.Method; +import java.lang.reflect.InvocationTargetException; + +import org.apache.beehive.controls.api.properties.PropertyMap; +import org.apache.beehive.controls.api.context.ControlBeanContext; +import org.apache.beehive.controls.api.ControlException; +import org.apache.beehive.controls.spi.bean.ControlFactory; +import org.apache.beehive.controls.spi.bean.JavaControlFactory; +import org.apache.commons.discovery.tools.DiscoverClass; + +/** + * Helper class for using controls. Includes static methods to help instantiate controls, and initialize + * declarative control clients. + */ +public class Controls +{ + final private static String DEFAULT_FACTORY_CLASS = JavaControlFactory.class.getName(); + + /** + * Factory method for instantiating controls. Controls instantiated using this method will be associated with the + * current thread-local ControlBeanContext (possibly none), and have an auto-generated ID. + * + * @param cl the classloader used to load the ControlBean. If null, the system classloader will be used. + * @param beanName the fully qualified name of the ControlBean class. + * @param props an optional PropertyMap containing initial property values for the control. May be null. + * @return an instance of the specified ControlBean. + * @throws ClassNotFoundException + */ + public static ControlBean instantiate( ClassLoader cl, + String beanName, + PropertyMap props ) + throws ClassNotFoundException + { + return instantiate( cl, beanName, props, null, null ); + } + + /** + * Factory method for instantiating controls. + * + * @param cl the classloader used to load the ControlBean. If null, the system classloader will be used. + * @param beanName the fully qualified name of the ControlBean class. + * @param props an optional PropertyMap containing initial property values for the control. May be null. + * @param cbc the ControlBeanContext that will nest the created control. If null, the thread-local context + * (possibly none) will be used. + * @param id a unique ID for the created control. If null, an ID will be auto-generated. + * @return an instance of the specified ControlBean. + * @throws ClassNotFoundException + */ + public static ControlBean instantiate( ClassLoader cl, + String beanName, + PropertyMap props, + ControlBeanContext cbc, + String id ) + throws ClassNotFoundException + { + Class beanClass = ( cl == null ) ? Class.forName( beanName ) : cl.loadClass( beanName ); + return instantiate(beanClass, props, cbc, id); + } + + /** + * Factory method for instantiating controls. + * + * @param beanClass the ControlBean class to instantiate + * @param props an optional PropertyMap containing initial property values for the control. + * may be null. + * @param context the ControlBeanContext that will nest the created control. If null, the + * thread-local context (possibly none) will be used. + * @param id a unique ID for the created control. If null, an ID will be auto-generated. + * @return an instance of the specified ControlBean. + */ + public static T instantiate( Class beanClass, + PropertyMap props, + ControlBeanContext context, + String id ) + { + try + { + DiscoverClass discoverer = new DiscoverClass(); + Class factoryClass = discoverer.find( ControlFactory.class, DEFAULT_FACTORY_CLASS ); + ControlFactory factory = (ControlFactory)factoryClass.newInstance(); + return factory.instantiate( beanClass, props, context, id ); + } + catch ( Exception e ) + { + throw new ControlException( "Exception creating ControlBean", e ); + } + } + + /** + * Helper method for initializing instances of declarative control clients (objects that use controls via @Control + * and @EventHandler annotations). This method runs the client-specific generated ClientInitializer class to do + * its initialization work. + * + * @param cl the classloader used to load the ClientInitializer. If null, defaults to the classloader used to + * load the client object being initialized. + * @param client the client object being initialized. + * @param cbc the ControlBeanContext to be associated with the client object (that will nest the controls the client + * defines). If null, the thread-local context (possibly none) will be used. + * @throws ControlException + * @throws ClassNotFoundException + */ + public static void initializeClient( ClassLoader cl, Object client, ControlBeanContext cbc ) + throws ClassNotFoundException + { + Class clientClass = client.getClass(); + String clientName = clientClass.getName(); + + if ( cl == null ) + cl = clientClass.getClassLoader(); + + String initName = clientName + "ClientInitializer"; + Class initClass = cl.loadClass( initName ); + + try + { + Method m = initClass.getMethod( "initialize", ControlBeanContext.class, clientClass ); + m.invoke(null, cbc, client ); + } + catch ( Throwable e ) + { + if ( e instanceof InvocationTargetException ) + { + if ( e.getCause() != null ) + { + e = e.getCause(); + } + } + + throw new ControlException( "Exception trying to run client initializer: " + e.getClass().getName() + ", " + + e.getMessage(), e ); + } + } +} diff --git a/controls/src/api/org/apache/beehive/controls/api/bean/DefaultControlChecker.java b/controls/src/api/org/apache/beehive/controls/api/bean/DefaultControlChecker.java new file mode 100644 index 0000000..13911d5 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/bean/DefaultControlChecker.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.bean; + +import com.sun.mirror.apt.AnnotationProcessorEnvironment; +import com.sun.mirror.declaration.Declaration; + +/** + * The default or "empty" control checker that assigned to an @ControlInterface's + * controlChecker attribute if none is provided. + */ +public final class DefaultControlChecker implements ControlChecker +{ + public void check(Declaration decl, AnnotationProcessorEnvironment env) { }; +} diff --git a/controls/src/api/org/apache/beehive/controls/api/bean/Extensible.java b/controls/src/api/org/apache/beehive/controls/api/bean/Extensible.java new file mode 100644 index 0000000..43b11a1 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/bean/Extensible.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.bean; + +import java.lang.reflect.Method; + +/** + * The Extensible interface is implemented by a Java Control implementation class if the + * control defines an extensibility model that allows extended operations to be declared + * using a JCX interface. + *

+ * The interface provides the invoke method, that is called whenever an + * extended operation is called by the client at run time. + */ +public interface Extensible +{ + /** + * Called by the Controls runtime to handle calls to methods of an + * extensible control. + *

+ * @param method The extended operation that was called. + * @param args Parameters of the operation. + * @return The value that should be returned by the operation. + * @throws java.lang.Throwable any exception declared on the extended operation may be + * thrown. If a checked exception is thrown from the implementation that is not declared + * on the original interface, it will be wrapped in a ControlException. + */ + public Object invoke(Method method, Object[] args) throws Throwable; +} diff --git a/controls/src/api/org/apache/beehive/controls/api/bean/ExternalPropertySets.java b/controls/src/api/org/apache/beehive/controls/api/bean/ExternalPropertySets.java new file mode 100644 index 0000000..b81cfdf --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/bean/ExternalPropertySets.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.bean; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Used on control interfaces to specify any external property sets that + * the control uses. External property sets are property sets that are + * their own top-level interfaces, i.e. not nested. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +public @interface ExternalPropertySets +{ + Class[] value(); +} diff --git a/controls/src/api/org/apache/beehive/controls/api/bean/Threading.java b/controls/src/api/org/apache/beehive/controls/api/bean/Threading.java new file mode 100644 index 0000000..ed504f0 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/bean/Threading.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.bean; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Used to specify the desired threading policy to apply to a control + * implementation type. See {@link ThreadingPolicy}. Only permitted + * on classes that are also annotated with {@link ControlImplementation}. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +public @interface Threading +{ + ThreadingPolicy value() default ThreadingPolicy.SINGLE_THREADED; +} diff --git a/controls/src/api/org/apache/beehive/controls/api/bean/ThreadingPolicy.java b/controls/src/api/org/apache/beehive/controls/api/bean/ThreadingPolicy.java new file mode 100644 index 0000000..924963a --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/bean/ThreadingPolicy.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.bean; + +/** + * Specifies threading policy for control implementations. The constants + * of this enumerated type describe the threading policies that apply + * during execution of controls. They are used in conjunction with the + * {@link Threading} annotation type to specify the responsibilities of + * the runtime infrastructure and control implementation with respect to + * threading. + */ +public enum ThreadingPolicy +{ + /** + * When a control implementation is declared as SINGLE_THREADED, the + * controls infrastructure ensures that only a single thread will be + * executing in a particular instance of that control at any time. + * This is the default policy if no {@link Threading} annotation is + * specified. + */ + SINGLE_THREADED, + /** + * When a control implementation is declared as MULTI_THREADED, the + * controls infrastructure permits multiple threads to concurrently + * execute in instances of that control. It is then the responsibility + * of the implementation to ensure internal thread-safety using + * standard Java concurrency mechanisms. This policy may yield higher + * performance, at the cost of additional work on the implementor's part. + */ + MULTI_THREADED +} diff --git a/controls/src/api/org/apache/beehive/controls/api/context/Context.java b/controls/src/api/org/apache/beehive/controls/api/context/Context.java new file mode 100644 index 0000000..7042160 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/context/Context.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.context; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * The Context annotation type is used to annotate a field within a control implementation + * class that refers to a contextual service. The Java Controls runtime will automatically + * initialize the field value to an appropriate provider of the requested service, or will + * throw a construction or deserialization error if no such provider is available. + * + * The following is a simple example: + * + *

+ * @ControlImplementation
+ * public class MyControlImpl
+ * {
+ *     @Context
+ *     ControlContext myContext;
+ * }
+ * 
+ * This example declares a field named myContext that will automatically be + * initialized by the Java Controls runtime to refer to a provider of the + * ControlContext contextual service. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD}) +public @interface Context +{ +} diff --git a/controls/src/api/org/apache/beehive/controls/api/context/ControlBeanContext.java b/controls/src/api/org/apache/beehive/controls/api/context/ControlBeanContext.java new file mode 100644 index 0000000..00871dc --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/context/ControlBeanContext.java @@ -0,0 +1,238 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.context; + +import java.beans.beancontext.BeanContextServices; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyVetoException; +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Method; + +import org.apache.beehive.controls.api.bean.ControlBean; +import org.apache.beehive.controls.api.events.EventSet; +import org.apache.beehive.controls.api.properties.PropertyMap; + +/** + * The ControlBeanContext interface defines the basic set of contextual services and lifecycle + * events for Java ControlBean implementations. + *

+ * ControlBeanContext also extends the java.beans.beancontext.BeanContextServices + * interface, so it also provide core Java Beans services for managing contained controls, + * looking up contextual services, and locating the parent {@link java.beans.beancontext.BeanContext} context. + *

+ * A Control implementation class can obtain access to the ControlBeanContext associated + * with it by declaring an instance field of this type and annotating it with the + * org.apache.beehive.controls.api.context.Context annotation, as in the following + * example: + * + *

+ * import org.apache.beehive.controls.api.context.Context;
+ * import org.apache.beehive.controls.api.context.ControlBeanContext;
+ *
+ * @ControlImplementation
+ * public class MyControlImpl
+ * {
+ *     @Context
+ *     ControlBeanContext myContext;
+ * }
+ * 
+ * The Java Control runtime will automatically initialize this field to a reference to the + * ControlBeanContext associated with the implementation instance. + */ +public interface ControlBeanContext extends BeanContextServices +{ + /** + * Returns the public or extension interface associated with the context + */ + public Class getControlInterface(); + + /** + * Returns the current value of PropertySet for the associated control, or + * null if the property set has not been bound. Actual bindings for property + * values may be the result of annotations on the control field or class, + * property setting via factory arguments or setter APIs, or external + * configuration. + * + * @param propertySet the PropertySet to return + * @return the requested PropertySet instance, or null if not bound + * + * @see org.apache.beehive.controls.api.properties.PropertySet + */ + public T getControlPropertySet(Class propertySet); + + /** + * Returns the current value of PropertySet for the provided method, or null + * if the property set has not been bound for this method. + * + * @param m the Method to check for properties. + * @param propertySet the PropertySet to return + * @return the requested PropertySet instance, or null if not bound + * + * @see org.apache.beehive.controls.api.properties.PropertySet + */ + public T getMethodPropertySet(Method m, Class propertySet) + throws IllegalArgumentException; + + /** + * Returns the current value of PropertySet for the selected (by index) method parameter, + * or null if the property set has not been bound for this method. + * + * @param m the Method to check for properties + * @param i the index of the method parameter to check for the request PropertySet + * @param propertySet the PropertySet to return + * @return the request PropertySet instance, or null if not bound + */ + public T getParameterPropertySet(Method m, int i, Class propertySet) + throws IllegalArgumentException, IndexOutOfBoundsException; + + /** + * Returns an array containing the parameter names for the specified method + * + * @param m the Method whose parameter names should be returned. + * @return the array of parameter names (or an empty array if no parameters) + */ + public String [] getParameterNames(Method m) + throws IllegalArgumentException; + + /** + * Returns the value of a named method parameter from the input parameter array. + * + * @param m the Method associated with the input parameter list + * @param parameterName the name of the requested parameter + * @param parameters the array of method parameters + * @return the element in the input parameter array that corresponds to the requested + * parameter + */ + public Object getParameterValue(Method m, String parameterName, Object [] parameters) + throws IllegalArgumentException; + + /** + * Returns the current set of properties (in PropertyMap format) for the control + * associated with the context. The return map will contain the values for all bound + * properties for the control. + * @return the PropertyMap containing properties of the control. This map is read-only; + * any changes to it will not effect the local bean instance. + * + * @see org.apache.beehive.controls.api.properties.PropertyMap + */ + public PropertyMap getControlPropertyMap(); + + /** + * Returns an instance of a contextual service based upon the local context. If + * no provider for this service is available, then null will be returned. + * + * @param serviceClass the class of the requested service + * @param selector the service dependent parameter + * @return an instance of the request service, or null if unavailable + * + * @see java.beans.beancontext.BeanContextServices#getService + */ + public T getService(Class serviceClass, Object selector); + + /** + * Returns a ControlHandle instance that enables operations and events to be dispatched + * to the target control, if it is running inside of a container that supports external + * event dispatch. If the runtime container for the control does not support this + * functionality, a value of null will be returned. + * + * @return a ControlHandle instance for the control, or null. + * + * @see org.apache.beehive.controls.api.context.ControlHandle + */ + public ControlHandle getControlHandle(); + + /** + * Returns the PropertyMap containing default properties for an AnnotatedElement + * in the current context. + */ + public PropertyMap getAnnotationMap(AnnotatedElement annotElem); + + /** + * Returns the ClassLoader used to load the ControlBean class associated with the control + * implementation instance. This is useful for loading other classes or resources that may + * have been packaged with the public interfaces of the Control type (since they may not + * necessarily have been packaged directly with the implementation class). + */ + public java.lang.ClassLoader getClassLoader(); + + /** + * Returns true if this container guarantees single-threaded behaviour. + */ + public boolean isSingleThreadedContainer(); + + /** + * Returns the peer ControlBean associated with this ControlBeanContext. If the context + * represents a top-level container (i.e. not a Control containing other controls), null + * will be returned. + */ + public ControlBean getControlBean(); + + /** + * Returns any child ControlBean that is nested in the ControlBeanContext, or null + * if no matching child is found. The id parameter is relative to + * the current nesting context, not an absolute control id. + */ + public ControlBean getBean(String id); + + /** + * The Lifecycle event interface defines a set of lifecycle events exposed by the + * ControlBeanContext to any registered listener. + */ + @EventSet + public interface LifeCycle + { + /** + * The onCreate event is delivered when the control implementation instance for + * the associated bean has been instantiated and fully initialized. + */ + public void onCreate(); + + /** + * The onPropertyChange event is delivered when a property setter method is + * called for a bound property on the Java Control. + * + * @see org.apache.beehive.controls.api.packaging.PropertyInfo + */ + public void onPropertyChange(PropertyChangeEvent pce); + + /** + * The onVetoableChange event is delivered when a property setter method is + * called for a constrained property on the Java Control. A PropertyVetoException + * may be thrown to veto the change made by the client. + * + * @see org.apache.beehive.controls.api.packaging.PropertyInfo + */ + public void onVetoableChange(PropertyChangeEvent pce) throws PropertyVetoException; + } + + /** + * Registers a new listener for LifeCycle events on the context. + * + * @see org.apache.beehive.controls.api.context.ControlBeanContext.LifeCycle + */ + public void addLifeCycleListener(LifeCycle listener); + + /** + * Removes a currently registered LifeCycle event listener on the context. + * + * @see org.apache.beehive.controls.api.context.ControlBeanContext.LifeCycle + */ + public void removeLifeCycleListener(LifeCycle listener); +} \ No newline at end of file diff --git a/controls/src/api/org/apache/beehive/controls/api/context/ControlContainerContext.java b/controls/src/api/org/apache/beehive/controls/api/context/ControlContainerContext.java new file mode 100644 index 0000000..97e0d51 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/context/ControlContainerContext.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.context; + +import org.apache.beehive.controls.api.bean.ControlBean; +import org.apache.beehive.controls.api.events.EventDispatcher; + +/** + * The ControlContainerContext interface defines the basic contract between an external container + * of controls and the Controls runtime. + */ +public interface ControlContainerContext extends EventDispatcher, ControlBeanContext +{ + /** + * Makes the ControlContainerContext instance the current active context. This is + * called at the beginning of the execution scope for the control container. + */ + public void beginContext(); + + /** + * Ends the active context associated with the ControlContainerContext. This is called + * at the end of the execution scope for the control container. + */ + public void endContext(); + + /** + * Returns a ControlHandle to the component containing the control. This handle can be + * used to dispatch events and operations to a control instance. This method will return + * null if the containing component does not support direct dispatch. + */ + public ControlHandle getControlHandle(ControlBean bean); +} diff --git a/controls/src/api/org/apache/beehive/controls/api/context/ControlHandle.java b/controls/src/api/org/apache/beehive/controls/api/context/ControlHandle.java new file mode 100644 index 0000000..ec93ff6 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/context/ControlHandle.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.context; + +import org.apache.beehive.controls.api.events.EventRef; +import java.lang.reflect.InvocationTargetException; + +/** + * The ControlHandle interface defines a reference object to a control instance that enables + * control events to be fired on the control. Control container implementations will provide + * implementation of this interface that use container-specific dispatch mechanisms to locate + * the appropriate control container instance when events are fired. + * + * Classes implementing the ControlHandle interface should also implement the + * java.io.Serializable interface. This will enable handles to be serialized / + * deserialized as part of event queueing or routing. + */ +public interface ControlHandle +{ + /** + * Returns the controlID of the target control referenced by this handle + */ + public String getControlID(); + + /** + * Delivers the specified event to the target control referenced by this handle. + */ + public Object sendEvent(EventRef event, Object [] args) + throws IllegalAccessException,IllegalArgumentException,InvocationTargetException; +} diff --git a/controls/src/api/org/apache/beehive/controls/api/context/ControlThreadContext.java b/controls/src/api/org/apache/beehive/controls/api/context/ControlThreadContext.java new file mode 100644 index 0000000..92a9c56 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/context/ControlThreadContext.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.context; + +import java.util.Stack; + +/** + * The ControlThreadContext class manages the association between ControlContainerContexts + * and threads of execution. For a given thread of execution, the beginning and ending of + * contexts will always be nested (never interleaved), so each thread will maintain its own + * stack of currently executing contexts. This can be used to reassociate with the current + * active context. + */ +public class ControlThreadContext +{ + /** + * This thread local maintains a per-thread stack of ControlContainerContext instances. + */ + private static ThreadLocal> _threadContexts = + new ThreadLocal>(); + + /** + * Returns the active ControlContainerContext for the current thread, or null if no + * context is currently active. + * @return the current active ControlContainerContext + */ + public static ControlContainerContext getContext() + { + Stack contextStack = _threadContexts.get(); + if (contextStack == null || contextStack.size() == 0) + return null; + + return contextStack.peek(); + } + + /** + * Defines the beginning of a new control container execution context. + */ + public static void beginContext(ControlContainerContext context) + { + Stack contextStack = _threadContexts.get(); + if (contextStack == null) + { + contextStack = new Stack(); + _threadContexts.set(contextStack); + } + contextStack.push(context); + } + + /** + * Ends the current control container execution context + * @throws IllegalStateException if there is not current active context or it is not + * the requested context. + */ + public static void endContext(ControlContainerContext context) + { + Stack contextStack = _threadContexts.get(); + if (contextStack == null || contextStack.size() == 0) + throw new IllegalStateException("No context started for current thread"); + + if (contextStack.peek() != context) + throw new IllegalStateException("Context is not the current active context"); + + contextStack.pop(); + } +} diff --git a/controls/src/api/org/apache/beehive/controls/api/context/ResourceContext.java b/controls/src/api/org/apache/beehive/controls/api/context/ResourceContext.java new file mode 100644 index 0000000..a0ae1f0 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/context/ResourceContext.java @@ -0,0 +1,167 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.context; + +import org.apache.beehive.controls.api.events.EventSet; + +/** + * The ResourceContext interface defines a basic contextual service for coordinating the + * resource utilization of a control implementation within a resource scope defined external + * to the control. This contextual service that provides assistance to a Control in managing + * any external resources (connections, sesssions, etc) that may be relatively expensive to + * obtain and/or can only be held for a relatively short duration. + *

+ * A ResourceContext implementation may be provided by an external container of Controls, such + * as a servlet engine or EJB container, that coordinates the resource lifecycle of controls with + * the activities of the external container. For example, the resource scope for a + * ResourceContext provider associated with the web tier might enable control resources to be + * used for the duration of a single http request; for the EJB tier it might mean for the + * lifetime of the current EJB invocation or active transaction. + *

+ * A control implementation participates in this resource management contract by declaring a + * ResourceContext instance annotated with the + * @Context annotation, the standard service provider model of the Control runtime will + * associate the control instance with a ResourceControl provider implementation that is + * associated with the current execution context. This is demonstrated by the following + * code excerpt from a ControlImplementation class: + *

+ *


+ * @org.apache.beehive.controls.api.bean.ControlImplementation
+ * public class MyControlImpl
+ * {
+ *     ...
+ *     // Declare need for resource mgmt support via the ResourceContext service
+ *     @org.apache.beehive.controls.api.context.Context
+ *     ResourceContext resourceContext;
+ *     ...
+ * 
+ *

+ * Once the control has been associated with a ResourceContext provider, the provider will + * deliver events to the Control Implementation instance according to the following basic + * contract: + *

+ *

    + *
  • the ResourceContext provider notifies a control implementation when it should acquire its + * resources using the onAcquire event. + *
  • the ResourceContext provider notifies a control implementation when it should release its + * resources using the onRelease event. + *
+ *

+ * The following code fragment shows how to receive resource events from within a Control + * implementation: + *

+ *


+ * import org.apache.beehive.controls.api.events.EventHandler;
+ * 
+ * ...
+ *
+ * @EventHandler(field="resourceContext",
+ *                eventSet=ResourceContext.ResourceEvents.class,
+ *                eventName="onAcquire")
+ * public void onAcquire() 
+ * { 
+ *      // code to obtain connections/sessions/...
+ * }
+ * 
+ * @EventHandler(field="resourceContext", 
+ *                eventSet=ResourceContext.ResourceEvents.class,
+ *                eventName="onRelease")
+ * public void onRelease() 
+ * { 
+ *      // code to release connections/sessions/...
+ * }
+ * 
+ *

+ * The onAcquire resource event is guaranteed to be delivered once before any operation declared + * on a public or extension interface associated with the control. This event will be delivered + * once, and only once, within a particular resource scope associated with the ResourceContext. + * + * If a control needs to utilize its resources in another context (such as in response to a + * PropertyChange notification), the ResourceContext also provides support for manually + * acquiring and releasing resources. + * + * @see org.apache.beehive.controls.api.context.ResourceContext.ResourceEvents + * @see org.apache.beehive.controls.api.context.Context + * @see org.apache.beehive.controls.api.events.EventHandler + */ +public interface ResourceContext +{ + /** + * The acquire method allows a Control implementation to manually request acquisition. + * This is useful in contexts where the control needs access to associated resources + * from outside the scope of an operation. If invoked when the control has not currently + * acquired resources, the onAcquire event will be delivered to the control and it will + * be registered in the current resource scope as holding resources. If the control has + * previously acquired resources in the current resource scope, then calling acquire() + * will have no effect. + */ + public void acquire(); + + /** + * The release method allows a Control implement to manually release resources immediately, + * instead of waiting until the end of the current resource scope. If invoked when the + * control has currently acquired resources, the onRelease event will be delivered immediately + * and the control will no longer be in the list of controls holding resources in the current + * resource scope. If the control has not previously acquired resources, then calling + * release() will have no effect. + */ + public void release(); + + /** + * The hasResources method returns true if the control has currently acquired resources, + * false otherwise. + */ + public boolean hasResources(); + + /** + * The ResourceEvents interface defines the resource events delivered by a ResourceContext + * provider. + */ + @EventSet + public interface ResourceEvents + { + /** + * The onAcquire event will be delivered by a ResourceContext provider to the + * Control implementation before any operation on the control is invoked within + * the resource scope associated with the provider and its associated container. This + * provides the opportunity for the implementation instance to obtain any resource it + * uses to provide its services. + */ + public void onAcquire(); + + /** + * The onRelease event will be delivered by a ResourceContext provider to the + * Control implementation immediately before before the end of the resource + * scope associated with the provider and its associated container. This provides + * the opportunity for the implementation instance to relinquish any resources it + * obtained during onAcquire event handling. + */ + public void onRelease(); + } + + /** + * Registers a listener that implements the ResourceEvents interface for the ResourceContext. + */ + public void addResourceEventsListener(ResourceEvents resourceListener); + + /** + * Unregisters a listener that implements the ResourceEvents interface for the ResourceContext. + */ + public void removeResourceEventsListener(ResourceEvents resourceListener); +} diff --git a/controls/src/api/org/apache/beehive/controls/api/events/Client.java b/controls/src/api/org/apache/beehive/controls/api/events/Client.java new file mode 100644 index 0000000..1778181 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/events/Client.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.events; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * The Client annotation type is used to mark fields in a Control implementation class + * that define client event proxies. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD}) +public @interface Client +{ +} diff --git a/controls/src/api/org/apache/beehive/controls/api/events/EventDispatchHelper.java b/controls/src/api/org/apache/beehive/controls/api/events/EventDispatchHelper.java new file mode 100644 index 0000000..c0c1768 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/events/EventDispatchHelper.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.events; + +import java.lang.reflect.InvocationTargetException; + +import org.apache.beehive.controls.api.context.ControlContainerContext; +import org.apache.beehive.controls.api.context.ControlHandle; +import org.apache.beehive.controls.api.context.ControlThreadContext; + +/** + * The EventDispatchHelper class is a simple implementation of the EventDispatcher interface + * that is suitable for use inside the execution context of a control container. It + * assumes that you are already running inside the target container instance, and all that is + * required is the correct routing of the event to the correct control. + */ +public class EventDispatchHelper implements EventDispatcher +{ + public Object dispatchEvent(ControlHandle target, EventRef event, Object [] args) + throws IllegalAccessException, IllegalArgumentException, InvocationTargetException + { + // + // Obtain the current active control container context + // + ControlContainerContext context = ControlThreadContext.getContext(); + if (context == null) + throw new IllegalStateException("No active control container context"); + + // + // Dispatch the event using it. + // + return context.dispatchEvent(target, event, args); + } +} diff --git a/controls/src/api/org/apache/beehive/controls/api/events/EventDispatcher.java b/controls/src/api/org/apache/beehive/controls/api/events/EventDispatcher.java new file mode 100644 index 0000000..11f4c30 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/events/EventDispatcher.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.events; + +import java.lang.reflect.InvocationTargetException; + +import org.apache.beehive.controls.api.context.ControlHandle; + +/** + * The EventDispatcher interface defines the method signature that a container supporting + * the external dispatch of Control events would implement. + */ +public interface EventDispatcher +{ + /** + * Dispatches a Control event to a target control. + * @param target the target control + * @param event the event to deliver to the control + * @param args the parameters to the control event + * @throws IllegalAccessException the underlying event method is not accessible due to + * access control. + * @throws IllegalArgumentException the target is not valid, the event is not a valid event + * type for the requested target, or the argument types do not match the event + * signature. + * @throws InvocationTargetException wraps any exception thrown by the underlying event + * handler. + */ + public Object dispatchEvent(ControlHandle target, EventRef event, Object [] args) + throws IllegalAccessException, IllegalArgumentException, + InvocationTargetException; +} diff --git a/controls/src/api/org/apache/beehive/controls/api/events/EventDispatcherRemote.java b/controls/src/api/org/apache/beehive/controls/api/events/EventDispatcherRemote.java new file mode 100644 index 0000000..0d60258 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/events/EventDispatcherRemote.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.events; + +import java.rmi.RemoteException; + +import org.apache.beehive.controls.api.context.ControlHandle; + +/** + * The EventDispatcherRemote interface defines the event dispatch signature when event + * dispatching is happening via RMI. + * + * @see org.apache.beehive.controls.api.events.EventDispatcher + */ +public interface EventDispatcherRemote +{ + /** + * Dispatches a Control event to a target control. + * @param target the target control + * @param event the event to deliver to the control + * @param args the parameters to the control event + * @throws RemoteException wraps any exception thrown during event dispatch + */ + public Object dispatchEvent(ControlHandle target, EventRef event, Object [] args) + throws RemoteException; +} diff --git a/controls/src/api/org/apache/beehive/controls/api/events/EventHandler.java b/controls/src/api/org/apache/beehive/controls/api/events/EventHandler.java new file mode 100644 index 0000000..e4ed3a6 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/events/EventHandler.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.events; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * The EventHandler annotation type is used to mark a method that provides the event handler + * implementation for a Control event. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +public @interface EventHandler +{ + /** + * The field name of the Java control event source. This must be an @Control field declared + * on the class defining the event handler method (or on a superclass if the field is not + * declared to be private). + */ + String field(); + + /** + * The EventSet interface that declares the event. This must be a valid EventSet interface + * associated with the control type of the field member. + */ + Class eventSet(); + + /** + * The name of the handled event. This must be the name of a method declared on the EventSet + * interface referenced by the eventSet member. The annotated method must have + * an event signature that exactly matches one of the event methods with this name. + */ + String eventName(); +} diff --git a/controls/src/api/org/apache/beehive/controls/api/events/EventRef.java b/controls/src/api/org/apache/beehive/controls/api/events/EventRef.java new file mode 100644 index 0000000..55742ce --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/events/EventRef.java @@ -0,0 +1,255 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.events; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.WeakHashMap; + +/** + * The EventRef class represents a reference to a specific Control event. EventRefs can + * be used to fire external events into a Control, in contexts where the event source may + * not share the associated EventSet class instance with the event target, or even have + * access to the EventSet class itself. + *

+ * It is roughly equivalent to the java.lang.reflect.Method object that refers to a method + * on an EventSet interface, but has several additional properties: + *

    + *
  • It is serializable, so can be persisted/restored or passed across the wire
  • + *
  • It supports materializing the EventRef back to a Method reference in a way that allows + * EventRefs to be passed across class loaders
  • + *
  • It can be constructed in contexts where a reference to the actual EventSet class might + * not be available (using a String event descriptor format to describe events)
  • + *
+ */ +public class EventRef implements java.io.Serializable +{ + // + // Static helper map to go from a primitive type to the type descriptor string + // + static private HashMap _primToType = new HashMap(); + static + { + _primToType.put(Integer.TYPE, "I"); + _primToType.put(Boolean.TYPE, "Z"); + _primToType.put(Byte.TYPE, "B"); + _primToType.put(Character.TYPE, "C"); + _primToType.put(Short.TYPE, "S"); + _primToType.put(Long.TYPE, "J"); + _primToType.put(Float.TYPE, "F"); + _primToType.put(Double.TYPE, "D"); + _primToType.put(Void.TYPE, "V"); + } + + /** + * Constructs a new EventRef based upon a Method reference. The input method must be one + * that is declared within a Control EventSet interface. + * @param eventMethod the Method associated with the event + */ + public EventRef(Method eventMethod) + { + _method = eventMethod; + _descriptor = computeEventDescriptor(eventMethod); + } + + /** + * Constructs a new EventRef using an event descriptor string. The format of this string + * is: + *
 
+     *      .
+     * 
+ * where eventSet refers to the fully qualified name of the EventSet class, + * eventName refers to the name of the event Method, and eventDescriptor + * describes the event argument and return types using the method descriptor format + * defined in the Java Language Specification. + *

+ * For example, given the following EventSet interface: + *

+     * @ControlInterface
+     * public interface MyControl
+     * {
+     *     @EventSet
+     *     public interface MyEvents
+     *     {
+     *          public String myEvent(int arg0, Object arg2);
+     *     }
+     * }
+     * 
+ * the eventDescriptor for myEvent would be: + *
 
+     *     MyControl.MyEvents.myEvent(ILjava/lang/Object;)Ljava/lang/String;
+     * 
+ * @param eventDescriptor the event descriptor string associated with the event + */ + public EventRef(String eventDescriptor) + { + _descriptor = eventDescriptor; + } + + /** + * Returns the event descriptor string associated with the EventRef. + * @param controlInterface the ControlInterface + */ + public String getEventDescriptor(Class controlInterface) + { + // + // NOTE: The input controlInterface is currently unused, but included to + // enable downstream optimization of serialization representation. See the + // OPTIMIZE comment below for more details. If implemented, the interface + // is needed to reverse the transformation from a hash back to a method or + // descriptor. + // + if (_descriptor == null) + _descriptor = computeEventDescriptor(_method); + + return _descriptor; + } + + /** + * Helper method that computes the event descriptor sting for a method + */ + private String computeEventDescriptor(Method method) + { + StringBuilder sb = new StringBuilder(); + + // Add event class and method name + sb.append(method.getDeclaringClass().getName()); + sb.append("."); + sb.append(method.getName()); + + // Add event arguments + Class [] parms = method.getParameterTypes(); + sb.append("("); + for (int i = 0; i < parms.length; i++) + appendTypeDescriptor(sb, parms[i]); + sb.append(")"); + + // Add event return type + appendTypeDescriptor(sb, method.getReturnType()); + + return sb.toString(); + } + + /** + * Helper method that appends a type descriptor to a StringBuilder. Used + * while accumulating an event descriptor string. + */ + private void appendTypeDescriptor(StringBuilder sb, Class clazz) + { + if (clazz.isPrimitive()) + sb.append(_primToType.get(clazz)); + else if (clazz.isArray()) + sb.append(clazz.getName().replace('.','/')); + else + { + sb.append("L"); + sb.append(clazz.getName().replace('.','/')); + sb.append(";"); + } + } + + /** + * Returns the event Method associated with this EventRef. + */ + public Method getEventMethod(Class controlInterface) + { + // + // If we already hold a method reference and its loader matches up with the input + // interface, then just return it. + // + if (_method != null && + _method.getDeclaringClass().getClassLoader().equals(controlInterface.getClassLoader())) + return _method; + + // + // Otherwise, obtain the mapping from descriptors to methods, and use it to + // convert back to a method. + // + String eventDescriptor = getEventDescriptor(controlInterface); + HashMap descriptorMap = getDescriptorMap(controlInterface); + if (!descriptorMap.containsKey(eventDescriptor)) + { + throw new IllegalArgumentException("Control interface " + controlInterface + + " does not contain an event method that " + + " corresponds to " + eventDescriptor); + } + return descriptorMap.get(eventDescriptor); + } + + /** + * A WeakHashMap used to cache the event descriptor-to-Method mapping for control + * interfaces. + */ + static private WeakHashMap> _descriptorMaps = + new WeakHashMap>(); + + private HashMap getDescriptorMap(Class controlInterface) + { + // + // If the local cache has the mapping, then return it. + // + HashMap descMap = _descriptorMaps.get(controlInterface); + if (descMap == null) + { + // + // Compute the mapping from event descriptors to event methods, using reflection + // + descMap = new HashMap(); + Class [] innerClasses = controlInterface.getClasses(); + for (int i = 0; i < innerClasses.length; i++) + { + if (!innerClasses[i].isInterface() || + !innerClasses[i].isAnnotationPresent(EventSet.class)) + continue; + + Method [] eventMethods = innerClasses[i].getMethods(); + for (int j = 0; j < eventMethods.length; j++) + descMap.put(computeEventDescriptor(eventMethods[j]), eventMethods[j]); + } + _descriptorMaps.put(controlInterface, descMap); + } + return descMap; + } + + + /** + * Two EventRefs are equal if the method descriptor string associated with them is equal + */ + public boolean equals(Object obj) + { + if (obj == null || !(obj instanceof EventRef)) + return false; + + return _descriptor.equals(((EventRef)obj)._descriptor); + } + + public String toString() + { + return "EventRef: " + _descriptor; + } + + // + // OPTIMIZE: A more efficient internal representation for serialization/wire purposes + // would be to compute a hash of the descriptor string (ala RMI opnums), that could be + // reconstituted on the other end, given a candidate ControlInterface. The public APIs + // are structured to support this downstream optimization. + // + private String _descriptor; + transient private Method _method; +} diff --git a/controls/src/api/org/apache/beehive/controls/api/events/EventSet.java b/controls/src/api/org/apache/beehive/controls/api/events/EventSet.java new file mode 100644 index 0000000..e66988e --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/events/EventSet.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.events; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * The EventSet annotation type is used to mark an interface that defines a group of events + * associated with a Java Control. By convention, event interfaces are defined as inner + * classes on the Java Control public interface. Each method defined within a + * event interface indicates an event that can be delivered by the control. + *

+ * Here is a simple example: + *

+ * public interface MyControl extends org.apache.beehive.controls.api.Control
+ * {
+ *     @EventSet
+ *     public interface MyEvents
+ *     {
+ *         public void anEvent();
+ *     }
+ *
+ *     ...
+ * }
+ * 
+ * This will declare an event interface named MyEvents that declares a single + * event: anEvent + * + * The declaration of an EventSet for a control also means that the associated Control + * JavaBean will have listener registration/deregistration APIs. The name of these + * APIs will be add/removeListener, and the argument will be an + * listener instance that implements the EventSet interface. + *

+ * The above example would result in the following APIs on MyControlBean + * + *

+ * public class MyControlBean implements MyControl
+ * {
+ *     ...
+ *     public void addMyEventsListener(MyEvents listener) { ... }
+ *     public void removeMyEventsListener(MyEvents listener) { ... }
+ * 
+ */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +public @interface EventSet +{ + /** + * Defines whether the events defined by the interface are unicast events. A unicast + * event set may have only a single listener registered to receive events for any + * given bean instance. Any attempt to register additional listeners will result in + * a java.util.TooManyListenersException being thrown by the event + * listener registration method. + *

+ * If an event set provides multicast support (the default), then it may only declare + * event methods that have a void return type. Unicast event sets may + * support event return values, that will be provided by the (single) registered + * listener. + */ + public boolean unicast() default false; +} diff --git a/controls/src/api/org/apache/beehive/controls/api/events/RemoteEventDispatcher.java b/controls/src/api/org/apache/beehive/controls/api/events/RemoteEventDispatcher.java new file mode 100644 index 0000000..26b1cc4 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/events/RemoteEventDispatcher.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.events; + +import java.rmi.RemoteException; + +import org.apache.beehive.controls.api.context.ControlHandle; + +/** + * The RemoteEventDispatcher interface defines the method signature that a container supporting + * the external dispatch of Control events would implement if events can be dispatched using RMI. + */ +public interface RemoteEventDispatcher +{ + /** + * Dispatches a Control event to a target control. + * @param target the target control + * @param event the event to deliver to the control + * @param args the parameters to the control event + * @throws IllegalAccessException the underlying event method is not accessible due to + * access control. + * @throws IllegalArgumentException the target is not valid, the event is not a valid event + * type for the requested target, or the argument types do not match the event + * signature. + * @throws InvocationTargetException wraps any exception thrown by the underlying event + * handler. + */ + public Object dispatchEvent(ControlHandle target, EventRef event, Object [] args) + throws RemoteException; +} diff --git a/controls/src/api/org/apache/beehive/controls/api/packaging/BeanInfo.java b/controls/src/api/org/apache/beehive/controls/api/packaging/BeanInfo.java new file mode 100644 index 0000000..31aa7d9 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/packaging/BeanInfo.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.packaging; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + +/** + * The FeatureInfo annotation type defines a JSR-175 syntax for annotating a Control to + * provide BeanInfo FeatureDescriptor information for the bean, its properties, methods, + * or events. + *

+ * The elements of FeatureInfo correspond 1-to-1 with the information exposed by the + * java.beans.FeatureDescriptor class. + * + * @see java.beans.FeatureDescriptor + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +public @interface BeanInfo +{ + /** + * The NoCustomizer class can be used as the value of the customizerClass attribute to + * indicate that the bean has no customizer. + */ + static public class NoCustomizer {} + + public Class customizerClass() default NoCustomizer.class; +} diff --git a/controls/src/api/org/apache/beehive/controls/api/packaging/EventSetInfo.java b/controls/src/api/org/apache/beehive/controls/api/packaging/EventSetInfo.java new file mode 100644 index 0000000..d6f0dd2 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/packaging/EventSetInfo.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.packaging; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + +/** + * The EventSetInfo annotation type defines a JSR-175 syntax for annotating a Control + * property declaration to provide java.beans.EventSetDescriptor information. Generic + * feature information is defined using the FeatureInfo annotation type + *

+ * The elements of EventStInfo correspond 1-to-1 with the information exposed by the + * java.beans.EventSetDescriptor class. + * + * @see java.beans.EventSetDescriptor + */ +@Target({ElementType.TYPE}) // appears on EventSet interface declaration +public @interface EventSetInfo +{ + public boolean isUnicast() default false; // single listener model + public boolean isDefault() default true; // is the default event set +} diff --git a/controls/src/api/org/apache/beehive/controls/api/packaging/FeatureAttribute.java b/controls/src/api/org/apache/beehive/controls/api/packaging/FeatureAttribute.java new file mode 100644 index 0000000..3f8ae75 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/packaging/FeatureAttribute.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.packaging; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + +/** + * The FeatureAttribute annotation type defines a JSR-175 syntax for specifying JavaBean + * FeatureDescriptor attributes associated with a Control. + * + * @see org.apache.beehive.controls.api.packaging.FeatureInfo + */ +public @interface FeatureAttribute +{ + /* Specifies the feature attribute name */ + public String name(); + + /* Specifies the feature attribute value */ + public String value(); +} diff --git a/controls/src/api/org/apache/beehive/controls/api/packaging/FeatureInfo.java b/controls/src/api/org/apache/beehive/controls/api/packaging/FeatureInfo.java new file mode 100644 index 0000000..b9719cc --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/packaging/FeatureInfo.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.packaging; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + +/** + * The FeatureInfo annotation type defines a JSR-175 syntax for annotating a Control to + * provide BeanInfo FeatureDescriptor information for the bean, its properties, methods, + * or events. + *

+ * The elements of FeatureInfo correspond 1-to-1 with the information exposed by the + * java.beans.FeatureDescriptor class. + * + * @see java.beans.FeatureDescriptor + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +public @interface FeatureInfo +{ + public String displayName() default ""; // default: use reflection name + public String name() default ""; // default: use reflection name + public String shortDescription() default ""; + public boolean isExpert() default false; + public boolean isHidden() default false; + public boolean isPreferred() default false; + public FeatureAttribute [] attributes() default {}; +} diff --git a/controls/src/api/org/apache/beehive/controls/api/packaging/ManifestAttribute.java b/controls/src/api/org/apache/beehive/controls/api/packaging/ManifestAttribute.java new file mode 100644 index 0000000..7616877 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/packaging/ManifestAttribute.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.packaging; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + +/** + * The ManifestAttribute annotation type defines a JSR-175 syntax for specifying JAR + * manifest attributes associated with a control type. The Beehive Controls packaging + * support will process these annotation during the construction of a JAR file that + * contains Controls. + */ +@Target({ElementType.TYPE}) +public @interface ManifestAttribute +{ + /* Specifies the manifest attribute name */ + public String name(); + + /* Specifies the manifest attribute value */ + public String value(); +} diff --git a/controls/src/api/org/apache/beehive/controls/api/packaging/ManifestAttributes.java b/controls/src/api/org/apache/beehive/controls/api/packaging/ManifestAttributes.java new file mode 100644 index 0000000..5832209 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/packaging/ManifestAttributes.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.packaging; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + +/** + * The ManifestAttributes annotation type enables a set of manifest attributes attributes + * to be defined for a given control type. + * + * @see org.apache.beehive.controls.api.packaging.ManifestAttribute + */ +@Target({ElementType.TYPE}) +public @interface ManifestAttributes +{ + /* Specifies the set of ManifestAttribute annotation values */ + public ManifestAttribute [] value(); +} diff --git a/controls/src/api/org/apache/beehive/controls/api/packaging/PropertyInfo.java b/controls/src/api/org/apache/beehive/controls/api/packaging/PropertyInfo.java new file mode 100644 index 0000000..7c14a4c --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/packaging/PropertyInfo.java @@ -0,0 +1,49 @@ +package org.apache.beehive.controls.api.packaging; + +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + +import java.beans.PropertyEditor; + +/** + * The PropertyInfo annotation type defines a JSR-175 syntax for annotating a Control + * property declaration to provide java.beans.PropertyDescriptor information. Generic + * feature information is defined using the FeatureInfo annotation type + *

+ * The elements of PropertyInfo correspond 1-to-1 with the information exposed by the + * java.beans.PropertyDescriptor class. + * + * @see java.beans.PropertyDescriptor + */ +@Target({ElementType.METHOD}) // appears on PropertySet method declaration (i.e. properties) +public @interface PropertyInfo +{ + /** + * The NoEditor class can be used as the value of the editorClass attribute to + * indicate that the property has no editor + */ + static public class NoEditor {}; + + public boolean bound() default false; // Sends PropertyChange events + public boolean constrained() default false; // Sends VetoableChange events + public Class editorClass() default NoEditor.class; // default == no editor +} diff --git a/controls/src/api/org/apache/beehive/controls/api/properties/AnnotatedElementMap.java b/controls/src/api/org/apache/beehive/controls/api/properties/AnnotatedElementMap.java new file mode 100644 index 0000000..3cad6ca --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/properties/AnnotatedElementMap.java @@ -0,0 +1,292 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.properties; + +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.lang.annotation.Inherited; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import org.apache.beehive.controls.api.bean.ControlBean; +import org.apache.beehive.controls.api.bean.ControlExtension; +import org.apache.beehive.controls.api.bean.ControlInterface; + +/** + * The AnnotatedElementMap represents a read-only PropertyMap where property values are + * derived from Java 5.0 (JSR-175) annotations. + */ +public class AnnotatedElementMap + extends BaseMap + implements PropertyMap,java.io.Serializable +{ + /** + * Creates a new PropertyMap that is initialized based upon the type and annotations + * associated with an AnnotatedElement. + */ + public AnnotatedElementMap(AnnotatedElement annotElem) + { + if (annotElem instanceof Class) + setMapClass((Class)annotElem); + else if (annotElem instanceof Field) + setMapClass(((Field)annotElem).getType()); + else if (annotElem instanceof Method) + { + Class mapClass = getMethodMapClass((Method)annotElem); + setMapClass(mapClass); + } + else + throw new IllegalArgumentException("Unsupported element type: " + annotElem.getClass()); + + _annotElem = annotElem; + } + + // For methods, make sure we find a declaring class that is a valid + // map class. For extended callback methods, we need to walk up a bit + // further in the hierarchy. + + Class getMethodMapClass(Method method) { + + Class origMapClass = method.getDeclaringClass(); + Class mapClass = origMapClass; + while (mapClass != null && !isValidMapClass(mapClass)) { + mapClass = mapClass.getDeclaringClass(); + } + if (mapClass == null) { + mapClass = origMapClass; + } + return mapClass; + } + + boolean isValidMapClass(Class mapClass) { + if (ControlBean.class.isAssignableFrom(mapClass)) + { + return true; + } + else + { + if (mapClass.isAnnotation() || + mapClass.isAnnotationPresent(ControlInterface.class) || + mapClass.isAnnotationPresent(ControlExtension.class)) { + return true; + } + } + return false; + } + + /** + * Sets the property specifed by 'key' within this map. + */ + public void setProperty(PropertyKey key, Object value) + { + throw new IllegalStateException("AnnotatedElementMap is a read-only PropertyMap"); + } + + /** + * Returns the property value specified by 'key' within this map. + */ + public Object getProperty(PropertyKey key) + { + if (!isValidKey(key)) + throw new IllegalArgumentException("Key " + key + " is not valid for " + _mapClass); + + + // + // Look for the property value on the associated annotated element + // + Class propertySet = key.getPropertySet(); + Annotation annot = _annotElem.getAnnotation(propertySet); + if (annot != null) + return key.extractValue(annot); + + // + // If the property supports inheritance and the annotated element is an interface, + // then we'll search up the ControlInheritance/Extension hierachy to see if it is + // provided higher up the chain. + // + if (propertySet.isAnnotationPresent(Inherited.class) && _annotElem instanceof Class) + { + Class controlIntf = (Class)_annotElem; + do + { + Class [] superIntfs = controlIntf.getInterfaces(); + controlIntf = null; + for (int i = 0; i < superIntfs.length; i++) + { + if (superIntfs[i].isAnnotationPresent(ControlInterface.class) || + superIntfs[i].isAnnotationPresent(ControlExtension.class)) + { + controlIntf = superIntfs[i]; + annot = controlIntf.getAnnotation(propertySet); + if (annot != null) + return key.extractValue(annot); + } + } + + } + while (controlIntf != null); + } + + // + // Call up to superclass for delegation / default value + // + return super.getProperty(key); + } + + /** + * Returns true if the PropertyMap contains one or more values for the specified + * PropertySet, false otherwise + */ + public boolean containsPropertySet(Class propertySet) + { + if (_annotElem.isAnnotationPresent(propertySet)) + return true; + + // + // Call up to superclass for delegation + // + return super.containsPropertySet(propertySet); + } + + /** + * Returns the AnnotatedElement used for PropertyMap values. + */ + public AnnotatedElement getAnnotatedElement() + { + return _annotElem; + } + + /** + * Returns a String version of method argument lists based upon the method argument types + */ + private String getMethodArgs(Method m) + { + StringBuffer sb = new StringBuffer(); + Class [] argTypes = m.getParameterTypes(); + for (int i = 0; i < argTypes.length; i++) + { + if (i != 0) sb.append(","); + sb.append(argTypes[i].toString()); + } + return sb.toString(); + } + + /** + * Overrides the standard Serialization writeObject method to compute and store the element + * information in a serializable form. + */ + private void writeObject(java.io.ObjectOutputStream out) throws IOException + { + // + // When serializing, compute sufficient information about the annotated element to + // allow it to be reassociated later in readObject + // + if (_annotElem instanceof Class) + { + _elemClass = (Class)_annotElem; + _elemDesc = null; // non required + } + else if (_annotElem instanceof Field) + { + Field f = (Field)_annotElem; + _elemClass = f.getDeclaringClass(); + _elemDesc = f.getName(); + } + else if (_annotElem instanceof Method) + { + Method m = (Method)_annotElem; + _elemClass = m.getDeclaringClass(); + _elemDesc = m.getName() + "(" + getMethodArgs(m) + ")"; + } + + out.defaultWriteObject(); + } + + /** + * Overrides the standard Serialization readObject implementation to reassociated with the + * target AnnotatedElement after deserialization. + */ + private void readObject(java.io.ObjectInputStream in) + throws IOException, ClassNotFoundException + { + in.defaultReadObject(); + + if (_elemDesc == null) // element is a Class + _annotElem = _elemClass; + else + { + int argsIndex = _elemDesc.indexOf('('); + if (argsIndex < 0) // element is a Field + { + try + { + _annotElem = _elemClass.getDeclaredField(_elemDesc); + } + catch (NoSuchFieldException nsfe) + { + throw new IOException("Unable to locate field " + nsfe); + } + } + else // element is a method + { + String methodName = _elemDesc.substring(0, argsIndex); + if (_elemDesc.charAt(argsIndex+1) == ')') + { + // At least handle the null args case quickly + try + { + _annotElem = _elemClass.getDeclaredMethod(methodName, new Class [] {}); + } + catch (NoSuchMethodException nsme) + { + throw new IOException("Unable to locate method " +_elemDesc); + } + } + else + { + // Linear search for the rest :( + String methodArgs = _elemDesc.substring(argsIndex+1, _elemDesc.length()-1); + Method [] methods = _elemClass.getDeclaredMethods(); + for (int i = 0; i < methods.length; i++) + { + if (methods[i].getName().equals(methodName) && + getMethodArgs(methods[i]).equals(methodArgs)) + { + _annotElem = methods[i]; + break; + } + } + + if (_annotElem == null) + { + throw new IOException("Unable to locate method " + _elemDesc); + } + } + } + } + } + + // The AnnotatedElement upon which this PropertyMap is based. This is marked transient, + // because many Reflection types are not Serializable. + transient private AnnotatedElement _annotElem; + + private Class _elemClass; // Class associated with the annotated element + private String _elemDesc; // Description of the element +} diff --git a/controls/src/api/org/apache/beehive/controls/api/properties/BaseMap.java b/controls/src/api/org/apache/beehive/controls/api/properties/BaseMap.java new file mode 100644 index 0000000..db0c6c0 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/properties/BaseMap.java @@ -0,0 +1,217 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.properties; + +import java.lang.annotation.Annotation; + +import org.apache.beehive.controls.api.bean.ControlBean; +import org.apache.beehive.controls.api.bean.ControlExtension; +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.bean.ExternalPropertySets; + +/** + * The BaseMap class provide an abstract base PropertyMap class from which other + * concrete PropertyMap implementation can derive. It contains some common code + * (such as property key validation and the implementation of the base delegation model) + * that is generically useful. + */ +abstract public class BaseMap implements PropertyMap, java.io.Serializable +{ + /** + * Sets the PropertySet or Control interface associated with this map. Only properties + * declared by the PropertySet or one of the PropertySets on the Control interface may + * be used with this map. + */ + protected void setMapClass(Class mapClass) + { + // + // If the provided map class is a ControlBean type, then locate associated control + // interface or extension that defines properties. + // + if (ControlBean.class.isAssignableFrom(mapClass)) + { + Class [] intfs = mapClass.getInterfaces(); + for (int i = 0; i < intfs.length; i++) + { + if (intfs[i].isAnnotationPresent(ControlInterface.class) || + intfs[i].isAnnotationPresent(ControlExtension.class)) + { + mapClass = intfs[i]; + break; + } + } + } + else + { + if (!mapClass.isAnnotation() && + !mapClass.isAnnotationPresent(ControlInterface.class) && + !mapClass.isAnnotationPresent(ControlExtension.class)) + throw new IllegalArgumentException(mapClass+" must be Control or annotation type"); + } + + _mapClass = mapClass; + } + + /** + * Returns the PropertySet or Control interface class associated with the PropertyMap. + */ + public Class getMapClass() { return _mapClass; } + + /** + * Checks to see if the provided class is a control or property set interface that is + * compatible with the local PropertyMap. + */ + private boolean isCompatibleClass(Class checkClass) + { + // + // If the check class is equal to or a super-interface of the map class, then + // they are compatible. + // + if (_mapClass.isAssignableFrom(checkClass)) + return true; + + // + // If the check class is a property set declared by the map class or a super interface + // of the map class, then they are compatible. + // + if (checkClass.isAnnotationPresent(PropertySet.class)) + { + Class declaringClass = checkClass.getDeclaringClass(); + + // External property sets are always compatible. + // TODO: Could do a more extensive check.. + if (declaringClass == null) + return true; + + if (declaringClass.isAssignableFrom(_mapClass)) + return true; + } + + // + // If the map class is a property set declared by the check class or a super interface + // of the check class, then they are compatible. This is the inverse of the last check, + // and happens e.g. when a programatically instantiated control w/ an initial property + // map needs to delegate to the control interface's property map. + // + if (_mapClass.isAnnotationPresent(PropertySet.class)) + { + Class declaringClass = _mapClass.getDeclaringClass(); + if (declaringClass != null && + declaringClass.isAssignableFrom(checkClass)) + return true; + + // External property sets have no declaring class + if (declaringClass == null) + { + ExternalPropertySets eps = (ExternalPropertySets) checkClass.getAnnotation(ExternalPropertySets.class); + if (eps != null) + { + Class[] propSets = eps.value(); + if (propSets != null) + { + for (Class ps : propSets) + { + if (_mapClass.equals(ps)) + return true; + } + } + } + } + } + + return false; + } + + /** + * Checks to ensure that the provided key is a valid key for this PropertyMap + */ + protected boolean isValidKey(PropertyKey key) + { + return isCompatibleClass(key.getPropertySet()); + } + + /** + * Sets a delegate base property map from which values will be derived if not found within + * the local property map. + */ + public synchronized void setDelegateMap(PropertyMap delegateMap) + { + if (!isCompatibleClass(delegateMap.getMapClass())) + throw new IllegalArgumentException("The delegate map type (" + delegateMap.getMapClass() + " is an incompatible type with " + _mapClass); + + _delegateMap = delegateMap; + } + + /** + * Returns a delegate base property map from which values will be derived if not found within + * the local property map. + */ + public PropertyMap getDelegateMap() + { + return _delegateMap; + } + + /** + * Returns the property value specified by 'key' within this map. + */ + public Object getProperty(PropertyKey key) + { + // + // Delegate up to any parent map + // + if (_delegateMap != null) + return _delegateMap.getProperty(key); + + // + // If neither found a value, return the default value + // + return key.getDefaultValue(); + } + + /** + * Returns true if the PropertyMap contains one or more values for the specified + * PropertySet, false otherwise. + */ + public boolean containsPropertySet(Class propertySet) + { + // + // Defer to any delegate map + // + if (_delegateMap != null) + return _delegateMap.containsPropertySet(propertySet); + + return false; + } + + /** + * Returns a PropertySet proxy instance that derives its data from the contents of + * the property map. Will return null if the PropertyMap does not contain any properties + * associated with the specified PropertySet. + */ + public T getPropertySet(Class propertySet) + { + if (!containsPropertySet(propertySet)) + return null; + + return PropertySetProxy.getProxy(propertySet, this); + } + + Class _mapClass; // associated Control or PropertySet class + PropertyMap _delegateMap; // wrapped PropertyMap (or null) +} diff --git a/controls/src/api/org/apache/beehive/controls/api/properties/BaseProperties.java b/controls/src/api/org/apache/beehive/controls/api/properties/BaseProperties.java new file mode 100644 index 0000000..3dd9a70 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/properties/BaseProperties.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.properties; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Base properties that are present intrinsically on all controls. + */ +@PropertySet +@Target( {ElementType.TYPE, ElementType.FIELD} ) +@Retention( RetentionPolicy.RUNTIME ) +public @interface BaseProperties +{ + /** + * Fully qualified classname of the implementation class for the control. If null, + * the default algorithm for * determining the implementation class will be used -- + * basically, adding "Impl" to the control interface name. + */ + String controlImplementation() default ""; +} diff --git a/controls/src/api/org/apache/beehive/controls/api/properties/BeanPropertyMap.java b/controls/src/api/org/apache/beehive/controls/api/properties/BeanPropertyMap.java new file mode 100644 index 0000000..6d88e5c --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/properties/BeanPropertyMap.java @@ -0,0 +1,186 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.properties; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Proxy; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +/** + * The BeanPropertyMap class represents a collection of property values where properties are + * stored in a local HashMap. + */ +public class BeanPropertyMap extends BaseMap implements PropertyMap,java.io.Serializable +{ + private static final HashMap _primToObject = new HashMap(); + + static + { + _primToObject.put(Integer.TYPE, Integer.class); + _primToObject.put(Long.TYPE, Long.class); + _primToObject.put(Short.TYPE, Short.class); + _primToObject.put(Byte.TYPE, Byte.class); + _primToObject.put(Float.TYPE, Float.class); + _primToObject.put(Double.TYPE, Double.class); + _primToObject.put(Character.TYPE, Character.class); + _primToObject.put(Boolean.TYPE, Boolean.class); + } + + /** + * Creates an empty BeanPropertyMap associated with the specific Control public + * interface, PropertySet, or annotation type. + */ + public BeanPropertyMap(Class mapClass) + { + setMapClass(mapClass); + } + + /** + * Creates a BeanPropertyMap that wraps another PropertyMap. Any changes via setProperty + * will be maintained locally on the constructed map, but getProperty will delegate to the + * base PropertyMap for properties not set locally. + */ + public BeanPropertyMap(PropertyMap map) + { + setMapClass(map.getMapClass()); + setDelegateMap(map); + } + + /** + * Creates a BeanPropertyMap where default values are derived from a single annotation + * type instance. This can be used to create a map from a property getter return value, + * to modify element values. + */ + public BeanPropertyMap(T annot) + { + // If the annotation value is actually a PropertySetProxy, then unwrap it and use + // the standard delegation model + try + { + Object handler = Proxy.getInvocationHandler(annot); + if (handler instanceof PropertySetProxy) + { + PropertySetProxy psp = (PropertySetProxy)handler; + setMapClass(psp.getPropertySet()); + setDelegateMap(psp.getPropertyMap()); + return; + } + } + catch (IllegalArgumentException iae) {} // regular annotation + + _annot = annot; + setMapClass(annot.getClass()); + } + + /** + * Sets the property specifed by 'key' within this map. + */ + public synchronized void setProperty(PropertyKey key, Object value) + { + if (!isValidKey(key)) + throw new IllegalArgumentException("Key " + key + " is not valid for " + getMapClass()); + + // + // Validate the value argument, based upon the property type reference by the key + // + Class propType = key.getPropertyType(); + if (value == null) + { + if (propType.isPrimitive() || propType.isAnnotation()) + throw new IllegalArgumentException("Invalid null value for key " + key); + } + else + { + if (propType.isPrimitive()) + propType = (Class)_primToObject.get(propType); + + if (!propType.isAssignableFrom(value.getClass())) + { + throw new IllegalArgumentException("Value class (" + value.getClass() + + ") not of expected type: " + propType); + } + } + _properties.put(key, value); + _propertySets.add(key.getPropertySet()); + } + + /** + * Returns the property value specified by 'key' within this map. + */ + public Object getProperty(PropertyKey key) + { + if (!isValidKey(key)) + throw new IllegalArgumentException("Key " + key + " is not valid for " + getMapClass()); + + // + // Check local properties first + // + if (_properties.containsKey(key)) + return _properties.get(key); + + // + // Return the value of the annotation type instance (if any) + // + if (_annot != null) + return key.extractValue(_annot); + + // + // Call up to superclass, for delegation model / default value + // + return super.getProperty(key); + } + + /** + * Returns true if the PropertyMap contains one or more values for the specified + * PropertySet, false otherwise + */ + public boolean containsPropertySet(Class propertySet) + { + // If we have an annotation type instance and it matches up with the requested + // type, then return true + if (_annot != null && _annot.getClass().equals(propertySet)) + return true; + + if (_propertySets.contains(propertySet)) + return true; + + // + // Call up to superclass, for delegation model + // + return super.containsPropertySet(propertySet); + } + + /** + * Returns the set of PropertyKeys that are locally set in this property map. Note: + * this does not include any properties that might be set as a result of + * property lookup delegation. + */ + public Set getPropertyKeys() { return _properties.keySet(); } + + // local default annotation value, only set if annot constructor form is used + Annotation _annot; + + // locally maintained property values + HashMap _properties = new HashMap(); + + // locally maintained PropertySets + HashSet _propertySets = new HashSet(); +} diff --git a/controls/src/api/org/apache/beehive/controls/api/properties/PropertyKey.java b/controls/src/api/org/apache/beehive/controls/api/properties/PropertyKey.java new file mode 100644 index 0000000..eb78591 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/properties/PropertyKey.java @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.properties; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import org.apache.beehive.controls.api.ControlException; + +/** + * The PropertyKey class represents a key that can be used to set a JSR-175 attribute member + * value within a PropertyMap. + */ +public class PropertyKey implements java.io.Serializable +{ + /** + * This constructor takes the JSR-175 metadata interface that is associated with + * the contained attributes. + */ + public PropertyKey(Class propertySet, String propertyName) + { + if (!propertySet.isAnnotation()) + { + throw new IllegalArgumentException("Class " + propertySet + " is not a valid annotation type"); + } + + try + { + _getMethod = propertySet.getMethod(propertyName, (Class [])null); + _propertySet = propertySet; + _propertyName = propertyName; + _propertyType = _getMethod.getReturnType(); + + // + // Compute a hash code for the key instance that will be constant for all keys + // that reference the same interface/member combo + // + _hashCode = new String(propertySet.getName() + "." + propertyName).hashCode(); + } + catch (NoSuchMethodException nsme) + { + throw new IllegalArgumentException(propertyName + + "is not a valid member of the metadata interface " + propertySet); + } + } + + protected Method getMethod() + { + if (null == _getMethod) + { + try + { + _getMethod = _propertySet.getMethod(_propertyName, (Class [])null); + } + catch(NoSuchMethodException nsmEx) + { + // This can only happen if a PropertySet is incompatibly changed after + // serialization of a PropertyKey (since it is initially validated in + // the constructor). + throw new ControlException("Unable to locate PropertyKey accessor method", nsmEx); + } + } + return _getMethod; + } + + /** + * Computes the default value for the value of this property key, or null if there + * is no defined default. + */ + public Object getDefaultValue() + { + // Query the accessor method for the default value + // This method will return 'null' if there is no defined default + return getMethod().getDefaultValue(); + } + + /** + * Extracts the value of the key from an Annotation instance + */ + /* package */ Object extractValue(Annotation annot) + { + try + { + return getMethod().invoke(annot, new Object [] {}); + } + // TODO -- cleanup exception handling, property defining a PropertyException + catch (RuntimeException re) { throw re; } + catch (Exception e) + { + throw new RuntimeException("Unable to extract value for " + _propertyName, e); + } + } + + public boolean equals(Object obj) + { + // fast success for static key declaration cases + if (this == obj) + return true; + + // fast fail on obvious differences + if (obj == null || !(obj instanceof PropertyKey) || _hashCode != obj.hashCode()) + return false; + + // slower success on two equivalent keys constructed independently + PropertyKey keyObj = (PropertyKey)obj; + return _propertySet.equals(keyObj._propertySet) && + _propertyName.equals(keyObj._propertyName); + } + + public int hashCode() { + return _hashCode; + } + + public String toString() + { + return "PropertyKey: " + _propertySet.getName() + "." + _propertyName; + } + + public Class getPropertySet() { + return _propertySet; + } + + public String getPropertyName() { + return _propertyName; + } + + public Class getPropertyType() { + return _propertyType; + } + + public Annotation[] getAnnotations() { + return getMethod().getAnnotations(); + } + + Class _propertySet; + String _propertyName; + Class _propertyType; + int _hashCode; + + // WARNING: This field should never be accessed directly but instead via the getMethod() + // API. This ensures that the (transient) value is appropriately recomputed when necessary. + private transient Method _getMethod; +} \ No newline at end of file diff --git a/controls/src/api/org/apache/beehive/controls/api/properties/PropertyMap.java b/controls/src/api/org/apache/beehive/controls/api/properties/PropertyMap.java new file mode 100644 index 0000000..fb27400 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/properties/PropertyMap.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.properties; + +import java.lang.annotation.Annotation; + +/** + * The PropertyMap interface represents a collection of ControlBean properties. Concrete + * implementations of this interface might derive property values from a local Map, Java 5.0 + * annotations, external configuration, or other property sources. + */ +public interface PropertyMap +{ + /** + * Returns the PropertySet or Control interface class associated with the PropertyMap. + */ + public Class getMapClass(); + + /** + * Sets a delegate base property map from which values will be derived if not found within + * the local property map. + */ + public void setDelegateMap(PropertyMap delegateMap); + + /** + * Returns a delegate base property map from which values will be derived if not found within + * the local property map. + */ + public PropertyMap getDelegateMap(); + + /** + * Sets the property specifed by 'key' within this map. + */ + public void setProperty(PropertyKey key, Object value); + + /** + * Returns the property value specified by 'key' within this map. + */ + public Object getProperty(PropertyKey key); + + /** + * Returns true if the PropertyMap contains one or more values for the specified + * PropertySet, false otherwise + */ + public boolean containsPropertySet(Class propertySet); + + /** + * Returns a PropertySet proxy instance that derives its data from the contents of + * the property map. Will return null if the PropertyMap does not contain any properties + * associated with the specified PropertySet. + */ + public T getPropertySet(Class propertySet); +} diff --git a/controls/src/api/org/apache/beehive/controls/api/properties/PropertySet.java b/controls/src/api/org/apache/beehive/controls/api/properties/PropertySet.java new file mode 100644 index 0000000..d8c07b1 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/properties/PropertySet.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.properties; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * The PropertySet annotation type is used to mark an interface that defines a set of + * properties that are associated with a Java Control. By convention, property sets + * are declared as an inner annotation types on the Java Control public interface. + *

+ * Each member of the annotation type targeted by the PropertySet annotation + * will define a new property for the control. + *

+ * Here is a simple example: + *

+ * public interface MyControl extends org.apache.beehive.controls.api.Control
+ * {
+ *     @PropertySet
+ *     public @interface MyProperties
+ *     {
+ *         public String aStringProperty();
+ *         public int anIntProperty();
+ *         ...
+       }
+ * }
+ * 
+ *

+ * A Java Control can have multiple property sets associated with it. + */ +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.ANNOTATION_TYPE}) +public @interface PropertySet +{ + /** + * The prefix member defines a prefix that will be used in all property setter/getter + * methods for properties in the PropertySet. It is necessary to specify + * a prefixes when a control interface has multiple property sets that contain + * properties with the same name. + *

+ * The following code shows the basic conventions for setter/getter methods on a Java + * Control Bean: + *

+     *     public void set<prefix><propertyName>(<propertyType> value);
+     *     public <propertyType> get<prefix><propertyName>();
+     * 
/code> + * where prefix is the prefix member value, propertyName is + * the name of the declared property member, and propertyType is the + * type associated with the declared property member. + */ + String prefix() default ""; + + /** + * The externalConfig member defines whether properties in the set will be settable + * via external configuration. + */ + boolean externalConfig() default true; + + /** + * The optional member specifies that this property set may optionally be associated + * with the control. Because there is no way to represent an 'unset' property value, + * optional properties will not expose a getter method to clients; a control + * implementation class can determine whether a property is/is not set, because the + * PropertySet query APIs on ControlBeanContext will return null if unset. For + * properties that are not optional, a PropertySet instance with all default values + * will be returned if unset. + * + * @see org.apache.beehive.controls.api.context.ControlBeanContext#getControlPropertySet + * @see org.apache.beehive.controls.api.context.ControlBeanContext#getMethodPropertySet + */ + boolean optional() default false; + + /** + * The hasSetters member defines whether properties in the set will have programmatic + * setter methods. + */ + boolean hasSetters() default true; +} \ No newline at end of file diff --git a/controls/src/api/org/apache/beehive/controls/api/properties/PropertySetProxy.java b/controls/src/api/org/apache/beehive/controls/api/properties/PropertySetProxy.java new file mode 100644 index 0000000..1743e59 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/properties/PropertySetProxy.java @@ -0,0 +1,139 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.properties; + +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +/** + * The PropertySetProxy class is a dynamic proxy {@link InvocationHandler} class that exposes the + * values held within a PropertyMap as an Object implementing an annotation type interface. + *

+ * This enables properties resolved using the {@link PropertyMap}'s hiearchical resolution mechanism to + * be exposed to the client of the proxy in the same way that Java 5 annotations are + * exposed using raw Java reflection APIs. A proxy of this type should behave identically + * to the one returned from a call to AnnotatedElement.getAnnotation(), but backed + * by a richer, more dynamic resolution mechanism. + * + * @see java.lang.reflect.Proxy + * @see java.lang.reflect.InvocationHandler + * @see java.lang.reflect.AnnotatedElement#getAnnotation + * @see org.apache.beehive.controls.api.properties.PropertySet + * @see org.apache.beehive.controls.api.properties.PropertyMap + */ +public class PropertySetProxy implements InvocationHandler +{ + /** + * Creates a new proxy instance implementing the PropertySet interface and backed + * by the data from the property map. + * + * @param propertySet an annotation type that has the PropertySet meta-annotation + * @param propertyMap the PropertyMap containing property values backing the proxy + * @return proxy that implements the PropertySet interface + */ + public static T getProxy(Class propertySet, PropertyMap propertyMap) + { + assert propertySet != null && propertyMap != null; + + if (!propertySet.isAnnotation()) + throw new IllegalArgumentException(propertySet + " is not an annotation type"); + + return (T)Proxy.newProxyInstance(propertySet.getClassLoader(), + new Class [] {propertySet }, + new PropertySetProxy(propertySet, propertyMap)); + } + + /** + * Private constructor, called only from the getProxy factory method + */ + private PropertySetProxy(Class propertySet, PropertyMap propertyMap) + { + _propertySet = propertySet; + _propertyMap = propertyMap; + } + + // + // InvocationHandler.invoke + // + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable + { + // Handle cases where Object/Annotation methods are called on this + // proxy. We were getting null back from Annotation.annotationType. + Object value = null; + if (method.getDeclaringClass() == Object.class) + { + try { + if (method.getName().equals("getClass")) + { + value = _propertySet; + } + else + { + value = method.invoke(_propertyMap, args); + } + } + catch (Exception e) + { + e.printStackTrace(); + } + } + else if (method.getDeclaringClass() == Annotation.class && + method.getName().equals("annotationType")) + { + value = _propertySet; + } + else + { + + // Query the nested value in the property map + PropertyKey key = new PropertyKey(_propertySet, method.getName()); + value = _propertyMap.getProperty(key); + + // If the returned value is itself a PropertyMap (i.e. a nested annotation type), + // then wrap it in a PropertySetProxy instance before returning. + if (value instanceof PropertyMap) + { + PropertyMap propertyMap = (PropertyMap)value; + value = getProxy(propertyMap.getMapClass(), propertyMap); + } + } + + return value; + } + + /** + * Returns the PropertySet annotation type associated with the proxy + */ + public Class getPropertySet() { + return _propertySet; + } + + /** + * Returns the underlying PropertyMap containing the property values exposed by the + * proxy. + */ + public PropertyMap getPropertyMap() { + return _propertyMap; + } + + private Class _propertySet; + private PropertyMap _propertyMap; +} diff --git a/controls/src/api/org/apache/beehive/controls/api/versioning/Version.java b/controls/src/api/org/apache/beehive/controls/api/versioning/Version.java new file mode 100644 index 0000000..3704f9f --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/versioning/Version.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.versioning; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Used by the control author to specify the version (major.minor) of the control interface. + * Allowed on interfaces annotated with @ControlInterface. This version number + * is the basis for control versioning, and versioning constraints against it are enforced both at + * compile time and runtime. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +public @interface Version +{ + /** + * Major version number, typically used to track significant functionality changes. + */ + int major(); + /** + * Minor version number, typically used to track small internal changes/fixes. Version + * constraints default to ignoring the minor version number in their comparisons, but may + * be configured to specify a particular minor version. + */ + int minor() default 0; +} diff --git a/controls/src/api/org/apache/beehive/controls/api/versioning/VersionRequired.java b/controls/src/api/org/apache/beehive/controls/api/versioning/VersionRequired.java new file mode 100644 index 0000000..a89a012 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/versioning/VersionRequired.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.versioning; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Specifies the minimum version of the control interface that this extension + * requires. Allowed on control extensions (interfaces annotated with + * @ControlExtension), and on control field declarations (fields annotated + * with @Control). The version requirement is enforced at compile time of + * extensions and control client, and at runtime when the appropriate control + * bean is classloaded. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.FIELD}) +public @interface VersionRequired +{ + /** + * The major version value required for this control extension or instance + * declaration to work. Any version number greater than or equal to this + * value will suffice, implying that this requirement is valid only when + * back compatibility is part of the contract when increasing the version + * number. Negative values mean that any major version is + * acceptable (in which case this annotation should probably just not be + * present). + */ + int major(); + + /** + * The minor version value required for this control extension or instance + * declaration to work. Any version number greater than or equal to this + * value will suffice. Negative values mean that any minor version is + * acceptable (the default case). + */ + int minor() default -1; +} diff --git a/controls/src/api/org/apache/beehive/controls/api/versioning/VersionSupported.java b/controls/src/api/org/apache/beehive/controls/api/versioning/VersionSupported.java new file mode 100644 index 0000000..47682b7 --- /dev/null +++ b/controls/src/api/org/apache/beehive/controls/api/versioning/VersionSupported.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.api.versioning; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Specifies the maximum version of the control interface that this implementation + * supports. Allowed on control implementations (interfaces annotated with + * @ControlImplementation). This version requirement is enforced at compile time + * of the implementation, and at runtime when the implementation is classloaded. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +public @interface VersionSupported +{ + /** + * The major version of the control interface that this implementation + * supports. Any version number less than or equal to this value will suffice, + * implying that this constraint is only valid when backwards compatibility + * is part of the contract when increasing the version number. Negative + * values mean that any major version is acceptable (in which case this + * annotation should probably just not be + * present). + */ + int major(); + + /** + * The minor version of the control interface that this implementation + * supports. Any version number less than or equal to this value will suffice. + * Negative values mean that any minor version is acceptable (the default case). + */ + int minor() default -1; +} diff --git a/controls/src/beehive-controls.pom b/controls/src/beehive-controls.pom new file mode 100644 index 0000000..b2ee1fc --- /dev/null +++ b/controls/src/beehive-controls.pom @@ -0,0 +1,51 @@ + + + + + + 4.0.0 + org.apache.beehive + beehive-controls + beehive-controls + @beehive.version@ + + + velocity + velocity-dep + 1.4 + + + commons-discovery + commons-discovery + 0.2 + + + commons-logging + commons-logging + 1.0.4 + + + junit + junit + 3.8.1 + test + + + \ No newline at end of file diff --git a/controls/src/runtime/META-INF/services/com.sun.mirror.apt.AnnotationProcessorFactory b/controls/src/runtime/META-INF/services/com.sun.mirror.apt.AnnotationProcessorFactory new file mode 100644 index 0000000..abbd3ee --- /dev/null +++ b/controls/src/runtime/META-INF/services/com.sun.mirror.apt.AnnotationProcessorFactory @@ -0,0 +1,26 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# $Header:$ +# + +# +# This configures APT so the ControlProcessorFactory can be used to process Control annotations +# +org.apache.beehive.controls.runtime.generator.apt.ControlAnnotationProcessorFactory +org.apache.beehive.controls.runtime.generator.apt.ControlClientAnnotationProcessorFactory +org.apache.beehive.controls.runtime.generator.apt.ControlMemberTypeAnnotationProcessorFactory +org.apache.beehive.controls.runtime.generator.apt.ControlSecondaryAnnotationProcessorFactory diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/assembly/AppAssemblyContext.java b/controls/src/runtime/org/apache/beehive/controls/runtime/assembly/AppAssemblyContext.java new file mode 100644 index 0000000..ffb5e67 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/assembly/AppAssemblyContext.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.assembly; + +import org.apache.beehive.controls.api.assembly.ControlAssemblyContext; +import org.apache.beehive.controls.api.assembly.ControlAssemblyException; + +import java.io.File; +import java.util.Map; +import java.util.Set; + +/** + * A ControlAssemblyContext implementation supporting standard Enterprise app modules + */ +public class AppAssemblyContext + extends BaseAssemblyContext + implements ControlAssemblyContext.EntAppModule +{ + + public static class Factory + implements ControlAssemblyContext.Factory + { + public AppAssemblyContext newInstance( Class controlIntfOrExt, + Map bindings, + Set clients, + File moduleRoot, + String moduleName, + File srcOutputRoot ) + throws ControlAssemblyException + { + return new AppAssemblyContext( controlIntfOrExt, bindings, clients, + moduleRoot, moduleName, srcOutputRoot ); + } + } + + protected AppAssemblyContext( Class controlIntfOrExt, Map bindings, + Set clients, File moduleRoot, + String moduleName, File srcOutputRoot ) + throws ControlAssemblyException + { + super( controlIntfOrExt, bindings, clients, moduleRoot, moduleName, srcOutputRoot ); + } + + public File getApplicationXml() + { + return new File( getModuleDir(), "META-INF" + File.separator + "application.xml" ); + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/assembly/AssembleTask.java b/controls/src/runtime/org/apache/beehive/controls/runtime/assembly/AssembleTask.java new file mode 100644 index 0000000..fff2a32 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/assembly/AssembleTask.java @@ -0,0 +1,268 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.assembly; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.HashMap; +import java.util.Set; +import java.util.TreeSet; +import java.net.URL; +import java.net.URLClassLoader; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.types.FileSet; +import org.apache.beehive.controls.runtime.generator.apt.ControlClientManifest; +import org.apache.beehive.controls.api.assembly.ControlAssemblyException; + +/** + * AssembleTask defines a custom ant task to perform control assembly. + *

+ * The core assembly algorithm is documented and implemented in {@link Assembler}. + *

+ * Required attributes:
+ * moduleDir: path to the root of J2EE module on which to perform assembly.
+ * srcOutputDir: path to the dir where control assemblers may output source files. + * It may be necessary to run additional build steps in order to process such files (for example, + * if an assembler outputs Java source code, that code may need to be compiled).
+ * contextFactoryClassname: fully qualified classname of a factory class that implements + * {@link org.apache.beehive.controls.api.assembly.ControlAssemblyContext.Factory}. Typically this + * would depend on the type of module on which assembly is being run (EJB, webapp, etc). Different + * contexts will expose different APIs to control assemblers (making different descriptors available, + * etc). + *

+ * Supported nested elements:
+ * classpath: specifies the classpath that will be searched for control interfaces/implementations, + * control clients and control assemblers.
+ * fileset: specifies the control client manifests that should be processed by this assembly call.
+ *

+ * An example usage of the AssembleTask in an ant build script (build.xml): + *

+

+ <taskdef name="assemble" classname="org.apache.beehive.controls.runtime.assembly.AssembleTask" + classpathref="controls.dependency.path" onerror="report" /> + + <assemble moduleDir="${build.beans}" + srcOutputDir="${build.beansrc}" + contextFactoryClassname="org.apache.beehive.controls.runtime.assembly.EJBAssemblyContext$Factory"> + <classpath> + <path refid="test.classpath"/> + <pathelement location="${build.beans}"/> + </classpath> + <fileset dir="${build.beans}"> + <include name="**\*.controls.properties"/> + </fileset> + </assemble> + + */ +public class AssembleTask extends Task +{ + public AssembleTask() + { + // do nothing + } + + public void setContextFactoryClassName(String contextFactoryClassName) + { + _contextFactoryClassName = contextFactoryClassName; + } + + public void setModuleDir( File moduleDir ) + { + _moduleDir = moduleDir; + } + + public void setModuleName( String moduleName ) + { + _moduleName = moduleName; + } + + public void setSrcOutputDir( File srcOutputDir ) + { + _srcOutputDir = srcOutputDir; + } + + public void setBindingFile(File bindingFile) + { + _bindingFile = bindingFile; + } + + public FileSet createFileset() + { + _clientManifestFileSet = new FileSet(); + return _clientManifestFileSet; + } + + // used to set classpath as an attribute + public void setClasspath(Path classpath) + { + _classPath = new Path(getProject()); + _classPath.append(classpath); + } + + // used to set classpath as a nested element + public Path createClasspath() + { + _classPath = new Path(getProject()); + return _classPath; + } + + public void execute() + { + validateAttributeSettings(); + + if (_clientManifestFileSet == null) + { + log("No input fileset specified, nothing to do."); + return; + } + + // get list of input files as list of ControlRefs files + File filesetDir = _clientManifestFileSet.getDir(getProject()); + String[] clientManifests = _clientManifestFileSet. + getDirectoryScanner(getProject()).getIncludedFiles(); + + if (clientManifests.length == 0) + { + log("Input fileset contained no files, nothing to do."); + return; + } + + List manifestFiles = new ArrayList(); + for ( String mf : clientManifests ) + { + File f = new File(filesetDir, mf ); + if (!f.exists()) + { + log("File " + f.getAbsolutePath() + + " in input fileset does not exist."); + continue; + } + + manifestFiles.add(f); + } + + // REVIEW: nested control usage is handled poorly right now. + // Need to refine how we pick up control client manifests, especially + // for manifests inside control jars (instead of blindly scanning and + // including all manifests inside all jars, should base it on actual nested + // control usage as analyzed by starting at non-control clients). + try + { + // Build map of control types to assemble by scanning supplied manifests + + Map controlTypesToImpls = new HashMap(); + Map> controlTypesToClients = + new HashMap>(); + + for ( File mf : manifestFiles ) + { + ControlClientManifest ccmf = new ControlClientManifest( mf ); + String controlClient = ccmf.getControlClient(); + List controlTypes = ccmf.getControlTypes(); + for ( String ct : controlTypes ) + { + controlTypesToImpls.put( ct, ccmf.getDefaultImpl( ct ) ); + Set clients = controlTypesToClients.get( ct ); + if (clients == null) + { + clients = new TreeSet(); + controlTypesToClients.put( ct, clients ); + } + clients.add( controlClient ); + } + } + + // Build classloader to do loading + // + // TODO: The module dir should probably be in the classpath, since it seems reasonable + // for assemblers to want access to the classes in the module. + + String[] classpaths = _classPath == null ? new String[0] : _classPath.list(); + ClassLoader cl = buildClassLoader( classpaths, Assembler.class.getClassLoader() ); + + Assembler.assemble( _moduleDir, _moduleName, _srcOutputDir, _contextFactoryClassName, + controlTypesToImpls, controlTypesToClients, cl ); + } + catch (Exception e) + { + e.printStackTrace(); + throw new BuildException("Assembly failed.", e); + } + } + + private void validateAttributeSettings() throws BuildException + { + if (_contextFactoryClassName == null) + throw new BuildException("The contextFactoryClassName attribute must be set"); + + if (_moduleDir == null) + throw new BuildException("The moduleDir attribute must be set"); + + if (_srcOutputDir == null) + throw new BuildException("The srcOutputDir attribute must be set"); + } + + private ClassLoader buildClassLoader( String[] paths, ClassLoader parentCL) + throws ControlAssemblyException + { + List list = new ArrayList(); + for (int i=0; i controlTypeToImpl, + Map> controlTypeToClients, + ClassLoader cl ) + throws ControlAssemblyException, IOException + { + if ( !moduleRoot.exists() || !srcOutputRoot.exists() ) + throw new IOException( "Directories " + moduleRoot + " or " + srcOutputRoot + " don't exist!"); + + if ( factoryName == null ) + throw new ControlAssemblyException( "Missing context factory names" ); + + if ( cl == null ) + throw new ControlAssemblyException( "Must specify a classloader" ); + + ClassLoader origCL = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader( cl ); + + try + { + // Create the requested ControlAssemblyContext.Factory + Class factoryClass = cl.loadClass( factoryName ); + ControlAssemblyContext.Factory factory = (ControlAssemblyContext.Factory)factoryClass.newInstance(); + + // Iterate over control types + Set controlTypes = controlTypeToImpl.keySet(); + for ( String ct : controlTypes ) + { + // Search for applicable ControlAssemblers as specified on the control impls + String cImpl = controlTypeToImpl.get( ct ); + Class cImplClass = cl.loadClass( cImpl ); + + ControlImplementation a = (ControlImplementation)cImplClass.getAnnotation(ControlImplementation.class); + if ( a == null ) + throw new ControlAssemblyException( "Control implementation class=" + cImpl + " missing ControlImplementation annotation" ); + + // For each non-default ControlAssembler, create one and call it. + Class assemblerClass = a.assembler(); + if ( !assemblerClass.equals(DefaultControlAssembler.class) ) + { + ControlAssembler assembler = assemblerClass.newInstance(); + Set clients = controlTypeToClients.get( ct ); + ControlAssemblyContext cac = factory.newInstance( + cl.loadClass(ct), null, clients, moduleRoot, moduleName, srcOutputRoot ); + assembler.assemble( cac ); + } + } + } + catch ( ControlAssemblyException cae ) + { + // just rethrow ControlAssemblyExceptions, which will typically come from user-provided assemblers. + throw cae; + } + catch ( Throwable t ) + { + // Not expecting any throwables other than ControlAssemblyExceptions, so consider them as + // unexpected infrastructure issues and wrap them in a CAE. + throw new ControlAssemblyException( "Assembly infrastructure exception", t); + } + finally + { + Thread.currentThread().setContextClassLoader( origCL ); + } + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/assembly/BaseAssemblyContext.java b/controls/src/runtime/org/apache/beehive/controls/runtime/assembly/BaseAssemblyContext.java new file mode 100644 index 0000000..969471d --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/assembly/BaseAssemblyContext.java @@ -0,0 +1,204 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.assembly; + +import java.io.File; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.Map; +import java.util.Set; +import java.util.LinkedList; +import java.util.Queue; + +import com.sun.mirror.apt.Messager; +import com.sun.mirror.util.SourcePosition; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.assembly.ControlAssemblyContext; +import org.apache.beehive.controls.api.assembly.ControlAssemblyException; +import org.apache.beehive.controls.runtime.bean.ControlUtils; + +/** + * Abstract ControlAssemblyContext implementation. Provides a basic implementation of most non-module-specific + * APIs, meant to be extended by module-specific types. + */ +public abstract class BaseAssemblyContext implements ControlAssemblyContext +{ + protected BaseAssemblyContext( Class controlIntfOrExt, Map bindings, + Set clients, File moduleRoot, + String moduleName, File srcOutputRoot ) + throws ControlAssemblyException + { + _controlIntfOrExt = controlIntfOrExt; + _bindings = bindings; + _clients = clients; + _moduleRoot = moduleRoot; + _moduleName = moduleName; + _srcOutputRoot = srcOutputRoot; + _messager = new DefaultAssemblyMessager(); + + // Compute and cache "most derived ControlInterface" + Queue q = new LinkedList(); + Class ci = controlIntfOrExt; + + while ( ci != null ) + { + if ( ci.isAnnotationPresent(ControlInterface.class) ) + { + _controlMostDerivedIntf = ci; + break; + } + + Class[] supers = ci.getInterfaces(); + for ( Class s : supers ) + q.offer( s ); + + ci = q.poll(); + } + + if ( _controlMostDerivedIntf == null ) + throw new ControlAssemblyException( "Invalid control type: " + controlIntfOrExt.getName() ); + } + + public Class getControlType() + { + return _controlIntfOrExt; + } + + public Class getMostDerivedControlInterface() + { + return _controlMostDerivedIntf; + } + + // TODO - if we want to override class annotations on instance then here is where we will do it + public T + getControlAnnotation(Class annotationClass) + { + Class controlInterface = getControlType(); + return (T)controlInterface.getAnnotation(annotationClass); + } + + public T + getControlMethodAnnotation(Class annotationClass, Method m) + throws NoSuchMethodException + { + Class controlInterface = getControlType(); + Method controlMethod = controlInterface.getMethod( + m.getName(), m.getParameterTypes()); + + return (T)controlMethod.getAnnotation(annotationClass); + } + + public String getDefaultImplClassName() + { + Class ci = getMostDerivedControlInterface(); + ControlInterface a = (ControlInterface) + ci.getAnnotation(ControlInterface.class); + + return ControlUtils.resolveDefaultBinding( a.defaultBinding(), ci.getName() ); + } + + public File getSrcOutputDir() + { + return _srcOutputRoot; + } + + public File getModuleDir() + { + return _moduleRoot; + } + + public String getModuleName() + { + return _moduleName; + } + + public Set getClients() + { + return _clients; + } + + public Messager getMessager() + { + return _messager; + } + + public boolean hasErrors() + { + return _nErrors > 0; + } + + private class DefaultAssemblyMessager implements Messager + { + public void printError( SourcePosition pos, String msg ) + { + printDiagnostic( "Error", pos, msg ); + _nErrors++; + } + public void printError( String msg ) + { + printError( null, msg ); + } + + public void printNotice( SourcePosition pos, String msg ) + { + printDiagnostic( "Notice", pos, msg ); + } + public void printNotice( String msg ) + { + printNotice( null, msg ); + } + + public void printWarning( SourcePosition pos, String msg ) + { + printDiagnostic( "Warning", pos, msg ); + } + public void printWarning( String msg ) + { + printWarning( null, msg ); + } + + protected void printDiagnostic( String type, SourcePosition pos, String msg ) + { + String fn = ""; + int line = 0; + int column = 0; + + if ( pos != null ) + { + fn = pos.file().getName(); + line = pos.line(); + column = pos.column(); + } + + System.out.println( type + ": (" + fn + ":" + line + ":" + column + ") " + msg ); + } + } + + private File _moduleRoot; + private String _moduleName; + private File _srcOutputRoot; + private Class _controlIntfOrExt; + private Map _bindings; + private Set _clients; + private Messager _messager; + private int _nErrors = 0; + + private Class _controlMostDerivedIntf; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/assembly/EJBAssemblyContext.java b/controls/src/runtime/org/apache/beehive/controls/runtime/assembly/EJBAssemblyContext.java new file mode 100644 index 0000000..dadd3be --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/assembly/EJBAssemblyContext.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.assembly; + +import org.apache.beehive.controls.api.assembly.ControlAssemblyContext; +import org.apache.beehive.controls.api.assembly.ControlAssemblyException; + +import java.io.File; +import java.util.Map; +import java.util.Set; + +/** + * A ControlAssemblyContext implementation supporting standard EJB modules + */ +public class EJBAssemblyContext + extends BaseAssemblyContext + implements ControlAssemblyContext.EJBModule +{ + public static class Factory implements ControlAssemblyContext.Factory + { + public EJBAssemblyContext newInstance( Class controlIntfOrExt, + Map bindings, + Set clients, + File moduleRoot, + String moduleName, + File srcOutputRoot ) + throws ControlAssemblyException + { + return new EJBAssemblyContext( controlIntfOrExt, bindings, clients, + moduleRoot, moduleName, srcOutputRoot ); + } + } + + protected EJBAssemblyContext( Class controlIntfOrExt, Map bindings, + Set clients, File moduleRoot, + String moduleName, File srcOutputRoot ) + throws ControlAssemblyException + { + super( controlIntfOrExt, bindings, clients, moduleRoot, moduleName, srcOutputRoot ); + } + + public File getEjbJarXml() + { + return new File( getModuleDir(), "META-INF" + File.separator + "ejb-jar.xml"); + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/assembly/WebAppAssemblyContext.java b/controls/src/runtime/org/apache/beehive/controls/runtime/assembly/WebAppAssemblyContext.java new file mode 100644 index 0000000..c1e909a --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/assembly/WebAppAssemblyContext.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.assembly; + +import org.apache.beehive.controls.api.assembly.ControlAssemblyContext; +import org.apache.beehive.controls.api.assembly.ControlAssemblyException; + +import java.io.File; +import java.util.Map; +import java.util.Set; + +/** + * A ControlAssemblyContext implementation supporting standard web-app modules + */ +public class WebAppAssemblyContext + extends BaseAssemblyContext + implements ControlAssemblyContext.WebAppModule +{ + public static class Factory + implements ControlAssemblyContext.Factory + { + public WebAppAssemblyContext newInstance( Class controlIntfOrExt, + Map bindings, + Set clients, + File moduleRoot, + String moduleName, + File srcOutputRoot ) + throws ControlAssemblyException + { + return new WebAppAssemblyContext( controlIntfOrExt, bindings, clients, + moduleRoot, moduleName, srcOutputRoot ); + } + } + + protected WebAppAssemblyContext(Class controlIntfOrExt, + Map bindings, + Set clients, + File moduleRoot, + String moduleName, + File srcOutputRoot ) + throws ControlAssemblyException + { + super( controlIntfOrExt, bindings, clients, moduleRoot, moduleName, srcOutputRoot ); + } + + public File getWebXml() + { + return new File( getModuleDir(), "WEB-INF" + File.separator + "web.xml"); + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/bean/AdaptorPersistenceDelegate.java b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/AdaptorPersistenceDelegate.java new file mode 100644 index 0000000..aa72e8c --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/AdaptorPersistenceDelegate.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.bean; + +import java.beans.DefaultPersistenceDelegate; +import java.beans.Encoder; +import java.beans.Expression; + +/** + * The AdaptorPersistenceDelegate class supports the XML persistance of Control Client Event + * Adaptor instances by implementing the java.beans.PersistenceDelegate API, and + * overriding the default persistance algorithm based upon the runtime structure for Controls. + */ +public class AdaptorPersistenceDelegate extends DefaultPersistenceDelegate +{ + /** + * PersistenceDelegate.instantiate() + */ + protected Expression instantiate(Object oldInstance, Encoder out) + { + if (! (oldInstance instanceof EventAdaptor)) + return super.instantiate(oldInstance, out); + + // + // An implementation instance is actually constructed at decode time by calling + // ControlBean.ensureControl on the parent bean. This will create a new impl + // instance and run the impl initializer on it. + // + return new Expression(oldInstance, oldInstance.getClass(), "new", + new Object[] { ((EventAdaptor)oldInstance).getClient() }); + } + + /** + * PersistenceDelegate.initialize() + */ + protected void initialize(Class type, Object oldInstance, Object newInstance, Encoder out) + { + super.initialize(type, oldInstance, newInstance, out); + } + + /** + * PersistenceDelegate.writeObject() + */ + public void writeObject(Object oldInstance, Encoder out) + { + super.writeObject(oldInstance, out); + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/bean/AnnotatedElementMapPersistenceDelegate.java b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/AnnotatedElementMapPersistenceDelegate.java new file mode 100644 index 0000000..27b61b5 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/AnnotatedElementMapPersistenceDelegate.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.bean; + +import java.beans.PersistenceDelegate; +import java.beans.Encoder; +import java.beans.Expression; + +import org.apache.beehive.controls.api.properties.AnnotatedElementMap; + +/** + * The AnnotatedElementMapPersistenceDelegate is an XMLEncoder PersistenceDelegate for + * the org.apache.beehive.controls.api.properties.AnnotatedElementMap + * class. + */ +public class AnnotatedElementMapPersistenceDelegate extends PersistenceDelegate +{ + protected Expression instantiate(Object oldInstance, Encoder out) + { + // + // Modify the default constructor to pass in the AnnotatedElement wrapped by the map + // + AnnotatedElementMap aem = (AnnotatedElementMap)oldInstance; + return new Expression(aem, aem.getClass(), "new", + new Object [] { aem.getAnnotatedElement() }); + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/bean/AnnotationConstraintValidator.java b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/AnnotationConstraintValidator.java new file mode 100644 index 0000000..0cff69f --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/AnnotationConstraintValidator.java @@ -0,0 +1,574 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.bean; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.text.ParsePosition; +import java.util.Date; + +import org.apache.beehive.controls.api.bean.AnnotationMemberTypes; +import org.apache.beehive.controls.api.bean.AnnotationConstraints.MembershipRule; +import org.apache.beehive.controls.api.bean.AnnotationConstraints.MembershipRuleValues; +import org.apache.beehive.controls.api.properties.PropertyKey; + +/** + * This class offers methods for validating values assigned to a control property. + * The validation process will ensure + * 1. The value is appropriate for the property's property type + * 2. The value satisfies the constraints defined on the property type + * 3. The value satisfies the constraints defined on the property set that the property is defined in. + * Refer to {@link org.apache.beehive.controls.api.bean.AnnotationMemberTypes AnnotationMemberTypes} and + * {@link org.apache.beehive.controls.api.bean.AnnotationConstraints AnnotationConstraints} for more + * information on property constraints. + */ +public class AnnotationConstraintValidator +{ + + public AnnotationConstraintValidator() + { + super(); + } + + /** + * This method ensures that any control property value assignment satisfies + * all property constraints. This method should be called by control + * property setters to ensure values assigned to properties at runtime are + * validated. + * + * @param key + * The property that the specified key is assigned to + * @param value + * The value assigned to the specified property key + * @throws IllegalArgumentException + * when the value assigned to the specified property key does + * not satisfy a property constraint. + */ + public static void validate(PropertyKey key, Object value) + throws IllegalArgumentException + { + validate(key.getAnnotations(), value); + } + + /** + * This method ensures the membership constraints defined on a property set + * is satisfied. + * + * @param propertySet the property set to validate + */ + public static void validateMembership(Annotation propertySet) + { + Class c = propertySet.annotationType(); + MembershipRule rule = (MembershipRule) c.getAnnotation(MembershipRule.class); + if (rule == null) + return; + MembershipRuleValues ruleValue = rule.value(); + String[] memberNames = rule.memberNames(); + Method[] members = getMembers(c, memberNames); + int i = getNumOfMembersSet(propertySet, members); + if (ruleValue == MembershipRuleValues.ALL_IF_ANY) + { + if (i != 0 && i != members.length) + throw new IllegalArgumentException("The membership rule on " + propertySet.toString() + + " is not satisfied. Either all members must be set or none is set"); + } + else if (ruleValue == MembershipRuleValues.EXACTLY_ONE) + { + if (i != 1) + throw new IllegalArgumentException("The membership rule on " + propertySet.toString() + + " is not satisfied. Exactly one member must be set"); + } + else if (ruleValue == MembershipRuleValues.AT_LEAST_ONE) + { + if (i < 1) + throw new IllegalArgumentException("The membership rule on " + propertySet.toString() + + " is not satisfied. At least one member must be set"); + } + else if (ruleValue == MembershipRuleValues.AT_MOST_ONE) + { + if (i > 1) + throw new IllegalArgumentException("The membership rule on " + propertySet.toString() + + " is not satisfied. At most one member may be set"); + } + } + + private static Method[] getMembers(Class c, String[] memberNames) + { + Method[] methods = null; + if (memberNames == null || memberNames.length == 0) + { + methods = c.getDeclaredMethods(); + } + else + { + methods = new Method[memberNames.length]; + for (int i = 0; i < memberNames.length; i++) + { + try + { + methods[i] = c.getMethod(memberNames[i], (Class[]) null); + } + catch (Exception e) + { + // method is not found, so the member is ignored. + } + } + } + return methods; + } + + private static int getNumOfMembersSet(Annotation propertySet, + Method[] members) + { + int num = 0; + for (Method m : members) + { + Class returnType = m.getReturnType(); + Object o = null; + try + { + o = m.invoke(propertySet, (Object[]) null); + } + catch (Exception e) + { + // This should never happen. + throw new RuntimeException(e); + } + + if ((returnType == String.class && !((String) o) + .equals(AnnotationMemberTypes.OPTIONAL_STRING)) + || (returnType == int.class && ((Integer) o).intValue() != AnnotationMemberTypes.OPTIONAL_INT) + || (returnType == short.class && ((Short) o) + .shortValue() != AnnotationMemberTypes.OPTIONAL_SHORT) + || (returnType == long.class && ((Long) o).longValue() != AnnotationMemberTypes.OPTIONAL_LONG) + || (returnType == float.class && ((Float) o) + .floatValue() != AnnotationMemberTypes.OPTIONAL_FLOAT) + || (returnType == double.class && ((Double) o) + .doubleValue() != AnnotationMemberTypes.OPTIONAL_DOUBLE) + || (returnType == char.class && ((Character) o) + .charValue() != AnnotationMemberTypes.OPTIONAL_CHAR) + || (returnType == byte.class && ((Byte) o).byteValue() != AnnotationMemberTypes.OPTIONAL_BYTE) + || (returnType == boolean.class && !((Boolean) o) + .booleanValue())) + num++; + } + return num; + } + + protected static synchronized void validate(Annotation[] annotations, + Object value) throws IllegalArgumentException + { + + // Determine if the member is optional. This is done in a separate loop + // because a control property may have multiple constraints and the + // optional + // annotation may be declared after another constraint annotation. + boolean optional = false; + for (Annotation a : annotations) + { + if (a instanceof AnnotationMemberTypes.Optional) + { + optional = true; + break; + } + } + + for (Annotation a : annotations) + { + if (a instanceof AnnotationMemberTypes.Text) + validateText((AnnotationMemberTypes.Text) a, value, optional); + else if (a instanceof AnnotationMemberTypes.Decimal) + validateDecimal((AnnotationMemberTypes.Decimal) a, value, + optional); + else if (a instanceof AnnotationMemberTypes.Int) + validateInt((AnnotationMemberTypes.Int) a, value, optional); + else if (a instanceof AnnotationMemberTypes.Date) + validateDate((AnnotationMemberTypes.Date) a, value, optional); + else if (a instanceof AnnotationMemberTypes.FilePath) + validateFilePath((AnnotationMemberTypes.FilePath) a, value, + optional); + else if (a instanceof AnnotationMemberTypes.JndiName) + validateJndiName((AnnotationMemberTypes.JndiName) a, value, + optional); + else if (a instanceof AnnotationMemberTypes.QName) + validateQName((AnnotationMemberTypes.QName) a, value, optional); + else if (a instanceof AnnotationMemberTypes.URI) + validateURI((AnnotationMemberTypes.URI) a, value, optional); + else if (a instanceof AnnotationMemberTypes.URL) + validateURL((AnnotationMemberTypes.URL) a, value, optional); + else if (a instanceof AnnotationMemberTypes.URN) + validateURN((AnnotationMemberTypes.URN) a, value, optional); + else if (a instanceof AnnotationMemberTypes.XML) + validateXML((AnnotationMemberTypes.XML) a, value, optional); + } + } + + private static void validateXML(AnnotationMemberTypes.XML a, Object value, + boolean optional) + { + } + + private static void validateURN(AnnotationMemberTypes.URN a, Object value, + boolean optional) + { + if (optional + && (value == null || value + .equals(AnnotationMemberTypes.OPTIONAL_STRING))) + return; + + if (!(value instanceof String)) + { + error("The value, " + + value + + ", assigned to an URN property must be of type java.lang.String."); + } + + URI.create((String) value); + } + + private static void validateURL(AnnotationMemberTypes.URL a, Object value, + boolean optional) + { + if (optional + && (value == null || value + .equals(AnnotationMemberTypes.OPTIONAL_STRING))) + return; + + if (!(value instanceof String)) + { + error("The value, " + + value + + ", assigned to an URL property must be of type java.lang.String."); + } + + try + { + new URL((String) value); + } + catch (MalformedURLException mue) + { + error("The value, " + value + + ", assigned to the URL property is a malformed URL.", mue); + } + } + + private static void validateURI(AnnotationMemberTypes.URI a, Object value, boolean optional) + { + if (optional + && (value == null || value + .equals(AnnotationMemberTypes.OPTIONAL_STRING))) + return; + + if (!(value instanceof String)) + { + error("The value, " + + value + + ", assigned to an URI property must be of type java.lang.String."); + } + + URI.create((String) value); + } + + private static void validateQName(AnnotationMemberTypes.QName a, Object value, boolean optional) + { + } + + private static void validateJndiName(AnnotationMemberTypes.JndiName a, Object value, boolean optional) + { + } + + private static void validateFilePath(AnnotationMemberTypes.FilePath a, Object value, boolean optional) + { + if (optional + && (value == null || value + .equals(AnnotationMemberTypes.OPTIONAL_STRING))) + return; + + if (!(value instanceof String)) + { + error("The value, " + + value + + ", assigned to a FilePath property must be of type java.lang.String."); + } + +//Temporarily commenting out the following check on FilePath until +//an agreement is reached on what is a valid FilePath. +// +// File file = new File((String) value); +// if (!file.isFile() || !file.canRead()) +// { +// error("The value, " +// + value +// + ", assigned to a FilePath property must be a readable file."); +// } + + } + + private static void validateDate(AnnotationMemberTypes.Date a, Object value, boolean optional) { + + if (optional && (value == null || value.equals(AnnotationMemberTypes.OPTIONAL_STRING))) + return; + + if (!(value instanceof String)) + error("The value, " + + value + + ", assigned to a date property must be of type java.lang.String."); + + String format = a.format(); + Date date = null; + try { + date = parseDate(format , (String)value); + } catch (ParseException pe) { + error("The value, " + + value + + ", assigned to a date property is not in the specified format of: " + + format); + } + + String minValue = a.minValue(); + if (minValue != null && minValue.length() > 0) { + + Date minDate = null; + try { + minDate = parseDate(format, a.minValue()); + } catch (ParseException pe) { + error("The value, " + + minValue + + ", assigned to minValue date constraint property is not in the specified format of: " + + format); + } + + if (minDate.compareTo(date) > 0) { + error("The value, " + + value + + ", assigned to a date property is earlier than the earliest date allowed: " + + minValue); + } + } + + String maxValue = a.maxValue(); + if (maxValue != null && maxValue.length() > 0) { + + Date maxDate = null; + try { + maxDate = parseDate(format, a.maxValue()); + } catch (ParseException pe) { + error("The value, " + + maxValue + + ", assigned to maxValue date constraint property is not in the specified format of: " + + format); + } + + if (maxDate.compareTo(date) < 0) { + error("The date, " + + value + + ", assigned to a date property is later than the latest date allowed: " + + maxValue); + } + } + } + + /** + * Parse a date value into the specified format. Pay special attention to the case of the value + * having trailing characters, ex. 12/02/2005xx which will not cause the parse of the date to fail + * but should be still treated as an error for our purposes. + * + * @param format Format string for the date. + * @param value A String containing the date value to parse. + * @return A Date instance if the parse was successful. + * @throws ParseException If the value is not a valid date. + */ + public static Date parseDate(String format, String value) + throws ParseException { + + SimpleDateFormat sdFormat = new SimpleDateFormat(format); + sdFormat.setLenient(false); + ParsePosition pp = new ParsePosition(0); + Date d = sdFormat.parse(value, pp); + + /* + a date value such as: 12/01/2005x will not cause a parse error, + use the parse position to detect this case. + */ + if (d == null || pp.getIndex() < value.length()) + throw new ParseException("Parsing date value, " + + value + + ", failed at index " + pp.getIndex(), pp.getIndex()); + else return d; + } + + /** + * @param value + */ + private static void validateInt(AnnotationMemberTypes.Int a, Object value, boolean optional) { + if (optional + && (value == null || + value.equals(AnnotationMemberTypes.OPTIONAL_STRING) || + value.equals(AnnotationMemberTypes.OPTIONAL_INT))) + return; + + int intValue = 0; + + if (value instanceof String) + { + try + { + intValue = Integer.parseInt((String) value); + } + catch (NumberFormatException nfe) + { + error("The value ," + + value + + ", assigned to an int property does not represent an integer."); + } + } + else if (value instanceof Integer) + { + intValue = ((Integer) value).intValue(); + } + else + { + error("The value, " + + value + + ", assigned to an int property must be of type java.lang.String or int."); + } + + if (intValue < a.minValue()) + error("The value, " + + intValue + + ", assigned to an int property is less than the minimum value allowed: " + + a.minValue() + "."); + else if (intValue > a.maxValue()) + error("The value, " + + intValue + + ", assigned to an int property exeeds the maximum value allowed: " + + a.maxValue() + "."); + } + + private static void validateDecimal(AnnotationMemberTypes.Decimal a, + Object value, boolean optional) + { + if (optional + && (value == null || + value.equals(AnnotationMemberTypes.OPTIONAL_STRING) || + value.equals(AnnotationMemberTypes.OPTIONAL_FLOAT) || + value.equals(AnnotationMemberTypes.OPTIONAL_DOUBLE))) + return; + + double doubleValue = 0; + String doubleString = null; + + if (value instanceof String) + { + doubleValue = Double.parseDouble((String)value); + doubleString = (String)value; + } + else if (value instanceof Float) + { + doubleValue = ((Float)value).doubleValue(); + doubleString = ((Float)value).toString(); + } + else if (value instanceof Double) + { + doubleValue = ((Double)value).doubleValue(); + doubleString = ((Double)value).toString(); + } + else + { + error("The value, " + + value + + ", assigned to a decimal property must be of type float, double, or java.lang.String."); + } + + if (doubleValue < a.minValue()) + error("The value, " + + doubleValue + + ", assigned to a decimal property is less than the the minimum value allowed: " + + a.minValue() + "."); + + if (doubleValue > a.maxValue()) + error("The value, " + + doubleValue + + ", assigned to a decimal property exceeds the maximum value allowed: " + + a.maxValue() + "."); + + int decimalPos = doubleString.indexOf('.'); + + if (decimalPos == -1 || a.places() == AnnotationMemberTypes.UNLIMITED_PLACES) + return; + + if (doubleString.length() - decimalPos - 1 > a.places()) + error("The decimal places in the value, " + doubleString + + ", assigned to a decimal property exceeds " + a.places() + + ", the number of decimal places allowed."); + + } + + private static void validateText(AnnotationMemberTypes.Text a, + Object value, boolean optional) + { + if (optional + && (value == null || value + .equals(AnnotationMemberTypes.OPTIONAL_STRING))) + return; + + if (!(value instanceof String)) + error("The value, " + + value + + ", assigned to a text property must be of type java.lang.String."); + + String str = (String) value; + if (str.length() > a.maxLength()) + error("The value, " + + str + + ", assigned to a text property exceeds the maximum length allowed: " + + a.maxLength()); + + if (a.isLong()) + { + try + { + Long.parseLong(str); + } + catch (NumberFormatException nfe) + { + error("The value, " + + str + + ", assigned to a text property with a long number constraint does not represent a long number."); + } + } + + } + + private static void error(String message) + { + error(message, null); + } + + private static void error(String message, Throwable t) + { + throw new IllegalArgumentException(message, t); + } + +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/bean/BeanListener.java b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/BeanListener.java new file mode 100644 index 0000000..9d41ebf --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/BeanListener.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.bean; + +/** + * The BeanListener class acts as the abstract base class for generated event listeners + * associated with a ControlBean. + */ +abstract public class BeanListener + implements java.io.Serializable +{ + protected BeanListener() + { + this(null); + } + + protected BeanListener(Object source) + { + _source = source; + } + + abstract public BeanListener cloneListener(Object source); + + public Object getSource() { + return _source; + } + + Object _source; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/bean/BeanPersistenceDelegate.java b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/BeanPersistenceDelegate.java new file mode 100644 index 0000000..c1c8798 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/BeanPersistenceDelegate.java @@ -0,0 +1,312 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.bean; + +import java.beans.BeanInfo; +import java.beans.DefaultPersistenceDelegate; +import java.beans.Encoder; +import java.beans.EventSetDescriptor; +import java.beans.Expression; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PersistenceDelegate; +import java.beans.PropertyDescriptor; +import java.beans.Statement; +import java.beans.XMLEncoder; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Iterator; + +import org.apache.beehive.controls.api.ControlException; +import org.apache.beehive.controls.api.properties.AnnotatedElementMap; +import org.apache.beehive.controls.api.properties.BeanPropertyMap; +import org.apache.beehive.controls.api.properties.PropertyKey; +import org.apache.beehive.controls.api.properties.PropertyMap; + +/** + * The BeanPersistenceDelegate class supports the XML persistence of Control JavaBeans by + * implementing the java.beans.PersistenceDelegate API, and overriding the default + * persistence algorithm based upon the runtime structure for Controls. It selectively registers + * other PersistenceDelegate instances for other nested entities, as required, to ensure that + * runtime-defined state and object relationships are properly maintained. + *

+ * For the BeanInfo of all generated ControlJavaBeans, a BeanPersistenceDelegate instance will + * be registered as the "persistenceDelegate" attribute in the BeanDescriptor. The standard + * java.beans.Encoder persistence delegate lookup mechanism recognizes this attribute + * and will use the instance to persist an ControlBeans written to the encoding stream. + *

+ * The BeanPersistence class implements optimized property persistence based upon the + * fact that the ControlBean already has a map containing all non-default property state. Rather + * than using the standard (and slower) algorithm of comparing the encoding instance against a + * 'clean' instance, the delegate can simply retrieve the map and persist the values contained + * within it. + * + * @see java.beans.XMLEncoder + * @see java.beans.PersistenceDelegate + */ +public class BeanPersistenceDelegate extends DefaultPersistenceDelegate +{ + /** + * The FieldPersistencersistence is an XMLEncoder PersistenceDelegate for the + * java.lang.reflect.Field claass. It is similar to the one that comes + * bundled with the JDK with one key exception: it works for non-public fields as + * well. + */ + class FieldPersistenceDelegate extends PersistenceDelegate + { + protected Expression instantiate(Object oldInstance, Encoder out) + { + Field f = (Field)oldInstance; + return new Expression(oldInstance, f.getDeclaringClass(), "getDeclaredField", + new Object[]{f.getName()}); + } + } + + /** + * PersistenceDelegate.instantiate() + */ + protected Expression instantiate(Object oldInstance, Encoder out) + { + XMLEncoder xmlOut = (XMLEncoder)out; + ControlBean control = (ControlBean)oldInstance; + + // + // If processing a nested control, then use the parent bean's context as the + // constructor context + // + ControlBeanContext cbc = null; + if (xmlOut.getOwner() != null) + cbc = ((ControlBean)xmlOut.getOwner()).getControlBeanContext(); + + // + // See if the ControlBean has any associated PropertyMap in its delegation chain + // that was derived from an AnnotatedElement so this relationship (and any associated + // external config delegates) will be restored as part of the decoding process. + // + // BUGBUG: What about a user-created PropertyMap that was passed into the constructor? + // + AnnotatedElementMap aem = null; + PropertyMap pMap = control.getPropertyMap(); + while (pMap != null) + { + if (pMap instanceof AnnotatedElementMap) + { + aem = (AnnotatedElementMap)pMap; + + // + // Ignore a class-valued AnnotationElementMap.. this just refers to the + // Control type, and will be automatically reassociated at construction + // time + // + if (aem.getAnnotatedElement() instanceof Class) + aem = null; + + xmlOut.setPersistenceDelegate(AnnotatedElementMap.class, + new AnnotatedElementMapPersistenceDelegate()); + + break; + } + + pMap = pMap.getDelegateMap(); + } + + + // + // Create a constructor that that uses the following form: + // new (ControlBeanContext cbc, String id, PropertyMap map) + // The context is set to null, so the current active container context will be + // used, the id will be the ID of the original control and the map will be + // any AnnotatedElementMap that was passed into the original constructor. + // + return new Expression(control, control.getClass(), "new", + new Object [] {cbc, control.getLocalID(), aem}); + } + + /** + * PersistenceDelegate.initialize() + */ + protected void initialize(Class type, Object oldInstance, Object newInstance, Encoder out) + { + // + // Get the bean and associated beanInfo for the source instance + // + ControlBean control = (ControlBean)oldInstance; + BeanInfo beanInfo; + try + { + beanInfo = Introspector.getBeanInfo(control.getClass()); + } + catch (IntrospectionException ie) + { + throw new ControlException("Unable to locate BeanInfo", ie); + } + + // + // Cast the encoding stream to an XMLEncoder (only encoding supported) and then set + // the stream owner to the bean being persisted + // + XMLEncoder xmlOut = (XMLEncoder)out; + Object owner = xmlOut.getOwner(); + xmlOut.setOwner(control); + try + { + + // + // The default implementation of property persistence will use BeanInfo to + // incrementally compare oldInstance property values to newInstance property values. + // Because the bean instance PropertyMap holds only the values that have been + // modified, this process can be optimized by directly writing out only the properties + // found in the map. + // + BeanPropertyMap beanMap = control.getPropertyMap(); + PropertyDescriptor [] propDescriptors = beanInfo.getPropertyDescriptors(); + for (PropertyKey pk : beanMap.getPropertyKeys()) + { + // + // Locate the PropertyDescriptor for the modified property, and use it to write + // the property value to the encoder stream + // + String propName = pk.getPropertyName(); + boolean found = false; + for (int i = 0; i < propDescriptors.length; i++) + { + if (propName.equals(propDescriptors[i].getName())) + { + found = true; + + // Only write the property if it is not flagged as transient + Object transientVal = propDescriptors[i].getValue("transient"); + if (transientVal == null || transientVal.equals(Boolean.FALSE)) + { + xmlOut.writeStatement( + new Statement(oldInstance, + propDescriptors[i].getWriteMethod().getName(), + new Object [] {beanMap.getProperty(pk)})); + } + } + } + if (found == false) + { + throw new ControlException("Unknown property in bean PropertyMap: " + pk); + } + } + + // + // Get the bean context associated with the bean, and persist any nested controls + // + ControlBeanContext cbc = control.getControlBeanContext(); + if (cbc.size() != 0) + { + xmlOut.setPersistenceDelegate(ControlBeanContext.class, + new ContextPersistenceDelegate()); + + Iterator nestedIter = cbc.iterator(); + while (nestedIter.hasNext()) + { + Object bean = nestedIter.next(); + if (bean instanceof ControlBean) + { + xmlOut.writeStatement( + new Statement(cbc, "add", new Object [] { bean } )); + } + } + } + + // + // Restore any listeners associated with the control + // + EventSetDescriptor [] eventSetDescriptors = beanInfo.getEventSetDescriptors(); + for (int i = 0; i < eventSetDescriptors.length; i++) + { + EventSetDescriptor esd = eventSetDescriptors[i]; + Method listenersMethod = esd.getGetListenerMethod(); + String addListenerName = esd.getAddListenerMethod().getName(); + if (listenersMethod != null) + { + // + // Get the list of listeners, and then add statements to incrementally + // add them in the same order + // + try + { + Object [] lstnrs = (Object [])listenersMethod.invoke(control, + new Object []{}); + for (int j = 0; j < lstnrs.length; j++) + { + // + // If this is a generated EventAdaptor class, then set the delegate + // explicitly + // + if (lstnrs[j] instanceof EventAdaptor) + xmlOut.setPersistenceDelegate(lstnrs[j].getClass(), + new AdaptorPersistenceDelegate()); + xmlOut.writeStatement( + new Statement(control, addListenerName, new Object [] {lstnrs[j]})); + } + } + catch (Exception iae) + { + throw new ControlException("Unable to initialize listeners", iae); + } + } + } + + // + // See if the control holds an implementation instance, if so, we need to include + // it (and any nested controls or state) in the encoding stream + // + Object impl = control.getImplementation(); + if (impl != null) + { + + // + // Set the persistence delegate for the impl class to the Impl delegate, + // set the current stream owner to the bean, and then write the implementation + // + Class implClass = impl.getClass(); + if (xmlOut.getPersistenceDelegate(implClass) instanceof DefaultPersistenceDelegate) + xmlOut.setPersistenceDelegate(implClass, new ImplPersistenceDelegate()); + + // + // HACK: This bit of hackery pushes the impl into the persistence stream + // w/out actually requiring it be used as an argument elsewhere, since there + // is no public API on the bean that takes an impl instance as an argument. + // + xmlOut.writeStatement( + new Statement(impl, "toString", null)); + } + } + finally + { + // Restore the previous encoding stream owner + xmlOut.setOwner(owner); + } + } + + /** + * PersistenceDelegate.writeObject() + */ + public void writeObject(Object oldInstance, Encoder out) + { + // Override the default FieldPersistence algorithm for the encoder, so private fields + // can also be encoded + out.setPersistenceDelegate(Field.class, new FieldPersistenceDelegate()); + super.writeObject(oldInstance, out); + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ClientInitializer.java b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ClientInitializer.java new file mode 100644 index 0000000..cc9b365 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ClientInitializer.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.bean; + +import java.lang.reflect.AnnotatedElement; +import org.apache.beehive.controls.api.context.ControlBeanContext; +import org.apache.beehive.controls.api.properties.PropertyMap; +import org.apache.beehive.controls.api.properties.AnnotatedElementMap; +import org.apache.beehive.controls.api.versioning.VersionRequired; +import org.apache.beehive.controls.api.versioning.Version; + +/** + * The ClientInitializer class is an abstract base class that all generated Control + * client initializer classes will extend. It provides common utilities and supporting code + * for initialization, and has a shared package relationship with the base ControlBean + * class providing access to internals not available in a more general context. + */ +abstract public class ClientInitializer +{ + /** + * Enforces the VersionRequired annotation at runtime (called when an instance of a control is annotated + * with VersionRequired). Throws a ControlException if enforcement fails. + * + * @param versionRequired the value of the VersionRequired annotation on a control field + */ + protected static void enforceVersionRequired( ControlBean control, VersionRequired versionRequired ) + { + Class controlIntf = ControlUtils.getMostDerivedInterface( control.getControlInterface() ); + + Version versionPresent = (Version) controlIntf.getAnnotation( Version.class ); + if ( versionPresent != null ) + { + ControlBean.enforceVersionRequired( controlIntf.getCanonicalName(), versionPresent, versionRequired ); + } + } + + /** + * Returns the annotation map for the specified element. + */ + public static PropertyMap getAnnotationMap(ControlBeanContext cbc, AnnotatedElement annotElem) + { + if ( cbc == null ) + return new AnnotatedElementMap(annotElem); + + return cbc.getAnnotationMap(annotElem); + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ContextPersistenceDelegate.java b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ContextPersistenceDelegate.java new file mode 100644 index 0000000..8c83d2d --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ContextPersistenceDelegate.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.bean; + +import java.beans.DefaultPersistenceDelegate; +import java.beans.Encoder; +import java.beans.Expression; +import java.beans.XMLEncoder; + +/** + * The ContextPersistenceDelegate class supports the XML persistance of ControlBeanContext + * instances by implementing the java.beans.PersistenceDelegate API, and overriding + * the default persistance algorithm based upon the runtime structure for Controls. + *

+ */ +public class ContextPersistenceDelegate extends DefaultPersistenceDelegate +{ + /** + * PersistenceDelegate.instantiate() + */ + protected Expression instantiate(Object oldInstance, Encoder out) + { + // + // Instead of directly creating a context instance, simply ask the containing + // bean to return the associated context. + // + return new Expression(((XMLEncoder)out).getOwner(), "getControlBeanContext", null); + } + + /** + * PersistenceDelegate.initialize() + */ + protected void initialize(Class type, Object oldInstance, Object newInstance, Encoder out) + { + //super.initialize(type, oldInstance, newInstance, out); + } + + /** + * PersistenceDelegate.writeObject() + */ + public void writeObject(Object oldInstance, Encoder out) + { + super.writeObject(oldInstance, out); + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlBean.java b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlBean.java new file mode 100644 index 0000000..d56e0fd --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlBean.java @@ -0,0 +1,1119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.bean; + +import java.beans.beancontext.BeanContext; +import java.beans.beancontext.BeanContextServices; +import java.beans.PropertyChangeSupport; +import java.beans.VetoableChangeSupport; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.concurrent.Semaphore; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.TooManyListenersException; +import java.util.Vector; + +import org.apache.beehive.controls.api.ControlException; +import org.apache.beehive.controls.api.properties.BaseProperties; +import org.apache.beehive.controls.api.properties.AnnotatedElementMap; +import org.apache.beehive.controls.api.properties.PropertyMap; +import org.apache.beehive.controls.api.properties.BeanPropertyMap; +import org.apache.beehive.controls.api.properties.PropertyKey; +import org.apache.beehive.controls.api.properties.PropertySetProxy; +import org.apache.beehive.controls.api.versioning.VersionRequired; +import org.apache.beehive.controls.api.versioning.Version; +import org.apache.beehive.controls.api.bean.Threading; +import org.apache.beehive.controls.api.bean.ThreadingPolicy; +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.context.ControlThreadContext; +import org.apache.beehive.controls.api.events.EventRef; +import org.apache.beehive.controls.api.events.EventSet; +import org.apache.beehive.controls.spi.context.ControlBeanContextFactory; +import org.apache.beehive.controls.spi.svc.Interceptor; +import org.apache.beehive.controls.spi.svc.InterceptorPivotException; +import org.apache.commons.discovery.tools.DiscoverClass; + +/** + * The ControlBean class is an abstract base class for the JavaBean classes generated to support + * Beehive Controls. + *

+ * The ControlBean class indirectly implements BeanContextProxy; the + * {@link org.apache.beehive.controls.api.context.ControlBeanContext} that it contains/scopes acts as that proxy. + *

+ * All support APIs (which may be called from derived subclasses or contextual services) + * are generally marked as protected and have names that start with an underscore. This avoids the + * possibility that the name might conflict with a user-defined method on a control's public or + * extended Control interfaces. + *

+ * NOTE: Adding public methods should be done with great care; any such method becomes part of the + * public API, and occupies the method namespace for all controls. + */ +abstract public class ControlBean + implements org.apache.beehive.controls.api.bean.ControlBean +{ + /** + * + * @param context the containing ControlBeanContext. May be null, in which case the bean will attempt to + * associate with an active context at runtime (via thread-locals). + * @param id the local ID for the control, scoped to the control bean context. + * @param initProperties a PropertyMap containing initial properties for the control + * @param controlIntf the control interface or extension directly implemented by the control bean + */ + protected ControlBean(org.apache.beehive.controls.api.context.ControlBeanContext context, + String id, + PropertyMap initProperties, + Class controlIntf) + { + super(); + + _localID = id; + _controlIntf = controlIntf; + + // + // If no containing context was specified during construction, see if there is a current + // active container context and implicitly associated the control with it. + // + if (context == null) + context = ControlThreadContext.getContext(); + + ControlBeanContextFactory cbcFactory = lookupControlBeanContextFactory(context); + _cbc = cbcFactory.instantiate(this); + + // + // Associate this bean with the context. Beans may run without a context! + // Note that the add() call has the side-effect of calling ControlBean.setBeanContext(), which does + // additional setup work, so we make sure we always call that anyways! + // + if (context != null) + context.add(this); + else + setBeanContext(null); + + // + // Get the default map for the control class. This contains the default property + // values for all beans of the class. + // + PropertyMap classMap = getAnnotationMap(controlIntf); + if (initProperties != null) + { + // + // If the initialization map derives its values from a Java annotated element, + // then allow container overrides on this element to be applied. This will also + // coelesce maps referencing the same element. + // + AnnotatedElement annotElem = null; + if (initProperties instanceof AnnotatedElementMap) + { + annotElem = ((AnnotatedElementMap)initProperties).getAnnotatedElement(); + initProperties = getAnnotationMap(annotElem); + } + + // + // If an initial property map was provided, set it to delegate to the default + // map, and then create a wrapper map around it for storing per instance + // properties. + // + if (annotElem != controlIntf) + initProperties.setDelegateMap(classMap); + _properties = new BeanPropertyMap(initProperties); + } + else + { + // + // If no initial map was provided, simply create an empty map wrapping the + // control class default. + // + _properties = new BeanPropertyMap(classMap); + } + + } + + /** + * Configure this bean to be thread-safe given the threading settings of the impl class and + * the outer container. + */ + private void ensureThreadingBehaviour() + { + // + // If the implementation class requires a guarantee of single-threaded behavior and the + // outer container does not guarantee it, then enable invocation locking on this + // bean instance. + // + if (hasSingleThreadedImpl() && ! _cbc.hasSingleThreadedParent()) + _invokeLock = new Semaphore(1, true); + else + _invokeLock = null; + } + /** + * Return the BeanContextService proxy associated with this bean instance + */ + final public ControlBeanContext getBeanContextProxy() + { + return _cbc; + } + + /** + * Returns the nesting BeanContext for this ControlBean. This is thread-safe even though it + * is not synchronized. + */ + final public BeanContext getBeanContext() + { + // + // Indirect through the bean proxy for this control bean and up to its parent nesting + // context. Both these calls (getBeanContextProxy() and getBeanContext()) are, and must + // remain, thread-safe. + // + return getBeanContextProxy().getBeanContext(); + } + + /** + * Called by the BeanContextProxy (_cbc) whenever the _parent_ context containing this control bean is + * changed. This is the place to do any initialization (or reinitialization) that is dependent + * upon attributes of the container for the ControlBean. + * + * Note: this is called in the ControlBean ctor, when a parent context calls add() on the nascent + * bean. + * + * @param bc the new parent context containing this control bean (not _cbc) + */ + final public synchronized void setBeanContext(BeanContext bc) + { + ensureThreadingBehaviour(); + } + + /** + * Returns the control ID for this control + */ + final public String getControlID() + { + return _cbc.getControlID(); + } + + /** + * Returns the public interface for this control. + */ + final public Class getControlInterface() + { + return _controlIntf; + } + + /** + * Returns true if the implementation class for this ControlBean requires the framework + * to ensure thread-safety for it. + */ + /*package*/ boolean hasSingleThreadedImpl() + { + return _threadingPolicy == ThreadingPolicy.SINGLE_THREADED; + } + + /** + * Obtains an instance of the appropriate ImplInitializer class + */ + protected synchronized ImplInitializer getImplInitializer() + { + if (_implInitializer == null) + { + try + { + Class initClass = _implClass.getClassLoader().loadClass( + _implClass.getName() + "Initializer"); + _implInitializer = (ImplInitializer)initClass.newInstance(); + } + catch (Exception e) + { + throw new ControlException("Control initialization failure", e); + } + } + return _implInitializer; + } + + /** + * Returns the target control instance associated with this ControlBean, performing lazy + * instantiation and initialization of the instance. + * + * REVIEW: could probably improve the granularity of locking here, but start w/ just + * synchronizing the entire fn. + */ + public synchronized Object ensureControl() + { + if (_control == null) + { + // + // See if the property map specifies an implementation class for the control; + // if not, use default binding. + // + + String implBinding = null; + BaseProperties bp = _properties.getPropertySet( BaseProperties.class ); + if ( bp != null ) + implBinding = bp.controlImplementation(); + else + implBinding = ControlUtils.getDefaultControlBinding(_controlIntf); + + try + { + _implClass = _controlIntf.getClassLoader().loadClass(implBinding); + + // + // Validate that the specified implementation class has an @ControlImplementation + // annotation, else downstream requirements (such as having a valid control init + // class) will not be met. + // + if (_implClass.getAnnotation(ControlImplementation.class) == null) + { + throw new ControlException("@" + ControlImplementation.class.getName() + " annotation is missing from control implementation class: " + _implClass.getName()); + } + } + catch (ClassNotFoundException cnfe) + { + throw new ControlException("Unable to load control implementation: " + implBinding, cnfe); + } + + // + // Cache the threading policy associated with the impl + // + Threading thr = (Threading)_implClass.getAnnotation(Threading.class); + if ( thr != null ) + _threadingPolicy = thr.value(); + else + _threadingPolicy = ThreadingPolicy.SINGLE_THREADED; // default to single-threaded + + ensureThreadingBehaviour(); + + try + { + // + // Create and initialize the new instance + // + _control = _implClass.newInstance(); + + try + { + /* + Run the ImplInitializer. This class is code generated based on metadata from a control + implementation. If a Control implementation declares event handlers for the + ControlBeanContext or for the ResourceContext, executing this code generated class + will add the appropriate LifeCycle and / or Resource event listeners. + */ + getImplInitializer().initialize(this, _control); + _hasServices = true; + } + catch (Exception e) + { + throw new ControlException("Control initialization failure", e); + } + + // + // Once the control is initialized, then allow the associated context + // to do any initialization. + // + ControlBeanContext cbcs = getBeanContextProxy(); + + /* + Implementation note: this call will run the LifeCycleListener(s) that have + been wired-up to the ControlBeanContext object associated with this ControlBean. + */ + cbcs.initializeControl(); + } + catch (RuntimeException re) { + // never mask RuntimeExceptions + throw re; + } + catch (Exception e) + { + throw new ControlException("Unable to create control instance", e); + } + } + + // + // If the implementation instance does not currently have contextual services, they + // are lazily restored here. + // + if (!_hasServices) + { + getImplInitializer().initServices(this, _control); + _hasServices = true; + } + + return _control; + } + + /** + * Returns the implementation instance associated with this ControlBean. + */ + /* package */ Object getImplementation() { + return _control; + } + + /** + * The preinvoke method is called before all operations on the control. In addition to + * providing a basic hook for logging, context initialization, resource management, + * and other common services, it also provides a hook for interceptors. + */ + protected void preInvoke(Method m, Object [] args, String [] interceptorNames) + throws InterceptorPivotException + { + // + // If the implementation expects single threaded behavior and our container does + // not guarantee it, then enforce it locally here + // + if (_invokeLock != null) + { + try { _invokeLock.acquire(); } catch (InterruptedException ie) { } + } + + // + // Process interceptors + // + if ( interceptorNames != null ) + { + for ( String n : interceptorNames ) + { + Interceptor i = ensureInterceptor( n ); + try + { + i.preInvoke( this, m, args ); + } + catch (InterceptorPivotException ipe) + { + ipe.setInterceptorName(n); + throw ipe; + } + } + } + + Vector invokeListeners = getInvokeListeners(); + if (invokeListeners.size() > 0) + { + for (InvokeListener listener : invokeListeners) + listener.preInvoke(m, args); + } + } + + /** + * The preinvoke method is called before all operations on the control. It is the basic + * hook for logging, context initialization, resource management, and other common + * services + */ + protected void preInvoke(Method m, Object [] args) + { + try + { + preInvoke(m, args, null); + } + catch (InterceptorPivotException ipe) + { + //this will never happen because no interceptor is passed. + } + } + + /** + * The postInvoke method is called after all operations on the control. In addition to + * providing the basic hook for logging, context initialization, resource management, and other common + * services, it also provides a hook for interceptors. During preInvoke, interceptors will be + * called in the order that they are in the list. During postInvoke, they will be called in the + * reverse order. Here is an example of the call sequence with I1, I2, and I3 being interceptors in the list: + * + * I1.preInvoke() -> I2.preInvoke() -> I3.preInvoke() -> invoke method + * | + * I1.postInvoke() <- I2.postInvoke() <- I3.postInvoke() <--- + * + * In the event that an interceptor in the list pivoted during preInvoke, the "pivotedInterceptor" + * parameter indicates the interceptor that had pivoted, and the interceptors succeeding it in the list will + * not be called during postInvoke. + */ + protected void postInvoke(Method m, Object [] args, Object retval, Throwable t, String [] interceptorNames, String pivotedInterceptor) + { + try + { + Vector invokeListeners = getInvokeListeners(); + if (invokeListeners.size() > 0) + { + for (InvokeListener listener : invokeListeners) + listener.postInvoke(retval, t); + } + + // + // Process interceptors + // + if ( interceptorNames != null ) + { + for (int cnt = interceptorNames.length-1; cnt >= 0; cnt-- ) + { + String n = interceptorNames[cnt]; + if (pivotedInterceptor == null || n.equals(pivotedInterceptor)) + { + pivotedInterceptor = null; + Interceptor i = ensureInterceptor( n ); + i.postInvoke( this, m, args, retval, t ); + } + } + } + } + finally + { + // + // Release any lock obtained above in preInvoke + // + if (_invokeLock != null) + _invokeLock.release(); + } + } + + /** + * The postInvoke method is called after all operations on the control. It is the basic + * hook for logging, context initialization, resource management, and other common + * services. + */ + protected void postInvoke(Method m, Object [] args, Object retval, Throwable t) + { + postInvoke(m, args, retval, t, null, null); + } + + + /** + * Sets the EventNotifier for this ControlBean + */ + protected void setEventNotifier(Class eventSet, T notifier) + { + _notifiers.put(eventSet,notifier); + + // + // Register this notifier for all EventSet interfaces up the interface inheritance + // hiearachy as well + // + List superEventSets = new ArrayList(); + getSuperEventSets(eventSet, superEventSets); + Iterator i = superEventSets.iterator(); + while (i.hasNext()) + { + Class superEventSet = i.next(); + _notifiers.put(superEventSet,notifier); + } + } + + /** + * Finds all of the EventSets extended by the input EventSet, and adds them to + * the provided list. + * @param eventSet + * @param superEventSets + */ + private void getSuperEventSets(Class eventSet, List superEventSets) + { + Class[] superInterfaces = eventSet.getInterfaces(); + if (superInterfaces != null) + { + for (int i=0; i < superInterfaces.length; i++) + { + Class superInterface = superInterfaces[i]; + if (superInterface.isAnnotationPresent(EventSet.class)) + { + superEventSets.add(superInterface); + + // Continue traversing up the EventSet inheritance hierarchy + getSuperEventSets(superInterface, superEventSets); + } + } + } + } + + /** + * Returns an EventNotifier/UnicastEventNotifier for this ControlBean for the target event set + */ + protected T getEventNotifier(Class eventSet) + { + return (T)_notifiers.get(eventSet); + } + + /** + * Returns the list of InvokeListeners for this ControlBean + */ + /* package */ Vector getInvokeListeners() + { + if (_invokeListeners == null) + _invokeListeners = new Vector(); + return _invokeListeners; + } + + /** + * Registers a new InvokeListener for this ControlBean. + */ + /* package */ void addInvokeListener(InvokeListener invokeListener) + { + getInvokeListeners().addElement(invokeListener); + } + + /** + * Deregisters an existing InvokeListener for this ControlBean. + */ + /* package */ void removeInvokeListener(InvokeListener invokeListener) + { + getInvokeListeners().removeElement(invokeListener); + } + + /** + * Returns the local (parent-relative) ID for this ControlBean + */ + protected String getLocalID() + { + return _localID; + } + + /** + * Set the local (parent-relative) ID for this ControlBean. It has package access because + * the local ID should only be set from within the associated context, and only when the + * bean is currently anonymous (hence the assertion below) + */ + /* package */ void setLocalID(String localID) + { + assert _localID == null; // should only set if not already set! + _localID = localID; + } + + /** + * Returns the bean context instance associated with the this bean, as opposed to the + * parent context returned by the public getBeanContext() API. + */ + public ControlBeanContext getControlBeanContext() + { + // + // The peer context instance is the context provider for this ControlBean + // + return getBeanContextProxy(); + } + + /** + * Locates and obtains a context service from the BeanContextServices instance + * supporting this bean. + * + * The base design for the BeanContextServicesSupport is that it will delegate up to peers + * in a nesting context, so a nested control bean will look 'up' to find a service provider. + */ + protected Object getControlService(Class serviceClass, Object selector) + throws TooManyListenersException + + { + // + // Get the associated context object, then use it to locate the (parent) bean context. + // Services are always provided by the parent context. + // + ControlBeanContext cbc = getControlBeanContext(); + BeanContext bc = cbc.getBeanContext(); + if (bc == null || !(bc instanceof BeanContextServices)) + throw new ControlException("Can't locate service context: " + bc); + + // + // Call getService on the parent context, using this bean as the requestor and the + // associated peer context instance as the child and event listener parameters. + // + return ((BeanContextServices)bc).getService(cbc, this, serviceClass, selector, cbc); + } + + /** + * Sets a property on the ControlBean instance. All generated property setter methods + * will delegate down to this method. + */ + protected void setControlProperty(PropertyKey key, Object o) + { + AnnotationConstraintValidator.validate(key, o); + _properties.setProperty(key, o); + } + + /** + * Dispatches the requested operation event on the ControlBean. + * @see org.apache.beehive.controls.runtime.bean.ControlContainerContext#dispatchEvent + */ + /* package */ Object dispatchEvent(EventRef event, Object [] args) + throws IllegalAccessException,IllegalArgumentException, + InvocationTargetException + { + ensureControl(); + + // + // Translate the EventRef back to an actual event method on the ControlInterface + // + Class controlInterface = getControlInterface(); + Method method = event.getEventMethod(controlInterface); + + // + // Locate the target of the event + // + Object eventTarget = null; + if (method.getDeclaringClass().isAssignableFrom(_control.getClass())) + { + // + // If the control implementation implements that EventSet interface, then + // dispatch the event directly to it, and allow it do make the decision about + // how/when to dispatch to any external listeners (via a @Client notifier + // instance) + // + eventTarget = _control; + } + else + { + // + // The associated control implementation does not directly handle the event, + // so find the event notifier instance for the EventSet interface associated + // with the method. + // + eventTarget = _notifiers.get(method.getDeclaringClass()); + if (eventTarget == null) + throw new IllegalArgumentException("No event notifier found for " + event); + } + + // + // Dispatch the event + // + return method.invoke(eventTarget, args); + } + + /** + * Returns a property on the ControlBean instance. This version does not coerce + * an annotation type property from a PropertyMap to a proxy instance of the + * type. + */ + protected Object getRawControlProperty(PropertyKey key) + { + return _properties.getProperty(key); + } + + /** + * Returns a property on the ControlBean instance. All generated property getter methods + * will delegate down to this method + */ + protected Object getControlProperty(PropertyKey key) + { + Object value = getRawControlProperty(key); + + // If the held value is a PropertyMap, then wrap it in an annotation proxy of + // the expected type. + if (value instanceof PropertyMap) + { + PropertyMap map = (PropertyMap)value; + value = PropertySetProxy.getProxy(map.getMapClass(), map); + } + + return value; + } + + /* this method is implemented during code generation by a ControlBean extension */ + /** + * Returns the local cache for ControlBean property maps. + */ + abstract protected Map getPropertyMapCache(); + + /** + * Returns the PropertyMap containing values associated with an AnnotatedElement. Elements + * that are associated with the bean's Control interface will be locally cached. + */ + protected PropertyMap getAnnotationMap(AnnotatedElement annotElem) + { + Map annotCache = getPropertyMapCache(); + + // If in the cache already , just return it + if (annotCache.containsKey(annotElem)) + return (PropertyMap)annotCache.get(annotElem); + + // + // Ask the associated ControlBeanContext to locate and initialize a PropertyMap, then + // store it in the local cache. + // + PropertyMap map = getControlBeanContext().getAnnotationMap(annotElem); + annotCache.put(annotElem, map); + + return map; + } + + /** + * Returns the property map containing the properties for the bean + */ + /* package */ BeanPropertyMap getPropertyMap() + { + return _properties; + } + + /** + * This protected version is only available to concrete subclasses that expose bound + * property support. This method is synchronized to enable lazy instantiation, in + * the belief that it is a bigger win to avoid allocating when there are no listeners + * than it is to introduce synchronization overhead on access. + */ + synchronized protected PropertyChangeSupport getPropertyChangeSupport() + { + if (_changeSupport == null) + _changeSupport = new PropertyChangeSupport(this); + + return _changeSupport; + } + + /** + * Delivers a PropertyChangeEvent to any registered PropertyChangeListeners associated + * with the property referenced by the specified key. + * + * This method *should not* be synchronized, as the PropertyChangeSupport has its own + * built in synchronization mechanisms. + */ + protected void firePropertyChange(PropertyKey propertyKey, Object oldValue, Object newValue) + { + // No change support instance means no listeners + if (_changeSupport == null) + return; + + _changeSupport.firePropertyChange(propertyKey.getPropertyName(), oldValue, newValue); + } + + /** + * This protected version is only available to concrete subclasses that expose bound + * property support. This method is synchronized to enable lazy instantiation, in + * the belief that is a bigger win to avoid allocating when there are no listeners + * than it is to introduce synchronization overhead on access. + */ + synchronized protected VetoableChangeSupport getVetoableChangeSupport() + { + if (_vetoSupport == null) + _vetoSupport = new VetoableChangeSupport(this); + + return _vetoSupport; + } + + /** + * Delivers a PropertyChangeEvent to any registered VetoableChangeListeners associated + * with the property referenced by the specified key. + * + * This method *should not* be synchronized, as the VetoableChangeSupport has its own + * built in synchronization mechanisms. + */ + protected void fireVetoableChange(PropertyKey propertyKey, Object oldValue, Object newValue) + throws java.beans.PropertyVetoException + { + // No veto support instance means no listeners + if (_vetoSupport == null) + return; + + _vetoSupport.fireVetoableChange(propertyKey.getPropertyName(), oldValue, newValue); + } + + /** + * Returns the parameter names for a method on the ControlBean. Actual mapping is done + * by generated subclasses, so if we reach the base ControlBean implementation, then + * no parameter names are available for the target method. + */ + protected String [] getParameterNames(Method m) + { + throw new IllegalArgumentException("No parameter name data for " + m); + } + + /** + * Computes the most derived ControlInterface for the specified ControlExtension. + * @param controlIntf + * @return the most derived ControlInterface + * @deprecated Use {@link ControlUtils#getMostDerivedInterface(Class)} instead. This method will + * be removed in the next release. + */ + public static Class getMostDerivedInterface(Class controlIntf) + { + return ControlUtils.getMostDerivedInterface(controlIntf); + } + + /** + * Enforces the VersionRequired annotation at runtime (called from each ControlBean). + * @param intfName + * @param version + * @param versionRequired + */ + protected static void enforceVersionRequired(String intfName, Version version, VersionRequired versionRequired) + { + if ( versionRequired != null ) + { + int majorRequired = versionRequired.major(); + int minorRequired = versionRequired.minor(); + + if ( majorRequired < 0 ) // no real version requirement + return; + + int majorPresent = -1; + int minorPresent = -1; + if ( version != null ) + { + majorPresent = version.major(); + minorPresent = version.minor(); + + if ( majorRequired <= majorPresent && + (minorRequired < 0 || minorRequired <= minorPresent) ) + { + // Version requirement is satisfied + return; + } + } + + // + // Version requirement failed + // + throw new ControlException( "Control extension " + intfName + " fails version requirement: requires interface version " + + majorRequired + "." + minorRequired + ", found interface version " + + majorPresent + "." + minorPresent + "." ); + } + } + + + /** + * Implementation of the Java serialization writeObject method + */ + private synchronized void writeObject(ObjectOutputStream oos) + throws IOException + { + if (_control != null) + { + // + // If the implementation class is marked as transient/stateless, then reset the + // reference to it prior to serialization. A new instance will be created by + // ensureControl() upon first use after deserialization. + // If the implementation class is not transient, then invoke the ImplInitializer + // resetServices method to reset all contextual service references to null, as + // contextual services should never be serializated and always reassociated on + // deserialization. + // + ControlImplementation implAnnot = (ControlImplementation)_implClass.getAnnotation(ControlImplementation.class); + assert implAnnot != null; + if (implAnnot.isTransient()) + { + _control = null; + } + else + { + getImplInitializer().resetServices(this, _control); + _hasServices = false; + } + } + + oos.defaultWriteObject(); + } + + /** + * Called during XMLDecoder reconstruction of a ControlBean. + */ + public void decodeImpl(Object impl) + { + if (impl != _control) + throw new ControlException("Cannot change implementation"); + } + + /** + * Internal method used to lookup a ControlBeanContextFactory. This factory is used to create the + * ControlBeanContext object for this ControlBean. The factory is discoverable from either the containing + * ControlBeanContext object or from the environment. If the containing CBC object exposes a + * contextual service of type {@link ControlBeanContextFactory}, the factory returned from this will + * be used to create a ControlBeanContext object. + * + * @param context + * @return the ControlBeanContextFactory discovered in the environment or a default one if no factory is configured + */ + private ControlBeanContextFactory lookupControlBeanContextFactory + (org.apache.beehive.controls.api.context.ControlBeanContext context) { + + // first, try to find the CBCFactory from the container + if(context != null) { + ControlBeanContextFactory cbcFactory = context.getService(ControlBeanContextFactory.class, null); + + if(cbcFactory != null) { + return cbcFactory; + } + } + + // Create the context that acts as the BeanContextProxy for this bean (the context that this bean _defines_). + try + { + DiscoverClass discoverer = new DiscoverClass(); + Class factoryClass = + discoverer.find(ControlBeanContextFactory.class, DefaultControlBeanContextFactory.class.getName()); + + return (ControlBeanContextFactory)factoryClass.newInstance(); + } + catch (Exception e) { + throw new ControlException("Exception creating ControlBeanContext", e); + } + } + + /** + * Retrieves interceptor instances, creates them lazily. + */ + protected Interceptor ensureInterceptor( String n ) + { + Interceptor i = null; + if ( _interceptors == null ) + { + _interceptors = new HashMap(); + } + else + { + i = _interceptors.get( n ); + } + + if ( i == null ) + { + try + { + i = (Interceptor) getControlService( getControlBeanContext().getClassLoader().loadClass( n ), null ); + } + catch ( Exception e ) + { + // Couldn't instantiate the desired service; usually this is because the service interface itself + // isn't present on this system at runtime (ClassNotFoundException), or if the container of the + // control didn't registers the service. + + /* TODO log a message here to that effect, but just swallow the exception for now. */ + } + finally + { + // We want to always return an interceptor, so if we can't get the one we want, we'll substitute + // a "null" interceptor that does nothing. + if ( i == null) + i = new NullInterceptor(); + + _interceptors.put( n, i ); + } + } + return i; + } + + /** + * The "null" interceptor that does nothing. Used when a specific interceptor + * is unavailable at runtime. + */ + static private class NullInterceptor + implements Interceptor + { + public void preInvoke( org.apache.beehive.controls.api.bean.ControlBean cb, Method m, Object [] args ) {} + public void postInvoke( org.apache.beehive.controls.api.bean.ControlBean cb, Method m, Object [] args, Object retval, Throwable t) {} + public void preEvent( org.apache.beehive.controls.api.bean.ControlBean cb, Class eventSet, Method m, Object [] args) {} + public void postEvent( org.apache.beehive.controls.api.bean.ControlBean cb, Class eventSet, Method m, Object [] args, Object retval, Throwable t ) {} + } + + /** BEGIN unsynchronized fields */ + + /** + * The following fields are initialized in the constructor and never subsequently changed, + * so they are safe for unsynchronized read access + */ + + /** + * The control implementation class bound to this ControlBean + */ + protected Class _implClass; + + /** + * The threading policy associated with the control implementation wrapped by this + * ControlBean. Initialized to MULTI_THREADED in order to assume multi-threadedness + * until a bean is associated with a specific (potentially single-threaded) implementation. + */ + transient private ThreadingPolicy _threadingPolicy = ThreadingPolicy.MULTI_THREADED; + + /** + * Contains the per-instance properties set for this ControlBean. + */ + private BeanPropertyMap _properties; + + /** END unsynchronized fields */ + + /* BEGIN synchronized fields */ + + /* + * The following fields must be: + * 1) only written in synchronized methods or (unsynchronized) constructors + * 2) only read in synchronized methods or methods that are safe wrt the values changing during + * execution. + */ + + /** + * The control implementation instance wrapped by this ControlBean + */ + private Object _control; + + /** + * The control bean context instance associated with this ControlBean + */ + private ControlBeanContext _cbc; + + /** + * An ImplInitializer instances used to initialize/reset the state of the associated + * implementation instance. + */ + transient private ImplInitializer _implInitializer; + + /** + * Indicates whether the contextual services associated with the bean have been + * fully initialized. + */ + transient private boolean _hasServices = false; + + /** + * Used to guarantee single threaded invocation when required. If the + * outer container provides the guarantee or the implementation itself + * is threadsafe, then the value will be null. + */ + transient private Semaphore _invokeLock; + + /** + * This field manages PropertyChangeListeners (if supporting bound properties). + */ + private PropertyChangeSupport _changeSupport; + + /** + * This field manages VetoabbleChangeListeners (if supporting constrained properties) + */ + private VetoableChangeSupport _vetoSupport; + + /** END synchronized fields */ + + /** + * The (context relative) control ID associated with this instance + */ + private String _localID; + + /** + * The public control interface associated with this ControlBean + */ + private Class _controlIntf; + + /** + * This field manages the register listener list(s) associated with event set interfaces + * for the ControlBean. The value objects are either UnicastEventNotifier or EventNotifier + * instances, depending upon whether the associated EventSet interface is unicast or + * multicast. + */ + private HashMap _notifiers = new HashMap(); + + /** + * Maintains the list of callback event listeners (if any) for this ControlBean. + */ + transient private Vector _invokeListeners; + + /** + * HashMap to hold interceptor impl instances. + * Populated lazily. Maps interceptor interface name to impl. + */ + transient private HashMap _interceptors; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlBeanContext.java b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlBeanContext.java new file mode 100644 index 0000000..ec2db56 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlBeanContext.java @@ -0,0 +1,1120 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.bean; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyVetoException; +import java.beans.PropertyChangeListener; +import java.beans.VetoableChangeListener; +import java.beans.beancontext.BeanContext; +import java.beans.beancontext.BeanContextServiceRevokedEvent; +import java.beans.beancontext.BeanContextServiceProvider; +import java.beans.beancontext.BeanContextServices; +import java.beans.beancontext.BeanContextChild; +import java.beans.beancontext.BeanContextServiceRevokedListener; +import java.beans.beancontext.BeanContextServicesListener; +import java.beans.beancontext.BeanContextMembershipListener; +import java.beans.beancontext.BeanContextServiceAvailableEvent; +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.TooManyListenersException; +import java.util.Vector; +import java.util.Collection; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectInputStream; +import java.net.URL; + +import org.apache.beehive.controls.api.ControlException; +import org.apache.beehive.controls.api.context.ControlHandle; +import org.apache.beehive.controls.api.properties.AnnotatedElementMap; +import org.apache.beehive.controls.api.properties.BeanPropertyMap; +import org.apache.beehive.controls.api.properties.PropertyMap; +import org.apache.beehive.controls.api.properties.PropertySet; +import org.apache.beehive.controls.api.properties.PropertySetProxy; + +/** + * The ControlBeanContext implements the basic BeanContextServices implementation + * for ControlBeans. + * + * It provides several basic functions: + * - it defines the generic services that are available for all control containers + * - it acts as the base class for other container service implementations + * - it acts as the BeanContextServicesRevokedListener when an associated control + * bean has lost access to services. + */ +public class ControlBeanContext + implements org.apache.beehive.controls.api.context.ControlBeanContext, + java.beans.PropertyChangeListener, + java.beans.VetoableChangeListener, + java.io.Serializable +{ + /** + * Creates a new ControlBeanContext instance associated with a specific control bean. If the + * ControlBean is null, this ControlBeanContext object represents a top-level Control + * container. This constructor uses the default implementation of the + * {@link java.beans.beancontext.BeanContextServices} interface from the JDK. + * + * @param bean The control bean that contains/scopes the ControlBeanContext. If null, it means the + * ControlBeanContext is for a top-level container. + */ + protected ControlBeanContext(ControlBean bean) + { + this(bean, DEFAULT_BEAN_CONTEXT_SERVICES_FACTORY); + } + + /** + * Creates a new ControlBeanContext instance associated with a specific control bean. If the + * ControlBean is null, this ControlBeanContext object represents a top-level Control + * container. This constructor uses the beanContextServicesDelegate instance as the + * implementation of the {@link java.beans.beancontext.BeanContextServices} interface. + * + * @param bean The control bean + * @param beanContextServicesFactory A factory that can be used to create the BeanContextServicesFactory object + * that implements support for the {@link BeanContextServices} interface. + */ + protected ControlBeanContext(ControlBean bean, BeanContextServicesFactory beanContextServicesFactory) { + super(); + + _bean = bean; + + // ensure that there is a valid factory for creating the BCS delegate + if(beanContextServicesFactory == null) + beanContextServicesFactory = DEFAULT_BEAN_CONTEXT_SERVICES_FACTORY; + + _beanContextServicesDelegate = beanContextServicesFactory.instantiate(this); + initialize(); + } + + /** + * Called by BeanContextSupport superclass during construction and deserialization to + * initialize subclass transient state + */ + public void initialize() + { + // + // Register the ControlBeanContext provider on all new context instances. + // + addService(org.apache.beehive.controls.api.context.ControlBeanContext.class, CONTROL_BEAN_CONTEXT_PROVIDER); + } + + /** + * Implements the + * {@link java.beans.beancontext.BeanContextServiceRevokedListener#serviceRevoked(java.beans.beancontext.BeanContextServiceRevokedEvent)} + * method. This is called if the associated {@link ControlBean} has requested a service that is being subsequently + * revoked. + */ + public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) + { + // + // This can happen, if the control is disassociated from a parent context that is + // providing services. + // + } + + /** + * Overrides the {@link java.beans.beancontext.BeanContextChild#setBeanContext(java.beans.beancontext.BeanContext)} + * method. This hook is used to perform additional processing that needs to occur when the control is associated + * with a new nesting context. + */ + public synchronized void setBeanContext(BeanContext beanContext) + throws PropertyVetoException + { + ControlBeanContext cbcs = null; + + if (beanContext != null) + { + // + // ControlBeans can only be nested in context service instances that derive + // from ControlBeanContext. + // + if (!(beanContext instanceof ControlBeanContext)) + { + PropertyChangeEvent pce = new PropertyChangeEvent(_bean, "beanContext", getBeanContext(), beanContext); + throw new PropertyVetoException("Context does not support nesting controls: " + + beanContext.getClass(), pce); + } + + cbcs = (ControlBeanContext)beanContext; + } + + + _beanContextServicesDelegate.setBeanContext(beanContext); + + resetControlID(); + + _hasSingleThreadedParent = cbcs != null ? cbcs.isSingleThreadedContainer() : false; + + // + // Notify the bean that its context (container) has been set. + // + if (_bean != null) + _bean.setBeanContext(beanContext); + } + + /** + * The NameGenerator class is a simple helper class that creates new unique names based + * upon a base prefix and an incrementing counter + */ + private static class NameGenerator implements java.io.Serializable + { + NameGenerator(String namePrefix) + { + _namePrefix = namePrefix; + } + + /** + * Get the next unique name + */ + public synchronized String next() + { + return _namePrefix + _nextIndex++; + } + + int _nextIndex = 0; + String _namePrefix; + } + + /** + * Returns a new NameGenerator instance based upon a particular naming + * prefix. + */ + private NameGenerator getNameGenerator(String namePrefix) + { + synchronized(this) + { + if (_nameGenerators == null) + _nameGenerators = new HashMap(); + + NameGenerator nameGenerator = _nameGenerators.get(namePrefix); + if (nameGenerator == null) + { + nameGenerator = new NameGenerator(namePrefix); + _nameGenerators.put(namePrefix, nameGenerator); + } + return nameGenerator; + } + } + + /** + * Generates a new unique control ID for an instance of the target class + */ + public String generateUniqueID(Class clazz) + { + String namePrefix = clazz.getName(); + int dotIndex = namePrefix.lastIndexOf('.'); + if (dotIndex > 0) + namePrefix = namePrefix.substring(dotIndex+1); + NameGenerator nameGenerator = getNameGenerator(namePrefix); + return nameGenerator.next(); + } + + /** + * Overrides the BeanContextSupport.add() method to perform additional validation + * that is unique for ControlBeans containers. + */ + public boolean add(Object targetChild) + { + // + // The context can contain ControlBeans and other types of objects, such as a control + // factory. + // + String beanID = null; + if (targetChild instanceof ControlBean) + { + ControlBean bean = (ControlBean)targetChild; + beanID = bean.getLocalID(); + + // + // The bean is anonymous, so we must generate a new unique name within this context. + // + if (beanID == null) + { + beanID = generateUniqueID(bean.getClass()); + bean.setLocalID(beanID); + } + + ControlBean existingBean = (ControlBean)_childMap.get(beanID); + if (existingBean != null && existingBean != targetChild) + { + throw new IllegalArgumentException("Attempting to add control with duplicate ID: " + + beanID); + } + } + + boolean added = _beanContextServicesDelegate.add(targetChild); + if (added && beanID != null) + _childMap.put(beanID, targetChild); + + return added; + } + + /** + * Overrides the BeanContextSupport.remove() method to perform additional post-processing + * on child removal. + */ + public boolean remove(Object targetChild) + { + assert targetChild instanceof ControlBean; // should be guaranteed above + boolean removed = _beanContextServicesDelegate.remove(targetChild); + + if (removed) + { + // + // Remove from the locally maintained child map + // + String localID = ((ControlBean)targetChild).getLocalID(); + Object removedChild = _childMap.remove(localID); + assert removedChild == targetChild; // just being safe + } + return removed; + } + + /** + * Returns a ControlBean instance nested the current BeanContext. + * @param id the identifier for the target control, relative to the current + * context. + */ + public ControlBean getBean(String id) + { + // If no control id separator found, the bean is a direct child of this context + int delim = id.indexOf(org.apache.beehive.controls.api.bean.ControlBean.IDSeparator); + if (delim < 0) // child is a direct descendent + return (ControlBean)_childMap.get(id); + + // Find the child referenced by the first element in the path + ControlBean bean = (ControlBean)_childMap.get(id.substring(0, delim)); + if (bean == null) + return bean; + + // Get the BeanContext associated with the found child, and then ask it + // to resolve the rest of the path + return bean.getBeanContextProxy().getBean(id.substring(delim+1)); + } + + /** + * Returns the ControlBean associated directly with the ControlBeanContext. If the + * context represents a top-level container, will return null. + */ + public ControlBean getControlBean() + { + return _bean; + } + + public synchronized boolean hasSingleThreadedParent() + { + return _hasSingleThreadedParent; + } + + /** + * Returns true if this container associated with this context service enforces + * single-threaded invocation, false otherwise. + * + * This MUST be overridden by container-specific subclasses in order to change + * the default behavior. If a single-threaded container intends to guarantee + * single-threaded behavior (such as the EJB container), this should return true. + */ + public synchronized boolean isSingleThreadedContainer() + { + return ( hasSingleThreadedParent() || ( _bean != null && _bean.hasSingleThreadedImpl() )); + } + + /** + * The initializeControl method is invoked when the implementation instance associated + * with the context has been instantiated and initialized. + */ + public void initializeControl() + { + // + // Deliver the onCreate event to any register lifecycle listeners + // + if (_lifeCycleListeners != null) + { + for (LifeCycle lifeCycleListener : _lifeCycleListeners) { + lifeCycleListener.onCreate(); + } + } + } + + /** + * Returns the PropertyMap containing default properties for an AnnotatedElement + * in the current context. The initialization of PropertyMap binding is always + * done by delegating to a {@link ControlContainerContext}, enabling containers to implement + * property binding mechanisms (such as external config) that may override the values + * contained within the element annotations. + */ + public PropertyMap getAnnotationMap(AnnotatedElement annotElem) + { + ControlBeanContext beanContext = this; + while (beanContext != null) + { + // REVIEW: should ControlContainerContext-derived classes override getBeanAnnotationMap? Not sure + // that name makes sense, and perhaps it shouldn't take a ControlBean. + if (beanContext instanceof ControlContainerContext) + return beanContext.getBeanAnnotationMap(_bean, annotElem); + beanContext = (ControlBeanContext)beanContext.getBeanContext(); + } + + // No ControlContainerContext was found, so just use the default implementation + return getBeanAnnotationMap(_bean, annotElem); + } + + /** + * The default implementation of getBeanAnnotationMap. This returns a map based purely + * upon annotation reflection + */ + protected PropertyMap getBeanAnnotationMap(ControlBean bean, AnnotatedElement annotElem) + { + PropertyMap map = new AnnotatedElementMap(annotElem); + + // REVIEW: is this the right place to handle the general control client case? + if ( bean != null ) + setDelegateMap( map, bean, annotElem ); + + return map; + } + + static protected void setDelegateMap( PropertyMap map, ControlBean bean, AnnotatedElement annotElem ) + { + // + // If building an annotation map for a method or field, we want to delegate back + // to the base control type. + // + Class annotClass = null; + if (annotElem instanceof Field) + { + annotClass = ((Field)annotElem).getType(); + } + else if (annotElem instanceof Method) + { + annotClass = bean.getControlInterface(); + } + + if (annotClass != null) + { + PropertyMap delegateMap = bean.getAnnotationMap(annotClass); + map.setDelegateMap(delegateMap); + } + } + + // + // ControlBeanContext.getControlInterface + // + public Class getControlInterface() + { + return _bean.getControlInterface(); + } + + // + // ControlBeanContext.getControlPropertySet + // + public T getControlPropertySet(Class propertySet) + { + PropertyMap map = _bean.getPropertyMap(); + + // + // Optional properties are not exposed to clients using traditional JavaBean + // setters/getters (because there is way to represent an 'unset' value); for + // these properties, the impl can tell if the PropertySet is unset because + // this method will return null. + // + if (!map.containsPropertySet(propertySet)) + { + PropertySet psAnnot = propertySet.getAnnotation(PropertySet.class); + if (psAnnot.optional()) + return null; + } + + // + // Construct a new PropertySet proxy instance that derives its values from + // the bean property map. + // + return PropertySetProxy.getProxy(propertySet, map); + } + + // + // ControlBeanContext.getMethodPropertySet + // + public T getMethodPropertySet(Method m, Class propertySet) + { + PropertyMap map = _bean.getAnnotationMap(m); + + // + // Optional properties are not exposed to clients using traditional JavaBean + // setters/getters (because there is way to represent an 'unset' value); for + // these properties, the impl can tell if the PropertySet is unset because + // this method will return null. + // + if (!map.containsPropertySet(propertySet)) + { + PropertySet psAnnot = propertySet.getAnnotation(PropertySet.class); + if (psAnnot.optional()) + return null; + } + + // + // Construct a new PropertySet proxy instance that derives its values from + // the method property map. + // + return PropertySetProxy.getProxy(propertySet, _bean.getAnnotationMap(m)); + } + + // + // ControlBeanContext.getParameterPropertySet + // + public T getParameterPropertySet(Method m, int i, Class propertySet) + throws IllegalArgumentException, IndexOutOfBoundsException + { + if (i >= m.getParameterTypes().length) + throw new IndexOutOfBoundsException("Invalid parameter index for method:" + m); + + // todo: Currently, there is no external override mechanism for method parameters + Annotation [] paramAnnots = m.getParameterAnnotations()[i]; + for (Annotation paramAnnot : paramAnnots) + if (propertySet.isAssignableFrom(paramAnnot.getClass())) + return (T) paramAnnot; + + return null; + } + + // + // ControlBeanContext.getParameterNames + // + public String [] getParameterNames(Method m) + throws IllegalArgumentException + { + return _bean.getParameterNames(m); + } + + // + // ControlBeanContext.getNamedParameterValue + // + public Object getParameterValue(Method m, String parameterName, Object [] parameters) + throws IllegalArgumentException + { + String [] names = getParameterNames(m); + + // Validate the input parameter array + if (parameters.length != names.length) + throw new IllegalArgumentException("Expected " + names.length + " parameters," + + "Found " + parameters.length); + + // Finding the index of the matching parameter name + int i = 0; + while (i < names.length) + { + if (names[i].equals(parameterName)) + break; + i++; + } + if (i == names.length) + throw new IllegalArgumentException("No method parameter with name: " + parameterName); + + // Return the parameter value at the matched index + return parameters[i]; + } + + // + // ControlBeanContext.getPropertyMap + // + public PropertyMap getControlPropertyMap() + { + // + // Return a wrapped copy of the original bean property map, so any edits + // don't impact the bean properties. + // + return new BeanPropertyMap(_bean.getPropertyMap()); + } + + // + // ControlBeanContext.getService + // + public T getService(Class serviceClass, Object selector) + { + // + // If the requested service is a ControlBeanContext instance, the current instance + // can be returned. + // + if (serviceClass.equals(org.apache.beehive.controls.api.context.ControlBeanContext.class)) + return (T)this; + + // + // The parent BeanContext is responsible for providing requested services. If + // no parent context is available or it is does not manage services, then no service. + // + BeanContext bc = getBeanContext(); + if (bc == null || !(bc instanceof BeanContextServices)) + return null; + + // + // Call getService on the parent context, using this bean as the requestor and the + // this context as the child context and ServicesRevoked event listener parameters. + // + try + { + return (T)((BeanContextServices)bc).getService(this, _bean, serviceClass, selector, this); + } + catch (TooManyListenersException tmle) + { + // This would be highly unusual... it implies that the registration for service + // revocation notifications failed for some reason. + throw new ControlException("Unable to register for service events", tmle); + } + } + + // + // ControlBeanContext.getControlHandle + // + public ControlHandle getControlHandle() + { + // + // Find the associated ControlContainerContext, which provides a container-specific + // implementation of ControlHandle + // + ControlBeanContext beanContext = this; + while (beanContext != null && !(beanContext instanceof ControlContainerContext)) + beanContext = (ControlBeanContext)beanContext.getBeanContext(); + + if (beanContext == null) + return null; + + // + // Ask the container for a ControlHandle instance referencing the target bean + // + return ((ControlContainerContext)beanContext).getControlHandle(_bean); + } + + // + // ControlBeanContext.getClassLoader + // + public java.lang.ClassLoader getClassLoader() + { + return getControlInterface().getClassLoader(); + } + + // + // ControlBeanContext.addLifeCycleListener + // + synchronized public void addLifeCycleListener(LifeCycle listener) + { + if (_lifeCycleListeners == null) + { + _lifeCycleListeners = new Vector(); + + // + // Since bound/constrained property changes are exposed as lifecycle events, we + // need to register ourselves as a listener for these events the first time a + // lifecycle listener is added. + // + _bean.getPropertyChangeSupport().addPropertyChangeListener(this); + _bean.getVetoableChangeSupport().addVetoableChangeListener(this); + } + _lifeCycleListeners.addElement(listener); + } + + // + // ControlBeanContext.removeLifeCycleListener + // + synchronized public void removeLifeCycleListener(LifeCycle listener) + { + if (_lifeCycleListeners != null) + _lifeCycleListeners.removeElement(listener); + } + + // + // PropertyChangeListener.propertyChange + // + public void propertyChange(PropertyChangeEvent pce) + { + if (_lifeCycleListeners != null) + { + for (LifeCycle lifeCycleListener : _lifeCycleListeners) { + lifeCycleListener.onPropertyChange(pce); + } + } + } + + // + // VetoableChangeListener.vetoableChange + // + public void vetoableChange(PropertyChangeEvent pce) throws PropertyVetoException + { + if (_lifeCycleListeners != null) + { + for (LifeCycle lifeCycleListener : _lifeCycleListeners) { + lifeCycleListener.onVetoableChange(pce); + } + } + } + + /* package */ String getControlID() + { + if (_controlID != null || _bean == null) + return _controlID; + + // Initially set to the local beans relative ID + String id = _bean.getLocalID(); + + // If there is a parent context, prepend its ID and the ID separator + BeanContext bc = getBeanContext(); + if (bc != null && bc instanceof ControlBeanContext) + { + String parentID = ((ControlBeanContext)bc).getControlID(); + if (parentID != null) + { + id = parentID + + org.apache.beehive.controls.api.bean.ControlBean.IDSeparator + + id; + } + } + + // Cache the computed value + _controlID = id; + + return id; + } + + /** + * Resets the composite control ID for this context and all children beneath it. This + * can be used to invalidate cached values when necessary (for example, when a context + * is reparented). + */ + private void resetControlID() + { + _controlID = null; + for (Object child : this) { + if (child instanceof ControlBeanContext) + ((ControlBeanContext) child).resetControlID(); + } + } + + // + // BeanContextServices.getCurrentServiceClasses + // Override the default implementation of getCurrentServiceClasses inherited from + // java.beans.beancontext.BeanContextServicesSuppport. The reason for this is a bug/ + // flaw in its underlying implementation. It does not include any services exposed + // by any nesting contexts. This is contradictory to the implementation of hasService() + // and getService() which do delegate up to a parent context to find services if not + // available on the local context. This means hasService() could return 'true' for a + // service that isn't returned by getCurrentServiceClasses(), which seems like a bug. + // + synchronized public Iterator getCurrentServiceClasses() + { + Set classSet = new HashSet(); + BeanContextServices bcs = _beanContextServicesDelegate; + + while (bcs != null) + { + Iterator iter = bcs.getCurrentServiceClasses(); + while (iter.hasNext()) + classSet.add(iter.next()); + + // Go up to the parent, if it is a service provider as well + BeanContext bc = getBeanContext(); + if (bc instanceof BeanContextServices && bcs != bc) + bcs = (BeanContextServices)bc; + else + bcs = null; + } + return classSet.iterator(); + } + + // + // BeanContextServices.getCurrentServiceSelectors + // Override getCurrentServiceSelectors for the same reason as above + // + public Iterator getCurrentServiceSelectors(Class serviceClass) + { + if (hasService(serviceClass)) + return _beanContextServicesDelegate.getCurrentServiceSelectors(serviceClass); + + BeanContext bc = getBeanContext(); + if (bc instanceof BeanContextServices) + return ((BeanContextServices)bc).getCurrentServiceSelectors(serviceClass); + + return null; + } + + private synchronized void writeObject(ObjectOutputStream oos) + throws IOException { + oos.defaultWriteObject(); + if(_beanContextServicesDelegate instanceof java.beans.beancontext.BeanContextSupport) { + ((java.beans.beancontext.BeanContextSupport)_beanContextServicesDelegate).writeChildren(oos); + } else if(_beanContextServicesDelegate instanceof org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport) { + ((org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport)_beanContextServicesDelegate).writeChildren(oos); + } + else assert false; + } + + private synchronized void readObject(ObjectInputStream ois) + throws IOException, ClassNotFoundException { + ois.defaultReadObject(); + + if(_beanContextServicesDelegate instanceof java.beans.beancontext.BeanContextSupport) { + ((java.beans.beancontext.BeanContextSupport)_beanContextServicesDelegate).readChildren(ois); + } else if(_beanContextServicesDelegate instanceof org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport) { + ((org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport)_beanContextServicesDelegate).readChildren(ois); + } + else assert false; + + // Re-initialize a deserialized control hierarchy. + initialize(); + } + + protected BeanContextServicesFactory getBeanContextServicesFactory() { + return DEFAULT_BEAN_CONTEXT_SERVICES_FACTORY; + } + + public boolean equals(Object o) { + /* todo: make sure this logic is right / sufficient */ + if (this == o) + return true; + + if(!(o instanceof org.apache.beehive.controls.api.context.ControlBeanContext)) + return false; + + return o instanceof ControlBeanContext && + _beanContextServicesDelegate.equals(((ControlBeanContext)o)._beanContextServicesDelegate); + } + + public int hashCode() { + /* todo: make sure this logic is right / sufficient */ + int result; + result = (_bean != null ? _bean.hashCode() : 0); + result = 31 * result + (_beanContextServicesDelegate != null ? _beanContextServicesDelegate.hashCode() : 0); + return result; + } + + /* -------------------------------------------------------------------------- + + Implementation of java.beans.beancontext.BeanContextServices + + -------------------------------------------------------------------------- */ + public boolean addService(Class serviceClass, BeanContextServiceProvider serviceProvider) { + return _beanContextServicesDelegate.addService(serviceClass, serviceProvider); + } + + public void revokeService(Class serviceClass, BeanContextServiceProvider serviceProvider, boolean revokeCurrentServicesNow) { + _beanContextServicesDelegate.revokeService(serviceClass, serviceProvider, revokeCurrentServicesNow); + } + + public boolean hasService(Class serviceClass) { + return _beanContextServicesDelegate.hasService(serviceClass); + } + + public Object getService(BeanContextChild child, Object requestor, Class serviceClass, Object serviceSelector, BeanContextServiceRevokedListener bcsrl) throws TooManyListenersException { + return _beanContextServicesDelegate.getService(child, requestor, serviceClass, serviceSelector, bcsrl); + } + + public void releaseService(BeanContextChild child, Object requestor, Object service) { + _beanContextServicesDelegate.releaseService(child, requestor, service); + } + + public void addBeanContextServicesListener(BeanContextServicesListener bcsl) { + _beanContextServicesDelegate.addBeanContextServicesListener(bcsl); + } + + public void removeBeanContextServicesListener(BeanContextServicesListener bcsl) { + _beanContextServicesDelegate.removeBeanContextServicesListener(bcsl); + } + + public Object instantiateChild(String beanName) throws IOException, ClassNotFoundException { + return _beanContextServicesDelegate.instantiateChild(beanName); + } + + public InputStream getResourceAsStream(String name, BeanContextChild bcc) throws IllegalArgumentException { + return _beanContextServicesDelegate.getResourceAsStream(name, bcc); + } + + public URL getResource(String name, BeanContextChild bcc) throws IllegalArgumentException { + return _beanContextServicesDelegate.getResource(name, bcc); + } + + public void addBeanContextMembershipListener(BeanContextMembershipListener bcml) { + _beanContextServicesDelegate.addBeanContextMembershipListener(bcml); + } + + public void removeBeanContextMembershipListener(BeanContextMembershipListener bcml) { + _beanContextServicesDelegate.removeBeanContextMembershipListener(bcml); + } + + public BeanContext getBeanContext() { + return _beanContextServicesDelegate.getBeanContext(); + } + + public void addPropertyChangeListener(String name, PropertyChangeListener pcl) { + _beanContextServicesDelegate.addPropertyChangeListener(name, pcl); + } + + public void removePropertyChangeListener(String name, PropertyChangeListener pcl) { + _beanContextServicesDelegate.removePropertyChangeListener(name, pcl); + } + + public void addVetoableChangeListener(String name, VetoableChangeListener vcl) { + _beanContextServicesDelegate.addVetoableChangeListener(name, vcl); + } + + public void removeVetoableChangeListener(String name, VetoableChangeListener vcl) { + _beanContextServicesDelegate.removeVetoableChangeListener(name, vcl); + } + + public int size() { + return _beanContextServicesDelegate.size(); + } + + public boolean isEmpty() { + return _beanContextServicesDelegate.isEmpty(); + } + + public boolean contains(Object o) { + return _beanContextServicesDelegate.contains(o); + } + + public Iterator iterator() { + return _beanContextServicesDelegate.iterator(); + } + + public Object[] toArray() { + return _beanContextServicesDelegate.toArray(); + } + + public Object[] toArray(Object[] a) { + return _beanContextServicesDelegate.toArray(a); + } + + public boolean containsAll(Collection c) { + return _beanContextServicesDelegate.containsAll(c); + } + + public boolean addAll(Collection c) { + return _beanContextServicesDelegate.addAll(c); + } + + public boolean removeAll(Collection c) { + return _beanContextServicesDelegate.removeAll(c); + } + + public boolean retainAll(Collection c) { + return _beanContextServicesDelegate.retainAll(c); + } + + public void clear() { + _beanContextServicesDelegate.clear(); + } + + public void setDesignTime(boolean designTime) { + _beanContextServicesDelegate.setDesignTime(designTime); + } + + public boolean isDesignTime() { + return _beanContextServicesDelegate.isDesignTime(); + } + + public boolean needsGui() { + return _beanContextServicesDelegate.needsGui(); + } + + public void dontUseGui() { + _beanContextServicesDelegate.dontUseGui(); + } + + public void okToUseGui() { + _beanContextServicesDelegate.okToUseGui(); + } + + public boolean avoidingGui() { + return _beanContextServicesDelegate.avoidingGui(); + } + + public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) { + _beanContextServicesDelegate.serviceAvailable(bcsae); + } + + /* -------------------------------------------------------------------------- + + Static / deprecated methods. + + -------------------------------------------------------------------------- */ + + /** + * Applies externally defined (via INTERCEPTOR_CONFIG_FILE) ordering priority for + * controls interceptor services. + * + * @param interceptors + * @return String[] + * @deprecated Use {@link InterceptorUtils#prioritizeInterceptors(String[])} instead. This method will + * be removed in the next point release. + */ + public static String[] prioritizeInterceptors( String [] interceptors ) { + return InterceptorUtils.prioritizeInterceptors(interceptors); + } + + /** + * Returns the default binding based entirely upon annotations or naming conventions. + * @param controlIntf the control interface class + * @return the class name of the default control implementation binding + * @deprecated Use {@link ControlUtils#getDefaultControlBinding(Class)} insated. This method will be + * removed in the next point release. + */ + public static String getDefaultControlBinding(Class controlIntf) + { + return ControlUtils.getDefaultControlBinding(controlIntf); + } + + /** + * Implements the default control implementation binding algorithm ( + "Impl" ). See + * documentation for the org.apache.beehive.controls.api.bean.ControlInterface annotation. + * + * @param implBinding the value of the defaultBinding attribute returned from a ControlInterface annotation + * @param controlClass the actual name of the interface decorated by the ControlInterface annotation + * @return the resolved defaultBinding value + * @deprecated Use {@link ControlUtils#resolveDefaultBinding(String, String)} insated. This method + * will be removed in the next point release. + */ + public static String resolveDefaultBinding( String implBinding, String controlClass ) + { + return ControlUtils.resolveDefaultBinding(implBinding, controlClass); + } + + /** + * The ControlBeanContextProvider inner class acts as a single BeanContext service + * provider for the ControlBeanContext service class. The implementation is simple, + * because the runtime ControlBeanContext implementation class directly implements + * this interface. + */ + private static class ControlBeanContextProvider implements BeanContextServiceProvider + { + // + // BeanContextServiceProvider.getService() + // + public Object getService(BeanContextServices bcs, Object requestor, Class serviceClass, + Object serviceSelector) + { + // + // Contextual services for a ControlBean is provided by the peer context + // instance. + // + if (requestor instanceof ControlBean) + return ((ControlBean)requestor).getControlBeanContext(); + + return null; + } + + // + // BeanContextServiceProvider.releaseService() + // + public void releaseService(BeanContextServices bcs, Object requestor, Object service) + { + // noop, because context exists whether referenced or not + } + + // + // BeanContextServiceProvider.getContextServiceSelectors() + // + public Iterator getCurrentServiceSelectors(BeanContextServices bcs, Class serviceClass) + { + return null; // no selectors + } + } + + /*package*/ static abstract class BeanContextServicesFactory { + protected abstract BeanContextServices instantiate(ControlBeanContext controlBeanContext); + } + + private static final class DefaultBeanContextServicesFactory + extends BeanContextServicesFactory { + protected BeanContextServices instantiate(ControlBeanContext controlBeanContext) { + return new java.beans.beancontext.BeanContextServicesSupport(controlBeanContext); + } + } + + /** + * A singleton instance of the ControlBeanContextProvider class is that will be registered + * on all ControlBeanContext instances. The provider can be a singleton because it is + * completely stateless and thread-safe. + */ + private static final ControlBeanContextProvider CONTROL_BEAN_CONTEXT_PROVIDER = + new ControlBeanContextProvider(); + + /** + * A singleton instance of the BeanContextServicesFactory class that can be implemented by subclasses + * to allow top-level Control containers to provide their own implementations of the + * {@link java.beans.beancontext.BeanContextServices} interface. This field is considered an implementation + * detail and should not be referenced directly. + */ + private static final BeanContextServicesFactory DEFAULT_BEAN_CONTEXT_SERVICES_FACTORY = + new DefaultBeanContextServicesFactory(); + + /** + * The ControlBean instance that this context is providing services for. This value can + * be null, if the context instance is associated with top-level (non-control) context. + */ + private ControlBean _bean; + + /** + * Indicates whether this context's parent guarantees single-threaded behaviour. + */ + private boolean _hasSingleThreadedParent = false; + + /** + * Maps children by the local (relative) ID of the child to the actual bean instance. + * This needs to be synchronized, because adds/removes/gets are not necessarily guaranteed + * to happen within the scope of the global hierarchy lock. It would be relatively easy + * to synchronize add/remove, since setBeanContext on the child is inside this lock scope, + * but gets on the map are another story. + */ + private Map _childMap = Collections.synchronizedMap(new HashMap()); + + /** + * Maintains a set of NameGenerators (for control ID generation) keyed by a + * base prefix. The map itself is lazily constructed, so there is minimal + * overhead of no id generation is needed in this context. + */ + private Map _nameGenerators; + + /** + * Maintains the list of lifecycle event listeners (if any) for this context. + */ + private transient Vector _lifeCycleListeners; + + /** + * Caches the full composite control ID, that includes the entire path from the root + * ContainerContext to the associated bean. This value can be transient, since it + * can be easily recomputed when needed. + */ + private transient String _controlID; + + /** + * Object that implements the java.beans.beancontext APIs from the JDK to provide compliance with the + * JavaBeans BeanContext / BeanContextChild specification. The ControlBeanContext class uses + * this object as a delegate to provide this functionality rather than extending the BeanContext + * support classes directly. This allows for more flexibility in how the BeanContextServices (et al) + * API implementations evolve over time. + */ + private BeanContextServices _beanContextServicesDelegate; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlBeanInfo.java b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlBeanInfo.java new file mode 100644 index 0000000..931c779 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlBeanInfo.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.bean; + +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +/** + * The ControlBeanInfo class is an abstract base class for the JavaBean BeanInfo classes generated + * to support Beehive controls. It is used to bundle helper code common across all generated + * BeanInfo classes. + */ +abstract public class ControlBeanInfo extends java.beans.SimpleBeanInfo +{ + /** + * Protected constructor that is called from generated BeanInfo subclasses. + * @param beanClass the JavaBean class for which BeanInfo is being provided. + */ + protected ControlBeanInfo(Class beanClass) + { + super(); + _beanClass = beanClass; + } + + /* + * Gets a possibly-localized string for the given input string. + * @param input This the the string that may be localizable. If it is of the form + * "%foo.bar.Baz%", then the resource Baz will be looked up in the foo.bar bundle using + * standard ResourceBundle rules for the default Locale using the control's classloader. + * If the input does not start and end with '%', or if the bundle is not located, the string + * will be returned verbatim. + * @return the string to be displayed, or the input string if no resource is found. + */ + final protected String localizeString(String input) + { + if (input == null || !input.startsWith("%") || !input.endsWith("%")) + return input; + String bundleName = input.substring(1, input.length()-1); + String resourceName = null; + int lastDot = bundleName.lastIndexOf('.'); + while (lastDot != -1 && lastDot != 0 && (lastDot+1 < bundleName.length())) + { + // move last element from bundle to resource. foo.bar.Baz could be the + // Baz property in foo.bar, or the bar.Baz property in foo. + if (resourceName == null) + resourceName = bundleName.substring(lastDot+1); + else + resourceName = bundleName.substring(lastDot+1) + '.' + resourceName; + bundleName = bundleName.substring(0, lastDot); + + try + { + ResourceBundle bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault(), + _beanClass.getClassLoader()); + if (bundle != null) + { + String lookup = bundle.getString(resourceName); + if (lookup != null) + return lookup; + } + } + catch (MissingResourceException mre) + { } + + lastDot = bundleName.lastIndexOf('.'); + } + + return input; + } + + Class _beanClass; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlContainerContext.java b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlContainerContext.java new file mode 100644 index 0000000..715ee1d --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlContainerContext.java @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.bean; + +import java.lang.reflect.InvocationTargetException; +import java.util.Stack; + +import org.apache.beehive.controls.api.context.ControlHandle; +import org.apache.beehive.controls.api.context.ControlThreadContext; +import org.apache.beehive.controls.api.context.ResourceContext; +import org.apache.beehive.controls.api.events.EventDispatcher; +import org.apache.beehive.controls.api.events.EventRef; + +/** + * The ControlContainerContext class provides a base class implementation for external containers + * of ControlBeans. It provides additional services, such as: + * + * - defines a contextual service provider for the ResourceManager interface + * - defines a simplified contract for the external container to interact with resource + * management (beginContext/endContext) + */ +public class ControlContainerContext + extends ControlBeanContext + implements EventDispatcher, org.apache.beehive.controls.api.context.ControlContainerContext +{ + public ControlContainerContext() + { + super(null); + } + + protected ControlContainerContext(BeanContextServicesFactory beanContextServicesFactory) { + super(null, beanContextServicesFactory); + } + + /** + * Defines the beginning of a new control container execution context. + */ + public void beginContext() + { + ControlThreadContext.beginContext(this); + } + + /** + * Ends the current control container execution context + */ + public void endContext() + { + try + { + // + // Release all resources associated with the current execution context. + // + releaseResources(); + } + finally + { + ControlThreadContext.endContext(this); + } + } + + /** + * Called by BeanContextSupport superclass during construction and deserialization to + * initialize subclass transient state + */ + public void initialize() + { + super.initialize(); + + // + // Register the ResourceContext provider on all new ControlContainerContext instances. + // + addService(org.apache.beehive.controls.api.context.ResourceContext.class, + ResourceContextImpl.getProvider()); + } + + /** + * Adds a new managed ResourceContext to the ControlContainerContext. This method + * is used to register a resource context that has just acquired resources + * @param resourceContext the ResourceContext service that has acquired resources + * @param bean the acquiring ControlBean. Unused by the base implementation, but + * available so subclassed containers can have access to the bean. + */ + protected synchronized void addResourceContext(ResourceContext resourceContext, ControlBean bean) + { + if (!resourceContext.hasResources()) + _resourceContexts.push(resourceContext); + } + + /** + * Removes a managed ResourceContext from the ControlContainerContext. This method + * is used to unregister a resource context that has already acquired resources + * @param resourceContext the ResourceContext service to be removed + * @param bean the acquiring ControlBean. Unused by the base implementation, but + * available so subclassed containers can have access to the bean. + */ + protected synchronized void removeResourceContext(ResourceContext resourceContext, ControlBean bean) + { + // + // Ignore removal requests received within the context of global cleanup. The + // stack is already being popped, so these are just requests for resources that + // already have in-flight removal taking place. + // + if (!_releasingAll && resourceContext.hasResources()) + _resourceContexts.remove(resourceContext); + } + + /** + * Releases all ResourceContexts associated with the current ControlContainerContext. + * This method is called by the associated container whenever all managed ResourceContexts + * that have acquired resources should release them. + */ + protected synchronized void releaseResources() + { + // Set the local flag indicating global resource release is occuring + _releasingAll = true; + + // + // Iterate through the list of acquired ResourceContexts and release them + // + while (!_resourceContexts.empty()) + { + ResourceContext resourceContext = _resourceContexts.pop(); + resourceContext.release(); + } + + // Clear the local flag indicating global resource release is occuring + _releasingAll = false; + } + + /** + * Dispatch an operation or an event to a bean within this container bean context. + * @param handle the control handle identifying the target bean + * @param event the event to be invoked on the target bean + * @param args the arguments to be passed to the target method invocation + */ + public Object dispatchEvent(ControlHandle handle, EventRef event, Object [] args) + throws IllegalArgumentException, IllegalAccessException, InvocationTargetException + { + ControlBean bean = getBean(handle.getControlID()); + if (bean == null) + throw new IllegalArgumentException("Invalid bean ID: " + handle.getControlID()); + + return bean.dispatchEvent(event, args); + } + + /** + * Returns a ControlHandle to the component containing the control. This handle can be + * used to dispatch events and operations to a control instance. This method will return + * null if the containing component does not support direct dispatch. + * + * @param bean the target control bean + */ + public ControlHandle getControlHandle(org.apache.beehive.controls.api.bean.ControlBean bean) + { + // + // The base implementation doesn't support dispatch. Containers should override + // and return a valid service handle that does component-specific dispatch. + // + return null; + } + + /** + * Returns true if this container guarantees single-threaded behaviour. By default, top-level + * containers are assumed to NOT guarantee this; specific container implementations (for example, + * for EJB containers) should override this appropriately. + */ + public boolean isSingleThreadedContainer() + { + return false; + } + + boolean _releasingAll; + Stack _resourceContexts = new Stack(); +} \ No newline at end of file diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlUtils.java b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlUtils.java new file mode 100644 index 0000000..94c6509 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ControlUtils.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.bean; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.bean.ControlExtension; +import org.apache.beehive.controls.api.ControlException; + +/** + * Utilities used by the Controls runtime. + */ +public final class ControlUtils { + + private ControlUtils() {} + + /** + * Implements the default control implementation binding algorithm ( + "Impl" ). See + * documentation for the org.apache.beehive.controls.api.bean.ControlInterface annotation. + * + * @param implBinding the value of the defaultBinding attribute returned from a ControlInterface annotation + * @param controlClass the actual name of the interface decorated by the ControlInterface annotation + * @return the resolved defaultBinding value + */ + public static String resolveDefaultBinding( String implBinding, String controlClass ) + { + int intfIndex = implBinding.indexOf(ControlInterface.INTERFACE_NAME); + if (intfIndex >= 0) + { + implBinding = implBinding.substring(0,intfIndex) + controlClass + + implBinding.substring(intfIndex + + ControlInterface.INTERFACE_NAME.length()); + } + return implBinding; + } + + /** + * Returns the default binding based entirely upon annotations or naming conventions. + * @param controlIntf the control interface class + * @return the class name of the default control implementation binding + */ + static String getDefaultControlBinding(Class controlIntf) + { + controlIntf = getMostDerivedInterface(controlIntf); + + ControlInterface intfAnnot = + (ControlInterface)controlIntf.getAnnotation(ControlInterface.class); + String implBinding = intfAnnot.defaultBinding(); + implBinding = resolveDefaultBinding( implBinding, controlIntf.getName() ); + + return implBinding; + } + + /** + * Computes the most derived ControlInterface for the specified ControlExtension. + * @param controlIntf + * @return the most derived ControlInterface + */ + static Class getMostDerivedInterface(Class controlIntf) + { + while (controlIntf.isAnnotationPresent(ControlExtension.class)) + { + Class [] intfs = controlIntf.getInterfaces(); + boolean found = false; + for (int i = 0; i < intfs.length; i++) + { + if (intfs[i].isAnnotationPresent(ControlExtension.class) || + intfs[i].isAnnotationPresent(ControlInterface.class)) + { + controlIntf = intfs[i]; + found = true; + break; + } + } + if (!found) + { + throw new ControlException("Can't find base control interface for " + controlIntf); + } + } + return controlIntf; + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/bean/DefaultControlBeanContextFactory.java b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/DefaultControlBeanContextFactory.java new file mode 100644 index 0000000..e075b36 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/DefaultControlBeanContextFactory.java @@ -0,0 +1,57 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + $Header:$ +*/ +package org.apache.beehive.controls.runtime.bean; + +import org.apache.beehive.controls.api.bean.ControlBean; +import org.apache.beehive.controls.api.context.ControlBeanContext; +import org.apache.beehive.controls.spi.context.ControlBeanContextFactory; + +/** + * Default implementation of the {@link ControlBeanContextFactory} that simply creates an instance of a + * {@link ControlBeanContext} given the current {@link ControlBean}. + */ +/* package */ class DefaultControlBeanContextFactory + implements ControlBeanContextFactory { + + /** + * Create the {@link ControlBeanContext} for the {@link ControlBean}. + * @param controlBean + * @return the {@link ControlBeanContext} + */ + public ControlBeanContext instantiate(ControlBean controlBean) { + if(!(controlBean instanceof org.apache.beehive.controls.runtime.bean.ControlBean)) + throw new IllegalArgumentException("The ControlBean of type \"" + + controlBean.getClass().getName() + + "\" is unsupported. The ControlBean must extend " + + org.apache.beehive.controls.runtime.bean.ControlBean.class.getName()); + + /* + The provided ControlBean is a "api.bean.ControlBean"; this factory implementation only creates + ControlBeanContext implementations for "runtime.bean.ControlBean" types. Ensuare that this is + of that type. + */ + org.apache.beehive.controls.runtime.bean.ControlBean runtimeControlBean = + (org.apache.beehive.controls.runtime.bean.ControlBean)controlBean; + + /* + Create a simple new ControlBeanContext. + */ + return new org.apache.beehive.controls.runtime.bean.ControlBeanContext(runtimeControlBean); + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/bean/EventAdaptor.java b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/EventAdaptor.java new file mode 100644 index 0000000..2c6d481 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/EventAdaptor.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.bean; + +/** + * The EventAdaptor interface will be implemented by all code-generated event adaptor classes + * used to deliver control events to clients. + */ +public interface EventAdaptor +{ + /** + * Returns the client instance that will be the target of the event. + */ + Object getClient(); +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/bean/EventNotifier.java b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/EventNotifier.java new file mode 100644 index 0000000..e48ac42 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/EventNotifier.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.bean; + +import java.util.Iterator; +import java.util.LinkedList; + +/** + * The EventNotifier class provides basic callback listener management and event delivery + * services for ControlBean instances. + */ +public class EventNotifier implements java.io.Serializable +{ + /** + * Adds a new callback event listener for this EventNotifier + */ + synchronized public void addListener(Object listener) + { + _listeners.add(listener); + } + + /** + * Remove an existing callback event listener for this EventNotifier + */ + synchronized public void removeListener(Object listener) + { + if (!_listeners.contains(listener)) + throw new IllegalStateException("Invalid listener, not currently registered"); + + _listeners.remove(listener); + } + + /** + * Returns an iterator over the full set of listeners + */ + public Iterator listenerIterator() + { + return _listeners.iterator(); + } + + /** + * Returns the number of registered listeners + */ + public int getListenerCount() + { + return _listeners.size(); + } + + /** + * Returns the listener list in array form + */ + public void getListeners(Object [] listeners) + { + _listeners.toArray(listeners); + } + + private LinkedList _listeners = new LinkedList(); +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ImplInitializer.java b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ImplInitializer.java new file mode 100644 index 0000000..3323258 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ImplInitializer.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.bean; + +/** + * The ImplInitializer class is an abstract base class that all generated Control + * initalization classes will extend. It provides common utilities and supporting code + * for initialization, and has a shared package relationship with the base ControlBean + * class providing access to internals not available in a more general context. + */ +abstract public class ImplInitializer +{ + /** + * Initializes a new ControlImplementation instance associated with the specified bean. + */ + public void initialize(ControlBean bean, Object target) + { + initServices(bean, target); + initControls(bean, target); + initEventProxies(bean, target); + } + + /** + * Initializes all contextual services required by the target implementation instance. + * The default initializer implementation is a noop, but will be overridden by + * generated subclasses that contain contextual services. + */ + public void initServices(ControlBean bean, Object target) { }; + + /** + * Resets all contextual services on the target implementation instance to null. + * The default initializer implementation is a noop, but will be overridden by + * generated subclasses that contain contextual services. + */ + public void resetServices(ControlBean bean, Object target) { }; + + /** + * Initializes all nested controls required by the target implementation instance. + * The default initializer implementation is a noop, but will be overridden by + * generated subclasses that contain nested controls + */ + public void initControls(ControlBean bean, Object target) { }; + + /** + * Initializes all event proxies required by the target implementation instance. + * The default initializer implementation is a noop, but will be overridden by + * generated subclasses that contain event proxies + */ + public void initEventProxies(ControlBean bean, Object target) { }; + + + /** + * Returns the ControlBean event notifier for the specified eventSet + */ + public Object getEventNotifier(ControlBean bean, Class eventSet) + { + return bean.getEventNotifier(eventSet); + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ImplPersistenceDelegate.java b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ImplPersistenceDelegate.java new file mode 100644 index 0000000..054a973 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ImplPersistenceDelegate.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.bean; + +import java.beans.BeanInfo; +import java.beans.DefaultPersistenceDelegate; +import java.beans.Encoder; +import java.beans.Expression; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PersistenceDelegate; +import java.beans.PropertyDescriptor; +import java.beans.Statement; +import java.beans.XMLEncoder; +import java.util.Set; + +import org.apache.beehive.controls.api.ControlException; + +/** + * The ImplPersistenceDelegate class supports the XML persistance of Control Implementation + * instances by implementing the java.beans.PersistenceDelegate API, and overriding + * the default persistance algorithm based upon the runtime structure for Controls. + *

+ */ +public class ImplPersistenceDelegate extends DefaultPersistenceDelegate +{ + /** + * PersistenceDelegate.instantiate() + */ + protected Expression instantiate(Object oldInstance, Encoder out) + { + // + // An implementation instance is actually constructed at decode time by calling + // ControlBean.ensureControl on the parent bean. This will create a new impl + // instance and run the impl initializer on it. + // + return new Expression(((XMLEncoder)out).getOwner(), "ensureControl", null); + } + + /** + * PersistenceDelegate.initialize() + */ + protected void initialize(Class type, Object oldInstance, Object newInstance, Encoder out) + { + super.initialize(type, oldInstance, newInstance, out); + } + + /** + * PersistenceDelegate.writeObject() + */ + public void writeObject(Object oldInstance, Encoder out) + { + super.writeObject(oldInstance, out); + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/bean/InterceptorUtils.java b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/InterceptorUtils.java new file mode 100644 index 0000000..8b29d5a --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/InterceptorUtils.java @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.bean; + +import java.util.ArrayList; +import java.util.Set; +import java.util.HashSet; +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.IOException; + +/** + * Class used to support prioritizing interceptors on methods of a {@link ControlBean}. + */ +public final class InterceptorUtils { + + private InterceptorUtils() {} + + /** + * Filename that contains ordering priority for controls interceptor services. + * Each line in the file is a fully qualified interface name. The first line in the file + * is highest priority. + */ + public static final String INTERCEPTOR_CONFIG_FILE = "controls-interceptors.config"; + + // todo: this interceptor priority list should be stored by ClassLoader instead of shared between them + /** + * List that keeps track of the interceptors in their priority order. + */ + private static ArrayList _interceptorPriorities; + + /** + * Applies externally defined (via {@link #INTERCEPTOR_CONFIG_FILE}) ordering priority for + * controls interceptor services. + * + * @param interceptors + * @return String[] + */ + public static String[] prioritizeInterceptors( String [] interceptors ) + { + if ( interceptors == null ) + return null; + + // Read external configuration to obtain desired prioritization. + if ( _interceptorPriorities == null ) + { + // Only attempt to read the external configuration once; bounce the VM if you + // want to try again. + _interceptorPriorities = new ArrayList(); + BufferedReader in = null; + try + { + InputStream configFileStream = + ControlBeanContext.class.getClassLoader().getResourceAsStream( INTERCEPTOR_CONFIG_FILE ); + + if ( configFileStream != null ) + { + in = new BufferedReader(new InputStreamReader(configFileStream)); + String str; + while ((str = in.readLine()) != null) + _interceptorPriorities.add(str); + } + } + catch (IOException e) + { + // ignore + } + finally + { + try { + if (in != null) + in.close(); + } + catch ( IOException ie ) { /* ignore */ } + } + } + + // Put input list of interceptors into a Set for easy lookup + Set input = new HashSet(); + for ( String ii : interceptors ) + input.add( ii ); + + // Scan through priorities list, building a prioritized list + ArrayList prioritized = new ArrayList(interceptors.length); + for ( String p : _interceptorPriorities ) + { + if ( input.contains(p) ) + { + input.remove(p); + prioritized.add(p); + } + } + + // Anything still left in the input set did not have a priority associated with it, + // so they just go at the end in arbitrary order. + for ( String p : input ) + prioritized.add(p); + + return prioritized.toArray(new String[prioritized.size()]); + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/bean/InvokeListener.java b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/InvokeListener.java new file mode 100644 index 0000000..c09ba75 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/InvokeListener.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.bean; + +import java.lang.reflect.Method; + +/** + * The InvokeListener interface can be implemented by contextual services or helper + * classes associated with a ControlBean that want pre/post hook notifications of + * invocations occuring on a ControlBean. + * + * Hooking is "read only". An InvokeListener cannot modify the invoked method, + * arguments, return value or thrown exceptions in any way. + */ +public interface InvokeListener extends java.util.EventListener +{ + /** + * Called just prior to invoking an operation or callback event on a control. + */ + public void preInvoke(Method m, Object [] args); + + /** + * Called just after inovcation of an operation or callback event on a control + */ + public void postInvoke(Object retval, Throwable t); +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ResourceContextImpl.java b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ResourceContextImpl.java new file mode 100644 index 0000000..e0b0706 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/ResourceContextImpl.java @@ -0,0 +1,172 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.bean; + +import java.beans.beancontext.BeanContextServiceProvider; +import java.beans.beancontext.BeanContextServices; +import java.lang.reflect.Method; +import java.util.Iterator; +import java.util.Vector; + +import org.apache.beehive.controls.api.context.ResourceContext; + +/** + * The ResourceContextImpl class provides an implementation of the ResourceContext service, + * as well as a simple singleton provider that can be used to obtain new instances. + */ +public class ResourceContextImpl implements ResourceContext, InvokeListener +{ + /** + * The ResourceContextProvider inner class acts as a single BeanContext service + * provider for the ResourceContext service class. + */ + private static class ResourceContextProvider + implements BeanContextServiceProvider { + + // + // BeanContextServiceProvider.getService() + // + public Object getService(BeanContextServices bcs, Object requestor, Class serviceClass, Object serviceSelector) + { + // + // There is an implied contract between ControlContainerContext and ControlBean + // classes required to implement the resource management contract. This cannot + // be supported for any generic BeanContextChild class. + // + if (requestor instanceof ControlBean) + { + return new ResourceContextImpl((ControlContainerContext)bcs, (ControlBean)requestor); + } + + return null; + } + + // + // BeanContextServiceProvider.releaseService() + // + public void releaseService(BeanContextServices bcs, Object requestor, Object service) + { + return; // Should not happen, service is never unregistered + } + + // + // BeanContextServiceProvider.getContextServiceSelectors() + // + public Iterator getCurrentServiceSelectors(BeanContextServices bcs, Class serviceClass) + { + return null; // no selectors + } + } + + /** + * A singleton instance of the ResourceContextProvider class is what will be registered + * on all ControlContainerContext instances. The provider can be a singleton because it is + * completely stateless and thread-safe. + */ + static private ResourceContextProvider _theProvider = new ResourceContextProvider(); + + /** + * Returns the ResourceContextProvider used to create new ResourceContext instances + */ + static /* package */ ResourceContextProvider getProvider() { return _theProvider; } + + /** + * Constructs a new ResourceContext service implementation to manage resources for + * a target ControlBean within a specific ControlContainerContext + */ + public ResourceContextImpl(ControlContainerContext containerContext, ControlBean bean) + { + _containerContext = containerContext; + _bean = bean; + + // + // Register to receive invocation notifications from the target bean + // + _bean.addInvokeListener(this); + } + + /** + * Implements the InvokeListener.preInvoke method. This hook will be called before the + * managed beans' operations are invoked + */ + public void preInvoke(Method m, Object [] args) + { + if (!_hasAcquired) + acquire(); + } + + /** + * Implements the InvokeListener.postInvoke method. + */ + public void postInvoke(Object retval, Throwable t) {} + + // ResourceContext.acquire() + public void acquire() + { + if (_hasAcquired) + return; + + // Deliver the onAcquire event to registered listeners + for (ResourceEvents resourceListener : _listeners) + resourceListener.onAcquire(); + + // Register this ResourceContext with associated container context + _containerContext.addResourceContext(this, _bean); + + // Set the flag to indicate resources have been acquired. + _hasAcquired = true; + } + + // ResourceContext.release() + public void release() + { + if (!_hasAcquired) + return; + + // Deliver the onRelease event to the registered listeners + for (ResourceEvents resourceListener : _listeners) + resourceListener.onRelease(); + + // Unregister this ResourceContext with associated container context + _containerContext.removeResourceContext(this, _bean); + + // Reset the flag to indicate resources have been released. + _hasAcquired = false; + } + + // ResourceContext.hasResources() + public boolean hasResources() { return _hasAcquired; } + + // ResourceContext.addResourceEventsListener + public void addResourceEventsListener(ResourceEvents resourceListener) + { + _listeners.add(resourceListener); + } + + // ResourceContext.removeResourceEventsListener + public void removeResourceEventsListener(ResourceEvents resourceListener) + { + _listeners.remove(resourceListener); + } + + private Vector _listeners = new Vector(); + private boolean _hasAcquired = false; + private ControlContainerContext _containerContext; + private ControlBean _bean; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/bean/UnicastEventNotifier.java b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/UnicastEventNotifier.java new file mode 100644 index 0000000..747a045 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/UnicastEventNotifier.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.bean; + +import java.util.TooManyListenersException; + +/** + * The UnicastEventNotifier class provides basic callback listener management and event delivery + * services for unicast EventSets on ControlBean instances. + */ +public class UnicastEventNotifier implements java.io.Serializable +{ + /** + * Adds a new callback event listener for this EventNotifier. This method will also + * perform a check to see if there is already a register listener, and throw a + * java.util.TooManyListenersException if there is already a registered + * listener. + */ + synchronized public void addListener(Object listener) throws TooManyListenersException + { + if (_listener != null) + throw new TooManyListenersException("Callback listener is already registered"); + _listener = listener; + } + + /** + * Remove an existing callback event listener for this EventNotifier + */ + synchronized public void removeListener(Object listener) + { + if (_listener != listener) + { + throw new IllegalStateException("Invalid listener, not currently registered"); + } + _listener = null; + } + + /** + * Returns the listener associated with this EventNotifier + */ + public Object getListener() + { + return _listener; + } + + /** + * Returns the number of registered listeners + */ + public int getListenerCount() + { + return (_listener != null) ? 1 : 0; + } + + /** + * Returns the listener list in array form + */ + public void getListeners(Object [] listeners) + { + if (_listener != null) + listeners[0] = _listener; + } + + private Object _listener; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/bean/WebContextFactoryProvider.java b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/WebContextFactoryProvider.java new file mode 100644 index 0000000..cf96e09 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/bean/WebContextFactoryProvider.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.bean; + +import java.beans.beancontext.BeanContextServices; +import java.beans.beancontext.BeanContextServiceProvider; +import java.util.Iterator; +import java.util.Collections; + +import org.apache.beehive.controls.spi.context.ControlBeanContextFactory; +import org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport; + +/** + *

+ * This class acts as a ControlBeanContextFactoryProvider that exposes this factory as a contextual service + * from inside of a ControlBeanContext. + *

+ *

+ * Note: This class, the service provider, and the contextual service it provides are considerd an implementation + * detail and should not be used from user code. + *

+ */ +public class WebContextFactoryProvider + implements BeanContextServiceProvider { + + private static final WebContextFactoryProvider theProvider = new WebContextFactoryProvider(); + private static final WebControlBeanContextFactory theFactory = new WebControlBeanContextFactory(); + + public static final ControlBeanContext.BeanContextServicesFactory WEB_CONTEXT_BCS_FACTORY = + new WebContextBeanContextServicesFactory(); + + public static BeanContextServiceProvider getProvider() { + return theProvider; + } + + private WebContextFactoryProvider() { + } + + public Object getService(BeanContextServices bcs, Object requestor, Class serviceClass, Object serviceSelector) { + return theFactory; + } + + public void releaseService(BeanContextServices bcs, Object requestor, Object service) { + } + + public Iterator getCurrentServiceSelectors(BeanContextServices bcs, Class serviceClass) { + return Collections.EMPTY_LIST.iterator(); + } + + /** + *

+ * {@link ControlBeanContextFactory} implementation that provides a {@link ControlBeanContext} object + * used for web-tier control containment. + *

+ *

+ * Note: This factory is considerd an implementation detail and should not be referenced from user code. + *

+ */ + /*package*/ static class WebControlBeanContextFactory + implements ControlBeanContextFactory { + + public org.apache.beehive.controls.api.context.ControlBeanContext instantiate + (org.apache.beehive.controls.api.bean.ControlBean controlBean) { + + if(!(controlBean instanceof ControlBean)) + throw new IllegalArgumentException("The ControlBean of type \"" + + controlBean.getClass().getName() + + "\" is unsupported. The ControlBean must extend " + + ControlBean.class.getName()); + + ControlBean runtimeControlBean = (ControlBean)controlBean; + + return new ControlBeanContext(runtimeControlBean, WEB_CONTEXT_BCS_FACTORY); + } + } + + /*package*/ static class WebContextBeanContextServicesFactory + extends ControlBeanContext.BeanContextServicesFactory { + protected BeanContextServices instantiate(ControlBeanContext controlBeanContext) { + return new ControlBeanContextServicesSupport(controlBeanContext); + + /* The java implementation of the BeanContext support classes, + not currently used by Beehive due to performance issues. + + return new java.beans.beancontext.BeanContextServicesSupport(controlBeanContext); + */ + } + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptAnnotationHelper.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptAnnotationHelper.java new file mode 100644 index 0000000..c0cd889 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptAnnotationHelper.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +import java.util.HashMap; +import java.util.Map; + +import com.sun.mirror.declaration.AnnotationMirror; +import com.sun.mirror.declaration.AnnotationTypeElementDeclaration; +import com.sun.mirror.declaration.AnnotationValue; + +/** + * The AptAnnotationHelper class is a helper class that aids in the reading of annotation + * values using APT metadata + */ +public class AptAnnotationHelper +{ + /** + * Initialize a new helper instance based upon a specific annotation declaration. + * @param annot The annotation value declaration + */ + public AptAnnotationHelper(AnnotationMirror annot) + { + // + // Build maps from the element name to its declaration and values + // + Map elemValues = + annot.getElementValues(); + + for (AnnotationTypeElementDeclaration ated : elemValues.keySet()) + { + _elementMap.put(ated.getSimpleName(), ated); + _valueMap.put(ated.getSimpleName(), elemValues.get(ated)); + } + }; + + /** + * Returns the AnnotationTypeElementDeclaration for a particular element + */ + public AnnotationTypeElementDeclaration getElementDeclaration(String elemName) + { + if (_elementMap.containsKey(elemName)) + return _elementMap.get(elemName); + return null; + } + + /** + * Returns the value of a particular element as a String + */ + public String getStringValue(String elemName) + { + if (_valueMap.containsKey(elemName)) + return _valueMap.get(elemName).toString(); + return null; + } + + /** + * Returns the value of a particular element as an Object + */ + public Object getObjectValue(String elemName) + { + if (_valueMap.containsKey(elemName)) + return _valueMap.get(elemName).getValue(); + return null; + } + + private HashMap _elementMap = + new HashMap(); + private HashMap _valueMap = + new HashMap(); +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptClientField.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptClientField.java new file mode 100644 index 0000000..df8923b --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptClientField.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +import java.util.ArrayList; + +import com.sun.mirror.apt.AnnotationProcessorEnvironment; +import com.sun.mirror.declaration.FieldDeclaration; + +/** + * The AptClientField class describes a reference to a client callback notifier within an + * AptControlImplementation class. + */ +public class AptClientField extends AptField +{ + /** + * Base constructor, protected so only a custom subclass can invoke + * @param controlImpl the declaring AptControlImplementation + */ + public AptClientField(AptControlImplementation controlImpl, FieldDeclaration fieldDecl) + { + super(fieldDecl); + _controlImpl = controlImpl; + }; + + private AptControlImplementation _controlImpl; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptContextField.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptContextField.java new file mode 100644 index 0000000..211ca5f --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptContextField.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +import com.sun.mirror.declaration.FieldDeclaration; +import com.sun.mirror.type.InterfaceType; +import com.sun.mirror.type.TypeMirror; +import org.apache.beehive.controls.runtime.generator.apt.TwoPhaseAnnotationProcessor; + +/** + * The AptContextField class contains information about a field referring to a contextual + * service with an AptControlImplementation class. + */ +public class AptContextField extends AptEventField +{ + /** + * Base constructor, protected so only a custom subclass can invoke + * @param controlImpl the declaring ControlImplementation + */ + public AptContextField(AptControlImplementation controlImpl, FieldDeclaration fieldDecl, + TwoPhaseAnnotationProcessor ap) + { + super(fieldDecl); + _controlImpl = controlImpl; + _ap = ap; + }; + + /** + * Initializes a ControlInterface associated with this context field. Because + * contextual services can expose both APIs and events, they are similar to controls. + */ + protected AptControlInterface initControlInterface() + { + TypeMirror fieldType = _fieldDecl.getType(); + if (! (fieldType instanceof InterfaceType)) + { + _ap.printError( _fieldDecl, "context.field.badinterface" ); + return null; + } + + // + // For contextual services, the declared type of the field is always the public + // interface for the contextual service. + // + return new AptControlInterface(((InterfaceType)_fieldDecl.getType()).getDeclaration(), + _ap); + } + + private AptControlImplementation _controlImpl; + private TwoPhaseAnnotationProcessor _ap; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptControlClient.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptControlClient.java new file mode 100644 index 0000000..5f974fa --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptControlClient.java @@ -0,0 +1,406 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.io.IOException; +import java.io.Writer; + +import com.sun.mirror.apt.Filer; +import com.sun.mirror.declaration.*; +import com.sun.mirror.type.TypeMirror; +import com.sun.mirror.type.ClassType; + +import org.apache.beehive.controls.api.events.EventHandler; +import org.apache.beehive.controls.runtime.generator.apt.TwoPhaseAnnotationProcessor; + +/** + * The AptControlClient class contains metadata about a class that contains nested control + * references (AptControlField). + */ +public class AptControlClient extends AptType implements Generator +{ + /** + * Constructs a new ControlClient instance where information is derived + * from APT metadata + * @param decl the annotated declaration + */ + public AptControlClient(Declaration decl, TwoPhaseAnnotationProcessor ap) + { + _ap = ap; + if (! (decl instanceof ClassDeclaration)) + { + _ap.printError( decl, "control.illegal.usage" ); + return; + } + _clientDecl = (ClassDeclaration)decl; + setDeclaration(_clientDecl); + + _controls = initControls(); + initEventAdaptors(); + + // + // Construct a new initializer class from this implementation class + // + _init = new ClientInitializer(this); + } + + /** + * Returns true if this type of client requires that nested controls have unique identifiers + */ + protected boolean needsUniqueID() + { + // + // BUGBUG: + // Pageflows need to have a more unique ID generated for fields, because multiple pageflows + // may be shared within a single ControlContainerContext, and just using the field name could + // result in collisions. A better (and less hard-wired) approach is needed than searching for + // specific annotations. Perhaps a model that enables particular client types to subclass + // AptControlClient and override getID() would be much better. + // + for (AnnotationMirror annotMirror : _clientDecl.getAnnotationMirrors()) + { + String annotType = annotMirror.getAnnotationType().toString(); + if (annotType.equals("org.apache.beehive.netui.pageflow.annotations.Jpf.Controller") || + annotType.equals("org.apache.beehive.netui.pageflow.annotations.Jpf.Backing")) + return true; + } + return false; + } + + /** + * Returns a unique ID for a control field + */ + public String getID(AptControlField control) + { + if (!needsUniqueID()) + return "\"" + control.getName() + "\""; + + return "client.getClass() + \"@\" + client.hashCode() + \"." + control.getClassName() + "." + control.getName() + "\""; + } + + /** + * Returns the list of ControlFields declared directly by this ControlImpl + */ + public ArrayList getControls() { return _controls; } + + /** + * Returns true if the implemenation class contains any nested controls + */ + public boolean hasControls() { return _controls.size() != 0; } + + /** + * Returns true if the control client needs field initialization support + */ + public boolean needsFieldInit() + { + return hasControls(); + } + + /** + * Returns the field with the specified name + */ + public AptField getField(String name) + { + for (AptField field : _controls) + if (field.getName().equals(name)) + return field; + + return null; + } + + /** + * Returns the list of fully qualified class names for types that are derived + * from this Generator + */ + public String [] getGeneratedTypes() + { + return new String [] { _init.getClassName() }; + } + + /** + * Returns the information necessary to generate a ImplInitializer from this + * ControlImplementation. + */ + public List getCheckOutput(Filer filer) throws IOException + { + return null; + } + + /** + * Returns the information necessary to generate a ClientInitializer from this control + */ + public List getGenerateOutput(Filer filer) throws IOException + { + HashMap map = new HashMap(); + map.put("client", this); // control client + map.put("init", _init); // control client initializer + + Writer writer = new IndentingWriter(filer.createSourceFile(_init.getClassName())); + GeneratorOutput genOut = + new GeneratorOutput(writer,"org/apache/beehive/controls/runtime/generator/ClientInitializer.vm", + map); + ArrayList genList = new ArrayList(1); + genList.add(genOut); + return genList; + } + + /** + * Initializes the list of ControlFields declared directly by this ControlClient + */ + protected ArrayList initControls() + { + ArrayList controls = new ArrayList(); + + if ( _clientDecl == null || _clientDecl.getFields() == null ) + return controls; + + Collection declaredFields = _clientDecl.getFields(); + for (FieldDeclaration fieldDecl : declaredFields) + { + if (fieldDecl.getAnnotation(org.apache.beehive.controls.api.bean.Control.class) != null) + controls.add(new AptControlField(this, fieldDecl, _ap)); + } + return controls; + } + + public boolean hasSuperClient() + { + return ( getSuperClientName() != null ); + } + + /** + * Returns the fully qualified classname of the closest control client in the inheritance chain. + * @return class name of the closest control client + */ + public String getSuperClientName() + { + ClassType superType = _clientDecl.getSuperclass(); + + while ( superType != null ) + { + ClassDeclaration superDecl = superType.getDeclaration(); + + Collection declaredFields = superDecl.getFields(); + for (FieldDeclaration fieldDecl : declaredFields) + { + if (fieldDecl.getAnnotation(org.apache.beehive.controls.api.bean.Control.class) != null) + { + // Found an @control annotated field, so return this class name + return superDecl.getQualifiedName(); + } + } + + superType = superType.getSuperclass(); + } + + return null; + } + + /** + * Returns the super class for this class + */ + public AptControlClient getSuperClass() { return null; } + + /** + * Initializes the list of EventAdaptors for this ControlImpl + */ + protected void initEventAdaptors() + { + if ( _clientDecl == null || _clientDecl.getMethods() == null ) + return; + + for (MethodDeclaration clientMethod : _clientDecl.getMethods()) + { + // + // Do a quick check for the presence of the EventHandler annotation on methods + // + if (clientMethod.getAnnotation(EventHandler.class) == null || + clientMethod.toString().equals("()")) + continue; + + // + // EventHandler annotations on private methods cause compilation error. + // + if (isPrivateMethod(clientMethod)) + { + _ap.printError( clientMethod, "eventhandler.method.is.private"); + continue; + } + + // + // If found, we must actually read the value using an AnnotationMirror, since it + // contains a Class element (eventSet) that cannot be loaded + // + AnnotationMirror handlerMirror = null; + for (AnnotationMirror annot : clientMethod.getAnnotationMirrors()) + { + if ( annot == null || + annot.getAnnotationType() == null || + annot.getAnnotationType().getDeclaration() == null || + annot.getAnnotationType().getDeclaration().getQualifiedName() == null ) + return; + + if ( annot.getAnnotationType().getDeclaration().getQualifiedName().equals( + "org.apache.beehive.controls.api.events.EventHandler")) + { + handlerMirror = annot; + break; + } + } + if (handlerMirror == null) + { + throw new CodeGenerationException("Unable to find EventHandler annotation on " + + clientMethod); + } + + AptAnnotationHelper handlerAnnot = new AptAnnotationHelper(handlerMirror); + + // + // Locate the EventField based upon the field element value + // + String fieldName = (String)handlerAnnot.getObjectValue("field"); + AptEventField eventField = (AptEventField)getField(fieldName); + if (eventField == null) + { + // Deliberately not issuing a diagnostic if an event handler specifies + // a field that isn't a control. Other annotation processors also + // handle event handlers, so delegate diagnostic responsibility to them. + continue; + } + + // + // Locate the EventSet based upon the eventSet element value + // + Object tmo = handlerAnnot.getObjectValue("eventSet"); + if (!(tmo instanceof TypeMirror)) + continue; + + TypeMirror tm = (TypeMirror)tmo; + String setName = tm.toString(); + + AptControlInterface controlIntf = eventField.getControlInterface(); + AptEventSet eventSet = controlIntf.getEventSet(setName); + + // todo: remove workaround once bug has been resolved. + /* Workaround JIRA issue BEEHIVE-1143, eventset name may + contain a '$' seperator between the outer class and inner class. + Should be a '.' seperator. Only applies to Eclipse APT. This + workaround is also present in AptControlImplementation.initEventAdapters + */ + if (tm.getClass().getName().startsWith("org.eclipse.")) { + setName = setName.replace('$', '.'); + } + // end of workaround + + if (eventSet == null) + { + _ap.printError( clientMethod, "eventhandler.eventset.not.found", setName ); + continue; + } + + // + // Register a new EventAdaptor for the EventSet, if none exists already + // + EventAdaptor adaptor = eventField.getEventAdaptor(eventSet); + if (adaptor == null) + { + adaptor = new EventAdaptor(eventField, eventSet); + eventField.addEventAdaptor(eventSet, adaptor); + } + + // + // Locate the EventSet method based upon the eventName element value. Once + // found, add a new AptEventHandler to the adaptor for this event. + // + boolean found = false; + String eventName = (String)handlerAnnot.getObjectValue("eventName"); + AptMethod handlerMethod = new AptMethod(clientMethod, _ap); + + // + // Will start at the currrent event set and look up through any ones it + // extends to try and find a matching event + // + while (eventSet != null) + { + for (AptEvent controlEvent : eventSet.getEvents()) + { + if (controlEvent == null || + controlEvent.getName() == null || + !controlEvent.getName().equals(eventName)) + continue; + + if ( controlEvent.getArgTypes() == null ) + continue; + + // + // BUGBUG: If the arguments are parameterized, then the event handler + // might declare a specific bound version of the type, so a direct + // comparison will fail. If parameterized, we don't validate. + // + if (controlEvent.hasParameterizedArguments() || + (controlEvent.getArgTypes().equals(handlerMethod.getArgTypes()) && + controlEvent.getReturnType().equals(handlerMethod.getReturnType()) + ) + ) + { + HashSet throwSet = new HashSet(controlEvent.getThrowsList()); + ArrayList handlerThrows = handlerMethod.getThrowsList(); + boolean throwsMatches = true; + for ( String t : handlerThrows ) + { + if ( !throwSet.contains(t) ) + throwsMatches = false; + } + + if ( !throwsMatches ) + { + _ap.printError( clientMethod, "eventhandler.throws.mismatch", handlerMethod.getName() ); + } + + adaptor.addHandler(controlEvent, + new AptEventHandler(controlEvent, clientMethod, _ap )); + found = true; + break; + } + } + if (found) // outer loop too + break; + + // + // Look up on the super event set if not found at the current level + // + eventSet = eventSet.getSuperEventSet(); + } + if (!found) + { + _ap.printError( clientMethod, "eventhandler.method.not.found", setName ); + } + } + } + + ClassDeclaration _clientDecl; + TwoPhaseAnnotationProcessor _ap; + ArrayList _controls; + ClientInitializer _init; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptControlField.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptControlField.java new file mode 100644 index 0000000..f226e50 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptControlField.java @@ -0,0 +1,181 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +import java.util.Collection; + +import com.sun.mirror.declaration.ClassDeclaration; +import com.sun.mirror.declaration.FieldDeclaration; +import com.sun.mirror.declaration.InterfaceDeclaration; +import com.sun.mirror.declaration.TypeDeclaration; +import com.sun.mirror.type.DeclaredType; +import com.sun.mirror.type.InterfaceType; +import com.sun.mirror.type.TypeMirror; +import com.sun.mirror.type.MirroredTypeException; + +import org.apache.beehive.controls.api.bean.ControlExtension; +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.api.versioning.VersionRequired; +import org.apache.beehive.controls.runtime.generator.apt.TwoPhaseAnnotationProcessor; + +/** + * The AptControlField class contains information about a field that refers to a nested control. + */ +public class AptControlField extends AptEventField +{ + /** + * Base constructor, protected so only a custom subclass can invoke + * @param controlClient the declaring AptType + */ + public AptControlField(AptType controlClient, FieldDeclaration controlDecl, + TwoPhaseAnnotationProcessor ap) + { + super( controlDecl ); + _controlClient = controlClient; + _ap = ap; + _controlBean = new ControlBean(getControlInterface()); + } + + /** + * Does this control field have a VersionRequired annotation? + * @return true if there is a version required annotation; false otherwise + */ + public boolean hasVersionRequired() + { + return ( _fieldDecl.getAnnotation( VersionRequired.class ) != null ); + } + + /** + * Initializes the ControlInterface associated with this ControlField + */ + protected AptControlInterface initControlInterface() + { + TypeMirror controlType = _fieldDecl.getType(); + if (! (controlType instanceof DeclaredType)) + { + _ap.printError( _fieldDecl, "control.field.bad.type" ); + return null; + } + + // + // The field can either be declared as the bean type or the public interface type. + // If it is the bean type, then we need to reflect to find the public interface + // type it implements. + // + TypeDeclaration typeDecl = ((DeclaredType)controlType).getDeclaration(); + InterfaceDeclaration controlIntf = null; + + // + // It is possible that the declared type is associated with a to-be-generated + // bean type. In this case, look for the associated control interface on the + // processor input list. + // + if ( typeDecl == null ) + { + String className = controlType.toString(); + String intfName = className.substring(0, className.length() - 4); + String interfaceHint = getControlInterfaceHint(); + controlIntf = (InterfaceDeclaration)_ap.getAnnotationProcessorEnvironment().getTypeDeclaration(intfName); + + if (controlIntf == null) + { + // The specified class name may not be fully qualified. In this case, the + // best we can do is look for a best fit match against the input types + for (TypeDeclaration td :_ap.getAnnotationProcessorEnvironment().getSpecifiedTypeDeclarations()) + { + // if an interface hint was provided, use it to find the control interface, + // if not provided try to find the control interface by matching simple names. + if (interfaceHint != null) { + if (td instanceof InterfaceDeclaration && + td.getQualifiedName().equals(interfaceHint)) + { + controlIntf = (InterfaceDeclaration)td; + break; + } + } + else { + if (td instanceof InterfaceDeclaration && + td.getSimpleName().equals(intfName)) + { + controlIntf = (InterfaceDeclaration)td; + break; + } + } + } + } + } + else if (typeDecl instanceof ClassDeclaration) + { + Collection implIntfs = ((ClassDeclaration)typeDecl).getSuperinterfaces(); + for (InterfaceType intfType : implIntfs) + { + InterfaceDeclaration intfDecl = intfType.getDeclaration(); + + if ( intfDecl == null ) + return null; + + if (intfDecl.getAnnotation(ControlInterface.class) != null|| + intfDecl.getAnnotation(ControlExtension.class) != null) + { + controlIntf = intfDecl; + break; + } + } + } + else if (typeDecl instanceof InterfaceDeclaration) + { + controlIntf = (InterfaceDeclaration)typeDecl; + } + + if (controlIntf == null) + { + _ap.printError( _fieldDecl, "control.field.bad.type.2" ); + return null; + } + + return new AptControlInterface(controlIntf, _ap); + } + + /** + * Get the interface hint attribute value (as a string) from the Control annotation, + * if it wasn't specified return null. + */ + private String getControlInterfaceHint() { + + Control controlAnnotation = _fieldDecl.getAnnotation(Control.class); + String interfaceHint = null; + try { + // always excepts + controlAnnotation.interfaceHint(); + } catch (MirroredTypeException mte) { + interfaceHint = ("java.lang.Object".equals(mte.getQualifiedName())) ? null : mte.getQualifiedName(); + } + return interfaceHint; + } + + /** + * Returns the ControlBean associated with this ControlField + */ + public ControlBean getControlBean() { return _controlBean; } + + private TwoPhaseAnnotationProcessor _ap; + private AptType _controlClient; + private ControlBean _controlBean; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptControlImplementation.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptControlImplementation.java new file mode 100644 index 0000000..9e7986c --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptControlImplementation.java @@ -0,0 +1,516 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +import java.io.IOException; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; + + +import com.sun.mirror.apt.Filer; +import com.sun.mirror.declaration.AnnotationMirror; +import com.sun.mirror.declaration.ClassDeclaration; +import com.sun.mirror.declaration.Declaration; +import com.sun.mirror.declaration.FieldDeclaration; +import com.sun.mirror.declaration.InterfaceDeclaration; +import com.sun.mirror.declaration.MethodDeclaration; +import com.sun.mirror.type.InterfaceType; +import com.sun.mirror.type.TypeMirror; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.events.Client; +import org.apache.beehive.controls.api.events.EventHandler; +import org.apache.beehive.controls.api.versioning.VersionSupported; +import org.apache.beehive.controls.api.versioning.Version; +import org.apache.beehive.controls.runtime.generator.apt.TwoPhaseAnnotationProcessor; + +/** + * The AptControlImplementation class provides validation and metadata management when + * processing a ControlImplementation class. + */ +public class AptControlImplementation extends AptType implements Generator +{ + /** + * Constructs a new AptControlImplementation instance where information is derived + * from APT metadata + * @param decl the annotated declaration + */ + public AptControlImplementation(Declaration decl, TwoPhaseAnnotationProcessor ap) + { + _ap = ap; + if (! (decl instanceof ClassDeclaration)) + { + _ap.printError( decl, "control.implementation.badclass" ); + return; + } + _implDecl = (ClassDeclaration)decl; + setDeclaration(_implDecl); + + _superClass = initSuperClass(); + + _contexts = initContexts(); + + _controls = initControls(); + + _clients = initClients(); + + initEventAdaptors(); + + // + // Check serializability of the implementation class. Any non-transient implementation + // must implement the java.io.Serializable marker interface to indicate that the author + // has considered serializability. + // + ControlImplementation implAnnot = _implDecl.getAnnotation(ControlImplementation.class); + if (!implAnnot.isTransient()) + { + if (!isSerializable()) + { + _ap.printError( decl, "control.implementation.unserializable" ); + } + } + + // + // Construct a new initializer class from this implementation class + // + _init = new ImplInitializer(this); + + if ( getControlInterface() == null ) + { + _ap.printError( decl, "control.implementation.missing.interface" ); + return; + } + + _versionSupported = initVersionSupported(); + + enforceVersionSupported(); + } + + /** + * Initializes the super interface that this ControlImpl extends (or null if a + * base class) + */ + private AptControlImplementation initSuperClass() + { + if ( _implDecl == null || _implDecl.getSuperclass() == null ) + return null; + + ClassDeclaration superDecl = _implDecl.getSuperclass().getDeclaration(); + if (superDecl != null && + superDecl.getAnnotation(org.apache.beehive.controls.api.bean.ControlImplementation.class) != null) + { + return new AptControlImplementation(superDecl, _ap); + } + + return null; + } + + /** + * Returns the super interface for this interface + */ + public AptControlImplementation getSuperClass() { return _superClass; } + + /** + * Initializes the list of ContextField declared directly by this ControlImpl + */ + private ArrayList initContexts() + { + ArrayList contexts = new ArrayList(); + + if ( _implDecl == null || _implDecl.getFields() == null ) + return contexts; + + Collection declaredFields = _implDecl.getFields(); + for (FieldDeclaration fieldDecl : declaredFields) + { + if (fieldDecl.getAnnotation(org.apache.beehive.controls.api.context.Context.class) != null) + contexts.add(new AptContextField(this, fieldDecl, _ap)); + } + return contexts; + } + + /** + * Returns the list of ContextFields declared directly by this ControlImplementation + */ + public ArrayList getContexts() { return _contexts; } + + /** + * Returns true if the implemenation class contains any nested services + */ + public boolean hasContexts() { return _contexts.size() != 0; } + + /** + * Initializes the list of ControlFields for this ControlImpl + */ + private ArrayList initControls() + { + ArrayList fields = new ArrayList(); + + if ( _implDecl == null || _implDecl.getFields() == null ) + return fields; + + Collection declaredFields = _implDecl.getFields(); + for (FieldDeclaration fieldDecl : declaredFields) + { + if (fieldDecl.getAnnotation(org.apache.beehive.controls.api.bean.Control.class) != null) + fields.add(new AptControlField(this, fieldDecl, _ap)); + } + return fields; + } + + /** + * Returns true if the implemenation class contains any nested controls + */ + public boolean hasControls() { return _controls.size() != 0; } + + /** + * Initializes the list of ClientFields declared directly by this ControlImpl + */ + protected ArrayList initClients() + { + ArrayList clients = new ArrayList(); + + if ( _implDecl == null || _implDecl.getFields() == null ) + return clients; + + Collection declaredFields = _implDecl.getFields(); + for (FieldDeclaration fieldDecl : declaredFields) + { + if (fieldDecl.getAnnotation(Client.class) != null) + clients.add(new AptClientField(this, fieldDecl)); + } + return clients; + } + + /** + * Returns the list of ClientFields declared directly by this ControlImplementation + */ + public ArrayList getClients() { return _clients; } + + /** + * Returns the VersionSupported annotation, if any. + */ + public VersionSupported getVersionSupported() { return _versionSupported; } + + /** + * Returns true if the implemenation class contains any nested event proxies + */ + public boolean hasClients() { return _clients.size() != 0; } + + /** + * Returns the field with the specified name + */ + public AptField getField(String name) + { + for (AptField genField : _contexts) + if (genField.getName().equals(name)) + return genField; + for (AptField genField : _clients) + if (genField.getName().equals(name)) + return genField; + + return null; + } + + public AptEventField getControlField(String name) + { + for (AptControlField controlField : _controls) + if (controlField.getName().equals(name)) + return controlField; + + return null; + } + + /** + * Returns the list of fully qualified class names for types that are derived + * from this Generator + */ + public String [] getGeneratedTypes() + { + return new String [] { _init.getClassName() }; + } + + /** + * Returns the information necessary to generate a ImplInitializer from this + * ControlImplementation. + */ + public List getCheckOutput(Filer filer) throws IOException + { + HashMap map = new HashMap(); + map.put("impl", this); // control implementation + map.put("init", _init); // control impl initializer + + Writer writer = new IndentingWriter(filer.createSourceFile(_init.getClassName())); + GeneratorOutput genOut = + new GeneratorOutput(writer,"org/apache/beehive/controls/runtime/generator/ImplInitializer.vm", + map); + ArrayList genList = new ArrayList(1); + genList.add(genOut); + return genList; + } + + /** + * Returns the list of generated files derived from this Generator during the + * generate phase of annotation processing. + */ + public List getGenerateOutput(Filer filer) throws IOException + { + return null; + } + + /** + * Returns the ControlInterface implemented by this ControlImpl. + */ + public AptControlInterface getControlInterface() + { + if ( _implDecl == null || _implDecl.getSuperinterfaces() == null ) + return null; + + Collection superInterfaces = _implDecl.getSuperinterfaces(); + for (InterfaceType intfType : superInterfaces) + { + InterfaceDeclaration intfDecl = intfType.getDeclaration(); + if (intfDecl != null && + intfDecl.getAnnotation(org.apache.beehive.controls.api.bean.ControlInterface.class) != null) + return new AptControlInterface(intfDecl, _ap); + } + + return null; + } + + /** + * Initializes the list of EventAdaptors for this ControlImpl + */ + protected void initEventAdaptors() + { + if ( _implDecl == null || _implDecl.getMethods() == null ) + return; + + for (MethodDeclaration implMethod : _implDecl.getMethods()) + { + // + // Do a quick check for the presence of the EventHandler annotation on methods + // + if (implMethod.getAnnotation(EventHandler.class) == null || + implMethod.toString().equals("()")) + continue; + + // + // EventHandler annotations on private methods cause compilation error. + // + if (isPrivateMethod(implMethod)) + { + _ap.printError(implMethod, "eventhandler.method.is.private"); + continue; + } + + // + // If found, we must actually read the value using an AnnotationMirror, since it + // contains a Class element (eventSet) that cannot be loaded + // + AnnotationMirror handlerMirror = null; + for (AnnotationMirror annot : implMethod.getAnnotationMirrors()) + { + if ( annot == null || + annot.getAnnotationType() == null || + annot.getAnnotationType().getDeclaration() == null || + annot.getAnnotationType().getDeclaration().getQualifiedName() == null ) + return; + + if ( annot.getAnnotationType().getDeclaration().getQualifiedName().equals( + "org.apache.beehive.controls.api.events.EventHandler")) + { + handlerMirror = annot; + break; + } + } + if (handlerMirror == null) + { + throw new CodeGenerationException("Unable to find EventHandler annotation on " + + implMethod); + } + + AptAnnotationHelper handlerAnnot = new AptAnnotationHelper(handlerMirror); + + // + // Locate the EventField based upon the field element value + // + String fieldName = (String)handlerAnnot.getObjectValue("field"); + AptEventField eventField = (AptEventField)getField(fieldName); + if (eventField == null) + { + // eventField == null means this field isn't interesting for the purposes + // of this processor (control impls). However, only emit an error message + // if the field isn't on a nested control + if ( getControlField(fieldName) == null ) + _ap.printError( implMethod, "eventhandler.field.not.found", fieldName ); + + continue; + } + + // + // Locate the EventSet based upon the eventSet element value + // + TypeMirror tm = (TypeMirror)( handlerAnnot.getObjectValue("eventSet") ); + if ( tm == null ) + continue; + String setName = tm.toString(); + AptControlInterface controlIntf = eventField.getControlInterface(); + + // todo: remove workaround once bug has been resolved. + /* Workaround for JIRA issue BEEHIVE-1143, eventset name may + contain a '$' seperator between the outer class and inner class. + Should be a '.' seperator. Only applies to Eclipse APT. This + workaround is also present in AptControlClient.initEventAdapters + */ + if (tm.getClass().getName().startsWith("org.eclipse.")) { + setName = setName.replace('$', '.'); + } + // end of workaround + + AptEventSet eventSet = controlIntf.getEventSet(setName); + if (eventSet == null) + { + _ap.printError( implMethod, "eventhandler.eventset.not.found", setName ); + continue; + } + + // + // Register a new EventAdaptor for the EventSet, if none exists already + // + EventAdaptor adaptor = eventField.getEventAdaptor(eventSet); + if (adaptor == null) + { + adaptor = new EventAdaptor(eventField, eventSet); + eventField.addEventAdaptor(eventSet, adaptor); + } + + // + // Locate the EventSet method based upon the eventName element value. Once + // found, add a new AptEventHandler to the adaptor for this event. + // + boolean found = false; + String eventName = (String)handlerAnnot.getObjectValue("eventName"); + AptMethod handlerMethod = new AptMethod(implMethod, _ap); + for (AptEvent controlEvent : eventSet.getEvents()) + { + if (controlEvent == null || controlEvent.getName() == null || + !controlEvent.getName().equals(eventName)) + continue; + if ( controlEvent.getArgTypes() == null ) + continue; + + // + // BUGBUG: If the arguments are parameterized, then the event handler + // might declare a specific bound version of the type, so a direct + // comparison will fail. If parameterized, we don't validate. + // + if (controlEvent.hasParameterizedArguments() || + controlEvent.getArgTypes().equals(handlerMethod.getArgTypes())) + { + adaptor.addHandler(controlEvent, + new AptEventHandler(controlEvent, implMethod, _ap)); + found = true; + break; + } + } + if (!found) + { + _ap.printError( implMethod, "eventhandler.method.not.found", setName ); + } + } + } + + private VersionSupported initVersionSupported() + { + if ( _implDecl == null ) + return null; + return _implDecl.getAnnotation(VersionSupported.class); + } + + /** + * Enforces the VersionRequired annotation for control extensions. + */ + private void enforceVersionSupported() + { + if ( _versionSupported != null ) + { + int majorSupported = _versionSupported.major(); + int minorSupported = _versionSupported.minor(); + + if ( majorSupported < 0 ) // no real version support requirement + return; + + AptControlInterface ci = getControlInterface(); + if ( ci == null ) + return; + + int majorPresent = -1; + int minorPresent = -1; + Version ciVersion = ci.getVersion(); + if ( ciVersion != null ) + { + majorPresent = ciVersion.major(); + minorPresent = ciVersion.minor(); + + if ( majorSupported >= majorPresent && + (minorSupported < 0 || minorSupported >= minorPresent) ) + { + // Version requirement is satisfied + return; + } + } + + // + // Version requirement failed + // + + _ap.printError( _implDecl, "versionsupported.failed", _implDecl.getSimpleName(), majorSupported, minorSupported, + majorPresent, minorPresent ); + } + } + + /** + * Does this control impl on one of it superclasses implement java.io.Serializable? + * @return true if this control impl or one of its superclasses implements java.io.Serializable. + */ + protected boolean isSerializable() { + + for (InterfaceType superIntf: _implDecl.getSuperinterfaces()) { + if (superIntf.toString().equals("java.io.Serializable")) { + return true; + } + } + + // check to see if the superclass is serializable + return _superClass != null && _superClass.isSerializable(); + } + + private ClassDeclaration _implDecl; + private TwoPhaseAnnotationProcessor _ap; + private AptControlImplementation _superClass; + private ArrayList _contexts; + private ArrayList _clients; + private ArrayList _controls; + private ImplInitializer _init; + private VersionSupported _versionSupported; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptControlInterface.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptControlInterface.java new file mode 100644 index 0000000..399f1e1 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptControlInterface.java @@ -0,0 +1,1149 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +import java.io.*; +import java.lang.reflect.*; +import java.lang.annotation.*; +import java.net.*; +import java.util.*; + +import com.sun.mirror.apt.Filer; +import com.sun.mirror.declaration.AnnotationMirror; +import com.sun.mirror.declaration.AnnotationTypeDeclaration; +import com.sun.mirror.declaration.Declaration; +import com.sun.mirror.declaration.InterfaceDeclaration; +import com.sun.mirror.declaration.MethodDeclaration; +import com.sun.mirror.declaration.TypeDeclaration; +import com.sun.mirror.type.DeclaredType; +import com.sun.mirror.type.InterfaceType; +import com.sun.mirror.type.MirroredTypesException; + +import org.apache.beehive.controls.api.bean.ControlChecker; +import org.apache.beehive.controls.api.bean.ControlExtension; +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.bean.ExternalPropertySets; +import org.apache.beehive.controls.api.events.EventSet; +import org.apache.beehive.controls.api.packaging.FeatureInfo; +import org.apache.beehive.controls.api.packaging.ManifestAttribute; +import org.apache.beehive.controls.api.packaging.ManifestAttributes; +import org.apache.beehive.controls.api.properties.PropertySet; +import org.apache.beehive.controls.api.versioning.Version; +import org.apache.beehive.controls.api.versioning.VersionRequired; +import org.apache.beehive.controls.runtime.generator.apt.TwoPhaseAnnotationProcessor; +import org.apache.beehive.controls.runtime.generator.apt.CheckerAnnotationProcessorEnvironmentImpl; + +/** + * The AptControlInterface provides validation and metadata management for a ControlInterface + * or ControlExtension class during APT processing. It is also used to model the interface + * to contextual services, since they parallel the conventions of control interfaces. + */ +public class AptControlInterface extends AptType implements Generator +{ + /** + * Constructs a new AptControlInterface instance where interface information is derived + * from an APT interface declaration + * @param decl the annotated Declaration + * @param ap the top-level annotation processor + */ + public AptControlInterface(Declaration decl, TwoPhaseAnnotationProcessor ap) + { + _ap = ap; + + // + // Verify that the @ControlInterface/@ControlExtension annotations are only used on an + // interface. + // Note: AptControlInterface is also used to construct the operation and event model + // for contextual services (see AptContextField). Becaue contextual sevices can actually + // be classes as well as interfaces, the test below has to be specific to the annotated + // use cases + // + if (! (decl instanceof InterfaceDeclaration) && + (decl.getAnnotation(ControlExtension.class) != null || + decl.getAnnotation(ControlInterface.class) != null)) + { + _ap.printError(decl, "control.interface.annotation.badlocation" ); + return; + } + + _intfDecl = (InterfaceDeclaration)decl; + setDeclaration(_intfDecl); + + _isExtension = initIsExtension(); + + _superClass = initSuperClass(); + + _operations = initOperations(); + + _intfProps = initIntfProperties(); + + _propertySets = initPropertySets(); + + _eventSets = initEventSets(); + + _featureInfo = initFeatureInfo(); + + _version = initVersion(); + _versionRequired = initVersionRequired(); + + // + // Construct a bean instance for this interface + // + _bean = new ControlBean(this); + + // + // Enforce VersionRequired semantics + // + enforceVersionRequired(); + + // + // Do work specific to control extensions + // + + if (isExtension()) + { + // + // If this is an control extension, run the control-author-specified + // checker class to perform additional validation. + // + check(); + } + } + + /** + * Returns the parent control interface or extension type from which the control + * interface is derived (or null, if it is at the root of the interface hierarchy) + */ + public InterfaceType getSuperType() + { + if ( _intfDecl.getSuperinterfaces() == null ) + return null; + + for (InterfaceType intfType : _intfDecl.getSuperinterfaces()) + { + InterfaceDeclaration superDecl = intfType.getDeclaration(); + if ( superDecl != null ) + { + if (superDecl.getAnnotation(ControlExtension.class) != null || + superDecl.getAnnotation(ControlInterface.class) != null) + { + _superDecl = superDecl; + return intfType; + } + } + } + + return null; + } + + /** + * Initializes the super interface that this ControlInterface extends (or sets it to null + * if a base interface) + */ + private AptControlInterface initSuperClass() + { + // + // Look for a super interface that is either a control interface or extension. + // If found, return it. + // + InterfaceType superType = getSuperType(); + if (superType == null) + { + // At this point, we're processing the root of the interface heirarchy, + // which is not permitted to be a ControlExtension (that would imply a + // ControlExtension that wasn't actually extending a ControlInterface). + if ( isExtension() ) + { + _ap.printError( _intfDecl, "control.extension.badinterface"); + } + + return null; + } + + InterfaceDeclaration superDecl = superType.getDeclaration(); + if ( superDecl != null ) + { + if (superDecl.getAnnotation(ControlExtension.class) != null || + superDecl.getAnnotation(ControlInterface.class) != null) + { + _superDecl = superDecl; + AptControlInterface superIntf = new AptControlInterface(_superDecl, _ap); + + if (!isExtension() && superIntf.isExtension()) + { + _ap.printError( _intfDecl, "control.interface.badinterface"); + } + return superIntf; + } + } + + return null; + } + + /** + * Returns the super interface for this interface + */ + public AptControlInterface getSuperClass() { return _superClass; } + + /** + * Initializes the list of operations declared by this AptControlInterface + */ + private AptMethodSet initOperations() + { + AptMethodSet operList = new AptMethodSet(); + + if ( _intfDecl == null ) + return operList; + + // + // Add the methods from the current interface and all super interfaces *other* + // than the one from which control inheritance or extension is defined. These + // exceptions are handled on the super ControlInterface (the return value + // of AptControlInterface.initSuperClass()) + // + // Do this by: + // - initially populate the check vector with the control interface + // - iterate through the check vector, examining each interface to: + // * ignore the super interface + // * add all declared interface methods to the operations list + // * add any super interfaces to the Vector (avoiding recursion) + // - the iteration continues until all superinterfaces have been processed + // + Vector checkIntfs = new Vector(); + checkIntfs.add(_intfDecl); + + for (int i = 0; i < checkIntfs.size(); i++) + { + InterfaceDeclaration intfDecl = checkIntfs.elementAt(i); + if (intfDecl.equals(_superDecl)) + continue; + + if ( intfDecl.getMethods() == null ) + continue; + + // Add all declared methods, but ignore the mystery methods + for (MethodDeclaration methodDecl : intfDecl.getMethods()) + if (!methodDecl.toString().equals("()")) + operList.add(new AptOperation(this, methodDecl, _ap)); + + if ( intfDecl.getSuperinterfaces() == null ) + continue; + + for (InterfaceType superType : intfDecl.getSuperinterfaces()) + { + InterfaceDeclaration superDecl = superType.getDeclaration(); + if (superDecl != null && !checkIntfs.contains(superDecl)) + checkIntfs.add(superDecl); + } + } + + return operList; + } + + /** + * Returns the list of ControlOperations declared directly by this AptControlInterface + */ + public Collection getOperations() { return _operations.getMethods(); } + + /** + * Returns the total number of operations for this control interface + */ + public int getOperationCount() + { + int count = _operations.size(); + if (_superClass != null) + count += _superClass.getOperationCount(); + + return count; + } + + /** + * Initializes the list of PropertySets declared or referenced by this AptControlInterface + */ + private ArrayList initPropertySets() + { + ArrayList propSets = new ArrayList(); + + if ( _intfDecl == null ) + return propSets; + + // TODO: enforce presence of prefixes when multiple property sets w/ the same + // property name exist + + // + // Add the intrinsic/base property set + // + + TypeDeclaration basePropsDecl = + _ap.getAnnotationProcessorEnvironment().getTypeDeclaration( "org.apache.beehive.controls.api.properties.BaseProperties" ); + if ( basePropsDecl != null ) + { + propSets.add( new AptPropertySet( null, basePropsDecl, _ap ) ); + } + + // + // Add external property sets + // + ExternalPropertySets extPropsAnnotation = _intfDecl.getAnnotation(ExternalPropertySets.class); + if ( extPropsAnnotation != null ) + { + if (isExtension()) + { + _ap.printError( _intfDecl, "extpropertyset.illegal.usage" ); + } + + try + { + Class[] extProps = extPropsAnnotation.value(); + } + catch ( MirroredTypesException mte ) + { + Collection extProps = mte.getQualifiedNames(); + for ( String extPropName : extProps ) + { + TypeDeclaration extPropDecl = _ap.getAnnotationProcessorEnvironment().getTypeDeclaration( extPropName ); + if ( extPropDecl != null ) + { + AptPropertySet extPropSet = new AptPropertySet( null, extPropDecl, _ap ); + propSets.add( extPropSet ); + } + else + { + _ap.printError( _intfDecl, "extpropertyset.type.not.found", extPropName ); + } + } + } + } + + // + // Add nested property sets + // + + if ( _intfDecl.getNestedTypes() == null ) + return propSets; + + for (TypeDeclaration innerDecl : _intfDecl.getNestedTypes()) + { + boolean fError = false; + if (innerDecl.getAnnotation(PropertySet.class) != null) + { + if (! (innerDecl instanceof AnnotationTypeDeclaration)) + { + _ap.printError( innerDecl, "propertyset.not.annotation.type" ); + fError = true; + } + + Retention ret = innerDecl.getAnnotation(Retention.class); + if (ret == null || ret.value() != RetentionPolicy.RUNTIME) + { + _ap.printError( innerDecl, "propertyset.missing.retention" ); + fError = true; + } + + if (isExtension()) + { + _ap.printError( innerDecl, "propertyset.illegal.usage.2" ); + fError = true; + } + + if ( !fError ) + propSets.add( + new AptPropertySet(this, (AnnotationTypeDeclaration)innerDecl, _ap)); + } + } + + // + // Detect the presence of locally declared bound or constrained properties + // Enforce property name (including prefix) uniqueness across all propertysets on this interface. + // + + Set propertyNames = new HashSet(); + + for (AptPropertySet propSet : propSets) + { + for (AptProperty prop : propSet.getProperties()) + { + if (prop.isBound()) + _hasBoundProperties = true; + + if (prop.isConstrained()) + _hasConstrainedProperties = true; + + String propName = prop.getAccessorName(); + + if ( propertyNames.contains( propName ) ) + { + _ap.printError( _intfDecl, "propertyset.duplicate.property.names", propName, propSet.getShortName() ); + } + else + { + propertyNames.add( propName ); + } + } + } + + return propSets; + } + + /** + * Returns the list of PropertySets declared directly by this AptControlInterface + */ + public Collection getPropertySets() { return _propertySets; } + + /** + * Returns the total number of properties for this control interface + */ + public int getPropertyCount() + { + int count; + if (_superClass == null) + count = 0; + else + count = _superClass.getPropertyCount(); + + for (AptPropertySet propertySet : _propertySets) { + // if a property set is set to optional and hasSetters is set to false, + // there isn't a getter or setter available for that property + if (propertySet.hasSetters() || !propertySet.isOptional()) { + count += propertySet.getProperties().size(); + } + } + + count += _intfProps.size(); + return count; + } + + /** + * Returns the list of properties defined by getter and setter methods in this control interface. + */ + public Collection getInterfaceProperties() { return _intfProps; } + + /** + * Returns true if the interface has any bound properties associated with it. + */ + public boolean hasBoundProperties() + { + if (_superClass != null && _superClass.hasBoundProperties()) + return true; + + return _hasBoundProperties; + } + + /** + * Returns true if this interface is the first interface in the inheritance hierarchy + * to declare support for bound properties. This is used to declared PropertyChangeListener + * registration methods for the bean once (and only once). + */ + public boolean addsBoundPropertySupport() + { + // + // If a super interface has already added support, then not added here + // + if (_superClass != null && _superClass.addsBoundPropertySupport()) + return false; + + return hasBoundProperties(); + } + + /** + * Returns true if any properties declared directly by this control interface are constrained + * properties. This will not reflect the attributes of properties declared on + * an interface from which this interface derives. + */ + public boolean hasConstrainedProperties() + { + if (_superClass != null && _superClass.hasConstrainedProperties()) + return true; + + return _hasConstrainedProperties; + } + + /** + * Returns true if this interface is the first interface in the inheritance hierarchy + * to declare support for constrained properties. This is used to declared + * VetoableChangeListener registration methods for the bean once (and only once). + */ + public boolean addsConstrainedPropertySupport() + { + // + // If a super interface has already added support, then not added here + // + if (_superClass != null && _superClass.addsConstrainedPropertySupport()) + return false; + + return hasConstrainedProperties(); + } + + /** + * Initializes the list of EventSets declared by this AptControlInterface + */ + private ArrayList initEventSets() + { + ArrayList eventSets = new ArrayList(); + + if ( _intfDecl == null || _intfDecl.getNestedTypes() == null ) + return eventSets; + + for (TypeDeclaration innerDecl : _intfDecl.getNestedTypes()) + { + // HACKHACK: There appear to be mirror API bugs where calling getAnnotation() + // on certain entity types will result in an endless loop. For now, work around + // this by a priori filtering... but this mechanism will drop errors that appear + // on an inapropriate type (see check below) + if (! (innerDecl instanceof InterfaceDeclaration)) + continue; + + if (innerDecl.getAnnotation(EventSet.class) != null) + { + + if (! (innerDecl instanceof InterfaceDeclaration)) + { + _ap.printError( innerDecl, "eventset.illegal.usage" ); + } + else + { + eventSets.add( + new AptEventSet(this, (InterfaceDeclaration)innerDecl, _ap)); + } + } + } + return eventSets; + } + + /** + * Returns the list of AptEventSet declared directly by this AptControlInterface + */ + public Collection getEventSets() { return _eventSets; } + + /** + * Returns the total number of operations for this control interface + */ + public int getEventSetCount() + { + int count = _eventSets.size(); + if (_superClass != null) + count += _superClass.getEventSetCount(); + + return count; + } + + /** + * Returns the number of event sets declared in this control interface. + * Does not include eventset's declared in super class(es). + */ + public int getLocalEventSetCount() + { + return _eventSets.size(); + } + + /** + * Returns the AptEventSet with the specified name + */ + public AptEventSet getEventSet(String name) + { + for (AptEventSet eventSet: getEventSets()) + if (eventSet.getClassName().equals(name)) + return eventSet; + + if (_superClass != null) + return _superClass.getEventSet(name); + + return null; + } + + /** + * Returns the FeatureInfo attributes for this control interface + */ + public FeatureInfo getFeatureInfo() { return _featureInfo; } + + /** + * Returns the list of fully qualified class names for types that are derived + * from this Generator + */ + public String [] getGeneratedTypes() + { + return new String [] { _bean.getClassName() }; + } + + /** + * Returns the Version annotation, if any. + */ + public Version getVersion() + { + return _version; + } + + /** + * Returns the VersionRequired annotation, if any. + */ + public VersionRequired getVersionRequired() + { + return _versionRequired; + } + + /** + * Returns the information necessary to generate a ControlBean from this AptControlInterface + */ + public List getCheckOutput(Filer filer) throws IOException + { + HashMap map = new HashMap(); + + map.put("intf", this); // the control interface + map.put("bean", _bean); + + ArrayList genList = new ArrayList(); + + // + // the ControlBean class + // + Writer beanWriter = new IndentingWriter(filer.createSourceFile(_bean.getClassName())); + GeneratorOutput beanSource = + new GeneratorOutput(beanWriter, + "org/apache/beehive/controls/runtime/generator/ControlBean.vm", map); + genList.add(beanSource); + + // + // the ControlBean BeanInfo class + // + Writer beanInfoWriter = new IndentingWriter(filer.createSourceFile(_bean.getBeanInfoName())); + GeneratorOutput beanInfoSource = + new GeneratorOutput(beanInfoWriter, + "org/apache/beehive/controls/runtime/generator/ControlBeanInfo.vm", map); + genList.add(beanInfoSource); + + return genList; + } + + /** + * Returns the information necessary to generate a packaging information from this + * AptControlInterface. Since this information is not needed during type validation, + * it can be delated until the generate phase. + */ + public List getGenerateOutput(Filer filer) throws IOException + { + HashMap map = new HashMap(); + + map.put("intf", this); // the control interface + map.put("bean", _bean); + + ArrayList genList = new ArrayList(); + + // + // the ControlBean MANIFEST.MF section + // + Writer manifestWriter = filer.createTextFile(Filer.Location.CLASS_TREE, _bean.getPackage(), + new File(_bean.getShortName() + ".class.manifest"), + null); + GeneratorOutput beanManifest = + new GeneratorOutput(manifestWriter, + "org/apache/beehive/controls/runtime/generator/ControlManifest.vm", + map); + genList.add(beanManifest); + + return genList; + } + + /** + * Returns true if this interface is a ControlExtension (jcx) interface, false + * otherwise. + */ + public boolean isExtension() + { + return _isExtension; + } + + /** + * Returns the most-derived interface in the inheritance chain that is annotated + * with @ControlInterface. It represents the point in the inheritance chain + * where @ControlInterface becomes @ControlExtension (i.e., anything interface derived from + * the 'most-derived interface' is annotated with @ControlExtension). May return + * null if the inheritance chain is malformed. + */ + public AptControlInterface getMostDerivedInterface() + { + // + // Walk up ControlInterface chain looking for the 1st instance annotated + // w/ @ControlInterface (as opposed to @ControlExtension) + // + // REVIEW: TBD rules for inheritance of @ControlInterface will affect this. + // Probably need to keep walking and examine each @ControlInterface in the chain. + // Run all checkers in chain? Make checkers responsible for invoking their base + // class-defined checkers? + // + + AptControlInterface ancestor = getSuperClass(); + while (ancestor != null) + { + if (!ancestor.isExtension()) + break; + + ancestor = ancestor.getSuperClass(); + } + + return ancestor; + } + + /** + * Returns a classloader that can be used to load external classes + */ + public ClassLoader getExternalClassLoader() + { + Map opts = _ap.getAnnotationProcessorEnvironment().getOptions(); + String classpath = opts.get("-classpath"); + + if ( classpath != null ) + { + String [] cpEntries = classpath.split( File.pathSeparator ); + ArrayList a = new ArrayList(); + for ( String e : cpEntries ) + { + try + { + File f = (new File(e)).getCanonicalFile(); + URL u = f.toURL(); + a.add(u); + } + catch (Exception ex) + { + System.err.println( "getExternalClassLoader(): bad cp entry=" + e ); + System.err.println( "Exception processing e=" + ex ); + } + } + URL [] urls = new URL[a.size()]; + urls = (URL[]) a.toArray(urls); + + return new URLClassLoader( urls, ControlChecker.class.getClassLoader() ); + } + + return null; + } + + // + // These are defined by the JAR spec, Name-value pair section + // + static final String alphaNum = "ABCDEFGHIJKLMNOPQRSUVWXYZabcdefghijklmnopqrstuvwyz0123456789"; + static final String headerChar = alphaNum + "_-"; + + /** + * Validates a manifest attribute. If the attribute is invalid, it will generate + * appropriate APT messager entries and return false, else return true. + */ + private boolean isValidManifestAttribute(ManifestAttribute attr) + { + String name = attr.name(); + String value = attr.value(); + boolean isValid = true; + + /* + Note, the null-check for "name" is necessary when the annotation processor is hosted inside + of an IDE where the name attribute of the ManifestAttribute metadata can be null + temporarily. In order to "keep going", just report a warning and proceed. + */ + if (name == null || name.length() == 0) + { + _ap.printError( _intfDecl, "manifestattribute.illegal.name.1" ); + isValid = false; + } + else + { + if (alphaNum.indexOf(name.charAt(0)) < 0) + { + _ap.printError( _intfDecl, "manifestattribute.illegal.name.2" ); + isValid = false; + } + for (int i = 1; i < name.length(); i++) + { + if (headerChar.indexOf(name.charAt(i)) < 0) + { + _ap.printError( _intfDecl, "manifestattribute.illegal.name.3", name.charAt(i) ); + isValid = false; + break; + } + } + } + + /* + Note, the null-check for "value" is necessary when the annotation processor is hosted inside + of an IDE where the value attribute of the ManifestAttribute metadata can be null + temporarily. In order to "keep going", just report a warning and proceed. + */ + if (value == null || value.length() == 0) + { + _ap.printError( _intfDecl, "manifestattribute.illegal.name.4" ); + isValid = false; + } + else + { + // TODO: validate string contents are valid UTF-8? + } + + return isValid; + } + + /** + * Returns the array of ManifestAttributes associated with the AptControlInterface + */ + public HashMap getManifestAttributes() + { + HashMap attributes = new HashMap(); + + if ( _intfDecl == null ) + return attributes; + + try + { + ManifestAttributes annotAttrs =_intfDecl.getAnnotation(ManifestAttributes.class); + if (annotAttrs != null) + { + ManifestAttribute [] attrs = (ManifestAttribute [])annotAttrs.value(); + for (int i = 0; i < attrs.length; i++) + { + if (isValidManifestAttribute(attrs[i])) + attributes.put(attrs[i].name(), attrs[i].value()); + } + } + ManifestAttribute annotAttr = _intfDecl.getAnnotation(ManifestAttribute.class); + if (annotAttr != null) + { + if (isValidManifestAttribute(annotAttr)) + attributes.put(annotAttr.name(), annotAttr.value()); + } + return attributes; + } + catch (Exception e) { e.printStackTrace(); return attributes; } + } + + /** + * Computes whether this interface is a ControlInterface or a ControlExtension + */ + private boolean initIsExtension() + { + if ( _intfDecl == null ) + return false; + + return _intfDecl.getAnnotation(ControlExtension.class) != null; + } + + /** + * Returns the FeatureInfo annotation for this control interface, or null if there is none. + */ + private FeatureInfo initFeatureInfo() + { + if ( _intfDecl == null ) + return null; + return _intfDecl.getAnnotation(FeatureInfo.class); + } + + /** + * Returns the Version annotation for this control interface, or null if there is none. + */ + private Version initVersion() + { + if ( _intfDecl == null ) + return null; + return _intfDecl.getAnnotation(Version.class); + } + + /** + * Returns the VersionRequired annotation for this control interface, or null if there is none. + */ + private VersionRequired initVersionRequired() + { + if ( _intfDecl == null ) + return null; + return _intfDecl.getAnnotation(VersionRequired.class); + } + + /** + * Enforces the VersionRequired annotation for control extensions. + */ + private void enforceVersionRequired() + { + if ( _versionRequired != null ) + { + if ( !isExtension() ) + { + _ap.printError( _intfDecl, "versionrequired.illegal.usage" ); + return; + } + + int majorRequired = _versionRequired.major(); + int minorRequired = _versionRequired.minor(); + + if ( majorRequired < 0 ) // no real version requirement + return; + + AptControlInterface ci = getMostDerivedInterface(); + if ( ci == null ) + return; + + int majorPresent = -1; + int minorPresent = -1; + Version ciVersion = ci._version; + if ( ciVersion != null ) + { + majorPresent = ciVersion.major(); + minorPresent = ciVersion.minor(); + + if ( majorRequired <= majorPresent && + (minorRequired < 0 || minorRequired <= minorPresent) ) + { + // Version requirement is satisfied + return; + } + } + + // + // Version requirement failed + // + _ap.printError( _intfDecl, "versionrequired.failed", _intfDecl.getSimpleName(), + majorRequired, minorRequired, majorPresent, minorPresent ); + } + } + + /** + * Runs control-specific checker class (if specified) + */ + public void check() + { + // + // Find the nearest @ControlInterface, which is where the relevant control checker + // annotation will be found. + // + + AptControlInterface mostDerived = (AptControlInterface) getMostDerivedInterface(); + if ( mostDerived == null ) + return; + + InterfaceDeclaration intfDecl = mostDerived._intfDecl; + + if ( intfDecl == null ) + return; + + AnnotationMirror controlMirror = null; + + for (AnnotationMirror annot : intfDecl.getAnnotationMirrors()) + { + if (annot.getAnnotationType().getDeclaration().getQualifiedName().equals( + "org.apache.beehive.controls.api.bean.ControlInterface")) + { + controlMirror = annot; + break; + } + } + + assert ( controlMirror != null ) : "Found a control interface that isn't annotated properly: " + intfDecl; + + AptAnnotationHelper controlAnnot = new AptAnnotationHelper(controlMirror); + + // + // Read the name of the checker class from the @ControlInterface annotation, + // dynamically load and run it. + // + + DeclaredType checkerMirror = (DeclaredType)controlAnnot.getObjectValue("checker"); + if ( checkerMirror == null ) + { + // try the deprecated 'checkerClass' attribute + checkerMirror = (DeclaredType)controlAnnot.getObjectValue("checkerClass"); + } + + if ( checkerMirror != null && checkerMirror.getDeclaration() != null ) + { + // TODO: optimize to not invoke default checker? + String checkerName = checkerMirror.toString(); + + try + { + ClassLoader loader = getExternalClassLoader(); + + Class checkerClass = loader.loadClass( checkerName ); + if ( !ControlChecker.class.isAssignableFrom(checkerClass) ) + { + _ap.printError( intfDecl, "control.interface.illegal.checker", intfDecl.getSimpleName(), checkerName ); + } + else + { + + Constructor ctor = checkerClass.getConstructor(); + + ControlChecker checker = (ControlChecker) ctor.newInstance(); + CheckerAnnotationProcessorEnvironmentImpl ape = + new CheckerAnnotationProcessorEnvironmentImpl(_ap); + checker.check( _intfDecl, ape ); + } + } + catch ( Exception e ) { + _ap.printError( intfDecl, "control.interface.checker.load.failed", intfDecl.getSimpleName(), checkerName ); + } + } + } + + /** + * Build a list of properties defined by getter/setter methods on this control interface. + */ + private ArrayList initIntfProperties() { + + HashMap intfPropMap = new HashMap(); + + Collection ops = getOperations(); + for (AptOperation op : ops) { + String opName = op.getName(); + if (!op.isPublic()) { + continue; + } + + if (isGetter(op)) { + String propertyName = getIntfPropertyName(op); + if (intfPropMap.containsKey(propertyName)) { + intfPropMap.get(propertyName).setGetterName(opName); + } + else { + intfPropMap.put(propertyName, new AptControlInterfaceProperty(propertyName, opName, null)); + } + } + else if (isSetter(op)) { + String propertyName = getIntfPropertyName(op); + if (intfPropMap.containsKey(propertyName)) { + intfPropMap.get(propertyName).setSetterName(opName); + } + else { + intfPropMap.put(propertyName, new AptControlInterfaceProperty(propertyName, null, opName)); + } + } + else if (isIsGetter(op)) { + String propertyName = getIntfPropertyName(op); + if (intfPropMap.containsKey(propertyName)) { + intfPropMap.get(propertyName).setGetterName(opName); + } + else { + intfPropMap.put(propertyName, new AptControlInterfaceProperty(propertyName, opName, null)); + } + } + } + return new ArrayList(intfPropMap.values()); + } + + /** + * Does the method have a Java Beans getter method signature. + * @param method AptMethod instance + * @return true if getter + */ + private boolean isGetter(AptMethod method) { + String methodName = method.getName(); + + if (methodName.length() < 4) + return false; + + if (!methodName.startsWith("get")) + return false; + + if (method.getArgList().length() > 0) + return false; + + if ("void".equals(method.getReturnType())) + return false; + + return true; + } + + /** + * Does the method have a Java Beans getter method signature (is varient). + * @param method AptMethod instance. + * @return true if 'is' getter. + */ + private boolean isIsGetter(AptMethod method) { + String methodName = method.getName(); + + if (methodName.length() < 3) + return false; + + if (!methodName.startsWith("is")) + return false; + + if (method.getArgList().length() > 0) + return false; + + if (!"boolean".equals(method.getReturnType())) + return false; + + return true; + } + + /** + * Does the method have a Java Beans setter method signature (is varient). + * @param method AptMethod instance. + * @return true if setter. + */ + private boolean isSetter(AptMethod method) { + String methodName = method.getName(); + + if (methodName.length() < 4) + return false; + + if (!methodName.startsWith("set")) + return false; + + String argList = method.getArgList(); + if (argList.length() == 0) + return false; + + if (argList.indexOf(',') > -1) + return false; + + if (!"void".equals(method.getReturnType())) + return false; + + return true; + } + + /** + * Generate a property name from a method name. + * @param method AptMethod instance. + * @return property name. + */ + private String getIntfPropertyName(AptMethod method) { + String opName = method.getName(); + + int prefixIdx = 3; + if (opName.startsWith("is")) + prefixIdx = 2; + + if (opName.length() == prefixIdx + 1) + return "" + Character.toLowerCase(opName.charAt(prefixIdx)); + + return Character.toLowerCase(opName.charAt(prefixIdx)) + opName.substring(prefixIdx+1); + } + + private ArrayList _intfProps; + private AptControlInterface _superClass; + private AptMethodSet _operations; + private ArrayList _propertySets; + private boolean _isExtension; // true if ControlExtension, else ControlInterface + private boolean _hasBoundProperties; + private boolean _hasConstrainedProperties; + private ArrayList _eventSets; + private ControlBean _bean; + private FeatureInfo _featureInfo; + private Version _version; + private VersionRequired _versionRequired; + private InterfaceDeclaration _intfDecl; + private InterfaceDeclaration _superDecl; + private TwoPhaseAnnotationProcessor _ap; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptControlInterfaceProperty.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptControlInterfaceProperty.java new file mode 100644 index 0000000..9d31f78 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptControlInterfaceProperty.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +/** + * A property derived from a getter/setter method of the control interface. + */ +public final class AptControlInterfaceProperty { + private final String _name; + private String _setterName; + private String _getterName; + + /** + * Constructs a new AptControlInterfaceProperty instance. + * + * @param name Property name, may not be null. + * @param getterName Getter method name, may be null. + * @param setterName Setter method name, may be null. + */ + public AptControlInterfaceProperty(String name, String getterName, String setterName) { + assert name != null; + _name = name; + _getterName = getterName; + _setterName = setterName; + } + + /** + * Set the setter method name. + * + * @param setterName + */ + protected void setSetterName(String setterName) { + _setterName = setterName; + } + + /** + * Set the getter method name. + * + * @param getterName + */ + protected void setGetterName(String getterName) { + _getterName = getterName; + } + + /** + * Get the setter method name. + * + * @return setter method name, may be null. + */ + public String getSetterName() { + return _setterName; + } + + /** + * Get the getter method name. + * + * @return getter method name, may be null. + */ + public String getGetterName() { + return _getterName; + } + + /** + * Get the property name. + * + * @return Property name. + */ + public String getName() { + return _name; + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptEvent.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptEvent.java new file mode 100644 index 0000000..eee1cc7 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptEvent.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +import com.sun.mirror.declaration.MethodDeclaration; +import com.sun.mirror.type.VoidType; + +import org.apache.beehive.controls.runtime.generator.apt.TwoPhaseAnnotationProcessor; + +/** + * The AptEvent class represents a control Property where the event attributes + * are derived using APT metadata + */ +public class AptEvent extends AptMethod +{ + /** + * Constructs a new AptEvent instance from APT metadata + * @param eventSet the declaring EventSet + * @param eventDecl the event annotation type element declaration + */ + public AptEvent(AptEventSet eventSet, MethodDeclaration eventDecl, TwoPhaseAnnotationProcessor ap) + { + super(eventDecl, ap); + _eventSet = eventSet; + _eventDecl = eventDecl; + + // + // If the event is in multicast event set but does not return 'void', then generate + // an error. Only unicast events can have a return value, to avoid ambiguity over + // which listener gets to provide the value. + // + if (!eventSet.isUnicast() && !(eventDecl.getReturnType() instanceof VoidType)) + { + ap.printError( eventDecl, "eventset.illegal.multicast" ); + } + } + + /** + * Returns the name of the static field that holds the name of this method. + */ + public String getMethodField() + { + // + // Both the event set and event name must be used for the generated field to avoid + // conflicts between same-named events in different event sets. + // + StringBuffer sb = new StringBuffer(); + sb.append("_"); + sb.append(_eventSet.getShortName()); + sb.append("_"); + sb.append(getName()); + int methodIndex = getIndex(); + if (methodIndex != -1) + sb.append(methodIndex); + sb.append("Event"); + return sb.toString(); + } + + /** + * Returns the EventSet associated with the event + */ + public AptEventSet getEventSet() { return _eventSet; } + + MethodDeclaration _eventDecl; + private AptEventSet _eventSet; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptEventField.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptEventField.java new file mode 100644 index 0000000..d5ed712 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptEventField.java @@ -0,0 +1,162 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; + +import com.sun.mirror.declaration.FieldDeclaration; +import com.sun.mirror.declaration.TypeDeclaration; +import com.sun.mirror.declaration.TypeParameterDeclaration; +import com.sun.mirror.type.DeclaredType; +import com.sun.mirror.type.ReferenceType; +import com.sun.mirror.type.TypeMirror; + +/** + * The AptEventField class represents a field type that is also an event source + */ +abstract public class AptEventField extends AptField +{ + public AptEventField(FieldDeclaration fieldDecl) + { + super(fieldDecl); + } + + /** + * Inits the ControlInterface associated with this event field. The public interface + * for controls and contextual services, and their associated events can be modeled in the + * same way. Subclasses will override this to assign an appropriate interface. + */ + abstract protected AptControlInterface initControlInterface(); + + /** + * Computes the binding from any formal type parameters declared on the control interface + * to bound types on the field declaration. + */ + private void initTypeParameterBindings() + { + // + // Get an iterator to both the declared type arguments and the original type + // declaration on the associated control interface + // + DeclaredType fieldType = (DeclaredType)_fieldDecl.getType(); + Iterator paramBoundIter = fieldType.getActualTypeArguments().iterator(); + + TypeDeclaration intfDecl = (TypeDeclaration)_controlIntf.getTypeDeclaration(); + Iterator paramDeclIter = + intfDecl.getFormalTypeParameters().iterator(); + + // + // Iterate through them in parallel, creating a mapping from the original formal + // type parameter name to the actual bound type. In parallel, also build up a + // representation of the bound type declaration. + // + // NOTE: If no type binding is done on the field declaration, then loop below + // will not execute and no mappings/empty bound decl will be the result. + // + StringBuffer sb = new StringBuffer(); + boolean isFirst = true; + while (paramBoundIter.hasNext()) + { + TypeMirror paramBound = paramBoundIter.next(); + TypeParameterDeclaration paramDecl = paramDeclIter.next(); + + // + // Save a mapping from the formal type name to the bound mirror type + // + _typeBindingMap.put(paramDecl.getSimpleName(), paramBound); + + if (isFirst) + { + sb.append("<"); + isFirst = false; + } + else + sb.append(", "); + sb.append(paramBound); + } + if (!isFirst) + sb.append(">"); + + _boundParameterDecl = sb.toString(); + } + + /** + * Returns the ControlInterface associated with this event field + */ + public AptControlInterface getControlInterface() + { + if (_controlIntf == null) + { + _controlIntf = initControlInterface(); + if (_controlIntf != null) + initTypeParameterBindings(); + } + return _controlIntf; + } + + /** + * Gets the EventAdaptor for a particular EventSet + */ + public EventAdaptor getEventAdaptor(AptEventSet eventSet) + { + return _eventAdaptors.get(eventSet); + } + + /** + * Adds a EventAdaptor for a particular EventSet + */ + public void addEventAdaptor(AptEventSet eventSet, EventAdaptor eventAdaptor) + { + assert !_eventAdaptors.containsKey(eventSet); + _eventAdaptors.put(eventSet, eventAdaptor); + } + + /** + * Returns all EventAdaptors for this EventField + */ + public Collection getEventAdaptors() + { + return _eventAdaptors.values(); + } + + /** + * Returns the bound parameter declaration for this event field + */ + public String getBoundParameters() + { + return _boundParameterDecl; + } + + /** + * Returns the formal type binding map (from name to bound type) for the event field + */ + public HashMap getTypeBindingMap() + { + return _typeBindingMap; + } + + HashMap _eventAdaptors = + new HashMap(); + + String _boundParameterDecl; + HashMap _typeBindingMap = new HashMap(); + private AptControlInterface _controlIntf; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptEventHandler.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptEventHandler.java new file mode 100644 index 0000000..7a8e44e --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptEventHandler.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +import com.sun.mirror.declaration.MethodDeclaration; + +import org.apache.beehive.controls.runtime.generator.apt.TwoPhaseAnnotationProcessor; + +/** + * The AptEventHandler class represents a control EventHandler where the event attributes + * are derived using APT metadata + */ +public class AptEventHandler extends AptMethod +{ + /** + * Constructs a new AptEventHandler instance + * from APT metadata + * @param event the handled ControlEvent + * @param handlerDecl the handler method declaration + */ + public AptEventHandler(AptEvent event, MethodDeclaration handlerDecl, TwoPhaseAnnotationProcessor ap) + { + super(handlerDecl, ap); + _event = event; + _handlerDecl = handlerDecl; + } + + /** + * Returns the ControlEvent associated with the ControlEventHandler + */ + public AptEvent getEvent() { return _event; } + + MethodDeclaration _handlerDecl; + private AptEvent _event; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptEventSet.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptEventSet.java new file mode 100644 index 0000000..24afb26 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptEventSet.java @@ -0,0 +1,352 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; + +import com.sun.mirror.declaration.InterfaceDeclaration; +import com.sun.mirror.declaration.MethodDeclaration; +import com.sun.mirror.declaration.TypeDeclaration; +import com.sun.mirror.declaration.TypeParameterDeclaration; +import com.sun.mirror.type.InterfaceType; + +import org.apache.beehive.controls.api.events.EventSet; +import org.apache.beehive.controls.api.packaging.EventSetInfo; +import org.apache.beehive.controls.runtime.generator.apt.TwoPhaseAnnotationProcessor; + +/** + * The AptEventSet class represents a control EventSet where the events + * are derived using APT metadata. + */ +public class AptEventSet extends AptType +{ + /** + * Constructs a new AptEventSet instance from APT metadata + * @param controlIntf the declaring control interface + * @param eventSet the EventSet class + * @param ap the associated AnnotationProcessor + */ + public AptEventSet(AptControlInterface controlIntf, InterfaceDeclaration eventSet, + TwoPhaseAnnotationProcessor ap) + { + _controlIntf = controlIntf; + _eventSet = eventSet; + _ap = ap; + setDeclaration(eventSet); + + EventSet eventSetAnnot = eventSet.getAnnotation(EventSet.class); + if (eventSetAnnot != null) + _unicast = eventSetAnnot.unicast(); + + // + // If an EventSet interface has formal type parameters, they must be a subset of + // the original formal type parameters declared on the original control interface. + // This is required because it must be possible to bind the types of events immediately + // upon construction of the bean... there is no opportunity to separately specify + // parameterization for the event set for the purpose of creating listeners, client + // notifiers, etc. + // + TypeDeclaration intfDecl = controlIntf.getTypeDeclaration(); + for (TypeParameterDeclaration estpd : _eventSet.getFormalTypeParameters()) + { + boolean found = false; + for (TypeParameterDeclaration citpd : intfDecl.getFormalTypeParameters()) + { + if (estpd.getSimpleName().equals(citpd.getSimpleName())) + { + found = true; + break; + } + } + if (! found) + { + // + // BUGBUG: Ideally, this would be estpd.getPosition, but this seems to return + // 0,0 for the current APT implementation, so we use the event set position + // instead. + // Once this works, the 'break' below can also be removed to present errors + // for multiple invalid parameters + // + _ap.printError( eventSet, "eventset.formal.parameter.mismatch" ); + break; + } + } + + _superEventSet = initSuperEventSet(); + + _events = initEvents(); + } + + /** + * Checks to see if this EventSet extends an EventSet declared on a parent control interface. If + * found it will return the parent EventSet, or return null if not found. + */ + public AptEventSet initSuperEventSet() + { + // This will be common, so short circuit quickly + AptControlInterface superControl = _controlIntf.getSuperClass(); + if (superControl == null) + return null; + + // Compute a hash set containing the qualified names of all super interfaces + // for this EventSet + HashSet extendNames = new HashSet(); + for (InterfaceType superType: _eventSet.getSuperinterfaces()) + { + InterfaceDeclaration superDecl = superType.getDeclaration(); + if (superDecl != null) + extendNames.add(superDecl.getQualifiedName()); + } + + // Starting with the parent of the ControlInterface declaring this EventSet, look + // for a parent interface that declares ones of these super interfaces as an event + // set + while (superControl != null) + { + Collection superEventSets = superControl.getEventSets(); + for (AptEventSet superEventSet : superEventSets) + { + if (extendNames.contains(superEventSet.getClassName())) + return superEventSet; + } + + superControl = superControl.getSuperClass(); + } + + // Nothing found, so no super event set + return null; + } + + /** + * Returns any EventSet from which this event set derives (or null if none) + */ + public AptEventSet getSuperEventSet() { return _superEventSet; } + + /** + * Initializes the list of Events associated with this EventSet + */ + protected AptMethodSet initEvents() + { + AptMethodSet events = new AptMethodSet(); + if ( _eventSet == null || _eventSet.getMethods() == null ) + return events; + + // + // Add all of the public methods directly declared and inherited from extended + // interfaces, except for the EventSet super interface (if any) + // + ArrayList intfList = new ArrayList(); + intfList.add(_eventSet); + for (int i = 0; i < intfList.size(); i++) + { + InterfaceDeclaration intfDecl = intfList.get(i); + + // + // Don't add events that are derived from a super event set. These are not added because + // this class picks a single super interface to extend from when building a hierarchy + // of callback notifiers (etc). So, the super event set that was chosen first is left out + // of the list of event methods since they're captured in superclasses in the Control's implementation + // + if (_superEventSet != null && _superEventSet.getClassName().equals(intfDecl.getQualifiedName())) + continue; + + // Add all declared methods, but ignore the mystery methods + for (MethodDeclaration methodDecl : intfDecl.getMethods()) + if (!methodDecl.toString().equals("()")) + events.add(new AptEvent(this, methodDecl, _ap)); + + // + // Add all superinterfaces of the target interface to the list + // + for (InterfaceType superType: intfDecl.getSuperinterfaces()) + { + InterfaceDeclaration superDecl = superType.getDeclaration(); + if (superDecl != null && !intfList.contains(superDecl)) + intfList.add(superDecl); + } + } + + return events; + } + + /** + * Returns the list of Events associated with this EventSet + */ + public Collection getEvents() { return _events.getMethods(); } + + /** + * Returns 'true' if the event set support only unicast (single listener) events, + * false otherwise. + */ + public boolean isUnicast() + { + return _unicast; + } + + /** + * Returns the number of Events for this EventSet and any super event set + */ + public int getEventCount() + { + int count = _events.size(); + if (_superEventSet != null) + count += _superEventSet.getEventCount(); + return count; + } + + /** + * Returns the programmatic descriptor name to be returned by the EventDescriptor + * for the event set. + */ + public String getDescriptorName() + { + // + // The javadocs for java.beans.EventSetDescriptor suggest that the programmatic name + // should start w/ a lowercase letter. So we use the unqualified event set interface + // name w/ the first character lowercased. + // + String name = getShortName(); + return Character.toLowerCase(name.charAt(0)) + name.substring(1); + } + + /** + * Returns the name of the generated notifier class for this ControlEventSet + */ + public String getNotifierClass() + { + StringBuffer sb = new StringBuffer(getShortName()); + sb.append("Notifier"); + + // + // If the event set declaration has any parameterized types, then include them on + // the notifier class as well. Currently, these can only be parameterized types + // from the outer (control interface), since there is no other mechanism for specifying + // type values at notifier construction (other than propagation from the outer type). + // + sb.append(getFormalTypeParameterNames()); + return sb.toString(); + } + + /** + * Returns any 'extends' clause that should be placed on the generated notifier class + */ + public String getNotifierExtends() + { + // + // All EventNotifiers are rooted from a common utility class, so if there is no + // super event set, then extend the utility notifier class. + // + if (_superEventSet == null) + { + if (_unicast) + return "org.apache.beehive.controls.runtime.bean.UnicastEventNotifier"; + else + return "org.apache.beehive.controls.runtime.bean.EventNotifier"; + } + + // + // Otherwise, a generated notifier will extend the notifier of any parent event set + // + return _superEventSet.getNotifierClass(); + } + + /** + * Returns the short name for this notifier's base class. + */ + public String getNotifierExtendsShortName() { + + if (_superEventSet == null) + { + if (_unicast) + return "UnicastEventNotifier"; + else + return "EventNotifier"; + } + + return _superEventSet.getNotifierClass(); + } + + /** + * Return true if this notifier extends the UnicastEventNotifier or EventNotifier base class. + */ + public boolean isExtendsNotifierBase() { + return _superEventSet == null; + } + + /** + * Returns the name of the method used to register a new EventSet listener + */ + public String getAddListenerMethod() + { + return "add" + getShortName() + "Listener"; + } + + /** + * Returns the name of the method used to register a new EventSet listener + */ + public String getRemoveListenerMethod() + { + return "remove" + getShortName() + "Listener"; + } + + /** + * Returns the name of the method used to retrieve the (unicast) EventSet listener + */ + public String getGetListenersMethod() + { + return "get" + getShortName() + "Listeners"; + } + + /** + * Returns the name of a custom-generated method to initialize MethodDescriptor bean + * info for the events in this EventSet + */ + public String getInfoInitializer() + { + return "init" + getShortName() + "Events"; + } + + /** + * Returns any EventSetInfo associated with the event set (or null if none) + */ + public EventSetInfo getEventSetInfo() + { + if ( _eventSet == null ) + return null; + + return _eventSet.getAnnotation(EventSetInfo.class); + } + + /** + * Returns the underlying APT InterfaceDeclaration associated with this event set + */ + public InterfaceDeclaration getDeclaration() + { + return _eventSet; + } + + private TwoPhaseAnnotationProcessor _ap; + private InterfaceDeclaration _eventSet; + private AptEventSet _superEventSet; + private AptControlInterface _controlIntf; + private AptMethodSet _events; + private boolean _unicast; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptField.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptField.java new file mode 100644 index 0000000..cf3992b --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptField.java @@ -0,0 +1,109 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +import java.util.Collection; + +import com.sun.mirror.declaration.FieldDeclaration; +import com.sun.mirror.declaration.Modifier; + +/** + * The AptField class is a helper class that knows how to generate useful information + * about a Field using APT metadata + */ +public class AptField +{ + AptField(FieldDeclaration fieldDecl) + { + _fieldDecl = fieldDecl; + } + + /** + * Returns the name of the method + */ + public String getName() + { + if ( _fieldDecl == null ) + return ""; + return _fieldDecl.getSimpleName(); + } + + /** + * Returns a local variable used when setting the field value + */ + public String getLocalName() { return "_" + getName(); } + + /** + * Returns the type of the field + */ + public String getType() + { + if ( _fieldDecl == null || _fieldDecl.getType() == null ) + return ""; + + return _fieldDecl.getType().toString(); + } + + /** + * Returns the class name of the field (does not include any formal type parameters + */ + public String getClassName() + { + if ( _fieldDecl == null || _fieldDecl.getType() == null ) + return ""; + + // + // This is lazily... but much easier than navigating the APT type system and just + // as effective ;) + String typeName = _fieldDecl.getType().toString(); + int formalIndex = typeName.indexOf('<'); + if (formalIndex > 0) + return typeName.substring(0, formalIndex); + return typeName; + } + + /** + * Returns the access modifier associated with the field + */ + public String getAccessModifier() + { + if ( _fieldDecl == null ) + return ""; + + Collection modifiers = _fieldDecl.getModifiers(); + if (modifiers.contains(Modifier.PRIVATE)) + return "private"; + if (modifiers.contains(Modifier.PROTECTED)) + return "protected"; + if (modifiers.contains(Modifier.PUBLIC)) + return "public"; + + return ""; + } + + /** + * Returns the name of a static local field using to refer to this Field + */ + public String getReflectField() + { + return "_" + getName() + "Field"; + } + + protected FieldDeclaration _fieldDecl; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptMethod.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptMethod.java new file mode 100644 index 0000000..2238f7c --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptMethod.java @@ -0,0 +1,464 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Collection; + +import com.sun.mirror.declaration.AnnotationMirror; +import com.sun.mirror.declaration.AnnotationTypeDeclaration; +import com.sun.mirror.declaration.MethodDeclaration; +import com.sun.mirror.declaration.ParameterDeclaration; +import com.sun.mirror.declaration.TypeParameterDeclaration; +import com.sun.mirror.declaration.Modifier; +import com.sun.mirror.type.AnnotationType; +import com.sun.mirror.type.DeclaredType; +import com.sun.mirror.type.PrimitiveType; +import com.sun.mirror.type.ReferenceType; +import com.sun.mirror.type.TypeMirror; +import com.sun.mirror.type.WildcardType; + +import org.apache.beehive.controls.api.packaging.FeatureInfo; +import org.apache.beehive.controls.runtime.generator.apt.TwoPhaseAnnotationProcessor; + + +/** + * The AptMethod class defines a base set of utility methods for acessing method attributes + * based upon an APT method declaration. + */ +public class AptMethod +{ + // + // Maps primitive type names to a default value string + // + private static HashMap _defaultReturnValues = new HashMap(); + + static final HashMap _primToObject = + new HashMap(); + + static + { + _defaultReturnValues.put("void", ""); + _defaultReturnValues.put("boolean", "false"); + _defaultReturnValues.put("char", "'\0'"); + _defaultReturnValues.put("byte", "0"); + _defaultReturnValues.put("short", "0"); + _defaultReturnValues.put("int", "0"); + _defaultReturnValues.put("long", "0"); + _defaultReturnValues.put("float", "0.0f"); + _defaultReturnValues.put("double", "0.0d"); + + _primToObject.put(PrimitiveType.Kind.BOOLEAN, "Boolean"); + _primToObject.put(PrimitiveType.Kind.BYTE, "Byte"); + _primToObject.put(PrimitiveType.Kind.CHAR, "Character"); + _primToObject.put(PrimitiveType.Kind.DOUBLE, "Double"); + _primToObject.put(PrimitiveType.Kind.FLOAT, "Float"); + _primToObject.put(PrimitiveType.Kind.INT, "Integer"); + _primToObject.put(PrimitiveType.Kind.LONG, "Long"); + _primToObject.put(PrimitiveType.Kind.SHORT, "Short"); + } + + + /** + * Constructs a new AptMethod instance associated with a specific method declaration + */ + public AptMethod(MethodDeclaration methodDecl, TwoPhaseAnnotationProcessor ap ) + { + _methodDecl = methodDecl; + _interceptorServiceNames = initInterceptorServiceNames(); + _ap = ap; + } + + /** + * Returns the name of the method + */ + public String getName() + { + if ( _methodDecl == null ) + return ""; + + return _methodDecl.getSimpleName(); + } + + /** + * Returns the argument declaration of the method, applying the bindings in the provided + * type map to any parameter types + */ + public String getArgDecl(HashMap bindingMap) + { + StringBuffer sb = new StringBuffer(); + + if ( _methodDecl.getParameters() == null ) + return ""; + + int i = 0; + for (ParameterDeclaration paramDecl : _methodDecl.getParameters()) + { + TypeMirror paramType = paramDecl.getType(); + if ( paramType == null ) + return ""; + + if (bindingMap != null && bindingMap.containsKey(paramType.toString())) + paramType = bindingMap.get(paramType.toString()); + + if (i != 0) + sb.append(", "); + + sb.append(paramType.toString()); + + sb.append(' '); + + // BUGBUG: when the MethodDeclaration is derived from Reflection, this seems + // to return 'arg0' for all arguments! + String argName = paramDecl.getSimpleName(); + if (argName.equals("arg0")) + sb.append("arg" + i); + else + sb.append(argName); + + i++; + } + return sb.toString(); + } + + /** + * Returns the arguments declarations for the method, with no formal parameter binding applied + */ + public String getArgDecl() + { + return getArgDecl(null); + } + + /** + * Returns the the method argument names, in a comma separated list + */ + public String getArgList(boolean quoteDelimit) + { + StringBuffer sb = new StringBuffer(); + int i = 0; + + if ( _methodDecl.getParameters() == null ) + return ""; + + for (ParameterDeclaration paramDecl : _methodDecl.getParameters()) + { + if (i != 0) + sb.append(", "); + + // BUGBUG: when the MethodDeclaration is derived from Reflection, this seems + // to return 'arg0' for all arguments! + String argName = paramDecl.getSimpleName(); + if (quoteDelimit) sb.append('"'); + if (argName.equals("arg0")) + sb.append("arg" + i); + else + sb.append(argName); + if (quoteDelimit) sb.append('"'); + i++; + } + return sb.toString(); + } + + /** + * Default form of getArgList, that does not quote delimit arguments + */ + public String getArgList() { return getArgList(false); } + + /** + * Returns the the method argument classes, in a comma separated list + */ + public String getArgTypes() + { + StringBuffer sb = new StringBuffer(); + int i = 0; + + if ( _methodDecl == null || _methodDecl.getParameters() == null ) + return ""; + + for (ParameterDeclaration paramDecl : _methodDecl.getParameters()) + { + if (i++ != 0) + sb.append(", "); + + TypeMirror paramType = paramDecl.getType(); + if (paramType == null) + return ""; + + // + // Use the erasure here, because we only want the raw type, not the reference + // type + // + sb.append(_ap.getAnnotationProcessorEnvironment().getTypeUtils().getErasure(paramType)); + sb.append(".class"); + } + return sb.toString(); + } + + /** + * Returns 'true' if the method uses any parameterized types as parameters + */ + public boolean hasParameterizedArguments() + { + for (ParameterDeclaration paramDecl : _methodDecl.getParameters()) + { + TypeMirror paramType = paramDecl.getType(); + if (paramType instanceof ReferenceType || paramType instanceof WildcardType) + return true; + } + return false; + } + + /** + * Returns the declaration of any generic formal types associated with the method + */ + public String getFormalTypes() + { + if ( _methodDecl == null || _methodDecl.getReturnType() == null ) + return ""; + + Collection formalTypes = _methodDecl.getFormalTypeParameters(); + if (formalTypes.size() == 0) + return ""; + + StringBuffer sb = new StringBuffer("<"); + boolean isFirst = true; + for (TypeParameterDeclaration tpd: formalTypes) + { + if (isFirst) + isFirst = false; + else + sb.append(", "); + + sb.append(tpd.toString()); + } + sb.append(">"); + return sb.toString(); + } + + /** + * Returns the method return type, applying any formal type parameter bindings defined + * by the provided map. + */ + public String getReturnType(HashMap bindingMap) + { + if ( _methodDecl == null || _methodDecl.getReturnType() == null ) + return ""; + + String returnType = _methodDecl.getReturnType().toString(); + if (bindingMap != null && bindingMap.containsKey(returnType)) + return bindingMap.get(returnType).toString(); + + return returnType; + } + + /** + * Returns the method return type with no type bindings applied + */ + public String getReturnType() + { + return getReturnType(null); + } + + /** + * Returns the throws clause of the operation + */ + public String getThrowsClause() + { + if ( _methodDecl == null || _methodDecl.getThrownTypes() == null ) + return ""; + + Collection thrownTypes = _methodDecl.getThrownTypes(); + if (thrownTypes.size() == 0) + return ""; + + StringBuffer sb = new StringBuffer("throws "); + int i = 0; + for (ReferenceType exceptType : thrownTypes) + { + if (i++ != 0) + sb.append(", "); + sb.append(exceptType.toString()); + } + return sb.toString(); + } + + /** + * Returns an ArrayList of thrown exceptions + */ + public ArrayList getThrowsList() + { + ArrayList throwsList = new ArrayList(); + + if ( _methodDecl == null || + _methodDecl.getThrownTypes() == null || + _methodDecl.getThrownTypes().size() == 0 ) + return throwsList; + + Collection thrownTypes = _methodDecl.getThrownTypes(); + for (ReferenceType exceptType : thrownTypes) + throwsList.add(exceptType.toString()); + + return throwsList; + } + + /** + * Returns a default return value string for the method, based upon bound return type + */ + public String getDefaultReturnValue(HashMap typeBinding) + { + String returnType = getReturnType(typeBinding); + if (_defaultReturnValues.containsKey(returnType)) + return _defaultReturnValues.get(returnType); + return "null"; + } + + /** + * Returns a default return value string for the method, with no type binding applied + */ + public String getDefaultReturnValue() + { + return getDefaultReturnValue(null); + } + + /** + * Returns any FeatureInfo associated with the method (or null if none) + */ + public FeatureInfo getFeatureInfo() + { + if ( _methodDecl == null ) + return null; + + return _methodDecl.getAnnotation(FeatureInfo.class); + } + + /** + * Sets the unique index value for this method. If a particular method is overloaded, + * then each associated AptMethod will have a unique index; otherwise, the index is -1. + */ + public void setIndex(int index) + { + _index = index; + } + + /** + * Returns the unique index value for this method. + */ + public int getIndex() { return _index; } + + /** + * Is this a public method? + * @return true if public + */ + protected boolean isPublic() { + Collection modifiers = _methodDecl.getModifiers(); + return modifiers.contains(Modifier.PUBLIC); + } + + MethodDeclaration _methodDecl; + int _index = -1; + TwoPhaseAnnotationProcessor _ap; + + /** + * Returns the names of interceptor service interfaces associated with this operation + * @return the names of the interceptor service interfaces associated with this operation + */ + public Collection getInterceptorServiceNames() + { + return _interceptorServiceNames; + } + + /** + * Returns the names of interceptor service interfaces associated with this operation, formatted as a + * constant initializer string. + * @return the names of the interceptor service interfaces associated with this operation + */ + public String getInterceptorDecl() + { + Collection names = getInterceptorServiceNames(); + if ( names == null || names.size() == 0 ) + return null; + + StringBuffer ret = new StringBuffer("{"); + + String [] n = names.toArray(new String[0]); + for (int i=0 ; i < n.length ; ++i) + { + ret.append('"'); ret.append( n[i] ); ret.append('"'); + if ( i != n.length-1 ) + ret.append(", "); + } + ret.append( "}" ); + + return ret.toString(); + } + + private Collection initInterceptorServiceNames() + { + ArrayList ret = new ArrayList(); + + if (_methodDecl == null) + return ret; + + // Iterate over annotations on operation, looking for interceptor-based ones + Collection annotations = _methodDecl.getAnnotationMirrors(); + for ( AnnotationMirror a : annotations ) + { + AnnotationType at = a.getAnnotationType(); + AnnotationTypeDeclaration atd = at.getDeclaration(); + + /* + When performing annotation processing, the ATD here might be null if the apt.exe runtime + is unable to resolve the type to something specific. This will happen when a type referenced + in a source file is invalid because of a bad / missing import, mis-spelling, etc. When + this happens, annotation processing should merilly continue and let javac.exe report + the type errors. Better to do that than to throw an NPE here. + */ + if (atd == null) + continue; + + Collection metaAnnotations = atd.getAnnotationMirrors(); + + /* + Look for annotations that are meta-annotated with @InterceptorAnnotation + */ + for ( AnnotationMirror ma : metaAnnotations ) + { + if ( ma.getAnnotationType().getDeclaration().getQualifiedName(). + equals( "org.apache.beehive.controls.spi.svc.InterceptorAnnotation" ) ) + { + /* + found an interceptor-based annotation, add it! + */ + AptAnnotationHelper ia = new AptAnnotationHelper( ma ); + DeclaredType serviceType = (DeclaredType) ia.getObjectValue("service"); + String intf = serviceType.toString(); + ret.add( intf ); + + break; + } + } + } + + return ret; + } + + Collection _interceptorServiceNames; + +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptMethodSet.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptMethodSet.java new file mode 100644 index 0000000..7784540 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptMethodSet.java @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +import java.util.HashMap; +import java.util.Collection; + +/** + * The AptMethodSet method represents a collection of AptMethod objects. It contains special + * support for method overloading, to ensure that overloaded method objects contained within + * the set will each have a unique index value. + * + * @see org.apache.beehive.controls.runtime.generator.AptMethod#setIndex + */ +public class AptMethodSet +{ + /** + * Adds a new method to the list. Also detects overloaded methods and ensures that they + * will receive a unique index value. + */ + public void add(T method) + { + // check for overridden method + if (isOverrideMethod(method)) { + return; + } + + // Add to the list of managed methods + _methods.put(method.getName() + method.getArgTypes(), method); + + // Ensure that all added methods have a unique index + Object nameValue = _nameMap.get(method.getName()); + if (nameValue == null) + { + // first method with this name, considered unique (for now) + _nameMap.put(method.getName(), method); + } + else + { + int nextIndex; + if (nameValue instanceof AptMethod) + { + // 2nd method with this name, add index to original and start indexing + ((AptMethod)nameValue).setIndex(0); + nextIndex = 1; + } + else + { + // 3rd (or later) method with this name, continue indexing + nextIndex = ((Integer)nameValue).intValue(); + } + + method.setIndex(nextIndex++); + _nameMap.put(method.getName(), nextIndex); + } + } + + /** + * Get the collection of methods in this set. + */ + public Collection getMethods() + { + return _methods.values(); + } + + /** + * Get the number of methods in this set. + */ + public int size() + { + return _methods.size(); + } + + /** + * Determine of the method overrides a previously added method. + * @param method Method to check. + * @return true if method is an override to an existing method and does not need to be added + * to this method set. + */ + private boolean isOverrideMethod(T method) + { + return _methods.containsKey(method.getName() + method.getArgTypes()); + } + + private HashMap _nameMap = new HashMap(); // method name -> a single (unique) AptMethod or next index + private HashMap _methods = new HashMap(); // method name + arg types -> AptMethod +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptOperation.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptOperation.java new file mode 100644 index 0000000..b94acdf --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptOperation.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +import com.sun.mirror.declaration.*; +import org.apache.beehive.controls.runtime.generator.apt.TwoPhaseAnnotationProcessor; + +/** + * The AptOperation class represents a control operation where the operation attributes + * are derived using APT metadata. + */ +public class AptOperation extends AptMethod +{ + /** + * Constructs a new ControlOperation instance where interface information is derived + * from APT metadata + * @param controlIntf the declaring ControlInterface + * @param methodDecl the method associated with the operation + */ + public AptOperation(AptControlInterface controlIntf, MethodDeclaration methodDecl, TwoPhaseAnnotationProcessor ap) + { + super(methodDecl, ap); + _controlIntf = controlIntf; + _operDecl = methodDecl; + } + + + /** + * Returns the name of the static field that holds the name of this method. + */ + public String getMethodField() + { + StringBuffer sb = new StringBuffer(); + sb.append("_"); + sb.append(getName()); + int methodIndex = getIndex(); + if (methodIndex != -1) + sb.append(methodIndex); + sb.append("Method"); + return sb.toString(); + } + + /** + * Returns the AptControlInterface associated with this ControlOperation + */ + public AptControlInterface getControlInterface() { return _controlIntf; } + + MethodDeclaration _operDecl; + AptControlInterface _controlIntf; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptProperty.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptProperty.java new file mode 100644 index 0000000..49ae657 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptProperty.java @@ -0,0 +1,244 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +import java.util.Collection; +import java.util.Map; + +import com.sun.mirror.declaration.AnnotationTypeElementDeclaration; +import com.sun.mirror.declaration.AnnotationMirror; +import com.sun.mirror.declaration.AnnotationValue; +import com.sun.mirror.type.AnnotationType; +import com.sun.mirror.type.PrimitiveType; + +import org.apache.beehive.controls.api.packaging.FeatureInfo; +import org.apache.beehive.controls.api.packaging.PropertyInfo; +import org.apache.beehive.controls.runtime.generator.apt.TwoPhaseAnnotationProcessor; + +/** + * The AptProperty class represents a control Property where the property attributes + * are derived using APT metadata + */ +public class AptProperty +{ + /** + * Constructs a new AptProperty instance + * from APT metadata + * @param propertySet the declaring PropertySet + * @param propDecl the declration of the property annotation type element + */ + public AptProperty(AptPropertySet propertySet, AnnotationTypeElementDeclaration propDecl, + TwoPhaseAnnotationProcessor ap) + { + _propertySet = propertySet; + _propDecl = propDecl; + _ap = ap; + + // + // Primitive properties must specify a default value, to provide consistent semantics + // in cases where no value has been set by annotation, client, or configuration. Object + // typed properties have an optional default, and 'null' in this context means that the + // property value has not been set. + // + if (propDecl.getReturnType() instanceof PrimitiveType && + propDecl.getDefaultValue() == null) + { + _ap.printError( propDecl, "property.primitive.without.default", propDecl.getSimpleName() ); + } + } + + /** + * Returns the PropertySet associated with the Property + */ + public AptPropertySet getPropertySet() { return _propertySet; } + + /** + * Returns the base property name. The associated accessor methods will have the + * form set{name} and get{name} + */ + public String getAccessorName() + { + StringBuffer sb = new StringBuffer(); + sb.append(_propertySet.getPrefix()); + + String name = getName(); + sb.append(Character.toUpperCase(name.charAt(0))); + if (name.length() > 0) + sb.append(name.substring(1)); + return sb.toString(); + } + + /** + * Returns the name of the property reading accessor method + */ + public String getReadMethod() + { + StringBuffer sb = new StringBuffer(); + if (getType().equals("boolean")) + sb.append("is"); + else + sb.append("get"); + sb.append(getAccessorName()); + return sb.toString(); + } + + /** + * Returns the name of the property writing accessor method + */ + public String getWriteMethod() + { + return "set" + getAccessorName(); + } + + /** + * Returns the name associated with this Property in the PropertySet + */ + public String getName() + { + if ( _propDecl == null ) + return ""; + + // + // Use the member name of the property method in the property set + // + return _propDecl.getSimpleName(); + } + + /** + * Returns the static final field name containing the key for this Property + */ + public String getKeyName() + { + return getAccessorName() + "Key"; + } + + /** + * Returns the type of the Property + */ + public String getType() + { + if ( _propDecl == null || _propDecl.getReturnType() == null ) + return ""; + + return _propDecl.getReturnType().toString(); + } + + /** + * Returns true if the property is an annotation type, false otherwise + */ + public boolean isAnnotation() + { + if ( _propDecl == null ) + return false; + + return _propDecl.getReturnType() instanceof AnnotationType; + } + + /** + * Returns any PropertyInfo associated with the property (or null if none) + */ + public PropertyInfo getPropertyInfo() + { + if ( _propDecl == null ) + return null; + + return _propDecl.getAnnotation(PropertyInfo.class); + } + + /** + * Returns any FeatureInfo associated with the property (or null if none) + */ + public FeatureInfo getFeatureInfo() + { + if ( _propDecl == null ) + return null; + + return _propDecl.getAnnotation(FeatureInfo.class); + } + + /** + * Returns 'true' is the property is a bound property that will support registration of + * a PropertyChangeListener for change notifications. + */ + public boolean isBound() + { + // + // Constrained properties are implicitly bound. Refer to section 7.4.3 of the JavaBeans + // spec for the rationale. + // + PropertyInfo propInfo = getPropertyInfo(); + return propInfo != null && (propInfo.bound() || propInfo.constrained()); + } + + /** + * Returns 'true' is the property is a constrained property that will support registration of + * a VetoableChangeListener for vetoable change notifications. + */ + public boolean isConstrained() + { + PropertyInfo propInfo = getPropertyInfo(); + return propInfo != null && propInfo.constrained(); + } + + /** + * Returns the class name of the property editor class, or null + */ + public String getEditorClass() + { + PropertyInfo pi = getPropertyInfo(); + if (pi == null) + return null; + + // + // This is trickier, because APT doesn't allow access to Class-valued annotations, + // because the type may not yet have been compiled. + // + Collection annotMirrors = _propDecl.getAnnotationMirrors(); + for (AnnotationMirror am: annotMirrors) + { + if (am.getAnnotationType().toString().equals( + "org.apache.beehive.controls.api.packaging.PropertyInfo")) + { + Map avs = + am.getElementValues(); + for (AnnotationTypeElementDeclaration ated: avs.keySet()) + { + if (ated.toString().equals("editorClass()")) + { + // + // Get the annotation value, and ignore the default value which implies + // no editor class (because 'null' cannot be a default value) + // + String editorClass = avs.get(ated).getValue().toString(); + if (editorClass.equals("org.apache.beehive.controls.api.packaging.PropertyInfo.NoEditor.class")) + return null; + + return editorClass; + } + } + break; + } + } + return null; + } + + AnnotationTypeElementDeclaration _propDecl; + private AptPropertySet _propertySet; + TwoPhaseAnnotationProcessor _ap; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptPropertySet.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptPropertySet.java new file mode 100644 index 0000000..8ba0c39 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptPropertySet.java @@ -0,0 +1,154 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +import java.util.ArrayList; +import java.util.Collection; + +import com.sun.mirror.declaration.AnnotationTypeDeclaration; +import com.sun.mirror.declaration.AnnotationTypeElementDeclaration; +import com.sun.mirror.declaration.MethodDeclaration; +import com.sun.mirror.declaration.Declaration; + +import org.apache.beehive.controls.api.properties.PropertySet; +import org.apache.beehive.controls.runtime.generator.apt.TwoPhaseAnnotationProcessor; + +/** + * The AptPropertySet class represents a control PropertySet where the property list + * is derived using APT metadata + */ +public class AptPropertySet +{ + /** + * Constructs a new AptPropertySet instance from APT metadata + * @param controlIntf the declaring bean interface. May be null (external property set) + * @param propertySet the PropertySet declaration + * @param ap the annotation processor + */ + public AptPropertySet(AptControlInterface controlIntf, + Declaration propertySet, + TwoPhaseAnnotationProcessor ap) + { + _ap = ap; + _controlIntf = controlIntf; + + if (!(propertySet instanceof AnnotationTypeDeclaration)) + { + _ap.printError( propertySet, "propertyset.illegal.usage" ); + return; + } + _propertySet = (AnnotationTypeDeclaration)propertySet; + + _isOptional = _propertySet.getAnnotation(PropertySet.class).optional(); + _hasSetters = _propertySet.getAnnotation(PropertySet.class).hasSetters(); + + _properties = initProperties(); + } + + /** + * Initializes the list of ControlProperties associated with this ControlPropertySet + */ + protected ArrayList initProperties() + { + ArrayList properties = new ArrayList(); + + if (_propertySet == null || _propertySet.getMethods() == null ) + return properties; + + // Add all declared method, but ignore the mystery methods + for (MethodDeclaration methodDecl : _propertySet.getMethods()) + if (!methodDecl.toString().equals("()")) + properties.add( + new AptProperty(this,(AnnotationTypeElementDeclaration)methodDecl,_ap)); + + return properties; + } + + /** + * Returns the list of ControlProperties associated with this ControlPropertySet + */ + public Collection getProperties() { return _properties; } + + /** + * Returns the fully qualified package name of this property set + */ + public String getPackage() + { + if (_propertySet == null || _propertySet.getPackage() == null ) + return ""; + + return _propertySet.getPackage().getQualifiedName(); + } + + /** + * Returns the unqualified classname of this property set + */ + public String getShortName() + { + if (_propertySet == null ) + return ""; + + return _propertySet.getSimpleName(); + } + + /** + * Returns the fully qualified class name of the property set + */ + public String getClassName() + { + if (_propertySet == null ) + return ""; + + return _propertySet.getQualifiedName(); + } + + /** + * Returns the property name prefix for properties in this PropertySet + */ + public String getPrefix() + { + if (_propertySet == null || _propertySet.getAnnotation(PropertySet.class) == null ) + return ""; + + return _propertySet.getAnnotation(PropertySet.class).prefix(); + } + + /** + * Returns whether or not this propertyset exposes setters + */ + public boolean isOptional() + { + return _isOptional; + } + + /** + * Returns whether or not this propertyset exposes setters + */ + public boolean hasSetters() + { + return _hasSetters; + } + + private AnnotationTypeDeclaration _propertySet; + private AptControlInterface _controlIntf; // may be null if an external property set + private ArrayList _properties; + private TwoPhaseAnnotationProcessor _ap; + private boolean _isOptional; + private boolean _hasSetters; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptTask.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptTask.java new file mode 100644 index 0000000..d6d445b --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptTask.java @@ -0,0 +1,316 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.DirectoryScanner; +import org.apache.tools.ant.taskdefs.Javac; +import org.apache.tools.ant.types.Commandline; +import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.util.FileUtils; +import org.apache.tools.ant.util.GlobPatternMapper; +import org.apache.tools.ant.util.SourceFileScanner; + +import java.io.File; +import java.io.IOException; +import java.util.StringTokenizer; +import java.util.Vector; + +/** + * The AptTask class defines a custom ANT task for invoking APT-based code generation. It + * derives from the built-in task, so all of the attributes and nested elements of that + * task are supported, for source list selection, classpath selection, compiler arguments, + * etc. Each of these options will be passed onto APT for processing. + *

+ * AptTask also adds some new attributes: + *

    + *
  • gendir - specifies the directory where temporary source files that are produced during + * generation will be kept. + *
  • srcExtensions - provides a comma-separated list of source file extensions that are + * considered valid input to APT. The default value is "*.java". + *
  • + */ +public class AptTask extends Javac +{ + /** + * The srcExtensions attribute can be set to a comma-separated list of source filename + * extensions that are considered to be valid inputs to APT processing. + * The default value is "*.java". + */ + public void setSrcExtensions(String srcExts) + { + StringTokenizer tok = new StringTokenizer(srcExts, ","); + while (tok.hasMoreTokens()) + _srcExts.add(tok.nextToken()); + } + + /** + * The srcExtensions attribute can be set to a comma-separated list of processor options + * (of the form option or option=value) to be passed to + * APT. + */ + public void setProcessorOptions(String processorOptions) + { + StringTokenizer tok = new StringTokenizer(processorOptions, ","); + while (tok.hasMoreTokens()) + _processorOptions.add(tok.nextToken()); + } + + /** + * The gendir attribute specifies the name of the output directory for any files generated + * as a result of calling APT. + */ + public void setGendir(File genDir) + { + _genDir = genDir; + } + + /** + * The nocompile attribute disables compilation of the input source file list and any + * generated sources that are derived from them. The default value is 'false'. + */ + public void setNocompile(boolean nocompile) + { + _nocompile = nocompile; + } + + /** + * The compileByExtension attribute causes each input source extension to be compiled + * independently (and sequentially). This is useful when one type of extensio can + * possibly depend upon the generation output from another. The default value 'false'. + */ + public void setCompileByExtension(boolean compileByExt) + { + _compileByExt = compileByExt; + } + + /** + * Override the implementation of scanDir, to look for additional files based upon any + * specified source extensions + */ + protected void scanDir(File srcDir, File destDir, String[] files, String ext) + { + // If no source path was specified, we effectively created one by adding the generation + // path. Because of this, we need to be sure and add all source dirs to the path too. + if (!_hasSourcepath) + { + Path srcPath = new Path(getProject()); + srcPath.setLocation(srcDir); + Path sp = getSourcepath(); + sp.append(srcPath); + setSourcepath(sp); + } + + GlobPatternMapper m = new GlobPatternMapper(); + m.setFrom(ext); + m.setTo("*.class"); + SourceFileScanner sfs = new SourceFileScanner(this); + if (ext.equals("*.java")) + { + File[] newFiles = sfs.restrictAsFiles(files, srcDir, destDir, m); + if (newFiles.length > 0) + { + File[] newCompileList = new File[compileList.length + newFiles.length]; + System.arraycopy(compileList, 0, newCompileList, 0, compileList.length); + System.arraycopy(newFiles, 0, newCompileList, compileList.length, + newFiles.length); + compileList = newCompileList; + } + } + else + { + String [] newSources = sfs.restrict(files, srcDir, destDir, m); + int extLen = ext.length() - 1; // strip wildcard + if (newSources.length > 0) + { + File[] newCompileList = new File[compileList.length + newSources.length]; + System.arraycopy(compileList, 0, newCompileList, 0, compileList.length); + try + { + FileUtils fileUtils = FileUtils.newFileUtils(); + for (int j = 0; j < newSources.length; j++) + { + String toName = + newSources[j].substring(0, newSources[j].length() - extLen) + + ".java"; + + File srcFile = new File(srcDir, newSources[j]); + File dstFile = new File(_genDir, toName); + fileUtils.copyFile(srcFile, dstFile, null, true, true); + newCompileList[compileList.length + j] = dstFile; + } + } + catch (IOException ioe) + { + throw new BuildException("Unable to copy " + ext + " file", ioe, + getLocation()); + } + compileList = newCompileList; + } + } + } + + public void execute() throws BuildException + { + // Ensure that the gendir attribute was specified + if (_genDir == null) + throw new BuildException("Missing genDir attribute: must be set to codegen output directory", getLocation()); + + + // If no source extension specified, then just process .java files + if (_srcExts.size() == 0) + _srcExts.add("*.java"); + + // Save whether a user sourcepath was provided, and if so, the paths + String[] userSourcepaths = null; + _hasSourcepath = getSourcepath() != null; + if ( _hasSourcepath ) + userSourcepaths = getSourcepath().list(); + + // The generation dir is always added to the source path for compilation + Path genPath = new Path(getProject()); + genPath.setLocation(_genDir); + setSourcepath(genPath); + + // If the user sourcepath specifies subdirs underneath the srcdir, then we need to add + // the corresponding subdirs under the gendir to the source path for compilation. + // For example, if the user sourcepath is ";\WEB-INF\src", + // then the sourcepath for compilation should include ";\WEB-INF\src". + if ( _hasSourcepath ) + { + String srcDirPath = (getSrcdir().list())[0]; // TODO: handle multiple srcdirs + for ( String p: userSourcepaths ) + { + if ( p.startsWith( srcDirPath ) && p.length() > srcDirPath.length() ) + { + File genDirElem = new File( _genDir, p.substring( srcDirPath.length()+1 )); + Path gp = new Path(getProject()); + gp.setLocation( genDirElem ); + setSourcepath(gp); + } + } + } + + // + // Select the executable (apt) and set fork = true + // + setExecutable("apt"); + setFork(true); + + // + // Specify the code generation output directory to APT + // + Commandline.Argument arg = createCompilerArg(); + arg.setValue("-s"); + arg = createCompilerArg(); + arg.setFile(_genDir); + + //add the -nocompile flag if set to true + if(_nocompile) + { + Commandline.Argument ncarg = createCompilerArg(); + ncarg.setValue("-nocompile"); + } + + // + // Add processor options. + // + for (Object i : _processorOptions) + { + Commandline.Argument optionArg = createCompilerArg(); + optionArg.setValue("-A" + i); + } + + checkParameters(); + resetFileLists(); + + // Iterate through the list of input extensions, matching/dependency checking based + // upon the input list. + for (int j = 0; j < _srcExts.size(); j++) + { + String ext = (String)_srcExts.get(j); + Vector inputFiles = new Vector(); + + // scan source directories and dest directory to build up + // compile lists + String[] list = getSrcdir().list(); + File destDir = getDestdir(); + for (int i = 0; i < list.length; i++) + { + File srcFile = getProject().resolveFile(list[i]); + if (!srcFile.exists()) { + throw new BuildException("srcdir \"" + + srcFile.getPath() + + "\" does not exist!", getLocation()); + } + + // + // The base algorithm is tweaked here, to allow elements + // to contain a list of files _or_ a list of directories to scan. + // + if (srcFile.isDirectory()) + { + DirectoryScanner ds = this.getDirectoryScanner(srcFile); + String[] files = ds.getIncludedFiles(); + scanDir(srcFile, destDir != null ? destDir : srcFile, files, ext); + } + else + { + // + // BUGBUG: Because these bypass scanning, they also bypass dependency chks :( + // + if (srcFile.getPath().endsWith(ext.substring(1))) + inputFiles.add(srcFile); + } + } + + if (inputFiles.size() != 0) + { + File[] newCompileList = new File[compileList.length + inputFiles.size()]; + inputFiles.toArray(newCompileList); + System.arraycopy(compileList, 0, newCompileList, inputFiles.size(), + compileList.length); + compileList = newCompileList; + } + + // + // If processing/compiling on a per-extension basis, then handle the current list, + // then reset the list fo files to compile before moving to the next extension + // + if (_compileByExt) + { + compile(); + resetFileLists(); + } + } + + // + // If not processing on a per-extension basis, then compile the entire aggregated list + // + if (!_compileByExt) + compile(); + } + + protected boolean _nocompile = false; + protected boolean _compileByExt = false; + protected boolean _hasSourcepath; + protected File _genDir; + protected Vector/**/ _srcExts = new Vector/**/(); + protected Vector/**/ _processorOptions = new Vector/**/(); +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptType.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptType.java new file mode 100644 index 0000000..0393343 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/AptType.java @@ -0,0 +1,168 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +import java.util.Collection; + +import com.sun.mirror.declaration.TypeDeclaration; +import com.sun.mirror.declaration.TypeParameterDeclaration; +import com.sun.mirror.declaration.MethodDeclaration; +import com.sun.mirror.declaration.Modifier; + +/** + * The AptType abstract class defines a base set of methods that are generally available + * for template usage on type declaration objects + */ +public class AptType +{ + /** + * Sets the TypeDeclaration associated with this AptType. + */ + protected void setDeclaration(TypeDeclaration typeDecl) + { + _typeDecl = typeDecl; + } + + /** + * Checks a MethodDeclaration for a 'private' modifier. + * + * @param md MethodDeclaration to check. + * @return true if private modifier is present. + */ + protected boolean isPrivateMethod(MethodDeclaration md) + { + Collection modifiers = md.getModifiers(); + for (Modifier m : modifiers) + { + if (m.compareTo(Modifier.PRIVATE) == 0) + return true; + } + return false; + } + + /** + * Returns the fully qualified classname of this AptType + */ + public String getClassName() + { + if ( _typeDecl == null) + return ""; + + return _typeDecl.getQualifiedName(); + } + + /** + * Returns the base package name associated with the AptType + */ + public String getPackage() + { + if ( _typeDecl == null) + return ""; + + return _typeDecl.getPackage().getQualifiedName(); + } + + /** + * Returns the unqualified class name associated with the AptType + */ + public String getShortName() + { + if ( _typeDecl == null ) + return ""; + + return _typeDecl.getSimpleName(); + } + + /** + * Helper method to return type parameter information + */ + private String getFormalTypeParameters(boolean namesOnly) + { + Collection ftColl = _typeDecl.getFormalTypeParameters(); + if (ftColl.size() == 0) + return ""; + + StringBuffer sb = new StringBuffer("<"); + boolean isFirst = true; + for (TypeParameterDeclaration tpDecl : ftColl) + { + if (!isFirst) + sb.append(","); + else + isFirst = false; + + if (namesOnly) + sb.append(tpDecl.getSimpleName()); + else + sb.append(tpDecl.toString()); + } + sb.append(">"); + return sb.toString(); + } + + /** + * Returns the full formal type parameter declaration associated with the type declaration + */ + public String getFormalTypeParameters() + { + return getFormalTypeParameters(false); + } + + /** + * Returns the name of any formal type parameter names associated with the type declaration. + */ + public String getFormalTypeParameterNames() + { + return getFormalTypeParameters(true); + } + + /** + * Returns the short name and the names of any formal type parameters associated with + * the type. The format is suitable for use in location (such as variable declarations + * or extends clauses) where you want formal type parameters listed. + */ + public String getFormalShortName() + { + StringBuffer sb = new StringBuffer(getShortName()); + sb.append(getFormalTypeParameterNames()); + return sb.toString(); + } + + /** + * Returns the class name and the names of any formal type parameters associated with + * the type. The format is suitable for use in location (such as variable declarations + * or extends clauses) where you want formal type parameters listed. + */ + public String getFormalClassName() + { + StringBuffer sb = new StringBuffer(getClassName()); + sb.append(getFormalTypeParameterNames()); + return sb.toString(); + } + + /** + * Returns the underlying type declaration name + */ + public TypeDeclaration getTypeDeclaration() + { + return _typeDecl; + } + + TypeDeclaration _typeDecl; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ClientInitializer.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ClientInitializer.java new file mode 100644 index 0000000..0d44df3 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ClientInitializer.java @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +import java.util.ArrayList; + +/** + * The ClientInitializer represents a generated class that contains the code + * necessary to initialize a client that uses controls declaratively (via Control and + * EventHandler annotations). + */ +public class ClientInitializer +{ + /** + * Constructs a new ClientInitializer class + * @param controlClient the control client this initializer will target + */ + protected ClientInitializer(AptControlClient controlClient) + { + super(); + + assert controlClient != null; + + _controlClient = controlClient; + _packageName = _controlClient.getPackage(); + _shortName = _controlClient.getShortName() + "ClientInitializer"; + _className = isRootPackage() ? _shortName : _packageName + "." + _shortName; + + // + // Compute the list of impl fields that will require reflected Fields. This is + // done unconditionally for all @Control fields (to support PropertyMap initialization) + // + + _reflectFields = new ArrayList(); + for (AptField genField : _controlClient.getControls()) + _reflectFields.add(genField); + } + + /** + * Returns the package name of the ClientInitializer + */ + public String getPackage() { return _packageName; } + + /** + * Is the ClientInitializer in the root package? + */ + public boolean isRootPackage() { return getPackage() == null || getPackage().equals(""); } + + /** + * Returns the unqualified classname of the ClientInitializer + */ + public String getShortName() { return _shortName; } + + /** + * Returns the fully qualfied classname of the ClientInitializer + */ + public String getClassName() { return _className; } + + /** + * Returns the ControlBean implementation instance + */ + public AptControlClient getControlClient() { return _controlClient; } + + public ClientInitializer getSuperClass() { return null; } + + /** + * Returns true if the initializer will use Reflection to initialize the field, false + * otherwise. + */ + static public boolean needsReflection(AptField genField) + { + // + // Since initializers are generated into the same package as the initialized class, + // only private access fields require reflection + // + String accessModifier = genField.getAccessModifier(); + if (accessModifier.equals("private")) + return true; + + return false; + } + + /** + * Returns the list of impl class fields that must be initialized using Reflection + */ + public ArrayList getReflectFields() + { + return _reflectFields; + } + + String _packageName; + String _shortName; + String _className; + AptControlClient _controlClient; + ArrayList _reflectFields; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ClientInitializer.vm b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ClientInitializer.vm new file mode 100644 index 0000000..01f49cd --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ClientInitializer.vm @@ -0,0 +1,211 @@ +## +## The Velocity code generation template for the ClientInitializer class generated for +## a control client class (a class that uses controls declaratively). +## +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## +## $Header:$ +## +## The following context variables are used by this template: +## $client - a ControlClient instance +## $init - a ClientInitializer instance that defines the attributes of the intializer +## +## The actual class template apears at the end of this file, and is preceded by a number of +## supporting macros that define elements of the template. +## +## SUPPORTING MACROS +## +## This macro defines any static final Field values needed for field initialization +## +#macro (declareReflectFields) + #foreach ($field in $init.reflectFields) + static final Field $field.reflectField; + #end +#end +## +## This macro initializes the value of any static final Field values for field initialization +## +#macro (initReflectFields) + try + { + #foreach ($field in $init.reflectFields) + $field.reflectField = ${client.className}.class.getDeclaredField("$field.name"); + ${field.reflectField}.setAccessible(true); + #end + } + catch (NoSuchFieldException __bc_nsfe) + { + throw new ExceptionInInitializerError(__bc_nsfe); + } +#end +## +## This macro declares a new event adaptor class that maps events from an EventSet to +## a set of implemented handlers on a control client +## +#macro (declareEventAdaptor $adaptor) + #set ($eventSet = $adaptor.eventSet) + #set ($binding = $adaptor.eventField.typeBindingMap) + public static class $adaptor.className + implements ${eventSet.className}${adaptor.eventSetBinding}, + EventAdaptor, java.io.Serializable + { + private static final long serialVersionUID = 1L; + + $client.className __bc_client; + + public ${adaptor.className}($client.className client) { __bc_client = client; } + + public Object getClient() { return __bc_client; } + + #foreach ($event in $eventSet.events) + public ${event.getReturnType($binding)} ${event.name}(${event.getArgDecl($binding)}) $event.throwsClause + { + #if ($adaptor.hasHandler($event)) + #if ($event.returnType != "void") return #end __bc_client.${adaptor.getHandler($event).name}(${event.argList}); + #elseif ($event.returnType != "void") + return $event.getDefaultReturnValue($binding); + #end + } + #end + + #foreach ($superEvent in $eventSet.superEventSet.events) + public ${superEvent.getReturnType($binding)} ${superEvent.name}(${superEvent.getArgDecl($binding)}) $superEvent.throwsClause + { + #if ($adaptor.hasHandler($superEvent)) + #if ($superEvent.returnType != "void") return #end __bc_client.${adaptor.getHandler($superEvent).name}(${superEvent.argList}); + #elseif ($superEvent.returnType != "void") + return $superEvent.getDefaultReturnValue($binding); + #end + } + #end + } + +#end +## +## This macro declares the generated classes that act as event adaptors between an event +## source (control in this case) and client class event handlers. +## +#macro (declareEventAdaptors) + #foreach ($control in $client.controls) + #foreach ($adaptor in $control.eventAdaptors) + #declareEventAdaptor($adaptor) + #end + #end +#end +## +## This macro initializes any event adaptors for a declared control +## +#macro (initEventAdaptors $control) + #foreach ($adaptor in $control.eventAdaptors) + ${control.localName}.${adaptor.eventSet.addListenerMethod}(new ${adaptor.className}(client)); + #end +#end +## +## +## This macro defines the initialization of a declared control. A check is made first to see +## if an external initializer (like java.beans.XMLDecoder) has already instantiated a configured +## bean into the context. +## +#macro (initControl $client $control) + __bc_id = ${client.getID($control)}; + $control.controlBean.className $control.localName = (cbc == null ? null : ($control.controlBean.className)cbc.getBean(__bc_id)); + if ($control.localName == null) + $control.localName = (${control.controlBean.className}) Controls.instantiate(${control.controlBean.className}.class, getAnnotationMap(cbc, ${control.reflectField}), cbc, __bc_id ); + #initEventAdaptors($control) + + #if ($control.hasVersionRequired()) + enforceVersionRequired( $control.localName, ${control.reflectField}.getAnnotation(VersionRequired.class) ); + #end + + #if ($init.needsReflection($control)) + ${control.reflectField}.set(client, $control.localName); + #else + client.${control.name} = $control.localName; + #end +#end +## +## +## This macro defines the initialization method for all declared control instances. +## +#macro (declareFieldInit) + private static void initializeFields(ControlBeanContext cbc, + $client.className client) + { + try + { + String __bc_id; + #foreach ($control in $client.Controls) + #if ($velocityCount == 1) + // + // Initialize any nested controls used by the client + // + #end + #initControl($client $control) + #end + } + catch (RuntimeException __bc_re) { throw __bc_re; } + catch (Exception __bc_e) + { + __bc_e.printStackTrace(); + throw new ControlException("Initializer failure", __bc_e); + } + } +#end + +## +## THE CONTROL INITIALIZER CLASS TEMPLATE +## +#if (!$init.isRootPackage()) +package $init.package; +#end + +import java.lang.reflect.Field; +import org.apache.beehive.controls.api.ControlException; +import org.apache.beehive.controls.api.bean.Controls; +import org.apache.beehive.controls.api.versioning.VersionRequired; +import org.apache.beehive.controls.api.context.ControlBeanContext; +import org.apache.beehive.controls.runtime.bean.EventAdaptor; +import org.apache.beehive.controls.runtime.bean.AdaptorPersistenceDelegate; + +@SuppressWarnings("all") +public class $init.shortName + extends org.apache.beehive.controls.runtime.bean.ClientInitializer +{ + #if ($init.reflectFields.size() != 0) + #declareReflectFields() + static + { + #initReflectFields() + } + #end + + #if ($client.needsFieldInit()) + #declareEventAdaptors() + + #declareFieldInit() + #end + + public static void initialize(ControlBeanContext cbc, $client.ClassName client) + { + #if ($client.hasSuperClient()) + ${client.superClientName}ClientInitializer.initialize( cbc, client ); + #end + + #if ($client.needsFieldInit()) + initializeFields( cbc, client ); + #end + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/CodeGenerationException.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/CodeGenerationException.java new file mode 100644 index 0000000..eba6226 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/CodeGenerationException.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +/** + * A simple exception wrapper class used for code generation failures. These is a runtime + * exception, because user errors that result in code generation failures are reported + * through the APT messager class. + */ +public class CodeGenerationException extends RuntimeException +{ + public CodeGenerationException() { + super(); + } + + public CodeGenerationException(String msg, Exception e) { + super(msg, e); + } + + public CodeGenerationException(String msg) { + super(msg); + } + + public CodeGenerationException(Exception e) { + super("Code Generation Exception", e); + } +} + diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/CodeGenerator.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/CodeGenerator.java new file mode 100644 index 0000000..0ee23d8 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/CodeGenerator.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +/** + * The CodeGenerator class is an abstract base class that encapsulates the invocation + * Apache Velocity or other code generation tools that generate source artifacts. + *

    + * This primary motivation for this abstraction is to decouple the loading and invocation + * of Velocity from the mainline control generation process. + */ +abstract public class CodeGenerator +{ + public CodeGenerator() { + } + + abstract public void generate(GeneratorOutput genOut) throws CodeGenerationException; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBean.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBean.java new file mode 100644 index 0000000..486c372 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBean.java @@ -0,0 +1,132 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +import com.sun.mirror.type.InterfaceType; + +/** + * The ControlBean class is an class representing a generated JavaBean class that can host + * control implementation types associated with a particular control public or extension + * interface. + */ +public class ControlBean +{ + /** + * Constructs a new ControlBean class supporting a particular bean interface + * @param controlIntf the public interface associated with the bean + */ + protected ControlBean(AptControlInterface controlIntf) + { + super(); + _controlIntf = controlIntf; + if (_controlIntf != null) + { + _packageName = _controlIntf.getPackage(); + _shortName = _controlIntf.getShortName() + "Bean"; + _className = isRootPackage() ? _shortName : _packageName + "." + _shortName; + + _superClass = new ControlBean(_controlIntf.getSuperClass()); + } + else + { + Class c = org.apache.beehive.controls.runtime.bean.ControlBean.class; + _packageName = c.getPackage().getName(); + _className = c.getName(); + _shortName = _className.substring(_packageName.length() + 1); + } + } + + /** + * Return whether the ControlBean is contained in a package. + */ + public boolean isRootPackage() { + return _packageName == null || _packageName.trim().equals(""); + } + + /** + * Returns the fully qualified package name of the ControlBean + */ + public String getPackage() { return _packageName; } + + /** + * Returns the unqualified classname of the ControlBean + */ + public String getShortName() { return _shortName; } + + /** + * Returns the fully qualified classname of the ControlBean + */ + public String getClassName() { return _className; } + + /** + * Returns the class declaration for the ControlBean + */ + public String getClassDeclaration() + { + StringBuffer sb = new StringBuffer(_shortName); + sb.append(_controlIntf.getFormalTypeParameters()); + return sb.toString(); + } + + /** + * Returns the fully qualified classname of the ControlBean BeanInfo class. The + * standard JavaBean naming convention is used to enable automatic location by + * the JavaBean introspector. + */ + public String getBeanInfoName() { return _className + "BeanInfo"; } + + + /** + * Returns the class as a Jar Manifest Name attribute + */ + public String getManifestName() { return _className.replace('.','/') + ".class"; } + + /** + * Returns the public or extension interface associated with the ControlBean + */ + public AptControlInterface getControlInterface() { return _controlIntf; } + + /** + * Returns the super class for this ControlBean + */ + public ControlBean getSuperClass() { return _superClass; } + + /** + * Returns any formal type parameters that should be bound for the bean's superclass, + * based upon any type bindings that occur on the original interface. + */ + public String getSuperTypeBinding() + { + InterfaceType superType = _controlIntf.getSuperType(); + if (superType != null) + { + String typeStr = superType.toString(); + int paramIndex = typeStr.indexOf('<'); + if (paramIndex > 0) + return typeStr.substring(paramIndex); + } + return ""; + } + + String _packageName; + String _shortName; + String _className; + AptControlInterface _controlIntf; + ControlBean _superClass; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBean.vm b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBean.vm new file mode 100644 index 0000000..56eee0f --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBean.vm @@ -0,0 +1,696 @@ +## +## The Velocity code generation template for the JavaBean generated from a Control public +## or extension interface. +## +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## +## $Header:$ +## +## The following context variables are used by this template: +## $bean - a ControlBean instance that defines the attributes of the bean +## $intf - a ControlInterface instance that defines the attributes of the public interface +## +## The actual class template apears at the end of this file, and is preceded by a number of +## supporting macros that define elements of the template. +## +## LOCAL SUPPORTING MACROS +## +## This macro declares the template for defining bean constructors +## +#macro (declareConstructors) + /** + * This is the public constructor for the class. A client-defined control ID may + * be provided. This ID must be unique within the nesting ControlBeanContext. + * @param context The containing ControlBeanContext + * @param id The control identifier (or null to autogenerate a unique value) + * @param props The initialization Properties for the new instance (or null for defaults) + */ + public ${bean.shortName}(ControlBeanContext context, String id, PropertyMap props) + { + this(context, id, props, ${intf.className}.class); + } + + /** + * This is the public null-arg constructor for this ControlBean. If a control id + * is not provided, a unique value will be auto-generated. + */ + public ${bean.shortName}() + { + this(null, null, null); + } + + /** + * This is the protected version that is used by any ControlBean subclass + */ + protected ${bean.shortName}(ControlBeanContext context, String id, PropertyMap props, Class controlClass) + { + super(context, id, props, controlClass); + + #foreach ($eventSet in $intf.eventSets) + #if ($velocityCount == 1) + // + // Register event notifier instances for any EventSets + // + #end + setEventNotifier(${eventSet.className}.class, new ${eventSet.notifierClass}()); + #end + } + +#end +## +## This macro defines the implementation of of the getParameterNames helper method +## +#macro (declareGetParameterNames) + /** + * Returns an array of parameter names for the request method, or null if no parameter + * data is available. + */ + protected String [] getParameterNames(Method m) + { + // Check the local map for operations on this bean type + if (_methodParamMap.containsKey(m)) + { + return _methodParamMap.get(m); + } + + // Delegate up if not found locally + return super.getParameterNames(m); + } +#end +## +## This macro defines the implementation of an operation +## +#macro (declareOperationImpl $operation) + #set ($returnType = $operation.returnType) + /** + * Implements ${intf.className}.${operation.name} + */ + public $operation.formalTypes $returnType ${operation.name}($operation.argDecl) $operation.throwsClause + { + Object [] __bc_argArray = new Object[] { $operation.argList }; + Throwable __bc_thrown = null; + #if (!$intf.isExtension()) + $intf.formalClassName __bc_target = ($intf.formalClassName)ensureControl(); + #else + Extensible __bc_target = (Extensible)ensureControl(); + #end + #if ($returnType != "void") + $returnType __bc_retval = ${operation.defaultReturnValue}; + #end + #if ($operation.interceptorServiceNames.size() > 0) + String __bc_pivotedInterceptor = null; + #end + + try + { + #if ($operation.interceptorServiceNames.size() == 0) + preInvoke(${operation.methodField}, __bc_argArray); + #else + preInvoke(${operation.methodField}, __bc_argArray, ${operation.methodField}Interceptors); + #end + + ## + ## There are two basic generation patterns: + ## - standard invoke (declared on a ControlInterface) + ## - extensible invoke (declared on a ControlExtension) + ## + #if ($returnType != "void") + __bc_retval = + #end + #if (!$intf.isExtension()) + __bc_target.${operation.name}($operation.argList) + #else + #if ($returnType != "void") + (#toObject ($returnType)) + #end + __bc_target.invoke(${operation.methodField}, __bc_argArray) + #end + ; + } + #if ($operation.interceptorServiceNames.size() > 0) + catch (org.apache.beehive.controls.spi.svc.InterceptorPivotException __bc_ipe) + { + __bc_pivotedInterceptor = __bc_ipe.getInterceptorName(); + #if ($returnType != "void") + __bc_retval = (#toObject ($returnType))__bc_ipe.getReturnValue(); + #end + } + #end + catch (Throwable __bc_t) + { + // + // All exceptions are caught here, so postInvoke processing has visibility into + // the exception status. Errors, RuntimExceptions, or declared checked exceptions will + // be rethrown. + // + __bc_thrown = __bc_t; + + if (__bc_t instanceof Error) throw (Error)__bc_t; + else if (__bc_t instanceof RuntimeException) throw (RuntimeException)__bc_t; + #foreach ($thrownException in $operation.throwsList) + else if (__bc_t instanceof $thrownException) throw ($thrownException)__bc_t; + #end + + throw new UndeclaredThrowableException(__bc_t); + } + finally + { + #if ($returnType == "void") + Object __bc_rv = null; + #else + Object __bc_rv = __bc_retval; + #end + #if ($operation.interceptorServiceNames.size() == 0) + postInvoke(${operation.methodField}, __bc_argArray, __bc_rv, __bc_thrown); + #else + postInvoke(${operation.methodField}, __bc_argArray, __bc_rv, __bc_thrown, ${operation.methodField}Interceptors, __bc_pivotedInterceptor); + #end + } + #if ($returnType != "void") + return __bc_retval; + #end + } + +#end +## +## This macro defines the property accessor methods for a bean property +## +#macro (declarePropertyAccessors $property) + /** + * A PropertyKey that can be used to access the $property.name property of the + * $property.propertySet.shortName PropertySet + */ + public static final PropertyKey $property.keyName = new PropertyKey(${property.propertySet.className}.class, "$property.name"); + + #if ($property.propertySet.hasSetters()) + public synchronized void ${property.writeMethod}($property.type value) + #if ($property.constrained) + throws java.beans.PropertyVetoException + #end + { + #if ($property.bound || $property.constrained) + // Ensure the control impl exists, since it may want to receive property events + ensureControl(); + + Object __bc_oldValue = getRawControlProperty($property.keyName); + #end + + #if ($property.constrained) + fireVetoableChange($property.keyName, __bc_oldValue, value); + #end + setControlProperty($property.keyName, value); + #if ($property.bound) + firePropertyChange($property.keyName, __bc_oldValue, value); + #end + } + #end + + #if (!$property.propertySet.isOptional()) + public $property.type ${property.readMethod}() + { + return (#toObject($property.type))getControlProperty($property.keyName); + } + #end + +#end +## +## This macro declares the registration methods supporting a PropertyChangeListener +## +#macro (declareBoundPropertySupport) + /** + * Adds a new PropertyChangeListener for listening to changes on bound properties of this + * control. + */ + public void addPropertyChangeListener(PropertyChangeListener pcl) + { + getPropertyChangeSupport().addPropertyChangeListener(pcl); + } + + /** + * Adds a new PropertyChangeListener for listening to changes to a specific bound + * property of this control. + */ + public void addPropertyChangeListener(String propertyName, PropertyChangeListener pcl) + { + getPropertyChangeSupport().addPropertyChangeListener(propertyName, pcl); + } + + /** + * Removes a registered PropertyChangeListener listening to changes on bound properties of + * this control. + */ + public void removePropertyChangeListener(PropertyChangeListener pcl) + { + getPropertyChangeSupport().removePropertyChangeListener(pcl); + } + + /** + * Removes a registered PropertyChangeListener listening to changes on a specific bound + * property of this control. + */ + public void removePropertyChangeListener(String propertyName, PropertyChangeListener pcl) + { + getPropertyChangeSupport().removePropertyChangeListener(propertyName, pcl); + } +#end +## +## This macro declares the registration methods supporting a VetoableChangeListener +## +#macro (declareConstrainedPropertySupport) + /** + * Adds a new PropertyChangeListener for listening to changes on bound properties of this + * control. + */ + public void addVetoableChangeListener(VetoableChangeListener vcl) + { + getVetoableChangeSupport().addVetoableChangeListener(vcl); + } + + /** + * Adds a new PropertyChangeListener for listening to changes to a specific constrained + * property of this control. + */ + public void addVetoableChangeListener(String propertyName, VetoableChangeListener vcl) + { + getVetoableChangeSupport().addVetoableChangeListener(propertyName, vcl); + } + + /** + * Removes a registered PropertyChangeListener listening to changes on constrained properties + * of this control. + */ + public void removeVetoableChangeListener(VetoableChangeListener vcl) + { + getVetoableChangeSupport().removeVetoableChangeListener(vcl); + } + + /** + * Removes a registered PropertyChangeListener listening to changes to a specific constrained + * property of this control. + */ + public void removeVetoableChangeListener(String propertyName, VetoableChangeListener vcl) + { + getVetoableChangeSupport().removeVetoableChangeListener(propertyName, vcl); + } +#end +## +## This macro defines the implementation of an event routing method +## +#macro (declareEventImpl $event) + #set ($returnType = $event.returnType) + public $returnType ${event.name}($event.argDecl) $event.throwsClause + { + Throwable __bc_thrown = null; + #if ($returnType != "void") + $returnType __bc_retval = ${event.defaultReturnValue}; + #end + + $eventSet.notifierClass __bc_notifier = ($eventSet.notifierClass)getEventNotifier(${eventSet.className}.class); + + #if ($event.eventSet.unicast) + $event.eventSet.formalClassName __bc_listener = ($event.eventSet.formalClassName)__bc_notifier.getListener(); + + // + // If an event listener has been registered, then deliver the event + // + if (__bc_listener != null) + { + Object [] __bc_argArray = new Object[] {$event.argList}; + #if ($event.interceptorServiceNames.size() != 0) + String __bc_pivotedInterceptor = null; + #end + try + { + #if ($event.interceptorServiceNames.size() != 0) + preEvent($event.methodField, __bc_argArray, ${event.methodField}Interceptors); + #end + #if ($returnType != "void") + __bc_retval = __bc_listener.${event.name}($event.argList); + #else + __bc_listener.${event.name}($event.argList); + #end + } + #if ($event.interceptorServiceNames.size() != 0) + catch (org.apache.beehive.controls.spi.svc.InterceptorPivotException __bc_ipe) + { + __bc_pivotedInterceptor = __bc_ipe.getInterceptorName(); + #if ($returnType != "void") + __bc_retval = (#toObject ($returnType))__bc_ipe.getReturnValue(); + #end + } + #end + catch (Throwable __bc_t) + { + // + // All exceptions are caught here, so postEvent processing has visibility into + // the exception status. Errors, RuntimExceptions, or declared checked exceptions will + // be rethrown. + // + __bc_thrown = __bc_t; + + if (__bc_t instanceof Error) throw (Error)__bc_t; + else if (__bc_t instanceof RuntimeException) throw (RuntimeException)__bc_t; + #foreach ($thrownException in $event.throwsList) + else if (__bc_t instanceof $thrownException) throw ($thrownException)__bc_t; + #end + + throw new UndeclaredThrowableException(__bc_t); + } + #if ($event.interceptorServiceNames.size() != 0) + finally + { + #if ($returnType == "void") + Object __bc_rv = null; + #else + Object __bc_rv = __bc_retval; + #end + postEvent($event.methodField, __bc_argArray, __bc_rv, __bc_thrown, ${event.methodField}Interceptors, __bc_pivotedInterceptor); + } + #end + } + #if ($returnType != "void") + return __bc_retval; + #end + #else + Object [] __bc_argArray = new Object[] {$event.argList}; + + #if ($event.interceptorServiceNames.size() != 0) + String __bc_pivotedInterceptor = null; + #end + java.util.Iterator __bc_listenerIter = __bc_notifier.listenerIterator(); + + try + { + #if ($event.interceptorServiceNames.size() != 0) + preEvent($event.methodField, __bc_argArray, ${event.methodField}Interceptors); + #end + while (__bc_listenerIter.hasNext()) + { + $event.eventSet.formalClassName __bc_listener = ($eventSet.formalClassName)__bc_listenerIter.next(); + __bc_listener.${event.name}($event.argList); + } + } + #if ($event.interceptorServiceNames.size() != 0) + catch (org.apache.beehive.controls.spi.svc.InterceptorPivotException __bc_ipe) + { + __bc_pivotedInterceptor = __bc_ipe.getInterceptorName(); + } + #end + catch (Throwable __bc_t) + { + // + // All exceptions are caught here, so postEvent processing has visibility into + // the exception status. Errors, RuntimExceptions, or declared checked exceptions will + // be rethrown. + // + __bc_thrown = __bc_t; + + if (__bc_t instanceof Error) throw (Error)__bc_t; + else if (__bc_t instanceof RuntimeException) throw (RuntimeException)__bc_t; + #foreach ($thrownException in $event.throwsList) + else if (__bc_t instanceof $thrownException) throw ($thrownException)__bc_t; + #end + + throw new UndeclaredThrowableException(__bc_t); + } + #if ($event.interceptorServiceNames.size() != 0) + finally + { + postEvent($event.methodField, __bc_argArray, null, __bc_thrown, ${event.methodField}Interceptors, __bc_pivotedInterceptor); + } + #end + #end + } + +#end +## +## This macro defines the implementation of a preEvent method +## +#macro (declarePreEvent $eventSet) + private void preEvent(Method method, Object[] argArray, String[] interceptors) + throws org.apache.beehive.controls.spi.svc.InterceptorPivotException + { + for ( String __bc_n : interceptors ) + { + org.apache.beehive.controls.spi.svc.Interceptor __bc_i = ensureInterceptor( __bc_n ); + try + { + __bc_i.preEvent( ${bean.shortName}.this, ${eventSet.formalClassName}.class , method, argArray ); + } + catch (org.apache.beehive.controls.spi.svc.InterceptorPivotException __bc_ipe) + { + __bc_ipe.setInterceptorName(__bc_n); + throw __bc_ipe; + } + } + } +#end +## +## This macro defines the implementation of a postEvent method +## +#macro (declarePostEvent $eventSet) + private void postEvent(Method method, Object[] argArray, Object retval, Throwable t, String[] interceptors, String pivotedInterceptor) + { + for (int __bc_cnt = interceptors.length - 1; __bc_cnt >= 0; __bc_cnt--) + { + String __bc_n = interceptors[__bc_cnt]; + if (pivotedInterceptor == null || __bc_n.equals(pivotedInterceptor)) + { + pivotedInterceptor = null; + org.apache.beehive.controls.spi.svc.Interceptor __bc_i = ensureInterceptor( __bc_n ); + __bc_i.postEvent( ${bean.shortName}.this, ${eventSet.formalClassName}.class , method, argArray, retval, t ); + } + } + } +#end +## +## This macro defines an EventSet proxy implementation for routing events +## +#macro (declareEventSetImpl $eventSet) + /** + * This inner class implements a simple proxy to deliver $eventSet.shortName events + * back to a register listener. + */ + protected class $eventSet.notifierClass + #if ($eventSet.extendsNotifierBase) + extends $eventSet.notifierExtends + #else + extends ${bean.superClass.className}.${eventSet.notifierExtendsShortName} + #end + implements ${eventSet.formalClassName}, java.io.Serializable + { + private static final long serialVersionUID = 1L; + + #set ( $interceptor = false ) + #foreach ($event in $eventSet.events) + #declareEventImpl($event) + #if ($event.interceptorServiceNames.size() != 0) + #set ( $interceptor = true ) + #end + #end + #if ( $interceptor ) + #declarePreEvent ($eventSet) + #declarePostEvent ($eventSet) + #end + } + +#end +## +## This macros defines the EventSet listener registration methods +## +#macro (declaredListenerMethods $eventSet) + /** + * Registers a new listener for ${eventSet.shortName} events on the bean. + */ + public synchronized void ${eventSet.addListenerMethod}($eventSet.formalClassName listener) + #if ($eventSet.unicast) + throws java.util.TooManyListenersException + #end + { + $eventSet.notifierClass __bc_notifier = ($eventSet.notifierClass)getEventNotifier(${eventSet.className}.class); + __bc_notifier.addListener(listener); + } + + /** + * Unregisters an existing listener for ${eventSet.shortName} events on the bean. + */ + public synchronized void ${eventSet.removeListenerMethod}($eventSet.formalClassName listener) + { + $eventSet.notifierClass __bc_notifier = ($eventSet.notifierClass)getEventNotifier(${eventSet.className}.class); + __bc_notifier.removeListener(listener); + } + + /** + * Returns the array of registered listeners for ${eventSet.shortName} events on the bean, or + * an empty array if no listener has been registered + */ + public synchronized $eventSet.formalClassName [] ${eventSet.getListenersMethod}() + { + $eventSet.notifierClass __bc_notifier = ($eventSet.notifierClass)getEventNotifier(${eventSet.className}.class); + $eventSet.formalClassName [] __bc_listeners = new ${eventSet.className}[__bc_notifier.getListenerCount()]; + __bc_notifier.getListeners(__bc_listeners); + return __bc_listeners; + } +#end +## +## This macro declares the local (bean class) cache that is used for shared PropertyMaps +## +#macro (declarePropertyCache) + /** + * The _annotCache maintains a lookup cache from AnnotatedElements to an associated + * PropertyMap. This enables these maps to be shared across multiple beans. + */ + static private HashMap __bc_annotCache = new HashMap(); + + protected Map getPropertyMapCache() { return __bc_annotCache; } +#end +## +## This macro enforces the VersionRequired annotation semantics +## +#macro (enforceVersionRequired) + /* + * Enforce VersionRequired + */ + Class __bc_controlIntf = null; + + #if ($intf.getMostDerivedInterface()) + __bc_controlIntf = ${intf.getMostDerivedInterface().className}.class; + #end + + Version __bc_versionPresent = (Version)__bc_controlIntf.getAnnotation(Version.class); + VersionRequired __bc_versionRequired = (${bean.shortName}.class).getAnnotation(VersionRequired.class); + + org.apache.beehive.controls.runtime.bean.ControlBean.enforceVersionRequired("${intf.className}", __bc_versionPresent, __bc_versionRequired); +#end +## +## This macro declares the interceptor arrays for operations and eventsets +## +#macro (declareMethodInterceptors) + #foreach ($operation in $intf.operations) + #if ($operation.interceptorServiceNames.size() != 0) + private static String[] ${operation.methodField}Interceptors = ${operation.interceptorDecl}; + #end + #end + + #foreach ($eventSet in $intf.eventSets) + #foreach ($event in $eventSet.events) + #if ($event.interceptorServiceNames.size() != 0) + private static String[] ${event.methodField}Interceptors = ${event.interceptorDecl}; + #end + #end + #end +#end + +## +## This macro declares the code that prioritizes interceptor arrays for operations +## +#macro (prioritizeInterceptors) + #foreach ($operation in $intf.operations) + #if ($operation.interceptorServiceNames.size() != 0) + ${operation.methodField}Interceptors = org.apache.beehive.controls.runtime.bean.InterceptorUtils.prioritizeInterceptors( ${operation.methodField}Interceptors ); + #end + #end + #foreach ($eventSet in $intf.eventSets) + #foreach ($event in $eventSet.events) + #if ($event.interceptorServiceNames.size() != 0) + ${event.methodField}Interceptors = org.apache.beehive.controls.runtime.bean.InterceptorUtils.prioritizeInterceptors(${event.methodField}Interceptors); + #end + #end + #end + +#end +## +## THE CONTROLBEAN CLASS TEMPLATE +## +#if (!$bean.isRootPackage()) +package $bean.package; +#end + +import java.beans.*; + +import java.lang.reflect.Method; +import java.lang.reflect.UndeclaredThrowableException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.beehive.controls.api.bean.*; +import org.apache.beehive.controls.api.context.ControlBeanContext; +import org.apache.beehive.controls.api.properties.PropertyKey; +import org.apache.beehive.controls.api.properties.PropertyMap; +import org.apache.beehive.controls.api.versioning.*; + +@SuppressWarnings("all") +public class ${bean.classDeclaration} + extends ${bean.superClass.className}${bean.superTypeBinding} + implements ${intf.formalClassName} +{ + #if ($intf.operations.size() != 0 || $intf.localEventSetCount != 0) + #declareMethodStatics() + + static + { + #initMethodStatics() + } + + #declareMethodInterceptors() + + static + { + #prioritizeInterceptors() + } + + #end + + #if ($intf.getVersionRequired()) + static + { + #enforceVersionRequired() + } + #end + + #declareConstructors() + + #if ($intf.operations.size() != 0) + #declareGetParameterNames() + + #foreach ($operation in $intf.operations) + #declareOperationImpl ($operation) + #end + #end + + #foreach ($propertySet in $intf.propertySets) + #foreach ($property in $propertySet.properties) + #declarePropertyAccessors ($property) + #end + #end + + #if ($intf.addsBoundPropertySupport()) + #declareBoundPropertySupport() + #end + + #if ($intf.addsConstrainedPropertySupport()) + #declareConstrainedPropertySupport() + #end + + #foreach ($eventSet in $intf.eventSets) + #declareEventSetImpl ($eventSet) + #declaredListenerMethods($eventSet) + #end + + #declarePropertyCache() + + private static final long serialVersionUID = 1L; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBeanInfo.vm b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBeanInfo.vm new file mode 100644 index 0000000..ab044a9 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlBeanInfo.vm @@ -0,0 +1,400 @@ +## +## The Velocity code generation template for the JavaBean BeanInfo generated from a Control public +## or extension interface. +## +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## +## $Header:$ +## +## The following context variables are used by this template: +## $bean - a ControlBean instance that defines the attributes of the bean +## $intf - a ControlInterface instance that defines the attributes of the public interface +## +## The initFeatureDescriptor macro will initialize the contents of a FeatureDescriptor using +## a FeatureInfo annotation instance. +## +## The localizeString is used to inject code to do resource bundle lookup on string values that +## begin/end with '%'. See org.apache.beehive.controls.runtime.ControlBeanInfo.localizeString() +## for details +## +#macro (localizeString $string) +#if ($string.startsWith('%') && $string.endsWith('%')) localizeString("$string") #else "$string" #end +#end +#macro (initFeatureDescriptor $featureDesc $featureInfo $defaultName) +#if (! $featureInfo.name().equals("")) +${featureDesc}.setName(#localizeString("$featureInfo.name()")); +#else +${featureDesc}.setName("$defaultName"); +#end +#if (! $featureInfo.displayName().equals("")) +${featureDesc}.setDisplayName(#localizeString("$featureInfo.displayName()")); +#else +${featureDesc}.setDisplayName("$defaultName"); +#end +${featureDesc}.setShortDescription(#localizeString("$featureInfo.shortDescription()")); +${featureDesc}.setExpert($featureInfo.isExpert()); +${featureDesc}.setHidden($featureInfo.isHidden()); +${featureDesc}.setPreferred($featureInfo.isPreferred()); +## +## Reading arrays of annotation type instances is broken under JDK1.5.0b51 +## +###foreach ($featureAttr in $featureInfo.attributes()) +##${featureDesc}.setValue("$featureAttr.name()","$featureAttr.value()"); +###end +#end +## +## Begin - Main body for ControlBeanInfo class template +## +#if (!$bean.isRootPackage()) +package $bean.package; +#end + +import java.beans.BeanDescriptor; +import java.beans.EventSetDescriptor; +import java.beans.IntrospectionException; +import java.beans.MethodDescriptor; +import java.beans.ParameterDescriptor; +import java.beans.PropertyDescriptor; +import java.beans.PropertyEditor; +import java.lang.reflect.Method; +import java.util.HashMap; + +import org.apache.beehive.controls.api.ControlException; +import org.apache.beehive.controls.runtime.bean.BeanPersistenceDelegate; +import org.apache.beehive.controls.runtime.packaging.ControlEventSetDescriptor; + +@SuppressWarnings("all") +public class ${bean.shortName}BeanInfo +#if ($intf.superClass) + extends ${bean.superClass.className}BeanInfo +#else + extends org.apache.beehive.controls.runtime.bean.ControlBeanInfo +#end +{ + #if ($intf.operations.size() != 0 || $intf.eventSets.size() != 0) + #declareMethodStatics() + + static + { + #initMethodStatics() + } + #end + + /** + * Default null-arg constructor used to create a new BeanInfo instance + */ + public ${bean.shortName}BeanInfo() + { + super(${bean.className}.class); + } + + /** + * Protected constructor used if this BeanInfo class is extended. + */ + protected ${bean.shortName}BeanInfo(Class beanClass) + { + super(beanClass); + } + + // java.beans.BeanInfo.getBeanDescriptor + public BeanDescriptor getBeanDescriptor() + { + BeanDescriptor bd = new BeanDescriptor(${bean.className}.class); + #if ($intf.featureInfo) + #initFeatureDescriptor("bd" $intf.featureInfo $bean.shortName) + #else + bd.setName(#localizeString("$bean.shortName")); + bd.setDisplayName(#localizeString("$bean.shortName")); + #end + + // + // The org.apache.beehive.controls.runtime.bean.BeanPersistenceDelegate class + // implements the XMLDecode delegation model for all Control JavaBean types. It + // provides optimized XML persistance based upon the Control runtime architecture. + // The 'persistenceDelegate' attribute of a BeanDescriptor is used by XMLEncoder to + // locate a delegate for a particular JavaBean type. + // + bd.setValue("persistenceDelegate", new BeanPersistenceDelegate()); + + return bd; + } + + /** + * Stores MethodDescriptor descriptors for this bean and its superclasses into + * an array, starting at the specified index + */ + protected void initMethodDescriptors(MethodDescriptor [] methodDescriptors, int index) + throws java.beans.IntrospectionException + { + #if ($intf.operations.size() > 0) + String [] __bc_paramNames; + ParameterDescriptor [] __bc_paramDescriptors; + MethodDescriptor md; + #end + + #foreach ($operation in $intf.operations) + // + // Declare MethodDescriptor for ${operation.name}(${operation.argList}) + // + __bc_paramNames = _methodParamMap.get($operation.methodField); + __bc_paramDescriptors = new ParameterDescriptor[__bc_paramNames.length]; + for (int j = 0; j < __bc_paramNames.length; j++) + { + __bc_paramDescriptors[j] = new ParameterDescriptor(); + __bc_paramDescriptors[j].setName(__bc_paramNames[j]); + __bc_paramDescriptors[j].setDisplayName(__bc_paramNames[j]); + } + md = new MethodDescriptor($operation.methodField, __bc_paramDescriptors); + #if ($operation.featureInfo) + #initFeatureDescriptor("md" $operation.featureInfo $operation.name) + #end + methodDescriptors[index++] = md; + + #end + + #if ($intf.superClass) + // + // Add method descriptors from parent BeanInfo + // + super.initMethodDescriptors(methodDescriptors, index); + #end + } + + public MethodDescriptor [] getMethodDescriptors() + { + MethodDescriptor [] __bc_methodDescriptors = new MethodDescriptor[$intf.operationCount]; + try + { + initMethodDescriptors(__bc_methodDescriptors, 0); + } + catch (java.beans.IntrospectionException __bc_ie) + { + throw new ControlException("Unable to create MethodDescriptor", __bc_ie); + } + return __bc_methodDescriptors; + } + + /** + * Stores PropertyDescriptor descriptors for this bean and its superclasses into + * an array, starting at the specified index + */ + protected void initPropertyDescriptors(PropertyDescriptor [] propDescriptors, int index) + throws java.beans.IntrospectionException + { + PropertyDescriptor pd; + + #foreach ($propertySet in $intf.propertySets) + #foreach ($property in $propertySet.properties) + #if ($property.getType().equals("boolean")) + #set ( $getterName = "is${property.accessorName}" ) + #else + #set ( $getterName = "get${property.accessorName}" ) + #end + #if ($propertySet.hasSetters()) + #set ( $setterName = "set${property.accessorName}" ) + #if ($propertySet.isOptional()) + pd = new PropertyDescriptor(#localizeString("$property.name"), ${bean.className}.class, null, "$setterName"); + #else + pd = new PropertyDescriptor(#localizeString("$property.name"), ${bean.className}.class, "$getterName", "$setterName"); + #end + #else + #if (! $propertySet.isOptional()) + pd = new PropertyDescriptor(#localizeString("$property.name"), ${bean.className}.class, "$getterName", null ); + #end + #end + #if ($propertySet.hasSetters() || !$propertySet.isOptional()) + #if ($property.propertyInfo) + pd.setBound($property.propertyInfo.bound()); + pd.setConstrained($property.propertyInfo.constrained()); + #if ($property.editorClass) + pd.setPropertyEditorClass(${property.editorClass}.class); + #end + #end + #if ($property.featureInfo) + #initFeatureDescriptor("pd" $property.featureInfo $property.name) + #end + propDescriptors[index++] = pd; + #end + #end + #end + + #if ($intf.interfaceProperties.size() > 0) + // + // add property descriptors for any getter/setters defined in control interface + // + #end + #foreach ($intfprop in $intf.interfaceProperties) + #if ($intfprop.getterName && $intfprop.setterName) + pd = new PropertyDescriptor(#localizeString("$intfprop.name"), ${bean.className}.class, "$intfprop.getterName", "$intfprop.setterName"); + propDescriptors[index++] = pd; + #elseif ($intfprop.getterName) + pd = new PropertyDescriptor(#localizeString("$intfprop.name"), ${bean.className}.class, "$intfprop.getterName", null); + propDescriptors[index++] = pd; + #elseif ($intfprop.setterName) + pd = new PropertyDescriptor(#localizeString("$intfprop.name"), ${bean.className}.class, null, "$intfprop.setterName"); + propDescriptors[index++] = pd; + #end + #end + + #if ($intf.superClass) + // + // Add property descriptors from parent BeanInfo + // + super.initPropertyDescriptors(propDescriptors, index); + #end + } + + // java.beans.BeanInfo.getPropertyDescriptors + public PropertyDescriptor [] getPropertyDescriptors() + { + PropertyDescriptor [] __bc_propDescriptors = new PropertyDescriptor[$intf.propertyCount]; + try + { + initPropertyDescriptors(__bc_propDescriptors, 0); + } + catch (java.beans.IntrospectionException __bc_ie) + { + throw new ControlException("Unable to create PropertyDescriptor", __bc_ie); + } + return __bc_propDescriptors; + } + + #foreach ($eventSet in $intf.eventSets) + // + // Adds the EventDescriptors for $eventSet.shortName to the EventDescriptor array, starting + // at index + // + protected void ${eventSet.infoInitializer}(MethodDescriptor [] eventDescriptors, int index) + { + String [] __bc_paramNames; + ParameterDescriptor [] __bc_paramDescriptors; + MethodDescriptor md; + + // + // Build a method descriptor for each event method in the event set + // + #foreach ($event in $eventSet.events) + + // + // Declare MethodDescriptor for ${event.name}(${event.argList}) + // + __bc_paramNames = _methodParamMap.get($event.methodField); + __bc_paramDescriptors = new ParameterDescriptor[__bc_paramNames.length]; + for (int k = 0; k < __bc_paramNames.length; k++) + { + __bc_paramDescriptors[k] = new ParameterDescriptor(); + __bc_paramDescriptors[k].setName(__bc_paramNames[k]); + __bc_paramDescriptors[k].setDisplayName(__bc_paramNames[k]); + } + md = new MethodDescriptor($event.methodField, __bc_paramDescriptors); + #if ($event.featureInfo) + #initFeatureDescriptor("md" $event.featureInfo $event.name) + #end + eventDescriptors[index++] = md; + #end + + #if ($eventSet.superEventSet) + // + // Add events from the parent EventSet + // + ${eventSet.superEventSet.infoInitializer}(eventDescriptors, index); + #end + } + + #end + + protected void initEventSetDescriptors(EventSetDescriptor [] eventSetDescriptors, int index) + throws java.beans.IntrospectionException + { + #if ($intf.eventSets.size() > 0) + MethodDescriptor [] __bc_eventDescriptors; + EventSetDescriptor __bc_esd; + Method __bc_addListener, __bc_removeListener, __bc_getListeners; + Class __bc_eventIntf; + #end + + #foreach ($eventSet in $intf.eventSets) + __bc_eventIntf = ${eventSet.className}.class; + + // + // Find the add/remove listener methods + // + try + { + __bc_addListener = + ${bean.className}.class.getDeclaredMethod("$eventSet.addListenerMethod", + new Class [] { __bc_eventIntf }); + __bc_removeListener = + ${bean.className}.class.getDeclaredMethod("$eventSet.removeListenerMethod", + new Class [] { __bc_eventIntf }); + __bc_getListeners = + ${bean.className}.class.getDeclaredMethod("$eventSet.getListenersMethod", + new Class [] {}); + } + catch (NoSuchMethodException __bc_nsme) + { + // This is moderately lame, but there is no checked exception declared for this + // method. This could only happen as a result of a mismatch between bean class + // and introspector codegen. + throw new ControlException("Unable to locate listener method", __bc_nsme); + } + + // + // Build the MethodDescriptor array contain all event set events + // + __bc_eventDescriptors = new MethodDescriptor[$eventSet.eventCount]; + ${eventSet.infoInitializer}(__bc_eventDescriptors, 0); + + try + { + __bc_esd = new ControlEventSetDescriptor(localizeString("$eventSet.descriptorName"), + __bc_eventIntf, __bc_eventDescriptors, __bc_addListener, __bc_removeListener, __bc_getListeners); + #if ($eventSet.featureInfo) + #initFeatureDescriptor("esd" $eventSet.featureInfo $eventSet.descriptorName) + #end + __bc_esd.setUnicast($eventSet.unicast); + } + catch (IntrospectionException __bc_ie) + { + throw new ControlException("Unable to create EventDescriptor", __bc_ie); + } + eventSetDescriptors[index++] = __bc_esd; + + #end + + #if ($intf.superClass) + // + // Add event set descriptors from parent BeanInfo + // + super.initEventSetDescriptors(eventSetDescriptors, index); + #end + } + + // java.beans.BeanInfo.getEventSetDescriptors + public EventSetDescriptor [] getEventSetDescriptors() + { + EventSetDescriptor [] __bc_eventSetDescriptors = new EventSetDescriptor[$intf.eventSetCount]; + try + { + initEventSetDescriptors(__bc_eventSetDescriptors, 0); + } + catch (java.beans.IntrospectionException __bc_ie) + { + throw new ControlException("Unable to create EventSetDescriptor", __bc_ie); + } + return __bc_eventSetDescriptors; + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlMacros.vm b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlMacros.vm new file mode 100644 index 0000000..6881a50 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlMacros.vm @@ -0,0 +1,93 @@ +## +## The Velocity code generation template file containing various method macro utilities +## +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## +## $Header:$ +## +## The following context variables are used by this template: +## $bean - a ControlBean instance that defines the attributes of the bean +## $intf - a ControlInterface instance that defines the attributes of the public interface +## +## The actual class template apears at the end of this file, and is preceded by a number of +## supporting macros that define elements of the template. +## +## SUPPORTING MACROS +## +## A simple helper macro that converts a primitive type to the equivalent object +## +#macro (toObject $type)#if ($type == "int")Integer#elseif ($type == "long")Long#elseif ($type == "boolean")Boolean#elseif ($type == "byte")Byte#elseif ($type == "short")Short#elseif ($type == "char")Character#elseif ($type == "float")Float#elseif ($type == "double")Double#else${type}#end#end +## +## A simple helper macro that converts a object type to the equivalent primitive +## +## This macro provides the template for declaring the static final Method fields that +## are associated with all declared operations +## +#macro (declareMethodStatics) + #foreach ($operation in $intf.operations) + static final Method $operation.methodField; + #end + #foreach ($eventSet in $intf.eventSets) + #foreach ($event in $eventSet.events) + static final Method $event.methodField; + #end + #end + + // + // This HashMap will map from a Method to the array of names for parameters of the + // method. This is necessary because parameter name data isn't carried along in the + // class file, but if available can enable ease of use by referencing parameters by + // the declared name (vs. by index). + // + // This map should be read-only after its initialization in the static block, hence + // using a plain HashMap is thread-safe. + // + static HashMap _methodParamMap = new HashMap(); +#end +## +## This macros provides the template for initializing the static final Method fields that +## are associated with declared operations +## +#macro (initMethodStatics) + + ## First verify that if an eventSet was defined it is not empty. + #set($eCount=0) + #foreach($eventSet in $intf.eventSets) + #foreach($event in $eventSet.events) + #set($eCount=$eCount+1) + #end + #end + + #if ($intf.operations.size() > 0 || $eCount > 0) + try + { + #foreach ($operation in $intf.operations) + $operation.methodField = ${intf.className}.class.getMethod("${operation.name}", new Class [] {$operation.argTypes}); + _methodParamMap.put($operation.methodField, new String [] { $operation.getArgList(true) }); + #end + #foreach ($eventSet in $intf.eventSets) + #foreach ($event in $eventSet.events) + $event.methodField = ${eventSet.className}.class.getMethod("${event.name}", new Class [] {$event.argTypes}); + _methodParamMap.put($event.methodField, new String [] { $event.getArgList(true) }); + #end + #end + } + catch (NoSuchMethodException __bc_nsme) + { + throw new ExceptionInInitializerError(__bc_nsme); + } + #end +#end diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlManifest.vm b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlManifest.vm new file mode 100644 index 0000000..5e830c2 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ControlManifest.vm @@ -0,0 +1,42 @@ +## +## The Velocity code generation template for the JAR manifest file (META-INF/MANIFEST.MF) +## entries associated with a control bean and its public interface or extension class. +## +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## +## $Header:$ +## +## The following context variables are used by this template: +## $bean - a ControlBean instance that defines the attributes of the bean +## $intf - a ControlInterface instance that defines the attributes of the public interface +## +## +## THE CONTROL BEAN MANIFEST.MF TEMPLATE +## +## This template defines the JAR manifest contents that will be injected into any JAR file +## containing Beehive controls. The template is used to generate per-control manifest files, +## which are then merged by the org.apache.beehive.controls.runtime.packaging.ControlJarTask +## ant task into a single JAR manifest file. +## +Manifest-Version: 1.0 + +Name: $bean.manifestName +Java-Bean: true +Beehive-Control: true +#set ($attrs = $intf.manifestAttributes) +#foreach ($name in $attrs.keySet()) +${name}: ${attrs.get($name)} +#end diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/EventAdaptor.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/EventAdaptor.java new file mode 100644 index 0000000..119a507 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/EventAdaptor.java @@ -0,0 +1,154 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +import java.util.HashMap; + +import com.sun.mirror.type.TypeMirror; +import com.sun.mirror.declaration.TypeParameterDeclaration; + +/** + * The EventAdaptor class represents the generated class that is necessary to route + * events for a EventSet onto implemented EventHandlers on an implementation class. + */ +public class EventAdaptor +{ + /** + * Constructs a new EventAdaptor for events declared on an EventSet + */ + public EventAdaptor(AptEventField eventField, AptEventSet eventSet) + { + _eventField = eventField; + _eventSet = eventSet; + _className = initClassName(); + } + + /** + * Computes a unique adaptor class name + */ + private String initClassName() + { + StringBuffer sb = new StringBuffer(); + String fieldName = _eventField.getName(); + String setName = _eventSet.getClassName(); + sb.append(Character.toUpperCase(fieldName.charAt(0))); + if (fieldName.length() > 1) + sb.append(fieldName.substring(1)); + sb.append(setName.substring(setName.lastIndexOf('.') + 1)); + sb.append("EventAdaptor"); + return sb.toString(); + } + + /** + * Returns the name of the generated class for this adaptor. + */ + public String getClassName() + { + return _className; + } + + /** + * Returns the name of the generated class for this adaptor, including any formal type + * declarations from the associate event set. + */ + public String getFormalClassName() + { + StringBuffer sb = new StringBuffer(_className); + sb.append(_eventSet.getFormalTypeParameters()); + return sb.toString(); + } + + /** + * Returns the event field associated with this event adaptor + */ + public AptEventField getEventField() { return _eventField; } + + /** + * Returns the EventSet associated with this Adaptor + */ + public AptEventSet getEventSet() { return _eventSet; } + + /** + * Adds a new EventHandler for a Event to the EventAdaptor + */ + public void addHandler(AptEvent event, AptMethod eventHandler) + { + assert event.getEventSet() == _eventSet; + _handlerMap.put(event, eventHandler); + } + + /** + * Returns true if there is an EventHandler for ControlEvent on this EventAdaptor + */ + public boolean hasHandler(AptEvent event) + { + return _handlerMap.containsKey(event); + } + + /** + * Returns the EventHandler for a ControlEvent on this EventAdaptor + */ + public AptMethod getHandler(AptEvent event) + { + return _handlerMap.get(event); + } + + /** + * Returns any formal type parameter declaration for EventSet interface associated with + * the adaptor class. This will bind the formal types of the interface based on any type + * binding from the event field declaration + */ + public String getEventSetBinding() + { + // Get the type bindings for the associated event field. + HashMap typeBinding = _eventField.getTypeBindingMap(); + + StringBuffer sb = new StringBuffer(); + boolean isFirst = true; + for (TypeParameterDeclaration tpd : + _eventSet.getDeclaration().getFormalTypeParameters()) + { + if (isFirst) + { + sb.append("<"); + isFirst = false; + } + else + sb.append(", "); + + // Map from the declared formal type name to the bound type name + // If no map entry exists (i.e. not bindings were specified on the field + // declaration, then the implied binding is to Object.class + String typeName = tpd.getSimpleName(); + if (typeBinding.containsKey(typeName)) + sb.append(typeBinding.get(tpd.getSimpleName())); + else + sb.append("java.lang.Object"); + } + if (!isFirst) + sb.append(">"); + + return sb.toString(); + } + + private String _className; + private AptEventField _eventField; + private AptEventSet _eventSet; + private HashMap _handlerMap = new HashMap(); +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/GenClass.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/GenClass.java new file mode 100644 index 0000000..dfac951 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/GenClass.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +import java.io.IOException; +import java.util.List; + +import com.sun.mirror.apt.Filer; + +/** + * The GenClass abstract class defines a base set of methods that are generally available + * for template usage on class-type objects + *

    + * This is done with an abstract class (instead of an interface) so derived abstract classes + * can be subclassed from it w/out requiring all of the methods to be declared there. + */ +abstract public class GenClass +{ + /** + * Returns the fully qualified classname associated with the GenClass + */ + abstract public String getClassName(); + + /** + * Returns the base package name associated with the GenClass + */ + abstract public String getPackage(); + + /** + * Returns the unqualified class name associated with the GenClass + */ + abstract public String getShortName(); + + /** + * Returns the super class for this class + */ + abstract public GenClass getSuperClass(); + + /** + * Returns true if the GenClass extends another class + */ + public boolean hasSuperClass() + { + return getSuperClass() != null; + } + + /** + * Returns the list of fully qualified class names for types that are derived + * from this GenClass + */ + public String [] getGeneratedTypes() + { + return null; + } + + /** + * Returns the list of generated files derived from this GenClass during the + * check phase of annotation processing. + */ + public List getCheckOutput(Filer filer) throws IOException + { + return null; + } + + /** + * Returns the list of generated files derived from this GenClass during the + * generate phase of annotation processing. + */ + public List getGenerateOutput(Filer filer) throws IOException + { + return null; + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/Generator.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/Generator.java new file mode 100644 index 0000000..e9b9dfb --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/Generator.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +import java.io.IOException; +import java.util.List; + +import com.sun.mirror.apt.Filer; + +/** + * The Generator interface will be implemented by APT data types that result in the generation + * of new source or text artifacts. + * for template usage on class-type objects + *

    + * This is done with an abstract class (instead of an interface) so derived abstract classes + * can be subclassed from it w/out requiring all of the methods to be declared there. + */ +public interface Generator +{ + /** + * Returns the list of fully qualified class names for types that are derived + * from this Generator + */ + public String [] getGeneratedTypes(); + + /** + * Returns the list of generated files derived from this Generator during the + * check phase of annotation processing. + */ + public List getCheckOutput(Filer filer) throws IOException; + + /** + * Returns the list of generated files derived from this Generator during the + * generate phase of annotation processing. + */ + public List getGenerateOutput(Filer filer) throws IOException; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/GeneratorOutput.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/GeneratorOutput.java new file mode 100644 index 0000000..f311fb7 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/GeneratorOutput.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +import java.io.Writer; +import java.util.HashMap; + +/** + * The GeneratorOutput class represents a single file output by the code generation process, + * as well as the template and context information necessary to generate it. + */ +public class GeneratorOutput +{ + public GeneratorOutput(Writer outWriter, String templateName, HashMap context) + { + _outWriter = outWriter; + _templateName = templateName; + _context = context; + } + + public String getTemplateName() { + return _templateName; + } + + public HashMap getContext() { + return _context; + } + + public Writer getWriter() { + return _outWriter; + } + + String _templateName; + Writer _outWriter; + HashMap _context; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ImplInitializer.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ImplInitializer.java new file mode 100644 index 0000000..59363b6 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ImplInitializer.java @@ -0,0 +1,148 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +import java.util.ArrayList; + +/** + * The ImplInitializer class is a generated class that contains the code necessary to initialize + * a ControlBean implementation instance. + */ +public class ImplInitializer +{ + /** + * Constructs a new ImplInitializer class supporting a particular control bean implementation + * @param controlImpl the control implementation to be initialized + */ + protected ImplInitializer(AptControlImplementation controlImpl) + { + super(); + _controlImpl = controlImpl; + _controlIntf = _controlImpl.getControlInterface(); + if (_controlImpl != null) + { + _packageName = _controlImpl.getPackage(); + _shortName = _controlImpl.getShortName() + "Initializer"; + _className = _packageName + "." + _shortName; + if (_controlImpl.getSuperClass() != null) + _superClass = new ImplInitializer(_controlImpl.getSuperClass()); + } + else + { + Class c = org.apache.beehive.controls.runtime.bean.ImplInitializer.class; + _packageName = c.getPackage().getName(); + _className = c.getName(); + _shortName = _className.substring(_packageName.length() + 1); + } + + // + // Compute the list of impl fields that will require reflected Fields. + // + _reflectFields = new ArrayList(); + for (AptField genField : _controlImpl.getContexts()) + if (needsReflection(genField)) + _reflectFields.add(genField); + for (AptField genField : _controlImpl.getClients()) + if (needsReflection(genField)) + _reflectFields.add(genField); + } + + /* + * Return whether the ControlBean is contained in a package. + */ + public boolean isRootPackage() { + return _packageName == null || _packageName.trim().equals(""); + } + + /** + * Returns the package name of the ImplInitializer + */ + public String getPackage() { return _packageName; } + + /** + * Returns the unqualified classname of the ImplInitializer + */ + public String getShortName() { return _shortName; } + + /** + * Returns the fully qualfied classname of the ImplInitializer + */ + public String getClassName() { return _className; } + + /** + * Returns the fully qualified classname of any associated ClientInitializer + */ + public String getClientInitializerName() + { + return _controlImpl.getClassName() + "ClientInitializer"; + } + + /** + * Returns the ControlBean implementation instance + */ + public AptControlImplementation getControlImplementation() { return _controlImpl; } + + /** + * Returns the public or extension interface associated with the ControlBean implementation + */ + public AptControlInterface getControlInterface() { return _controlIntf; } + + /** + * Returns the ImplInitializer super class for this ImplInitializer + */ + public ImplInitializer getSuperClass() { return _superClass; } + + /** + * Returns true if the ImplInitializer has a super class + */ + public boolean hasSuperClass() { return _superClass != null; } + + /** + * Returns true if the initializer will use Reflection to initialize the field, false + * otherwise. + */ + static public boolean needsReflection(AptField genField) + { + // + // Since initializers are generated into the same package as the initialized class, + // only private access fields require reflection + // + String accessModifier = genField.getAccessModifier(); + if (accessModifier.equals("private")) + return true; + + return false; + } + + /** + * Returns the list of impl class fields that must be initialized using Reflection + */ + public ArrayList getReflectFields() + { + return _reflectFields; + } + + String _packageName; + String _shortName; + String _className; + AptControlImplementation _controlImpl; + AptControlInterface _controlIntf; + ImplInitializer _superClass; + ArrayList _reflectFields; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ImplInitializer.vm b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ImplInitializer.vm new file mode 100644 index 0000000..86f2f3b --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/ImplInitializer.vm @@ -0,0 +1,281 @@ +## +## The Velocity code generation template for the Initializer class generated from a Control +## implementation class +## +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## +## $Header:$ +## +## The following context variables are used by this template: +## $init - a ImplInitializer instance that defines the attributes of the intializer +## +## The actual class template apears at the end of this file, and is preceded by a number of +## supporting macros that define elements of the template. +## +## SUPPORTING MACROS +## +## +## This macro defines any static final Field values needed for field initialization +## +#macro (declareReflectFields) + #foreach ($field in $init.reflectFields) + static final Field $field.reflectField; + #end +#end +## +## This macro initializes the value of any static final Field values for field initialization +## +#macro (initReflectFields) + try + { + #foreach ($field in $init.reflectFields) + $field.reflectField = ${impl.className}.class.getDeclaredField("$field.name"); + ${field.reflectField}.setAccessible(true); + #end + } + catch (NoSuchFieldException __bc_nsfe) + { + throw new ExceptionInInitializerError(__bc_nsfe); + } +#end +## +## This macro declares a new event adaptor class that maps events from an EventSet to +## a set of implemented handlers on a control implementation +## +#macro (declareEventAdaptor $adaptor) + #set ($eventSet = $adaptor.eventSet) + protected static class $adaptor.className implements $eventSet.className, java.io.Serializable + { + private static final long serialVersionUID = 1L; + + $impl.className __bc_impl; + + ${adaptor.className}($impl.className impl) { __bc_impl = impl; } + + #foreach ($event in $eventSet.events) + public ${event.returnType} ${event.name}(${event.argDecl}) $event.throwsClause + { + #if ($adaptor.hasHandler($event)) + #if ($event.returnType != "void") return #end __bc_impl.${adaptor.getHandler($event).name}(${event.argList}); + #elseif ($event.returnType != "void") + return $event.defaultReturnValue; + #end + } + #end + } + +#end +## +## This macros declares any generated class that act as event adaptors between an event +## source (control or context) and implementation class event handlers. +## +#macro (declareEventAdaptors) + #foreach ($context in $impl.contexts) + #foreach ($adaptor in $context.eventAdaptors) + #declareEventAdaptor($adaptor) + #end + #end +#end +## +## This macro initializes any event adaptors for a nested control +## +#macro (initEventAdaptors $control) + #foreach ($adaptor in $control.eventAdaptors) + ${control.localName}.${adaptor.eventSet.addListenerMethod}(new ${adaptor.className}(__bc_impl)); + #end +#end +## +## This macro defines the initialization of a contextual service +## +#macro (initContext $context) + #if ($context.getType().equals("org.apache.beehive.controls.api.context.ControlBeanContext")) + $context.type $context.localName = __bc_beanContext; + #else + $context.type $context.localName = ($context.type)__bc_beanContext.getService(${context.type}.class, null); + #end + if ($context.localName == null) + throw new ControlException("Contextual service $context.type is not available"); + #initEventAdaptors($context) + #if ($init.needsReflection($context)) + ${context.reflectField}.set(__bc_impl, $context.localName); + #else + __bc_impl.$context.name = $context.localName; + #end +#end +## +## This macro defines the initialization of a contextual service +## +#macro (resetContext $context) + #if ($init.needsReflection($context)) + ${context.reflectField}.set(__bc_impl, null); + #else + __bc_impl.$context.name = null; + #end +#end +## +## This macro defines the initialization of a event notification proxy +## +#macro (initEventProxy $proxy) + $proxy.className $proxy.localName = ($proxy.className)getEventNotifier(bean, ${proxy.className}.class); + #if ($init.needsReflection($proxy)) + ${proxy.reflectField}.set(__bc_impl, $proxy.localName); + #else + __bc_impl.$proxy.name = $proxy.localName; + #end +#end +## +## This macro defines the initialization method for all nested contextual services +## +#macro (declareServiceInit) + /** + * Initializes the nested contextual services required by the implementation + */ + public void initServices(ControlBean bean, Object target) + { + $impl.className __bc_impl = ($impl.className)target; + + super.initServices(bean, __bc_impl); + + ControlBeanContext __bc_beanContext = bean.getControlBeanContext(); + try + { + #foreach ($context in $impl.contexts) + #initContext($context) + #end + } + catch (RuntimeException __bc_re) { throw __bc_re; } + catch (Exception __bc_e) + { + throw new ControlException("Contextual service initialization failure", __bc_e); + } + } + + /** + * Resets all nested contextual services instances to null + */ + public void resetServices(ControlBean bean, Object target) + { + $impl.className __bc_impl = ($impl.className)target; + + super.resetServices(bean, __bc_impl); + + try + { + #foreach ($context in $impl.contexts) + #resetContext($context) + #end + } + catch (RuntimeException __bc_re) { throw __bc_re; } + catch (Exception __bc_e) + { + throw new ControlException("Contextual service reset failure", __bc_e); + } + } +#end +## +## This macro defines the initialization method for all nested control references +## +#macro (declareControlsInit) + /** + * Initializes the nested client event proxies required by the implementation + */ + public void initControls(ControlBean bean, Object target) + { + $impl.className __bc_impl = ($impl.className)target; + // DO NOT DELEGATE TO SUPERCLASS HERE. THE CONTROL CLIENT INIT HIERARCHY + // WILL INITIALIZE ALL THE WAY DOWN TO THE BASE CLASS! + + try + { + ${init.clientInitializerName}.initialize(bean.getControlBeanContext(), __bc_impl); + } + catch (RuntimeException __bc_re) { throw __bc_re; } + catch (Exception __bc_e) + { + throw new ControlException("Client event proxy initialization failure", __bc_e); + } + } +#end +## +## This macro defines the initialization method for all nested event proxies +## +#macro (declareEventProxyInit) + /** + * Initializes the nested client event proxies required by the implementation + */ + public void initEventProxies(ControlBean bean, Object target) + { + $impl.className __bc_impl = ($impl.className)target; + + super.initEventProxies(bean, __bc_impl); + + try + { + #foreach ($proxy in $impl.clients) + #initEventProxy($proxy) + #end + } + catch (RuntimeException __bc_re) { throw __bc_re; } + catch (Exception __bc_e) + { + throw new ControlException("Client event proxy initialization failure", __bc_e); + } + } +#end +## +## THE CONTROL INITIALIZER CLASS TEMPLATE +## +#if (!$init.isRootPackage()) +package $init.package; +#end + +import java.lang.reflect.Field; +import org.apache.beehive.controls.api.ControlException; +import org.apache.beehive.controls.api.context.ControlBeanContext; +import org.apache.beehive.controls.runtime.bean.ControlBean; + +@SuppressWarnings("all") +public class $init.shortName + #if ($init.hasSuperClass()) + extends $init.superClass.className + #else + extends org.apache.beehive.controls.runtime.bean.ImplInitializer + #end +{ + #if ($init.reflectFields.size() != 0) + #declareReflectFields() + static + { + #initReflectFields() + } + #end + + #if ($impl.hasContexts() || $impl.hasClients()) + #declareEventAdaptors() + #end + + #if ($impl.hasContexts()) + #declareServiceInit() + #end + + #if ($impl.hasControls()) + #declareControlsInit() + #end + + #if ($impl.hasClients()) + #declareEventProxyInit() + #end +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/IndentingWriter.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/IndentingWriter.java new file mode 100644 index 0000000..d4adaaf --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/IndentingWriter.java @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +import java.io.IOException; +import java.io.Writer; + +/** + * The IndentingWriter class is a simple implementation of an indenting code writer + */ +public class IndentingWriter extends Writer +{ + /** current depth: + *

    +     * // depth = 0;
    +     * {
    +     *   // depth now is 2
    +     *   {
    +     *     // depth now is 4
    +     *   }
    +     *   // depth now is 2
    +     * }
    +     * // depth now is 0
    +     * 
    + */ + protected int depth = 0; + + public IndentingWriter(Writer delegate) + { + this(delegate, + Integer.getInteger("org.apache.beehive.controls.runtime.generator.indentLevel", 4).intValue()); + } + + public IndentingWriter(Writer delegate, int indentLevel) + { + _out = delegate; + this._indentLevel = indentLevel; + } + + public void write(char cbuf[], int off, int len) throws IOException + { + if (off < 0 || off + len > cbuf.length) + throw new ArrayIndexOutOfBoundsException(); + + for (int i = off; i < off + len; i++) + { + char c = cbuf[i]; + if (c == '}') + { + decrDepth(); + } + else if ((c == ' ' || c == '\t') && _needIndent) + { + continue; + } + + if (_needIndent) + indent(); + _out.write(c); + + if (c == '\n') + { + _needIndent = true; + } + else if (c == '{') + { + incrDepth(); + } + } + } + + public void flush() throws IOException + { + _out.flush(); + } + + public void close() throws IOException + { + _out.close(); + } + + private void indent() throws IOException + { + for (int i = 0; i < depth; i++) + { + _out.write(' '); + } + _needIndent = false; + } + + private void incrDepth() + { + depth += _indentLevel; + } + + private void decrDepth() + { + depth -= _indentLevel; + if (depth < 0) + depth = 0; + } + + protected Writer _out; + protected int _indentLevel; + private boolean _needIndent = false; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/VelocityAptLogSystem.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/VelocityAptLogSystem.java new file mode 100644 index 0000000..43b4488 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/VelocityAptLogSystem.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +import org.apache.velocity.runtime.RuntimeServices; +import org.apache.velocity.runtime.log.LogSystem; + +import com.sun.mirror.apt.Messager; + +/** + * The VelocityAptLogSystem implements the org.apache.velocity.runtime.LogSystem + * interface for logging messages from Velocity and routes warnings and errors to the log + * system of APT. + */ +public class VelocityAptLogSystem implements LogSystem +{ + /** + * This is the name of the Velocity configuration property that will be used to pass + * the APT environment from the execution environment into the logger instance. This + * property must be set on the VelocityEngine instance, and the value should be the + * com.sun.mirror.apt.Messager instance that should be used to log messages. + */ + static final String APT_ENV_PROPERTY = VelocityAptLogSystem.class + "." + "environment"; + + /** + * The prefix to apply to Velocity error and warnings before passing to APT, to make it + * easier to identify Velocity output + */ + static final private String MESSAGE_PREFIX = "VELOCITY: "; + + /** + * This can be set to true when debugging Velocity codegen templates to have all output + * from Velocity sent to the APT logger + */ + static final private boolean _debugging = false; + + public VelocityAptLogSystem(Messager messager) + { + _messager = messager; + } + + public void init(RuntimeServices rs) throws java.lang.Exception + { + } + + public void logVelocityMessage(int level, java.lang.String message) + { + if (level == LogSystem.ERROR_ID) + _messager.printError(MESSAGE_PREFIX + message); + else if (level == LogSystem.WARN_ID) + _messager.printWarning(MESSAGE_PREFIX + message); + else if (_debugging) + _messager.printNotice(MESSAGE_PREFIX + message); + } + + Messager _messager; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/VelocityGenerator.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/VelocityGenerator.java new file mode 100644 index 0000000..81be05a --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/VelocityGenerator.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator; + +import java.io.Writer; +import java.util.HashMap; + +import org.apache.velocity.VelocityContext; +import org.apache.velocity.Template; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader; + +import com.sun.mirror.apt.AnnotationProcessorEnvironment; + +/** + * The VelocityGenerator class is an implementation of CodeGenerator that uses standard + * Apache Velocity classes from the system classpath. + */ +public class VelocityGenerator extends CodeGenerator +{ + public VelocityGenerator(AnnotationProcessorEnvironment env) throws Exception + { + super(); + + // Create a Velocity engine instance to support codgen + _ve = new VelocityEngine(); + _ve.setProperty(VelocityEngine.RESOURCE_LOADER, "class"); + _ve.setProperty("class." + VelocityEngine.RESOURCE_LOADER + ".class", + ClasspathResourceLoader.class.getName()); + _ve.setProperty("velocimacro.library", + "org/apache/beehive/controls/runtime/generator/ControlMacros.vm"); + + // Use the VelocityAptLogSystem to bridge Velocity warnings and errors back to APT + VelocityAptLogSystem logger = new VelocityAptLogSystem(env.getMessager()); + _ve.setProperty(VelocityEngine.RUNTIME_LOG_LOGSYSTEM, logger); + + _ve.init(); + } + + /** + * Implementation of the CodeGenerator.generate() method, using standard Velocity + * package naming conventions and the system class loader + */ + public void generate(GeneratorOutput genOut) throws CodeGenerationException + { + // + // Create a new VelocityContext + // + VelocityContext vc = new VelocityContext(); + + // + // Transfer any code generation properties excepted by the templates into the context + // + HashMap genContext = genOut.getContext(); + for(String key : genContext.keySet()) + vc.put(key, genContext.get(key)); + + try + { + Writer genWriter = genOut.getWriter(); + Template template = getTemplate(genOut.getTemplateName()); + template.merge(vc, genWriter); + genWriter.close(); + } + // never wrap RuntimeException + catch (RuntimeException re) { + throw re; + } + catch (Exception e) { + throw new CodeGenerationException(e); + } + } + + // + // Returns the requested template, and caches the result for subsequent requests using the + // same template. + // + public Template getTemplate(String templateName) throws Exception + { + if (_templateMap.containsKey(templateName)) + return _templateMap.get(templateName); + + Template t = _ve.getTemplate(templateName); + _templateMap.put(templateName, t); + return t; + } + + private HashMap _templateMap = new HashMap(); + private VelocityEngine _ve; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/AnnotationConstraintAptValidator.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/AnnotationConstraintAptValidator.java new file mode 100644 index 0000000..0a3d2a7 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/AnnotationConstraintAptValidator.java @@ -0,0 +1,187 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator.apt; + +import java.io.File; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.beehive.controls.api.bean.AnnotationMemberTypes; +import org.apache.beehive.controls.api.bean.AnnotationConstraints.MembershipRule; +import org.apache.beehive.controls.api.bean.AnnotationConstraints.MembershipRuleValues; +import org.apache.beehive.controls.api.properties.PropertyKey; +import org.apache.beehive.controls.api.properties.PropertySet; +import org.apache.beehive.controls.runtime.bean.AnnotationConstraintValidator; + +import com.sun.mirror.declaration.AnnotationMirror; +import com.sun.mirror.declaration.AnnotationTypeDeclaration; +import com.sun.mirror.declaration.AnnotationTypeElementDeclaration; +import com.sun.mirror.declaration.AnnotationValue; +import com.sun.mirror.declaration.Declaration; +import com.sun.mirror.declaration.MethodDeclaration; +import com.sun.mirror.declaration.TypeDeclaration; +import com.sun.mirror.type.AnnotationType; + +/** + * This class is for validating control property values at build time + * It calls {@link org.apache.beehive.controls.runtime.bean.AnnotationConstraintValidator + * AnnotationConstraintValidator} to do the validation. + */ +public class AnnotationConstraintAptValidator extends AnnotationConstraintValidator +{ + + public AnnotationConstraintAptValidator() + { + super(); + } + + /** + * This method ensures that any control property value assignment satisfies + * all property constraints. This method should be called from an annotation + * processor to ensure declarative control property assignment using + * annotations are validated at build time. This method is currently called + * from ControlAnnotationProcessor and ControlClientAnnotationProcessor. + * + * @param d + * a declaration which may contain a control property value + * assignment + * @throws IllegalArgumentException + * when the declaration contains a control property value + * assignment that does not satisfy a property constraint. + */ + public static void validate(Declaration d) throws IllegalArgumentException + { + Collection mirrors = d.getAnnotationMirrors(); + + // for each annotations defined on the declaration, if the annotation + // is a PropertySet, ensure the values assigned to the properties + // satisfy all PropertySet and PropertyType constraints. + for (AnnotationMirror m : mirrors) + { + AnnotationTypeDeclaration decl = m.getAnnotationType().getDeclaration(); + /* + when embedding this annotation processor in an IDE, the declaration + could be null when it doesn't resolve to a valid type. In this case, + just continue processing declarations. + */ + if(decl == null) { + continue; + } + else if (decl.getAnnotation(PropertySet.class) != null) + { + Iterator> i = + m.getElementValues().entrySet().iterator(); + while (i.hasNext()) + { + Map.Entry entry = + i.next(); + Collection annotations = getMemberTypeAnnotations(entry.getKey()); + if (annotations.size() > 0) + { + Annotation[] anArray = new Annotation[annotations.size()]; + annotations.toArray(anArray); + validate(anArray, entry.getValue().getValue()); + } + } + + //If a membership rule is defined on the property set, ensure the rule is satisfied. + if (decl.getAnnotation(MembershipRule.class) != null) + { + try + { + String declClassName = decl.getQualifiedName(); + + TypeDeclaration owningClass = decl.getDeclaringType(); + if (owningClass != null) + declClassName = owningClass.getQualifiedName() + "$" + decl.getSimpleName(); + + Class clazz = Class.forName(declClassName); + Annotation a = d.getAnnotation(clazz); + validateMembership(a); + } + catch (ClassNotFoundException cnfe) + { + //should not happen + } + } + } + } + + // If the declaration is a class or interface, validate its methods + // and fields. + if (d instanceof TypeDeclaration) + { + TypeDeclaration td = ((TypeDeclaration) d); + for (Declaration md : td.getMethods()) + validate(md); + for (Declaration fd : td.getFields()) + validate(fd); + } + // If the delcaration is a method, validate its parameters. + else if (d instanceof MethodDeclaration) + { + for (Declaration pd : ((MethodDeclaration) d).getParameters()) + validate(pd); + } + + } + + private static Collection getMemberTypeAnnotations(Declaration decl) + { + Collection annotations = new ArrayList(); + for (AnnotationMirror am : decl.getAnnotationMirrors()) + { + AnnotationType at = am.getAnnotationType(); + try + { + if (at.getContainingType() == null) + continue; + String containingClassName = at.getContainingType() + .getDeclaration().getQualifiedName(); + if (containingClassName.equals(AnnotationMemberTypes.class + .getName())) + { + String memberTypeName = at.getDeclaration().getSimpleName(); + Class clazz = Class.forName(containingClassName + "$" + + memberTypeName); + Annotation a = decl.getAnnotation(clazz); + if (null != a) + { + annotations.add(a); + } + } + } + catch (ClassNotFoundException e) + { + } + } + return annotations; + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/CheckerAnnotationProcessorEnvironmentImpl.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/CheckerAnnotationProcessorEnvironmentImpl.java new file mode 100644 index 0000000..e993fce --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/CheckerAnnotationProcessorEnvironmentImpl.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator.apt; + +import com.sun.mirror.apt.AnnotationProcessorEnvironment; +import com.sun.mirror.apt.AnnotationProcessorListener; +import com.sun.mirror.apt.Filer; +import com.sun.mirror.apt.Messager; +import com.sun.mirror.declaration.AnnotationTypeDeclaration; +import com.sun.mirror.declaration.Declaration; +import com.sun.mirror.declaration.PackageDeclaration; +import com.sun.mirror.declaration.TypeDeclaration; +import com.sun.mirror.util.Declarations; +import com.sun.mirror.util.Types; + +import java.util.Collection; +import java.util.Map; + +/** + * Wrapper for an AnnotationProcessorEnvironment instance. + * Keeps track of errors / warnings logged. + */ +public final class CheckerAnnotationProcessorEnvironmentImpl implements AnnotationProcessorEnvironment { + private final AnnotationProcessorEnvironment _aptEnv; + private final CheckerMessagerImpl _messager; + + /** + * @param aptDiagnostics + */ + public CheckerAnnotationProcessorEnvironmentImpl(Diagnostics aptDiagnostics) { + _aptEnv = aptDiagnostics.getAnnotationProcessorEnvironment(); + _messager = new CheckerMessagerImpl(_aptEnv.getMessager(), aptDiagnostics); + } + + /** + * Get the number of errors sent to the messager. + * + * @return Number of errors. + */ + public int getErrorCount() { + return _messager.getErrorCount(); + } + + /** + * Get the number of warnings sent to the messager. + * + * @return Number of warnings. + */ + public int getWarningCount() { + return _messager.getWarningCount(); + } + + public Messager getMessager() { + return _messager; + } + + public Filer getFiler() { + return _aptEnv.getFiler(); + } + + public Map getOptions() { + return _aptEnv.getOptions(); + } + + public Collection getSpecifiedTypeDeclarations() { + return _aptEnv.getSpecifiedTypeDeclarations(); + } + + public PackageDeclaration getPackage(String string) { + return _aptEnv.getPackage(string); + } + + public TypeDeclaration getTypeDeclaration(String string) { + return _aptEnv.getTypeDeclaration(string); + } + + public Collection getTypeDeclarations() { + return _aptEnv.getTypeDeclarations(); + } + + public Declarations getDeclarationUtils() { + return _aptEnv.getDeclarationUtils(); + } + + public Types getTypeUtils() { + return _aptEnv.getTypeUtils(); + } + + public void addListener(AnnotationProcessorListener listener) { + _aptEnv.addListener(listener); + } + + public void removeListener(AnnotationProcessorListener listener) { + _aptEnv.removeListener(listener); + } + + public Collection getDeclarationsAnnotatedWith(AnnotationTypeDeclaration typeDeclaration) { + return _aptEnv.getDeclarationsAnnotatedWith(typeDeclaration); + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/CheckerMessagerImpl.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/CheckerMessagerImpl.java new file mode 100644 index 0000000..daacdba --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/CheckerMessagerImpl.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator.apt; + +import com.sun.mirror.apt.Messager; +import com.sun.mirror.util.SourcePosition; + +/** + * Wrap a com.sun.mirror.apt.Messager instance to track errors and warnings. + */ +public final class CheckerMessagerImpl implements Messager { + private final Messager _messager; + private final Diagnostics _aptDiagnostics; + private int _errorCount; + private int _warningCount; + + + /** + * Constructor. + * + * @param messager Messager to wrap. + */ + CheckerMessagerImpl(Messager messager, Diagnostics aptDiagnostics) { + _messager = messager; + _aptDiagnostics = aptDiagnostics; + _errorCount = _warningCount = 0; + } + + /** + * Get the number of errors sent to this messager. + * + * @return Number of errors. + */ + int getErrorCount() { + return _errorCount; + } + + /** + * Get the number of warnings sent to this messager. + * + * @return Number of warnings. + */ + int getWarningCount() { + return _warningCount; + } + + public void printError(String string) { + _errorCount++; + _aptDiagnostics.setHasErrors(true); + _messager.printError(string); + } + + public void printError(SourcePosition sourcePosition, String string) { + _errorCount++; + _aptDiagnostics.setHasErrors(true); + _messager.printError(sourcePosition, string); + } + + public void printWarning(String string) { + _warningCount++; + _messager.printWarning(string); + } + + public void printWarning(SourcePosition sourcePosition, String string) { + _warningCount++; + _messager.printWarning(sourcePosition, string); + } + + public void printNotice(String string) { + _messager.printNotice(string); + } + + public void printNotice(SourcePosition sourcePosition, String string) { + _messager.printNotice(sourcePosition, string); + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/ControlAnnotationProcessor.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/ControlAnnotationProcessor.java new file mode 100644 index 0000000..aee20ff --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/ControlAnnotationProcessor.java @@ -0,0 +1,166 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator.apt; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Set; + +import com.sun.mirror.apt.AnnotationProcessorEnvironment; +import com.sun.mirror.declaration.AnnotationTypeDeclaration; +import com.sun.mirror.declaration.Declaration; + +import org.apache.beehive.controls.api.bean.ControlExtension; +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.properties.PropertySet; + +import org.apache.beehive.controls.runtime.generator.*; + +public class ControlAnnotationProcessor extends TwoPhaseAnnotationProcessor +{ + public ControlAnnotationProcessor(Set atds, + AnnotationProcessorEnvironment env) + { + super(atds, env); + } + + @Override + public void check(Declaration decl) + { + AnnotationProcessorEnvironment env = getAnnotationProcessorEnvironment(); + Generator genClass = null; + if (decl.getAnnotation(ControlInterface.class) != null) + { + genClass = new AptControlInterface(decl, this); + } + else if (decl.getAnnotation(ControlExtension.class) != null) + { + genClass = new AptControlInterface(decl, this); + + // When a control extension is declared, values may be assigned to + // the properties of the parent controls. The property constraint + // validator is called here to ensure all values assigned satisfy any + // constraints declared in the properties. + try + { + AnnotationConstraintAptValidator.validate(decl); + } + catch (IllegalArgumentException iae) + { + printError(decl, "propertyset.illegal.argument.error", iae.getMessage()); + } + + } + else if (decl.getAnnotation(ControlImplementation.class) != null) + { + genClass = new AptControlImplementation(decl, this); + } + else if (decl.getAnnotation(PropertySet.class) != null) + { + new AptPropertySet(null, decl, this); + } + + if ( genClass != null && !hasErrors() ) + { + try + { + List genList = genClass.getCheckOutput(env.getFiler()); + if (genList == null || genList.size() == 0) + return; + + for (GeneratorOutput genOut : genList) + { + getGenerator().generate(genOut); + } + } + catch (IOException ioe) + { + throw new CodeGenerationException("Code generation failure: ", ioe); + } + } + } + + @Override + public void generate(Declaration decl) + { + AnnotationProcessorEnvironment env = getAnnotationProcessorEnvironment(); + Generator genClass = null; + if (decl.getAnnotation(ControlInterface.class) != null) + { + genClass = new AptControlInterface(decl, this); + } + if (decl.getAnnotation(ControlExtension.class) != null) + { + genClass = new AptControlInterface(decl, this); + } + else if (decl.getAnnotation(ControlImplementation.class) != null) + { + genClass = new AptControlImplementation(decl, this); + } + + if ( genClass != null ) + { + try + { + List genList = genClass.getGenerateOutput(env.getFiler()); + if (genList == null || genList.size() == 0) + return; + + for (GeneratorOutput genOut : genList) + { + getGenerator().generate(genOut); + } + } + catch (IOException ioe) + { + throw new CodeGenerationException("Code generation failure: ", ioe); + } + } + } + + /** + * Returns the CodeGenerator instance supporting this processor, instantiating a new + * generator instance if necessary. + */ + protected CodeGenerator getGenerator() + { + if (_generator == null) + { + // + // Locate the class that wraps the Velocity code generation process + // + AnnotationProcessorEnvironment env = getAnnotationProcessorEnvironment(); + + try + { + _generator = new VelocityGenerator(env); + } + catch (Exception e) + { + throw new CodeGenerationException("Unable to create code generator", e); + } + } + return _generator; + } + + HashMap _typeMap = new HashMap(); + CodeGenerator _generator; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/ControlAnnotationProcessorFactory.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/ControlAnnotationProcessorFactory.java new file mode 100644 index 0000000..0f047f7 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/ControlAnnotationProcessorFactory.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator.apt; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Set; + +import com.sun.mirror.apt.AnnotationProcessor; +import com.sun.mirror.apt.AnnotationProcessorFactory; +import com.sun.mirror.apt.AnnotationProcessorEnvironment; +import com.sun.mirror.declaration.AnnotationTypeDeclaration; + +public class ControlAnnotationProcessorFactory implements AnnotationProcessorFactory +{ + private static final Collection _supportedAnnotations = + Collections.unmodifiableCollection( + Arrays.asList(new String[] { + org.apache.beehive.controls.api.bean.ControlInterface.class.getName(), + org.apache.beehive.controls.api.bean.ControlExtension.class.getName(), + org.apache.beehive.controls.api.bean.ControlImplementation.class.getName(), + org.apache.beehive.controls.api.properties.PropertySet.class.getName() + })); + + private static final Collection _supportedOptions = + Collections.unmodifiableCollection( + Arrays.asList(new String[] { + "-AcontrolGenerator", // sets CodeGenerator class + })); + + public Collection supportedOptions() + { + return _supportedOptions; + } + + public Collection supportedAnnotationTypes() + { + return _supportedAnnotations; + } + + public AnnotationProcessor getProcessorFor(Set atds, + AnnotationProcessorEnvironment env) + { + return new ControlAnnotationProcessor(atds, env); + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/ControlClientAnnotationProcessor.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/ControlClientAnnotationProcessor.java new file mode 100644 index 0000000..b6837c4 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/ControlClientAnnotationProcessor.java @@ -0,0 +1,663 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator.apt; + +import java.util.Set; +import java.util.Map; +import java.util.HashSet; +import java.util.HashMap; +import java.util.Collection; +import java.util.List; +import java.util.LinkedList; +import java.util.Queue; +import java.io.File; +import java.io.IOException; +import com.sun.mirror.apt.AnnotationProcessorEnvironment; +import com.sun.mirror.apt.Filer; +import com.sun.mirror.declaration.AnnotationTypeDeclaration; +import com.sun.mirror.declaration.FieldDeclaration; +import com.sun.mirror.declaration.TypeDeclaration; +import com.sun.mirror.declaration.Declaration; +import com.sun.mirror.declaration.Modifier; +import com.sun.mirror.declaration.ClassDeclaration; +import com.sun.mirror.declaration.AnnotationValue; +import com.sun.mirror.declaration.AnnotationMirror; +import com.sun.mirror.declaration.InterfaceDeclaration; +import com.sun.mirror.type.TypeMirror; +import com.sun.mirror.type.ClassType; +import com.sun.mirror.type.InterfaceType; +import com.sun.mirror.type.DeclaredType; + +import org.apache.beehive.controls.runtime.bean.ControlUtils; +import org.apache.beehive.controls.runtime.generator.CodeGenerationException; +import org.apache.beehive.controls.runtime.generator.AptAnnotationHelper; +import org.apache.beehive.controls.runtime.generator.AptControlClient; +import org.apache.beehive.controls.runtime.generator.GeneratorOutput; +import org.apache.beehive.controls.runtime.generator.Generator; +import org.apache.beehive.controls.runtime.generator.VelocityGenerator; +import org.apache.beehive.controls.runtime.generator.CodeGenerator; +import org.apache.beehive.controls.api.versioning.Version; +import org.apache.beehive.controls.api.versioning.VersionRequired; +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.bean.ControlExtension; + +public class ControlClientAnnotationProcessor + extends TwoPhaseAnnotationProcessor { + + public ControlClientAnnotationProcessor(Set atds, AnnotationProcessorEnvironment env ) { + super( atds,env ); + } + + @Override + public void check( Declaration d ) + { + if ( d instanceof FieldDeclaration ) + checkControlField( (FieldDeclaration)d ); + + // if @Control is used on something other than a field, the Java lang + // checker should produce an error due to the @Target violation. + + if ( d instanceof TypeDeclaration ) + checkControlClientType( (TypeDeclaration)d ); + + // When a control is instantiated declaratively, values may be assigned to + // the control's properties declaratively as well. The property constraint + // validator is called here to ensure all values assigned satisfy any + // constraints declared in the properties. + try + { + AnnotationConstraintAptValidator.validate(d); + } + catch (IllegalArgumentException iae) + { + printError(d, "propertyset.illegal.argument.error", iae.getMessage()); + } + } + + private static void addControlType(Map> clientsMap, TypeDeclaration clientType, + TypeMirror controlFieldType) + { + Set controlTypes = clientsMap.get( clientType ); + + if ( controlTypes == null ) + { + controlTypes = new HashSet(); + clientsMap.put( clientType, controlTypes ); + } + + controlTypes.add( controlFieldType ); + } + + /** + * Each control client requires a manifest that documents the controls that it references. + * + * @throws CodeGenerationException + */ + @Override + public void generate() throws CodeGenerationException + { + super.generate(); + + /* + The annotation processor may be passed multiple control client types. Build a map that + links each control client type with the set of control types that it uses. + */ + + Map> clientsMap = new HashMap>(); + + for (AnnotationTypeDeclaration atd : _atds) + { + if (atd.getSimpleName().equals("Control") ) + { + AnnotationProcessorEnvironment env = getAnnotationProcessorEnvironment(); + Collection decls = env.getDeclarationsAnnotatedWith(atd); + for (Declaration decl : decls) + { + if ( decl instanceof FieldDeclaration ) + { + FieldDeclaration fd = (FieldDeclaration)decl; + TypeDeclaration clientType = fd.getDeclaringType(); + TypeMirror controlFieldType = fd.getType(); + addControlType( clientsMap, clientType, controlFieldType ); + + /* + Add the control type to any derived class. Fields with + private and default (package) access are also included + here as the controls in superclasses may be exposed + through public or protected methods to subclasses. + */ + Collection specifiedTypeDeclartions = env.getSpecifiedTypeDeclarations(); + for (TypeDeclaration td : specifiedTypeDeclartions) + { + if (td instanceof ClassDeclaration) + { + ClassType superclass = ((ClassDeclaration) td).getSuperclass(); + while (superclass != null) + { + if (superclass.getDeclaration().equals(clientType)) + { + addControlType(clientsMap, td, controlFieldType); + break; + } + + superclass = superclass.getSuperclass(); + } + } + } + } + } + } + else if (atd.getSimpleName().equals("ControlReferences")) + { + Collection decls = getAnnotationProcessorEnvironment().getDeclarationsAnnotatedWith(atd); + for (Declaration decl : decls) + { + if ( decl instanceof TypeDeclaration ) + { + TypeDeclaration clientType = (TypeDeclaration)decl; + Set controlTypes = clientsMap.get( clientType ); + if ( controlTypes == null ) + { + controlTypes = new HashSet(); + clientsMap.put( clientType, controlTypes ); + } + + // Read ControlReferences annotation + AnnotationMirror controlMirror = null; + for (AnnotationMirror annot : clientType.getAnnotationMirrors()) + { + if (annot.getAnnotationType().getDeclaration().getQualifiedName().equals( + "org.apache.beehive.controls.api.bean.ControlReferences")) + { + controlMirror = annot; + break; + } + } + + assert( controlMirror != null ); + + // Add each control type listed in the ControlReferences annotation + AptAnnotationHelper controlAnnot = new AptAnnotationHelper(controlMirror); + Collection references = (Collection)controlAnnot.getObjectValue("value"); + if ( references != null ) + { + for ( AnnotationValue av : references ) + { + TypeMirror crType = (TypeMirror)av.getValue(); + controlTypes.add( crType ); + } + } + } + } + } + } + + // For each client type: + // 1 - emit a controls client manifest in the same dir as the client type's class. + // 2 - emit a controls client initializer class in the same pkg/dir as the client type's class + + Filer f = getAnnotationProcessorEnvironment().getFiler(); + Set clientTypes = clientsMap.keySet(); + for ( TypeDeclaration clientType : clientTypes ) + { + // Emit manifest + + String clientPkg = clientType.getPackage().getQualifiedName(); + File clientManifestName = + new File( clientType.getSimpleName() + ControlClientManifest.FILE_EXTENSION ); + + ControlClientManifest mf = new ControlClientManifest( clientType.getQualifiedName() ); + + try + { + Set controlTypes = clientsMap.get( clientType ); + for ( TypeMirror controlType : controlTypes ) + { + InterfaceDeclaration controlIntfOrExt = getControlInterfaceOrExtension(controlType); + InterfaceDeclaration controlIntf = getMostDerivedControlInterface( controlIntfOrExt ); + + assert controlIntf != null : "Can't find most derived control intf for=" + controlIntfOrExt; + + ControlInterface annot = controlIntf.getAnnotation(ControlInterface.class); + String defBinding = annot.defaultBinding(); + + defBinding = ControlUtils.resolveDefaultBinding( defBinding, controlIntf.getQualifiedName() ); + + mf.addControlType( controlIntfOrExt.getQualifiedName(), defBinding ); + } + + mf.emit( f, clientPkg, clientManifestName, null ); + } + catch ( IOException ie ) + { + printError( clientType, "controls.client.manifest.ioerror" ); + ie.printStackTrace( ); + } + + // Emit initializer + + AnnotationProcessorEnvironment env = getAnnotationProcessorEnvironment(); + Generator genClass = new AptControlClient( clientType, this ); + + if ( genClass != null ) + { + try + { + List genList = genClass.getGenerateOutput(env.getFiler()); + if (genList == null || genList.size() == 0) + return; + + for (GeneratorOutput genOut : genList) + { + getGenerator().generate(genOut); + } + } + catch (IOException ioe) + { + throw new CodeGenerationException("Code generation failure: ", ioe); + } + } + } + } + + @Override + public void generate(Declaration decl) + { + } + + private void checkControlField( FieldDeclaration f ) + { + TypeMirror fieldType = f.getType(); + + // Make sure that this field doesn't try to override another that's inherited. + String fieldName = f.getSimpleName(); + TypeDeclaration declaringType = f.getDeclaringType(); + + if ( declaringType instanceof ClassDeclaration ) + { + for ( ClassType i = ( ( ClassDeclaration ) declaringType ).getSuperclass(); i != null; i = i.getSuperclass() ) + { + ClassDeclaration decl = i.getDeclaration(); + + if ( decl != null ) + { + for ( FieldDeclaration baseClassField : decl.getFields() ) + { + if ( fieldName.equals( baseClassField.getSimpleName() ) ) + { + Collection modifiers = baseClassField.getModifiers(); + + if ( modifiers.contains( Modifier.PROTECTED ) || modifiers.contains( Modifier.PUBLIC ) ) + { + printError( f, "control.field.override", decl.getQualifiedName() ); + } + } + } + } + } + } + + // Valid control field instances can be of an interface type + // or a class type. + if ( fieldType instanceof InterfaceType ) + { + // Valid interface type decls must be annotated w/ @ControlInterface + // or @ControlExtension. + Declaration fieldTypeDecl = ((InterfaceType)fieldType).getDeclaration(); + if ( fieldTypeDecl.getAnnotation(ControlInterface.class) == null && + fieldTypeDecl.getAnnotation(ControlExtension.class) == null ) + printError( f, "control.field.bad.interfacetype" ); + } + else if ( fieldType instanceof ClassType ) + { + // Valid class type decls must implements the ControlBean API. + + // Walk the implementation inheritance hierarchy, seeing if one of the + // classes implements ControlBean. + // + // REVIEW: Does NOT check if the interfaces might implement ControlBean! + // This is unnecessary for our impl, since our generated bean class directly + // implements ControlBean, but other impls may choose to do otherwise. + boolean foundControlBean = false; + ClassType classType = (ClassType)fieldType; + + if (classType.getDeclaration() != null) + { + outer: while ( classType != null ) + { + Collection intfs = classType.getSuperinterfaces(); + for ( InterfaceType intfType : intfs ) + { + if ( intfType.getDeclaration().getQualifiedName().equals( "org.apache.beehive.controls.api.bean.ControlBean" ) ) + { + foundControlBean = true; + break outer; + } + } + classType = classType.getSuperclass(); + } + if ( !foundControlBean ) + printError( f, "control.field.bad.classtype" ); + + // Valid generated beans should only "implement" the control interface/extension, and no others + classType = (ClassType)fieldType; + Collection intfs = classType.getSuperinterfaces(); + if ( intfs.size() != 1 ) + { + printError( f, "control.field.bad.classtype.badinterface" ); + } + + for ( InterfaceType intfType : intfs ) + { + if ( intfType.getDeclaration().getAnnotation(ControlExtension.class) == null && + intfType.getDeclaration().getAnnotation(ControlInterface.class) == null) + { + printError( f, "control.field.bad.classtype.badinterface"); + } + } + } + else + { + // TODO: This could be a ControlBean type that is going to be generated by + // the current APT processing iteration. It should be possible to do more + // specific verification here using the getTypeDeclaration API on + // AnnotationProcessorEnvironment. In any event, the implementation of + // getControlInterface will properly handle this case, and if it cannot a + // malformed type error will be generated. + } + } + else + { + printError( f, "control.field.bad.type" ); + } + + // Enforce any versioning requirements this control field has. + // + // Since our generate() does some detailed grovelling of control types, make sure that + // will not result in an error by doing that grovelling now. Control types may be + // malformed if the source for those types has errors (yet the apt type may still exist!). + try + { + InterfaceDeclaration controlIntfOrExt = getControlInterfaceOrExtension(fieldType); + InterfaceDeclaration controlIntf = getMostDerivedControlInterface( controlIntfOrExt ); + + if ( controlIntf != null ) + { + enforceVersionRequired( f, controlIntf ); + } + else + { + printError( f, "control.field.type.malformed" ); + } + } + catch ( CodeGenerationException cge ) + { + printError( f, "control.field.type.malformed" ); + } + + assert declaringType != null : "Field " + f + " has no declaring type!"; + + if ( declaringType.getDeclaringType() != null ) + printError( f, "control.field.in.inner.class" ); + + Collection mods = f.getModifiers(); + + if ( mods.contains( Modifier.TRANSIENT )) + printError( f, "transient.control.field" ); + + if ( mods.contains( Modifier.STATIC )) + printError( f, "static.control.field" ); + + } + + private void checkControlClientType( TypeDeclaration t ) + { + // validate @ControlReferences + AnnotationMirror controlMirror = null; + + for (AnnotationMirror annot : t.getAnnotationMirrors()) + { + if (annot.getAnnotationType().getDeclaration().getQualifiedName().equals( + "org.apache.beehive.controls.api.bean.ControlReferences")) + { + controlMirror = annot; + break; + } + } + + // Bail out if no @ControlReferences annotation found + if ( controlMirror == null ) + return; + + AptAnnotationHelper controlAnnot = new AptAnnotationHelper(controlMirror); + + // + // Validate that the types listed in the ControlReferences annotations are actually + // control types. + // + + Collection references = (Collection)controlAnnot.getObjectValue("value"); + + if ( references != null ) + { + for ( AnnotationValue av : references ) + { + DeclaredType crType = (DeclaredType)av.getValue(); + if ( crType instanceof InterfaceType ) + { + // Valid interface type decls must be annotated w/ @ControlInterface + // or @ControlExtension. + Declaration typeDecl = crType.getDeclaration(); + if ( typeDecl.getAnnotation(ControlInterface.class) == null && + typeDecl.getAnnotation(ControlExtension.class) == null ) + printError( t, "control.reference.bad.interfacetype" ); + } + else { + printError( t, "control.reference.bad.interfacetype" ); + } + } + } + } + + /** + * Given a InterfaceType or ClassType, returns the InterfaceType for the control type's + * public interface/extension. + * @param intfOrBeanClass + * @return The InterfaceType for the control type's public interface/extension. + */ + private InterfaceDeclaration getControlInterfaceOrExtension( TypeMirror intfOrBeanClass ) + { + if (intfOrBeanClass instanceof InterfaceType) + { + return ((InterfaceType)intfOrBeanClass).getDeclaration(); + } + else if (intfOrBeanClass instanceof ClassType) + { + ClassType classType = (ClassType)intfOrBeanClass; + + // If the bean type declaration cannot be found, then the only (valid) possibility + // is that it is a generated type from the current processor pass. See if a base + // interface type can be determined from the current processor input list. + if (classType.getDeclaration() == null) + { + // + // Compute the bean type name, and the associated interface name by stripping + // the "Bean" suffix + // + String className = classType.toString(); + AnnotationProcessorEnvironment ape = getAnnotationProcessorEnvironment(); + InterfaceDeclaration id = null; + String intfName = null; + if (className.length() > 4) { + intfName = className.substring(0, className.length() - 4); + id = (InterfaceDeclaration)ape.getTypeDeclaration(intfName); + } + + if (id == null && intfName != null) + { + // The specified class name may not be fully qualified. In this case, the + // best we can do is look for a best fit match against the input types + for (TypeDeclaration td :ape.getSpecifiedTypeDeclarations()) + { + if (td instanceof InterfaceDeclaration && + td.getSimpleName().equals(intfName)) + { + return (InterfaceDeclaration)td; + } + } + } + return id; + } + else + { + // direct supers only + Collection intfs = classType.getSuperinterfaces(); + + // per the code in checkControlField, this set must be of size 1 + // and the 1 super interface must be a control interface/extension + // a value of zero may be valid if the control field is not referencing + // a control -- for this case fall through and return null. + assert ( intfs.size() <= 1 ); + for ( InterfaceType intfType : intfs ) + return intfType.getDeclaration(); + } + } + else + { + throw new CodeGenerationException( "Param not a interface or class type"); + } + + return null; + } + + /** + * Given a control interface or extension, do a BFS of its inheritance heirarchy for + * the first one marked with @ControlInterface. This represents the point in the + * heirarchy where use of @ControlExtension changes to use of @ControlInterface. + * + * @param controlIntfOrExt an interface annotated with @ControlInterface or @ControlExtension. + * @return most derived interface in the heirarchy annotated with @ControlInterface, null + * if no such interface found. + */ + private InterfaceDeclaration getMostDerivedControlInterface( InterfaceDeclaration controlIntfOrExt ) + { + Queue q = new LinkedList(); + + InterfaceDeclaration id = controlIntfOrExt; + while ( id != null ) + { + if ( id.getAnnotation(ControlInterface.class) != null ) + break; + + Collection supers = id.getSuperinterfaces(); + for ( InterfaceType s : supers ) + q.offer( s.getDeclaration() ); + + id = q.poll(); + } + + return id; + } + + /** + * Enforces the VersionRequired annotation for control fields. + */ + private void enforceVersionRequired( FieldDeclaration f, InterfaceDeclaration controlIntf ) + { + VersionRequired versionRequired = f.getAnnotation(VersionRequired.class); + Version versionPresent = controlIntf.getAnnotation(Version.class); + + if (versionRequired != null) { + int majorRequired = -1; + try { + majorRequired = versionRequired.major(); + } + catch(NullPointerException ignore) { + /* + the major version annotation is required and if unspecified, will + throw an NPE when it is quereid but not provided. this error will + be caught during syntactic validation perfoemed by javac, so ignore + it if an NPE is caught here + */ + return; + } + + int minorRequired = versionRequired.minor(); + + /* no version requirement, so return */ + if(majorRequired < 0) + return; + + int majorPresent = -1; + int minorPresent = -1; + if ( versionPresent != null ) + { + try { + majorPresent = versionPresent.major(); + } + catch(NullPointerException ignore) { + /* + the major version annotation is required and if unspecified, will + throw an NPE when it is quereid but not provided. this error will + be caught during syntactic validation perfoemed by javac, so ignore + it if an NPE is caught here + */ + } + + minorPresent = versionPresent.minor(); + + if ( majorRequired <= majorPresent && + (minorRequired < 0 || minorRequired <= minorPresent) ) + { + // Version requirement is satisfied + return; + } + } + + // + // Version requirement failed + // + printError( f, "control.field.bad.version", f.getSimpleName(), majorRequired, minorRequired, + majorPresent, minorPresent ); + } + } + + /** + * Returns the CodeGenerator instance supporting this processor, instantiating a new + * generator instance if necessary. + */ + protected CodeGenerator getGenerator() { + + if (_generator == null) { + /* Locate the class that wraps the Velocity code generation process */ + AnnotationProcessorEnvironment env = getAnnotationProcessorEnvironment(); + + try { + _generator = new VelocityGenerator(env); + } + catch (Exception e) { + throw new CodeGenerationException("Unable to create code generator", e); + } + } + + return _generator; + } + + CodeGenerator _generator; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/ControlClientAnnotationProcessorFactory.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/ControlClientAnnotationProcessorFactory.java new file mode 100644 index 0000000..4e6540f --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/ControlClientAnnotationProcessorFactory.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator.apt; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Set; + +import com.sun.mirror.apt.AnnotationProcessor; +import com.sun.mirror.apt.AnnotationProcessorFactory; +import com.sun.mirror.apt.AnnotationProcessorEnvironment; +import com.sun.mirror.declaration.AnnotationTypeDeclaration; + +public class ControlClientAnnotationProcessorFactory implements AnnotationProcessorFactory +{ + private static final Collection _supportedAnnotations = + Collections.unmodifiableCollection( + Arrays.asList(new String[] { + org.apache.beehive.controls.api.bean.Control.class.getName(), + org.apache.beehive.controls.api.bean.ControlReferences.class.getName() + })); + + private static final Collection _supportedOptions = + Collections.unmodifiableCollection( Arrays.asList( new String[0] ) ); + + public Collection supportedOptions() + { + return _supportedOptions; + } + + public Collection supportedAnnotationTypes() + { + return _supportedAnnotations; + } + + public AnnotationProcessor getProcessorFor(Set atds, + AnnotationProcessorEnvironment env) + { + return new ControlClientAnnotationProcessor(atds, env); + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/ControlClientManifest.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/ControlClientManifest.java new file mode 100644 index 0000000..d9db1e5 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/ControlClientManifest.java @@ -0,0 +1,253 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator.apt; + +import com.sun.mirror.apt.Filer; + +import java.io.*; +import java.util.*; + +/** + * The controls client manifest (aka "client manifest") surfaces the set of + * control types used by a client, and make the assembly process more + * efficient. The control client annotation processor generates a client + * manifest documenting the set of used control types. This manifest is a + * java.util.Properties file that specifies: + * + * - classname of the control client + * - classnames of each control type used by that control client (the set + * identified by @Control and @ControlReference usages) and the + * corresponding default implementation binding + * + * Example client manifest: + * + * FooImpl.controls.properties + * --------------------------- + * .client.name=org.acme.controls.FooImpl + * org.acme.controls.CustomerDbBean=org.apache.beehive.controls.scl.DatabaseControlImpl + * org.acme.controls.DailyTimerBean=org.apache.beehive.controls.scl.TimerControlImpl + * + * The manifest is a generated artifact and is not user-editable. Ideally, the apt + * environment optimizes the writing of the manifest such that it's only written + * to disk when changes occur (allowing external build tools to use the timestamp of + * the manifest to determine whether assembly on a client needs to occur). + */ +public class ControlClientManifest +{ + public final static String CLIENT_NAME_PROP = ".client.name"; + public final static String BEEHIVE_VERSION_PROP = ".beehive.version"; + public final static String FILE_EXTENSION = ".controls.properties"; + + /** + * Loads a ControlClientManifest from an existing manifest file. + * @param f the manifest file + * @throws FileNotFoundException + * @throws IOException + */ + public ControlClientManifest( File f ) throws FileNotFoundException, IOException + { + if ( !f.exists() ) + throw new FileNotFoundException( "Control manifest file=" + f + " not found"); + + FileInputStream fis = new FileInputStream( f ); + _properties.load( fis ); + + String client = _properties.getProperty( CLIENT_NAME_PROP ); + if ( client == null || client.equals("") ) + throw new IOException( "Control client manifest missing client name" ); + } + + /** + * Creates a new ControlClientManifest + * @param client the fully qualified classname of the control client + */ + public ControlClientManifest( String client ) + { + if ( client == null || client.equals("") ) + throw new RuntimeException( "Missing or empty client name" ); + + _properties.setProperty( CLIENT_NAME_PROP, client ); + } + + /** + * @return the name of the control client in this manifest + */ + public String getControlClient() + { + return _properties.getProperty( CLIENT_NAME_PROP ); + } + + /** + * Adds a new control type to the manifest + * @param intf fully qualified name of the control type + * @param impl fully qualified name of the default implementation for the control type + */ + public void addControlType( String intf, String impl ) + { + _properties.setProperty( intf, impl ); + } + + /** + * @return a list of all control types listed in the manifest + */ + public List getControlTypes() + { + ArrayList l = new ArrayList(); + + Set keys = _properties.keySet(); + for ( Object k : keys ) + { + String propname = (String)k; + if ( propname.equals( CLIENT_NAME_PROP ) ) + continue; + + l.add( propname ); + } + + return l; + } + + /** + * @param controlType + * @return the default implementation for the control type listed in the manifest + */ + public String getDefaultImpl( String controlType ) + { + return (String)_properties.get( controlType ); + } + + /** + * Emits the manifest via an apt Filer implementation + * @param f an apt Filer + * @param pkg the package structure to place the manifest in + * @param mf the name of the manifest + * @throws IOException + */ + public void emit( Filer f, String pkg, File mf, String csn ) throws IOException + { + PrintWriter pw = f.createTextFile( Filer.Location.CLASS_TREE, pkg, mf, csn ); + + pw.println( "# Apache Beehive Controls client manifest (auto-generated, do not edit!)"); + Set props = _properties.keySet(); + for ( Object p : props ) + { + String name = (String)p; + String value = _properties.getProperty(name); + + /* convert the name and value to a format excpected by the Properties.load() method */ + name = escapeJava(name); + if (value != null) + value = escapeJava(value); + + pw.println( name + "=" + value ); + } + + pw.flush(); + pw.close(); + } + + private static String escapeJava(String str) { + if (str == null) + return null; + + try { + StringWriter writer = new StringWriter(str.length() * 2); + escapeJavaStyleString(writer, str); + return writer.toString(); + } catch (IOException ioe) { + /* this should never ever happen while writing to a StringWriter */ + ioe.printStackTrace(); + return null; + } + } + + private static void escapeJavaStyleString(Writer out, String str) + throws IOException { + + assert str != null : "Received a null string"; + assert out != null : "The writer must not be null"; + + int sz = str.length(); + for (int i = 0; i < sz; i++) { + char ch = str.charAt(i); + + /* convert to unicode */ + if (ch > 0xfff) + out.write("\\u" + hex(ch)); + else if (ch > 0xff) + out.write("\\u0" + hex(ch)); + else if (ch > 0x7f) + out.write("\\u00" + hex(ch)); + else if (ch < 32) { + switch (ch) { + case '\b': + out.write('\\'); + out.write('b'); + break; + case '\n': + out.write('\\'); + out.write('n'); + break; + case '\t': + out.write('\\'); + out.write('t'); + break; + case '\f': + out.write('\\'); + out.write('f'); + break; + case '\r': + out.write('\\'); + out.write('r'); + break; + default : + if (ch > 0xf) + out.write("\\u00" + hex(ch)); + else out.write("\\u000" + hex(ch)); + break; + } + } + else { + switch (ch) { + case '\'': + out.write('\''); + break; + case '"': + out.write('\\'); + out.write('"'); + break; + case '\\': + out.write('\\'); + out.write('\\'); + break; + default : + out.write(ch); + break; + } + } + } + } + + private static String hex(char ch) { + return Integer.toHexString(ch).toUpperCase(); + } + + private Properties _properties = new Properties(); +} + diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/ControlMemberTypeAnnotationProcessor.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/ControlMemberTypeAnnotationProcessor.java new file mode 100644 index 0000000..f50eb99 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/ControlMemberTypeAnnotationProcessor.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator.apt; + +import java.lang.annotation.Annotation; +import java.util.Set; +import java.text.ParseException; +import java.text.SimpleDateFormat; + +import org.apache.beehive.controls.api.bean.AnnotationMemberTypes; +import org.apache.beehive.controls.runtime.generator.AptControlInterface; +import org.apache.beehive.controls.runtime.generator.apt.TwoPhaseAnnotationProcessor; +import org.apache.beehive.controls.runtime.bean.AnnotationConstraintValidator; + +import com.sun.mirror.apt.AnnotationProcessorEnvironment; +import com.sun.mirror.declaration.AnnotationTypeDeclaration; +import com.sun.mirror.declaration.Declaration; +import com.sun.mirror.declaration.MethodDeclaration; +import com.sun.mirror.type.VoidType; + +public class ControlMemberTypeAnnotationProcessor extends TwoPhaseAnnotationProcessor +{ + /** + * @param atds + * @param env + */ + public ControlMemberTypeAnnotationProcessor( + Set atds, + AnnotationProcessorEnvironment env) + { + super(atds, env); + } + + public void check() + { + super.check(); + + } + public void check(Declaration decl) + { + if (decl.getAnnotation(AnnotationMemberTypes.Date.class) != null) + { + checkDate(decl); + } + } + + public void generate(Declaration decl) + { + } + + public void checkDate(Declaration decl) + { + AnnotationMemberTypes.Date date = decl.getAnnotation(AnnotationMemberTypes.Date.class); + + try + { + String dateValue = date.minValue(); + String format = date.format(); + + //Validate the date format specified + SimpleDateFormat sdFormat = new SimpleDateFormat(date.format()); + + //Validate that the date specified is in the specified format. + if (dateValue != null && dateValue.length() > 0) + AnnotationConstraintValidator.parseDate(format, dateValue); + dateValue = date.maxValue(); + if (dateValue != null && dateValue.length() > 0) + AnnotationConstraintValidator.parseDate(format, dateValue); + } + catch (ParseException pe) + { + printError( decl, "control.member.type.invalid.date.value.error"); + } + catch (Exception e) + { + printError( decl, "control.member.type.invalid.date.format.error"); + } + + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/ControlMemberTypeAnnotationProcessorFactory.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/ControlMemberTypeAnnotationProcessorFactory.java new file mode 100644 index 0000000..b77fcbe --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/ControlMemberTypeAnnotationProcessorFactory.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator.apt; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Set; + +import org.apache.beehive.controls.api.bean.AnnotationMemberTypes.Date; + +import com.sun.mirror.apt.AnnotationProcessor; +import com.sun.mirror.apt.AnnotationProcessorFactory; +import com.sun.mirror.apt.AnnotationProcessorEnvironment; +import com.sun.mirror.declaration.AnnotationTypeDeclaration; + +public class ControlMemberTypeAnnotationProcessorFactory implements AnnotationProcessorFactory +{ + private static final Collection _supportedAnnotations = + Collections.unmodifiableCollection( + Arrays.asList(new String[] { + org.apache.beehive.controls.api.bean.AnnotationMemberTypes.Date.class.getName(), + org.apache.beehive.controls.api.bean.AnnotationMemberTypes.Decimal.class.getName(), + org.apache.beehive.controls.api.bean.AnnotationMemberTypes.FilePath.class.getName(), + org.apache.beehive.controls.api.bean.AnnotationMemberTypes.Int.class.getName(), + org.apache.beehive.controls.api.bean.AnnotationMemberTypes.JndiName.class.getName(), + org.apache.beehive.controls.api.bean.AnnotationMemberTypes.Optional.class.getName(), + org.apache.beehive.controls.api.bean.AnnotationMemberTypes.QName.class.getName(), + org.apache.beehive.controls.api.bean.AnnotationMemberTypes.Text.class.getName(), + org.apache.beehive.controls.api.bean.AnnotationMemberTypes.URI.class.getName(), + org.apache.beehive.controls.api.bean.AnnotationMemberTypes.URL.class.getName(), + org.apache.beehive.controls.api.bean.AnnotationMemberTypes.URN.class.getName(), + org.apache.beehive.controls.api.bean.AnnotationMemberTypes.XML.class.getName() + })); + + private static final Collection _supportedOptions = + Collections.unmodifiableCollection( + Arrays.asList( new String[0] ) ); + + public Collection supportedOptions() + { + return _supportedOptions; + } + + public Collection supportedAnnotationTypes() + { + return _supportedAnnotations; + } + + public AnnotationProcessor getProcessorFor(Set atds, + AnnotationProcessorEnvironment env) + { + return new ControlMemberTypeAnnotationProcessor(atds, env); + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/ControlSecondaryAnnotationProcessor.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/ControlSecondaryAnnotationProcessor.java new file mode 100644 index 0000000..37a5cd6 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/ControlSecondaryAnnotationProcessor.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator.apt; + +import java.io.IOException; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Set; + +import com.sun.mirror.apt.AnnotationProcessor; +import com.sun.mirror.apt.AnnotationProcessorFactory; +import com.sun.mirror.apt.AnnotationProcessorEnvironment; +import com.sun.mirror.declaration.AnnotationTypeDeclaration; +import com.sun.mirror.declaration.Declaration; + +import org.apache.beehive.controls.api.bean.ControlExtension; +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.properties.PropertySet; + +import org.apache.beehive.controls.runtime.generator.*; + +/** + * Currently, the sole purpose of this annotation processor is to suppress warning messages from apt regarding + * "annotations without processors". + */ +public class ControlSecondaryAnnotationProcessor extends TwoPhaseAnnotationProcessor +{ + public ControlSecondaryAnnotationProcessor(Set atds, + AnnotationProcessorEnvironment env) + { + super(atds, env); + } + + @Override + public void check(Declaration decl) + { + } + + @Override + public void generate(Declaration decl) + { + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/ControlSecondaryAnnotationProcessorFactory.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/ControlSecondaryAnnotationProcessorFactory.java new file mode 100644 index 0000000..ca4b48d --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/ControlSecondaryAnnotationProcessorFactory.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator.apt; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Set; + +import com.sun.mirror.apt.AnnotationProcessor; +import com.sun.mirror.apt.AnnotationProcessorFactory; +import com.sun.mirror.apt.AnnotationProcessorEnvironment; +import com.sun.mirror.declaration.AnnotationTypeDeclaration; + +public class ControlSecondaryAnnotationProcessorFactory implements AnnotationProcessorFactory +{ + private static final Collection _supportedAnnotations = + Collections.unmodifiableCollection( + Arrays.asList(new String[] { + java.lang.annotation.Target.class.getName(), + java.lang.annotation.Retention.class.getName(), + org.apache.beehive.controls.api.bean.ExternalPropertySets.class.getName(), + org.apache.beehive.controls.api.bean.ControlReferences.class.getName(), + org.apache.beehive.controls.api.bean.Threading.class.getName(), + org.apache.beehive.controls.api.context.Context.class.getName(), + org.apache.beehive.controls.api.events.Client.class.getName(), + org.apache.beehive.controls.api.events.EventHandler.class.getName(), + org.apache.beehive.controls.api.events.EventSet.class.getName(), + org.apache.beehive.controls.api.packaging.BeanInfo.class.getName(), + org.apache.beehive.controls.api.packaging.EventSetInfo.class.getName(), + org.apache.beehive.controls.api.packaging.FeatureAttribute.class.getName(), + org.apache.beehive.controls.api.packaging.FeatureInfo.class.getName(), + org.apache.beehive.controls.api.packaging.ManifestAttribute.class.getName(), + org.apache.beehive.controls.api.packaging.ManifestAttributes.class.getName(), + org.apache.beehive.controls.api.packaging.PropertyInfo.class.getName(), + org.apache.beehive.controls.api.packaging.PropertyInfo.class.getName(), + org.apache.beehive.controls.api.packaging.PropertyInfo.class.getName(), + org.apache.beehive.controls.api.packaging.PropertyInfo.class.getName(), + org.apache.beehive.controls.api.properties.BaseProperties.class.getName(), + org.apache.beehive.controls.api.versioning.Version.class.getName(), + org.apache.beehive.controls.api.versioning.VersionRequired.class.getName(), + org.apache.beehive.controls.api.versioning.VersionSupported.class.getName() + })); + + private static final Collection _supportedOptions = + Collections.unmodifiableCollection( + Arrays.asList(new String[] { + "-AcontrolGenerator", // sets CodeGenerator class + })); + + public Collection supportedOptions() + { + return _supportedOptions; + } + + public Collection supportedAnnotationTypes() + { + return _supportedAnnotations; + } + + public AnnotationProcessor getProcessorFor(Set atds, + AnnotationProcessorEnvironment env) + { + return new ControlSecondaryAnnotationProcessor(atds, env); + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/Diagnostics.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/Diagnostics.java new file mode 100644 index 0000000..5ad109e --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/Diagnostics.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator.apt; + +import com.sun.mirror.apt.AnnotationProcessorEnvironment; +import com.sun.mirror.declaration.Declaration; +import com.sun.mirror.declaration.AnnotationValue; +import com.sun.mirror.declaration.AnnotationMirror; + +/** + * Wrapper class that allows the Control annotation processors to report diagnostics + * without calling directly against the {@link AnnotationProcessorEnvironment}. This + * class keeps track of whether errors have been reported during annotation processing. + */ +public abstract class Diagnostics +{ + private AnnotationProcessorEnvironment _env; + private boolean _hasErrors = false; + + protected Diagnostics( AnnotationProcessorEnvironment env ) + { + _env = env; + } + + public void addError( Declaration decl, String messageKey, Object ... args ) + { + _env.getMessager().printError( decl.getPosition(), getResourceString( messageKey, args ) ); + _hasErrors = true; + } + + public void addError( AnnotationMirror ann, String messageKey, Object ... args ) + { + _env.getMessager().printError( ann.getPosition(), getResourceString( messageKey, args ) ); + _hasErrors = true; + } + + public void addErrorArrayArgs( AnnotationMirror ann, String messageKey, Object[] args ) + { + _env.getMessager().printError( ann.getPosition(), getResourceString( messageKey, args ) ); + _hasErrors = true; + } + + public void addError( AnnotationValue annVal, String messageKey, Object ... args ) + { + _env.getMessager().printError( annVal.getPosition(), getResourceString( messageKey, args ) ); + _hasErrors = true; + } + + public void addWarning( Declaration decl, String messageKey, Object ... args ) + { + _env.getMessager().printWarning( decl.getPosition(), getResourceString( messageKey, args ) ); + } + + public void addWarning( AnnotationMirror ann, String messageKey, Object ... args ) + { + _env.getMessager().printWarning( ann.getPosition(), getResourceString( messageKey, args ) ); + } + + public void addWarning( AnnotationValue annVal, String messageKey, Object ... args ) + { + _env.getMessager().printWarning( annVal.getPosition(), getResourceString( messageKey, args ) ); + } + + public AnnotationProcessorEnvironment getAnnotationProcessorEnvironment() + { + return _env; + } + + protected abstract String getResourceString( String key, Object ... args ); + + public boolean hasErrors() + { + return _hasErrors; + } + + protected void setHasErrors( boolean hadErrors ) + { + _hasErrors = hadErrors; + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/TwoPhaseAnnotationProcessor.java b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/TwoPhaseAnnotationProcessor.java new file mode 100644 index 0000000..2f0ab4b --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/TwoPhaseAnnotationProcessor.java @@ -0,0 +1,181 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.generator.apt; + +import java.util.*; +import java.text.MessageFormat; + +import com.sun.mirror.apt.AnnotationProcessor; +import com.sun.mirror.apt.AnnotationProcessorEnvironment; +import com.sun.mirror.declaration.AnnotationTypeDeclaration; +import com.sun.mirror.declaration.Declaration; + +import org.apache.beehive.controls.runtime.generator.CodeGenerationException; + +/** + * The TwoPhaseAnnotationProcessor class is an abstract class that implements the APT + * AnnotationProcessor interface. It breaks the work of the process() method of the + * AnnotationProcessor down into two distinct phases, represented as abstract method + * of TwoPhaseAnnotationProcessor that are to be implemented by concrete subclasses. + *

    + * The two phases of processing are: + *

      + *
    • The check phase is used to validate input Declarations that have been + * annotated with annotations claimed by the processor to ensure that it + * is semantically valid. If the presence of the input Declaration implies the need + * to add new files, and those files need to be visible during the check phase for + * other Declarations, then the AnnotationProcessorEnvironment's Filer API should be + * used to add those files in this phase. The adding of such files at this point + * should typically not result in their emission to persistent storage (i.e. disk), + * but rather be kept in memory to be referenced by the check phase of other + * Declarations. + *
    • The generate phase will actually emit any source, binary, or class files + * that are derived from the input Declaration, including files added via the Filer + * API during the check phase. The Filer API may also be used in this phase to add + * new files, however, such additions will not be visible during the check phase of + * any Declarations. + *
    + *

    + * The benefits of breaking process() down into check() and generate() phases are: + *

      + *
    1. Makes it possible to perform the semantic validation of Declarations without + * necessarily resulting in code generation. + *
    2. Provides a clearer association between input Declarations and generator output. + *
    + * TwoPhaseAnnotationProcessor is intended provide a uniform mechanism for writing + * AnnotationProcessor implementations that can be used in tooling environments more + * sophisticated than command-line tools (that may not do all their work on source + * in a single pass). Such environments will typically also provide implementations + * of the AnnotationProcessorEnvironment and associated interfaces (Messager, + * Filer etc). + */ +abstract public class TwoPhaseAnnotationProcessor + extends Diagnostics + implements AnnotationProcessor +{ + public TwoPhaseAnnotationProcessor(Set atds, + AnnotationProcessorEnvironment env) + { + super( env ); + _atds = atds; + _locale = Locale.getDefault(); + } + + /** + * Implements AnnotationProcessor.process() as two phases, "check" and "generate". + * "generate" will not be called if "check" emitted any errors (via printError()). + */ + public void process() + { + check(); + + // Do not call generate if check resulted in errors. + if ( !hasErrors() ) + generate(); + } + + /** + * Performs semantic validation of input Declarations that are annotated with + * annotations claimed by this AnnotationProcessor. + */ + public void check() + { + for (AnnotationTypeDeclaration atd : _atds) + { + Collection decls = getAnnotationProcessorEnvironment().getDeclarationsAnnotatedWith(atd); + for (Declaration decl : decls) + { + check(decl); + } + } + } + + /** + * Emits additional artifacts for input Declarations that are annotated with + * annotations claimed by this AnnotationProcessor. + */ + public void generate() throws CodeGenerationException + { + for (AnnotationTypeDeclaration atd : _atds) + { + Collection decls = getAnnotationProcessorEnvironment().getDeclarationsAnnotatedWith(atd); + for (Declaration decl : decls) + { + generate(decl); + } + } + } + + /** + * The check method is responsible for all semantic validation of the input Declaration. + *

    + * All semantic errors/warnings associated with the input Declaration should + * be output during check via the {@link #printError} and + * {@link #printWarning} methods. If an implementation + * bypasses printError, it must override {@link #hasErrors()} to ensure correct behaviour. + *

    + * If the presence of the input Declaration implies the need to add new files, + * and those files need to be visible during the check phase for + * other Declarations, then the AnnotationProcessorEnvironment's Filer API should be + * used to add those files in this phase. The adding of such files at this point + * should typically not result in their emission to persistent storage (i.e. disk), + * but rather be kept in memory to be referenced by the check phase of other + * Declarations. + */ + abstract public void check(Declaration decl); + + /** + * The generate method is responsible for the generation of any additional artifacts + * (source, class, or binary) that are derived from the input Declaration. + */ + abstract public void generate(Declaration decl); + + // + // Helper functions for handling diagnostics + // + + /** + * Report an error detected during the "check" phase. The presence of errors + * will suppress execution of the "generate" phase. + */ + public void printError( Declaration d, String id, Object... args ) + { + addError( d, id, args ); + } + + /** + * Report a warning detected during the "check" phase. The presence of warnings + * will not affect execution of the "generate" phase. + */ + public void printWarning( Declaration d, String id, Object... args ) + { + addWarning( d, id, args ); + } + + protected String getResourceString( String id, Object... args ) + { + ResourceBundle rb = ResourceBundle.getBundle( + this.getClass().getPackage().getName() + ".strings", _locale ); + String pattern = rb.getString(id); + return MessageFormat.format(pattern, args); + } + + Set _atds; + Locale _locale; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/strings.properties b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/strings.properties new file mode 100644 index 0000000..64f2fee --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/generator/apt/strings.properties @@ -0,0 +1,186 @@ +control.field.bad.interfacetype=\ +A control field's type must be annotated with @ControlInterface or @ControlExtension if it's an interface. \ +Verify the type of the control field declaration is annotated correctly. + +control.field.bad.classtype=\ +A control field's type must implement org.apache.beehive.controls.api.bean.ControlBean if it's a class. \ +Verify the type of the control field declaration implements ControlBean. + +control.field.bad.classtype.badinterface=\ +If a control field's type is a class, that class must implement the control's public interface/extension and no other interface. \ +Verify the type of the control field declaration implements only the public interface/extension. + +control.field.type.malformed=\ +The type of the control field is malformed. Verify that the source of the type has no errors. + +control.field.bad.version=\ +Control field {0} fails version requirement: requires interface version {1}.{2}, found interface version {3}.{4} + +control.field.in.inner.class=\ +A control field can exist only within the top-level class. \ +Move fields marked with the Control annotation to just inside the top-level class. + +control.field.override=\ +This control field conflicts with another of the same name in superclass {0}. + +control.public.interface.not.found = \ +Cannot find the public interface for this control. \ +Verify that the public interface for this control is available in this project. + +transient.control.field =\ +A control can not be declared as transient. \ +Remove the transient modifier from the control declaration. + +static.control.field =\ +A control can not be declared as static. \ +Remove the static modifier from the control declaration. + +controls.client.manifest.ioerror= \ +An error occurred writing the controls client manifest. + +propertyset.illegal.argument.error=\ +A value assigned to a control property does not satisfy \ +its constraints. Cause: {0} + +control.member.type.invalid.date.value.error=\ +The value assigned to a date property must be in the format specified. + +control.member.type.invalid.date.format.error=\ +The date format specified is not valid, please see java.text.SimpleDateFormat for valid formats. + +control.reference.bad.interfacetype=\ +Types listed in @ControlReferences must be control interfaces (ie, interfaces annotated with @ControlInterface or @ControlExtension). \ +Verify the types listed in @ControlReferences are control interface types. + +control.interface.annotation.badlocation=\ +The ControlInterface or ControlExtension annotation may only be used on a Java interface. + +control.extension.badinterface=\ +Interfaces annotated with ControlExtension must extend an interface annotated with ControlInterface. + +control.interface.badinterface=\ +An interface annotated with @ControlInterface can only extend another ControlInterface. It is not valid for \ +a ControlInterface to extend a ControlExtension. + +property.primitive.without.default=\ +Primitive property {0} must specify a default value. + +propertyset.illegal.usage=\ +The PropertySet annotation may only be used on a Java annotation interface. + +propertyset.illegal.usage.2=\ +The @PropertySet annotation should only be used within an interface annotated with @ControlInterface, \ +never @ControlExtension. An extension can only use existing properties, not declare new ones. + +extpropertyset.illegal.usage=\ +The @ExternalPropertySets annotation should only be used on an interface annotated with \ +@ControlInterface, never @ControlExtension. An extension can only use existing properties, not declare new one. + +extpropertyset.type.not.found=\ +Unable to load type declaration for externally referenced PropertySet {0}. + +propertyset.not.annotation.type=\ +The PropertySet annotation must be on an Annotation type. + +propertyset.missing.retention=\ +The PropertySet annotation must be used in conjuction with @Retention(RetentionPolicy.RUNTIME). + +propertyset.duplicate.property.names=\ +Duplicate property name {0} found on property set '{1}'. Consider using the PropertySet 'prefix' \ +attribute to disambiguate. + +eventset.illegal.usage=\ +The EventSet annotation must be on an interface declaration. + +eventset.formal.parameter.mismatch=\ +Any EventSet formal type parameters must match ones declared on the associated control type. \ +No new formal type parameters may be introduced. + +eventset.illegal.multicast=\ +Event methods declared within a multicast EventSet cannot return a value. Change the return \ +type of this method declaration to void, or use the unicast attribute of @EventSet to change to a unicast event set. + +manifestattribute.illegal.name.1=\ +@ManifestAttribute name cannot be a zero-length string. + +manifestattribute.illegal.name.2=\ +@ManifestAttribute name must begin with an alphanumeric character. + +manifestattribute.illegal.name.3=\ +@ManifestAttribute name contains an invalid character: {0}. + +manifestattribute.illegal.name.4=\ +@ManifestAttribute value cannot be a zero-length string. + +versionrequired.illegal.usage=\ +Illegal usage of @VersionRequired: not permitted on interfaces annotated with @ControlInterface. + +versionrequired.failed=\ +Control extension {0} fails version requirement: requires interface version {1}.{2}, found interface \ +version {3}.{4}. + +control.interface.illegal.checker=\ +Control interface {0} specifies a checker class {1} that doesn't implement ControlChecker. + +control.interface.checker.load.failed=\ +Control interface {0} specifies a checker class {1} which cannot be loaded. Verify that the \ +apt -classpath value is correct. + +control.implementation.badclass=\ +The ControlImplementation annotation may only be used on a Java class. + +control.implementation.unserializable=\ +A ControlImplementation class must implement the java.io.Serializable interface or set the isTransient \ +attribute of @ControlImplementation to true. + +control.implementation.missing.interface=\ +Control implementations must implement a control interface. + +eventhandler.field.not.found=\ +Cannot find event source field: {0}. + +eventhandler.eventset.not.found=\ +Cannot find EventSet interface: {0}. + +eventhandler.method.is.private=\ +Methods annotated with the EventHandler annotation can not be private. + +eventhandler.method.not.found=\ +No event method with matching name and signature found on EventSet: {0}. + +eventhandler.throws.mismatch=\ +Handler method {0} 'throws' clause is not a proper subset of the eventset method's 'throws' clause. \ +Handlers may only throw throwables declared by the eventset method. + +versionsupported.failed=\ +Control implementation {0} fails version support requirement: highest supported interface version is \ +{1}.{2}, found interface version {3}.{4}. + +control.illegal.usage=\ +The Control annotation may only be used in a Java class. + +context.field.badinterface=\ +@Context field type must be an interface. + +control.field.bad.type=\ +@Control field type must be a valid ControlBean class or control interface. \ +Verify that the type of the field declaration is a control class or interface. + +control.field.bad.type.2=\ +Unable to identify control type of field. + + + + + + + + + + + + + + + + diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/packaging/ControlEventSetDescriptor.java b/controls/src/runtime/org/apache/beehive/controls/runtime/packaging/ControlEventSetDescriptor.java new file mode 100644 index 0000000..8367452 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/packaging/ControlEventSetDescriptor.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.packaging; + +import java.beans.EventSetDescriptor; +import java.beans.IntrospectionException; +import java.beans.MethodDescriptor; +import java.lang.ref.Reference; +import java.lang.ref.SoftReference; +import java.lang.reflect.Method; + +/** + * The ControlEventSetDescriptor is a result of an infortunate evoluntary flaw in the + * java.beans.EventSetDescriptor class. The getListeners functionality for event sets was + * added after the initial implementation, and unfortunately, there is no constructor that + * let you specify both the MethodDescriptors for events and the getListener + * method. To compensate for this, we must subclass and provide our own getGetListenerMethod + * implementation. + */ +public class ControlEventSetDescriptor extends EventSetDescriptor +{ + /** + * This constructor adds the getListenerMethod argument that is missing from the JDK! + */ + public ControlEventSetDescriptor(String eventSetName, + Class listenerType, + MethodDescriptor[] listenerMethodDescriptors, + Method addListenerMethod, + Method removeListenerMethod, + Method getListenerMethod) + throws IntrospectionException + { + super(eventSetName, listenerType, listenerMethodDescriptors, addListenerMethod, removeListenerMethod); + + // Follow the same pattern as the JDK and store the method as a soft reference, so + // the introspector (alone) won't prevent Class garbage collection. + _getMethodRef = new SoftReference(getListenerMethod); + } + + /** + * Override the default implementation of getGetListenerMethod to return the method + * provided in the constructor. + */ + public Method getGetListenerMethod() + { + if (_getMethodRef == null) + return null; + + return _getMethodRef.get(); + } + + Reference _getMethodRef; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/packaging/ControlJarTask.java b/controls/src/runtime/org/apache/beehive/controls/runtime/packaging/ControlJarTask.java new file mode 100644 index 0000000..4fe4345 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/packaging/ControlJarTask.java @@ -0,0 +1,157 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.packaging; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Vector; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.taskdefs.Jar; +import org.apache.tools.ant.taskdefs.Manifest; +import org.apache.tools.ant.taskdefs.ManifestException; +import org.apache.tools.ant.types.Resource; +import org.apache.tools.ant.types.FileSet; +import org.apache.tools.ant.util.FileUtils; +import org.apache.tools.zip.ZipOutputStream; + +/** + * The ControlTask class extends the standard ant Jar task to perform + * additional processing for JAR files that contain Beehive Controls. + */ +public class ControlJarTask extends Jar +{ + private static FileUtils fileUtils = FileUtils.newFileUtils(); + + /** + * Step #1: Wrap the implementation of Zip.grabResources. This method identifies the + * set of resources to be stored in the JAR file. For each added/updated resource, + * the overrided method will look for an associated .manifest file that any + * JAR manifest data to add/update in the JAR manifest. + */ + protected Resource[][] grabResources(FileSet[] filesets) + { + // + // Get the list of resources being added/updated by calling Zip.grabResources + // + Resource [][] resources = super.grabResources(filesets); + + // + // Iterate through the resources for each input FileSet, looking for an associated + // manifest file. + // + for (int i = 0; i < filesets.length; i++) + { + if (resources[i].length == 0) + continue; + + File base = filesets[i].getDir(getProject()); + Resource [] setResources = resources[i]; + + for (int j = 0; j < setResources.length; j++) + { + File manifestFile = + fileUtils.resolveFile(base, setResources[j].getName() + ".manifest"); + if (manifestFile.exists()) + manifestFiles.add(manifestFile); + } + } + + return resources; + } + + /** + * Step #2: Override Jar.initZipOutputStream to inject manifest sections. This is done + * by treating them as if they were 'inline' entries, from a task perspective. + */ + protected void initZipOutputStream(ZipOutputStream zOut) throws IOException, BuildException + { + if (manifestFiles.size() != 0) + { + // + // Create a default (empty) manifest + // + Manifest mergeManifest = Manifest.getDefaultManifest(); + + // + // Iterate through each found manifest file, merging its contents into the + // merge manifest + // + for (File manifestFile : manifestFiles) + { + FileInputStream fis = null; + try + { + fis = new FileInputStream(manifestFile); + Manifest resourceManifest = new Manifest(new InputStreamReader(fis)); + mergeManifest.merge(resourceManifest); + } + catch (IOException ioe) + { + throw new BuildException("Unable to read manifest file:" + manifestFile, ioe); + } + catch (ManifestException me) + { + throw new BuildException("Unable to process manifest file: "+ manifestFile, me); + } + finally + { + if (fis != null) fis.close(); + } + } + + // + // Set the merge manifest as the 'configured' manifest. This will treat its + // contents as if they had been included inline with the task, with + // similar precedence rules. + // + try + { + addConfiguredManifest(mergeManifest); + } + catch (ManifestException me) + { + throw new BuildException("Unable to add new manifest entries:" + me); + } + } + + super.initZipOutputStream(zOut); + } + + protected void addToManifest(Manifest jarManifest, List mergeList) + { + } + + /** + * Reset the manifest file list to be empty + */ + protected void cleanUp() + { + manifestFiles = new Vector(); + } + + /** + * Contains the set of manifest entries to merge into the JAR manifest + */ + private List manifestFiles = new Vector(); +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/servlet/ControlFilter.java b/controls/src/runtime/org/apache/beehive/controls/runtime/servlet/ControlFilter.java new file mode 100644 index 0000000..1ce5c2f --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/servlet/ControlFilter.java @@ -0,0 +1,127 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.servlet; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; + +/** + * The ControlFilter class provides an implementation of an HTTP servlet filter that supports + * running controls in the web tier. It works, in conjunction with the {@link ServletBeanContext} + * class to provide runtime containment for controls. It ensures that a valid BeanContext has + * been set up prior to forwarding the request to the actual target servlet, and does + * post-processing to ensure that resources have been properly released. + * + * This filter needs to be configured in web.xml for URL mappings that will be hosting servlets. + */ +public class ControlFilter implements Filter +{ + public static String BEAN_CONTEXT_ATTRIBUTE = ServletBeanContext.class.getName(); + + /** + * The contextClass init parameter is a class name that defines the BeanContext class to use + * for containing Controls in the servlet container. This class must be a subclass of + * the org.apache.beehive.runtime.servlet.ServletBeanContext class. + */ + public static String INIT_PARAM_CONTEXT_CLASS = "contextClass"; + + public void init(FilterConfig filterConfig) throws ServletException + { + _filterConfig = filterConfig; + String contextClassName = filterConfig.getInitParameter(INIT_PARAM_CONTEXT_CLASS); + if(contextClassName != null) + { + try + { + _contextClass = Class.forName(contextClassName); + } + catch(Exception e) + { + throw new ServletException("Cannot load container context class '"+contextClassName+"'"); + } + if(!ServletBeanContext.class.isAssignableFrom(_contextClass)) + { + throw new ServletException("'"+contextClassName+"' is not a ServletBeanContext sub-class"); + } + + } + } + + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws java.io.IOException, ServletException + { + if (request instanceof HttpServletRequest) + { + ServletBeanContext beanContext; + try + { + beanContext = (ServletBeanContext)_contextClass.newInstance(); + } + catch(Exception e) + { + throw new ServletException("Cannot construct BeanContext class instance: " + + _contextClass.getName()); + } + + // + // Start a new execution context + // + beanContext.beginContext(_filterConfig.getServletContext(), request, response); + try + { + // + // Pass the requst on to the next filter or target servlet + // + chain.doFilter(request, response); + } + finally + { + // + // End the execution context + // + beanContext.endContext(); + } + } + else + { + // + // If the filter is (mis)configured on something other than an http servlet, just + // pass it on + // + chain.doFilter(request, response); + } + } + + public void destroy() {} + + /** + * The FilterConfig associated with this filter instance. + */ + FilterConfig _filterConfig; + + /** + * The BeanContext class to use as the container for controls running in the ServletContainer + */ + private Class _contextClass = ServletBeanContext.class; +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/servlet/HttpRequestService.java b/controls/src/runtime/org/apache/beehive/controls/runtime/servlet/HttpRequestService.java new file mode 100644 index 0000000..4942d82 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/servlet/HttpRequestService.java @@ -0,0 +1,213 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.servlet; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import javax.servlet.ServletRequest; + +/** + * This class is the contextual service implementation for javax.servlet.http.HttpServletRequest. + * It acts as an intermediary between the client and the HttpServletRequest instance held by the + * associated ServletBeanContext. It validates that attempt to access the HttpServletRequest + * only occur during the servlet request processing lifecycle, then delegates to the underlying + * HttpServletRequest instance for actual services. + */ +/* package */ class HttpRequestService + extends ServletRequestService + implements HttpServletRequest +{ + + // todo: how will this class version with subsequent Servlet specification versions? + + /** + * This static helper class derives from javax.servlet.HttpServletRequestWrapper and can + * be used to wrap a HttpServletRequestService instance in cases where the client expects + * to be able to use the standard wrapper interfaces to unwrap requests. + */ + private static class Wrapper extends HttpServletRequestWrapper + { + Wrapper(HttpRequestService requestService) + { + super(requestService); + _requestService = requestService; + } + + /** + * Overrides the default HttpServletRequestWrapper.getRequest implementation. Rather + * than just returning the request passed into the constructor (i.e. the request + * service), it will go unwrap step further and return the current (active) http + * request. + */ + public HttpServletRequest getRequest() + { + return _requestService.getHttpServletRequest(); + } + + HttpRequestService _requestService; + } + + /* package */ HttpRequestService(ServletBeanContext beanContext) + { + super(beanContext); + } + + final protected HttpServletRequest getHttpServletRequest() + { + ServletRequest servletRequest = getServletBeanContext().getServletRequest(); + if (! (servletRequest instanceof HttpServletRequest)) + throw new IllegalStateException("Current request is not an HttpServletRequest"); + return (HttpServletRequest)servletRequest; + } + + /** + * This method returns a HttpServletRequestWrapper instance that wraps the request service. + * This is useful in instances where there is code that uses the wrapper interfaces to + * unwrap requests to get to the 'root' request. + */ + /* package */ HttpServletRequestWrapper getHttpRequestWrapper() + { + return new Wrapper(this); + } + + public java.lang.String getAuthType() + { + return getHttpServletRequest().getAuthType(); + } + + public javax.servlet.http.Cookie[] getCookies() + { + return getHttpServletRequest().getCookies(); + } + + public long getDateHeader(java.lang.String name) + { + return getHttpServletRequest().getDateHeader(name); + } + + public java.lang.String getHeader(java.lang.String name) + { + return getHttpServletRequest().getHeader(name); + } + + public java.util.Enumeration getHeaders(java.lang.String name) + { + return getHttpServletRequest().getHeaders(name); + } + + public java.util.Enumeration getHeaderNames() + { + return getHttpServletRequest().getHeaderNames(); + } + + public int getIntHeader(java.lang.String name) + { + return getHttpServletRequest().getIntHeader(name); + } + + public java.lang.String getMethod() + { + return getHttpServletRequest().getMethod(); + } + + public java.lang.String getPathInfo() + { + return getHttpServletRequest().getPathInfo(); + } + + public java.lang.String getPathTranslated() + { + return getHttpServletRequest().getPathTranslated(); + } + + public java.lang.String getContextPath() + { + return getHttpServletRequest().getContextPath(); + } + + public java.lang.String getQueryString() + { + return getHttpServletRequest().getQueryString(); + } + + public java.lang.String getRemoteUser() + { + return getHttpServletRequest().getRemoteUser(); + } + + public boolean isUserInRole(java.lang.String role) + { + return getHttpServletRequest().isUserInRole(role); + } + + public java.security.Principal getUserPrincipal() + { + return getHttpServletRequest().getUserPrincipal(); + } + + public java.lang.String getRequestedSessionId() + { + return getHttpServletRequest().getRequestedSessionId(); + } + + public java.lang.String getRequestURI() + { + return getHttpServletRequest().getRequestURI(); + } + + public java.lang.StringBuffer getRequestURL() + { + return getHttpServletRequest().getRequestURL(); + } + + public java.lang.String getServletPath() + { + return getHttpServletRequest().getServletPath(); + } + + public javax.servlet.http.HttpSession getSession(boolean create) + { + return getHttpServletRequest().getSession(create); + } + + public javax.servlet.http.HttpSession getSession() + { + return getHttpServletRequest().getSession(); + } + + public boolean isRequestedSessionIdValid() + { + return getHttpServletRequest().isRequestedSessionIdValid(); + } + + public boolean isRequestedSessionIdFromCookie() + { + return getHttpServletRequest().isRequestedSessionIdFromCookie(); + } + + public boolean isRequestedSessionIdFromURL() + { + return getHttpServletRequest().isRequestedSessionIdFromURL(); + } + + public boolean isRequestedSessionIdFromUrl() + { + return getHttpServletRequest().isRequestedSessionIdFromUrl(); + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/servlet/HttpResponseService.java b/controls/src/runtime/org/apache/beehive/controls/runtime/servlet/HttpResponseService.java new file mode 100644 index 0000000..17ff426 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/servlet/HttpResponseService.java @@ -0,0 +1,174 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.servlet; + +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletResponseWrapper; +import javax.servlet.ServletResponse; + +/** + * This class is the contextual service implementation for javax.servlet.http.HttpServletResponse. + * It acts as an intermediary between the client and the HttpServletResponse instance held by the + * associated ServletBeanContext. It validates that attempt to access the HttpServletResponse + * only occur during the servlet request processing lifecycle, then delegates to the underlying + * HttpServletResponse instance for actual services. + */ +/* package */ class HttpResponseService + extends ServletResponseService + implements HttpServletResponse +{ + + // todo: how will this class version with subsequent Servlet specification versions? + + /** + * This static helper class derives from javax.servlet.HttpServletResponseWrapper and can + * be used to wrap a HttpServletResponseService instance in cases where the client expects + * to be able to use the standard wrapper interfaces to unwrap responses. + */ + private static class Wrapper extends HttpServletResponseWrapper + { + Wrapper(HttpResponseService responseService) + { + super(responseService); + _responseService = responseService; + } + + /** + * Overrides the default HttpServletRequestWrapper.getResponse implementation. Rather + * than just returning the request passed into the constructor (i.e. the request + * service), it will go unwrap step further and return the current (active) http + * response. + */ + public HttpServletResponse getResponse() + { + return _responseService.getHttpServletResponse(); + } + + HttpResponseService _responseService; + } + + + /* package */ HttpResponseService(ServletBeanContext beanContext) + { + super(beanContext); + } + + final protected HttpServletResponse getHttpServletResponse() + { + ServletResponse servletRequest = getServletBeanContext().getServletResponse(); + if (! (servletRequest instanceof HttpServletResponse)) + throw new IllegalStateException("Current request is not an HttpServletResponse"); + return (HttpServletResponse)servletRequest; + } + + /** + * This method returns a ServletRequestWrapper instance that wraps the request service. + * This is useful in instances where there is code that uses the wrapper interfaces to + * unwrap requests to get to the 'root' request. + */ + /* package */ HttpServletResponse getHttpResponseWrapper() + { + return new Wrapper(this); + } + + public void addCookie(javax.servlet.http.Cookie cookie) + { + getHttpServletResponse().addCookie(cookie); + } + + public boolean containsHeader(java.lang.String name) + { + return getHttpServletResponse().containsHeader(name); + } + + public java.lang.String encodeURL(java.lang.String url) + { + return getHttpServletResponse().encodeURL(url); + } + + public java.lang.String encodeRedirectURL(java.lang.String url) + { + return getHttpServletResponse().encodeRedirectURL(url); + } + + public java.lang.String encodeUrl(java.lang.String url) + { + return getHttpServletResponse().encodeUrl(url); + } + + public java.lang.String encodeRedirectUrl(java.lang.String url) + { + return getHttpServletResponse().encodeRedirectUrl(url); + } + + public void sendError(int sc, java.lang.String msg) throws java.io.IOException + { + getHttpServletResponse().sendError(sc, msg); + } + + public void sendError(int sc) throws java.io.IOException + { + getHttpServletResponse().sendError(sc); + } + + public void sendRedirect(java.lang.String location) throws java.io.IOException + { + getHttpServletResponse().sendRedirect(location); + } + + public void setDateHeader(java.lang.String name, long date) + { + getHttpServletResponse().setDateHeader(name, date); + } + + public void addDateHeader(java.lang.String name, long date) + { + getHttpServletResponse().addDateHeader(name, date); + } + + public void setHeader(java.lang.String name, java.lang.String value) + { + getHttpServletResponse().setHeader(name, value); + } + + public void addHeader(java.lang.String name, java.lang.String value) + { + getHttpServletResponse().addHeader(name, value); + } + + public void setIntHeader(java.lang.String name, int value) + { + getHttpServletResponse().setIntHeader(name, value); + } + + public void addIntHeader(java.lang.String name, int value) + { + getHttpServletResponse().addIntHeader(name, value); + } + + public void setStatus(int sc) + { + getHttpServletResponse().setStatus(sc); + } + + public void setStatus(int sc, java.lang.String sm) + { + getHttpServletResponse().setStatus(sc, sm); + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/servlet/ServletBeanContext.java b/controls/src/runtime/org/apache/beehive/controls/runtime/servlet/ServletBeanContext.java new file mode 100644 index 0000000..2f33c06 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/servlet/ServletBeanContext.java @@ -0,0 +1,271 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.servlet; + +import java.util.Stack; +import java.io.InputStream; +import java.beans.beancontext.BeanContextChild; +import java.beans.beancontext.BeanContextServiceProvider; +import java.net.URL; +import java.net.MalformedURLException; +import javax.servlet.ServletContext; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.beehive.controls.runtime.bean.ControlContainerContext; +import org.apache.beehive.controls.runtime.bean.WebContextFactoryProvider; +import org.apache.beehive.controls.spi.context.ControlBeanContextFactory; + +/** + * The ServletBeanContext provides a ControlBeanContext implementation that offers services + * and a resource management context that is appropriate to web tier usage of controls. + */ +public class ServletBeanContext + extends ControlContainerContext +{ + public ServletBeanContext() { + // + // This sets the BeanContextServicesFactory instance on the ControlBeanContext and allows this + // CCC object to be created with a BeanContextServicesDelegate of the type returned by this factory + // + super(WebContextFactoryProvider.WEB_CONTEXT_BCS_FACTORY); + } + + /** + * Called by BeanContextSupport superclass during construction and deserialization to + * initialize subclass transient state + */ + public void initialize() + { + super.initialize(); + + // + // Register the ServletService classes associated with the ServletServiceProvider + // + ServletServiceProvider ssp = ServletServiceProvider.getProvider(); + addService(ServletContext.class, ssp); + addService(ServletRequest.class, ssp); + addService(ServletResponse.class, ssp); + addService(HttpServletRequest.class, ssp); + addService(HttpServletResponse.class, ssp); + + // + // Register an *internal* service that is used to create ControlBeanContext objects for + // children of this control container + // + _bcsp = WebContextFactoryProvider.getProvider(); + addService(ControlBeanContextFactory.class, _bcsp); + } + + /** + * Begins a new execution context, associated with a specific ServletRequest + */ + public void beginContext(ServletContext context, ServletRequest req, ServletResponse resp) + { + pushRequestContext(context, req, resp); + super.beginContext(); + } + + /** + * Ends the current execution context, and resetes the current active ServletRequest. + */ + public void endContext() + { + super.endContext(); + popRequestContext(); + } + + private Stack getRequestStack() + { + if (_reqStack == null) + _reqStack = new Stack(); + + return _reqStack; + } + + /** + * Pushes the current request context onto the stack + */ + private synchronized void pushRequestContext(ServletContext context, + ServletRequest req, + ServletResponse resp) + { + getRequestStack().push(new RequestContext(context, req, resp)); + } + + /** + * Pops the current request context from the stack + */ + private synchronized void popRequestContext() + { + getRequestStack().pop(); + } + + /** + * Returns the current request context, or null is none is available + */ + private synchronized RequestContext peekRequestContext() + { + Stack reqStack = getRequestStack(); + if (reqStack.empty()) + return null; + + return reqStack.peek(); + } + + /** + * Returns the ServletContext associated with this context (or null if not currently + * processing a request) + */ + public ServletContext getServletContext() + { + RequestContext reqContext = peekRequestContext(); + if (reqContext == null) + return null; + + return reqContext._context; + } + + /** + * Returns the ServletRequest associated with this context (or null if not currently + * processing a request) + */ + public ServletRequest getServletRequest() + { + RequestContext reqContext = peekRequestContext(); + if (reqContext == null) + return null; + + return reqContext._request; + } + + /** + * Returns the ServletResponse associated with this context (or null if not currently + * processing a request) + */ + public ServletResponse getServletResponse() + { + RequestContext reqContext = peekRequestContext(); + if (reqContext == null) + return null; + + return reqContext._response; + } + + /** + * Enables/disable the use of request/response wrappers for this context. By default, + * wrappers are enabled if this API is not invoked. + */ + public void setWrappers(boolean useWrappers) + { + _useWrappers = useWrappers; + } + + /** + * Override BeanContext.getResourceAsStream() so it delegates to the current ServletContext. + * + * @param name the resource name + * @param bcc the specified child + * @return an InputStream for reading the resource, or + * null if the resource could not be found. + * @throws IllegalArgumentException IllegalArgumentException if the resource is not valid + */ + public InputStream getResourceAsStream(String name, BeanContextChild bcc) + throws IllegalArgumentException + { + ServletContext sc = getServletContext(); + if ( sc != null ) + return sc.getResourceAsStream( name ); + + return null; + } + + /** + * Override BeanContext.getResource() so it delegates to the current ServletContext. + * + * @param name the resource name + * @param bcc the specified child + * @return a URL for the named + * resource for the specified child + * @throws IllegalArgumentException IllegalArgumentException if the resource is not valid + */ + public URL getResource(String name, BeanContextChild bcc) + throws IllegalArgumentException + { + ServletContext sc = getServletContext(); + if ( sc != null ) + { + try + { + return sc.getResource( name ); + } + catch ( MalformedURLException mue ) + { + throw new IllegalArgumentException( mue.getMessage() ); + } + } + + return null; + } + + /** + * Override ControlBeanContext.getService(). A control bean creates its bean context using the + * ControlBeanContextFactory service provided by this context. A control bean will attempt to create + * its context before adding its self to this context as a child. This creates a chicken/egg problem since + * only a child of a context may request a service from it. + * + * This method provides a way to crack the chicken/egg problem by first trying to get the service using the + * control bean context's getService() method, and if that call returns null and the requested service is + * the ControlBeanContextFactory then returning an instance of the service provider. + * + * @param serviceClass + * @param selector + */ + public T getService(Class serviceClass, Object selector) + { + T service = super.getService(serviceClass, selector); + if (service == null && serviceClass.equals(ControlBeanContextFactory.class)) { + return (T)_bcsp.getService(this, this, serviceClass, selector); + } + return service; + } + protected boolean useWrappers() { + return _useWrappers; + } + + private static class RequestContext + { + RequestContext(ServletContext context, ServletRequest req, ServletResponse resp) + { + _context = context; + _request = req; + _response = resp; + } + + ServletContext _context; + ServletResponse _response; + ServletRequest _request; + } + + private boolean _useWrappers = true; + private transient Stack _reqStack; + private transient BeanContextServiceProvider _bcsp; +} \ No newline at end of file diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/servlet/ServletContextService.java b/controls/src/runtime/org/apache/beehive/controls/runtime/servlet/ServletContextService.java new file mode 100644 index 0000000..ecc0b24 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/servlet/ServletContextService.java @@ -0,0 +1,189 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.servlet; + +import javax.servlet.ServletContext; + +import org.apache.beehive.controls.api.context.ControlContainerContext; +import org.apache.beehive.controls.api.context.ControlThreadContext; + +/** + * This class is the contextual service implementation for javax.servlet.ServletContext. It + * acts as an intermediary between the client and the ServletContext instance held by the + * associated ServletBeanContext. It validates that attempt to access the ServletContext + * only occur during the servlet request processing lifecycle, then delegates to the underlying + * ServletContext instance for actual services. + */ +/* package */ class ServletContextService + implements ServletContext +{ + + /* package */ ServletContextService(ServletBeanContext beanContext) + { + _beanContext = beanContext; + } + + /** + * This method retrieves the current ServletBeanContext for the service. It is capable + * of reassociating with the current active context, if the service instance has been + * serialized/deserialized. + */ + final protected ServletBeanContext getServletBeanContext() + { + if (_beanContext == null) + { + ControlContainerContext ccc = ControlThreadContext.getContext(); + if (! (ccc instanceof ServletBeanContext)) + throw new IllegalStateException("No ServletBeanContext available"); + + _beanContext = (ServletBeanContext)ccc; + } + return _beanContext; + } + + final protected ServletContext getServletContext() + { + ServletContext servletContext = getServletBeanContext().getServletContext(); + if (servletContext == null) + throw new IllegalStateException("No access to ServletContext outside request processing"); + return servletContext; + } + + public java.lang.Object getAttribute(java.lang.String name) + { + return getServletContext().getAttribute(name); + } + + public java.util.Enumeration getAttributeNames() + { + return getServletContext().getAttributeNames(); + } + + public ServletContext getContext(java.lang.String uripath) + { + return getServletContext().getContext(uripath); + } + + public java.lang.String getInitParameter(java.lang.String name) + { + return getServletContext().getInitParameter(name); + } + + public java.util.Enumeration getInitParameterNames() + { + return getServletContext().getInitParameterNames(); + } + + public int getMajorVersion() + { + return getServletContext().getMajorVersion(); + } + + public java.lang.String getMimeType(java.lang.String file) + { + return getServletContext().getMimeType(file); + } + + public int getMinorVersion() + { + return getServletContext().getMinorVersion(); + } + + public javax.servlet.RequestDispatcher getNamedDispatcher(java.lang.String name) + { + return getServletContext().getNamedDispatcher(name); + } + + public java.lang.String getRealPath(java.lang.String path) + { + return getServletContext().getRealPath(path); + } + + public javax.servlet.RequestDispatcher getRequestDispatcher(java.lang.String path) + { + return getServletContext().getRequestDispatcher(path); + } + + public java.net.URL getResource(java.lang.String path) throws java.net.MalformedURLException + { + return getServletContext().getResource(path); + } + + public java.io.InputStream getResourceAsStream(java.lang.String path) + { + return getServletContext().getResourceAsStream(path); + } + + public java.util.Set getResourcePaths(java.lang.String path) + { + return getServletContext().getResourcePaths(path); + } + + public java.lang.String getServerInfo() + { + return getServletContext().getServerInfo(); + } + + public javax.servlet.Servlet getServlet(java.lang.String name) throws javax.servlet.ServletException + { + return getServletContext().getServlet(name); + } + + public java.lang.String getServletContextName() + { + return getServletContext().getServletContextName(); + } + + public java.util.Enumeration getServletNames() + { + return getServletContext().getServletNames(); + } + + public java.util.Enumeration getServlets() + { + return getServletContext().getServlets(); + } + + public void log(java.lang.String msg) + { + getServletContext().log(msg); + } + + public void log(java.lang.Exception exception, java.lang.String msg) + { + getServletContext().log(exception, msg); + } + + public void log(java.lang.String message, java.lang.Throwable throwable) + { + getServletContext().log(message, throwable); + } + + public void removeAttribute(java.lang.String name) + { + getServletContext().removeAttribute(name); + } + + public void setAttribute(java.lang.String name, java.lang.Object object) + { + getServletContext().setAttribute(name, object); + } + + transient private ServletBeanContext _beanContext; // never access directly +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/servlet/ServletRequestService.java b/controls/src/runtime/org/apache/beehive/controls/runtime/servlet/ServletRequestService.java new file mode 100644 index 0000000..8f21912 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/servlet/ServletRequestService.java @@ -0,0 +1,252 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.servlet; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletRequestWrapper; + +import org.apache.beehive.controls.api.context.ControlContainerContext; +import org.apache.beehive.controls.api.context.ControlThreadContext; + +/** + * This class is the contextual service implementation for javax.servlet.ServletRequest. It + * acts as an intermediary between the client and the ServletRequest instance held by the + * associated ServletBeanContext. It validates that attempt to access the ServletRequest + * only occur during the servlet request processing lifecycle, then delegates to the underlying + * ServletRequest instance for actual services. + */ +/* package */ class ServletRequestService implements ServletRequest +{ + /** + * This static helper class derives from javax.servlet.ServletRequestWrapper and can + * be used to wrap a ServletRequestService instance in cases where the client expects + * to be able to use the standard wrapper interfaces to unwrap requests. + */ + private static class Wrapper extends ServletRequestWrapper + { + Wrapper(ServletRequestService requestService) + { + super(requestService); + _requestService = requestService; + } + + /** + * Overrides the default ServletRequestWrapper.getRequest implementation. Rather + * than just returning the request passed into the constructor (i.e. the request + * service), it will go unwrap step further and return the current (active) http + * request. + */ + public ServletRequest getRequest() + { + return _requestService.getServletRequest(); + } + + ServletRequestService _requestService; + } + + /* package */ ServletRequestService(ServletBeanContext beanContext) + { + _beanContext = beanContext; + } + + /** + * This method retrieves the current ServletBeanContext for the service. It is capable + * of reassociating with the current active context, if the service instance has been + * serialized/deserialized. + */ + final protected ServletBeanContext getServletBeanContext() + { + if (_beanContext == null) + { + ControlContainerContext ccc = ControlThreadContext.getContext(); + if (! (ccc instanceof ServletBeanContext)) + throw new IllegalStateException("No ServletBeanContext available"); + + _beanContext = (ServletBeanContext)ccc; + } + return _beanContext; + } + + /** + * This method returns a ServletRequestWrapper instance that wraps the request service. + * This is useful in instances where there is code that uses the wrapper interfaces to + * unwrap requests to get to the 'root' request. + */ + /* package */ ServletRequestWrapper getRequestWrapper() + { + return new Wrapper(this); + } + + final protected ServletRequest getServletRequest() + { + ServletRequest servletRequest = getServletBeanContext().getServletRequest(); + if (servletRequest == null) + throw new IllegalStateException("No access to ServletRequest outside request processing"); + return servletRequest; + } + + public java.lang.Object getAttribute(java.lang.String name) + { + return getServletRequest().getAttribute(name); + } + + public java.util.Enumeration getAttributeNames() + { + return getServletRequest().getAttributeNames(); + } + + public java.lang.String getCharacterEncoding() + { + return getServletRequest().getCharacterEncoding(); + } + + public void setCharacterEncoding(java.lang.String env) + throws java.io.UnsupportedEncodingException + { + getServletRequest().setCharacterEncoding(env); + } + + public int getContentLength() + { + return getServletRequest().getContentLength(); + } + + public java.lang.String getContentType() + { + return getServletRequest().getContentType(); + } + + public javax.servlet.ServletInputStream getInputStream() throws java.io.IOException + { + return getServletRequest().getInputStream(); + } + + public java.lang.String getParameter(java.lang.String name) + { + return getServletRequest().getParameter(name); + } + + public java.util.Enumeration getParameterNames() + { + return getServletRequest().getParameterNames(); + } + + public java.lang.String[] getParameterValues(java.lang.String name) + { + return getServletRequest().getParameterValues(name); + } + + public java.util.Map getParameterMap() + { + return getServletRequest().getParameterMap(); + } + + public java.lang.String getProtocol() + { + return getServletRequest().getProtocol(); + } + + public java.lang.String getScheme() + { + return getServletRequest().getScheme(); + } + + public java.lang.String getServerName() + { + return getServletRequest().getServerName(); + } + + public int getServerPort() + { + return getServletRequest().getServerPort(); + } + + public int getLocalPort() + { + return getServletRequest().getLocalPort(); + } + + public java.lang.String getLocalAddr() + { + return getServletRequest().getLocalAddr(); + } + + public java.lang.String getLocalName() + { + return getServletRequest().getLocalName(); + } + + + public java.io.BufferedReader getReader() throws java.io.IOException + { + return getServletRequest().getReader(); + } + + public java.lang.String getRemoteAddr() + { + return getServletRequest().getRemoteAddr(); + } + + public java.lang.String getRemoteHost() + { + return getServletRequest().getRemoteHost(); + } + + public int getRemotePort() + { + return getServletRequest().getRemotePort(); + } + + public void setAttribute(java.lang.String name, java.lang.Object o) + { + getServletRequest().setAttribute(name, o); + } + + public void removeAttribute(java.lang.String name) + { + getServletRequest().removeAttribute(name); + } + + public java.util.Locale getLocale() + { + return getServletRequest().getLocale(); + } + + public java.util.Enumeration getLocales() + { + return getServletRequest().getLocales(); + } + + public boolean isSecure() + { + return getServletRequest().isSecure(); + } + + public javax.servlet.RequestDispatcher getRequestDispatcher(java.lang.String path) + { + return getServletRequest().getRequestDispatcher(path); + } + + public java.lang.String getRealPath(java.lang.String path) + { + return getServletRequest().getRealPath(path); + } + + transient private ServletBeanContext _beanContext; // never access directly +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/servlet/ServletResponseService.java b/controls/src/runtime/org/apache/beehive/controls/runtime/servlet/ServletResponseService.java new file mode 100644 index 0000000..50a9a47 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/servlet/ServletResponseService.java @@ -0,0 +1,180 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.servlet; + +import javax.servlet.ServletResponse; +import javax.servlet.ServletResponseWrapper; + +import org.apache.beehive.controls.api.context.ControlContainerContext; +import org.apache.beehive.controls.api.context.ControlThreadContext; + +/** + * This class is the contextual service implementation for javax.servlet.ServletResponse. It + * acts as an intermediary between the client and the ServletResponse instance held by the + * associated ServletBeanContext. It validates that attempt to access the ServletResponse + * only occur during the servlet request processing lifecycle, then delegates to the underlying + * ServletResponse instance for actual services. + */ +/* package */ class ServletResponseService implements ServletResponse +{ + /** + * This static helper class derives from javax.servlet.ServletRequestWrapper and can + * be used to wrap a ServletRequestService instance in cases where the client expects + * to be able to use the standard wrapper interfaces to unwrap requests. + */ + private static class Wrapper extends ServletResponseWrapper + { + Wrapper(ServletResponseService responseService) + { + super(responseService); + _responseService = responseService; + } + + /** + * Overrides the default ServletRequestWrapper.getRequest implementation. Rather + * than just returning the request passed into the constructor (i.e. the request + * service), it will go unwrap step further and return the current (active) http + * request. + */ + public ServletResponse getResponse() + { + return _responseService.getServletResponse(); + } + + ServletResponseService _responseService; + } + + /* package */ ServletResponseService(ServletBeanContext beanContext) + { + _beanContext = beanContext; + } + + /** + * This method retrieves the current ServletBeanContext for the service. It is capable + * of reassociating with the current active context, if the service instance has been + * serialized/deserialized. + */ + final protected ServletBeanContext getServletBeanContext() + { + if (_beanContext == null) + { + ControlContainerContext ccc = ControlThreadContext.getContext(); + if (! (ccc instanceof ServletBeanContext)) + throw new IllegalStateException("No ServletBeanContext available"); + + _beanContext = (ServletBeanContext)ccc; + } + return _beanContext; + } + + final protected ServletResponse getServletResponse() + { + ServletResponse servletResponse = getServletBeanContext().getServletResponse(); + if (servletResponse == null) + throw new IllegalStateException("No access to ServletResponse outside request processing"); + return servletResponse; + } + + /** + * This method returns a ServletResponseWrapper instance that wraps the response service. + * This is useful in instances where there is code that uses the wrapper interfaces to + * unwrap responses to get to the 'root' response. + */ + /* package */ ServletResponseWrapper getResponseWrapper() + { + return new Wrapper(this); + } + + public java.lang.String getCharacterEncoding() + { + return getServletResponse().getCharacterEncoding(); + } + + public java.lang.String getContentType() + { + return getServletResponse().getContentType(); + } + + public javax.servlet.ServletOutputStream getOutputStream() throws java.io.IOException + { + return getServletResponse().getOutputStream(); + } + + public java.io.PrintWriter getWriter() throws java.io.IOException + { + return getServletResponse().getWriter(); + } + + public void setCharacterEncoding(java.lang.String charset) + { + getServletResponse().setCharacterEncoding(charset); + } + + public void setContentLength(int len) + { + getServletResponse().setContentLength(len); + } + + public void setContentType(java.lang.String type) + { + getServletResponse().setContentType(type); + } + + public void setBufferSize(int size) + { + getServletResponse().setBufferSize(size); + } + + public int getBufferSize() + { + return getServletResponse().getBufferSize(); + } + + public void flushBuffer() throws java.io.IOException + { + getServletResponse().flushBuffer(); + } + + public void resetBuffer() + { + getServletResponse().resetBuffer(); + } + + public boolean isCommitted() + { + return getServletResponse().isCommitted(); + } + + public void reset() + { + getServletResponse().reset(); + } + + public void setLocale(java.util.Locale loc) + { + getServletResponse().setLocale(loc); + } + + public java.util.Locale getLocale() + { + return getServletResponse().getLocale(); + } + + transient private ServletBeanContext _beanContext; // never access directly +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/servlet/ServletServiceProvider.java b/controls/src/runtime/org/apache/beehive/controls/runtime/servlet/ServletServiceProvider.java new file mode 100644 index 0000000..34e9eb4 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/servlet/ServletServiceProvider.java @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.runtime.servlet; + +import java.beans.beancontext.BeanContextServices; +import java.beans.beancontext.BeanContextServiceProvider; +import java.util.Iterator; + +import javax.servlet.ServletContext; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * The ServletContextProvider helper class acts at the BeanContextServiceProvider provides + * instances of web tier services associated with a ServletBeanContext + */ +class ServletServiceProvider implements BeanContextServiceProvider +{ + static final private ServletServiceProvider _provider = new ServletServiceProvider(); + + static ServletServiceProvider getProvider() { + return _provider; + } + + /* package */ ServletServiceProvider() {} + + public Object getService(BeanContextServices bcs, Object requestor, Class serviceClass, Object serviceSelector) + { + // + // These services are only available to controls running within the scope of a + // ServletBeanContext + // + if (! (bcs instanceof ServletBeanContext)) + return null; + + ServletBeanContext sbc = (ServletBeanContext)bcs; + if (serviceClass.equals(ServletContext.class)) + return new ServletContextService(sbc); + + if (serviceClass.equals(HttpServletRequest.class)) + { + HttpRequestService requestService = new HttpRequestService(sbc); + if (sbc.useWrappers()) + return requestService.getHttpRequestWrapper(); + return requestService; + } + + if (serviceClass.equals(HttpServletResponse.class)) + { + HttpResponseService responseService = new HttpResponseService(sbc); + if (sbc.useWrappers()) + return responseService.getHttpResponseWrapper(); + return responseService; + } + + if (serviceClass.equals(ServletRequest.class)) + { + ServletRequestService requestService = new ServletRequestService(sbc); + if (sbc.useWrappers()) + return requestService.getRequestWrapper(); + return requestService; + } + + if (serviceClass.equals(ServletResponse.class)) + { + ServletResponseService responseService = new ServletResponseService(sbc); + if (sbc.useWrappers()) + return responseService.getResponseWrapper(); + return responseService; + } + + return null; + } + + public void releaseService(BeanContextServices bcs, Object requestor, Object service) + { + // noop, because the provider isn't tracking service instances. + } + + public Iterator getCurrentServiceSelectors(BeanContextServices bcs, Class serviceClass) + { + return null; // no selectors + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/webcontext/ControlBeanContextChildSupport.java b/controls/src/runtime/org/apache/beehive/controls/runtime/webcontext/ControlBeanContextChildSupport.java new file mode 100755 index 0000000..e5b4ef2 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/webcontext/ControlBeanContextChildSupport.java @@ -0,0 +1,250 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.runtime.webcontext; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.beans.PropertyVetoException; +import java.beans.VetoableChangeListener; +import java.beans.VetoableChangeSupport; +import java.beans.beancontext.BeanContext; +import java.beans.beancontext.BeanContextChild; +import java.beans.beancontext.BeanContextServiceAvailableEvent; +import java.beans.beancontext.BeanContextServiceRevokedEvent; +import java.beans.beancontext.BeanContextServiceRevokedListener; +import java.beans.beancontext.BeanContextServicesListener; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.io.ObjectInputStream; +import java.util.EventListener; + +/** + * Implementation of the BeanContextChild api for Beehive controls. + */ +public class ControlBeanContextChildSupport + implements BeanContextChild, BeanContextServiceRevokedListener, + BeanContextServicesListener, Serializable, EventListener { + private static final long serialVersionUID = 1; + + private transient BeanContext _beanContext; + private transient boolean _vetodOnce; + private BeanContextChild _peer; + private PropertyChangeSupport _propertyChangeSupport; + private VetoableChangeSupport _vetoableChangeSupport; + + /** + * Constructor. + */ + public ControlBeanContextChildSupport() { + _beanContext = null; + _peer = this; + _vetodOnce = false; + _propertyChangeSupport = new PropertyChangeSupport(_peer); + _vetoableChangeSupport = new VetoableChangeSupport(_peer); + } + + /** + * Constructor -- java bean implements BeanContextChild and delegates the interface + * to this implementation. + * + * @param bcc + */ + public ControlBeanContextChildSupport(BeanContextChild bcc) { + _beanContext = null; + _vetodOnce = false; + _peer = (bcc != null) ? bcc : this; + _propertyChangeSupport = new PropertyChangeSupport(_peer); + _vetoableChangeSupport = new VetoableChangeSupport(_peer); + } + + /** + *

    + * Objects that implement this interface, + * shall fire a java.beans.PropertyChangeEvent, with parameters: + *

    + * propertyName "beanContext", oldValue (the previous nesting + * BeanContext instance, or null), + * newValue (the current nesting + * BeanContext instance, or null). + *

    + * A change in the value of the nesting BeanContext property of this + * BeanContextChild may be vetoed by throwing the appropriate exception. + *

    + * + * @param bc The BeanContext with which + * to associate this BeanContextChild. + */ + public synchronized void setBeanContext(BeanContext bc) throws PropertyVetoException { + + if (bc == _beanContext) return; + + // track if veto'd the first time, then then second time remove anyway (dont except); + if (!_vetodOnce) { + try { + _vetoableChangeSupport.fireVetoableChange("beanContext", _beanContext, bc); + } + catch (PropertyVetoException pve) { + _vetodOnce = true; + throw pve; + } + } + + releaseBeanContextResources(); + BeanContext oldValue = _beanContext; + _beanContext = bc; + _vetodOnce = false; + firePropertyChange("beanContext", oldValue, _beanContext); + } + + /** + * Gets the BeanContext associated + * with this BeanContextChild. + * + * @return the BeanContext associated + * with this BeanContextChild. + */ + public synchronized BeanContext getBeanContext() { + return _beanContext; + } + + /** + * Adds a PropertyChangeListener + * to this BeanContextChild + * in order to receive a PropertyChangeEvent + * whenever the specified property has changed. + * + * @param name the name of the property to listen on + * @param pcl the PropertyChangeListener to add + */ + public void addPropertyChangeListener(String name, PropertyChangeListener pcl) { + _propertyChangeSupport.addPropertyChangeListener(name, pcl); + } + + /** + * Removes a PropertyChangeListener from this + * BeanContextChild so that it no longer + * receives PropertyChangeEvents when the + * specified property is changed. + * + * @param name the name of the property that was listened on + * @param pcl the PropertyChangeListener to remove + */ + public void removePropertyChangeListener(String name, PropertyChangeListener pcl) { + _propertyChangeSupport.removePropertyChangeListener(name, pcl); + } + + /** + * Adds a VetoableChangeListener to + * this BeanContextChild + * to receive events whenever the specified property changes. + * + * @param name the name of the property to listen on + * @param vcl the VetoableChangeListener to add + */ + public void addVetoableChangeListener(String name, VetoableChangeListener vcl) { + _vetoableChangeSupport.addVetoableChangeListener(name, vcl); + } + + /** + * Removes a VetoableChangeListener from this + * BeanContextChild so that it no longer receives + * events when the specified property changes. + * + * @param name the name of the property that was listened on. + * @param vcl the VetoableChangeListener to remove. + */ + public void removeVetoableChangeListener(String name, VetoableChangeListener vcl) { + _vetoableChangeSupport.addVetoableChangeListener(name, vcl); + } + + /** + * The service named has been registered. getService requests for + * this service may now be made. + * + * @param bcsae the BeanContextServiceAvailableEvent + */ + public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) { + // noop + } + + /** + * The service named has been revoked. getService requests for + * this service will no longer be satisifed. + * + * @param bcsre the BeanContextServiceRevokedEvent received + * by this listener. + */ + public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) { + // Noop + } + + /** + * *************************************************************** + */ + + /** + * Get the delegate for this child. + */ + protected BeanContextChild getPeer() { + return _peer; + } + + /** + * Fire a property change event. + * @param name + * @param oldValue + * @param newValue + */ + protected void firePropertyChange(String name, Object oldValue, Object newValue) { + _propertyChangeSupport.firePropertyChange(name, oldValue, newValue); + } + + /** + * Release any resources that may have been acumlated from the current bean context, invoked + * by setBeanContext BEFORE the context is changed. + */ + protected void releaseBeanContextResources() { + // noop + } + + /** + * Serialization support -- throw IOException if a non-serializable delegate is present. + * + * @param out + */ + private void writeObject(ObjectOutputStream out) throws IOException { + if (!_peer.equals(this) && !(_peer instanceof Serializable)) { + throw new IOException("Bean context child delegate does not support serialization!!!"); + } + out.defaultWriteObject(); + } + + /** + * Deserialization support -- just deserialize. + * + * @param in + * @throws IOException + * @throws ClassNotFoundException + */ + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/webcontext/ControlBeanContextServicesSupport.java b/controls/src/runtime/org/apache/beehive/controls/runtime/webcontext/ControlBeanContextServicesSupport.java new file mode 100755 index 0000000..e576fa2 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/webcontext/ControlBeanContextServicesSupport.java @@ -0,0 +1,638 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.runtime.webcontext; + +import java.beans.beancontext.BeanContext; +import java.beans.beancontext.BeanContextChild; +import java.beans.beancontext.BeanContextServiceAvailableEvent; +import java.beans.beancontext.BeanContextServiceProvider; +import java.beans.beancontext.BeanContextServiceRevokedEvent; +import java.beans.beancontext.BeanContextServiceRevokedListener; +import java.beans.beancontext.BeanContextServices; +import java.beans.beancontext.BeanContextServicesListener; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TooManyListenersException; + +/** + * Implementation of BeanContextServices for Beehive Controls. Assumes single threaded usage. + */ +public class ControlBeanContextServicesSupport extends ControlBeanContextSupport implements BeanContextServices { + + private transient Map _serviceProviders; + private transient List _bcsListeners; + + /** + * Constructor. + */ + public ControlBeanContextServicesSupport() { + super(); + } + + /** + * Constructor which allows delegate to be passed in. + * + * @param peer BeanContextServices peer. + */ + public ControlBeanContextServicesSupport(BeanContextServices peer) { + super(peer); + } + + /** + * Adds a service to this BeanContext. + * BeanContextServiceProviders call this method + * to register a particular service with this context. + * If the service has not previously been added, the + * BeanContextServices associates + * the service with the BeanContextServiceProvider and + * fires a BeanContextServiceAvailableEvent to all + * currently registered BeanContextServicesListeners. + * The method then returns true, indicating that + * the addition of the service was successful. + * If the given service has already been added, this method + * simply returns false. + * + * @param serviceClass the service to add + * @param serviceProvider the BeanContextServiceProvider + * associated with the service + * @return true if service was added. + */ + public boolean addService(Class serviceClass, BeanContextServiceProvider serviceProvider) { + // todo: for multithreaded usage this block needs to be synchronized + if (!_serviceProviders.containsKey(serviceClass)) { + _serviceProviders.put(serviceClass, new ServiceProvider(serviceProvider)); + BeanContextServiceAvailableEvent bcsae = new BeanContextServiceAvailableEvent((BeanContextServices)getPeer(), serviceClass); + fireServiceAvailableEvent(bcsae); + return true; + } + // end synchronized + return false; + } + + /** + * BeanContextServiceProviders wishing to remove + * a currently registered service from this context + * may do so via invocation of this method. Upon revocation of + * the service, the BeanContextServices fires a + * BeanContextServiceRevokedEvent to its + * list of currently registered + * BeanContextServiceRevokedListeners and + * BeanContextServicesListeners. + * + * @param serviceClass the service to revoke from this BeanContextServices + * @param serviceProvider the BeanContextServiceProvider associated with + * this particular service that is being revoked + * @param revokeCurrentServicesNow a value of true + * indicates an exceptional circumstance where the + * BeanContextServiceProvider or + * BeanContextServices wishes to immediately + * terminate service to all currently outstanding references + * to the specified service. + */ + public void revokeService(Class serviceClass, BeanContextServiceProvider serviceProvider, boolean revokeCurrentServicesNow) { + // todo: for multithreaded usage this block needs to be synchronized + if (!_serviceProviders.containsKey(serviceClass)) { + return; + } + + // propagate to any children implementing BeanContextServices + Iterator i = iterator(); + while (i.hasNext()) { + Object o = i.next(); + if (o instanceof BeanContextServices) { + ((BeanContextServices) o).revokeService(serviceClass, serviceProvider, revokeCurrentServicesNow); + } + } + + BeanContextServiceRevokedEvent bcsre = + new BeanContextServiceRevokedEvent((BeanContextServices)getPeer(), serviceClass, revokeCurrentServicesNow); + fireServiceRevokedEvent(bcsre); + + // fire revoked event to requestor listeners, if the service is delegated the owner of the + // service should fire these events. + ServiceProvider sp = _serviceProviders.get(serviceClass); + if (!sp.isDelegated()) { + sp.revoke(bcsre); + } + + if (revokeCurrentServicesNow || !sp.hasRequestors()) { + _serviceProviders.remove(serviceClass); + } + // end synchronized + } + + /** + * Reports whether or not a given service is + * currently available from this context. + * + * @param serviceClass the service in question + * @return true if the service is available + */ + public synchronized boolean hasService(Class serviceClass) { + + // todo: for multithreaded usage this block needs to be synchronized + ServiceProvider sp = _serviceProviders.get(serviceClass); + if (sp != null && !sp.isRevoked()) { + return true; + } + + // if service not found locally check in nested context + BeanContext bc = getBeanContext(); + if (bc instanceof BeanContextServices) { + return ((BeanContextServices) bc).hasService(serviceClass); + } + return false; + // end synchronized + } + + /** + * A BeanContextChild, or any arbitrary object + * associated with a BeanContextChild, may obtain + * a reference to a currently registered service from its + * nesting BeanContextServices + * via invocation of this method. When invoked, this method + * gets the service by calling the getService() method on the + * underlying BeanContextServiceProvider. + * + * @param child the BeanContextChild + * associated with this request + * @param requestor the object requesting the service + * @param serviceClass class of the requested service + * @param serviceSelector the service dependent parameter + * @param bcsrl the + * BeanContextServiceRevokedListener to notify + * if the service should later become revoked + * @return a reference to this context's named + * Service as requested or null + * @throws java.util.TooManyListenersException + * + */ + public Object getService(BeanContextChild child, Object requestor, + Class serviceClass, Object serviceSelector, BeanContextServiceRevokedListener bcsrl) + throws TooManyListenersException { + + if (!contains(child)) { + throw new IllegalArgumentException(child + "is not a child of this context!"); + } + + Object service; + BeanContext bc = getBeanContext(); + + // todo: for multithreaded usage this block needs to be synchronized + // check to see if this is a known service + ServiceProvider sp = _serviceProviders.get(serviceClass); + if (sp != null) { + if (sp.isRevoked()) { + return null; + } + else if (sp.isDelegated()) { + service = ((BeanContextServices) bc).getService(getPeer(), requestor, serviceClass, serviceSelector, bcsrl); + } + else { + service = sp.getBCServiceProvider().getService((BeanContextServices)getPeer(), requestor, serviceClass, serviceSelector); + } + + if (service != null) { + sp.addChildReference(requestor, bcsrl); + } + return service; + } + + // unknown service provider, delegate the request to the nested BeanContextServices (if available) + if (bc instanceof BeanContextServices) { + service = ((BeanContextServices) bc).getService(getPeer(), requestor, serviceClass, serviceSelector, bcsrl); + if (service != null) { + sp = new ServiceProvider(); + sp.addChildReference(requestor, bcsrl); + _serviceProviders.put(serviceClass, sp); + } + return service; + } + return null; + } + + /** + * Releases a BeanContextChild's + * (or any arbitrary object associated with a BeanContextChild) + * reference to the specified service by calling releaseService() + * on the underlying BeanContextServiceProvider. + * + * @param child the BeanContextChild + * @param requestor the requestor + * @param service the service + */ + public void releaseService(BeanContextChild child, Object requestor, Object service) { + + if (!contains(child)) { + throw new IllegalArgumentException(child + "is not a child of this context!"); + } + + // todo: for multithreaded usage this block needs to be synchronized + Class serviceClass = findServiceClass(service); + ServiceProvider sp = _serviceProviders.get(serviceClass); + sp.removeChildReference(requestor); + + // if this is a delegated service, delegate the release request + // delegated services are removed from the _serviceProviders table + // as soon as their reference count drops to zero + if (sp.isDelegated()) { + BeanContextServices bcs = (BeanContextServices) getBeanContext(); + bcs.releaseService(this, requestor, service); + if (!sp.hasRequestors()) { + _serviceProviders.remove(serviceClass); + } + } + else { + sp.getBCServiceProvider().releaseService((BeanContextServices)getPeer(), requestor, service); + } + // end synchronized + } + + /** + * Gets the currently available services for this context. + * + * @return an Iterator consisting of the + * currently available services + */ + public Iterator getCurrentServiceClasses() { + + ArrayList currentClasses = new ArrayList(); + for (Class serviceClass : _serviceProviders.keySet()) { + ServiceProvider sp = _serviceProviders.get(serviceClass); + if (!sp.isRevoked() && !sp.isDelegated()) { + currentClasses.add(serviceClass); + } + } + return currentClasses.iterator(); + } + + /** + * Gets the list of service dependent service parameters + * (Service Selectors) for the specified service, by + * calling getCurrentServiceSelectors() on the + * underlying BeanContextServiceProvider. + * + * @param serviceClass the specified service + * @return the currently available service selectors + * for the named serviceClass + */ + public Iterator getCurrentServiceSelectors(Class serviceClass) { + + if (_serviceProviders.containsKey(serviceClass)) { + ServiceProvider sp = _serviceProviders.get(serviceClass); + if (!sp.isDelegated() && !sp.isRevoked()) { + return sp.getBCServiceProvider().getCurrentServiceSelectors((BeanContextServices)getPeer(), serviceClass); + } + } + return null; + } + + /** + * Adds a BeanContextServicesListener to this BeanContext. + * + * @param bcsl the BeanContextServicesListener to add + */ + public void addBeanContextServicesListener(BeanContextServicesListener bcsl) { + if (!_bcsListeners.contains(bcsl)) { + _bcsListeners.add(bcsl); + } + } + + /** + * Removes a BeanContextServicesListener + * from this BeanContext. + * + * @param bcsl the BeanContextServicesListener + * to remove from this context + */ + public void removeBeanContextServicesListener(BeanContextServicesListener bcsl) { + _bcsListeners.remove(bcsl); + } + + /* + * ********************************************************************************** + * Protected + * ********************************************************************************** + */ + + /** + * Invoked when all resources obtained from the current nested bean context + * need to be released. For BeanContextServices this means revoke any services + * obtained from a delegate services provider. Typically invoked when the parent + * context is changed. + */ + protected synchronized void releaseBeanContextResources() { + + for (Class serviceClass : _serviceProviders.keySet()) { + ServiceProvider sp = _serviceProviders.get(serviceClass); + if (sp.isDelegated()) { + sp.revoke(new BeanContextServiceRevokedEvent((BeanContextServices)getPeer(), serviceClass, true)); + } + } + } + + /* + * ********************************************************************************** + * Private + * ********************************************************************************** + */ + + /** + * first a service available event. + * + * @param bcsae + */ + private void fireServiceAvailableEvent(BeanContextServiceAvailableEvent bcsae) { + for (BeanContextServicesListener bcsl : _bcsListeners) { + bcsl.serviceAvailable(bcsae); + } + } + + /** + * Fire a service revoked event. + * + * @param bcsre + */ + private void fireServiceRevokedEvent(BeanContextServiceRevokedEvent bcsre) { + for (BeanContextServicesListener bcsl : _bcsListeners) { + bcsl.serviceRevoked(bcsre); + } + } + + /** + * Initialize data structures. + */ + protected void initialize() { + super.initialize(); + _serviceProviders = Collections.synchronizedMap(new HashMap()); + _bcsListeners = Collections.synchronizedList(new ArrayList()); + } + + /** + * Try to find the registered service for a service object instance. + * May return null if the object instance is not from a service registered + * with this service provider. + * + * @return Service class for service instance. + * @throws IllegalArgumentException if service class can not be found. + */ + private Class findServiceClass(Object service) { + for (Class sc : _serviceProviders.keySet()) { + if (sc.isInstance(service)) { + return sc; + } + } + throw new IllegalArgumentException("Cannot find service provider for: " + service.getClass().getCanonicalName()); + } + + /** + * Deserialization support. + * + * @param ois + * @throws IOException + * @throws ClassNotFoundException + */ + private synchronized void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { + ois.defaultReadObject(); + + int svcsSize = ois.readInt(); + for (int i = 0; i < svcsSize; i++) { + _serviceProviders.put((Class) ois.readObject(), (ServiceProvider) ois.readObject()); + } + + int listenersSize = ois.readInt(); + for (int i = 0; i < listenersSize; i++) { + _bcsListeners.add((BeanContextServicesListener) ois.readObject()); + } + } + + /** + * Serialize this instance including any serializable services and BeanContextServicesListeners. + * Any services or listeners which are not Serializable will not be present once deserialized. + * + * @param oos + * @throws IOException + */ + private synchronized void writeObject(ObjectOutputStream oos) throws IOException { + + int serializable = 0; + oos.defaultWriteObject(); + + // write out the service providers + Set> providers = _serviceProviders.entrySet(); + for (Map.Entry provider : providers) { + if (provider.getValue().isSerializable()) { + serializable++; + } + } + + oos.writeInt(serializable); + if (serializable > 0) { + for (Map.Entry entry : providers) { + if (entry.getValue().isSerializable()) { + oos.writeObject(entry.getKey()); + oos.writeObject(entry.getValue()); + } + } + } + + // write out the event listeners + serializable = 0; + for (BeanContextServicesListener l : _bcsListeners) { + if (l instanceof Serializable) { + serializable++; + } + } + + oos.writeInt(serializable); + if (serializable > 0) { + for (BeanContextServicesListener l : _bcsListeners) { + if (l instanceof Serializable) { + oos.writeObject(l); + } + } + } + } + + /* + * *************************************************************************************** + * Inner Classes + * *************************************************************************************** + */ + + /** + * A ServiceProvider instance is associated with a service class in a Map. One ServiceProvider + * exists for a given service type. The Service manager keeps track of all of the requestors + * for the given service. It provides functionality to add new references to services, remove + * references to services, and to notify referenants that a service has been revoked. + */ + private static final class ServiceProvider implements Serializable { + + private transient HashMap _requestors; + private BeanContextServiceProvider _bcss; + private boolean _revoked; + private final boolean _serializable; + + /** + * Constructor for delegated service provider. + */ + private ServiceProvider() { + _bcss = null; + _serializable = false; + } + + /** + * Constructor for local service provider. + */ + private ServiceProvider(BeanContextServiceProvider bcss) { + _bcss = bcss; + _serializable = _bcss instanceof Serializable; + } + + /** + * Add a child reference to this service provider. + * + * @param requestor + * @param bcsrl + * @throws TooManyListenersException + */ + private synchronized void addChildReference(Object requestor, BeanContextServiceRevokedListener bcsrl) + throws TooManyListenersException { + + ChildServiceReference csr = getRequestors().get(requestor); + if (csr == null) { + csr = new ChildServiceReference(bcsrl); + getRequestors().put(requestor, csr); + return; + } + + if (bcsrl != null && !bcsrl.equals(csr.getListener())) { + throw new TooManyListenersException(); + } + csr.incrementRefCount(); + } + + /** + * Remove a child reference from this Service provider. + * + * @param requestor + */ + private synchronized void removeChildReference(Object requestor) { + ChildServiceReference csr = getRequestors().get(requestor); + if (csr == null) return; + int refCount = csr.decrementRefCount(); + if (refCount <= 0) { + getRequestors().remove(requestor); + } + } + + /** + * Notify all the active requestors for this service that the service + * has been revoked (per spec). + */ + private synchronized void revoke(BeanContextServiceRevokedEvent bcsre) { + for (ChildServiceReference csr : getRequestors().values()) { + csr.getListener().serviceRevoked(bcsre); + } + _revoked = true; + } + + /** + * Get the BeanContextServiceProvider. + */ + private BeanContextServiceProvider getBCServiceProvider() { + return _bcss; + } + + /** + * True if this is a delegated service. + */ + private boolean isDelegated() { + return _bcss == null; + } + + /** + * True if this service has been revoked, but still has references. + */ + private boolean isRevoked() { + return _revoked; + } + + /** + * Can this service provider be serialized? + */ + private boolean isSerializable() { + return _serializable && !_revoked && !isDelegated(); + } + + /** + * True if any requestors are being tracked for this service. + */ + private boolean hasRequestors() { + return !getRequestors().isEmpty(); + } + + /** + * Get a reference to the transient requestors hashmap. + */ + private synchronized HashMap getRequestors() { + if (_requestors == null) { + _requestors = new HashMap(); + } + return _requestors; + } + } + + /** + * Keeps track of the number of references to a service for a single requestor. + * Associated with the requestor in the ServiceProvider's _requestors Map. + */ + private static final class ChildServiceReference { + + private int _refCount; + private BeanContextServiceRevokedListener _bcsrl; + + private ChildServiceReference(BeanContextServiceRevokedListener bcsrl) { + _bcsrl = bcsrl; + _refCount = 1; + } + + private int incrementRefCount() { + return ++_refCount; + } + + private int decrementRefCount() { + return --_refCount; + } + + private BeanContextServiceRevokedListener getListener() { + return _bcsrl; + } + } +} diff --git a/controls/src/runtime/org/apache/beehive/controls/runtime/webcontext/ControlBeanContextSupport.java b/controls/src/runtime/org/apache/beehive/controls/runtime/webcontext/ControlBeanContextSupport.java new file mode 100755 index 0000000..fc4d997 --- /dev/null +++ b/controls/src/runtime/org/apache/beehive/controls/runtime/webcontext/ControlBeanContextSupport.java @@ -0,0 +1,870 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.runtime.webcontext; + +import java.beans.Beans; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyVetoException; +import java.beans.VetoableChangeListener; +import java.beans.Visibility; +import java.beans.beancontext.BeanContext; +import java.beans.beancontext.BeanContextChild; +import java.beans.beancontext.BeanContextMembershipEvent; +import java.beans.beancontext.BeanContextMembershipListener; +import java.beans.beancontext.BeanContextProxy; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * BeanContext implementation for Beehive Controls. + */ +public class ControlBeanContextSupport extends ControlBeanContextChildSupport + implements BeanContext, Serializable, PropertyChangeListener, VetoableChangeListener { + + private static final long serialVersionUID = 1L; + + private transient Map _children; + private transient List _bcMembershipListeners; + + // change listeners used for children, in an attempt to prevent + // the unintentional serialization of this bean context by a + // problematic child. + private transient PropertyChangeListener _childPcl; + private transient VetoableChangeListener _childVcl; + + private boolean _designTime = false; + private boolean _mayUseGui = false; + + /** + * Constructor. + */ + public ControlBeanContextSupport() { + super(); + initialize(); + } + + /** + * Constructor. + * + * @param peer + */ + public ControlBeanContextSupport(BeanContext peer) { + super(peer); + initialize(); + } + + /** + * Instantiate the javaBean named as a + * child of this BeanContext. + * The implementation of the JavaBean is + * derived from the value of the beanName parameter, + * and is defined by the + * java.beans.Beans.instantiate() method. + * + * @param beanName The name of the JavaBean to instantiate + * as a child of this BeanContext + * @throws IOException + * @throws ClassNotFoundException if the class identified + * by the beanName parameter is not found + */ + public Object instantiateChild(String beanName) throws IOException, ClassNotFoundException { + BeanContextChild bcc = getPeer(); + return Beans.instantiate(bcc.getClass().getClassLoader(), beanName, (BeanContext) bcc); + } + + /** + * Analagous to java.lang.ClassLoader.getResourceAsStream(), + * this method allows a BeanContext implementation + * to interpose behavior between the child Component + * and underlying ClassLoader. + * + * @param name the resource name + * @param bcc the specified child + * @return an InputStream for reading the resource, + * or null if the resource could not + * be found. + * @throws IllegalArgumentException if the resource is not valid + */ + public InputStream getResourceAsStream(String name, BeanContextChild bcc) throws IllegalArgumentException { + + // bcc must be a child of this context + if (!contains(bcc)) { + throw new IllegalArgumentException("Child is not a member of this context"); + } + + ClassLoader cl = bcc.getClass().getClassLoader(); + InputStream is; + if (cl != null && (is = cl.getResourceAsStream(name)) != null) { + return is; + } + return ClassLoader.getSystemResourceAsStream(name); + } + + /** + * Analagous to java.lang.ClassLoader.getResource(), this + * method allows a BeanContext implementation to interpose + * behavior between the child Component + * and underlying ClassLoader. + * + * @param name the resource name + * @param bcc the specified child + * @return a URL for the named + * resource for the specified child + * @throws IllegalArgumentException if the resource is not valid + */ + public URL getResource(String name, BeanContextChild bcc) throws IllegalArgumentException { + + // bcc must be a child of this context + if (!contains(bcc)) { + throw new IllegalArgumentException("Child is not a member of this context"); + } + + ClassLoader cl = bcc.getClass().getClassLoader(); + URL url; + if (cl != null && (url = cl.getResource(name)) != null) { + return url; + } + return ClassLoader.getSystemResource(name); + } + + /** + * Adds the specified BeanContextMembershipListener + * to receive BeanContextMembershipEvents from + * this BeanContext whenever it adds + * or removes a child Component(s). + * + * @param bcml the BeanContextMembershipListener to be added + */ + public void addBeanContextMembershipListener(BeanContextMembershipListener bcml) { + _bcMembershipListeners.add(bcml); + } + + /** + * Removes the specified BeanContextMembershipListener + * so that it no longer receives BeanContextMembershipEvents + * when the child Component(s) are added or removed. + * + * @param bcml the BeanContextMembershipListener + * to be removed + */ + public void removeBeanContextMembershipListener(BeanContextMembershipListener bcml) { + _bcMembershipListeners.remove(bcml); + } + + /** + * Returns the number of children in this BeanContext. If this BeanContext + * contains more than Integer.MAX_VALUE children, returns + * Integer.MAX_VALUE. + * + * @return the number of elements in this collection + */ + public int size() { + return _children.size(); + } + + /** + * Returns true if this BeanContext has no children. + */ + public boolean isEmpty() { + return _children.isEmpty(); + } + + /** + * Returns true if this BeanContext contains the specified child. + * + * @param o element whose presence in this BeanContext is to be tested. + * @return true if this BeanContext contains the specified child + * @throws ClassCastException if the type of the specified element + * is incompatible with this collection (optional). + * @throws NullPointerException if the specified element is null and this + * collection does not support null elements (optional). + */ + public boolean contains(Object o) { + return _children.containsKey(o); + } + + /** + * Returns an iterator over the elements in this collection. The + * iterator's collection is non-modifiable and element does not + * correspond to the order that children are added. + * + * @return an Iterator over the children of this BeanContext + */ + public Iterator iterator() { + return Collections.unmodifiableSet(_children.keySet()).iterator(); + } + + /** + * Returns an array containing all of the children in this BeanContext. + *

    + * The returned array will be "safe" in that no references to it are + * maintained by this collection. (In other words, this method must + * allocate a new array even if this collection is backed by an array). + * The caller is thus free to modify the returned array.

    + *

    + * This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all of the elements in this collection + */ + public Object[] toArray() { + return _children.keySet().toArray(); + } + + /** + * Add a child to this BeanContext. If the child is already a child + * of this bean context this method returns immediately with a return + * value of false. + *

    + * If the child implements the BeanContextProxy interface, the child + * AND the BeanContextChild referenced by the proxy are added to this + * BeanContext. + * + * @param o element whose presence in this collection is to be ensured. + * @return true if this collection changed as a result of the + * call + * @throws UnsupportedOperationException add is not supported by + * this collection. + * @throws ClassCastException class of the specified element prevents it + * from being added to this collection. + * @throws NullPointerException if the specified element is null and this + * collection does not support null elements. + * @throws IllegalArgumentException some aspect of this element prevents + * it from being added to this collection. + */ + public boolean add(Object o) { + return internalAdd(o, true); + } + + /** + * Remove the specified child from this BeanContext. If the child + * to be removed implements the BeanContextProxy interface or is + * referenced from an existing BeanContextProxy child both children + * will be removed. + * + * @param o element to be removed from this collection, if present. + * @return true if this collection changed as a result of the + * call + * @throws ClassCastException if the type of the specified element + * is incompatible with this collection (optional). + * @throws NullPointerException if the specified element is null and this + * collection does not support null elements (optional). + * @throws UnsupportedOperationException remove is not supported by this + * collection. + */ + public boolean remove(Object o) { + return internalRemove(o, true); + } + + /** + * Not supported. + * + * @throws UnsupportedOperationException + */ + public boolean addAll(Collection c) { + // NOOP : Not Supported + throw new UnsupportedOperationException(); + } + + /** + * Not supported. + * + * @throws UnsupportedOperationException + */ + public void clear() { + // NOOP: Not supported + throw new UnsupportedOperationException(); + } + + /** + * Not supported. + * + * @throws UnsupportedOperationException + */ + public boolean retainAll(Collection c) { + // NOOP: Not supported + throw new UnsupportedOperationException(); + } + + /** + * Not supported. + * + * @throws UnsupportedOperationException + */ + public boolean removeAll(Collection c) { + throw new UnsupportedOperationException(); + } + + /** + * Returns true if this BeanContext contains all of the children + * in the specified collection. + * + * @param c collection to be checked for containment in this collection. + * @return true if this collection contains all of the elements + * in the specified collection + * @throws ClassCastException if the types of one or more elements + * in the specified collection are incompatible with this + * collection (optional). + * @throws NullPointerException if the specified collection contains one + * or more null elements and this collection does not support null + * elements (optional). + * @throws NullPointerException if the specified collection is + * null. + * @see #contains(Object) + */ + public boolean containsAll(Collection c) { + return _children.keySet().containsAll(c); + } + + /** + * Returns an array containing all of the children of this BeanContext; + * the runtime type of the returned array is that of the specified array. + * + * @param a the array into which the elements of this collection are to be + * stored, if it is big enough; otherwise, a new array of the same + * runtime type is allocated for this purpose. + * @return an array containing the elements of this collection + * @throws ArrayStoreException the runtime type of the specified array is + * not a supertype of the runtime type of every element in this + * collection. + * @throws NullPointerException if the specified array is null. + */ + public Object[] toArray(Object[] a) { + return _children.keySet().toArray(a); + } + + /** + * Sets the "value" of the "designTime" property. + *

    + * If the implementing object is an instance of java.beans.beancontext.BeanContext, + * or a subinterface thereof, then that BeanContext should fire a + * PropertyChangeEvent, to its registered BeanContextMembershipListeners, with + * parameters: + *

      + *
    • propertyName - java.beans.DesignMode.PROPERTYNAME + *
    • oldValue - previous value of "designTime" + *
    • newValue - current value of "designTime" + *
    + * Note it is illegal for a BeanContextChild to invoke this method + * associated with a BeanContext that it is nested within. + * + * @param designTime the current "value" of the "designTime" property + * @see java.beans.beancontext.BeanContext + * @see java.beans.beancontext.BeanContextMembershipListener + * @see java.beans.PropertyChangeEvent + */ + public void setDesignTime(boolean designTime) { + if (designTime == _designTime) return; + _designTime = designTime; + firePropertyChange("designTime", !_designTime, designTime); + } + + /** + * A value of true denotes that JavaBeans should behave in design time + * mode, a value of false denotes runtime behavior. + * + * @return the current "value" of the "designTime" property. + */ + public boolean isDesignTime() { + return _designTime; + } + + /** + * Determines whether this bean needs a GUI. + * + * @return True if the bean absolutely needs a GUI available in + * order to get its work done. + */ + public boolean needsGui() { + BeanContextChild bcc = getPeer(); + if (bcc != this && bcc instanceof Visibility) { + return ((Visibility) bcc).needsGui(); + } + + // check children + for (Object o : _children.keySet()) { + if (o instanceof Visibility) { + if (((Visibility) o).needsGui()) { + return true; + } + } + } + return false; + } + + /** + * This method instructs the bean that it should not use the Gui. + */ + public void dontUseGui() { + if (!_mayUseGui) return; + + _mayUseGui = false; + + for (Object o : _children.keySet()) { + if (o instanceof Visibility) { + ((Visibility) o).dontUseGui(); + } + } + } + + /** + * This method instructs the bean that it is OK to use the Gui. + */ + public void okToUseGui() { + if (_mayUseGui) return; + + _mayUseGui = true; + + for (Object o : _children.keySet()) { + if (o instanceof Visibility) { + ((Visibility) o).okToUseGui(); + } + } + } + + /** + * Determines whether this bean is avoiding using a GUI. + * + * @return true if the bean is currently avoiding use of the Gui. + * e.g. due to a call on dontUseGui(). + */ + public boolean avoidingGui() { + return !_mayUseGui && needsGui(); + } + + /** + * This method gets called when a bound property is changed. + * + * @param evt A PropertyChangeEvent object describing the event source + * and the property that has changed. + */ + public void propertyChange(PropertyChangeEvent evt) { + // monitor "beanContext" property + if ("beanContext".equals(evt.getPropertyName()) && contains(evt.getSource())) { + BeanContext bc = (BeanContext) getPeer(); + if (bc.equals(evt.getOldValue()) && !bc.equals(evt.getNewValue())) { + internalRemove(evt.getSource(), false); + } + } + } + + /** + * This method gets called when a constrained property is changed. + * + * @param evt a PropertyChangeEvent object describing the + * event source and the property that has changed. + * @throws java.beans.PropertyVetoException + * if the recipient wishes the property + * change to be rolled back. + */ + public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException { + // monitor "beanContext" property + if ("beanContext".equals(evt.getPropertyName()) + && contains(evt.getOldValue())) { + // noop: at this point doesn't veto + } + } + + /** + * ************************************************************************************* + */ + + + /** + * Init this classes data structures. + */ + protected void initialize() { + _bcMembershipListeners = new ArrayList(); + _children = Collections.synchronizedMap(new HashMap()); + + _childPcl = new PropertyChangeListener() { + public void propertyChange(PropertyChangeEvent pce) { + ControlBeanContextSupport.this.propertyChange(pce); + } + }; + + _childVcl = new VetoableChangeListener() { + public void vetoableChange(PropertyChangeEvent pce) throws PropertyVetoException { + ControlBeanContextSupport.this.vetoableChange(pce); + } + }; + } + + /** + * Fire a BeanContextMembershipEvent. + * + * @param bcme Event to fire. + * @param childrenAdded True if add event, false if remove event. + */ + private void fireMembershipEvent(BeanContextMembershipEvent bcme, boolean childrenAdded) { + + for (BeanContextMembershipListener bcml : _bcMembershipListeners) { + if (childrenAdded) { + bcml.childrenAdded(bcme); + } + else { + bcml.childrenRemoved(bcme); + } + } + } + + /** + * The internalAdd method is used in two different cases. If an add is done + * through the public add() api, this method is invoked with the publicApi + * parameter set to true. During deserialization of children this method + * is invoked with publicApi set to false. During deserialization it is + * not necessary to set Visibility features or re-register as a listener. + * + * @param o + * @param publicApi + * @return true if added. + */ + private boolean internalAdd(Object o, boolean publicApi) { + + if (contains(o)) return false; + + // todo: for multithreaded usage this block needs to be synchronized + // spec: if the object being added implements BeanContextChild or BeanContextProxy + // need to set the bean context of the object to this bean context. + BeanContextChild bcc = null; + BeanContextProxy bcp = null; + + if (o instanceof BeanContextProxy) { + if (o instanceof BeanContext) { + throw new IllegalArgumentException("May not implement both BeanContextProxy and BeanContext!!"); + } + bcp = (BeanContextProxy) o; + bcc = bcp.getBeanContextProxy(); + } + else if (o instanceof BeanContextChild) { + bcc = (BeanContextChild) o; + } + + if (bcc != null) { + try { + bcc.setBeanContext((BeanContext) getPeer()); + } + catch (PropertyVetoException e) { + throw new IllegalStateException(e); + } + + bcc.addPropertyChangeListener("beanContext", _childPcl); + bcc.addVetoableChangeListener("beanContext", _childVcl); + } + + if (publicApi) { + if (o instanceof Visibility) { + if (_mayUseGui) { + ((Visibility) o).okToUseGui(); + } + else { + ((Visibility) o).dontUseGui(); + } + } + if (o instanceof BeanContextMembershipListener) { + addBeanContextMembershipListener((BeanContextMembershipListener) o); + } + } + + if (bcp == null) { + _children.put(o, new BCChild(o)); + } + else { + _children.put(bcp, new BCChild(bcp, bcc, true)); + _children.put(bcc, new BCChild(bcp, bcc, false)); + } + + BeanContextMembershipEvent bcme = new BeanContextMembershipEvent((BeanContext) getPeer(), new Object[]{o}); + fireMembershipEvent(bcme, true); +// } + return true; + } + + /** + * There are two ways a object can be removed from a BeanContext, by either explicitly invoking the + * remove() api or if the child implements BeanContextChild by calling its setBeanContext() api. + * + * @param o + * @param publicApi + * @return true if successful + */ + private boolean internalRemove(Object o, boolean publicApi) { + + if (!contains(o)) return false; + + // todo: for multithreaded usage this block needs to be synchronized + BeanContextChild bcc = null; + if (o instanceof BeanContextProxy) { + bcc = ((BeanContextProxy) o).getBeanContextProxy(); + } + else if (o instanceof BeanContextChild) { + bcc = (BeanContextChild) o; + } + + if (bcc != null) { + + /* + If remove invoked as a result of the BeanContext receiving an unexpected PropertyChangeEvent + notification as a result of a 3rd party invoking setBeanContext() then the remove implementation + shall not invoke setBeanContext(null) on that child as part of the remove() semantics, since + doing so would overwrite the value previously set by the 3rd party. + */ + if (publicApi) { + + // remove the property/veto listeners -- we know we want to remove the bean + // and don't need to be notified if we have initiated the removal + bcc.removePropertyChangeListener("beanContext", _childPcl); + bcc.removeVetoableChangeListener("beanContext", _childVcl); + + try { + bcc.setBeanContext(null); + } + catch (PropertyVetoException e) { + // rewire the listeners we removed above then except + bcc.addPropertyChangeListener("beanContext", _childPcl); + bcc.addVetoableChangeListener("beanContext", _childVcl); + throw new IllegalStateException(e); + } + } + } + + if (o instanceof BeanContextMembershipListener) { + removeBeanContextMembershipListener((BeanContextMembershipListener) o); + } + + BCChild bc = _children.get(o); + if (bc.isProxy()) { + _children.remove(bc.getChild()); + } + else if (bc.hasProxy()) { + _children.remove(bc.getProxy()); + } + _children.remove(o); + + BeanContextMembershipEvent bcme = new BeanContextMembershipEvent((BeanContext) getPeer(), new Object[]{o}); + fireMembershipEvent(bcme, false); + // end synchronized block + return true; + } + + /** + * Serialize all serializable children (unless this BeanContext has a peer). Any + * children which are not serializable not be present upon deserialization. Also + * serialize any BeanContextMembership listeners which are serializable. + * + * @param out ObjectOutputStream to serialize to. + */ + private synchronized void writeObject(ObjectOutputStream out) throws IOException { + + // todo: for multithreaded usage this block needs to be synchronized + out.defaultWriteObject(); + + // spec: only write children if not using a peer + if (this.equals(getPeer())) { + writeChildren(out); + } + else { + out.writeInt(0); + } + + // write event handlers + int serializable = 0; + for (BeanContextMembershipListener listener : _bcMembershipListeners) { + if (listener instanceof Serializable) serializable++; + } + + out.writeInt(serializable); + if (serializable > 0) { + for (BeanContextMembershipListener listener : _bcMembershipListeners) { + if (listener instanceof Serializable) { + out.writeObject(listener); + } + } + } + // end synchronized block + } + + /** + * Necessary for the case of this bean context having a peer. The specification + * states that a bean context which has a peer should not serialize its children, + * this hook is necessary to allow the peer to serialize children. + * + * @param oos ObjectOutputStream + * @throws IOException + */ + public final void writeChildren(ObjectOutputStream oos) throws IOException { + int serializable = 0; + Set> bcChildren = _children.entrySet(); + for (Map.Entry entry : bcChildren) { + if (entry.getValue().isSerializable()) { + serializable++; + } + } + + oos.writeInt(serializable); + if (serializable > 0) { + for (Map.Entry bc : bcChildren) { + if (bc.getValue().isSerializable()) { + oos.writeObject(bc.getKey()); + } + } + } + } + + /** + * Deserialize this an instance of this class, including any children and + * BeanContextMembershipListeners which were present during serialization and + * were serializable. + * + * @param in ObjectInputStream to deserialize from. + * @throws IOException + * @throws ClassNotFoundException + */ + private synchronized void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + // todo: for multithreaded usage this block needs to be synchronized + in.defaultReadObject(); + initialize(); + + // only deserialize child if not using a peer + if (this.equals(getPeer())) { + readChildren(in); + } + + int listenerCount = in.readInt(); + for (int i = 0; i < listenerCount; i++) { + addBeanContextMembershipListener((BeanContextMembershipListener) in.readObject()); + } + // end synchronized block + } + + /** + * This public api is necessary to allow a bean context with a peer to deserialize its children. + * This api is not part any standard api. + * + * @param in ObjectInputStream + * @throws IOException + * @throws ClassNotFoundException + */ + public final void readChildren(ObjectInputStream in) throws IOException, ClassNotFoundException { + int childCount = in.readInt(); + for (int i = 0; i < childCount; i++) { + internalAdd(in.readObject(), false); + } + } + + /** + * A child of this BeanContext. This class is used to manage the relationship + * between a BeanContextProxy and its BeanContextChild. When a BeanContextProxy + * is added or removed from this context the BeanContextChild it references must + * also be added or removed. This requires that both the BeanContextChild and + * BeanContextProxy are added/removed to the list of children. This class + * is used to map from the proxy -> child and child -> proxy. + *

    + * The _child field is always guarenteed to be non-null, the proxy field may + * be null if this child does not have a proxy. + */ + private final static class BCChild { + + private Object _child; + private BeanContextProxy _proxy; + private boolean _isProxy; + private boolean _serializable; + + /** + * Construct a new BCChild for a child which is not related to a BeanContextProxy. + * + * @param child child to add -- must not be an instance of BeanContextProxy. + */ + protected BCChild(Object child) { + assert child != null; + assert !(child instanceof BeanContextProxy); + + _child = child; + _proxy = null; + _isProxy = false; + _serializable = _child instanceof Serializable; + } + + /** + * Construct a new BCChild for a proxy -> child relationship. + * + * @param proxy BeanContextProxy + * @param child BeanContextChild + * @param isProxy true if this will be entered into the child map keyed on the proxy. + */ + protected BCChild(BeanContextProxy proxy, BeanContextChild child, boolean isProxy) { + assert child != null; + assert proxy != null; + + _child = child; + _proxy = proxy; + _isProxy = isProxy; + _serializable = (_isProxy) && _child instanceof Serializable && _proxy instanceof Serializable; + } + + /** + * Get the proxy. + */ + protected BeanContextProxy getProxy() { + return _proxy; + } + + /** + * Get the child. + */ + protected Object getChild() { + return _child; + } + + /** + * True if a proxy was set for this child. + */ + protected boolean hasProxy() { + return _proxy != null; + } + + /** + * True if this child was keyed by its proxy in the child map. + */ + protected boolean isProxy() { + return _isProxy; + } + + /** + * True if this BCChild is serializable. + */ + protected boolean isSerializable() { + return _serializable; + } + } +} diff --git a/controls/src/spi/org/apache/beehive/controls/spi/bean/ControlFactory.java b/controls/src/spi/org/apache/beehive/controls/spi/bean/ControlFactory.java new file mode 100644 index 0000000..b37edab --- /dev/null +++ b/controls/src/spi/org/apache/beehive/controls/spi/bean/ControlFactory.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.spi.bean; + +import org.apache.beehive.controls.api.bean.ControlBean; +import org.apache.beehive.controls.api.context.ControlBeanContext; +import org.apache.beehive.controls.api.properties.PropertyMap; + +/** + * The ControlFactory interface defines a service provider interface for integrating + * an external JavaBean instantation/configuration framework with the Controls runtime. + */ +public interface ControlFactory +{ + /** + * Instantiates a new ControlBean of the requested class, using mechanisms provided + * by a provider-specific JavaBeans framework. + * + * @param beanClass the ControlBean class to instantiate + * @param props an initial set of client-specified properties to associate with the + * bean instance. May be null. + * @param context the containing ControlBeanContext for the bean, if nested inside of + * a container or other control. May be null to use the current active + * execution context. + * @param id the bean control ID. Must be unique within the containing context. If + * null, a unique identifier will be auto-generated. + * @return a new ControlBean instance of the requested class. + */ + public T instantiate(Class beanClass, + PropertyMap props, + ControlBeanContext context, + String id); +} diff --git a/controls/src/spi/org/apache/beehive/controls/spi/bean/JavaControlFactory.java b/controls/src/spi/org/apache/beehive/controls/spi/bean/JavaControlFactory.java new file mode 100644 index 0000000..900b106 --- /dev/null +++ b/controls/src/spi/org/apache/beehive/controls/spi/bean/JavaControlFactory.java @@ -0,0 +1,133 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.spi.bean; + +import java.io.InputStream; +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.Properties; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.beehive.controls.api.properties.PropertyMap; +import org.apache.beehive.controls.api.properties.BeanPropertyMap; +import org.apache.beehive.controls.api.properties.PropertyKey; +import org.apache.beehive.controls.api.bean.ControlBean; +import org.apache.beehive.controls.api.context.ControlBeanContext; +import org.apache.beehive.controls.api.ControlException; + +/** + * The SimpleControlFactory class is a default implementation of the + * org.apache.beehive.controls.api.bean.ControlFactory interface. It + * uses Java reflection to create new control instances. + * + * @see org.apache.beehive.controls.api.bean.Controls#instantiate + * @see org.apache.beehive.controls.spi.bean.ControlFactory + */ +public class JavaControlFactory implements ControlFactory +{ + private static ConcurrentHashMap _constructors = new ConcurrentHashMap(); + + private static final Properties _extImplBindings = new Properties(); + + private static final String EXT_IMPL_BINDING_CONFIG = "controlbindings.properties"; + private static final String KEY_CONTROL_IMPLEMENTATION = "controlImplementation"; + + static + { + InputStream is = JavaControlFactory.class.getClassLoader().getResourceAsStream( EXT_IMPL_BINDING_CONFIG ); + + if (is != null) { + try { + _extImplBindings.load(is); + } + catch(IOException ignore) { + // ignore... + } + finally { + try{is.close();} + catch(IOException ignore) { + // ignore... + } + } + } + } + + /** + * Instantiates a new ControlBean of the requested class, using mechanisms provided + * by a provider-specific JavaBeans framework. + * + * @param beanClass the ControlBean class to instantiate + * @param props an initial set of client-specified properties to associate with the + * bean instance. May be null. + * @param context the containing ControlBeanContext for the bean, if nested inside of + * a container or other control. May be null to use the current active + * execution context. + * @param id the bean control ID. Must be unique within the containing context. If + * null, a unique identifier will be auto-generated. + * @return a new ControlBean instance of the requested class. + */ + public T instantiate(Class beanClass, + PropertyMap props, + ControlBeanContext context, + String id) + { + String beanClassName = beanClass.getName(); + + String extImplBinding = _extImplBindings.getProperty( beanClassName + "_" + id ); + if ( extImplBinding == null ) + extImplBinding = _extImplBindings.getProperty( beanClassName ); + + if ( extImplBinding != null ) + { + BeanPropertyMap bpm = props == null ? new BeanPropertyMap( beanClass ) : new BeanPropertyMap( props ); + PropertyKey propKey = new PropertyKey(org.apache.beehive.controls.api.properties.BaseProperties.class, + KEY_CONTROL_IMPLEMENTATION); + + bpm.setProperty( propKey, extImplBinding ); + props = bpm; + } + + T ret = null; + try + { + Constructor ctor = _constructors.get(beanClass); + if (ctor == null) + { + ctor = beanClass.getConstructor(ControlBeanContext.class, + String.class, + PropertyMap.class); + + _constructors.put(beanClass, ctor); + } + ret = ctor.newInstance(context, id, props); + } + catch (InvocationTargetException ite) + { + Throwable t = ite.getCause(); + throw new ControlException("ControlBean constructor exception", t); + } + catch (Exception e) + { + throw new ControlException("Exception creating ControlBean", e); + } + + return ret; + } +} diff --git a/controls/src/spi/org/apache/beehive/controls/spi/context/ControlBeanContextFactory.java b/controls/src/spi/org/apache/beehive/controls/spi/context/ControlBeanContextFactory.java new file mode 100644 index 0000000..fbd9494 --- /dev/null +++ b/controls/src/spi/org/apache/beehive/controls/spi/context/ControlBeanContextFactory.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.spi.context; + +import org.apache.beehive.controls.api.bean.ControlBean; +import org.apache.beehive.controls.api.context.ControlBeanContext; + +/** + * The ControlBeanContextFactory defines a service provider interface for providing implementations + * of factories to create a {@link org.apache.beehive.controls.api.context.ControlBeanContext} + * object. This factory is only used to create ControlBeanContexts that are associated + * with a ControlBean instance; it is not used to create + * {@link org.apache.beehive.controls.api.context.ControlContainerContext} objects. + */ +public interface ControlBeanContextFactory { + + /** + * Instantiate a {@link ControlBeanContext} object that will be associated with the + * provided {@link ControlBean}. + * + * @param controlBean + * @return the ControlBeanContext instance + */ + public T instantiate(ControlBean controlBean); +} diff --git a/controls/src/spi/org/apache/beehive/controls/spi/svc/Interceptor.java b/controls/src/spi/org/apache/beehive/controls/spi/svc/Interceptor.java new file mode 100644 index 0000000..8d9fb80 --- /dev/null +++ b/controls/src/spi/org/apache/beehive/controls/spi/svc/Interceptor.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.spi.svc; + +import java.lang.reflect.Method; + +import org.apache.beehive.controls.api.bean.ControlBean; + +/** + * The controls implementation architecture has a interceptor model for + * adding annotation-based features. This model provides the ability to + * associate a JavaBeans service interface with an annotation to define + * its runtime feature behaviour. Such interfaces must extend this + * Interceptor interface, which defines the contract that the controls runtime + * has with interceptors. + * + * The controls runtime will automatically instantiate and execute + * implementations of interceptors at the appropriate execution points + * (pre/post invocation of a control operation, etc). + * + * The control runtime will continue the normal flow of control (ie, subsequent + * interceptors and operation/event execution) unless an interceptor throws a + * {@link InterceptorPivotException}. When this type of execption is encountered, + * the runtime will "pivot" out. + */ +public interface Interceptor +{ + /** Called before a control operation is invoked */ + public void preInvoke( ControlBean cb, Method m, Object [] args) + throws InterceptorPivotException; + + /** Called after a control operation is invoked */ + public void postInvoke( ControlBean cb, Method m, Object [] args, Object retval, Throwable t ); + + /** Called before a control event is fired (through a client proxy) */ + public void preEvent( ControlBean cb, Class eventSet, Method m, Object [] args ) + throws InterceptorPivotException; + + /** Called after a control event is fired (through a client proxy) */ + public void postEvent( ControlBean cb, Class eventSet, Method m, Object [] args, Object retval, Throwable t ); +} diff --git a/controls/src/spi/org/apache/beehive/controls/spi/svc/InterceptorAnnotation.java b/controls/src/spi/org/apache/beehive/controls/spi/svc/InterceptorAnnotation.java new file mode 100644 index 0000000..b8c0361 --- /dev/null +++ b/controls/src/spi/org/apache/beehive/controls/spi/svc/InterceptorAnnotation.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.spi.svc; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * InterceptorAnnotation is the meta-annotation used to identify annotations + * that are interceptor-based, and bind an interceptor service interface to + * those annotations. + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.ANNOTATION_TYPE) +public @interface InterceptorAnnotation +{ + /** + * The Interceptor-based JavaBeans service interface associated with the annotated annotation + * */ + Class service(); +} diff --git a/controls/src/spi/org/apache/beehive/controls/spi/svc/InterceptorPivotException.java b/controls/src/spi/org/apache/beehive/controls/spi/svc/InterceptorPivotException.java new file mode 100644 index 0000000..e7be967 --- /dev/null +++ b/controls/src/spi/org/apache/beehive/controls/spi/svc/InterceptorPivotException.java @@ -0,0 +1,111 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.spi.svc; + +/** + * The InterceptorPivotException class declares a checked exception that is thrown by + * an Interceptor upon pivoting. For example, if an interceptor wishes to stop a method + * from executing further and return a value, it can throw this exception and embed in + * the exception the return value that it wishes the method to return. + */ +public class InterceptorPivotException + extends Exception +{ + /** + * Comment for serialVersionUID + */ + private static final long serialVersionUID = 1L; + private Object returnValue; + private String interceptorName; + + /** + * Constructs a InterceptorPivotException object with the specified interceptor. + * + * @param interceptorName name of the interceptor that generated this exception + */ + public InterceptorPivotException(String interceptorName) + { + super(); + this.interceptorName = interceptorName; + } + + /** + * Constructs a InterceptorPivotException object with the specified interceptor + * and return value for the method that is intercepted. + * + * @param interceptorName name of the interceptor that generated this exception + * @param returnValue the return value of the method that is intercepted. + */ + public InterceptorPivotException(String interceptorName, Object returnValue) + { + super(); + this.interceptorName = interceptorName; + this.returnValue = returnValue; + } + + /** + * Constructs a ServiceException object using the specified interceptor, the + * return value for the method that is intercepted and message. + * + * @param interceptorName name of the interceptor that generated this exception + * @param returnValue the return value of the method that is intercepted. + * @param message The message to use. + */ + public InterceptorPivotException(String interceptorName, Object returnValue, String message) + { + super(message); + this.interceptorName = interceptorName; + this.returnValue = returnValue; + } + + /** + * Constructs a ServiceException object using the specified interceptor and + * a message. + * + * @param interceptorName name of the interceptor that generated this exception + * @param message The message to use. + */ + public InterceptorPivotException(String interceptorName, String message) + { + super(message); + this.interceptorName = interceptorName; + } + + /** + * @return Returns the interceptorName. + */ + public String getInterceptorName() + { + return interceptorName; + } + /** + * @return Returns the returnValue. + */ + public Object getReturnValue() + { + return returnValue; + } + /** + * @param interceptorName The interceptorName to set. + */ + public void setInterceptorName(String interceptorName) + { + this.interceptorName = interceptorName; + } +} diff --git a/controls/src/spi/org/apache/beehive/controls/spi/svc/ServiceException.java b/controls/src/spi/org/apache/beehive/controls/spi/svc/ServiceException.java new file mode 100644 index 0000000..6b5cfc4 --- /dev/null +++ b/controls/src/spi/org/apache/beehive/controls/spi/svc/ServiceException.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.spi.svc; + +/** + * The ServiceException class declares an checked exception that is thrown by the Service API + * runtime under certain failure conditions. + */ +public class ServiceException + extends Exception +{ + /** + * Constructs a ServiceException object with the specified String as a message. + * + * @param message The message to use. + */ + public ServiceException(String message) + { + super(message); + } + + /** + * Constructs a ServiceException object using the specified String as a message, and the + * specified Throwable as a nested exception. + * + * @param message The message to use. + * @param t The exception to nest within this + * exception. + */ + public ServiceException(String message, Throwable t) + { + super(message + "[" + t.getMessage() + "]", t); + } + + /* Private Constant(s) */ + private static final long serialVersionUID = 8818197331269164527L; +} diff --git a/controls/src/test-container/org/apache/beehive/controls/test/ControlTestException.java b/controls/src/test-container/org/apache/beehive/controls/test/ControlTestException.java new file mode 100644 index 0000000..96fc041 --- /dev/null +++ b/controls/src/test-container/org/apache/beehive/controls/test/ControlTestException.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.test; + +/** + * Exception type thrown when the controls test infrastructure reports framework errors. + */ +public class ControlTestException + extends RuntimeException { + + public ControlTestException() { + super(); + } + + public ControlTestException(String message) { + super(message); + } + + public ControlTestException(Throwable cause) { + super(cause); + } + + public ControlTestException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/controls/src/test-container/org/apache/beehive/controls/test/container/ControlTestContainerContext.java b/controls/src/test-container/org/apache/beehive/controls/test/container/ControlTestContainerContext.java new file mode 100644 index 0000000..15642ef --- /dev/null +++ b/controls/src/test-container/org/apache/beehive/controls/test/container/ControlTestContainerContext.java @@ -0,0 +1,87 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + $Header:$ +*/ +package org.apache.beehive.controls.test.container; + +import java.io.InputStream; +import java.beans.beancontext.BeanContextChild; +import java.beans.beancontext.BeanContextServiceProvider; + +import org.apache.beehive.controls.runtime.bean.ControlContainerContext; +import org.apache.beehive.controls.runtime.bean.WebContextFactoryProvider; +import org.apache.beehive.controls.spi.context.ControlBeanContextFactory; + +/** + * ControlContainerContext implementation used to test controls in a standalone JVM. + */ +public class ControlTestContainerContext + extends ControlContainerContext { + + private transient BeanContextServiceProvider _cbcFactoryProvider; + + public ControlTestContainerContext(){ + // + // This sets the BeanContextServicesFactory instance on the ControlBeanContext and allows this + // CCC object to be created with a BeanContextServicesDelegate of the type returned by this factory + // + super(WebContextFactoryProvider.WEB_CONTEXT_BCS_FACTORY); + } + + /** + * Called by BeanContextSupport superclass during construction and deserialization to + * initialize subclass transient state + */ + public void initialize() + { + super.initialize(); + // Register an *internal* service that is used to create ControlBeanContext objects for + // children of this control container + // + _cbcFactoryProvider = WebContextFactoryProvider.getProvider(); + addService(ControlBeanContextFactory.class, _cbcFactoryProvider); + } + + /** + * Override ControlBeanContext.getService(). A control bean creates its bean context using the + * ControlBeanContextFactory service provided by this context. A control bean will attempt to create + * its context before adding its self to this context as a child. This creates a chicken/egg problem since + * only a child of a context may request a service from it. + * + * This method provides a way to crack the chicken/egg problem by first trying to get the service using the + * control bean context's getService() method, and if that call returns null and the requested service is + * the ControlBeanContextFactory then returning an instance of the service provider. + * + * @param serviceClass + * @param selector + * @return + */ + public T getService(Class serviceClass, Object selector) + { + T service = super.getService(serviceClass, selector); + if (service == null && serviceClass.equals(ControlBeanContextFactory.class)) { + return (T)_cbcFactoryProvider.getService(this, this, serviceClass, selector); + } + return service; + } + + public InputStream getResourceAsStream(String name, BeanContextChild bcc) { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + InputStream inputStream = classLoader.getResourceAsStream(name); + return inputStream; + } +} diff --git a/controls/src/test-container/org/apache/beehive/controls/test/junit/ControlTestCase.java b/controls/src/test-container/org/apache/beehive/controls/test/junit/ControlTestCase.java new file mode 100644 index 0000000..9ebaa37 --- /dev/null +++ b/controls/src/test-container/org/apache/beehive/controls/test/junit/ControlTestCase.java @@ -0,0 +1,103 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + $Header:$ +*/ +package org.apache.beehive.controls.test.junit; + +import junit.framework.TestCase; + +import org.apache.beehive.controls.api.bean.ControlBean; +import org.apache.beehive.controls.api.context.ControlContainerContext; +import org.apache.beehive.controls.api.context.ControlThreadContext; +import org.apache.beehive.controls.test.container.ControlTestContainerContext; +import org.apache.beehive.controls.test.util.ControlContainerContextManager; +import org.apache.beehive.controls.test.util.ControlContainerContextManagerFactory; +import org.apache.beehive.controls.test.ControlTestException; + +/** + * Base control test case. + */ +public abstract class ControlTestCase + extends TestCase { + + /* todo: push strings into a .properties file */ + + private ControlContainerContextManager _controlContainerContextManager = null; + + public void setUp() + throws Exception { + + super.setUp(); + + beginContext(); + initializeControls(); + } + + public void tearDown() + throws Exception { + + super.tearDown(); + + endContext(); + } + + protected ControlContainerContext initializeControlContainerContext() { + return new ControlTestContainerContext(); + } + + protected ControlContainerContext getControlContainerContext() { + return getControlContainerContextManager().getControlContainerContext(); + } + + protected void initializeControls() { + getControlContainerContextManager().instantiateControls(this); + } + + protected void beginContext() { + getControlContainerContextManager().beginContext(); + } + + protected void endContext() { + getControlContainerContextManager().endContext(); + } + + protected ControlContainerContextManager getControlContainerContextManager() { + if(_controlContainerContextManager == null) { + ControlContainerContext ccc = initializeControlContainerContext(); + + if(ccc == null) + throw new ControlTestException("Could not instantiate a ControlContainerContextManager as the control container context was null"); + + _controlContainerContextManager = ControlContainerContextManagerFactory.getInstance(ccc); + } + + return _controlContainerContextManager; + } + + protected ControlBean instantiateControl(String className) { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + try { + Object controlBean = java.beans.Beans.instantiate(classLoader, className, ControlThreadContext.getContext()); + assert controlBean instanceof ControlBean; + return (ControlBean)controlBean; + } + catch(Exception e) { + throw new ControlTestException("Could not instantiate control with class \"" + className + + "\". Cause: " + e.getMessage(), e); + } + } +} diff --git a/controls/src/test-container/org/apache/beehive/controls/test/util/ControlContainerContextManager.java b/controls/src/test-container/org/apache/beehive/controls/test/util/ControlContainerContextManager.java new file mode 100644 index 0000000..f1a25b3 --- /dev/null +++ b/controls/src/test-container/org/apache/beehive/controls/test/util/ControlContainerContextManager.java @@ -0,0 +1,61 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + $Header:$ +*/ +package org.apache.beehive.controls.test.util; + +import org.apache.beehive.controls.api.bean.Controls; +import org.apache.beehive.controls.api.context.ControlThreadContext; +import org.apache.beehive.controls.api.context.ControlContainerContext; +import org.apache.beehive.controls.test.ControlTestException; + +/** + * + */ +public class ControlContainerContextManager { + + private ControlContainerContext _controlContainerContext; + + protected ControlContainerContextManager(ControlContainerContext controlContainerContext) { + super(); + _controlContainerContext = controlContainerContext; + } + + public ControlContainerContext getControlContainerContext() { + return ControlThreadContext.getContext(); + } + + public void instantiateControls(Object object) { + Class testClass = object.getClass(); + try { + Controls.initializeClient(Thread.currentThread().getContextClassLoader(), object, ControlThreadContext.getContext()); + } + catch(Exception e) { + if(e.getCause() instanceof ClassNotFoundException) + System.err.println("Could not locate initializer for '" + getClass().getName() + "'. Assuming no controls to initialize"); + else throw new ControlTestException("Exception initializing controls for type '" + testClass.getName() + "'", e); + } + } + + public void beginContext() { + _controlContainerContext.beginContext(); + } + + public void endContext() { + _controlContainerContext.endContext(); + } +} \ No newline at end of file diff --git a/controls/src/test-container/org/apache/beehive/controls/test/util/ControlContainerContextManagerFactory.java b/controls/src/test-container/org/apache/beehive/controls/test/util/ControlContainerContextManagerFactory.java new file mode 100644 index 0000000..a66d8f5 --- /dev/null +++ b/controls/src/test-container/org/apache/beehive/controls/test/util/ControlContainerContextManagerFactory.java @@ -0,0 +1,31 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + $Header:$ +*/ +package org.apache.beehive.controls.test.util; + +import org.apache.beehive.controls.api.context.ControlContainerContext; +import org.apache.beehive.controls.test.container.ControlTestContainerContext; + +/** + */ +public final class ControlContainerContextManagerFactory { + + public static ControlContainerContextManager getInstance(ControlContainerContext controlContainerContext) { + return new ControlContainerContextManager(controlContainerContext); + } +} diff --git a/controls/src/test-container/org/apache/beehive/controls/test/util/strings.properties b/controls/src/test-container/org/apache/beehive/controls/test/util/strings.properties new file mode 100644 index 0000000..e69de29 diff --git a/controls/test/build.xml b/controls/test/build.xml new file mode 100644 index 0000000..dfca734 --- /dev/null +++ b/controls/test/build.xml @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/controls/test/dist-test/build.xml b/controls/test/dist-test/build.xml new file mode 100644 index 0000000..037ba74 --- /dev/null +++ b/controls/test/dist-test/build.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/controls/test/dist-test/files/build.xml b/controls/test/dist-test/files/build.xml new file mode 100644 index 0000000..a29768e --- /dev/null +++ b/controls/test/dist-test/files/build.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/controls/test/dist-test/files/common/controls-test-imports.xml b/controls/test/dist-test/files/common/controls-test-imports.xml new file mode 100644 index 0000000..bfc7799 --- /dev/null +++ b/controls/test/dist-test/files/common/controls-test-imports.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/controls/test/src/README.txt b/controls/test/src/README.txt new file mode 100644 index 0000000..0b71964 --- /dev/null +++ b/controls/test/src/README.txt @@ -0,0 +1,26 @@ +This file describes what the various directories within control/test/src +are for and what to put where. + +Controls test are made up of four parts. + +* junit-controls + + This are examples of controls used for excercising different features + of the controls framework. For each new junit test a new control should + be created. + +* junit-tests + These are the Junit files for the test suite. When adding a new Junit test + file categorize into existing or new package group based on the functionality + being tests as necessary. + +* auxilaries + + Auxilary files are things like Checkers. Checkers must be compiled *before* + the clients that will need them are built. Files in 'aux' should not + contain any dependencies on files which are outside of the aux src tree. + +NOTE: + Tests which require the JPF context should be added to the controlsWeb tests + in the netui test suite. The controls DRTs do not have a dependency on netui + and should remain that way. diff --git a/controls/test/src/auxilaries/org/apache/beehive/controls/test/controls/checker/HelloChecked.java b/controls/test/src/auxilaries/org/apache/beehive/controls/test/controls/checker/HelloChecked.java new file mode 100644 index 0000000..e5e1bb6 --- /dev/null +++ b/controls/test/src/auxilaries/org/apache/beehive/controls/test/controls/checker/HelloChecked.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.checker; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.properties.PropertySet; + +@ControlInterface( checkerClass=HelloChecker.class ) +public interface HelloChecked +{ + // + // A simple enumerated type used to customize the greeting by gender + // + public enum GenderType + { + NEUTRAL, MALE, FEMALE + } + + public @interface Gender + { + GenderType value(); + } + + /** + * Declare a simple PropertySet, that allows the salutation used by the custom + * control to be customized. + */ + @PropertySet + @Target( {ElementType.TYPE, ElementType.FIELD, ElementType.METHOD} ) + @Retention(RetentionPolicy.RUNTIME) + public @interface Greeting + { + String salutation() default "Hello"; + Gender gender() default @Gender(GenderType.NEUTRAL); + } + + java.lang.String hello(java.lang.String name); + + java.lang.String lastVisitor(); + + int visitorCount(); +} diff --git a/controls/test/src/auxilaries/org/apache/beehive/controls/test/controls/checker/HelloChecker.java b/controls/test/src/auxilaries/org/apache/beehive/controls/test/controls/checker/HelloChecker.java new file mode 100644 index 0000000..24ce271 --- /dev/null +++ b/controls/test/src/auxilaries/org/apache/beehive/controls/test/controls/checker/HelloChecker.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.checker; + +import com.sun.mirror.apt.AnnotationProcessorEnvironment; +import com.sun.mirror.declaration.Declaration; +import com.sun.mirror.declaration.TypeDeclaration; +import com.sun.mirror.declaration.FieldDeclaration; + +import org.apache.beehive.controls.api.bean.ControlChecker; + +public class HelloChecker implements ControlChecker +{ + public void check(Declaration decl, AnnotationProcessorEnvironment env) + { + // Just refer to the public interface in some way to test + // this kind of dep. + HelloChecked.GenderType gt = HelloChecked.GenderType.NEUTRAL; + + if ( decl instanceof TypeDeclaration ) + { + env.getMessager().printNotice(decl.getPosition(), + "HelloChecker: found type decl=" + decl); + } + else if ( decl instanceof FieldDeclaration ) + { + env.getMessager().printNotice(decl.getPosition(), + "HelloChecker: found field decl=" + decl); + } + else + { + env.getMessager().printNotice(decl.getPosition(), + "HelloChecker: found decl=" + decl); + } + } +} + diff --git a/controls/test/src/auxilaries/org/apache/beehive/controls/test/controls/interceptor/SampleInterceptor.java b/controls/test/src/auxilaries/org/apache/beehive/controls/test/controls/interceptor/SampleInterceptor.java new file mode 100644 index 0000000..91391d7 --- /dev/null +++ b/controls/test/src/auxilaries/org/apache/beehive/controls/test/controls/interceptor/SampleInterceptor.java @@ -0,0 +1,53 @@ +package org.apache.beehive.controls.test.controls.interceptor; +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +import org.apache.beehive.controls.api.bean.ControlBean; +import org.apache.beehive.controls.spi.svc.Interceptor; +import org.apache.beehive.controls.spi.svc.InterceptorPivotException; +import java.lang.reflect.Method; + +public class SampleInterceptor implements Interceptor +{ + /** Called before a control operation is invoked */ + public void preInvoke( ControlBean cb, Method m, Object [] args) + throws InterceptorPivotException + { + System.out.println( "SampleInterceptor.preInvoke() called: bean=" + cb.getControlID() + " m=" + m.getName() ); + } + + /** Called after a control operation is invoked */ + public void postInvoke( ControlBean cb, Method m, Object [] args, Object retval, Throwable t ) + { + System.out.println( "SampleInterceptor.postInvoke() called: bean=" + cb.getControlID() + " m=" + m.getName() ); + } + + /** Called before a control event is fired (through a client proxy) */ + public void preEvent( ControlBean cb, Class eventSet, Method m, Object [] args ) + throws InterceptorPivotException + { + System.out.println( "SampleInterceptor.preEvent() called: bean=" + cb.getControlID() + " es=" + eventSet.getName() + " m=" + m.getName() ); + } + + /** Called after a control event is fired (through a client proxy) */ + public void postEvent( ControlBean cb, Class eventSet, Method m, Object [] args, Object retval, Throwable t ) + { + System.out.println( "SampleInterceptor.postEvent() called: bean=" + cb.getControlID() + " es=" + eventSet.getName() + " m=" + m.getName() ); + } +} diff --git a/controls/test/src/auxilaries/org/apache/beehive/controls/test/controls/interceptor/SampleInterceptorAnnotation.java b/controls/test/src/auxilaries/org/apache/beehive/controls/test/controls/interceptor/SampleInterceptorAnnotation.java new file mode 100644 index 0000000..5d4e55b --- /dev/null +++ b/controls/test/src/auxilaries/org/apache/beehive/controls/test/controls/interceptor/SampleInterceptorAnnotation.java @@ -0,0 +1,27 @@ +package org.apache.beehive.controls.test.controls.interceptor; +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +import org.apache.beehive.controls.spi.svc.InterceptorAnnotation; + +@InterceptorAnnotation( service=SampleInterceptor.class ) +public @interface SampleInterceptorAnnotation +{ +} + diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/assembly/AssemblyTestAssembler.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/assembly/AssemblyTestAssembler.java new file mode 100644 index 0000000..c0d14d0 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/assembly/AssemblyTestAssembler.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.assembly; + +import org.apache.beehive.controls.api.assembly.ControlAssembler; +import org.apache.beehive.controls.api.assembly.ControlAssemblyContext; +import org.apache.beehive.controls.api.assembly.ControlAssemblyException; + +import java.io.File; +import java.io.FileWriter; + +public class AssemblyTestAssembler implements ControlAssembler { + + public void assemble(ControlAssemblyContext cac) throws ControlAssemblyException { + + String genPackageName = "org.apache.beehive.controls.test.assembly.generated"; + String genClassName = "AssemblyTestGenerated"; + /* Write basic class structure out for later + compiliation and then finally instantiation in a test */ + try { + File dir = new File(cac.getSrcOutputDir(), genPackageName.replace(".", File.separator)); + dir.mkdirs(); + + FileWriter fw = new FileWriter(new File(dir, genClassName + ".java")); + fw.write("package " + genPackageName + ";" + + "public class " + genClassName + "{ }"); + fw.close(); + } + catch (java.io.IOException ioe) { + throw new ControlAssemblyException("Error writing " + + genPackageName.replace(".", File.separator) + + File.separator + genClassName, ioe); + } + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/assembly/AssemblyTestAssembler2.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/assembly/AssemblyTestAssembler2.java new file mode 100644 index 0000000..d90a623 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/assembly/AssemblyTestAssembler2.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.test.controls.assembly; + +import org.apache.beehive.controls.api.assembly.ControlAssembler; +import org.apache.beehive.controls.api.assembly.ControlAssemblyContext; +import org.apache.beehive.controls.api.assembly.ControlAssemblyException; + +import java.io.File; +import java.io.FileWriter; + +public class AssemblyTestAssembler2 implements ControlAssembler { + + public void assemble(ControlAssemblyContext cac) throws ControlAssemblyException { + + String genPackageName = "org.apache.beehive.controls.test.assembly.generated"; + String genClassName = "AssemblyTest2Generated"; + + /* Write basic class structure out for later + compiliation and then finally instantiation in a test */ + try { + File dir = new File(cac.getSrcOutputDir(), genPackageName.replace(".", File.separator)); + dir.mkdirs(); + + FileWriter fw = new FileWriter(new File(dir, genClassName + ".java")); + fw.write("package " + genPackageName + ";" + + "public class " + genClassName + "{ }"); + fw.close(); + } + catch (java.io.IOException ioe) { + throw new ControlAssemblyException("Error writing " + + genPackageName.replace(".", File.separator) + + File.separator + genClassName, ioe); + } + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/assembly/AssemblyTestControl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/assembly/AssemblyTestControl.java new file mode 100644 index 0000000..42f23cc --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/assembly/AssemblyTestControl.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.assembly; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +@ControlInterface( + defaultBinding = "org.apache.beehive.controls.test.controls.assembly.AssemblyTestControlImpl" +) +public interface AssemblyTestControl { +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/assembly/AssemblyTestControl2.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/assembly/AssemblyTestControl2.java new file mode 100644 index 0000000..17add3f --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/assembly/AssemblyTestControl2.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.assembly; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +@ControlInterface( + defaultBinding = "org.apache.beehive.controls.test.controls.assembly.AssemblyTestControl2Impl" +) +public interface AssemblyTestControl2 { +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/assembly/AssemblyTestControl2Impl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/assembly/AssemblyTestControl2Impl.java new file mode 100644 index 0000000..3d017d9 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/assembly/AssemblyTestControl2Impl.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.assembly; + +import org.apache.beehive.controls.api.bean.ControlImplementation; + +@ControlImplementation( + assembler = AssemblyTestAssembler2.class +) +public class AssemblyTestControl2Impl implements AssemblyTestControl2, java.io.Serializable { +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/assembly/AssemblyTestControlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/assembly/AssemblyTestControlImpl.java new file mode 100644 index 0000000..46661f9 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/assembly/AssemblyTestControlImpl.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.assembly; + +import org.apache.beehive.controls.api.bean.ControlImplementation; + +@ControlImplementation( + assembler = AssemblyTestAssembler.class, isTransient = true +) +public class AssemblyTestControlImpl implements AssemblyTestControl { +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontext/BeanContextPeer.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontext/BeanContextPeer.java new file mode 100644 index 0000000..4bd1964 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontext/BeanContextPeer.java @@ -0,0 +1,163 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.beancontext; + +import java.beans.beancontext.BeanContextChild; +import java.beans.beancontext.BeanContext; +import java.beans.beancontext.BeanContextMembershipListener; +import java.beans.PropertyVetoException; +import java.beans.PropertyChangeListener; +import java.beans.VetoableChangeListener; +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.net.URL; +import java.util.Iterator; +import java.util.Collection; + +/** + */ +public class BeanContextPeer implements BeanContext, Serializable { + + private String _message; + + public String getMessage() { return _message; } + public void setMessage(String message) { _message = message; } + + public Object instantiateChild(String beanName) throws IOException, ClassNotFoundException { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public InputStream getResourceAsStream(String name, BeanContextChild bcc) throws IllegalArgumentException { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public URL getResource(String name, BeanContextChild bcc) throws IllegalArgumentException { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public void addBeanContextMembershipListener(BeanContextMembershipListener bcml) { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void removeBeanContextMembershipListener(BeanContextMembershipListener bcml) { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void setBeanContext(BeanContext bc) throws PropertyVetoException { + //To change body of implemented methods use File | Settings | File Templates. + } + + public BeanContext getBeanContext() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public void addPropertyChangeListener(String name, PropertyChangeListener pcl) { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void removePropertyChangeListener(String name, PropertyChangeListener pcl) { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void addVetoableChangeListener(String name, VetoableChangeListener vcl) { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void removeVetoableChangeListener(String name, VetoableChangeListener vcl) { + //To change body of implemented methods use File | Settings | File Templates. + } + + public int size() { + return 0; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean isEmpty() { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean contains(Object o) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public Iterator iterator() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public Object[] toArray() { + return new Object[0]; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean add(Object o) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean remove(Object o) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean addAll(Collection c) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public void clear() { + //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean retainAll(Collection c) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean removeAll(Collection c) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean containsAll(Collection c) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public Object[] toArray(Object[] a) { + return new Object[0]; //To change body of implemented methods use File | Settings | File Templates. + } + + public void setDesignTime(boolean designTime) { + //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean isDesignTime() { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean needsGui() { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public void dontUseGui() { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void okToUseGui() { + //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean avoidingGui() { + return false; //To change body of implemented methods use File | Settings | File Templates. + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontext/BeanContextProxyImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontext/BeanContextProxyImpl.java new file mode 100755 index 0000000..97746c2 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontext/BeanContextProxyImpl.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.beancontext; + +import java.beans.beancontext.BeanContextProxy; +import java.beans.beancontext.BeanContextChild; + +/** + */ +public class BeanContextProxyImpl implements BeanContextProxy { + + private BeanContextChild _bcc; + + public BeanContextProxyImpl(BeanContextChild bcc) { + _bcc = bcc; + } + + public BeanContextChild getBeanContextProxy() + { + return _bcc; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontext/MembershipListener.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontext/MembershipListener.java new file mode 100755 index 0000000..18e7069 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontext/MembershipListener.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.beancontext; + +import java.beans.PropertyChangeListener; +import java.beans.VetoableChangeListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyVetoException; +import java.beans.beancontext.BeanContextMembershipListener; +import java.beans.beancontext.BeanContextMembershipEvent; +import java.util.LinkedList; +import java.io.Serializable; + +/** + * Created by IntelliJ IDEA. + * User: cschoett + * Date: Apr 13, 2006 + * Time: 9:25:47 AM + * To change this template use File | Settings | File Templates. + */ +public class MembershipListener implements BeanContextMembershipListener, Serializable { + + private LinkedList _recordedEvents; + + public MembershipListener() { + _recordedEvents = new LinkedList(); + } + + + public BeanContextMembershipEvent[] getEvents() { + BeanContextMembershipEvent[] result = new BeanContextMembershipEvent[_recordedEvents.size()]; + return _recordedEvents.toArray(result); + } + + public void reset() { + _recordedEvents.clear(); + } + + /** + * Called when a child or list of children is added to a + * BeanContext that this listener is registered with. + * + * @param bcme The BeanContextMembershipEvent + * describing the change that occurred. + */ + public void childrenAdded(BeanContextMembershipEvent bcme) + { + _recordedEvents.add(bcme); + } + + /** + * Called when a child or list of children is removed + * from a BeanContext that this listener + * is registered with. + * + * @param bcme The BeanContextMembershipEvent + * describing the change that occurred. + */ + public void childrenRemoved(BeanContextMembershipEvent bcme) + { + _recordedEvents.add(bcme); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontext/Resource.txt b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontext/Resource.txt new file mode 100644 index 0000000..cf609cc --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontext/Resource.txt @@ -0,0 +1,2 @@ +This is a text resource file used for junit testing of the ControlBeanContextSupport class. +xxx \ No newline at end of file diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontext/VisibilityImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontext/VisibilityImpl.java new file mode 100644 index 0000000..c685c5e --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontext/VisibilityImpl.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.beancontext; + +import java.beans.Visibility; + +/** + */ +public class VisibilityImpl implements Visibility { + + private boolean _canUseGui = false; + private boolean _needsGui = false; + + public boolean needsGui() { + return _needsGui; + } + + public void dontUseGui() { + _canUseGui = false; + } + + public void okToUseGui() { + _canUseGui = true; + } + + public boolean avoidingGui() { + return _needsGui && !_canUseGui; + } + + public boolean getCanUseGui() { + return _canUseGui; + } + + public void setNeedsGui(boolean needsGui) { + _needsGui = needsGui; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextchild/AlwaysVetoListener.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextchild/AlwaysVetoListener.java new file mode 100755 index 0000000..c7ba9e3 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextchild/AlwaysVetoListener.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.beancontextchild; + +import java.beans.VetoableChangeListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyVetoException; + +/** + * Created by IntelliJ IDEA. + * User: cschoett + * Date: Apr 13, 2006 + * Time: 9:25:47 AM + * To change this template use File | Settings | File Templates. + */ +public class AlwaysVetoListener implements VetoableChangeListener { + + public AlwaysVetoListener() { super(); } + + /** + * This method gets called when a constrained property is changed. + * + * @param evt a PropertyChangeEvent object describing the + * event source and the property that has changed. + * @throws java.beans.PropertyVetoException + * if the recipient wishes the property + * change to be rolled back. + */ + public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException { + throw new PropertyVetoException("VETO'd by: " + this, evt); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextchild/BeanChildPeer.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextchild/BeanChildPeer.java new file mode 100755 index 0000000..2947617 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextchild/BeanChildPeer.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.beancontextchild; + +import java.beans.beancontext.BeanContextChild; +import java.beans.beancontext.BeanContext; +import java.beans.PropertyVetoException; +import java.beans.PropertyChangeListener; +import java.beans.VetoableChangeListener; +import java.io.Serializable; + +/** + * Created by IntelliJ IDEA. + * User: cschoett + * Date: Apr 13, 2006 + * Time: 9:20:54 AM + * To change this template use File | Settings | File Templates. + */ +public class BeanChildPeer implements BeanContextChild, Serializable { + + private String _message; + + public String getMessage() { return _message; } + public void setMessage(String message) { _message = message; } + + public void setBeanContext(BeanContext bc) throws PropertyVetoException { + //To change body of implemented methods use File | Settings | File Templates. + } + + public BeanContext getBeanContext() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public void addPropertyChangeListener(String name, PropertyChangeListener pcl) { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void removePropertyChangeListener(String name, PropertyChangeListener pcl) { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void addVetoableChangeListener(String name, VetoableChangeListener vcl) { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void removeVetoableChangeListener(String name, VetoableChangeListener vcl) { + //To change body of implemented methods use File | Settings | File Templates. + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextchild/ChangeListener.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextchild/ChangeListener.java new file mode 100755 index 0000000..2be180a --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextchild/ChangeListener.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.beancontextchild; + +import java.beans.PropertyChangeListener; +import java.beans.VetoableChangeListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyVetoException; +import java.util.LinkedList; +import java.io.Serializable; + +/** + * Created by IntelliJ IDEA. + * User: cschoett + * Date: Apr 13, 2006 + * Time: 9:25:47 AM + * To change this template use File | Settings | File Templates. + */ +public class ChangeListener implements PropertyChangeListener, VetoableChangeListener, Serializable { + + private LinkedList _recordedEvents; + + public ChangeListener() { + _recordedEvents = new LinkedList(); + } + + /** + * This method gets called when a bound property is changed. + * + * @param evt A PropertyChangeEvent object describing the event source + * and the property that has changed. + */ + + public void propertyChange(PropertyChangeEvent evt) { + _recordedEvents.add(evt); + } + + /** + * This method gets called when a constrained property is changed. + * + * @param evt a PropertyChangeEvent object describing the + * event source and the property that has changed. + * @throws java.beans.PropertyVetoException + * if the recipient wishes the property + * change to be rolled back. + */ + public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException { + _recordedEvents.add(evt); + } + + public PropertyChangeEvent[] getEvents() { + PropertyChangeEvent[] result = new PropertyChangeEvent[_recordedEvents.size()]; + return _recordedEvents.toArray(result); + } + + public void reset() { + _recordedEvents.clear(); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextchild/DummyBeanContext.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextchild/DummyBeanContext.java new file mode 100755 index 0000000..74fd57f --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextchild/DummyBeanContext.java @@ -0,0 +1,162 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.beancontextchild; + +import java.beans.beancontext.BeanContext; +import java.beans.beancontext.BeanContextChild; +import java.beans.beancontext.BeanContextMembershipListener; +import java.beans.PropertyVetoException; +import java.beans.PropertyChangeListener; +import java.beans.VetoableChangeListener; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Iterator; +import java.util.Collection; + +/** + * Created by IntelliJ IDEA. + * User: cschoett + * Date: Apr 13, 2006 + * Time: 10:15:47 AM + * To change this template use File | Settings | File Templates. + */ +public class DummyBeanContext implements BeanContext { + + public Object instantiateChild(String beanName) throws IOException, ClassNotFoundException { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public InputStream getResourceAsStream(String name, BeanContextChild bcc) throws IllegalArgumentException { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public URL getResource(String name, BeanContextChild bcc) throws IllegalArgumentException { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public void addBeanContextMembershipListener(BeanContextMembershipListener bcml) { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void removeBeanContextMembershipListener(BeanContextMembershipListener bcml) { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void setBeanContext(BeanContext bc) throws PropertyVetoException { + //To change body of implemented methods use File | Settings | File Templates. + } + + public BeanContext getBeanContext() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public void addPropertyChangeListener(String name, PropertyChangeListener pcl) { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void removePropertyChangeListener(String name, PropertyChangeListener pcl) { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void addVetoableChangeListener(String name, VetoableChangeListener vcl) { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void removeVetoableChangeListener(String name, VetoableChangeListener vcl) { + //To change body of implemented methods use File | Settings | File Templates. + } + + public int size() { + return 0; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean isEmpty() { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean contains(Object o) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public Iterator iterator() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public Object[] toArray() { + return new Object[0]; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean add(Object o) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean remove(Object o) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean addAll(Collection c) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public void clear() { + //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean retainAll(Collection c) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean removeAll(Collection c) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean containsAll(Collection c) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public Object[] toArray(Object[] a) { + return new Object[0]; //To change body of implemented methods use File | Settings | File Templates. + } + + public void setDesignTime(boolean designTime) { + //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean isDesignTime() { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean needsGui() { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public void dontUseGui() { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void okToUseGui() { + //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean avoidingGui() { + return false; //To change body of implemented methods use File | Settings | File Templates. + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/BCChild.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/BCChild.java new file mode 100644 index 0000000..55b7c97 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/BCChild.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.beancontextservices; + +import java.beans.beancontext.BeanContextServiceAvailableEvent; +import java.beans.beancontext.BeanContextServiceRevokedEvent; +import java.beans.beancontext.BeanContextServices; +import java.util.TooManyListenersException; + +/** + * Extension of CBCCS, which listens for a service available event and + * gets a reference to that service. Must be regestered manually as + * ServicesSupport listener. + */ +public class BCChild extends org.apache.beehive.controls.runtime.webcontext.ControlBeanContextChildSupport { + + private transient int _refCount = 0; + private transient Object _service = null; + + public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) { + if (TestService.class.equals(bcsae.getServiceClass())) { + try { + _service = ((BeanContextServices)getBeanContext()).getService(this, this, TestService.class, null, this); + _refCount++; + } + catch (TooManyListenersException tmle) { + throw new RuntimeException(tmle); + } + } + } + + public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) { + if (bcsre.isServiceClass(TestService.class)) { + if (!bcsre.isCurrentServiceInvalidNow()) { + ((BeanContextServices)getBeanContext()).releaseService(this, this, _service); + } + _refCount--; + } + } + + public int getRefCount() { + return _refCount; + } + + /** + * Based on the 'Extensible Runtime Containment and Server Protocol for JavaBeans V 1.0' (glasgow spec), + * "When BeanContextChild instances are removed from a particular BeanContextServices instance, they + * shall discard all references to any services they obtained from that BeanContextServices by + * appropriate invocations of releaseService()" + */ + protected void releaseBeanContextResources() { + if (_service != null) { + while (_refCount > 0) { + ((BeanContextServices)getBeanContext()).releaseService(this, this, _service); + _refCount--; + } + } + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/BCChildNoServiceRelease.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/BCChildNoServiceRelease.java new file mode 100644 index 0000000..febc32a --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/BCChildNoServiceRelease.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.beancontextservices; + +import java.beans.beancontext.BeanContextServiceAvailableEvent; +import java.beans.beancontext.BeanContextServiceRevokedEvent; +import java.beans.beancontext.BeanContextServices; +import java.util.TooManyListenersException; + +/** + * Extension of CBCCS, which listens for a service available event and + * gets a reference to that service. Must be regestered manually as + * ServicesSupport listener. + */ +public class BCChildNoServiceRelease extends org.apache.beehive.controls.runtime.webcontext.ControlBeanContextChildSupport { + + private int _refCount = 0; + private Object _service = null; + + public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) { + if (TestService.class.equals(bcsae.getServiceClass())) { + try { + _service = ((BeanContextServices)getBeanContext()).getService(this, this, TestService.class, null, this); + _refCount++; + } + catch (TooManyListenersException tmle) { + throw new RuntimeException(tmle); + } + } + } + + public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) { + if (bcsre.isServiceClass(TestService.class) && bcsre.isCurrentServiceInvalidNow()) { +// spec: don't to this if invalidate now +// bcsre.getSourceAsBeanContextServices().releaseService(this, this, _service); + _refCount--; + } + } + + public int getRefCount() { + return _refCount; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/BCSCheckServices.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/BCSCheckServices.java new file mode 100644 index 0000000..f3a289e --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/BCSCheckServices.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.beancontextservices; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +/** + * A simple control which verifies that the service classes from the ControlBeanContext + * can be retrieved without causing a stack overflow. + */ +@ControlInterface +public interface BCSCheckServices { + + public boolean checkServices(); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/BCSCheckServicesImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/BCSCheckServicesImpl.java new file mode 100644 index 0000000..bfa9d18 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/BCSCheckServicesImpl.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.beancontextservices; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; + +import java.util.Iterator; + +/** + * A simple control which verifies that the service classes from the ControlBeanContext + * can be retrieved without causing a stack overflow. + */ +@ControlImplementation +public class BCSCheckServicesImpl implements BCSCheckServices, java.io.Serializable { + + @Context + private ControlBeanContext _cbc; + + public boolean checkServices() { + + Iterator i = _cbc.getCurrentServiceClasses(); + return true; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/NonSerializableServiceListener.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/NonSerializableServiceListener.java new file mode 100644 index 0000000..209750a --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/NonSerializableServiceListener.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.beancontextservices; + +import java.beans.beancontext.BeanContextServicesListener; +import java.beans.beancontext.BeanContextServiceAvailableEvent; +import java.beans.beancontext.BeanContextServiceRevokedEvent; +import java.util.EventObject; +import java.util.LinkedList; + +/** + */ +public class NonSerializableServiceListener implements BeanContextServicesListener { + + private LinkedList _recordedEvents; + + public NonSerializableServiceListener() { + _recordedEvents = new LinkedList(); + } + + public EventObject[] getEvents() { + EventObject[] result = new EventObject[_recordedEvents.size()]; + return _recordedEvents.toArray(result); + } + + public void reset() { + _recordedEvents.clear(); + } + + public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) { + _recordedEvents.add(bcsae); + } + + public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) { + _recordedEvents.add(bcsre); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/ServiceListener.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/ServiceListener.java new file mode 100644 index 0000000..a27889c --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/ServiceListener.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.beancontextservices; + +import java.beans.beancontext.BeanContextServiceAvailableEvent; +import java.beans.beancontext.BeanContextServiceRevokedEvent; +import java.beans.beancontext.BeanContextServicesListener; +import java.io.Serializable; +import java.util.EventObject; +import java.util.LinkedList; + +/** + */ +public class ServiceListener implements BeanContextServicesListener, Serializable { + + private LinkedList _recordedEvents; + + public ServiceListener() { + _recordedEvents = new LinkedList(); + } + + public EventObject[] getEvents() { + EventObject[] result = new EventObject[_recordedEvents.size()]; + return _recordedEvents.toArray(result); + } + + public void reset() { + _recordedEvents.clear(); + } + + public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) { + _recordedEvents.add(bcsae); + } + + public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) { + _recordedEvents.add(bcsre); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/ServicesBeanPeer.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/ServicesBeanPeer.java new file mode 100644 index 0000000..9428f0a --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/ServicesBeanPeer.java @@ -0,0 +1,218 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.beancontextservices; + +import java.beans.beancontext.BeanContextChild; +import java.beans.beancontext.BeanContext; +import java.beans.beancontext.BeanContextServices; +import java.beans.beancontext.BeanContextServiceProvider; +import java.beans.beancontext.BeanContextServiceRevokedListener; +import java.beans.beancontext.BeanContextServicesListener; +import java.beans.beancontext.BeanContextMembershipListener; +import java.beans.beancontext.BeanContextServiceAvailableEvent; +import java.beans.beancontext.BeanContextServiceRevokedEvent; +import java.beans.PropertyVetoException; +import java.beans.PropertyChangeListener; +import java.beans.VetoableChangeListener; +import java.util.TooManyListenersException; +import java.util.Iterator; +import java.util.Collection; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +/** + * Created by IntelliJ IDEA. + * User: cschoett + * Date: Apr 13, 2006 + * Time: 9:20:54 AM + * To change this template use File | Settings | File Templates. + */ +public class ServicesBeanPeer implements BeanContextServices { + + private String _message; + + public String getMessage() { return _message; } + public void setMessage(String message) { _message = message; } + + public boolean addService(Class serviceClass, BeanContextServiceProvider serviceProvider) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public void revokeService(Class serviceClass, BeanContextServiceProvider serviceProvider, boolean revokeCurrentServicesNow) { + //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean hasService(Class serviceClass) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public Object getService(BeanContextChild child, Object requestor, Class serviceClass, Object serviceSelector, BeanContextServiceRevokedListener bcsrl) throws TooManyListenersException { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public void releaseService(BeanContextChild child, Object requestor, Object service) { + //To change body of implemented methods use File | Settings | File Templates. + } + + public Iterator getCurrentServiceClasses() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public Iterator getCurrentServiceSelectors(Class serviceClass) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public void addBeanContextServicesListener(BeanContextServicesListener bcsl) { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void removeBeanContextServicesListener(BeanContextServicesListener bcsl) { + //To change body of implemented methods use File | Settings | File Templates. + } + + public Object instantiateChild(String beanName) throws IOException, ClassNotFoundException { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public InputStream getResourceAsStream(String name, BeanContextChild bcc) throws IllegalArgumentException { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public URL getResource(String name, BeanContextChild bcc) throws IllegalArgumentException { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public void addBeanContextMembershipListener(BeanContextMembershipListener bcml) { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void removeBeanContextMembershipListener(BeanContextMembershipListener bcml) { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void setBeanContext(BeanContext bc) throws PropertyVetoException { + //To change body of implemented methods use File | Settings | File Templates. + } + + public BeanContext getBeanContext() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public void addPropertyChangeListener(String name, PropertyChangeListener pcl) { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void removePropertyChangeListener(String name, PropertyChangeListener pcl) { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void addVetoableChangeListener(String name, VetoableChangeListener vcl) { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void removeVetoableChangeListener(String name, VetoableChangeListener vcl) { + //To change body of implemented methods use File | Settings | File Templates. + } + + public int size() { + return 0; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean isEmpty() { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean contains(Object o) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public Iterator iterator() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public Object[] toArray() { + return new Object[0]; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean add(Object o) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean remove(Object o) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean addAll(Collection c) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public void clear() { + //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean retainAll(Collection c) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean removeAll(Collection c) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean containsAll(Collection c) { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public Object[] toArray(Object[] a) { + return new Object[0]; //To change body of implemented methods use File | Settings | File Templates. + } + + public void setDesignTime(boolean designTime) { + //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean isDesignTime() { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean needsGui() { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public void dontUseGui() { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void okToUseGui() { + //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean avoidingGui() { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) { + //To change body of implemented methods use File | Settings | File Templates. + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/TestBCServiceProviderImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/TestBCServiceProviderImpl.java new file mode 100644 index 0000000..17d9046 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/TestBCServiceProviderImpl.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.beancontextservices; + +import java.beans.beancontext.BeanContextServiceProvider; +import java.beans.beancontext.BeanContextServices; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.ArrayList; +import java.io.Serializable; + +/** + * Service provider for TestService, should be registered with TestService as the serviceClass. + */ +public class TestBCServiceProviderImpl implements BeanContextServiceProvider, Serializable { + + private LinkedList _actions; + private int _refCount; + private List _serviceSelectors; + + public TestBCServiceProviderImpl() { + _actions = new LinkedList(); + _refCount = 0; + _serviceSelectors = new ArrayList(); + _serviceSelectors.add("ONE"); + _serviceSelectors.add("TWO"); + _serviceSelectors.add("THREE"); + } + + public Object getService(BeanContextServices bcs, Object requestor, Class serviceClass, Object serviceSelector) { + _actions.add("GET"); + _refCount++; + return new TestServiceImpl(); + } + + public void releaseService(BeanContextServices bcs, Object requestor, Object service) { + _actions.add("RELEASE"); + _refCount--; + assert _refCount > 0; + } + + public Iterator getCurrentServiceSelectors(BeanContextServices bcs, Class serviceClass) { + return _serviceSelectors.iterator(); + } + + public String[] getRecordedActions() { + String[] s = new String[1]; + return _actions.toArray(s); + } + + public int getRefCount() { + return _refCount; + } + + public void resetState() { + _actions = new LinkedList(); + _refCount = 0; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/TestNonSerializableBCServiceProviderImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/TestNonSerializableBCServiceProviderImpl.java new file mode 100644 index 0000000..2439519 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/TestNonSerializableBCServiceProviderImpl.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.beancontextservices; + +import java.beans.beancontext.BeanContextServiceProvider; +import java.beans.beancontext.BeanContextServices; +import java.util.LinkedList; +import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; + +/** + * Service provider for TestService, should be registered with TestService as the serviceClass. + */ +public class TestNonSerializableBCServiceProviderImpl implements BeanContextServiceProvider { + + private LinkedList _actions; + private int _refCount; + private List _serviceSelectors; + + public TestNonSerializableBCServiceProviderImpl() { + _actions = new LinkedList(); + _refCount = 0; + _serviceSelectors = new ArrayList(); + _serviceSelectors.add("ONE"); + _serviceSelectors.add("TWO"); + _serviceSelectors.add("THREE"); + } + + public Object getService(BeanContextServices bcs, Object requestor, Class serviceClass, Object serviceSelector) { + _actions.add("GET"); + _refCount++; + return new TestServiceImpl(); + } + + public void releaseService(BeanContextServices bcs, Object requestor, Object service) { + _actions.add("RELEASE"); + _refCount--; + assert _refCount > 0; + } + + public Iterator getCurrentServiceSelectors(BeanContextServices bcs, Class serviceClass) { + return _serviceSelectors.iterator(); + } + + public String[] getRecordedActions() { + String[] s = new String[1]; + return _actions.toArray(s); + } + + public int getRefCount() { + return _refCount; + } + + public void resetState() { + _actions = new LinkedList(); + _refCount = 0; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/TestNonSerializableService.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/TestNonSerializableService.java new file mode 100644 index 0000000..f1daa2f --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/TestNonSerializableService.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.beancontextservices; + +/** + */ +public class TestNonSerializableService { + + public String invokeService(int param) { + return "TestNonSerializableService: invoked with paramvalue = " + param; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/TestService.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/TestService.java new file mode 100644 index 0000000..20200ba --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/TestService.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.beancontextservices; + +/** + */ +public interface TestService { + + public String invokeService(int param); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/TestServiceImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/TestServiceImpl.java new file mode 100644 index 0000000..d37f239 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beancontextservices/TestServiceImpl.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.beancontextservices; + +/** + */ +public class TestServiceImpl implements TestService { + + public String invokeService(int param) { + return "TestServiceImpl invoked with paramvalue = " + param; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beaninfo/InfoTest.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beaninfo/InfoTest.java new file mode 100644 index 0000000..8dc4b2f --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beaninfo/InfoTest.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.beaninfo; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.events.EventSet; +import org.apache.beehive.controls.api.packaging.FeatureAttribute; +import org.apache.beehive.controls.api.packaging.FeatureInfo; +import org.apache.beehive.controls.api.packaging.ManifestAttribute; +import org.apache.beehive.controls.api.packaging.PropertyInfo; +import org.apache.beehive.controls.api.properties.PropertySet; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * A simple test class that tests using JSR-175 annotations to inject BeanInfo attributes + * for a Control type. + */ +@ControlInterface +/* THE B51 VANILLA APT PROCESSOR BARFS ON THIS RIGHT NOW +@ManifestAttributes (value={ + @ManifestAttribute(name="Attribute1", value="Value1"), + @ManifestAttribute(name="Attribute2", value="Value2"), + @ManifestAttribute(name="Attribute3", value="Value3") +}) */ +@ManifestAttribute(name = "Attribute1", value = "Value1") +@FeatureInfo( + name = "%org.apache.beehive.controls.test.controls.beaninfo.InfoTestBundle.name%", + displayName = "%org.apache.beehive.controls.test.controls.beaninfo.InfoTestBundle.displayName%", + attributes = + { + @FeatureAttribute(name = "fa1", value = "fv1"), + @FeatureAttribute(name = "fa2", value = "fv2") + }) +public interface InfoTest { + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.TYPE, ElementType.FIELD}) + public @interface TestProps { + @PropertyInfo(bound = true, constrained = false) + @FeatureInfo( + name = "%org.apache.beehive.controls.test.controls.beaninfo.InfoTestBundle.prop1.name%", + displayName = "InfoTest prop1") + public int prop1() default 0; + + public boolean prop2() default false; + } + + @EventSet(unicast = true) + public interface TestEvents { + @FeatureInfo(name = "InfoTest eventMethod1", displayName = "InfoTest eventMethod1", + isHidden = true, isExpert = true) + public void eventMethod1(); + + public int eventMethod2(String stringArg); + } + + @FeatureInfo( + name = "infoTestMethod name", + displayName = "%org.apache.beehive.controls.test.controls.beaninfo.InfoTestBundle.infoTestMethod.displayName%", + isHidden = true, + isExpert = true, + attributes = + { + @FeatureAttribute(name = "methodFA1", value = "methodFV2"), + @FeatureAttribute(name = "methodFA2", value = "methodFV2") + }) + public void infoTestMethod(int anIntArg, Class aClassArg); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beaninfo/InfoTestBundle.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beaninfo/InfoTestBundle.java new file mode 100644 index 0000000..bdfbb65 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beaninfo/InfoTestBundle.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.beaninfo; + +import java.util.ListResourceBundle; + +/** + * A resource bundle containing feature info strings. This is used to test the '%%' + * substitution syntax for bean info annotations. + */ + +public class InfoTestBundle extends ListResourceBundle { + static final Object[][] contents = + { + {"name", "InfoTest name"}, + {"displayName", "InfoTest display name"}, + {"prop1.name", "InfoTest prop1"}, + {"infoTestMethod.displayName", "infoTestMethod display name"} + }; + + public Object[][] getContents() { + return contents; + } + +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beaninfo/InfoTestImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beaninfo/InfoTestImpl.java new file mode 100644 index 0000000..3816e37 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/beaninfo/InfoTestImpl.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.beaninfo; + +import org.apache.beehive.controls.api.bean.ControlImplementation; + +/** + * A simple test impl that tests using JSR-175 annotations to inject BeanInfo attributes + * for a Control type. + */ +@ControlImplementation(isTransient = true) +public class InfoTestImpl implements InfoTest { + public void infoTestMethod(int anIntArg, Class aClassArg) { + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/checker/HelloCheckedExtend.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/checker/HelloCheckedExtend.java new file mode 100644 index 0000000..9652fcd --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/checker/HelloCheckedExtend.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.checker; + +import org.apache.beehive.controls.api.bean.ControlExtension; + +/** + * This is a test extension that declares operations of various types + *

    + */ +@ControlExtension +public interface HelloCheckedExtend extends HelloChecked +{ + public void voidExtOperation(); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/checker/HelloCheckedImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/checker/HelloCheckedImpl.java new file mode 100644 index 0000000..3b004be --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/checker/HelloCheckedImpl.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.checker; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.Extensible; + +import java.lang.reflect.Method; + +@ControlImplementation +public class HelloCheckedImpl implements HelloChecked, Extensible, java.io.Serializable +{ + public String _lastVisitor = ""; + int _visitorCount = 0; + + public String hello(String name) + { + _lastVisitor = name; + _visitorCount++; + return "Hello, " + name; + } + + public String lastVisitor() + { + return _lastVisitor; + } + + public int visitorCount() + { + return _visitorCount; + } + + /** + * Implements the Extensible.invoke interface when a JCX-declared method is called + */ + public Object invoke(Method method, Object [] args) + { + // + // To Be Implemented + // + return null; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/composition/Composer.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/composition/Composer.java new file mode 100644 index 0000000..8325098 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/composition/Composer.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.composition; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +import java.lang.annotation.Annotation; + +/** + * A simple control that tests control composition + */ +@ControlInterface +public interface Composer +{ + // + // Returns a propertySet value for a simple nested control + // + public Annotation getControlPropertySet(Class propertySet); + + // + // Returns a propertySet value for an extension nested control + // + public Annotation getExtensionControlPropertySet(Class propertySet); + + // + // Invokes nested controls + // + public void invokeNestedControls(); + + // + // returns recorded events + // + public String[] getEventLog(); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/composition/ComposerImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/composition/ComposerImpl.java new file mode 100644 index 0000000..8c94c06 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/composition/ComposerImpl.java @@ -0,0 +1,167 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.composition; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.api.events.EventHandler; +import org.apache.beehive.controls.test.controls.property.Props; +import org.apache.beehive.controls.test.controls.property.PropsExtension; + +import java.lang.annotation.Annotation; +import java.util.LinkedList; + +@ControlImplementation +public class ComposerImpl implements Composer, java.io.Serializable { + static final long serialVersionUID = 1L; + + @Control + @Props.SimpleProps(simpleString="A field annotation value") + Props propControl; + + @Control + @PropsExtension.SimpleProps(simpleString="A different field annotation value") + private PropsExtension propExtControl; + + @Nested.Index(1) + private @Control Nested nested1; + + @Control + @Nested.Index(2) + /* package */ Nested nested2; + + @Control + @Nested.Index(3) + protected Nested nested3; + + @Control + @Nested.Index(4) + public Nested nested4; + + private LinkedList _events = new LinkedList(); + + /** + * Provides a simple test API to externally query the PropertySet values on a + * nested control. + */ + public Annotation getControlPropertySet(Class propertySet) { + return propControl.getControlPropertySet(propertySet); + } + + public Annotation getExtensionControlPropertySet(Class propertySet) { + return propExtControl.getControlPropertySet(propertySet); + } + + public void invokeNestedControls() { + nested1.fireEvent( "Return", "returnVoid" ); + nested1.fireEvent( "Return", "returnInt" ); + nested1.fireEvent( "Return", "returnString" ); + } + + // + // Define various event handlers for the nested controls + // + @EventHandler(field="nested1", eventSet=Nested.Return.class, eventName="returnVoid") + public void nested1ReturnVoid() { + _events.add( "nested1ReturnVoid" ); + } + + @EventHandler(field="nested1", eventSet=Nested.Return.class, eventName="returnString") + public String nested1ReturnString() { + _events.add( "nested1ReturnString" ); + return "Hello"; + } + + @EventHandler(field="nested1", eventSet=Nested.Return.class, eventName="returnInt") + public int nested1ReturnInt() { + _events.add( "nested1ReturnInt" ); + return 21; + } + + @EventHandler(field="nested2", eventSet=Nested.Args.class, eventName="argsInt") + public int nested2ArgsInt(int value) { + _events.add( "nested2ArgsInt" ); + return value; + } + + @EventHandler(field="nested2", eventSet=Nested.Args.class, eventName="argsString") + public String nested2ArgsString(String value) { + _events.add( "nested2ArgsString" ); + return value; + } + + @EventHandler(field="nested2", eventSet=Nested.Args.class, eventName="argsMultiple") + public Object [] nested2ArgsMultiple(int val1, String val2) { + _events.add( "nested2ArgsMultiple" ); + return new Object[] {val1,val2}; + } + + @EventHandler(field="nested3", eventSet=Nested.Except.class, eventName="exceptIO") + public void nested3ExceptIO() + throws java.io.IOException { + _events.add( "nested3ExceptIO" ); + throw new java.io.IOException("Ouch"); + } + + @EventHandler(field="nested3", eventSet=Nested.Except.class, eventName="exceptRuntime") + public void nested3ExceptRuntime() + throws RuntimeException { + _events.add( "nested3ExceptRuntime" ); + throw new RuntimeException("Crash"); + } + + @EventHandler(field="nested3", eventSet=Nested.Except.class, eventName="exceptLocal") + public void nested3ExceptLocal() + throws Nested.LocalException { + _events.add( "nested3ExceptLocal" ); + throw new Nested.LocalException("Bang"); + } + + @EventHandler(field="nested3", eventSet=Nested.Except.class, eventName="exceptMultiple") + public void nested3ExceptMultiple() + throws java.io.IOException, RuntimeException { + _events.add( "nested3ExceptMultiple" ); + throw new java.io.IOException("Play nice!"); + } + + @EventHandler(field="nested4", eventSet=Nested.Return.class, eventName="returnInt") + public int nested4ReturnInt() { + _events.add( "nested4ReturnInt" ); + return 99; + } + + @EventHandler(field="nested4", eventSet=Nested.Args.class, eventName="argsString") + public String nested4ArgsString(String value) { + _events.add( "nested4ArgsString" ); + return value; + } + + @EventHandler(field="nested4", eventSet=Nested.Except.class, eventName="exceptLocal") + public void nested4ExceptLocal() + throws Nested.LocalException { + _events.add( "nested4ExceptLocal" ); + throw new Nested.LocalException("Bang"); + } + + public String[] getEventLog() { + String[] ret = new String[1]; + return _events.toArray(ret); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/composition/InnerControl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/composition/InnerControl.java new file mode 100644 index 0000000..06ce937 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/composition/InnerControl.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.test.controls.composition; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.events.EventSet; +import org.apache.beehive.controls.api.properties.PropertySet; + +/** + * A control interface designed to test control composition + */ +@ControlInterface +public interface InnerControl +{ + static final String DEFAULT_NAME="Bob"; + static final String DEFAULT_JOB="cleaner"; + + @PropertySet + @Target( {ElementType.TYPE, ElementType.FIELD} ) + @Retention(RetentionPolicy.RUNTIME) + public @interface Identity { + public String name() default DEFAULT_NAME; + //does not have a default value assigned + public String job(); + public int rank() default 0; + } + + @EventSet(unicast=true) + public interface Activity { + void wakeup(); + int readMessage(String message); + String report(); + } + + @EventSet(unicast=true) + public interface Action { + public Object[] shopping (double credit); + public void doStuff(String value); + } + + public void fireAllEvents(); + public void fireEvent(String eventSet, String eventName); + + /*Gets property value from context*/ + public String getNameFromContext(); + + /*Gets property value from context*/ + public String getJobFromContext(); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/composition/InnerControlEventListener.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/composition/InnerControlEventListener.java new file mode 100644 index 0000000..665a6a8 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/composition/InnerControlEventListener.java @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.test.controls.composition; + +/** + * A listener class for event raised by InnerControl + */ +public class InnerControlEventListener + implements InnerControl.Activity, + InnerControl.Action, + java.io.Serializable { + + private boolean wakeupReceived=false; + private boolean readMessageReceived=false; + private boolean reportReceived=false; + private boolean shoppingReceived=false; + private boolean doStuffReceived=false; + + /* + * BUG!!?? although the event declares methods wakeup, readMessage and + * report using default accessor, + * implmentation must change the method accessor to public, + * or, a compile error! + * + * attempting to assign weaker access privileges; was public + * [apt] void wakeup(){wakeupReceived=true;} + * + */ + + public void wakeup(){ + wakeupReceived=true; + } + + public int readMessage(String message){ + readMessageReceived=true; + return 0; + } + + public String report(){ + reportReceived=true; + return "a report from event listener"; + } + + public Object[] shopping (double credit){ + shoppingReceived=true; + //return (Object){"clothes","shoes","food"}; + return null; + } + + public void doStuff(String value){ + doStuffReceived=true; + } + + public boolean getWakeupResult(){ + return wakeupReceived; + } + + public boolean getReadMessageResult(){ + return readMessageReceived; + } + + public boolean getReportResult(){ + return reportReceived; + } + + public boolean getShoppingResult(){ + return shoppingReceived; + } + + public boolean getDoStuffResult(){ + return doStuffReceived; + } + + /** + * Checks all the event records and returns '0' if all the events have been received. + */ + public String getFinalResult(){ + + String result=""; + + if (!wakeupReceived) + result="WakeUp not received."; + if (!readMessageReceived) + result=result+"readMessage not received."; + if (!reportReceived) + result=result+"report not received."; + if (!shoppingReceived) + result=result+"shopping not received."; + if (!doStuffReceived) + result=result+"dostuff not received."; + + if (result.length()==0) + result="0"; + + return result; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/composition/InnerControlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/composition/InnerControlImpl.java new file mode 100644 index 0000000..bc1fd8a --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/composition/InnerControlImpl.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.test.controls.composition; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.events.Client; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; + +/* + * A control impl to test control composition. + * This control shall be instantiated by another control. + */ +@ControlImplementation +public class InnerControlImpl + implements InnerControl, java.io.Serializable { + + @Context + ControlBeanContext context; + + @Client + Activity activity; + + @Client + Action action; + + /*Gets property value from context*/ + public String getNameFromContext(){ + Identity identity = context.getControlPropertySet(InnerControl.Identity.class); + return identity.name(); + } + + /*Gets property value from context*/ + public String getJobFromContext(){ + Identity identity = context.getControlPropertySet(InnerControl.Identity.class); + return identity.job(); + } + + public void fireEvent(String eventSet, String eventName){ + + if ((eventSet!=null)&&(eventName!=null)){ + + if (eventSet.equalsIgnoreCase("Activity")){ + if (eventName.equalsIgnoreCase("wakeup")) + activity.wakeup(); + else if(eventName.equalsIgnoreCase("readMessage")) + activity.readMessage("message from nested control"); + else if(eventName.equalsIgnoreCase("report")) + activity.report(); + } + else if (eventSet.equalsIgnoreCase("Action")){ + if (eventName.equalsIgnoreCase("shopping")) + action.shopping(999.99d); + else if(eventName.equalsIgnoreCase("doStuff")) + action.doStuff("stuff to do"); + } + } + + } + + public void fireAllEvents(){ + activity.wakeup(); + activity.readMessage("message from nested control"); + activity.report(); + action.shopping(999.99d); + action.doStuff("stuff to do"); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/composition/Nested.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/composition/Nested.java new file mode 100644 index 0000000..12cf48e --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/composition/Nested.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.composition; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.properties.PropertySet; +import org.apache.beehive.controls.api.events.EventSet; + +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@ControlInterface +public interface Nested { + + public void fireEvent(String eventSet, String eventName); + + @PropertySet + @Target( {ElementType.TYPE, ElementType.FIELD} ) + @Retention(RetentionPolicy.RUNTIME) + public @interface Index { + int value() default -1; + } + + @EventSet(unicast=true) + public interface Return { + void returnVoid(); + String returnString(); + int returnInt(); + } + + @EventSet(unicast=true) + public interface Args { + public int argsInt(int value); + public String argsString(String value); + public Object [] argsMultiple(int val1, String val2); + } + + @EventSet + public interface Except { + void exceptIO() throws java.io.IOException; + void exceptRuntime() throws RuntimeException; + void exceptLocal() throws LocalException; + void exceptMultiple() throws java.io.IOException, RuntimeException; + } + + public class LocalException + extends Exception + { + LocalException(String msg) { + super(msg); + } + + LocalException(String msg, Throwable t) { + super(msg, t); + } + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/composition/NestedAssembler.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/composition/NestedAssembler.java new file mode 100644 index 0000000..66c04d1 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/composition/NestedAssembler.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.composition; + +import org.apache.beehive.controls.api.assembly.ControlAssembler; +import org.apache.beehive.controls.api.assembly.ControlAssemblyContext; + +public class NestedAssembler implements ControlAssembler { + + public void assemble(ControlAssemblyContext cac) { + System.out.println( "NestedAssembler:" ); + System.out.println( " context type=" + cac.getClass().getName() ); + System.out.println( " module=" + cac.getModuleDir() ); + System.out.println( " control type=" + cac.getControlType() ); + System.out.println( " control default impl=" + cac.getDefaultImplClassName() ); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/composition/NestedImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/composition/NestedImpl.java new file mode 100644 index 0000000..725de02 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/composition/NestedImpl.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.composition; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.events.Client; + +@ControlImplementation(assembler = NestedAssembler.class) +public class NestedImpl implements Nested, java.io.Serializable { + + @Client + Return returnClient; + + @Client + Args argsClient; + + @Client + Except exceptClient; + + public void fireEvent(String set, String name) { + if (set.equals("Return")) { + if (name.equals("returnVoid")) + returnClient.returnVoid(); + + if (name.equals("returnInt")) + returnClient.returnInt(); + + if (name.equals("returnString")) + returnClient.returnString(); + + } else if (set.equals("Args")) { + if (name.equals("argsInt")) + argsClient.argsInt(1); + + if (name.equals("argsString")) + argsClient.argsString("foo"); + + if (name.equals("argsMultiple")) + argsClient.argsMultiple(2, "bar"); + + } else if (set.equals("Except")) { + try { + if (name.equals("exceptIO")) + exceptClient.exceptIO(); + + if (name.equals("exceptRuntime")) + exceptClient.exceptRuntime(); + + if (name.equals("exceptLocal")) + exceptClient.exceptLocal(); + + if (name.equals("exceptMultiple")) + exceptClient.exceptMultiple(); + } + catch (Exception e) { + e.printStackTrace(); + } + } + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/composition/OuterControl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/composition/OuterControl.java new file mode 100644 index 0000000..2762aee --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/composition/OuterControl.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.test.controls.composition; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.events.EventSet; + +/** + * A control interface to test control composition. + */ +@ControlInterface +public interface OuterControl { + + @EventSet(unicast=true) + public interface OuterEvents { + int report(String message); + } + + public void fireOuterEvents(String message); + + public InnerControlBean getDeclaredNestedControl(); + public InnerControlBean getDeclaredNestedControl2(); + public InnerControlBean instantiateNestedControlProgrammatically(); + public InnerControlBean instantiateNestedControlWithProperty(); + + /* + * Test outer control receiving event from nested control using + * EventHandler. + */ + public String testActivityWakeup(); + public String testActivityReadMessage(); + public String testActivityReport(); + public String testActionShopping(); + public String testActionDostuff(); + + /* + * Tests outer control receiving event from nested control using + * event listener. The nested control is instantiated programmatically + */ + public String testEventListener(); + + /* + * Tests outer control receiving event from nested control using + * event listener. The nested control is instantiated decalratively + */ + public String testEventListenerByDeclare(); + + /* + * Tests outer control receiving event from nested control using + * inner class listener. The nested control is instantiated programmatically + */ + public String testInnerClassListener(); + + /* + * Tests outer control receiving event from nested control using + * inner class listener. The nested control is instantiated decalratively + */ + public String testInnerClassListenerByDeclare(); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/composition/OuterControlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/composition/OuterControlImpl.java new file mode 100644 index 0000000..76d5f42 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/composition/OuterControlImpl.java @@ -0,0 +1,502 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.test.controls.composition; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.api.events.Client; +import org.apache.beehive.controls.api.events.EventHandler; +import org.apache.beehive.controls.api.properties.BeanPropertyMap; + +/** + * A control implementation to test control composition. Makes two instances of nested control be declaration. + */ +@ControlImplementation +public class OuterControlImpl + implements OuterControl, java.io.Serializable { + + static final long serialVersionUID = 1L; + static final String EVENT_RECEIVED = "Event Received"; + + private String innerControlEventHandlerWakeUp = ""; + private String innerControlEventHandlerReadMessage = ""; + private String innerControlEventHandlerReport = ""; + private String innerControlEventHandlerShopping = ""; + private String innerControlEventHandlerDoStuff = ""; + + private boolean innerClassWakeUp = false; + private boolean innerClassReadMessage = false; + private boolean innerClassReport = false; + private boolean innerClassShopping = false; + private boolean innerClassDoStuff = false; + + private boolean innerControlInnerClassWakeUp = false; + private boolean innerControlInnerClassReadMessage = false; + private boolean innerControlInnerClassReport = false; + private boolean innerControlInnerClassShopping = false; + private boolean innerControlInnerClassDoStuff = false; + + @Client + transient OuterEvents outerEvents; + + /*Instantiates a nested control without reconfiguring the property*/ + @Control + InnerControlBean innerControl; + + @Control + @InnerControl.Identity(job = "farmer") + InnerControlBean innerControl2; + + // + // Define various event handlers for the nested controls + // + @EventHandler(field = "innerControl", eventSet = InnerControl.Activity.class, eventName = "wakeup") + public void innerControlwakeup() { + innerControlEventHandlerWakeUp = EVENT_RECEIVED; + } + + @EventHandler(field = "innerControl", eventSet = InnerControl.Activity.class, eventName = "readMessage") + public int innerControlreadMessage(String message) { + innerControlEventHandlerReadMessage = EVENT_RECEIVED; + return 0; + } + + @EventHandler(field = "innerControl", eventSet = InnerControl.Activity.class, eventName = "report") + public String innerControlreport() { + innerControlEventHandlerReport = EVENT_RECEIVED; + return "a report"; + } + + @EventHandler(field = "innerControl", eventSet = InnerControl.Action.class, eventName = "shopping") + public Object [] innerControlshopping(double credit) { + innerControlEventHandlerShopping = EVENT_RECEIVED; + return null; + } + + @EventHandler(field = "innerControl", eventSet = InnerControl.Action.class, eventName = "doStuff") + public void innerControldoStuff(String vakue) { + innerControlEventHandlerDoStuff = EVENT_RECEIVED; + } + + @EventHandler(field = "innerControl2", eventSet = InnerControl.Activity.class, eventName = "wakeup") + public void innerControl2wakeup() { + } + + @EventHandler(field = "innerControl2", eventSet = InnerControl.Activity.class, eventName = "readMessage") + public int innerControl2readMessage(String message) { + return 0; + } + + @EventHandler(field = "innerControl2", eventSet = InnerControl.Activity.class, eventName = "report") + public String innerControl2report() { + return "a report"; + } + + @EventHandler(field = "innerControl2", eventSet = InnerControl.Action.class, eventName = "shopping") + public Object [] innerControl2shopping(double credit) { + return null; + } + + @EventHandler(field = "innerControl2", eventSet = InnerControl.Action.class, eventName = "doStuff") + public void innerControl2doStuff(String vakue) { + } + + public void fireOuterEvents(String message) { + outerEvents.report(message); + } + + public InnerControlBean getDeclaredNestedControl() { + return innerControl; + } + + public InnerControlBean getDeclaredNestedControl2() { + return innerControl2; + } + + public InnerControlBean instantiateNestedControlProgrammatically() { + try { + InnerControlBean inner = + (InnerControlBean) java.beans.Beans.instantiate(Thread.currentThread().getContextClassLoader(), + "org.apache.beehive.controls.test.controls.composition.InnerControlBean"); + return inner; + } + catch (Exception e) { + return null; + } + } + + public InnerControlBean instantiateNestedControlWithProperty() { + try { + BeanPropertyMap props = new BeanPropertyMap(InnerControl.Identity.class); + props.setProperty(InnerControlBean.NameKey, "ken"); + props.setProperty(InnerControlBean.JobKey, "engineer"); + props.setProperty(InnerControlBean.RankKey, new Integer(2)); + InnerControlBean inner = (InnerControlBean) org.apache.beehive.controls.api.bean.Controls.instantiate( + Thread.currentThread().getContextClassLoader(), + "org.apache.beehive.controls.test.controls.composition.InnerControlBean", props); + return inner; + } + catch (Exception e) { + throw new RuntimeException("Failed to instantiate nested control", e); + } + } + + public String testActivityWakeup() { + + String result = ""; + if (innerControl == null) + result = "inner control is NULL"; + else { + innerControl.fireEvent("Activity", "wakeup"); + /*Wait for the events*/ + try { + Thread.sleep(1000); + if (innerControlEventHandlerWakeUp.equals(EVENT_RECEIVED)) + result = "0"; + else + result = "Acivity.wakeup not received by EventHandler"; + } + catch (Exception e) { + result = "Thread sleep interrupted." + e.toString(); + } + } + return result; + } + + public String testActivityReadMessage() { + + String result = ""; + if (innerControl == null) + result = "inner control is NULL"; + else { + innerControl.fireEvent("Activity", "readMessage"); + /*Wait for the events*/ + try { + Thread.sleep(1000); + + if (innerControlEventHandlerReadMessage.equals(EVENT_RECEIVED)) + result = "0"; + else + result = "Acivity.readMessage not received by EventHandler"; + } + catch (Exception e) { + result = "Thread sleep interrupted." + e.toString(); + } + } + return result; + + } + + public String testActivityReport() { + + String result = ""; + if (innerControl == null) + result = "inner control is NULL"; + else { + innerControl.fireEvent("Activity", "report"); + /*Wait for the events*/ + try { + Thread.sleep(1000); + + if (innerControlEventHandlerReport.equals(EVENT_RECEIVED)) + result = "0"; + else + result = "Acivity.report not received by EventHandler"; + } + catch (Exception e) { + result = "Thread sleep interrupted." + e.toString(); + } + } + return result; + + } + + public String testActionShopping() { + + String result = ""; + if (innerControl == null) + result = "inner control is NULL"; + else { + innerControl.fireEvent("Action", "shopping"); + /*Wait for the events*/ + try { + Thread.sleep(1000); + + if (innerControlEventHandlerShopping.equals(EVENT_RECEIVED)) + result = "0"; + else + result = "Action.shopping not received by EventHandler"; + } + catch (Exception e) { + result = "Thread sleep interrupted." + e.toString(); + } + } + return result; + + } + + public String testActionDostuff() { + + String result = ""; + if (innerControl == null) + result = "inner control is NULL"; + else { + innerControl.fireEvent("Action", "doStuff"); + /*Wait for the events*/ + try { + Thread.sleep(1000); + + if (innerControlEventHandlerDoStuff.equals(EVENT_RECEIVED)) + result = "0"; + else + result = "Action.doStuff not received by EventHandler"; + } + catch (Exception e) { + result = "Thread sleep interrupted." + e.toString(); + } + } + return result; + + } + + /*Tests outer control receiving event from nested control using + * event listener. The nested control is instantiated programmatically + */ + public String testEventListener() { + + String result = "init"; + try { + + InnerControlBean nested = (InnerControlBean) java.beans.Beans.instantiate( + Thread.currentThread().getContextClassLoader(), + "org.apache.beehive.controls.test.controls.composition.InnerControlBean"); + if (nested == null) + result = "Nested control instantiated programmatically is NULL."; + else { + //Create an Event Listener + InnerControlEventListener listener = new InnerControlEventListener(); + nested.addActivityListener(listener); + nested.addActionListener(listener); + nested.fireAllEvents(); + try { + Thread.sleep(1000); + result = listener.getFinalResult(); + } + catch (Exception e) { + result = "Thread sleep interrupted." + e.toString(); + } + + + } + } + catch (Exception e) { + result = "Exception caught:" + e.toString(); + } + return result; + } + + /*Tests outer control receiving event from nested control using + * event listener. The nested control is instantiated decalratively + */ + public String testEventListenerByDeclare() { + + String result = "init"; + + if (innerControl == null) + result = "Nested control instantiated declaratively is NULL."; + else { + try { + //Create an Event Listener + InnerControlEventListener listener = new InnerControlEventListener(); + innerControl.addActivityListener(listener); + innerControl.addActionListener(listener); + innerControl.fireAllEvents(); + + Thread.sleep(1000); + result = listener.getFinalResult(); + } + catch (Exception e) { + result = "Thread sleep interrupted." + e.toString(); + } + + + } + return result; + + } + + /*Tests outer control receiving event from nested control using + * inner class listener. The nested control is instantiated programmatically + */ + public String testInnerClassListener() { + + String result = "init"; + try { + InnerControlBean nested = (InnerControlBean) java.beans.Beans.instantiate( + Thread.currentThread().getContextClassLoader(), + "org.apache.beehive.controls.test.controls.composition.InnerControlBean"); + if (nested == null) + result = "Nested control instantiated programmatically is NULL."; + else { + nested.addActivityListener( + new InnerControl.Activity() { + + public void wakeup() { + innerClassWakeUp = true; + } + + public int readMessage(String message) { + innerClassReadMessage = true; + return 0; + } + + public String report() { + innerClassReport = true; + return "event received."; + } + } + ); + nested.addActionListener( + new InnerControl.Action() { + + public Object[] shopping(double credit) { + innerClassShopping = true; + //return {"food","drinks","candies"}; + return null; + } + + public void doStuff(String value) { + innerClassDoStuff = true; + } + } + ); + nested.fireAllEvents(); + try { + Thread.sleep(1000); + } + catch (Exception e) { + /* ignore */ + } + + result = getInnerClassListenerResult(); + } + } + catch (Exception e) { + result = "Exception caught:" + e.toString(); + } + return result; + } + + /*Tests outer control receiving event from nested control using + * inner class listener. The nested control is instantiated decalratively + */ + public String testInnerClassListenerByDeclare() { + + String result = "init"; + + if (innerControl == null) + result = "Nested control instantiated declaratively is NULL."; + else { + try { + innerControl.addActivityListener( + new InnerControl.Activity() { + public void wakeup() { + innerControlInnerClassWakeUp = true; + } + + public int readMessage(String message) { + innerControlInnerClassReadMessage = true; + return 0; + } + + public String report() { + innerControlInnerClassReport = true; + return "event received."; + } + } + ); + innerControl.addActionListener( + new InnerControl.Action() { + + public Object[] shopping(double credit) { + innerControlInnerClassShopping = true; + //return {"food","drinks","candies"}; + return null; + } + + public void doStuff(String value) { + innerControlInnerClassDoStuff = true; + } + } + ); + innerControl.fireAllEvents(); + + Thread.currentThread().sleep(1000); + } + catch (Exception e) { + } + + result = getInnerControlInnerClassListenerResult(); + } + return result; + + } + + private String getInnerClassListenerResult() { + + String result = ""; + + if (!innerClassWakeUp) + result = "WakeUp not received."; + if (!innerClassReadMessage) + result = result + "readMessage not received."; + if (!innerClassReport) + result = result + "report not received."; + if (!innerClassShopping) + result = result + "shopping not received."; + if (!innerClassDoStuff) + result = result + "dostuff not received."; + + if (result.length() == 0) + result = "0"; + + return result; + } + + private String getInnerControlInnerClassListenerResult() { + + String result = ""; + + if (!innerControlInnerClassWakeUp) + result = "WakeUp not received."; + if (!innerControlInnerClassReadMessage) + result = result + "readMessage not received."; + if (!innerControlInnerClassReport) + result = result + "report not received."; + if (!innerControlInnerClassShopping) + result = result + "shopping not received."; + if (!innerControlInnerClassDoStuff) + result = result + "dostuff not received."; + + if (result.length() == 0) + result = "0"; + + return result; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/context/BaseContext.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/context/BaseContext.java new file mode 100644 index 0000000..2bf45d3 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/context/BaseContext.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.context; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +@ControlInterface +public interface BaseContext { + String hello(String name); + String[] getEventLog(); + +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/context/BaseContextImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/context/BaseContextImpl.java new file mode 100644 index 0000000..1379dd6 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/context/BaseContextImpl.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.context; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; +import org.apache.beehive.controls.api.context.ControlBeanContext.LifeCycle; +import org.apache.beehive.controls.api.context.ResourceContext; +import org.apache.beehive.controls.api.context.ResourceContext.ResourceEvents; +import org.apache.beehive.controls.api.events.EventHandler; + +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.util.LinkedList; + +@ControlImplementation +public class BaseContextImpl implements BaseContext, java.io.Serializable { + @Context + private ControlBeanContext context; + @Context + private ResourceContext resourceContext; + + private transient LinkedList _events; + + public String hello(String name) { + _events.add("BaseContextImpl.hello " + name); + return "Hello, " + name; + } + + @EventHandler(field = "context", eventSet = LifeCycle.class, eventName = "onCreate") + public void onCreate() { + _events = new LinkedList(); + _events.add("BaseContextImpl.onCreate"); + } + + @EventHandler(field = "resourceContext", eventSet = ResourceEvents.class, eventName = "onAcquire") + /* package */ void onAcquire() { + _events.add("BaseContextImpl.onAcquire"); + } + + @EventHandler(field = "resourceContext", eventSet = ResourceEvents.class, eventName = "onRelease") + protected void onRelease() { + _events.add("BaseContextImpl.onRelease"); + } + + // + // Implement the serialization writeObject method. By design, contextual services should + // never be serialized, and this is done by making sure that they are set to null prior + // to impl instance serialization. This implementation of writeObject just verifies this, + // then uses the default algorithm + // + public void writeObject(ObjectOutputStream oos) + throws IOException, ClassNotFoundException { + if (context != null || resourceContext != null) + throw new RuntimeException("Contextual service(s) not reset prior to serialization"); + + oos.defaultWriteObject(); + } + + public String[] getEventLog() { + String[] ret = new String[1]; + return _events.toArray(ret); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/context/ContextParam.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/context/ContextParam.java new file mode 100644 index 0000000..acb39df --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/context/ContextParam.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.context; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.properties.PropertySet; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.Method; + +@ControlInterface +public interface ContextParam { + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.PARAMETER) + public @interface Param { + String value(); + } + + // + // Returns the array of names for parameters of the referenced method + // + public String [] paramNameTest(Method m); + + // + // Returns the array of @Param annotations for parameters for the referenced method + // + public Param [] paramAnnotTest(Method m); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/context/ContextParamExt.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/context/ContextParamExt.java new file mode 100644 index 0000000..7242a4b --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/context/ContextParamExt.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.context; + +import org.apache.beehive.controls.api.bean.ControlExtension; + +/** + * This is a test extension that declares various methods that can be used to test + * ControlBeanContext parameter access APIs + *

    + */ +@ControlExtension +public interface ContextParamExt extends ContextParam { + public int valueTest(@Param("paramName") String paramName, + @Param("firstArg") int firstArg, + @Param("anotherArg") int anotherArg, + /* No @Param */ int hasNoParam, + @Param("lastArg") int lastArg); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/context/ContextParamImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/context/ContextParamImpl.java new file mode 100644 index 0000000..c9f6986 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/context/ContextParamImpl.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.context; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.Extensible; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; + +import java.lang.reflect.Method; + +@ControlImplementation(isTransient = true) +public class ContextParamImpl implements ContextParam, Extensible { + @Context + ControlBeanContext context; + + public String [] paramNameTest(Method m) { + return context.getParameterNames(m); + } + + public Param [] paramAnnotTest(Method m) { + Param [] annots = new Param [m.getParameterTypes().length]; + for (int i = 0; i < annots.length; i++) + annots[i] = context.getParameterPropertySet(m, i, Param.class); + + return annots; + } + + // + // The implementation of Extensible.invoke() for this class will echo back one of the + // named parameters of the invoked method. + // + // JCX-defined methods *must* follow two simple rules: + // + // 1. the first method is expected to contain the name of one of the method parameters + // 2. the method return type must be assignment-compatible with the type of the request + // parameter + // + public Object invoke(Method m, Object [] params) { + return context.getParameterValue(m, (String) params[0], params); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/context/ServiceGetter.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/context/ServiceGetter.java new file mode 100644 index 0000000..4c7a55b --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/context/ServiceGetter.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.context; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +/** + * A control interface to test control context service + */ +@ControlInterface +public interface ServiceGetter { + public Object getService(Class theService, Object selector); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/context/ServiceGetterImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/context/ServiceGetterImpl.java new file mode 100644 index 0000000..45c4603 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/context/ServiceGetterImpl.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.context; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; + +/** + * A control implementation that retrieves specific service via controlContext + */ +@ControlImplementation(isTransient = true) +public class ServiceGetterImpl implements ServiceGetter { + + @Context + ControlBeanContext context; + + public Object getService(Class theService, Object selector) { + + return context.getService(theService, selector); + } + +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/contextevent/BeanContextRecorder.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/contextevent/BeanContextRecorder.java new file mode 100644 index 0000000..87c36a5 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/contextevent/BeanContextRecorder.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.contextevent; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +/** + * A control interface to test control context events. + * There are two sources of control context events: ControlBeanContext and + * ResouceContext. + * The implementation of this interface only listens to context events from ControlBeanContext. + */ +@ControlInterface +public interface BeanContextRecorder { + public String getRecord(); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/contextevent/BeanContextRecorderImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/contextevent/BeanContextRecorderImpl.java new file mode 100644 index 0000000..87914ce --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/contextevent/BeanContextRecorderImpl.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.contextevent; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; +import org.apache.beehive.controls.api.events.EventHandler; + +/** + * A control impl that listens to and records its lifecycle events + * This impl listens to context event by declaring EventHandler + *

    + * There are two sources of control context events: ControlBeanContext and + * ResouceContext. + * This class only listens to context events from ControlBeanContext. + */ + +@ControlImplementation +public class BeanContextRecorderImpl implements BeanContextRecorder, java.io.Serializable { + + private String event_log = "init"; + + @Context + ControlBeanContext context; + + /*A EventHandler that listens to onCreate event*/ + @EventHandler(field = "context", eventSet = ControlBeanContext.LifeCycle.class, eventName = "onCreate") + public void onCreate() { +// System.out.println("++++++++++++++++++++++++++++++++++++++++++++++"); +// System.out.println("onCreate invoked on BeanContextRecorderImpl"); +// System.out.println("++++++++++++++++++++++++++++++++++++++++++++++"); + + event_log = event_log + "onCreate"; + } + + + /*Returns the event log*/ + public String getRecord() { +// System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++"); +// System.out.println("getRecord on BeanContextRecorderImpl invoked"); +// System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++"); + + return event_log; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/contextevent/Recorder.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/contextevent/Recorder.java new file mode 100644 index 0000000..bcf2a20 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/contextevent/Recorder.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.contextevent; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +/** + * A control interface to test control context events. + * There are two sources of control context events: ControlBeanContext and + * ResouceContext. + * The implementation of this interface listens to context events from both sources. + */ +@ControlInterface +public interface Recorder { + public String getRecord(); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/contextevent/RecorderImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/contextevent/RecorderImpl.java new file mode 100644 index 0000000..1df9264 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/contextevent/RecorderImpl.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.contextevent; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; +import org.apache.beehive.controls.api.context.ResourceContext; +import org.apache.beehive.controls.api.events.EventHandler; + +/** + * A control impl that listens to and records _context events + * This impl listens to _context events by declaring EventHandler. + *

    + * There are two sources of control _context events: ControlBeanContext and + * ResouceContext. + * This class listens to _context events from both sources. + */ + +@ControlImplementation +public class RecorderImpl implements Recorder, java.io.Serializable { + + private String event_log = "init"; + + @Context + private ControlBeanContext _context; + @Context + private ResourceContext _resourceContext; + + /*A EventHandler that listens to onCreate event*/ + @EventHandler(field = "_context", eventSet = ControlBeanContext.LifeCycle.class, eventName = "onCreate") + public void onCreate() { +// System.out.println("+++++++++++++++++++++++++++++++++++++++++"); +// System.out.println("onCreate invoked on RecorderImpl"); +// System.out.println("++++++++++++++++++++++++++++++++++++++++++"); + + event_log = event_log + "onCreate"; + } + + /*A EventHandler that listens to onAcquire event*/ + @EventHandler(field = "_resourceContext", eventSet = ResourceContext.ResourceEvents.class, eventName = "onAcquire") + public void onAcquire() { +// System.out.println("+++++++++++++++++++++++++++++++++++++++++"); +// System.out.println("onAcquire invoked on RecorderImpl"); +// System.out.println("++++++++++++++++++++++++++++++++++++++++++"); + event_log = event_log + "onAcquire"; + } + + /*A EventHandler that listens to onRelease event*/ + @EventHandler(field = "_resourceContext", eventSet = ResourceContext.ResourceEvents.class, eventName = "onRelease") + public void onRelease() { +// System.out.println("+++++++++++++++++++++++++++++++++++++++++"); +// System.out.println("onRelease invoked on RecorderImpl"); +// System.out.println("++++++++++++++++++++++++++++++++++++++++++"); + + event_log = event_log + "onRelease"; + } + + /*Returns the event log*/ + public String getRecord() { +// System.out.println("++++++++++++++++++++++++++++++++++++++++++++++"); +// System.out.println("getRecord method invoked on RecorderImpl"); +// System.out.println("++++++++++++++++++++++++++++++++++++++++++++++"); + + return event_log; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/emptyeventset/EmptyEvent.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/emptyeventset/EmptyEvent.java new file mode 100644 index 0000000..49eef3b --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/emptyeventset/EmptyEvent.java @@ -0,0 +1,32 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + $Header:$ +*/ +package org.apache.beehive.controls.test.controls.emptyeventset; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.events.EventSet; + +@ControlInterface +public interface EmptyEvent { + + @EventSet() + public interface Callback { + } +} + + diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/emptyeventset/EmptyEventImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/emptyeventset/EmptyEventImpl.java new file mode 100644 index 0000000..99bd2de --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/emptyeventset/EmptyEventImpl.java @@ -0,0 +1,37 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + $Header:$ +*/ +package org.apache.beehive.controls.test.controls.emptyeventset; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.Extensible; +import java.lang.reflect.Method; + +@ControlImplementation(isTransient=true) +public class EmptyEventImpl implements EmptyEvent, Extensible { + + public String hello() { + return "Hello!"; + } + + public Object invoke(Method m, Object[] args) throws Throwable + { + System.out.println("Invoked!"); + return "Hello"; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/encoding/ExtPropertySet.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/encoding/ExtPropertySet.java new file mode 100644 index 0000000..3ec9699 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/encoding/ExtPropertySet.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.encoding; + +import org.apache.beehive.controls.api.properties.PropertySet; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * An externally defined property set. + */ +@PropertySet +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD}) +public @interface ExtPropertySet { + public static final int AGE_DEFAULT = 5; + + public int age() default org.apache.beehive.controls.test.controls.encoding.ExtPropertySet.AGE_DEFAULT; +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/encoding/NestProps.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/encoding/NestProps.java new file mode 100644 index 0000000..c76daef --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/encoding/NestProps.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.encoding; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +import java.lang.annotation.Annotation; + +/** + * A simple control that nests the Props control, for nested property testing. + */ +@ControlInterface +public interface NestProps extends Props { + // + // Returns a propertySet value for a simple nested control + // + public Annotation getNestedPropertySet(Class propertySet); + + // + // Returns a propertySet value for an extension nested control + // + public Annotation getExtensionControlPropertySet(Class propertySet); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/encoding/NestPropsImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/encoding/NestPropsImpl.java new file mode 100644 index 0000000..539290d --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/encoding/NestPropsImpl.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.encoding; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; +import org.apache.beehive.controls.api.events.Client; +import org.apache.beehive.controls.api.events.EventHandler; + +import java.beans.PropertyChangeEvent; +import java.lang.annotation.Annotation; + +@ControlImplementation +public class NestPropsImpl implements NestProps, java.io.Serializable { + static final long serialVersionUID = 1L; + + @Context + ControlBeanContext context; + + @Control + @SimpleProps(simpleString = "A field annotation value") + Props propControl; + + @Control + @ArrayProps(arrayString = {"One", "Two", "Three"}) + private PropsExtension propExtControl; + + @Client + PropertyEvents client; + + /** + * Provides a simple test API to externally query the PropertySet values on this + * control. + */ + public Annotation getControlPropertySet(Class propertySet) { + return context.getControlPropertySet(propertySet); + } + + /** + * Provides a simple test API to externally query the PropertySet values on a + * nested control. + */ + public Annotation getNestedPropertySet(Class propertySet) { + return propControl.getControlPropertySet(propertySet); + } + + public Annotation getExtensionControlPropertySet(Class propertySet) { + return propExtControl.getControlPropertySet(propertySet); + } + + // + // Expose PropertyEvents from three potential sources: local properties, or from either of + // the two nested controls + // + @EventHandler(field = "context", eventSet = ControlBeanContext.LifeCycle.class, + eventName = "onPropertyChange") + public void onContextChange(PropertyChangeEvent pce) { + client.onChange(pce); + } + + @EventHandler(field = "propControl", eventSet = PropertyEvents.class, + eventName = "onChange") + public void onPropsChange(PropertyChangeEvent pce) { + client.onChange(pce); + } + + @EventHandler(field = "propExtControl", eventSet = PropertyEvents.class, + eventName = "onChange") + public void onExtPropsChange(PropertyChangeEvent pce) { + client.onChange(pce); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/encoding/Props.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/encoding/Props.java new file mode 100644 index 0000000..6a1ad5a --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/encoding/Props.java @@ -0,0 +1,135 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.encoding; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.bean.ExternalPropertySets; +import org.apache.beehive.controls.api.events.EventSet; +import org.apache.beehive.controls.api.packaging.PropertyInfo; +import org.apache.beehive.controls.api.properties.PropertySet; + +import java.beans.PropertyChangeEvent; +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * A simple control that can be used for property testing of basic primitive properties, + * as well as nested an array property types. + */ +@ControlInterface +@ExternalPropertySets({ExtPropertySet.class}) +public interface Props { + // + // A simple enumeration used to test enum annotations + // + public enum SimpleEnum { + ChoiceA, ChoiceB, ChoiceC; } + + // + // Define static final constants for SimpleProps defaults + // + static final int INT_DEFAULT = 87; + static final String STRING_DEFAULT = "Hello"; + static final Class CLASS_DEFAULT = Object.class; + static final org.apache.beehive.controls.test.controls.encoding.Props.SimpleEnum ENUM_DEFAULT = org.apache.beehive.controls.test.controls.encoding.Props.SimpleEnum.ChoiceA; + + // + // + // Define a PropertySet that tests simple types + // + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD}) + public @interface SimpleProps { + int simpleInt() default org.apache.beehive.controls.test.controls.encoding.Props.INT_DEFAULT; + + String simpleString() default org.apache.beehive.controls.test.controls.encoding.Props.STRING_DEFAULT; + + Class simpleClass() default Object.class; + + org.apache.beehive.controls.test.controls.encoding.Props.SimpleEnum simpleEnum() default org.apache.beehive.controls.test.controls.encoding.Props.SimpleEnum.ChoiceA; + } + + // + // Define static final constants for ArrayProps defaults + // + static final int [] ARRAY_INT_DEFAULT = {99, 33, 66, 22}; + static final String [] ARRAY_STRING_DEFAULT = {"How", "are", "you", ",", "today", "?"}; + static final Class [] ARRAY_CLASS_DEFAULT = {java.util.HashMap.class, java.util.Iterator.class}; + static final org.apache.beehive.controls.test.controls.encoding.Props.SimpleEnum [] ARRAY_ENUM_DEFAULT = {org.apache.beehive.controls.test.controls.encoding.Props.SimpleEnum.ChoiceB, org.apache.beehive.controls.test.controls.encoding.Props.SimpleEnum.ChoiceC}; + + // + // Define a PropertySet that tests array types + // + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.TYPE, ElementType.FIELD}) + public @interface ArrayProps { + int [] arrayInt() default {99, 33, 66, 22}; + + String [] arrayString() default {"How", "are", "you", ",", "today", "?"}; + + Class [] arrayClass() default {java.util.HashMap.class, java.util.Iterator.class}; + + org.apache.beehive.controls.test.controls.encoding.Props.SimpleEnum [] arrayEnum() default {org.apache.beehive.controls.test.controls.encoding.Props.SimpleEnum.ChoiceB, org.apache.beehive.controls.test.controls.encoding.Props.SimpleEnum.ChoiceC}; + } + + // + // Define static final constants for SimpleProps defaults + // + static final int ANNOT_INT_DEFAULT = 9999999; + static final String ANNOT_STRING_DEFAULT = "Hola"; + static final Class ANNOT_CLASS_DEFAULT = java.beans.Beans.class; + static final org.apache.beehive.controls.test.controls.encoding.Props.SimpleEnum ANNOT_ENUM_DEFAULT = org.apache.beehive.controls.test.controls.encoding.Props.SimpleEnum.ChoiceC; + + // + // Define a PropertySet that tests properties that are themselves annotation types + // + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD}) + public @interface TestAnnot { + @PropertyInfo(bound = true) // will generate PropertyChange events + org.apache.beehive.controls.test.controls.encoding.Props.SimpleProps simpleAnnot() + default @org.apache.beehive.controls.test.controls.encoding.Props.SimpleProps( + simpleInt = org.apache.beehive.controls.test.controls.encoding.Props.ANNOT_INT_DEFAULT, + simpleString = org.apache.beehive.controls.test.controls.encoding.Props.ANNOT_STRING_DEFAULT, + simpleClass = java.beans.Beans.class, + simpleEnum = org.apache.beehive.controls.test.controls.encoding.Props.SimpleEnum.ChoiceC); + + org.apache.beehive.controls.test.controls.encoding.Props.ArrayProps arrayAnnot(); + } + + // + // Exposes PropertyChange events to an external client. + // + @EventSet + public interface PropertyEvents { + public void onChange(PropertyChangeEvent pce); + } + + // + // Define property keys to enable access to test members in a PropertyMap + // + public Annotation getControlPropertySet(Class propertySet); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/encoding/PropsExtension.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/encoding/PropsExtension.java new file mode 100644 index 0000000..793bf3e --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/encoding/PropsExtension.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.encoding; + +import org.apache.beehive.controls.api.bean.ControlExtension; + +/** + * Defines a new extension interface that derives from Props + */ +@ControlExtension +@org.apache.beehive.controls.test.controls.property.Props.SimpleProps(simpleInt = 3) +// matches INT_PRIM_VALUE below +public interface PropsExtension extends Props { + // the class annotation value set above + public static int SIMPLE_INT_VALUE = 3; + + // the method annotation vales set below + public static Class SIMPLE_CLASS_VALUE1 = java.beans.Beans.class; + public static Class SIMPLE_CLASS_VALUE2 = org.apache.beehive.controls.api.bean.ControlBean.class; + + @SimpleProps(simpleClass = java.beans.Beans.class) + public Object getPropertySetOnMethod1(Class propertySet); + + @SimpleProps(simpleClass = org.apache.beehive.controls.api.bean.ControlBean.class) + public Object getPropertySetOnMethod2(Class propertySet); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/encoding/PropsImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/encoding/PropsImpl.java new file mode 100644 index 0000000..5887680 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/encoding/PropsImpl.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.encoding; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.Extensible; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; +import org.apache.beehive.controls.api.events.Client; +import org.apache.beehive.controls.api.events.EventHandler; +import org.apache.beehive.controls.api.properties.PropertySet; + +import java.beans.PropertyChangeEvent; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +@ControlImplementation +public class PropsImpl implements Props, Extensible, java.io.Serializable { + static final long serialVersionUID = 1L; + + @Context + ControlBeanContext context; + + @Client + PropertyEvents client; + + /** + * Provides a simple test API to externally query the control instance PropertySet values + * returned by ControlBeanContext APIs + */ + public Annotation getControlPropertySet(Class propertySet) { + return context.getControlPropertySet(propertySet); + } + + /** + * Set up a handler for context property change events, then expose them using the + * EventSet declared on the public interface. + */ + @EventHandler(field = "context", eventSet = ControlBeanContext.LifeCycle.class, + eventName = "onPropertyChange") + public void onContextChange(PropertyChangeEvent pce) { + client.onChange(pce); + } + + /** + * This implementation of Extensible.invoke allows the testing of annotations found + * on JCX methods + */ + public Object invoke(Method m, Object [] args) throws Throwable { + if (!(args[0] instanceof Class) || + !(((Class) args[0]).isAnnotationPresent(PropertySet.class))) + throw new IllegalArgumentException("Arg 0 must be an PropertySet interface!"); + + return context.getMethodPropertySet(m, (Class) args[0]); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/event/Event2Listener.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/event/Event2Listener.java new file mode 100644 index 0000000..c01ca4f --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/event/Event2Listener.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.test.controls.event; + + +/** + * A listener class for Hello.EventSet2 event + */ +public class Event2Listener implements Hello.EventSet2 { + private String method1Result = "method1NotReceived"; + private String method2Result = "set2method2NotReceived"; + private String overloadMethod1 = "overloadMethod1NotReceived"; + private String overloadMethod2 = "overloadMethod2NotReceived"; + + + public void method1() { + //Event received, flip the counter + method1Result = "0"; + } + + public int set2Method2() { + //Event received, flip the counter + method2Result = "0"; + return 0; + } + + public boolean set2OverloadedMethod() { + //Event received, flip the counter + overloadMethod1 = "0"; + return true; + } + + public boolean set2OverloadedMethod(int anArg) { + //Event received, flip the counter + overloadMethod2 = "0"; + return true; + } + + public String getMethod2Result() { + + return method2Result; + } + + public String getAllResult() { + + return method1Result + method2Result + overloadMethod1 + overloadMethod2; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/event/Hello.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/event/Hello.java new file mode 100644 index 0000000..655fc63 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/event/Hello.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.event; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.events.EventSet; + +/** + * A ControlInterface that declares three events + */ +@ControlInterface +public interface Hello { + + @EventSet + public interface EventSet0 { + } + + + @EventSet + public interface EventSet1 { + public void method1(); + } + + @EventSet(unicast = true) + public interface EventSet2 { + public void method1(); + + public int set2Method2(); + + public boolean set2OverloadedMethod(); + + public boolean set2OverloadedMethod(int anArg); + } + + public void triggerEvents(); + + public void triggerEventsUsingHandle(); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/event/HelloImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/event/HelloImpl.java new file mode 100644 index 0000000..f93ad7f --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/event/HelloImpl.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.event; + +import org.apache.beehive.controls.api.ControlException; +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; +import org.apache.beehive.controls.api.context.ControlHandle; +import org.apache.beehive.controls.api.events.Client; +import org.apache.beehive.controls.api.events.EventRef; + +/** + * A control implementation that raises events when the method is invoked + */ +@ControlImplementation +public class HelloImpl implements Hello, java.io.Serializable { + @Client + private Hello.EventSet0 eventSet0; + @Client + private Hello.EventSet1 eventSet1; + @Client + private Hello.EventSet2 eventSet2; + + @Context + private ControlBeanContext beanContext; + + public void triggerEvents() { + eventSet1.method1(); + eventSet2.method1(); + eventSet2.set2Method2(); + eventSet2.set2OverloadedMethod(); + eventSet2.set2OverloadedMethod(68); + + } + + public void triggerEventsUsingHandle() { + ControlHandle handle = beanContext.getControlHandle(); + if (handle == null) + throw new ControlException("No control handle for context:" + beanContext); + + Object [] emptyArgs = new Object []{}; + + try { + // Create an event ref using the method descriptor string format + EventRef eventRef = new EventRef(Hello.EventSet1.class.getName() + ".method1()V"); + handle.sendEvent(eventRef, emptyArgs); + + // Create an event ref using Method reflection + eventRef = new EventRef(Hello.EventSet2.class.getMethod("method1", new Class []{})); + handle.sendEvent(eventRef, emptyArgs); + + // Create an event ref using string descriptor, the serialize/deserialize before use + eventRef = new EventRef(Hello.EventSet2.class.getName() + ".set2Method2()I"); + eventRef = SerializeUtils.testSerialize(eventRef); + handle.sendEvent(eventRef, emptyArgs); + + // Create an event ref using Method reflection, then serialize/deserialize before use + eventRef = new EventRef(Hello.EventSet2.class.getMethod("set2OverloadedMethod", + new Class []{})); + eventRef = SerializeUtils.testSerialize(eventRef); + handle.sendEvent(eventRef, emptyArgs); + + // Create an event ref using string descriptor, where arg matching is required + eventRef = new EventRef(Hello.EventSet2.class.getName() + ".set2OverloadedMethod(I)Z"); + handle.sendEvent(eventRef, new Object []{68}); + } + catch (Exception e) { + throw new ControlException("Event dispatch error", e); + } + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/event/SerializeUtils.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/event/SerializeUtils.java new file mode 100644 index 0000000..a0cda91 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/event/SerializeUtils.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.test.controls.event; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +/** + * Utility code for testing serialization behavior + */ +public final class SerializeUtils { + /** + * Serializes an object into a byte array, then deserializes it from the array and returns + * the deserialized object. + */ + public static T testSerialize(T obj) { + byte [] serializedObject; + T returnObject; + + ByteArrayOutputStream baos = null; + ObjectOutputStream oos = null; + try { + baos = new ByteArrayOutputStream(); + oos = new ObjectOutputStream(baos); + oos.writeObject(obj); + oos.flush(); + serializedObject = baos.toByteArray(); + } + catch (Exception e) { + throw new RuntimeException("Error serializing object", e); + } + finally { + if (oos != null) + try { + oos.close(); + } + catch (IOException ignore) { + } + if (baos != null) + try { + baos.close(); + } + catch (IOException ignore) { + } + } + + ByteArrayInputStream bais = null; + ObjectInputStream ois = null; + try { + bais = new ByteArrayInputStream(serializedObject); + ois = new ObjectInputStream(bais); + returnObject = (T) ois.readObject(); + ois.close(); + bais.close(); + } + catch (Exception e) { + throw new RuntimeException("Error deserializing object", e); + } + finally { + if (bais != null) + try { + bais.close(); + } + catch (IOException ignore) { + } + if (ois != null) + try { + ois.close(); + } + catch (IOException ignore) { + } + } + + if (!obj.equals(returnObject)) + throw new RuntimeException("Deserialized object is not equivalent to original!"); + + return returnObject; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/MessageBuffer.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/MessageBuffer.java new file mode 100644 index 0000000..aa6e636 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/MessageBuffer.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.test.controls.eventsetApt; + +import org.apache.beehive.controls.spi.svc.InterceptorAnnotation; + +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; +import java.lang.annotation.Retention; + + +/** + * Requests that a method or event is delivered asynchronously. + * This annotation must be placed in a control interface that + * is annotation already with @ControlInterface, @ControlExtension or @EventSet. + * This annotation should be placed on methods or events that should be asynchronous. + * + *
    NOTE: Message buffering is ONLY currently supported on controls being used within + * a web service. + */ +@InterceptorAnnotation (service= MessageBufferService.class) +@Documented +@Retention (RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface MessageBuffer +{ + public boolean enable() default true; + public int retryCount() default 0; + public String retryDelay() default "0s"; +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/MessageBufferService.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/MessageBufferService.java new file mode 100644 index 0000000..e887b25 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/MessageBufferService.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.test.controls.eventsetApt; + +import org.apache.beehive.controls.spi.svc.Interceptor; + +/* + * This class defines the MessageBuffer contextual service + * This isn't exposed to the user, but is used in the discovery + * process via META-INF/services to map an interceptor implementation + * to the MessageBuffer service to hook this all into the runtime. + * + * @author Copyright (c) 2004 by BEA Systems. All Rights Reserved. + */ + +public interface MessageBufferService extends Interceptor +{} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/MulticastBase.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/MulticastBase.java new file mode 100644 index 0000000..a0e8e81 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/MulticastBase.java @@ -0,0 +1,36 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + $Header:$ +*/ +package org.apache.beehive.controls.test.controls.eventsetApt; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.events.EventSet; + +/** + * Base control interface for testing eventsets with same name (multicast). + */ +@ControlInterface +public interface MulticastBase { + + @EventSet() + public interface Callback { + void method1(); + } +} + + diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/MulticastBaseImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/MulticastBaseImpl.java new file mode 100644 index 0000000..94291fd --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/MulticastBaseImpl.java @@ -0,0 +1,35 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + $Header:$ +*/ +package org.apache.beehive.controls.test.controls.eventsetApt; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.Extensible; +import java.lang.reflect.Method; + +/** + * Base control for testing inherited eventsets with same name (multicast). + */ +@ControlImplementation(isTransient=true) +public class MulticastBaseImpl implements MulticastBase, Extensible { + + public Object invoke(Method m, Object[] args) throws Throwable + { + return null; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/MulticastExt.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/MulticastExt.java new file mode 100644 index 0000000..d8e43c7 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/MulticastExt.java @@ -0,0 +1,34 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + $Header:$ +*/ +package org.apache.beehive.controls.test.controls.eventsetApt; + +import org.apache.beehive.controls.api.bean.ControlExtension; +import org.apache.beehive.controls.api.events.EventSet; + +/** + * Control for testing apt compilation of inherited eventsets with same name (multicast). + */ +@ControlExtension +public interface MulticastExt extends MulticastBase { + + @EventSet() + public interface Callback extends MulticastBase.Callback { + void method2(); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/NoMethodsBase.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/NoMethodsBase.java new file mode 100644 index 0000000..23f6195 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/NoMethodsBase.java @@ -0,0 +1,33 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + $Header:$ +*/ +package org.apache.beehive.controls.test.controls.eventsetApt; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.events.EventSet; + +@ControlInterface +public interface NoMethodsBase { + + @EventSet() + public interface Callback { + void method1(); + } +} + + diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/NoMethodsBaseImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/NoMethodsBaseImpl.java new file mode 100644 index 0000000..0f1b253 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/NoMethodsBaseImpl.java @@ -0,0 +1,32 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + $Header:$ +*/ +package org.apache.beehive.controls.test.controls.eventsetApt; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.Extensible; +import java.lang.reflect.Method; + +@ControlImplementation(isTransient=true) +public class NoMethodsBaseImpl implements NoMethodsBase, Extensible { + + public Object invoke(Method m, Object[] args) throws Throwable + { + return "Hello"; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/NoMethodsExt.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/NoMethodsExt.java new file mode 100644 index 0000000..6331497 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/NoMethodsExt.java @@ -0,0 +1,32 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + $Header:$ +*/ +package org.apache.beehive.controls.test.controls.eventsetApt; + +import org.apache.beehive.controls.api.bean.ControlExtension; +import org.apache.beehive.controls.api.events.EventSet; +import org.apache.beehive.controls.test.controls.eventsetApt.MessageBuffer; + +@ControlExtension +public interface NoMethodsExt extends NoMethodsBase { + @EventSet() + public interface Callback extends NoMethodsBase.Callback { + @MessageBuffer(retryCount=2, retryDelay="1s") + void method2(); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/UnicastBase.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/UnicastBase.java new file mode 100644 index 0000000..99809b7 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/UnicastBase.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.eventsetApt; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.events.EventSet; + +/** + * Control interface for testing inherited eventset's with same name (unicast). + */ +@ControlInterface +public interface UnicastBase { + + @EventSet(unicast=true) + public interface Callback { + void method1(); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/UnicastBaseImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/UnicastBaseImpl.java new file mode 100644 index 0000000..b5b1ef0 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/UnicastBaseImpl.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.eventsetApt; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.Extensible; + +import java.lang.reflect.Method; + +/** + * Base class for testing inherited eventset's with same name (unicast case). + */ +@ControlImplementation(isTransient=true) +public class UnicastBaseImpl implements UnicastBase, Extensible { + + public Object invoke(Method m, Object[] args) throws Throwable + { + return null; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/UnicastExt.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/UnicastExt.java new file mode 100644 index 0000000..8e09b03 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetApt/UnicastExt.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.eventsetApt; + +import org.apache.beehive.controls.api.bean.ControlExtension; +import org.apache.beehive.controls.api.events.EventSet; + +/** + * Extension of base control with eventset of same name (unicast case). + */ +@ControlExtension +public interface UnicastExt extends UnicastBase { + + @EventSet(unicast=true) + public interface Callback extends UnicastBase.Callback { + String method2(); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetControlExt/EventBase.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetControlExt/EventBase.java new file mode 100644 index 0000000..8e387ce --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetControlExt/EventBase.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.eventsetControlExt; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.events.EventSet; + +/** + * Control for testing apt compilation of control extensions whose base + * class implement an EventSet. + */ +@ControlInterface +public interface EventBase { + + @EventSet() + public interface Callback { + void method1(); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetControlExt/EventBaseImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetControlExt/EventBaseImpl.java new file mode 100644 index 0000000..92fd135 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetControlExt/EventBaseImpl.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.eventsetControlExt; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.Extensible; +import org.apache.beehive.controls.test.controls.eventsetApt.MulticastBase; + +import java.lang.reflect.Method; + +/** + * Control for testing apt compilation of control extensions whose base + * class implement an EventSet. + */ +@ControlImplementation(isTransient=true) +public class EventBaseImpl implements EventBase, Extensible { + + public Object invoke(Method m, Object[] args) throws Throwable + { + return null; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetControlExt/EventExt.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetControlExt/EventExt.java new file mode 100644 index 0000000..7c8c141 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetControlExt/EventExt.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.eventsetControlExt; + +import org.apache.beehive.controls.api.bean.ControlExtension; +import org.apache.beehive.controls.api.events.EventSet; +import org.apache.beehive.controls.test.controls.eventsetApt.MulticastBase; + +/** + * Control for testing apt compilation of control extensions whose base + * class implement an EventSet. + */ +@ControlExtension +public interface EventExt extends EventBase { + +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetInheritance/BaseEventSet.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetInheritance/BaseEventSet.java new file mode 100644 index 0000000..9de8ae8 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetInheritance/BaseEventSet.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.eventsetInheritance; + +import org.apache.beehive.controls.api.events.EventSet; + +/** + * Declares an EventSet. + */ +@EventSet() +public interface BaseEventSet { + void baseEventSetMethod(); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetInheritance/CtrlBase.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetInheritance/CtrlBase.java new file mode 100644 index 0000000..bb0d2e3 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetInheritance/CtrlBase.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.eventsetInheritance; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.events.EventSet; + +/** + * Control for testing apt compilation of control extensions whose base + * class implement an EventSet. + */ +@ControlInterface +public interface CtrlBase { + + @EventSet() + public static interface CtrlBaseCallback extends BaseEventSet { + void method1(); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetInheritance/CtrlBaseImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetInheritance/CtrlBaseImpl.java new file mode 100644 index 0000000..0c16ed3 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetInheritance/CtrlBaseImpl.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.eventsetInheritance; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.Extensible; +import org.apache.beehive.controls.api.events.Client; + +import java.lang.reflect.Method; + +/** + * Control for testing apt compilation of control extensions whose base + * class implement an EventSet. + */ +@ControlImplementation(isTransient=true) +public class CtrlBaseImpl implements CtrlBase, Extensible { + + @Client CtrlExt.CtrlExtCallback client; + + public Object invoke(Method m, Object[] args) throws Throwable + { + client.baseEventSetMethod(); + return null; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetInheritance/CtrlExt.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetInheritance/CtrlExt.java new file mode 100644 index 0000000..44fb113 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/eventsetInheritance/CtrlExt.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.eventsetInheritance; + +import org.apache.beehive.controls.api.bean.ControlExtension; +import org.apache.beehive.controls.api.events.EventSet; + +/** + * Control extension which defines an event set which extends the + * eventset defined in CtrlBase. + */ +@ControlExtension +public interface CtrlExt extends CtrlBase +{ + public void runTest(); + + @EventSet + public interface CtrlExtCallback extends CtrlBase.CtrlBaseCallback { + public void method11(); + } + +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/extension/ExtensibleControl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/extension/ExtensibleControl.java new file mode 100644 index 0000000..946eeac --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/extension/ExtensibleControl.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.test.controls.extension; + + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.events.EventSet; +import org.apache.beehive.controls.api.properties.PropertySet; + +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * A control interface with one method and one propertySet + */ +@ControlInterface +public interface ExtensibleControl { + static final String CURRENT_POSITION = "In_ExtensibleControl_Interface"; + static final String CURRENT_LAYER = "On_ExtensibleControl_Layer"; + + /* A property to be inherited by all the sub controls*/ + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + @Inherited + public @interface Origin { + String Birthplace() default "ExtensibleControl"; + } + + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + public @interface WhereAbout { + String Position() default CURRENT_POSITION; + + String Layer() default CURRENT_LAYER; + } + + @EventSet + public interface SuperClassEvent { + public void method1(); + } + + public String hello(); + + public String getLayerByContext(); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/extension/ExtensibleControlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/extension/ExtensibleControlImpl.java new file mode 100644 index 0000000..e23e892 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/extension/ExtensibleControlImpl.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.extension; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.Extensible; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; +import org.apache.beehive.controls.api.context.ResourceContext; +import org.apache.beehive.controls.api.events.EventHandler; + +import java.io.Serializable; +import java.lang.reflect.Method; + +/** + * A control impl. + * By implementing Extensible, this impl makes itself extensible + */ + +@ControlImplementation +public class ExtensibleControlImpl implements ExtensibleControl, Extensible, Serializable { + @Context + ControlBeanContext context; + + @Context + ResourceContext resourceContext; + + @EventHandler(field = "resourceContext", + eventSet = ResourceContext.ResourceEvents.class, + eventName = "onAcquire") + public void onAcquire() { + // System.err.println("ExtensibleControlImpl.onAcquire()"); + } + + @EventHandler(field = "resourceContext", + eventSet = ResourceContext.ResourceEvents.class, + eventName = "onRelease") + public void onRelease() { + // System.err.println("ExtensibleControlImpl.onRelease()"); + } + + public String hello() { + return "Hello from super control"; + } + + public String getLayerByContext() { + /**BUG: could not refer to Greeting directly*/ + WhereAbout whereabout = (WhereAbout) context.getControlPropertySet(WhereAbout.class); + + return whereabout.Layer(); + } + + public Object invoke(Method m, Object[] args) throws Throwable { + return null; + } + +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/extension/SubControl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/extension/SubControl.java new file mode 100644 index 0000000..a123310 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/extension/SubControl.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.extension; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.events.EventSet; +import org.apache.beehive.controls.api.properties.PropertySet; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * A sub control extending ExtensibleControl. + * This control declares one new method and one new propertySet. + * It also resets the value of the propertySet inherited from ExtensibleControl. + */ +//@ControlExtension ::JIRA-118 and JIRA-197 +@ControlInterface +@ExtensibleControl.WhereAbout(Layer = "On_SubControl_Interface_Layer") +public interface SubControl extends ExtensibleControl { + + static final String A_MESSAGE = "New Property Declared by Sub Control"; + + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + public @interface NewProperty { + String Message() default A_MESSAGE; + } + + @EventSet + public interface SubClassEvent { + public void method1(); + } + + public String hello2(); + + public String accessInheritedProperty(); + + public String getAnnotatedInheritedPropertyByContext(); + + public String getExtendedPropertyByContext(); + + public int invokeInheritedEventFromSubControl(); + + public int invokeExtendedEventFromSubControl(); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/extension/SubControlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/extension/SubControlImpl.java new file mode 100644 index 0000000..1e887dc --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/extension/SubControlImpl.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.extension; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; +import org.apache.beehive.controls.api.events.Client; + +/** + * A control impl of a SubControl and extending ExtensibleControlImpl. + * It accesses the propertySets inherited from ExtensibleControl, and extended by + * its own interface. + */ +@ControlImplementation +public class SubControlImpl extends ExtensibleControlImpl + implements SubControl, java.io.Serializable { + @Context + ControlBeanContext context; + + @Client + SubControl.SuperClassEvent superevent; + @Client + SubControl.SubClassEvent subevent; + + public String hello2() { + return "Hello from subcontrol"; + } + + /*Accessing the propertySet inherited from ExtensibleControl*/ + public String accessInheritedProperty() { + /**Bug: could not refer to WhereAbout directly*/ + ExtensibleControl.WhereAbout where = (ExtensibleControl.WhereAbout) context.getControlPropertySet(ExtensibleControl.WhereAbout.class); + return where.Position(); + } + + public String getAnnotatedInheritedPropertyByContext() { + ExtensibleControl.Origin origin = (ExtensibleControl.Origin) context.getControlPropertySet(ExtensibleControl.Origin.class); + return origin.Birthplace(); + } + + public String getExtendedPropertyByContext() { + SubControl.NewProperty newproperty = (SubControl.NewProperty) context.getControlPropertySet(SubControl.NewProperty.class); + return newproperty.Message(); + } + + public int invokeInheritedEventFromSubControl() { + superevent.method1(); + return 0; + } + + public int invokeExtendedEventFromSubControl() { + subevent.method1(); + return 0; + } + +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/generic/ExtendedSimpleControl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/generic/ExtendedSimpleControl.java new file mode 100644 index 0000000..de59e6f --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/generic/ExtendedSimpleControl.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.generic; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +/** + * This test interface does an extension of a generic type while binding some of the + * formal type parameters. This ensures that the type binding is properly applied + * to the code-generated bean types. + */ +@ControlInterface +public interface ExtendedSimpleControl extends SimpleControl { +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/generic/ExtendedSimpleControlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/generic/ExtendedSimpleControlImpl.java new file mode 100644 index 0000000..cabba34 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/generic/ExtendedSimpleControlImpl.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.generic; + +import org.apache.beehive.controls.api.bean.ControlImplementation; + +@ControlImplementation +public class ExtendedSimpleControlImpl + extends SimpleControlImpl + implements ExtendedSimpleControl, java.io.Serializable { +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/generic/ListControl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/generic/ListControl.java new file mode 100644 index 0000000..eb59cc9 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/generic/ListControl.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.generic; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.events.EventSet; +import org.apache.beehive.controls.api.properties.PropertySet; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +@ControlInterface +public interface ListControl> { + // + // Note: JSR-175 annotation types cannot have formal type parameters + // + @PropertySet + @Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD}) + @Retention(RetentionPolicy.RUNTIME) + public static @interface ListProps { + /** + * This property can be used to set the concrete List implementation + * to use for containing elements + */ + Class listClass() default ArrayList.class; + } + + public void add(E val); + + public boolean contains(X val); + + public E get(int index); + + public T copy(Collection src); + + public E getLast(Collection coll); + + // + // Test an EventSet that uses formal type paramters defined in the outer control interface. + // + @EventSet(unicast = true) + public interface ListEvents { + public E onAdd(E newElement); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/generic/ListControlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/generic/ListControlImpl.java new file mode 100644 index 0000000..8f05bf6 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/generic/ListControlImpl.java @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.generic; + +import org.apache.beehive.controls.api.ControlException; +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.Extensible; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; +import org.apache.beehive.controls.api.events.Client; +import org.apache.beehive.controls.api.events.EventHandler; + +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +@ControlImplementation +public class ListControlImpl> + implements ListControl, Extensible, java.io.Serializable { + @Context + ControlBeanContext context; + + @EventHandler(field = "context", eventSet = ControlBeanContext.LifeCycle.class, + eventName = "onCreate") + public void onCreate() { + } + + @Client + ListEvents client; + + /** + * Returns the list used to store control elements. This is lazily instantiated, to + * allow the list class to be set by either an annotation or by calling setListClass() + * on the bean prior to manipulating the list. + */ + private T getList() { + if (_list == null) { + Class listClass = + context.getControlPropertySet(ListProps.class).listClass(); + try { + _list = (T) listClass.newInstance(); + } + catch (Exception e) { + throw new ControlException("Cannot create List", e); + } + } + return _list; + } + + public void add(E val) { + getList().add(val); + client.onAdd(val); + } + + ; + + public boolean contains(X val) { + return getList().contains(val); + } + + public E get(int index) { + return getList().get(index); + } + + public T copy(Collection src) { + T list = getList(); + for (E item : src) + list.add(item); + + return list; + } + + public E getLast(Collection coll) { + E last = null; + Iterator collIter = coll.iterator(); + while (collIter.hasNext()) + last = collIter.next(); + + return last; + } + + /** + * TBD + */ + public Object invoke(Method method, Object [] args) throws Throwable { + // To Be Implemented + // + return null; + } + + // + // NEVER ACCESS DIRECTLY... ALWAYS CALL GETLIST()!!!! + // + T _list; +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/generic/SimpleControl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/generic/SimpleControl.java new file mode 100644 index 0000000..b074c85 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/generic/SimpleControl.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.generic; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +import java.util.Vector; + +/** + * A simple control interface declared with type parameter + * and uses an API with type parameters + */ +@ControlInterface +public interface SimpleControl

    { + + public void setThem(Vector

    v); + + public P getTheFirst(); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/generic/SimpleControlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/generic/SimpleControlImpl.java new file mode 100644 index 0000000..93ef229 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/generic/SimpleControlImpl.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.generic; + +import org.apache.beehive.controls.api.bean.ControlImplementation; + +import java.util.Vector; + +@ControlImplementation +public class SimpleControlImpl

    implements SimpleControl

    , java.io.Serializable { + private Vector

    mylist = new Vector

    (); + + public void setThem(Vector

    v) { + mylist = v; + } + + public P getTheFirst() { + return mylist.get(0); + } + +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/AddIn.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/AddIn.java new file mode 100644 index 0000000..5455b90 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/AddIn.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.inherit; + +/** + * This is a regular interface that will be extended to add operation and events to a subclassed + * ControlInterface + */ +public interface AddIn { + public void addInOperation1(); + + public void addInOperation2(); + + public interface AddInEvents { + public void addInEvent1(); + + public void addInEvent2(); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/Ext1.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/Ext1.java new file mode 100644 index 0000000..8c88560 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/Ext1.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.inherit; + +import org.apache.beehive.controls.api.bean.ControlExtension; +import org.apache.beehive.controls.api.events.EventSet; + +/** + * This is the third level interface for the inheritence test hiearachy. It defines a + * ControlExtension interface that extends the 2nd level ControlInterface + */ +@ControlExtension +public interface Ext1 extends Intf2 { + @Intf1Props(intf1Prop1 = 1) + public int [] ext1Operation1(); + + @Intf2Props(intf2Prop2 = 2) + public int [] ext1Operation2(); + + @EventSet + public interface Ext1Events extends Intf2Events { + @Intf1Props(intf1Prop1 = 1) + public void ext1Event1(); + + @Intf2Props(intf2Prop2 = 2) + public void ext1Event2(); + } + + /** + * Declare an EventSet that is new and unique to this extension + */ + @EventSet(unicast = true) + public interface Ext1NewEvents { + @Intf1Props(intf1Prop1 = 1) + public void ext1NewEvent1(); + + @Intf2Props(intf2Prop2 = 2) + public void ext2NewEvent2(); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/Ext2.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/Ext2.java new file mode 100644 index 0000000..e7cfb89 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/Ext2.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.inherit; + +import org.apache.beehive.controls.api.bean.ControlExtension; +import org.apache.beehive.controls.api.events.EventSet; + +/** + * This is the fourth level interface for the inheritence test hiearachy. It defines a + * ControlExtension interface that extends another ControlExtension + */ +@ControlExtension +public interface Ext2 extends Ext1 { + @Intf1Props(intf1Prop1 = 1) + public void ext2Operation1(); + + @Intf2Props(intf2Prop2 = 2) + public void ext2Operation2(); + + @EventSet + public interface Ext2Events extends Ext1Events { + @Intf1Props(intf1Prop1 = 1) + public void ext2Event1(); + + @Intf2Props(intf2Prop2 = 2) + public void ext2Event2(); + } + + /** + * Declare an EventSet that extends an EventSet on the original ControlInterface interface, + * but skips a level of inheritance + */ + @EventSet + public interface Ext2SkipEvents extends Intf2Events { + @Intf1Props(intf1Prop1 = 1) + public void extSkip2Event1(); + + @Intf1Props(intf1Prop1 = 1) + public void extSkip2Event2(); + } + + /** + * Declare an EventSet that is new and unique to this extension + */ + @EventSet(unicast = true) + public interface Ext2NewEvents { + @Intf1Props(intf1Prop1 = 1) + public void ext2NewEvent1(); + + @Intf2Props(intf2Prop2 = 2) + public void ext2NewEvent2(); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/Hello.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/Hello.java new file mode 100644 index 0000000..0bc79d1 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/Hello.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.inherit; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.properties.PropertySet; + +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@ControlInterface +public interface Hello +{ + // + // A simple enumerated type used to customize the greeting by gender + // + public enum GenderType + { + NEUTRAL, MALE, FEMALE + } + + public @interface Gender + { + org.apache.beehive.controls.test.controls.inherit.Hello.GenderType value(); + } + + /** + * Declare a simple PropertySet, that allows the salutation used by the custom + * control to be customized. + */ + @PropertySet + @Target( {ElementType.TYPE, ElementType.FIELD, ElementType.METHOD} ) + @Retention(RetentionPolicy.RUNTIME) + public @interface Greeting + { + String salutation() default "Hello"; + Gender gender() default @Gender(GenderType.NEUTRAL); + } + + String hello(String name); + + String lastVisitor(); + + int visitorCount(); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/HelloImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/HelloImpl.java new file mode 100644 index 0000000..c92fe26 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/HelloImpl.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.inherit; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.Extensible; + +import java.lang.reflect.Method; + +@ControlImplementation +public class HelloImpl implements Hello, Extensible, java.io.Serializable +{ + public String _lastVisitor = ""; + int _visitorCount = 0; + + public String hello(String name) + { + _lastVisitor = name; + _visitorCount++; + return "Hello, " + name; + } + + public String lastVisitor() + { + return _lastVisitor; + } + + public int visitorCount() + { + return _visitorCount; + } + + /** + * Implements the Extensible.invoke interface when a JCX-declared method is called + */ + public Object invoke(Method method, Object [] args) + { + // + // To Be Implemented + // + return null; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/Intf1.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/Intf1.java new file mode 100644 index 0000000..748d0cf --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/Intf1.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.inherit; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.events.EventSet; +import org.apache.beehive.controls.api.properties.PropertySet; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * This is the first level interface for the inheritence test hiearachy. It extends an interface + * that is not a ControlInterface, to ensure that it is possible to derive a Control from an + * existing interface. + */ +@ControlInterface +public interface Intf1 extends Root { + public int intf1Operation1(); + + public int intf1Operation2(); + + /** + * Declare a PropertySet for this interface + */ + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD}) + public @interface Intf1Props { + public int intf1Prop1() default 1; + + public int intf1Prop2() default 2; + } + + /** + * Declare an EventSet that extends one on the Root interface + */ + @EventSet + public interface Intf1Events extends RootEvents { + public void intf1Event1(); + + public void intf1Event2(); + } + + /** + * Declare an EventSet that is new and unique to this interface + */ + @EventSet(unicast = true) + public interface Intf1NewEvents { + public void intf1NewEvent1(); + + public void intf1NewEvent2(); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/Intf1Impl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/Intf1Impl.java new file mode 100644 index 0000000..2b647d5 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/Intf1Impl.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.inherit; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; +import org.apache.beehive.controls.api.events.Client; + +/** + * This is the first level interface for the inheritence test hiearachy. It extends an interface + * that is not a ControlInterface, to ensure that it is possible to derive a Control from an + * existing interface. + */ +@ControlImplementation +public class Intf1Impl extends RootImpl + implements Intf1, java.io.Serializable { + @Context + ControlBeanContext context; + @Client + Intf1Events intfEvents; + @Client + Intf1NewEvents intfNewEvents; + + @Control + Hello _h1; + + public int intf1Operation1() { + intfEvents.rootEvent1(); + intfEvents.intf1Event1(); + intfNewEvents.intf1NewEvent1(); + + return context.getControlPropertySet(Intf1Props.class).intf1Prop1(); + } + + public int intf1Operation2() { + intfEvents.rootEvent2(); + intfEvents.intf1Event2(); + intfNewEvents.intf1NewEvent2(); + + return context.getControlPropertySet(Intf1Props.class).intf1Prop2(); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/Intf2.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/Intf2.java new file mode 100644 index 0000000..ee8060c --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/Intf2.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.inherit; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.events.EventSet; +import org.apache.beehive.controls.api.properties.PropertySet; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * This is the second level interface for the inheritence test hiearachy. It extends another + * ControlInterface and also adds new operations/events via an extended interface. + */ +@ControlInterface +public interface Intf2 extends Intf1, AddIn { + public int intf2Operation1(); + + public int intf2Operation2(); + + /** + * Declare a PropertySet for this interface + */ + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD}) + public @interface Intf2Props { + public int intf2Prop1() default 1; + + public int intf2Prop2() default 2; + } + + @EventSet + public interface Intf2Events extends Intf1Events, AddInEvents { + public void intf2Event1(); + + public void intf2Event2(); + } + + /** + * Declare an EventSet that is new and unique to this interface + */ + @EventSet(unicast = true) + public interface Intf2NewEvents extends AddInEvents { + public void intf2NewEvent1(); + + public void intf2NewEvent2(); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/Intf2Impl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/Intf2Impl.java new file mode 100644 index 0000000..32d643e --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/Intf2Impl.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.inherit; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.Extensible; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; +import org.apache.beehive.controls.api.events.Client; + +import java.lang.reflect.Method; + +/** + * This is the second level control implementation, that tests subclassing one ControlImplementation + * from another. This implementation also adds support for the Extensible interface, to enable + * ControlExtension subinterfaces to be declared. + */ +@ControlImplementation +public class Intf2Impl extends Intf1Impl + implements Intf2, Extensible, java.io.Serializable { + @Context + ControlBeanContext context; + @Client + Intf2Events intfEvents; + @Client + Intf2NewEvents intfNewEvents; + + @Control + Hello _h2; + + public int intf2Operation1() { + super.intf1Operation1(); + + intfEvents.addInEvent1(); + intfEvents.intf1Event1(); + intfEvents.intf2Event1(); + + intfNewEvents.addInEvent1(); + intfNewEvents.intf2NewEvent1(); + + return context.getControlPropertySet(Intf2Props.class).intf2Prop1(); + } + + public int intf2Operation2() { + super.intf1Operation2(); + + intfEvents.intf1Event1(); + intfEvents.addInEvent1(); + intfEvents.intf2Event1(); + + intfNewEvents.addInEvent1(); + intfNewEvents.intf2NewEvent1(); + + return context.getControlPropertySet(Intf2Props.class).intf2Prop2(); + } + + public void addInOperation1() { + // Same as above + intf2Operation1(); + } + + public void addInOperation2() { + // Same as above + intf2Operation2(); + } + + public Object invoke(Method method, Object [] args) { + return null; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/Root.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/Root.java new file mode 100644 index 0000000..aeb1522 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/Root.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.inherit; + +/** + * This is the root interface for the inheritance test control hierarchy. It is not a + * ControlInterface, and exists to verify that it is possible to subclass a ControlInterface/ + * ControlImpl from an existing interface/impl class pair. + */ +public interface Root { + public void rootOperation1(); + + public void rootOperation2(); + + public interface RootEvents { + public void rootEvent1(); + + public void rootEvent2(); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/RootImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/RootImpl.java new file mode 100644 index 0000000..d5a9600 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/inherit/RootImpl.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.inherit; + +/** + * This is the root implementation for the inheritance test control hierarchy. It is not a + * ControlImplementation, and exists to verify that it is possible to subclass a ControlInterface/ + * ControlImpl from an existing interface/impl class pair. + */ +public class RootImpl implements Root { + public void rootOperation1() { + } + + public void rootOperation2() { + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/instantiate/BoundExtPropertySet.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/instantiate/BoundExtPropertySet.java new file mode 100644 index 0000000..1cdb441 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/instantiate/BoundExtPropertySet.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.instantiate; + +import org.apache.beehive.controls.api.packaging.PropertyInfo; +import org.apache.beehive.controls.api.properties.PropertySet; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * An externally defined property set. + */ +@PropertySet +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD}) +public @interface BoundExtPropertySet { + public static final int AGE_DEFAULT = 5; + + @PropertyInfo(bound = true) + public int age() default BoundExtPropertySet.AGE_DEFAULT; + + @PropertyInfo(constrained = true) + public float height() default 0.0f; +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/instantiate/BoundPropertyControl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/instantiate/BoundPropertyControl.java new file mode 100644 index 0000000..5c8e0ba --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/instantiate/BoundPropertyControl.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.instantiate; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.bean.ExternalPropertySets; +import org.apache.beehive.controls.api.packaging.PropertyInfo; +import org.apache.beehive.controls.api.properties.PropertySet; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * A control interface with bound and/or constrain propertySet + */ +@ControlInterface +@ExternalPropertySets({BoundExtPropertySet.class}) +public interface BoundPropertyControl { + static final String BRAND_DEFAULT = "DEFAULT_BRAND"; + static final String MATERIAL_DEFAULT = "DEFAULT_MATERIAL"; + static final String QUALITY_DEFAULT = "DEFAULT_QUALITY"; + + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + public @interface Wheel { + @PropertyInfo(bound = true) + public String Brand() default BoundPropertyControl.BRAND_DEFAULT; + } + + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + public @interface Door { + @PropertyInfo(constrained = true) + public String Material() default BoundPropertyControl.MATERIAL_DEFAULT; + } + + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + public @interface Window { + @PropertyInfo(bound = true, constrained = true) + public String Quality() default BoundPropertyControl.QUALITY_DEFAULT; + } + + public String sayHello(); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/instantiate/BoundPropertyControlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/instantiate/BoundPropertyControlImpl.java new file mode 100644 index 0000000..0fc0c92 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/instantiate/BoundPropertyControlImpl.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.instantiate; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; + +/** + * A control impl that accesses the property declared by its control interface via control context + */ + +@ControlImplementation(isTransient = true) +public class BoundPropertyControlImpl implements BoundPropertyControl { + @Context + ControlBeanContext context; + + /*Accesses the propertySet value and returns the value*/ + public String sayHello() { + /**BUG: could not refer to Greeting directly*/ + //Greeting greeting=(SingleProperty.Greeting)context.getControlPropertySet(SingleProperty.Greeting.class); + + //return greeting.GreetWord(); + return "Hello"; + } + +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/instantiate/HelloControl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/instantiate/HelloControl.java new file mode 100644 index 0000000..b8354b8 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/instantiate/HelloControl.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.instantiate; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +/** + * A control interface with one method declared. + */ + +@ControlInterface +public interface HelloControl { + public String hello(String input); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/instantiate/HelloControlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/instantiate/HelloControlImpl.java new file mode 100644 index 0000000..a392875 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/instantiate/HelloControlImpl.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.instantiate; + +import org.apache.beehive.controls.api.bean.ControlImplementation; + +/** + * A simple control impl + */ +@ControlImplementation(isTransient = true) +public class HelloControlImpl implements HelloControl { + public String hello(String input) { + return input; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/instantiate/SingleProperty.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/instantiate/SingleProperty.java new file mode 100644 index 0000000..1dea6fb --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/instantiate/SingleProperty.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.instantiate; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.properties.PropertySet; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * A control interface with three single-member propertySets and one method + */ +@ControlInterface +public interface SingleProperty +{ + static final String GREET_DEFAULT = "Hello"; + + /** + * A single member property with default value + */ + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + public @interface Greeting + { + public String GreetWord() default GREET_DEFAULT; + } + + /** + * A single member property without default value + */ + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + public @interface Identity + { + public String name(); + } + + /** + * A single member property of primitive types + */ + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + public @interface Identifier + { + public int age() default 20; + } + + + public String sayHello(); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/instantiate/SinglePropertyImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/instantiate/SinglePropertyImpl.java new file mode 100644 index 0000000..c070ebb --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/instantiate/SinglePropertyImpl.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.instantiate; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; + +/** + * A control impl that accesses the property declared by its control interface via control context + */ + +@ControlImplementation(isTransient=true) +public class SinglePropertyImpl implements SingleProperty +{ + @Context ControlBeanContext context; + + /*Accesses the propertySet value and returns the value*/ + public String sayHello() + { + /**BUG: could not refer to Greeting directly*/ + Greeting greeting= context.getControlPropertySet(Greeting.class); + + return greeting.GreetWord(); + } + +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interceptor/HelloIntercepted.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interceptor/HelloIntercepted.java new file mode 100644 index 0000000..4ffc6d6 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interceptor/HelloIntercepted.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.interceptor; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.events.EventSet; +import org.apache.beehive.controls.api.properties.PropertySet; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Code-gen test for interceptors. Note that there is currently no + * runtime test for interceptors; this just tests that the code-gen + * path for interceptors results in compilable code. + */ +@ControlInterface +public interface HelloIntercepted { + @EventSet + public interface multicastEvents { + @SampleInterceptorAnnotation + public void multicastNotify(int a); + } + + @EventSet(unicast = true) + public interface unicastEvents { + @SampleInterceptorAnnotation + public int unicastNotify(Object b); + } + + // + // A simple enumerated type used to customize the greeting by gender + // + public enum GenderType { + NEUTRAL, MALE, FEMALE + } + + public @interface Gender { + GenderType value(); + } + + /** + * Declare a simple PropertySet, that allows the salutation used by the custom + * control to be customized. + */ + @PropertySet + @Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD}) + @Retention(RetentionPolicy.RUNTIME) + public @interface Greeting { + String salutation() default "Hello"; + + Gender gender() default @Gender(GenderType.NEUTRAL); + } + + String hello(String name); + + @SampleInterceptorAnnotation + String lastVisitor(); + + @SampleInterceptorAnnotation + int visitorCount(); + + /** + * Test intereptor annotations on overloaded methods + */ + @SampleInterceptorAnnotation + int visitorCount(String name); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interceptor/HelloInterceptedImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interceptor/HelloInterceptedImpl.java new file mode 100644 index 0000000..88d1681 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interceptor/HelloInterceptedImpl.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.interceptor; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.Extensible; + +import java.lang.reflect.Method; + +@ControlImplementation +public class HelloInterceptedImpl implements HelloIntercepted, Extensible, java.io.Serializable { + public String _lastVisitor = ""; + int _visitorCount = 0; + + public String hello(String name) { + _lastVisitor = name; + _visitorCount++; + return "Hello, " + name; + } + + public String lastVisitor() { + return _lastVisitor; + } + + public int visitorCount() { + return _visitorCount; + } + + public int visitorCount(String name) { + return _visitorCount; + } + + /** + * Implements the Extensible.invoke interface when a JCX-declared method is called + */ + public Object invoke(Method method, Object [] args) { + // + // To Be Implemented + // + return null; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfaceHint/README.txt b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfaceHint/README.txt new file mode 100644 index 0000000..7bdd999 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfaceHint/README.txt @@ -0,0 +1,8 @@ +Some brief notes on this test: + +This test is setup so that the BarControl is processed last by APT so that the FooControlBean field must be resolved +to either a.FooControlBean or b.FooControlBean (this is the right choice). In order for APT to correctly determine +which FooControlBean to use it must correctly process the @Control annotation's control interface hint. + +If working properly the BarControlClientInitializer should have a reference to the correct FooControlBean, otherwise +a compilation error occurs. diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfaceHint/a/FooControl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfaceHint/a/FooControl.java new file mode 100755 index 0000000..7f7dc62 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfaceHint/a/FooControl.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.test.controls.interfaceHint.a; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +@ControlInterface +public interface FooControl { + +} \ No newline at end of file diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfaceHint/a/FooControlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfaceHint/a/FooControlImpl.java new file mode 100755 index 0000000..6d8a232 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfaceHint/a/FooControlImpl.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.test.controls.interfaceHint.a; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import java.io.Serializable; + +@ControlImplementation +public class FooControlImpl implements FooControl, Serializable { + private static final long serialVersionUID = 1L; + +} \ No newline at end of file diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfaceHint/b/FooControl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfaceHint/b/FooControl.java new file mode 100755 index 0000000..fa98a52 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfaceHint/b/FooControl.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.test.controls.interfaceHint.b; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +@ControlInterface +public interface FooControl { + +} \ No newline at end of file diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfaceHint/b/FooControlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfaceHint/b/FooControlImpl.java new file mode 100755 index 0000000..9058273 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfaceHint/b/FooControlImpl.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.test.controls.interfaceHint.b; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import java.io.Serializable; + +@ControlImplementation +public class FooControlImpl implements FooControl, Serializable { + private static final long serialVersionUID = 1L; + +} \ No newline at end of file diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfaceHint/c/BarControl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfaceHint/c/BarControl.java new file mode 100644 index 0000000..6e51358 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfaceHint/c/BarControl.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.interfaceHint.c; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +@ControlInterface +public interface BarControl { + + public Object getFooBean(); + +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfaceHint/c/BarControlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfaceHint/c/BarControlImpl.java new file mode 100644 index 0000000..ba72003 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfaceHint/c/BarControlImpl.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.test.controls.interfaceHint.c; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.test.controls.interfaceHint.b.FooControlBean; + +import java.io.Serializable; + +@ControlImplementation +public class BarControlImpl implements BarControl, Serializable { + private static final long serialVersionUID = 1L; + + @Control(interfaceHint = org.apache.beehive.controls.test.controls.interfaceHint.b.FooControl.class) + public FooControlBean _fooBean; + + public Object getFooBean() { return _fooBean; } + +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfacegetter/CtrlExtension.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfacegetter/CtrlExtension.java new file mode 100644 index 0000000..682eb5d --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfacegetter/CtrlExtension.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.interfacegetter; + +import org.apache.beehive.controls.api.bean.ControlExtension; + +/** + * Control interface for testing property generation from getter/setter methods. + */ +@ControlExtension +public interface CtrlExtension extends ExtCtrl { + + public String getTextExt(); + public int getCount(); + public void setCount(int count); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfacegetter/ExtCtrl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfacegetter/ExtCtrl.java new file mode 100644 index 0000000..2fba6ef --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfacegetter/ExtCtrl.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.interfacegetter; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +/** + * Control interface for testing property generation from getter/setter methods. + */ +@ControlInterface +public interface ExtCtrl { + + public String getText(); + public void setText(String text); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfacegetter/ExtCtrlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfacegetter/ExtCtrlImpl.java new file mode 100644 index 0000000..a9ad3f9 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfacegetter/ExtCtrlImpl.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.interfacegetter; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.Extensible; + +import java.lang.reflect.Method; + +/** + * Control implementation for testing getter/setter property generation + * from a control interface. + */ +@ControlImplementation(isTransient=true) +public class ExtCtrlImpl implements ExtCtrl, Extensible { + + public String getText() { + return null; + } + + public void setText(String text) { + } + + /** + * Called by the Controls runtime to handle calls to methods of an + * extensible control. + *

    + * + * @param method The extended operation that was called. + * @param args Parameters of the operation. + * @return The value that should be returned by the operation. + * @throws Throwable any exception declared on the extended operation may be + * thrown. If a checked exception is thrown from the implementation that is not declared + * on the original interface, it will be wrapped in a ControlException. + */ + public Object invoke(Method method, Object[] args) throws Throwable { + return null; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfacegetter/InterfaceGetterSetter.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfacegetter/InterfaceGetterSetter.java new file mode 100644 index 0000000..e7d3e5e --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfacegetter/InterfaceGetterSetter.java @@ -0,0 +1,34 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + $Header:$ +*/ +package org.apache.beehive.controls.test.controls.interfacegetter; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +/** + * Control interface for testing property generation from getter/setter methods. + */ +@ControlInterface +public interface InterfaceGetterSetter { + + + public String getText(); + public void setText(String text); + + public int getCount(); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfacegetter/InterfaceGetterSetterImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfacegetter/InterfaceGetterSetterImpl.java new file mode 100644 index 0000000..90d4d3b --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/interfacegetter/InterfaceGetterSetterImpl.java @@ -0,0 +1,40 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + $Header:$ +*/ +package org.apache.beehive.controls.test.controls.interfacegetter; + +import org.apache.beehive.controls.api.bean.ControlImplementation; + +/** + * Control implementation for testing getter/setter property generation + * from a control interface. + */ +@ControlImplementation(isTransient=true) +public class InterfaceGetterSetterImpl implements InterfaceGetterSetter { + + public String getText() { + return null; + } + + public void setText(String text) { + } + + public int getCount() { + return 0; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/lifecycle/ControlLifecycle.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/lifecycle/ControlLifecycle.java new file mode 100644 index 0000000..79708cf --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/lifecycle/ControlLifecycle.java @@ -0,0 +1,42 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + $Header:$ +*/ +package org.apache.beehive.controls.test.controls.lifecycle; + +import java.util.List; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.context.ControlBeanContext; +import org.apache.beehive.controls.api.context.ResourceContext; + +/** + * + */ +@ControlInterface +public interface ControlLifecycle { + + public String echo(String echo); + + public ControlBeanContext getTheControlBeanContext(); + + public ResourceContext getTheResourceContext(); + + public List getLifecycleEvents(); + + public void clearLifecycleEvents(); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/lifecycle/ControlLifecycleImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/lifecycle/ControlLifecycleImpl.java new file mode 100644 index 0000000..0d24511 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/lifecycle/ControlLifecycleImpl.java @@ -0,0 +1,108 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + $Header:$ +*/ +package org.apache.beehive.controls.test.controls.lifecycle; + +import java.util.List; +import java.util.LinkedList; +import java.util.Collections; + +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ResourceContext; +import org.apache.beehive.controls.api.context.ControlBeanContext; +import org.apache.beehive.controls.api.context.ControlThreadContext; +import org.apache.beehive.controls.api.context.ControlContainerContext; +import org.apache.beehive.controls.api.events.EventHandler; +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * + */ +@ControlImplementation(isTransient=true) +public class ControlLifecycleImpl + implements ControlLifecycle { + + private static final Log LOG = LogFactory.getLog(ControlLifecycleImpl.class); + + @Context + private ControlBeanContext _controlBeanContext; + + @Context + private ResourceContext _resourceContext; + + private LinkedList _lifecycleEventStrings = new LinkedList(); + private boolean _onReleaseCalled = true; + + public String echo(String value) { + return "Echo: '" + value + "'"; + } + + public ResourceContext getTheResourceContext() { + return _resourceContext; + } + + public ControlBeanContext getTheControlBeanContext() { + return _controlBeanContext; + } + + public List getLifecycleEvents() { + return Collections.unmodifiableList(_lifecycleEventStrings); + } + + public void clearLifecycleEvents() { + _lifecycleEventStrings.clear(); + } + + @EventHandler(field = "_controlBeanContext", eventSet = ControlBeanContext.LifeCycle.class, eventName = "onCreate") + public void onCreate() { + // System.out.println("bean context event -- onCreate"); + checkContainerContext(); + _lifecycleEventStrings.add("onCreate"); + } + + @EventHandler(field = "_resourceContext", eventSet = ResourceContext.ResourceEvents.class, eventName = "onAcquire") + public void onAquire() { + // System.out.println("bean context event -- onAcquire"); + checkContainerContext(); + + if(!_onReleaseCalled) + throw new IllegalStateException("onAcquire called without having called onRelease on the previous request!"); + + _onReleaseCalled = false; + _lifecycleEventStrings.add("onAcquire"); + } + + @EventHandler(field = "_resourceContext", eventSet = ResourceContext.ResourceEvents.class, eventName = "onRelease") + public void onRelease() { + // System.out.println("bean context event -- onRelease"); + checkContainerContext(); + _onReleaseCalled = true; + + _lifecycleEventStrings.add("onRelease"); + } + + private void checkContainerContext() { + ControlContainerContext ccc = ControlThreadContext.getContext(); + //System.out.println("control container context: " + (ccc != null ? ccc.hashCode() : "is null")); + + if(ccc == null) + throw new IllegalStateException("Control could not find a valid ControlContainerContext!"); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/methodOverride/BaseExtCtrl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/methodOverride/BaseExtCtrl.java new file mode 100644 index 0000000..ec5ad14 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/methodOverride/BaseExtCtrl.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.methodOverride; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +/** + */ +@ControlInterface +public interface BaseExtCtrl { + +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/methodOverride/BaseExtCtrlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/methodOverride/BaseExtCtrlImpl.java new file mode 100644 index 0000000..a901c42 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/methodOverride/BaseExtCtrlImpl.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.methodOverride; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.Extensible; + +import java.lang.reflect.Method; + +/** + */ +@ControlImplementation(isTransient=true) +public class BaseExtCtrlImpl implements BaseExtCtrl, Extensible { + + + /** + * Called by the Controls runtime to handle calls to methods of an + * extensible control. + *

    + * + * @param method The extended operation that was called. + * @param args Parameters of the operation. + * @return The value that should be returned by the operation. + * @throws Throwable any exception declared on the extended operation may be + * thrown. If a checked exception is thrown from the implementation that is not declared + * on the original interface, it will be wrapped in a ControlException. + */ + public Object invoke(Method method, Object[] args) throws Throwable { + return null; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/methodOverride/CustomerDao.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/methodOverride/CustomerDao.java new file mode 100644 index 0000000..2e1a35e --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/methodOverride/CustomerDao.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.test.controls.methodOverride; + +import org.apache.beehive.controls.api.bean.ControlExtension; + +@ControlExtension +public interface CustomerDao extends BaseExtCtrl, ICustomerDao { + static final long serialVersionUID = 1L; + + public int countCustomers(String bar); + + public String getCustomer(); + + public String[] getCustomerRange(int start, int finish); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/methodOverride/ICustomerDao.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/methodOverride/ICustomerDao.java new file mode 100644 index 0000000..74ec519 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/methodOverride/ICustomerDao.java @@ -0,0 +1,29 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + $Header:$ +*/ +package org.apache.beehive.controls.test.controls.methodOverride; + +public interface ICustomerDao { + public int countCustomers(String foo); + + public String getCustomer(); + + public String getCustomer(String name); + + public String[] getCustomerRange(int begin, int end); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/overload/HelloControl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/overload/HelloControl.java new file mode 100644 index 0000000..1a9af0d --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/overload/HelloControl.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.overload; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +/** + * A control interface with overloaded methods. + */ + +@ControlInterface +public interface HelloControl +{ + public String hello(String input); + public String hello(int i); + public String hello(boolean[] booleans); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/overload/HelloControlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/overload/HelloControlImpl.java new file mode 100644 index 0000000..31765be --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/overload/HelloControlImpl.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.overload; + +import org.apache.beehive.controls.api.bean.ControlImplementation; + +/** + * A control impl with overloaded methods + */ +@ControlImplementation(isTransient = true) +public class HelloControlImpl implements HelloControl { + public String hello(String input) { + return input; + } + + public String hello(int i) { + return String.valueOf(i); + } + + public String hello(boolean[] booleans) { + String result = null; + if (booleans.length > 0) { + result = ""; + for (int i = 0; i < booleans.length; i++) { + result = result + String.valueOf(booleans[i]); + } + } + return result; + } + +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/packaging/BoundExtPropertySet.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/packaging/BoundExtPropertySet.java new file mode 100644 index 0000000..de13cb4 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/packaging/BoundExtPropertySet.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.packaging; + +import org.apache.beehive.controls.api.packaging.PropertyInfo; +import org.apache.beehive.controls.api.properties.PropertySet; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * An externally defined property set. + */ +@PropertySet +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD}) +public @interface BoundExtPropertySet { + public static final int AGE_DEFAULT = 5; + + @PropertyInfo(bound = true) + public int age() default org.apache.beehive.controls.test.controls.packaging.BoundExtPropertySet.AGE_DEFAULT; + + @PropertyInfo(constrained = true) + public float height() default 0.0f; +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/packaging/BoundPropertyControl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/packaging/BoundPropertyControl.java new file mode 100644 index 0000000..fb53620 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/packaging/BoundPropertyControl.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.packaging; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.bean.ExternalPropertySets; +import org.apache.beehive.controls.api.packaging.PropertyInfo; +import org.apache.beehive.controls.api.properties.PropertySet; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * A control interface with bound and/or constrain propertySet + */ +@ControlInterface +@ExternalPropertySets({BoundExtPropertySet.class}) +public interface BoundPropertyControl { + static final String BRAND_DEFAULT = "DEFAULT_BRAND"; + static final String MATERIAL_DEFAULT = "DEFAULT_MATERIAL"; + static final String QUALITY_DEFAULT = "DEFAULT_QUALITY"; + + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + public @interface Wheel { + @PropertyInfo(bound = true) + public String Brand() default org.apache.beehive.controls.test.controls.packaging.BoundPropertyControl.BRAND_DEFAULT; + } + + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + public @interface Door { + @PropertyInfo(constrained = true) + public String Material() default org.apache.beehive.controls.test.controls.packaging.BoundPropertyControl.MATERIAL_DEFAULT; + } + + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + public @interface Window { + @PropertyInfo(bound = true, constrained = true) + public String Quality() default org.apache.beehive.controls.test.controls.packaging.BoundPropertyControl.QUALITY_DEFAULT; + } + + public String sayHello(); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/packaging/BoundPropertyControlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/packaging/BoundPropertyControlImpl.java new file mode 100644 index 0000000..5225be3 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/packaging/BoundPropertyControlImpl.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.packaging; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; + +/** + * A control impl that accesses the property declared by its control interface via control context + */ + +@ControlImplementation(isTransient=true) +public class BoundPropertyControlImpl implements BoundPropertyControl +{ + @Context + private ControlBeanContext context; + + /*Accesses the propertySet value and returns the value*/ + public String sayHello() + { + /**BUG: could not refer to Greeting directly*/ + //Greeting greeting=(SingleProperty.Greeting)context.getControlPropertySet(SingleProperty.Greeting.class); + + //return greeting.GreetWord(); + return "Hello"; + } + +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/packaging/FeatureInfoControl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/packaging/FeatureInfoControl.java new file mode 100644 index 0000000..3a0afa4 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/packaging/FeatureInfoControl.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.packaging; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.packaging.FeatureAttribute; +import org.apache.beehive.controls.api.packaging.FeatureInfo; + +/** + * A control interface with FeatureInfo annotations + */ + +@ControlInterface +@FeatureInfo( + displayName = "A Control to test packaging", + shortDescription = "This control is to test control packaging", + isExpert = true, + isHidden = true, + isPreferred = true, + attributes = { + @FeatureAttribute(name = "FirstFeatureOfThisControl", value = "valueOf the first feature"), + @FeatureAttribute(name = "SecondFeatureOfThisControl", value = "valueOf the second feature") + } + +) +public interface FeatureInfoControl { + + @FeatureInfo( + displayName = "The only method on this control", + shortDescription = "The feature info about the method on the control", + isExpert = true, + isHidden = true, + isPreferred = true, + attributes = { + @FeatureAttribute(name = "FirstFeatureOfThisMethod", value = "valueOf the first feature of the method"), + @FeatureAttribute(name = "SecondFeatureOfThisMethod", value = "valueOf the second feature of the method") + } + + ) + public String hello(String input); +} \ No newline at end of file diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/packaging/FeatureInfoControlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/packaging/FeatureInfoControlImpl.java new file mode 100644 index 0000000..16373b9 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/packaging/FeatureInfoControlImpl.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.packaging; + +import org.apache.beehive.controls.api.bean.ControlImplementation; + +/** + * A simple control impl + */ +@ControlImplementation(isTransient = true) +public class FeatureInfoControlImpl implements FeatureInfoControl { + public String hello(String input) { + return input; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/packaging/Hello.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/packaging/Hello.java new file mode 100644 index 0000000..eb1ee3d --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/packaging/Hello.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.packaging; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.events.EventSet; + +/** + * A ControlInterface that declares three events + */ +@ControlInterface +public interface Hello +{ + + @EventSet + public interface EventSet0 + {} + + + @EventSet + public interface EventSet1 + { + public void method1(); + } + + @EventSet(unicast=true) + public interface EventSet2 + { + public void method1(); + public int set2Method2(); + public boolean set2OverloadedMethod(); + public boolean set2OverloadedMethod(int anArg); + } + + public void triggerEvents(); + public void triggerEventsUsingHandle(); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/packaging/HelloControl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/packaging/HelloControl.java new file mode 100644 index 0000000..7bb3b0b --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/packaging/HelloControl.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.packaging; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.packaging.ManifestAttribute; +import org.apache.beehive.controls.api.packaging.ManifestAttributes; + +/** + * A control interface with one method declared. + */ + +@ControlInterface +@ManifestAttributes({ + /* @ManifestAttribute(name=";", value="HelloControlIFAttributeValue1"), */ +@ManifestAttribute(name = "HelloControlIFAttribute2", value = "HelloControlIFAttributeValue2"), +@ManifestAttribute(name = "HelloControlIFAttribute3", value = " ") + }) +public interface HelloControl { + public String hello(String input); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/packaging/HelloControlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/packaging/HelloControlImpl.java new file mode 100644 index 0000000..57a0256 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/packaging/HelloControlImpl.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.packaging; + +import org.apache.beehive.controls.api.bean.ControlImplementation; + +/** + * A simple control impl + */ +@ControlImplementation(isTransient = true) +public class HelloControlImpl implements HelloControl { + public String hello(String input) { + return input; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/packaging/HelloImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/packaging/HelloImpl.java new file mode 100644 index 0000000..5caddf8 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/packaging/HelloImpl.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.packaging; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.events.Client; +import org.apache.beehive.controls.api.events.EventRef; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; +import org.apache.beehive.controls.api.context.ControlHandle; +import org.apache.beehive.controls.api.ControlException; + +/** + * A control implementation that raises events when the method is invoked + */ +@ControlImplementation +public class HelloImpl implements Hello, java.io.Serializable +{ + @Client EventSet0 eventSet0; + @Client EventSet1 eventSet1; + @Client EventSet2 eventSet2; + + @Context ControlBeanContext beanContext; + + public void triggerEvents() + { + } + + public void triggerEventsUsingHandle() + { + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/propertiesoptional/OptionalPropertySet.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/propertiesoptional/OptionalPropertySet.java new file mode 100644 index 0000000..f38f4e4 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/propertiesoptional/OptionalPropertySet.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.propertiesoptional; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.properties.PropertySet; + +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Control interface for testing optional property sets. + */ +@ControlInterface +public interface OptionalPropertySet { + + public String echo(String echo); + + @PropertySet(optional = true) + @Target({ElementType.FIELD, ElementType.TYPE}) + @Retention(RetentionPolicy.RUNTIME) + public @interface Optional { + public String value() default "optional"; + } + + @PropertySet(prefix="pre", optional = true, hasSetters = false) + @Target({ElementType.FIELD, ElementType.TYPE}) + @Retention(RetentionPolicy.RUNTIME) + public @interface OptionalNoSetters { + public String value() default "optionalNoSetters"; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/propertiesoptional/OptionalPropertySetImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/propertiesoptional/OptionalPropertySetImpl.java new file mode 100644 index 0000000..95fa739 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/propertiesoptional/OptionalPropertySetImpl.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.propertiesoptional; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; + +import java.io.Serializable; + +/** + * Control impl for optional PropertySet unit test. + */ +@ControlImplementation() +public class OptionalPropertySetImpl + implements OptionalPropertySet, Serializable { + + @Context + private ControlBeanContext _beanContext; + + public String echo(String echo) { + return null; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/propertiessimple/Property.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/propertiessimple/Property.java new file mode 100644 index 0000000..fa1a626 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/propertiessimple/Property.java @@ -0,0 +1,43 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + $Header:$ +*/ +package org.apache.beehive.controls.test.controls.propertiessimple; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.properties.PropertySet; +import org.apache.beehive.controls.api.packaging.PropertyInfo; + +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@ControlInterface +public interface Property { + + public String echo(String echo); + + @PropertySet + @Target({ElementType.FIELD, ElementType.TYPE}) + @Retention(RetentionPolicy.RUNTIME) + public @interface Text { + + @PropertyInfo(bound=true) + public String value() default "Echo text"; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/propertiessimple/PropertyImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/propertiessimple/PropertyImpl.java new file mode 100644 index 0000000..932f3e2 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/propertiessimple/PropertyImpl.java @@ -0,0 +1,38 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + $Header:$ +*/ +package org.apache.beehive.controls.test.controls.propertiessimple; + +import java.io.Serializable; +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; + +@ControlImplementation() +public class PropertyImpl + implements Property, Serializable { + + @Context + private ControlBeanContext _beanContext; + + public String echo(String echo) { + Text textProp = (Text)_beanContext.getControlPropertySet(Text.class); + String value = textProp.value(); + return value + ": '" + echo + "'"; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/BoundExtPropertySet.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/BoundExtPropertySet.java new file mode 100644 index 0000000..f62c0fc --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/BoundExtPropertySet.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.property; + +import org.apache.beehive.controls.api.packaging.PropertyInfo; +import org.apache.beehive.controls.api.properties.PropertySet; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * An externally defined property set. + */ +@PropertySet +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD}) +public @interface BoundExtPropertySet { + public static final int AGE_DEFAULT = 5; + + @PropertyInfo(bound = true) + public int age() default AGE_DEFAULT; + + @PropertyInfo(constrained = true) + public float height() default 0.0f; +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/BoundPropertyControl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/BoundPropertyControl.java new file mode 100644 index 0000000..bbb4fab --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/BoundPropertyControl.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.property; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.bean.ExternalPropertySets; +import org.apache.beehive.controls.api.packaging.PropertyInfo; +import org.apache.beehive.controls.api.properties.PropertySet; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + + +/** + * A control interface with bound and/or constrain propertySet + */ +@ControlInterface +@ExternalPropertySets({BoundExtPropertySet.class}) +public interface BoundPropertyControl { + static final String BRAND_DEFAULT = "DEFAULT_BRAND"; + static final String MATERIAL_DEFAULT = "DEFAULT_MATERIAL"; + static final String QUALITY_DEFAULT = "DEFAULT_QUALITY"; + + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + public @interface Wheel { + @PropertyInfo(bound = true) + public String Brand() default BRAND_DEFAULT; + } + + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + public @interface Door { + @PropertyInfo(constrained = true) + public String Material() default MATERIAL_DEFAULT; + } + + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + public @interface Window { + @PropertyInfo(bound = true, constrained = true) + public String Quality() default QUALITY_DEFAULT; + } + + public String sayHello(); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/BoundPropertyControlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/BoundPropertyControlImpl.java new file mode 100644 index 0000000..a5f6aa1 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/BoundPropertyControlImpl.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.property; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; + +/** + * A control impl that accesses the property declared by its control interface via control context + */ + +@ControlImplementation(isTransient = true) +public class BoundPropertyControlImpl implements BoundPropertyControl { + @Context + ControlBeanContext context; + + /*Accesses the propertySet value and returns the value*/ + public String sayHello() { + /**BUG: could not refer to Greeting directly*/ + //Greeting greeting=(SingleProperty.Greeting)context.getControlPropertySet(SingleProperty.Greeting.class); + + //return greeting.GreetWord(); + return "Hello"; + } + +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/ExtPropertySet.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/ExtPropertySet.java new file mode 100644 index 0000000..cab2c7d --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/ExtPropertySet.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.property; + +import org.apache.beehive.controls.api.properties.PropertySet; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * An externally defined property set. + */ +@PropertySet +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD}) +public @interface ExtPropertySet { + public static final int AGE_DEFAULT = 5; + + public int age() default AGE_DEFAULT; +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/Hello.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/Hello.java new file mode 100644 index 0000000..19d6f21 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/Hello.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.property; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.properties.PropertySet; + +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@ControlInterface +public interface Hello +{ + // + // A simple enumerated type used to customize the greeting by gender + // + public enum GenderType + { + NEUTRAL, MALE, FEMALE + } + + public @interface Gender + { + GenderType value(); + } + + /** + * Declare a simple PropertySet, that allows the salutation used by the custom + * control to be customized. + */ + @PropertySet + @Target( {ElementType.TYPE, ElementType.FIELD, ElementType.METHOD} ) + @Retention(RetentionPolicy.RUNTIME) + public @interface Greeting + { + String salutation() default "Hello"; + Gender gender() default @Gender(GenderType.NEUTRAL); + } + + String hello(String name); + + String lastVisitor(); + + int visitorCount(); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/HelloImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/HelloImpl.java new file mode 100644 index 0000000..ddc8df2 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/HelloImpl.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.property; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.Extensible; + +import java.lang.reflect.Method; + +@ControlImplementation +public class HelloImpl implements Hello, Extensible, java.io.Serializable +{ + public String _lastVisitor = ""; + int _visitorCount = 0; + + public String hello(String name) + { + _lastVisitor = name; + _visitorCount++; + return "Hello, " + name; + } + + public String lastVisitor() + { + return _lastVisitor; + } + + public int visitorCount() + { + return _visitorCount; + } + + /** + * Implements the Extensible.invoke interface when a JCX-declared method is called + */ + public Object invoke(Method method, Object [] args) + { + // + // To Be Implemented + // + return null; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/NestProps.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/NestProps.java new file mode 100644 index 0000000..7d1eddb --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/NestProps.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.property; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +import java.lang.annotation.Annotation; + +/** + * A simple control that nests the Props control, for nested property testing. + */ +@ControlInterface +public interface NestProps extends Props { + // + // Returns a propertySet value for a simple nested control + // + public Annotation getNestedPropertySet(Class propertySet); + + // + // Returns a propertySet value for an extension nested control + // + public Annotation getExtensionControlPropertySet(Class propertySet); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/NestPropsImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/NestPropsImpl.java new file mode 100644 index 0000000..1f26873 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/NestPropsImpl.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.property; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; +import org.apache.beehive.controls.api.events.Client; +import org.apache.beehive.controls.api.events.EventHandler; + +import java.beans.PropertyChangeEvent; +import java.lang.annotation.Annotation; + +@ControlImplementation +public class NestPropsImpl implements NestProps, java.io.Serializable { + static final long serialVersionUID = 1L; + + @Context + ControlBeanContext context; + + @Control + @Props.SimpleProps(simpleString = "A field annotation value") + Props propControl; + + @Control + @PropsExtension.ArrayProps(arrayString = {"One", "Two", "Three"}) + private PropsExtension propExtControl; + + @Client + PropertyEvents client; + + /** + * Provides a simple test API to externally query the PropertySet values on this + * control. + */ + public Annotation getControlPropertySet(Class propertySet) { + return context.getControlPropertySet(propertySet); + } + + /** + * Provides a simple test API to externally query the PropertySet values on a + * nested control. + */ + public Annotation getNestedPropertySet(Class propertySet) { + return propControl.getControlPropertySet(propertySet); + } + + public Annotation getExtensionControlPropertySet(Class propertySet) { + return propExtControl.getControlPropertySet(propertySet); + } + + // + // Expose PropertyEvents from three potential sources: local properties, or from either of + // the two nested controls + // + @EventHandler(field = "context", eventSet = ControlBeanContext.LifeCycle.class, + eventName = "onPropertyChange") + public void onContextChange(PropertyChangeEvent pce) { + client.onChange(pce); + } + + @EventHandler(field = "propControl", eventSet = Props.PropertyEvents.class, + eventName = "onChange") + public void onPropsChange(PropertyChangeEvent pce) { + client.onChange(pce); + } + + @EventHandler(field = "propExtControl", eventSet = Props.PropertyEvents.class, + eventName = "onChange") + public void onExtPropsChange(PropertyChangeEvent pce) { + client.onChange(pce); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/PropEvents.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/PropEvents.java new file mode 100644 index 0000000..1c01c22 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/PropEvents.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.property; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.events.EventSet; +import org.apache.beehive.controls.api.packaging.PropertyInfo; +import org.apache.beehive.controls.api.properties.PropertySet; + +import java.beans.PropertyChangeListener; +import java.beans.VetoableChangeListener; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * A simple control that can be used for property testing of bound and constrained + * property event behavior. + */ +@ControlInterface +public interface PropEvents { + // + // Declare a set of bound properties. These should deliver PropertyChange events + // if modified. + // + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD}) + public @interface BoundProps { + @PropertyInfo(bound = true) + public int boundInt() default 0; + } + + // + // Declare a set of bound properties. These should deliver PropertyChange and + // VetoableChange events if modified. + // + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD}) + public @interface ConstrainedProps { + @PropertyInfo(constrained = true) + public int constrainedInt() default 0; + + } + + // + // Declared unbound and unconstrained events. These should deliver no events if + // modified. + // + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD}) + public @interface BasicProps { + public int basicInt() default 0; + } + + // + // These EventSets are used as an external test point for events received by the + // implementation class. The implementation will simply echo the ControlBeanContext + // lifecycle events it receives as events on these event sets. This enables events + // received by the Impl to be matched against those received by an externally registered + // listener. Except in veto scenarios, where someone later on the veto chain may not + // receive an event, they should be equivalent. + // + @EventSet + public interface ImplPropertyChange extends PropertyChangeListener { + } + + @EventSet + public interface ImplVetoableChange extends VetoableChangeListener { + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/PropEventsImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/PropEventsImpl.java new file mode 100644 index 0000000..ca36997 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/PropEventsImpl.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.property; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; +import org.apache.beehive.controls.api.events.Client; +import org.apache.beehive.controls.api.events.EventHandler; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyVetoException; + +@ControlImplementation +public class PropEventsImpl implements PropEvents, java.io.Serializable { + static final long serialVersionUID = 1L; + + @Context + ControlBeanContext context; + + @Client + ImplPropertyChange changeNotifier; + + @Client + ImplVetoableChange vetoNotifier; + + // + // Receive context propertyChange events and echo them as external callbacks + // + @EventHandler(field = "context", eventSet = ControlBeanContext.LifeCycle.class, + eventName = "onPropertyChange") + public void onPropertyChange(PropertyChangeEvent pce) { + changeNotifier.propertyChange(pce); + } + + // + // Receive context vetoableChange events and echo them as external callbacks + // + @EventHandler(field = "context", eventSet = ControlBeanContext.LifeCycle.class, + eventName = "onVetoableChange") + public void onVetoableChange(PropertyChangeEvent pce) throws PropertyVetoException { + vetoNotifier.vetoableChange(pce); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/PropertyConstraintControl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/PropertyConstraintControl.java new file mode 100644 index 0000000..f7728d6 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/PropertyConstraintControl.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.property; + +import org.apache.beehive.controls.api.bean.AnnotationMemberTypes; +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.properties.PropertySet; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@ControlInterface +public interface PropertyConstraintControl { + + @PropertySet + @Target({ElementType.FIELD, ElementType.TYPE}) + @Retention(RetentionPolicy.RUNTIME) + public @interface Person { + @AnnotationMemberTypes.Text(maxLength = 8) + public String name() default ""; + + @AnnotationMemberTypes.Date(minValue = "1900/1/1") + public String dob() default ""; + + @AnnotationMemberTypes.Int(minValue = 0, maxValue = 130) + public int age() default AnnotationMemberTypes.OPTIONAL_INT; + } + + public String hello(); + +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/PropertyConstraintControlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/PropertyConstraintControlImpl.java new file mode 100644 index 0000000..dadc72c --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/PropertyConstraintControlImpl.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.property; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; + +@ControlImplementation(isTransient = true) +public class PropertyConstraintControlImpl implements PropertyConstraintControl { + @Context + ControlBeanContext ctx; + + public String hello() { + Person person = (Person) ctx.getControlPropertySet(Person.class); + return "Hello " + person.name(); + } + +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/PropertyControl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/PropertyControl.java new file mode 100644 index 0000000..b5fa8b0 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/PropertyControl.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.property; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.properties.PropertySet; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * A control interface with multiple propertySets declared + */ +@ControlInterface +public interface PropertyControl { + static final String DEFAULT_ATTRIBUTE_VALUE1 = "Hello"; + static final String DEFAULT_ATTRIBUTE_VALUE3 = "Hello3"; + + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + public @interface PropertyOne { + public String attribute1() default DEFAULT_ATTRIBUTE_VALUE1; + + public String attribute2(); + } + + @PropertySet(prefix = "PropertyTwo") + @Retention(RetentionPolicy.RUNTIME) + public @interface PropertyTwo { + public String attribute3() default DEFAULT_ATTRIBUTE_VALUE3; + + public String attribute4(); + } + + + @PropertySet(optional = true) + @Retention(RetentionPolicy.RUNTIME) + public @interface PropertyThree { + public String attribute5(); + + public String attribute6(); + } + + @PropertySet(hasSetters = false) + @Retention(RetentionPolicy.RUNTIME) + public @interface PropertyFout { + public String attribute7(); + + public String attribute8(); + } + + + public String getAttribute1ByContext(); + + public String getAttribute3ByContext(); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/PropertyControlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/PropertyControlImpl.java new file mode 100644 index 0000000..7b3c21d --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/PropertyControlImpl.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.property; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; + +/** + * A control impl that accesses the property declared by its control interface via control context + */ + +@ControlImplementation(isTransient = true) +public class PropertyControlImpl implements PropertyControl { + @Context + ControlBeanContext context; + + /*Accesses the propertySet value and returns the value*/ + public String getAttribute1ByContext() { + /**BUG: could not refer to Greeting directly*/ + PropertyOne propertyOne = (PropertyControl.PropertyOne) context.getControlPropertySet(PropertyControl.PropertyOne.class); + + return propertyOne.attribute1(); + } + + /*Accesses the propertySet value and returns the value*/ + public String getAttribute3ByContext() { + /**BUG: could not refer to Greeting directly*/ + PropertyTwo propertyTwo = (PropertyControl.PropertyTwo) context.getControlPropertySet(PropertyControl.PropertyTwo.class); + + return propertyTwo.attribute3(); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/Props.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/Props.java new file mode 100644 index 0000000..109ede7 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/Props.java @@ -0,0 +1,135 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.property; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.bean.ExternalPropertySets; +import org.apache.beehive.controls.api.events.EventSet; +import org.apache.beehive.controls.api.packaging.PropertyInfo; +import org.apache.beehive.controls.api.properties.PropertySet; + +import java.beans.PropertyChangeEvent; +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * A simple control that can be used for property testing of basic primitive properties, + * as well as nested an array property types. + */ +@ControlInterface +@ExternalPropertySets({ExtPropertySet.class}) +public interface Props { + // + // A simple enumeration used to test enum annotations + // + public enum SimpleEnum { + ChoiceA, ChoiceB, ChoiceC; } + + // + // Define static final constants for SimpleProps defaults + // + static final int INT_DEFAULT = 87; + static final String STRING_DEFAULT = "Hello"; + static final Class CLASS_DEFAULT = java.lang.Object.class; + static final SimpleEnum ENUM_DEFAULT = SimpleEnum.ChoiceA; + + // + // + // Define a PropertySet that tests simple types + // + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD}) + public @interface SimpleProps { + int simpleInt() default INT_DEFAULT; + + String simpleString() default STRING_DEFAULT; + + Class simpleClass() default java.lang.Object.class; + + SimpleEnum simpleEnum() default SimpleEnum.ChoiceA; + } + + // + // Define static final constants for ArrayProps defaults + // + static final int [] ARRAY_INT_DEFAULT = {99, 33, 66, 22}; + static final String [] ARRAY_STRING_DEFAULT = {"How", "are", "you", ",", "today", "?"}; + static final Class [] ARRAY_CLASS_DEFAULT = {java.util.HashMap.class, java.util.Iterator.class}; + static final SimpleEnum [] ARRAY_ENUM_DEFAULT = {SimpleEnum.ChoiceB, SimpleEnum.ChoiceC}; + + // + // Define a PropertySet that tests array types + // + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.TYPE, ElementType.FIELD}) + public @interface ArrayProps { + int [] arrayInt() default {99, 33, 66, 22}; + + String [] arrayString() default {"How", "are", "you", ",", "today", "?"}; + + Class [] arrayClass() default {java.util.HashMap.class, java.util.Iterator.class}; + + SimpleEnum [] arrayEnum() default {SimpleEnum.ChoiceB, SimpleEnum.ChoiceC}; + } + + // + // Define static final constants for SimpleProps defaults + // + static final int ANNOT_INT_DEFAULT = 9999999; + static final String ANNOT_STRING_DEFAULT = "Hola"; + static final Class ANNOT_CLASS_DEFAULT = java.beans.Beans.class; + static final SimpleEnum ANNOT_ENUM_DEFAULT = SimpleEnum.ChoiceC; + + // + // Define a PropertySet that tests properties that are themselves annotation types + // + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD}) + public @interface TestAnnot { + @PropertyInfo(bound = true) // will generate PropertyChange events + SimpleProps simpleAnnot() + default @SimpleProps( + simpleInt = ANNOT_INT_DEFAULT, + simpleString = ANNOT_STRING_DEFAULT, + simpleClass = java.beans.Beans.class, + simpleEnum = SimpleEnum.ChoiceC); + + ArrayProps arrayAnnot(); + } + + // + // Exposes PropertyChange events to an external client. + // + @EventSet + public interface PropertyEvents { + public void onChange(PropertyChangeEvent pce); + } + + // + // Define property keys to enable access to test members in a PropertyMap + // + public Annotation getControlPropertySet(Class propertySet); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/PropsExtension.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/PropsExtension.java new file mode 100644 index 0000000..556e34a --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/PropsExtension.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.property; + +import org.apache.beehive.controls.api.bean.ControlExtension; + +/** + * Defines a new extension interface that derives from Props + */ +@ControlExtension +@Props.SimpleProps(simpleInt = 3) +// matches INT_PRIM_VALUE below +public interface PropsExtension extends Props { + // the class annotation value set above + public static int SIMPLE_INT_VALUE = 3; + + // the method annotation vales set below + public static Class SIMPLE_CLASS_VALUE1 = java.beans.Beans.class; + public static Class SIMPLE_CLASS_VALUE2 = org.apache.beehive.controls.api.bean.ControlBean.class; + + @SimpleProps(simpleClass = java.beans.Beans.class) + public Object getPropertySetOnMethod1(Class propertySet); + + @SimpleProps(simpleClass = org.apache.beehive.controls.api.bean.ControlBean.class) + public Object getPropertySetOnMethod2(Class propertySet); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/PropsImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/PropsImpl.java new file mode 100644 index 0000000..5101357 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/PropsImpl.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.property; + + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.Extensible; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; +import org.apache.beehive.controls.api.events.Client; +import org.apache.beehive.controls.api.events.EventHandler; +import org.apache.beehive.controls.api.properties.PropertySet; + +import java.beans.PropertyChangeEvent; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +@ControlImplementation +public class PropsImpl implements Props, Extensible, java.io.Serializable { + static final long serialVersionUID = 1L; + + @Context + ControlBeanContext context; + + @Client + PropertyEvents client; + + /** + * Provides a simple test API to externally query the control instance PropertySet values + * returned by ControlBeanContext APIs + */ + public Annotation getControlPropertySet(Class propertySet) { + return context.getControlPropertySet(propertySet); + } + + /** + * Set up a handler for context property change events, then expose them using the + * EventSet declared on the public interface. + */ + @EventHandler(field = "context", eventSet = ControlBeanContext.LifeCycle.class, + eventName = "onPropertyChange") + public void onContextChange(PropertyChangeEvent pce) { + client.onChange(pce); + } + + /** + * This implementation of Extensible.invoke allows the testing of annotations found + * on JCX methods + */ + public Object invoke(Method m, Object [] args) throws Throwable { + if (!(args[0] instanceof Class) || + !(((Class) args[0]).isAnnotationPresent(PropertySet.class))) + throw new IllegalArgumentException("Arg 0 must be an PropertySet interface!"); + + return context.getMethodPropertySet(m, (Class) args[0]); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/SingleProperty.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/SingleProperty.java new file mode 100644 index 0000000..f1c7175 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/SingleProperty.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.property; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.properties.PropertySet; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * A control interface with three single-member propertySets and one method + */ +@ControlInterface +public interface SingleProperty { + static final String GREET_DEFAULT = "Hello"; + + /** + * A single member property with default value + */ + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + public @interface Greeting { + public String GreetWord() default GREET_DEFAULT; + } + + /** + * A single member property without default value + */ + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + public @interface Identity { + public String name(); + } + + /** + * A single member property of primitive types + */ + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + public @interface Identifier { + public int age() default 20; + } + + + public String sayHello(); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/SinglePropertyImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/SinglePropertyImpl.java new file mode 100644 index 0000000..bfe75cc --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/SinglePropertyImpl.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.property; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; + +/** + * A control impl that accesses the property declared by its control interface via control context + */ + +@ControlImplementation(isTransient = true) +public class SinglePropertyImpl implements SingleProperty { + @Context + ControlBeanContext context; + + /*Accesses the propertySet value and returns the value*/ + public String sayHello() { + /**BUG: could not refer to Greeting directly*/ + Greeting greeting = (SingleProperty.Greeting) context.getControlPropertySet(SingleProperty.Greeting.class); + + return greeting.GreetWord(); + } + +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/constraint/BookControl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/constraint/BookControl.java new file mode 100644 index 0000000..de7d16d --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/constraint/BookControl.java @@ -0,0 +1,127 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.property.constraint; + +import org.apache.beehive.controls.api.bean.AnnotationConstraints; +import org.apache.beehive.controls.api.bean.AnnotationMemberTypes; +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.properties.PropertySet; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * A control interface for testing Annotation.MembershipRule + */ + +@ControlInterface +public interface BookControl { + /** + * A propertySet with AT_LEAST_ONE constraint + * User needs to set at least one value when instantiating controls declaratively; + * It is unknow what will happens when instantiating controls programmatically. + */ + @PropertySet + @Target({ElementType.FIELD, ElementType.TYPE}) + @Retention(RetentionPolicy.RUNTIME) + @AnnotationConstraints.MembershipRule(AnnotationConstraints.MembershipRuleValues.AT_LEAST_ONE) + public @interface Price { + @AnnotationMemberTypes.Decimal(minValue = 10) + public String us_price() default ""; + + @AnnotationMemberTypes.Decimal(minValue = 10) + public String ca_price() default ""; + + @AnnotationMemberTypes.Decimal(minValue = 10) + public String eu_price() default ""; + } + + /** + * A propertySet with AT_MOST_ONE + * User can not set more than one value when instantiating controls declaratively; + * It is unknow what will happens when instantiating controls programmatically. + */ + @PropertySet + @Target({ElementType.FIELD, ElementType.TYPE}) + @Retention(RetentionPolicy.RUNTIME) + @AnnotationConstraints.MembershipRule(AnnotationConstraints.MembershipRuleValues.AT_MOST_ONE) + public @interface Language { + @AnnotationMemberTypes.Text(maxLength = 10) + public String coverlanguage() default ""; + + @AnnotationMemberTypes.Text(maxLength = 10) + public String contentlanguage() default ""; + + @AnnotationMemberTypes.Text(maxLength = 10) + public String authorlanguage() default ""; + } + + /** + * A propertySet with EXACTLY_ONE + * User must set one value, and only one value when instantiating controls declaratively; + * It is unknow what will happens when instantiating controls programmatically. + */ + @PropertySet + @Target({ElementType.FIELD, ElementType.TYPE}) + @Retention(RetentionPolicy.RUNTIME) + @AnnotationConstraints.MembershipRule(AnnotationConstraints.MembershipRuleValues.EXACTLY_ONE) + public @interface Intro { + @AnnotationMemberTypes.Text(maxLength = 8) + public String title() default ""; + + @AnnotationMemberTypes.Text(maxLength = 8) + public String subject() default ""; + + @AnnotationMemberTypes.Text(maxLength = 8) + public String content() default ""; + } + + + /** + * Negative tests: members without @AnnotationMemberTypes causes compile errors + */ + + @PropertySet + @Target({ElementType.FIELD, ElementType.TYPE}) + @Retention(RetentionPolicy.RUNTIME) + @AnnotationConstraints.MembershipRule(AnnotationConstraints.MembershipRuleValues.AT_LEAST_ONE) + public @interface Material { + /* + public Object paper; + public Object cover; + */ + } + + + @PropertySet + @Target({ElementType.FIELD, ElementType.TYPE}) + @Retention(RetentionPolicy.RUNTIME) + @AnnotationConstraints.MembershipRule(AnnotationConstraints.MembershipRuleValues.EXACTLY_ONE) + public @interface Publisher { + /* + public Object paper; + public Object cover; + */ + } + + public String hello(); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/constraint/BookControlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/constraint/BookControlImpl.java new file mode 100644 index 0000000..3d52264 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/constraint/BookControlImpl.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.property.constraint; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; + +@ControlImplementation(isTransient = true) +public class BookControlImpl implements BookControl { + @Context + ControlBeanContext ctx; + + public String hello() { + return "Hello"; + } + +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/constraint/PersonControl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/constraint/PersonControl.java new file mode 100644 index 0000000..0418d38 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/constraint/PersonControl.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.property.constraint; + +import org.apache.beehive.controls.api.bean.AnnotationConstraints; +import org.apache.beehive.controls.api.bean.AnnotationMemberTypes; +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.properties.PropertySet; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * A control interface that declares PropertySets with constraints + */ + +@ControlInterface +public interface PersonControl { + + public final static double SAVINGS_MIN_VALUE = 100; + public final static String ISSUEDATE_MAXVALUE = "2007/01/31"; + public final static String EXPIRYDATE_MINVALUE = "2007/02/28"; + //public final static String ISSUEDATE_MAXVALUE=null; + + /** + * A propertySet with ALL_IF_ANY + * Rule is enforced at build time when users instantiate the control declaratively. + * It is unknow what will happens when instantiating controls programmatically. + */ + @PropertySet + @Target({ElementType.FIELD, ElementType.TYPE}) + @Retention(RetentionPolicy.RUNTIME) + @AnnotationConstraints.MembershipRule(AnnotationConstraints.MembershipRuleValues.ALL_IF_ANY) + public @interface Address { + @AnnotationMemberTypes.Text(maxLength = 8) + public String street(); + + @AnnotationMemberTypes.Text(maxLength = 8) + public String city(); + + @AnnotationMemberTypes.Text(maxLength = 8) + public String province(); + + @AnnotationMemberTypes.Int(minValue = 0, maxValue = 100000) + public int zipcode() default 0; + + } + + @PropertySet + @Target({ElementType.FIELD, ElementType.TYPE}) + @Retention(RetentionPolicy.RUNTIME) + @AnnotationConstraints.AllowExternalOverride + public @interface Assets { + //JIRA-203 AnnotationMemberTypes.Decimal should support float + + @AnnotationMemberTypes.Decimal(places = 2, minValue = SAVINGS_MIN_VALUE, maxValue = 10000) + public String savings() default "0"; + } + + @PropertySet + @Target({ElementType.FIELD, ElementType.TYPE}) + @Retention(RetentionPolicy.RUNTIME) + public @interface ID { + @AnnotationMemberTypes.Text(isLong = true) + public String idnumber() default "0"; + } + + + @PropertySet + @Target({ElementType.FIELD, ElementType.TYPE}) + @Retention(RetentionPolicy.RUNTIME) + public @interface DriverLicense { + @AnnotationMemberTypes.Date(maxValue = ISSUEDATE_MAXVALUE) + public String issuedate() default ""; + + @AnnotationMemberTypes.Date(minValue = EXPIRYDATE_MINVALUE) + public String expirydate() default ""; + + /* Test passing a null to revokedate. + Commented out temporarily + @AnnotationMemberTypes.Date(minValue=ISSUEDATE_MAXVALUE) + public String revokedate() default null; + */ + } + + public String hello(); + +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/constraint/PersonControlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/constraint/PersonControlImpl.java new file mode 100644 index 0000000..436a204 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/property/constraint/PersonControlImpl.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.property.constraint; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; + +@ControlImplementation(isTransient = true) +public class PersonControlImpl implements PersonControl { + @Context + ControlBeanContext ctx; + + public String hello() { + //Person person = (Person)ctx.getControlPropertySet(Person.class); + //return "Hello " + person.name(); + return "Hello"; + } + +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/serialization/ControlSerialization.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/serialization/ControlSerialization.java new file mode 100644 index 0000000..d76cef1 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/serialization/ControlSerialization.java @@ -0,0 +1,37 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + $Header:$ +*/ +package org.apache.beehive.controls.test.controls.serialization; + +import java.util.List; +import org.apache.beehive.controls.api.bean.ControlInterface; + +/** + * Test control serialization and lifecycle events associated with serialization. + */ +@ControlInterface +public interface ControlSerialization { + + public List getLifecycleEvents(); + + public void clearLifecycleEvents(); + + public int getControlState(); + + public void setControlState(int controlState); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/serialization/ControlSerializationImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/serialization/ControlSerializationImpl.java new file mode 100644 index 0000000..039ea79 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/serialization/ControlSerializationImpl.java @@ -0,0 +1,98 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + $Header:$ +*/ +package org.apache.beehive.controls.test.controls.serialization; + +import java.util.List; +import java.util.LinkedList; +import java.util.Collections; + +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ResourceContext; +import org.apache.beehive.controls.api.context.ControlBeanContext; +import org.apache.beehive.controls.api.context.ControlThreadContext; +import org.apache.beehive.controls.api.context.ControlContainerContext; +import org.apache.beehive.controls.api.events.EventHandler; +import org.apache.beehive.controls.api.bean.ControlImplementation; + +/** + * Control implementation for testing control serialization and associated lifecycle events. + */ +@ControlImplementation +public class ControlSerializationImpl + implements ControlSerialization, java.io.Serializable { + + private LinkedList _lifecycleEventStrings = new LinkedList(); + private boolean _onReleaseCalled = true; + private int _controlState = -1; + + @Context + private ControlBeanContext _controlBeanContext; + + @Context + private ResourceContext _resourceContext; + + public List getLifecycleEvents() { + return Collections.unmodifiableList(_lifecycleEventStrings); + } + + public void clearLifecycleEvents() { + _lifecycleEventStrings.clear(); + } + + public int getControlState() { + return _controlState; + } + + public void setControlState(int controlState) { + _controlState = controlState; + } + + @EventHandler(field = "_controlBeanContext", eventSet = ControlBeanContext.LifeCycle.class, eventName = "onCreate") + public void onCreate() { + checkContainerContext(); + _lifecycleEventStrings.add("onCreate"); + } + + @EventHandler(field = "_resourceContext", eventSet = ResourceContext.ResourceEvents.class, eventName = "onAcquire") + public void onAquire() { + // System.out.println("bean context event -- onAcquire : state " + _controlState + " ctrl " + this); + checkContainerContext(); + + if(!_onReleaseCalled) + throw new IllegalStateException("onAcquire called without having called onRelease on the previous request! Ctrl state = " + _controlState); + + _onReleaseCalled = false; + _lifecycleEventStrings.add("onAcquire"); + } + + @EventHandler(field = "_resourceContext", eventSet = ResourceContext.ResourceEvents.class, eventName = "onRelease") + public void onRelease() { + // System.out.println("bean context event -- onRelease : state = " + _controlState + " ctrl " + this); + checkContainerContext(); + _onReleaseCalled = true; + + _lifecycleEventStrings.add("onRelease"); + } + + private void checkContainerContext() { + ControlContainerContext ccc = ControlThreadContext.getContext(); + if(ccc == null) + throw new IllegalStateException("Control could not find a valid ControlContainerContext!"); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/simple/SimpleStatefulControl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/simple/SimpleStatefulControl.java new file mode 100644 index 0000000..e4736c2 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/simple/SimpleStatefulControl.java @@ -0,0 +1,19 @@ +/** + * Created by IntelliJ IDEA. + * User: ekoneil + * Date: Apr 27, 2006 + * Time: 12:47:00 PM + * To change this template use File | Settings | File Templates. + */ +package org.apache.beehive.controls.test.controls.simple; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +@ControlInterface +public interface SimpleStatefulControl { + + public int getValue(); + + public void setValue(int value); +} + \ No newline at end of file diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/simple/SimpleStatefulControlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/simple/SimpleStatefulControlImpl.java new file mode 100644 index 0000000..e9efb1d --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/simple/SimpleStatefulControlImpl.java @@ -0,0 +1,30 @@ +/** + * Created by IntelliJ IDEA. + * User: ekoneil + * Date: Apr 27, 2006 + * Time: 12:47:32 PM + * To change this template use File | Settings | File Templates. + */ +package org.apache.beehive.controls.test.controls.simple; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; + +@ControlImplementation(isTransient = true) +public class SimpleStatefulControlImpl + implements SimpleStatefulControl { + + @Context + private ControlBeanContext _context; + + private int _value; + + public int getValue() { + return _value; + } + + public void setValue(int value) { + _value = value; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/DefaultThreadControl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/DefaultThreadControl.java new file mode 100644 index 0000000..ac28914 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/DefaultThreadControl.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.threading; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +/** + * A control interface with two methods declared. + * This control interface is designed to test threading model of + * control framework. + */ + +@ControlInterface +public interface DefaultThreadControl { + public long doSlowIncrement(boolean isBlocker); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/DefaultThreadControlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/DefaultThreadControlImpl.java new file mode 100644 index 0000000..994ebb9 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/DefaultThreadControlImpl.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.threading; + +import org.apache.beehive.controls.api.bean.ControlImplementation; + +/** + * An impl of DefaultThreadControl. + *

    + * Test objective: create an instance of this impl, have one thread + * invoke doGet, and another thread invoke doSet + */ +@ControlImplementation +public class DefaultThreadControlImpl implements DefaultThreadControl, java.io.Serializable { + + private long counter = 0; + private boolean marker = false; + + + public long doSlowIncrement(boolean isBlocker) { + + if (isBlocker) { + marker = true; + while (marker) { + counter++; + try { + Thread.currentThread().sleep(200); + } + catch (InterruptedException e) { + e.printStackTrace(); + } + } + return counter; + } + else { + marker = false; + return counter; + } + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/MultiThreadControl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/MultiThreadControl.java new file mode 100644 index 0000000..ec8e2f4 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/MultiThreadControl.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.threading; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +/** + * A control interface with two methods declared. + * This control interface is designed to test threading model of + * control framework. + */ + +@ControlInterface +public interface MultiThreadControl { + public final static String METHOD1 = "blocker"; + public final static String METHOD2 = "unblocker"; + public final static long EXPECTED_DELAY = 150; + + public long doSlowIncrement(boolean isBlocker); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/MultiThreadControlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/MultiThreadControlImpl.java new file mode 100644 index 0000000..bd7b189 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/MultiThreadControlImpl.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.threading; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.Threading; +import org.apache.beehive.controls.api.bean.ThreadingPolicy; + +/** + * An impl of HelloControl. + * This impl is multi-threaded + */ +@ControlImplementation +@Threading(ThreadingPolicy.MULTI_THREADED) +public class MultiThreadControlImpl implements MultiThreadControl, java.io.Serializable { + private long counter = 0; + private boolean marker = false; + + + public long doSlowIncrement(boolean isBlocker) { + + if (isBlocker) { + marker = true; + while (marker) { + counter++; + try { + Thread.currentThread().sleep(200); + } + catch (InterruptedException e) { + e.printStackTrace(); + } + } + return counter; + } + else { + marker = false; + return counter; + } + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/SingleThreadControl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/SingleThreadControl.java new file mode 100644 index 0000000..4c82917 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/SingleThreadControl.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.threading; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +/** + * A control interface with two methods declared. + * This control interface is designed to test threading model of + * control framework. + */ + +@ControlInterface +public interface SingleThreadControl { + public long doSlowIncrement(boolean isBlocker); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/SingleThreadControlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/SingleThreadControlImpl.java new file mode 100644 index 0000000..0edce23 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/SingleThreadControlImpl.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.threading; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.Threading; +import org.apache.beehive.controls.api.bean.ThreadingPolicy; + +/** + * An impl of HelloControl. + */ +@ControlImplementation +@Threading(ThreadingPolicy.SINGLE_THREADED) +public class SingleThreadControlImpl implements SingleThreadControl, java.io.Serializable { + private long counter = 0; + private boolean marker = false; + + + public long doSlowIncrement(boolean isBlocker) { + + if (isBlocker) { + marker = true; + while (marker) { + counter++; + try { + Thread.currentThread().sleep(200); + } + catch (InterruptedException e) { + e.printStackTrace(); + } + } + return counter; + } + else { + marker = false; + return counter; + } + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/nested/CompositeMThreadControl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/nested/CompositeMThreadControl.java new file mode 100644 index 0000000..438457b --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/nested/CompositeMThreadControl.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.threading.nested; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +/** + * A control interface + */ +@ControlInterface +public interface CompositeMThreadControl { + + public int startSingleThreadNestedControl(); + + public int stopSingleThreadNestedControl(); + + public int startMultiThreadNestedControl(); + + public int stopMultiThreadNestedControl(); + +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/nested/CompositeMThreadControlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/nested/CompositeMThreadControlImpl.java new file mode 100644 index 0000000..1aad4f0 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/nested/CompositeMThreadControlImpl.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.threading.nested; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.Threading; +import org.apache.beehive.controls.api.bean.ThreadingPolicy; + +import java.io.Serializable; + +/** + * A multi-threaded impl of CompositeMThreadControl. + * Exposes methods to invoke the nested controls + */ +@ControlImplementation +@Threading(ThreadingPolicy.MULTI_THREADED) +public class CompositeMThreadControlImpl implements CompositeMThreadControl, Serializable { + + @Control + NestedSThreadControlBean nestedS; + + @Control + NestedMThreadControlBean nestedM; + + public int startSingleThreadNestedControl() { + return nestedS.doSlowIncrement(false); + } + + public int stopSingleThreadNestedControl() { + return nestedS.doSlowIncrement(true); + } + + public int startMultiThreadNestedControl() { + return nestedM.doSlowIncrement(false); + } + + public int stopMultiThreadNestedControl() { + return nestedM.doSlowIncrement(true); + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/nested/NestedMThreadControl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/nested/NestedMThreadControl.java new file mode 100644 index 0000000..882c46d --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/nested/NestedMThreadControl.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.threading.nested; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +/** + * A control interface with two methods declared. + * This control interface is designed to a nested control and + * test control threading. + */ + +@ControlInterface +public interface NestedMThreadControl { + public int doSlowIncrement(boolean isStopper); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/nested/NestedMThreadControlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/nested/NestedMThreadControlImpl.java new file mode 100644 index 0000000..dd47bdc --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/nested/NestedMThreadControlImpl.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.threading.nested; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.Threading; +import org.apache.beehive.controls.api.bean.ThreadingPolicy; + +/** + * An impl of NestedMThreadControl. + * If this impl is multi-threaded, a thread could stop the loop started by another thread. + */ +@ControlImplementation +@Threading(ThreadingPolicy.MULTI_THREADED) +public class NestedMThreadControlImpl implements NestedMThreadControl, java.io.Serializable { + private boolean marker = false; + private int counter = 0; + + public int doSlowIncrement(boolean isStopper) { + if (isStopper) { + marker = false; + return counter; + } + else { + marker = true; + while (marker) { + counter++; + try { + Thread.currentThread().sleep(200); + } + catch (InterruptedException e) { + e.printStackTrace(); + } + } + return counter; + } + } + +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/nested/NestedMultiThreadControl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/nested/NestedMultiThreadControl.java new file mode 100644 index 0000000..3dbae85 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/nested/NestedMultiThreadControl.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.threading.nested; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +/** + * A control interface with two methods declared. + * This control interface is designed to a nested control and + * test control threading. + */ + +@ControlInterface +public interface NestedMultiThreadControl { + + public long doRead(); + + public void doSet(); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/nested/NestedMultiThreadControlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/nested/NestedMultiThreadControlImpl.java new file mode 100644 index 0000000..816d895 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/nested/NestedMultiThreadControlImpl.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.threading.nested; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.Threading; +import org.apache.beehive.controls.api.bean.ThreadingPolicy; + +import java.util.Date; + +/** + * An impl of NestedMultiThreadControl. + *

    + * Test objective: doRead and doSet on same instance should not + * inter-lock each other when invoked by different thread. + */ +@ControlImplementation +@Threading(ThreadingPolicy.MULTI_THREADED) +public class NestedMultiThreadControlImpl implements NestedMultiThreadControl, java.io.Serializable { + public final static int LOOPS = 20; + private long count = 0; + + public long doRead() { + return count; + } + + public void doSet() { + for (int i = 0; i < LOOPS; i++) { + try { + Thread.sleep(1); + } + catch (InterruptedException e) { + } + Date now = new Date(); + count = now.getTime(); + } + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/nested/NestedSThreadControl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/nested/NestedSThreadControl.java new file mode 100644 index 0000000..12a0a15 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/nested/NestedSThreadControl.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.threading.nested; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +/** + * A control interface with one methods declared. + */ +@ControlInterface +public interface NestedSThreadControl { + public int doSlowIncrement(boolean isStopper); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/nested/NestedSThreadControlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/nested/NestedSThreadControlImpl.java new file mode 100644 index 0000000..b36081c --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/nested/NestedSThreadControlImpl.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.threading.nested; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.Threading; +import org.apache.beehive.controls.api.bean.ThreadingPolicy; + +/** + * An impl of NestedSThreadControl. + * If this impl is single-threaded, a thread could never stop the loop started by another thread. + */ +@ControlImplementation +@Threading(ThreadingPolicy.SINGLE_THREADED) +public class NestedSThreadControlImpl implements NestedSThreadControl, java.io.Serializable { + private boolean marker = false; + private int count = 0; + + public int doSlowIncrement(boolean isStopper) { + + if (isStopper) { + marker = false; + return count; + } + else { + marker = true; + while (marker) { + count++; + try { + Thread.currentThread().sleep(200); + } + catch (InterruptedException e) { + e.printStackTrace(); + } + } + return count; + } + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/nested/NestedSingleThreadControl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/nested/NestedSingleThreadControl.java new file mode 100644 index 0000000..185ec44 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/nested/NestedSingleThreadControl.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.threading.nested; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +/** + * A control interface with two methods declared. + * This control interface is designed to a nested control and + * test control threading. + */ + +@ControlInterface +public interface NestedSingleThreadControl { + + public long doRead(); + + public void doSet(); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/nested/NestedSingleThreadControlImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/nested/NestedSingleThreadControlImpl.java new file mode 100644 index 0000000..e283164 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/threading/nested/NestedSingleThreadControlImpl.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.threading.nested; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.Threading; +import org.apache.beehive.controls.api.bean.ThreadingPolicy; + +import java.util.Date; + +/** + * An impl of NestedHelloControl. + * By default, control impl is single thread. + *

    + * Test objective: doRead and doSet on same instance should + * inter-lock each other when invoked by different thread. + */ +@ControlImplementation +@Threading(ThreadingPolicy.SINGLE_THREADED) +public class NestedSingleThreadControlImpl + implements NestedSingleThreadControl, java.io.Serializable { + public final static int LOOPS = 50; + private long count = 0; + + public long doRead() { + return count; + } + + public void doSet() { + for (int i = 0; i < LOOPS; i++) { + try { + Thread.sleep(1); + } + catch (InterruptedException e) { + } + Date now = new Date(); + count = now.getTime(); + } + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/versioning/Hello.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/versioning/Hello.java new file mode 100644 index 0000000..39c65b2 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/versioning/Hello.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.versioning; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.properties.PropertySet; +import org.apache.beehive.controls.api.versioning.Version; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@ControlInterface +@Version(major = 2, minor = 1) +public interface Hello { + // + // A simple enumerated type used to customize the greeting by gender + // + public enum GenderType { + NEUTRAL, MALE, FEMALE + } + + public @interface Gender { + GenderType value(); + } + + /** + * Declare a simple PropertySet, that allows the salutation used by the custom + * control to be customized. + */ + @PropertySet + @Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD}) + @Retention(RetentionPolicy.RUNTIME) + public @interface Greeting { + String salutation() default "Hello"; + + Gender gender() default @Gender(GenderType.NEUTRAL); + } + + java.lang.String hello(java.lang.String name); + + java.lang.String lastVisitor(); + + int visitorCount(); +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/versioning/HelloImpl.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/versioning/HelloImpl.java new file mode 100644 index 0000000..c3692f8 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/versioning/HelloImpl.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.versioning; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.Extensible; +import org.apache.beehive.controls.api.versioning.VersionSupported; + +import java.lang.reflect.Method; + +@ControlImplementation +@VersionSupported(major = 2) +public class HelloImpl implements Hello, Extensible, java.io.Serializable { + public String _lastVisitor = ""; + int _visitorCount = 0; + + public String hello(String name) { + _lastVisitor = name; + _visitorCount++; + return "Hello, " + name; + } + + public String lastVisitor() { + return _lastVisitor; + } + + public int visitorCount() { + return _visitorCount; + } + + /** + * Implements the Extensible.invoke interface when a JCX-declared method is called + */ + public Object invoke(Method method, Object [] args) { + // + // To Be Implemented + // + return null; + } +} diff --git a/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/versioning/SubHello.java b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/versioning/SubHello.java new file mode 100644 index 0000000..3f2cf59 --- /dev/null +++ b/controls/test/src/junit-controls/org/apache/beehive/controls/test/controls/versioning/SubHello.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.controls.versioning; + +import org.apache.beehive.controls.api.bean.ControlExtension; +import org.apache.beehive.controls.api.versioning.VersionRequired; + +/** + * A control extension with VersionRequired annotation + */ +@ControlExtension +@VersionRequired(major = 1, minor = 1) +public interface SubHello extends Hello { +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/ComplexLifecycleTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/ComplexLifecycleTest.java new file mode 100644 index 0000000..3d166cb --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/ComplexLifecycleTest.java @@ -0,0 +1,93 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + $Header:$ +*/ +package org.apache.beehive.controls.test.junit; + +import java.util.List; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.api.context.ControlContainerContext; +import org.apache.beehive.controls.test.controls.lifecycle.ControlLifecycle; + +/** + * + */ +public class ComplexLifecycleTest + extends ControlTestCase { + + private boolean _beginContext; + private boolean _endContext; + + @Control + private ControlLifecycle _lifecycleControl; + + public void setUp() { + /* intentionally, this does not call super */ + } + + public void tearDown() { + /* intentionally, this does not call super */ + } + + public void testLifecycle() { + /* startup */ + getControlContainerContextManager().beginContext(); + assertTrue(_beginContext); + + initializeControls(); + + /* test */ + assertNotNull(_lifecycleControl); + assertNotNull(_lifecycleControl.getTheControlBeanContext()); + assertNotNull(_lifecycleControl.getTheResourceContext()); + + //System.out.println(_lifecycleControl.echo("foo")); + List events = _lifecycleControl.getLifecycleEvents(); + assertEquals(2, events.size()); + assertEquals("onCreate", events.get(0)); + assertEquals("onAcquire", events.get(1)); + + _lifecycleControl.clearLifecycleEvents(); + + _lifecycleControl.echo("bar"); + events = _lifecycleControl.getLifecycleEvents(); + assertEquals(0, events.size()); + + /* teardown */ + getControlContainerContextManager().endContext(); + assertTrue(_endContext); + } + + protected ControlContainerContext initializeControlContainerContext() { + return new LifecycleTestControlContainerContext(); + } + + class LifecycleTestControlContainerContext + extends org.apache.beehive.controls.runtime.bean.ControlContainerContext { + + public void beginContext() { + super.beginContext(); + _beginContext = true; + } + + public void endContext() { + super.endContext(); + _endContext = true; + } + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/ContextEventTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/ContextEventTest.java new file mode 100644 index 0000000..826c8c5 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/ContextEventTest.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.test.controls.contextevent.BeanContextRecorderBean; + +import java.beans.Beans; + +/** + * A TestCase that tests control's context event by listening to and recording controls' + * context event. + * All tests on controls instantiated declaratively are deactivated until this feature is supported. + *

    + * There are two sources of context events: ControlBeanContext and ResourceContext. + * ResourceContext is unavaliable for Java test by default. + */ +public class ContextEventTest extends ControlTestCase { + + /** + * A control that listens to and records context events in its impl + */ + @Control + private BeanContextRecorderBean myRecorder; + + /** + * Tests control impl listening to context events. + * The control is instantiated by declaration + */ + public void testRecordedByImplDeclaration() throws Exception { + assertNotNull(myRecorder); + assertEquals("initonCreate", myRecorder.getRecord()); + } + + /** + * Tests control impl listening to its context events. + * The control is instantiated programmatically + */ + public void testRecordedByImplProgram() throws Exception { + BeanContextRecorderBean recorderbean = (BeanContextRecorderBean) Beans.instantiate( + Thread.currentThread().getContextClassLoader(), + "org.apache.beehive.controls.test.controls.contextevent.BeanContextRecorderBean"); + + assertNotNull(recorderbean); + assertEquals("initonCreate", recorderbean.getRecord()); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/ControlBeanContextChildSupportTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/ControlBeanContextChildSupportTest.java new file mode 100755 index 0000000..1949269 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/ControlBeanContextChildSupportTest.java @@ -0,0 +1,230 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit; + +import org.apache.beehive.controls.test.controls.beancontextchild.BeanChildPeer; +import org.apache.beehive.controls.test.controls.beancontextchild.DummyBeanContext; +import org.apache.beehive.controls.test.controls.beancontextchild.ChangeListener; +import org.apache.beehive.controls.test.controls.beancontextchild.AlwaysVetoListener; +import org.apache.beehive.controls.runtime.webcontext.ControlBeanContextChildSupport; +import junit.framework.TestCase; + +import java.beans.beancontext.BeanContext; +import java.beans.PropertyVetoException; +import java.beans.PropertyChangeEvent; + +/** + * Junit tests for the ControlBeanContextChildSupport class. + */ +public class ControlBeanContextChildSupportTest extends TestCase { + + /** + * Create a new ControlBeanContextChildSupport. + */ + public void testCreate() { + ControlBeanContextChildSupport _cbcChildSupport = new ControlBeanContextChildSupport(); + assertNotNull(_cbcChildSupport); + } + + /** + * Create a new ControlBeanContextChildSupport instance with a bean context child peer. + */ + public void testCreateWithPeer() { + ControlBeanContextChildSupport cbcChildSupport = new ControlBeanContextChildSupport(new BeanChildPeer()); + assertNotNull(cbcChildSupport); + } + + /** + * Create a new ControlBeanContextChildSupport instance and set + * the bean context with no listeners registered. + */ + public void testSetBeanContext_NoListeners() { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextChildSupport cbcChildSupport = getContext(); + assertNotNull(cbcChildSupport); + + BeanContext bc = new DummyBeanContext(); + + try { + cbcChildSupport.setBeanContext(bc); + } catch (PropertyVetoException pve) { + fail("Unexpected PropertyVetoException:" + pve.toString()); + } + + assertEquals(bc, cbcChildSupport.getBeanContext()); + } + + /** + * Test setting a bean context on a child which has a peer defined. + * The main difference here is that the peer should be set as the + * event source for any PropertyChangeEvents/VetoableChangeEvents thrown. + */ + public void testSetBeanContext_PropertyChangeListener_Peer() { + BeanChildPeer bcp = new BeanChildPeer(); + ControlBeanContextChildSupport cbcChildSupport = new org.apache.beehive.controls.runtime.webcontext.ControlBeanContextChildSupport(bcp); + ChangeListener cl1 = new ChangeListener(); + + cbcChildSupport.addPropertyChangeListener("beanContext", cl1); + BeanContext bc = new DummyBeanContext(); + + // change beancontext value from null to bc + try { + cbcChildSupport.setBeanContext(bc); + } catch (PropertyVetoException pve) { + fail("Unexpected PropertyVetoException:" + pve.toString()); + } + + PropertyChangeEvent[] evts1 = cl1.getEvents(); + assertEquals(1, evts1.length); + assertNull(evts1[0].getOldValue()); + assertEquals(bc, evts1[0].getNewValue()); + assertEquals("beanContext", evts1[0].getPropertyName()); + assertEquals(bcp, evts1[0].getSource()); + } + + /** + * Register 2 Propertychange listeners, set the bean context and verify + * that the proper PropertyChangeEvents were generated. Attempt to + * set the BeanContext to the same value, verify that no events were + * generated (noop). + */ + public void testSetBeanContext_PropertyChangeListeners() { + ControlBeanContextChildSupport cbcChildSupport = getContext(); + assertNotNull(cbcChildSupport); + + ChangeListener cl1 = new ChangeListener(); + ChangeListener cl2 = new ChangeListener(); + + cbcChildSupport.addPropertyChangeListener("beanContext", cl1); + cbcChildSupport.addPropertyChangeListener("beanContext", cl2); + BeanContext bc = new DummyBeanContext(); + + // change beancontext value from null to bc + try { + cbcChildSupport.setBeanContext(bc); + } catch (PropertyVetoException pve) { + fail("Unexpected PropertyVetoException:" + pve.toString()); + } + + PropertyChangeEvent[] evts1 = cl1.getEvents(); + assertEquals(1, evts1.length); + assertNull(evts1[0].getOldValue()); + assertEquals(bc, evts1[0].getNewValue()); + assertEquals("beanContext", evts1[0].getPropertyName()); + assertEquals(cbcChildSupport, evts1[0].getSource()); + + PropertyChangeEvent[] evts2 = cl2.getEvents(); + assertEquals(1, evts2.length); + assertNull(evts2[0].getOldValue()); + assertEquals(bc, evts2[0].getNewValue()); + assertEquals("beanContext", evts2[0].getPropertyName()); + assertEquals(cbcChildSupport, evts2[0].getSource()); + + + // this should be a noop event-wise, setBeanContext just returns + // if beancontext is being set to same value. + cl1.reset(); + cl2.reset(); + try { + cbcChildSupport.setBeanContext(bc); + } catch (PropertyVetoException pve) { + fail("Unexpected PropertyVetoException:" + pve.toString()); + } + + evts1 = cl1.getEvents(); + assertEquals(0, evts1.length); + evts2 = cl2.getEvents(); + assertEquals(0, evts2.length); + + cbcChildSupport.removePropertyChangeListener("beanContext", cl1); + cbcChildSupport.removePropertyChangeListener("beanContext", cl2); + } + + /** + * Test a veto of setting the bean context. + */ + public void testSetBeanContext_VetoListeners() { + ControlBeanContextChildSupport cbcChildSupport = getContext(); + assertNotNull(cbcChildSupport); + + ChangeListener cl = new ChangeListener(); + AlwaysVetoListener avl = new AlwaysVetoListener(); + cbcChildSupport.addPropertyChangeListener("beanContext", cl); + cbcChildSupport.addVetoableChangeListener("beanContext", avl); + BeanContext bc = new DummyBeanContext(); + + // change beancontext value from null to bc + try { + cbcChildSupport.setBeanContext(bc); + } catch (PropertyVetoException pve) { + assertEquals("beanContext", pve.getPropertyChangeEvent().getPropertyName()); + assertEquals(bc, pve.getPropertyChangeEvent().getNewValue()); + assertNull(pve.getPropertyChangeEvent().getOldValue()); + + // should never have fired a property change event + PropertyChangeEvent[] evts1 = cl.getEvents(); + assertEquals(0, evts1.length); + return; + } + fail("Expected PropertyVetoException!!"); + } + + + /** + * A veto listener is only allowed to veto a beanContext change once, + * this is enforced by the setBeanContext() method of the CBCCS. + */ + public void testSetBeanContext_VetoOverride() { + ControlBeanContextChildSupport cbcChildSupport = getContext(); + boolean caughtVeto = false; + assertNotNull(cbcChildSupport); + + AlwaysVetoListener avl = new AlwaysVetoListener(); + cbcChildSupport.addVetoableChangeListener("beanContext", avl); + BeanContext bc = new DummyBeanContext(); + + // change beancontext value from null to bc + try { + cbcChildSupport.setBeanContext(bc); + } catch (PropertyVetoException pve) { + assertEquals("beanContext", pve.getPropertyChangeEvent().getPropertyName()); + assertEquals(bc, pve.getPropertyChangeEvent().getNewValue()); + assertNull(pve.getPropertyChangeEvent().getOldValue()); + caughtVeto = true; + } + + assertTrue(caughtVeto); + + // try again this should force override of veto + try { + cbcChildSupport.setBeanContext(bc); + } catch (PropertyVetoException pve) { + fail("Unexpected PropertyVetoException:" + pve.toString()); + } + + assertEquals(bc, cbcChildSupport.getBeanContext()); + } + + /** + * Abstracts the type of BeanContextSupport object being created. + */ + protected ControlBeanContextChildSupport getContext() { + return new ControlBeanContextChildSupport(); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/ControlBeanContextServicesSupportTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/ControlBeanContextServicesSupportTest.java new file mode 100644 index 0000000..2114791 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/ControlBeanContextServicesSupportTest.java @@ -0,0 +1,788 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.test.junit; + +import java.beans.PropertyVetoException; +import java.beans.beancontext.BeanContextServiceAvailableEvent; +import java.beans.beancontext.BeanContextServiceRevokedEvent; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.EventObject; +import java.util.Iterator; +import java.util.TooManyListenersException; + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport; +import org.apache.beehive.controls.test.controls.beancontextservices.BCChild; +import org.apache.beehive.controls.test.controls.beancontextservices.BCChildNoServiceRelease; +import org.apache.beehive.controls.test.controls.beancontextservices.ServiceListener; +import org.apache.beehive.controls.test.controls.beancontextservices.TestBCServiceProviderImpl; +import org.apache.beehive.controls.test.controls.beancontextservices.TestService; +import org.apache.beehive.controls.test.controls.beancontextservices.TestNonSerializableBCServiceProviderImpl; +import org.apache.beehive.controls.test.controls.beancontextservices.TestNonSerializableService; +import org.apache.beehive.controls.test.controls.beancontextservices.NonSerializableServiceListener; +import org.apache.beehive.controls.test.controls.beancontextservices.ServicesBeanPeer; + +/** + */ +public class ControlBeanContextServicesSupportTest extends ControlBeanContextSupportTest { + + /** + * Create a new ControlBeanContextServicesSupport. + */ + public void testCreateCBCSS() { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport _cbcsSupport = new org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport(); + assertNotNull(_cbcsSupport); + } + + /** + * Create a new ControlBeanContextServicesSupport instance with a bean delegate. + */ + public void testCreateCBCSSWithDelegate() { + ControlBeanContextServicesSupport _cbcsSupport = + new ControlBeanContextServicesSupport(new ServicesBeanPeer()); + assertNotNull(_cbcsSupport); + } + + /** + * Add a service / make sure it was registered. + */ + public void testAddService() { + ControlBeanContextServicesSupport cbcss = getContext(); + TestBCServiceProviderImpl sp = new TestBCServiceProviderImpl(); + cbcss.addService(TestService.class, sp); + assertTrue(cbcss.hasService(TestService.class)); + } + + /** + * Add a service which already exists in ServicesSupport. + */ + public void testAddDuplicateService() { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport cbcss = getContext(); + TestBCServiceProviderImpl sp = new TestBCServiceProviderImpl(); + assertTrue(cbcss.addService(TestService.class, sp)); + assertTrue(cbcss.hasService(TestService.class)); + + assertFalse(cbcss.addService(TestService.class, sp)); + } + + /** + * Add a service with a service listener registered. + */ + public void testAddServiceWithListener() { + ControlBeanContextServicesSupport cbcss = getContext(); + ServiceListener sl = new ServiceListener(); + cbcss.addBeanContextServicesListener(sl); + + TestBCServiceProviderImpl sp = new TestBCServiceProviderImpl(); + assertTrue(cbcss.addService(TestService.class, sp)); + + EventObject[] evts = sl.getEvents(); + assertEquals(1, evts.length); + assertTrue(evts[0] instanceof BeanContextServiceAvailableEvent); + assertTrue(((BeanContextServiceAvailableEvent) evts[0]).getServiceClass().equals(TestService.class)); + assertTrue(((BeanContextServiceAvailableEvent) evts[0]).getSourceAsBeanContextServices().equals(cbcss)); + } + + /** + * Add a service to a beancontextservices which has a peer, verify the event source is the peer. + */ + public void testAddServiceWithListener_Peer() { + ServicesBeanPeer sbp = new ServicesBeanPeer(); + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport cbcss = new org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport(sbp); + ServiceListener sl = new ServiceListener(); + cbcss.addBeanContextServicesListener(sl); + + TestBCServiceProviderImpl sp = new TestBCServiceProviderImpl(); + assertTrue(cbcss.addService(TestService.class, sp)); + + EventObject[] evts = sl.getEvents(); + assertEquals(1, evts.length); + assertTrue(evts[0] instanceof BeanContextServiceAvailableEvent); + assertTrue(((BeanContextServiceAvailableEvent) evts[0]).getServiceClass().equals(TestService.class)); + assertEquals(sbp, evts[0].getSource()); + } + + /** + * Verify that a services listener can be removed. + */ + public void testRemoveServiceListenerTest() { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport cbcss = getContext(); + ServiceListener sl = new ServiceListener(); + cbcss.addBeanContextServicesListener(sl); + cbcss.removeBeanContextServicesListener(sl); + + TestBCServiceProviderImpl service1 = new TestBCServiceProviderImpl(); + assertTrue(cbcss.addService(TestService.class, service1)); + + EventObject[] evts = sl.getEvents(); + assertEquals(0, evts.length); + } + + /** + * Test the revocation of a service which has no references to it. + */ + public void testRevokeService_NoReferences() { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport cbcss = getContext(); + + TestBCServiceProviderImpl service1 = new TestBCServiceProviderImpl(); + assertTrue(cbcss.addService(TestService.class, service1)); + + ServiceListener sl = new ServiceListener(); + cbcss.addBeanContextServicesListener(sl); + cbcss.revokeService(TestService.class, service1, false); + + // verify that the service was removed and that the Revoked event was fired and looks correct. + assertFalse(cbcss.hasService(TestService.class)); + + EventObject[] evts = sl.getEvents(); + assertEquals(1, evts.length); + assertTrue(evts[0] instanceof BeanContextServiceRevokedEvent); + assertTrue(((BeanContextServiceRevokedEvent) evts[0]).getSourceAsBeanContextServices().equals(cbcss)); + assertFalse(((BeanContextServiceRevokedEvent) evts[0]).isCurrentServiceInvalidNow()); + assertTrue(((BeanContextServiceRevokedEvent) evts[0]).isServiceClass(TestService.class)); + } + + /** + * Test the revocation of a service when the when the cbcss has a peer. + */ + public void testRevokeService_NoReferences_Peer() { + ServicesBeanPeer sbp = new ServicesBeanPeer(); + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport cbcss = new org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport(sbp); + + TestBCServiceProviderImpl service1 = new TestBCServiceProviderImpl(); + assertTrue(cbcss.addService(TestService.class, service1)); + + ServiceListener sl = new ServiceListener(); + cbcss.addBeanContextServicesListener(sl); + cbcss.revokeService(TestService.class, service1, false); + + // verify that the service was removed and that the Revoked event was fired and looks correct. + assertFalse(cbcss.hasService(TestService.class)); + + EventObject[] evts = sl.getEvents(); + assertEquals(1, evts.length); + assertTrue(evts[0] instanceof BeanContextServiceRevokedEvent); + assertTrue(((BeanContextServiceRevokedEvent) evts[0]).getSourceAsBeanContextServices().equals(sbp)); + assertFalse(((BeanContextServiceRevokedEvent) evts[0]).isCurrentServiceInvalidNow()); + } + + /** + * Test the immediate revocation of a service which has no references to it. + */ + public void testRevokeServiceNOW_NoReferences() { + ControlBeanContextServicesSupport cbcss = getContext(); + + TestBCServiceProviderImpl service1 = new TestBCServiceProviderImpl(); + assertTrue(cbcss.addService(TestService.class, service1)); + + ServiceListener sl = new ServiceListener(); + cbcss.addBeanContextServicesListener(sl); + cbcss.revokeService(TestService.class, service1, true); + + // verify that the service was removed and that the Revoked event was fired and looks correct. + assertFalse(cbcss.hasService(TestService.class)); + + EventObject[] evts = sl.getEvents(); + assertEquals(1, evts.length); + assertTrue(evts[0] instanceof BeanContextServiceRevokedEvent); + assertTrue(((BeanContextServiceRevokedEvent) evts[0]).getSourceAsBeanContextServices().equals(cbcss)); + assertTrue(((BeanContextServiceRevokedEvent) evts[0]).isCurrentServiceInvalidNow()); + assertTrue(((BeanContextServiceRevokedEvent) evts[0]).isServiceClass(TestService.class)); + } + + /** + * Test iterator over service classes. + */ + public void testGetCurrentServiceClasses() { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport cbcss = getContext(); + TestBCServiceProviderImpl service1 = new TestBCServiceProviderImpl(); + assertTrue(cbcss.addService(TestService.class, service1)); + + Iterator i = cbcss.getCurrentServiceClasses(); + assertTrue(i.hasNext()); + assertEquals(TestService.class, i.next()); + assertFalse(i.hasNext()); + } + + /** + * Test iterator over service classes, where the service has been revoked, + * expected behavior in this case is not to include service class in iterator. + */ + public void testGetCurrentServiceClasses_RevokedService() { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport cbcss = getContext(); + TestBCServiceProviderImpl service1 = new TestBCServiceProviderImpl(); + assertTrue(cbcss.addService(TestService.class, service1)); + cbcss.revokeService(TestService.class, service1, true); + + Iterator i = cbcss.getCurrentServiceClasses(); + assertFalse(i.hasNext()); + } + + /** + * Test for the hasService() for api test completness. + */ + public void testHasService() { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport cbcss = getContext(); + TestBCServiceProviderImpl service1 = new TestBCServiceProviderImpl(); + assertTrue(cbcss.addService(TestService.class, service1)); + assertTrue(cbcss.hasService(TestService.class)); + } + + /** + * Test for getCurrentServicesSelectors() api. + */ + public void testGetCurrentServiceSelectors() { + ControlBeanContextServicesSupport cbcss = getContext(); + TestBCServiceProviderImpl service1 = new TestBCServiceProviderImpl(); + assertTrue(cbcss.addService(TestService.class, service1)); + Iterator i = cbcss.getCurrentServiceSelectors(TestService.class); + assertEquals("ONE", i.next()); + assertEquals("TWO", i.next()); + assertEquals("THREE", i.next()); + assertFalse(i.hasNext()); + } + + // + // Service References + // + + /** + * Attempt to get a service with an invalid child. + */ + public void testGetService_IllegalChild() { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport cbcss = getContext(); + TestBCServiceProviderImpl service1 = new TestBCServiceProviderImpl(); + assertTrue(cbcss.addService(TestService.class, service1)); + + try { + cbcss.getService(cbcss, this, TestService.class, null, null); + } + catch (IllegalArgumentException iae) { + return; + } + catch (TooManyListenersException e) { + fail("UnExpected TooManyListenersException thrown!! " + e); + } + fail("Expected IllegalArgumentException to be throw!!"); + } + + /** + * Add a child, the child is registered as a listener, when the + * TestService service is registered the child should get a reference + * to it. + */ + public void testGetService() { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport cbcss = getContext(); + BCChild child = new BCChild(); + assertTrue(cbcss.add(child)); + cbcss.addBeanContextServicesListener(child); + + TestBCServiceProviderImpl service1 = new TestBCServiceProviderImpl(); + assertTrue(cbcss.addService(TestService.class, service1)); + + // test the following.... + // the child obtained a reference to the service + assertEquals(1, child.getRefCount()); + assertEquals(1, service1.getRefCount()); + } + + /** + * Verify that the release of a service worked. + */ + public void testReleaseService() { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport cbcss = getContext(); + BCChild child = new BCChild(); + assertTrue(cbcss.add(child)); + cbcss.addBeanContextServicesListener(child); + + TestBCServiceProviderImpl service1 = new TestBCServiceProviderImpl(); + assertTrue(cbcss.addService(TestService.class, service1)); + + assertEquals(1, child.getRefCount()); + assertEquals(1, service1.getRefCount()); + + // revoke the service -- triggers release call from child + cbcss.revokeService(TestService.class, service1, false); + assertEquals(0, child.getRefCount()); + assertEquals(0, service1.getRefCount()); + + // since no references should exist this call will return false + assertFalse(cbcss.hasService(TestService.class)); + } + + /** + * Revoke a service which has a reference which is not released on the revoke. + */ + public void testRevokeOnReferencedService() { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport cbcss = getContext(); + BCChildNoServiceRelease child = new BCChildNoServiceRelease(); + assertTrue(cbcss.add(child)); + cbcss.addBeanContextServicesListener(child); + + TestBCServiceProviderImpl service1 = new TestBCServiceProviderImpl(); + assertTrue(cbcss.addService(TestService.class, service1)); + + assertEquals(1, child.getRefCount()); + assertEquals(1, service1.getRefCount()); + + // revoke the service -- triggers release call from child + cbcss.revokeService(TestService.class, service1, false); + assertEquals(1, child.getRefCount()); + assertEquals(1, service1.getRefCount()); + assertFalse(cbcss.hasService(TestService.class)); + } + + /** + * Forcibly revoke a service which has a reference, + * verify that it no longer exists. + */ + public void testForceRevokeOnReferencedService() { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport cbcss = getContext(); + BCChildNoServiceRelease child = new BCChildNoServiceRelease(); + assertTrue(cbcss.add(child)); + cbcss.addBeanContextServicesListener(child); + + TestBCServiceProviderImpl service1 = new TestBCServiceProviderImpl(); + assertTrue(cbcss.addService(TestService.class, service1)); + + assertEquals(1, child.getRefCount()); + assertEquals(1, service1.getRefCount()); + + // remove the listener so the child doesn't get two revoked events + cbcss.removeBeanContextServicesListener(child); + cbcss.revokeService(TestService.class, service1, true); + assertEquals(0, child.getRefCount()); + + // service ref count is not updated since this is a forced + // revocation it is just removed from the cbcss + assertEquals(1, service1.getRefCount()); + assertFalse(cbcss.hasService(TestService.class)); + } + + /** + * Create a cbcss which has a child cbcss which contains a bean context child + * who invokes getService() when a new service is registered with th parent context. + */ + public void testGetDelegatedService() { + + // create the parent + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport parent_cbcss = getContext(); + + // create a child cbcss + ControlBeanContextServicesSupport child_cbcss = getContext(); + assertTrue(parent_cbcss.add(child_cbcss)); + + // add a bcchild which will reqest the service as soon as its added to the top-most parent + BCChild child = new BCChild(); + assertTrue(child_cbcss.add(child)); + + parent_cbcss.addBeanContextServicesListener(child); + + // add the service + TestBCServiceProviderImpl service1 = new TestBCServiceProviderImpl(); + assertTrue(parent_cbcss.addService(TestService.class, service1)); + + // verify the service has been aquired by the child + assertEquals(1, child.getRefCount()); + assertEquals(1, service1.getRefCount()); + + // verify the expected behavior in the child cbcss + assertTrue(child_cbcss.hasService(TestService.class)); + } + + /** + * Building on the previous test, aquire the service then release it. + */ + public void testRevokeDelegateService() { + + // create the parent + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport parent_cbcss = getContext(); + + // create a child cbcss + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport child_cbcss = getContext(); + assertTrue(parent_cbcss.add(child_cbcss)); + + // add a bcchild which will reqest the service as soon as its added to the top-most parent + BCChild child = new BCChild(); + assertTrue(child_cbcss.add(child)); + + parent_cbcss.addBeanContextServicesListener(child); + + // add the service + TestBCServiceProviderImpl service1 = new TestBCServiceProviderImpl(); + assertTrue(parent_cbcss.addService(TestService.class, service1)); + + // remove the listener so we don't get invoked twice to remove + // the service + parent_cbcss.removeBeanContextServicesListener(child); + + // revoke the service, this will cause the child holding a reference + // to the service to release it. + parent_cbcss.revokeService(TestService.class, service1, false); + + // verify the service has been released by the child + assertEquals(0, child.getRefCount()); + assertEquals(0, service1.getRefCount()); + + // verify the expected behavior in the child cbcss + assertFalse(child_cbcss.hasService(TestService.class)); + } + + /** + * Test the forcible revocation of a delegated service. + */ + public void testForcedRevokeOfDelegatedService() { + + // create the parent + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport parent_cbcss = getContext(); + + // create a child cbcss + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport child_cbcss = getContext(); + assertTrue(parent_cbcss.add(child_cbcss)); + + // add a bcchild which will reqest the service as soon as its added to the top-most parent + BCChildNoServiceRelease child = new BCChildNoServiceRelease(); + assertTrue(child_cbcss.add(child)); + + parent_cbcss.addBeanContextServicesListener(child); + + // add the service + TestBCServiceProviderImpl service1 = new TestBCServiceProviderImpl(); + assertTrue(parent_cbcss.addService(TestService.class, service1)); + + // remove the listener so we don't get invoked twice to remove + // the service + parent_cbcss.removeBeanContextServicesListener(child); + + // revoke the service, this will cause the child holding a reference + // to the service to release it. + parent_cbcss.revokeService(TestService.class, service1, true); + + // verify the service has been released by the child + assertEquals(0, child.getRefCount()); + + // service ref is not decremented in this case since the service gets dereferenced + assertEquals(1, service1.getRefCount()); + + // verify the expected behavior in the child cbcss + assertFalse(child_cbcss.hasService(TestService.class)); + } + + /** + * Cause a service to be implicitly revoked (for a child) by changing the parent + * of a child which contains a reference to that service. + */ + public void testImplicitServiceRevoke() { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport cbcss = getContext(); + + // add a bcchild which will reqest the service as soon as its added + BCChild child = new BCChild(); + assertTrue(cbcss.add(child)); + cbcss.addBeanContextServicesListener(child); + + // add the service + TestBCServiceProviderImpl service1 = new TestBCServiceProviderImpl(); + assertTrue(cbcss.addService(TestService.class, service1)); + + assertEquals(1, child.getRefCount()); + assertEquals(1, service1.getRefCount()); + cbcss.removeBeanContextServicesListener(child); + + try { + child.setBeanContext(null); + } + catch (PropertyVetoException e) { + fail("Unexpected ProperyVetoException!!"); + } + + assertEquals(0, child.getRefCount()); + assertEquals(0, service1.getRefCount()); + assertTrue(cbcss.hasService(TestService.class)); + } + + /** + * Test reparenting a cbcss which is a service provider to a child that + * has a reference to the service. The expected behavior here is that + * the child should still have a reference to the service since the + * service was not a delegated service. + */ + public void testReparentChild() { + // create the parent + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport parent_cbcss = getContext(); + + // create a child cbcss + ControlBeanContextServicesSupport child_cbcss = getContext(); + assertTrue(parent_cbcss.add(child_cbcss)); + + // add a bcchild which will reqest the service as soon as its added to the top-most parent + BCChild child = new BCChild(); + assertTrue(child_cbcss.add(child)); + + child_cbcss.addBeanContextServicesListener(child); + + // add the service + TestBCServiceProviderImpl service1 = new TestBCServiceProviderImpl(); + assertTrue(child_cbcss.addService(TestService.class, service1)); + + // remove the listener + child_cbcss.removeBeanContextServicesListener(child); + assertEquals(1, child.getRefCount()); + assertEquals(1, service1.getRefCount()); + + try { + child_cbcss.setBeanContext(null); + } + catch (PropertyVetoException e) { + fail("Unexpected ProperyVetoException!!!"); + } + + // verify that.... + + // the service is still available from the re-parented cbcss + assertTrue(child_cbcss.hasService(TestService.class)); + + // the child has been notified of the revocation + assertEquals(1, child.getRefCount()); + + // the service's refcount should still be the same + assertEquals(1, service1.getRefCount()); + } + + /** + * Cause a delegated service to be implicitly revoked (for child which implements the + * BeanContextServices API) by changing the parent of the child which contains a reference + * to that service. + */ + public void testImplicitDelegatedServiceRevoke() { + + // create the parent + ControlBeanContextServicesSupport parent_cbcss = getContext(); + + // create a child cbcss + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport child_cbcss = getContext(); + assertTrue(parent_cbcss.add(child_cbcss)); + + // add a bcchild which will reqest the service as soon as its added to the top-most parent + BCChild child = new BCChild(); + assertTrue(child_cbcss.add(child)); + + parent_cbcss.addBeanContextServicesListener(child); + + // add the service + TestBCServiceProviderImpl service1 = new TestBCServiceProviderImpl(); + assertTrue(parent_cbcss.addService(TestService.class, service1)); + + // remove the listener so we don't get invoked twice to remove + // the service + parent_cbcss.removeBeanContextServicesListener(child); + assertEquals(1, child.getRefCount()); + assertEquals(1, service1.getRefCount()); + + try { + child_cbcss.setBeanContext(null); + } + catch (PropertyVetoException e) { + fail("Unexpected ProperyVetoException!!!"); + } + + // verify that.... + + // the service is no longer available from the re-parented cbcss + assertFalse(child_cbcss.hasService(TestService.class)); + + // the child has been notified of the revocation + assertEquals(0, child.getRefCount()); + + // the service's refcount does not get decremented since + // this was an immediate revoke (seems odd but spec says it should work this way) + assertEquals(1, service1.getRefCount()); + } + + // + // Serialization tests + // + + /** + * Test the serialization of an empty ControlBeanContextServicesSupport. + */ + public void testSerializationEmptyBCS() throws IOException, ClassNotFoundException { + + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport cbcss = getContext(); + cbcss.setDesignTime(true); + + File serFile = serializeCBCSS(cbcss, "cbcss_1"); + cbcss = deserializeCBCSS(serFile); + assertTrue(cbcss.isEmpty()); + assertTrue(cbcss.isDesignTime()); + } + + /** + * Test Serialization with a service which is serializable. + */ + public void testSerializationWithService() throws IOException, ClassNotFoundException { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport cbcss = getContext(); + TestBCServiceProviderImpl service1 = new TestBCServiceProviderImpl(); + assertTrue(cbcss.addService(TestService.class, service1)); + + File serFile = serializeCBCSS(cbcss, "cbcss_2"); + cbcss = deserializeCBCSS(serFile); + assertTrue(cbcss.hasService(TestService.class)); + } + + /** + * Test serialization with a BeanContextServicesListener registered. + */ + public void testSerializationWithListeners() throws IOException, ClassNotFoundException { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport cbcss = getContext(); + ServiceListener sl = new ServiceListener(); + cbcss.addBeanContextServicesListener(sl); + + TestBCServiceProviderImpl service1 = new TestBCServiceProviderImpl(); + assertTrue(cbcss.addService(TestService.class, service1)); + + File serFile = serializeCBCSS(cbcss, "cbcss_3"); + cbcss = deserializeCBCSS(serFile); + + assertTrue(cbcss.hasService(TestService.class)); + // todo: it would be nice to be able to verify the listener's state + // the current implementation does not notify listeners that a service + // as been deserialized. + } + + /** + * Test serialization with a non-serializable BeanContextServicesListener registered. + */ + public void testSerializationWithNonSerializableListeners() throws IOException, ClassNotFoundException { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport cbcss = getContext(); + NonSerializableServiceListener sl = new NonSerializableServiceListener(); + cbcss.addBeanContextServicesListener(sl); + + TestBCServiceProviderImpl service1 = new TestBCServiceProviderImpl(); + assertTrue(cbcss.addService(TestService.class, service1)); + + File serFile = serializeCBCSS(cbcss, "cbcss_3"); + cbcss = deserializeCBCSS(serFile); + + assertTrue(cbcss.hasService(TestService.class)); + // todo: it would be nice to be able to verify the listener's state + // the current implementation does not notify listeners that a service + } + + /** + * Test serailization of the CBCSS when a non-serializable service is added. + * + * @throws IOException + * @throws ClassNotFoundException + */ + public void testSerializationWithNonSerializableService() throws IOException, ClassNotFoundException { + ControlBeanContextServicesSupport cbcss = getContext(); + TestNonSerializableBCServiceProviderImpl service1 = new TestNonSerializableBCServiceProviderImpl(); + assertTrue(cbcss.addService(TestNonSerializableService.class, service1)); + + File serFile = serializeCBCSS(cbcss, "cbcss_4"); + cbcss = deserializeCBCSS(serFile); + assertFalse(cbcss.hasService(TestNonSerializableService.class)); + } + + /** + * Test serialization with a child that has a reference to a service. + */ + public void testSerialziationWithChildReference() throws IOException, ClassNotFoundException { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport cbcss = getContext(); + BCChild child = new BCChild(); + assertTrue(cbcss.add(child)); + cbcss.addBeanContextServicesListener(child); + + TestBCServiceProviderImpl service1 = new TestBCServiceProviderImpl(); + assertTrue(cbcss.addService(TestService.class, service1)); + + // the child obtained a reference to the service + assertEquals(1, child.getRefCount()); + File serFile = serializeCBCSS(cbcss, "cbcss_5"); + cbcss = deserializeCBCSS(serFile); + + // test that.... + + // the service is available after serialization + assertTrue(cbcss.hasService(TestService.class)); + + // the child doesn't contian a reference to the service + // it is the child's responsibility to release any service references it may + // have before it is serialized. + Object[] children = cbcss.toArray(); + assertEquals(1, children.length); + assertEquals(0, ((BCChild)children[0]).getRefCount()); + } + + // + // helpers + // + + protected org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport getContext() { + return new ControlBeanContextServicesSupport(); + } + + /** + * Serialize a ControlBeanContextServicesSupport instance. + * + * @param cbcss Object to serialize. + * @param serFileName Name of file to serialize to. + * @return Serialization file. + * @throws IOException + */ + private File serializeCBCSS(ControlBeanContextServicesSupport cbcss, String serFileName) throws IOException { + File serFile = File.createTempFile(serFileName, "ser"); + ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(serFile)); + oos.writeObject(cbcss); + oos.close(); + return serFile; + } + + /** + * Deserialize a ControlBeanContextServicesSupport instance. + * + * @param serFile File to deserialize from. + * @return New instance. + * @throws IOException + * @throws ClassNotFoundException + */ + private ControlBeanContextServicesSupport deserializeCBCSS(File serFile) throws IOException, ClassNotFoundException { + ObjectInputStream ois = new ObjectInputStream(new FileInputStream(serFile)); + try { + return (org.apache.beehive.controls.runtime.webcontext.ControlBeanContextServicesSupport) ois.readObject(); + } finally { + ois.close(); + serFile.delete(); + } + } + + public static Test suite() { + return new TestSuite(ControlBeanContextServicesSupportTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(ControlBeanContextServicesSupportTest.suite()); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/ControlBeanContextSupportTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/ControlBeanContextSupportTest.java new file mode 100755 index 0000000..9046a1f --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/ControlBeanContextSupportTest.java @@ -0,0 +1,911 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.test.junit; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyVetoException; +import java.beans.beancontext.BeanContextMembershipEvent; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.beehive.controls.runtime.webcontext.ControlBeanContextChildSupport; +import org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport; +import org.apache.beehive.controls.test.controls.beancontext.BeanContextProxyImpl; +import org.apache.beehive.controls.test.controls.beancontext.MembershipListener; +import org.apache.beehive.controls.test.controls.beancontext.VisibilityImpl; +import org.apache.beehive.controls.test.controls.beancontext.BeanContextPeer; +import org.apache.beehive.controls.test.controls.beancontextchild.AlwaysVetoListener; +import org.apache.beehive.controls.test.controls.beancontextchild.ChangeListener; + +/** + */ +public class ControlBeanContextSupportTest + extends ControlBeanContextChildSupportTest { + + /** + * Create a new ControlBeanContextSupport. + */ + public void testCreateCBCS() { + ControlBeanContextSupport _cbcSupport = new ControlBeanContextSupport(); + assertNotNull(_cbcSupport); + } + + /** + * Create a new ControlBeanContextChildSupport instance with a bean delegate. + */ + public void testCreateWithDelegate() { + ControlBeanContextSupport _cbcSupport = new ControlBeanContextSupport(new BeanContextPeer()); + assertNotNull(_cbcSupport); + } + + // + // Collection Api tests + // + + /** + * Test addAll() collection api. + */ + public void testAddAll() { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport cbcs = getContext(); + + try { + cbcs.addAll(Collections.EMPTY_LIST); + } + catch (UnsupportedOperationException uoe) { + return; + } + fail("Expected UnsupportedOperationException!!"); + } + + /** + * Test clear() collection api. + */ + public void testClear() { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport cbcs = getContext(); + + try { + cbcs.clear(); + } + catch (UnsupportedOperationException uoe) { + return; + } + fail("Expected UnsupportedOperationException!!"); + } + + /** + * Test removeAll() collection api. + */ + public void testRemoveAll() { + ControlBeanContextSupport cbcs = getContext(); + + try { + cbcs.removeAll(Collections.EMPTY_LIST); + } + catch (UnsupportedOperationException uoe) { + return; + } + fail("Expected UnsupportedOperationException!!"); + } + + + /** + * Test retainAll() collection api. + */ + public void testRetainAll() { + ControlBeanContextSupport cbcs = getContext(); + + try { + cbcs.retainAll(Collections.EMPTY_LIST); + } + catch (UnsupportedOperationException uoe) { + return; + } + fail("Expected UnsupportedOperationException!!"); + } + + /** + * Test contains() collection api. + */ + public void testContains() { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport cbcs = getContext(); + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextChildSupport child1 = new ControlBeanContextChildSupport(); + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextChildSupport child2 = new ControlBeanContextChildSupport(); + + assertTrue(cbcs.add(child1)); + assertTrue(cbcs.contains(child1)); + assertFalse(cbcs.contains(child2)); + } + + /** + * Test containsAll() collection api. + */ + public void testContainsAll() { + ControlBeanContextSupport cbcs = getContext(); + ControlBeanContextChildSupport child1 = new ControlBeanContextChildSupport(); + ControlBeanContextChildSupport child2 = new ControlBeanContextChildSupport(); + ControlBeanContextChildSupport child3 = new org.apache.beehive.controls.runtime.webcontext.ControlBeanContextChildSupport(); + + assertTrue(cbcs.add(child1)); + assertTrue(cbcs.add(child2)); + + ArrayList children = new ArrayList(); + children.add(child1); + children.add(child2); + assertTrue(cbcs.containsAll(children)); + + children.add(child3); + assertFalse(cbcs.containsAll(children)); + } + + /** + * Test isEmpty() collection api. + */ + public void testIsEmpty() { + ControlBeanContextSupport cbcs = getContext(); + ControlBeanContextChildSupport child = new org.apache.beehive.controls.runtime.webcontext.ControlBeanContextChildSupport(); + + assertTrue(cbcs.isEmpty()); + assertTrue(cbcs.add(child)); + assertFalse(cbcs.isEmpty()); + } + + /** + * Test interator() collection api. Iterator returned should not + * allow for removal of items. NOTE: ControlBeanContextSupport + * uses a Map to store its children so the iteration order + * is not predictable. + */ + public void testIterator() { + + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport cbcs = getContext(); + ControlBeanContextChildSupport child1 = new ControlBeanContextChildSupport(); + assertTrue(cbcs.add(child1)); + + Iterator i = cbcs.iterator(); + assertTrue(i.hasNext()); + assertEquals(child1, i.next()); + + try { + i.remove(); + } + catch (UnsupportedOperationException uoe) { + return; + } + fail("Expected UnsupportedOperationException when trying to remove item via Iterator!!"); + } + + /** + * Test size() collection api. + */ + public void testSize() { + ControlBeanContextSupport cbcs = getContext(); + assertEquals(0, cbcs.size()); + + ControlBeanContextChildSupport child = new ControlBeanContextChildSupport(); + assertTrue(cbcs.add(child)); + assertEquals(1, cbcs.size()); + } + + /** + * Test toArray() collection api. + */ + public void testToObjectArray() { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport cbcs = getContext(); + ControlBeanContextChildSupport child = new ControlBeanContextChildSupport(); + assertTrue(cbcs.add(child)); + Object[] array = cbcs.toArray(); + assertEquals(1, array.length); + assertEquals(child, array[0]); + } + + /** + * Test toArray(Object[]) collection api. + */ + public void testToObjectArray2() { + ControlBeanContextSupport cbcs = getContext(); + ControlBeanContextChildSupport child = new ControlBeanContextChildSupport(); + assertTrue(cbcs.add(child)); + Object[] array = cbcs.toArray(new Object[1]); + assertEquals(1, array.length); + assertEquals(child, array[0]); + } + + //////////////////// add() API //////////////////////////////////////////////////////////////////////////// + + /** + * Add a single child to the context, verify that all the proper events are generated. + */ + public void testAddSingleChild() { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport cbcs = getContext(); + MembershipListener ml = new MembershipListener(); + cbcs.addBeanContextMembershipListener(ml); + + ControlBeanContextChildSupport child = new ControlBeanContextChildSupport(); + ChangeListener cl = new ChangeListener(); + child.addPropertyChangeListener("beanContext", cl); + + assertTrue(cbcs.add(child)); + + // verify that.... + + // a BeanContextMembershipEvent is fired... + BeanContextMembershipEvent[] bcme = ml.getEvents(); + assertEquals(1, bcme.length); + assertTrue(bcme[0].contains(child)); + + // the child recieved a PropertyEvent that is parent was changed + PropertyChangeEvent[] pce = cl.getEvents(); + assertEquals(1, pce.length); + assertEquals("beanContext", pce[0].getPropertyName()); + assertNull(pce[0].getOldValue()); + assertEquals(cbcs, pce[0].getNewValue()); + + // that the child was added to the collection + Object[] children = cbcs.toArray(); + assertEquals(1, children.length); + assertEquals(child, children[0]); + } + + /** + * Add a single child to a BeanContext which has a peer. + */ + public void testAddSingleChild_Peer() { + BeanContextPeer bcp = new BeanContextPeer(); + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport cbcs = new org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport(bcp); + + MembershipListener ml = new MembershipListener(); + cbcs.addBeanContextMembershipListener(ml); + + ControlBeanContextChildSupport child = new ControlBeanContextChildSupport(); + assertTrue(cbcs.add(child)); + + // verify that.... + + // a BeanContextMembershipEvent is fired and the source is the peer ... + BeanContextMembershipEvent[] bcme = ml.getEvents(); + assertEquals(1, bcme.length); + assertTrue(bcme[0].contains(child)); + assertEquals(bcp, bcme[0].getSource()); + + // the nested context of the child is the peer + assertEquals(bcp, child.getBeanContext()); + + // that the child was added to the collection + Object[] children = cbcs.toArray(); + assertEquals(1, children.length); + assertEquals(child, children[0]); + } + + /** + * Add a child which implements the BeanContextProxy interface. + */ + public void testAddProxyChild() { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport cbcs = getContext(); + MembershipListener ml = new MembershipListener(); + cbcs.addBeanContextMembershipListener(ml); + + ControlBeanContextChildSupport child = new ControlBeanContextChildSupport(); + BeanContextProxyImpl proxy = new BeanContextProxyImpl(child); + ChangeListener cl = new ChangeListener(); + child.addPropertyChangeListener("beanContext", cl); + + assertTrue(cbcs.add(proxy)); + + // verify that.... + + // a BeanContextMembershipEvent is fired... + BeanContextMembershipEvent[] bcme = ml.getEvents(); + assertEquals(1, bcme.length); + assertTrue(bcme[0].contains(proxy)); + + // the child recieved a PropertyEvent that is parent was changed + PropertyChangeEvent[] pce = cl.getEvents(); + assertEquals(1, pce.length); + assertEquals("beanContext", pce[0].getPropertyName()); + assertNull(pce[0].getOldValue()); + assertEquals(cbcs, pce[0].getNewValue()); + + // test that the proxy as well as the bcc it references were added to the bean context + // as children -- may seem a bit odd but the spec says it should work this way! + Object[] children = cbcs.toArray(); + assertEquals(2, children.length); + } + + /** + * Add a child which implements the Visibility interface. + */ + public void testAddVisibilityChild() { + ControlBeanContextSupport cbcs = getContext(); + cbcs.okToUseGui(); + + VisibilityImpl child = new VisibilityImpl(); + assertTrue(cbcs.add(child)); + assertTrue(child.getCanUseGui()); + + cbcs = new org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport(); + cbcs.dontUseGui(); + assertTrue(cbcs.add(child)); + assertFalse(child.getCanUseGui()); + } + + /** + * Attempt to re-add an existing child. + */ + public void testAddExistingChild() { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport cbcs = getContext(); + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextChildSupport child = new ControlBeanContextChildSupport(); + + assertTrue(cbcs.add(child)); + assertFalse(cbcs.add(child)); + } + + /** + * Add a child who veto's its add to the bean context. + */ + public void testAddChildWhoVetos() { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport cbcs = getContext(); + ControlBeanContextChildSupport child = new ControlBeanContextChildSupport(); + AlwaysVetoListener avl = new AlwaysVetoListener(); + child.addVetoableChangeListener("beanContext", avl); + + try { + cbcs.add(child); + } + catch (IllegalStateException ise) { + return; + } + fail("Excpected IllegalStateException!!!"); + } + + ////////////////////// test remove() API ///////////////////////////////////////////////////////////////////// + + /** + * Remove a child from the bean context, verify the proper events are generated. + */ + public void testRemoveSingleChild() { + + ControlBeanContextSupport cbcs = getContext(); + ControlBeanContextChildSupport child = new ControlBeanContextChildSupport(); + + // add the child + assertTrue(cbcs.add(child)); + + // setup listeners + ChangeListener cl = new ChangeListener(); + child.addPropertyChangeListener("beanContext", cl); + + MembershipListener ml = new MembershipListener(); + cbcs.addBeanContextMembershipListener(ml); + + // remove the child + assertTrue(cbcs.remove(child)); + + // verify that.... + + // a BeanContextMembershipEvent is fired... + BeanContextMembershipEvent[] bcme = ml.getEvents(); + assertEquals(1, bcme.length); + assertTrue(bcme[0].contains(child)); + + // the child recieved a PropertyEvent that is parent was changed + PropertyChangeEvent[] pce = cl.getEvents(); + assertEquals(1, pce.length); + assertEquals("beanContext", pce[0].getPropertyName()); + assertNull(pce[0].getNewValue()); + assertEquals(cbcs, pce[0].getOldValue()); + + // that the child was added to the collection + Object[] children = cbcs.toArray(); + assertEquals(0, children.length); + } + + /** + * Remove a child which implements BeanContextProxy. + */ + public void testRemoveProxyChild() { + ControlBeanContextSupport cbcs = getContext(); + ControlBeanContextChildSupport child = new ControlBeanContextChildSupport(); + BeanContextProxyImpl proxy = new BeanContextProxyImpl(child); + + // add the child + assertTrue(cbcs.add(proxy)); + + // setup listeners + ChangeListener cl = new ChangeListener(); + child.addPropertyChangeListener("beanContext", cl); + MembershipListener ml = new MembershipListener(); + cbcs.addBeanContextMembershipListener(ml); + + // remove the child + assertTrue(cbcs.remove(proxy)); + + // verify that.... + + // a BeanContextMembershipEvent is fired... + BeanContextMembershipEvent[] bcme = ml.getEvents(); + assertEquals(1, bcme.length); + assertTrue(bcme[0].contains(proxy)); + + // the child recieved a PropertyEvent that is parent was changed + PropertyChangeEvent[] pce = cl.getEvents(); + assertEquals(1, pce.length); + assertEquals("beanContext", pce[0].getPropertyName()); + assertNull(pce[0].getNewValue()); + assertEquals(cbcs, pce[0].getOldValue()); + + // that the child was removed from the collection + Object[] children = cbcs.toArray(); + assertEquals(0, children.length); + } + + /** + * Implicitly remove a child from the bean context by changing the value of the child's bean context. + */ + public void testImplicitRemoveSingleChild() { + + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport cbcs = getContext(); + ControlBeanContextChildSupport child = new ControlBeanContextChildSupport(); + + // add the child + assertTrue(cbcs.add(child)); + + // setup listeners + ChangeListener cl = new ChangeListener(); + child.addPropertyChangeListener("beanContext", cl); + + MembershipListener ml = new MembershipListener(); + cbcs.addBeanContextMembershipListener(ml); + + // set the child's bean context (implicitly remove from cbcs) + try { + child.setBeanContext(null); + } + catch (PropertyVetoException pve) { + fail("Unexpected PropertyVetoException!!!"); + } + + // verify that.... + + // a BeanContextMembershipEvent is fired... + BeanContextMembershipEvent[] bcme = ml.getEvents(); + assertEquals(1, bcme.length); + assertTrue(bcme[0].contains(child)); + + // the child recieved a PropertyChangeEvent that is parent was changed + PropertyChangeEvent[] pce = cl.getEvents(); + assertEquals(1, pce.length); + assertEquals("beanContext", pce[0].getPropertyName()); + assertNull(pce[0].getNewValue()); + assertEquals(cbcs, pce[0].getOldValue()); + + // that the child was removed from the collection + Object[] children = cbcs.toArray(); + assertEquals(0, children.length); + } + + /** + * Test an implicit remove of a child from a BeanContext which has a peer. + */ + public void testImplicitRemoveSingleChild_Peer() { + BeanContextPeer bcp = new BeanContextPeer(); + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport cbcs = new ControlBeanContextSupport(bcp); + ControlBeanContextChildSupport child = new ControlBeanContextChildSupport(); + + // add the child + assertTrue(cbcs.add(child)); + + // setup listeners + ChangeListener cl = new ChangeListener(); + child.addPropertyChangeListener("beanContext", cl); + + MembershipListener ml = new MembershipListener(); + cbcs.addBeanContextMembershipListener(ml); + + // set the child's bean context (implicitly remove from cbcs) + try { + child.setBeanContext(null); + } + catch (PropertyVetoException pve) { + fail("Unexpected PropertyVetoException!!!"); + } + + // verify that.... + + // a BeanContextMembershipEvent is fired... + BeanContextMembershipEvent[] bcme = ml.getEvents(); + assertEquals(1, bcme.length); + assertTrue(bcme[0].contains(child)); + assertEquals(bcp, bcme[0].getSource()); + + // the child recieved a PropertyChangeEvent that is parent was changed + PropertyChangeEvent[] pce = cl.getEvents(); + assertEquals(1, pce.length); + assertEquals("beanContext", pce[0].getPropertyName()); + assertNull(pce[0].getNewValue()); + assertEquals(bcp, pce[0].getOldValue()); + assertEquals(child, pce[0].getSource()); + + // that the child was removed from the collection + Object[] children = cbcs.toArray(); + assertEquals(0, children.length); + } + + /** + * Remove a child which is not currently a child of the bean context. + */ + public void testRemoveNonExistentChild() { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport cbcs = getContext(); + ControlBeanContextChildSupport child = new ControlBeanContextChildSupport(); + + assertFalse(cbcs.remove(child)); + } + + /** + * Remove a child which veto's its removal from the bean context. + */ + public void testRemoveChildWhoVetos() { + ControlBeanContextSupport cbcs = getContext(); + ControlBeanContextChildSupport child = new ControlBeanContextChildSupport(); + + // add the child + assertTrue(cbcs.add(child)); + + // setup listeners + AlwaysVetoListener avl = new AlwaysVetoListener(); + child.addVetoableChangeListener("beanContext", avl); + + // remove the child + try { + cbcs.remove(child); + } + catch (IllegalStateException ise) { + return; + } + fail("Expected IllegalStateException!!!"); + } + + // + // BeanContext Api tests + // + + /* + * addBeanContextMembershipListener -- see collection add methods + */ + + /* + * removeBeanContextMembershipListener -- see collection remove methods + */ + + + /** + * Test the instantiateChild() BeanContext api. Should create bean and add + * to BeanContext. + */ + public void testInstantiateBean() { + ControlBeanContextSupport cbcs = getContext(); + MembershipListener ml = new MembershipListener(); + cbcs.addBeanContextMembershipListener(ml); + + + VisibilityImpl child = null; + try { + child = (VisibilityImpl) cbcs.instantiateChild("org.apache.beehive.controls.test.controls.beancontext.VisibilityImpl"); + } + catch (IOException e) { + fail("Unexpected IOException during instantiateChild() test!!"); + } + catch (ClassNotFoundException e) { + fail("Unexpected ClassNotFoundException during instantiateChild() test!!"); + } + + BeanContextMembershipEvent[] evts = ml.getEvents(); + assertEquals(1, evts.length); + assertTrue(evts[0].contains(child)); + + assertEquals(1, cbcs.size()); + assertTrue(cbcs.contains(child)); + } + + /** + * Test the getResource() BeanContext API. + */ + public void testGetResource() { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport cbcs = getContext(); + ControlBeanContextChildSupport child = new ControlBeanContextChildSupport(); + + assertTrue(cbcs.add(child)); + + URL location = cbcs.getResource("org/apache/beehive/controls/test/controls/beancontext/Resource.txt", child); + assertNotNull(location); + } + + /** + * Test the getResource() BeanContext API, where the child parameter is not a child of the BeanContext. + */ + public void testGetResourceBadChild() { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport cbcs = getContext(); + ControlBeanContextChildSupport child = new ControlBeanContextChildSupport(); + try { + cbcs.getResource("org/apache/beehive/controls/test/controls/beancontext/Resource.txt", child); + } + catch (IllegalArgumentException iae) { + return; + } + fail("Expected IllegalArgumentException since specified child is not a child of the BeanContext!!"); + } + + /** + * Test the getResourceAsStream() BeanContext API. + */ + public void testGetResourceAsStream() throws IOException { + ControlBeanContextSupport cbcs = getContext(); + ControlBeanContextChildSupport child = new ControlBeanContextChildSupport(); + + assertTrue(cbcs.add(child)); + + InputStream is = cbcs.getResourceAsStream("org/apache/beehive/controls/test/controls/beancontext/Resource.txt", child); + assertNotNull(is); + is.close(); + } + + /** + * Test the getResourceAsStream() BeanContext API, where the child parameter is not a child of the BeanContext. + */ + public void testGetResourceAsStreamBadChild() { + ControlBeanContextSupport cbcs = getContext(); + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextChildSupport child = new ControlBeanContextChildSupport(); + + try { + cbcs.getResourceAsStream("org/apache/beehive/controls/test/controls/beancontext/Resource.txt", child); + } + catch (IllegalArgumentException iae) { + return; + } + fail("Expected IllegalArgumentException since specified child is not a child of the BeanContext!!"); + } + + // + // some simple visibility API tests + // + + /** + * Add a child which needGui, verify that it is picked up correctly. + */ + public void testNeedsGui() { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport cbcs = getContext(); + VisibilityImpl child = new VisibilityImpl(); + child.setNeedsGui(true); + + assertTrue(cbcs.add(child)); + assertTrue(cbcs.needsGui()); + } + + /** + * Test the negative case of needsGui() Visiblity API. + */ + public void testNeedsGuiNegative() { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport cbcs = getContext(); + VisibilityImpl child = new VisibilityImpl(); + child.setNeedsGui(false); + + assertTrue(cbcs.add(child)); + assertFalse(cbcs.needsGui()); + } + + /** + * Test the dontUseGui() Visibility API. + */ + public void testDontUseGui() { + ControlBeanContextSupport cbcs = getContext(); + VisibilityImpl child = new VisibilityImpl(); + + assertTrue(cbcs.add(child)); + cbcs.dontUseGui(); + assertFalse(child.getCanUseGui()); + } + + /** + * Test the okToUseGui() Visibility API. + */ + public void testOkToUseGui() { + ControlBeanContextSupport cbcs = getContext(); + VisibilityImpl child = new VisibilityImpl(); + + assertTrue(cbcs.add(child)); + cbcs.okToUseGui(); + assertTrue(child.getCanUseGui()); + } + + /** + * Test the avoidingGui Visibility API. + */ + public void testAvoidingGui() { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport cbcs = getContext(); + VisibilityImpl child = new VisibilityImpl(); + child.setNeedsGui(true); + + assertTrue(cbcs.add(child)); + cbcs.dontUseGui(); + + assertTrue(child.avoidingGui()); + } + + // + // Serialization tests + // + + /** + * Serialize/deserializeCBCS an empty bean context. + */ + public void testSerializationEmptyBeanContext() throws IOException, ClassNotFoundException { + ControlBeanContextSupport cbcs = getContext(); + cbcs.setDesignTime(true); + + File serFile = serializeCBCS(cbcs, "cbcs_1"); + cbcs = deserializeCBCS(serFile); + + assertTrue(cbcs.isEmpty()); + assertTrue(cbcs.isDesignTime()); + } + + /** + * Serialize BC with two children, no event listeners. + */ + public void testSerializationWithChildren() throws IOException, ClassNotFoundException { + ControlBeanContextSupport cbcs = getContext(); + ControlBeanContextChildSupport child1 = new ControlBeanContextChildSupport(); + ControlBeanContextChildSupport child2 = new ControlBeanContextChildSupport(); + + assertTrue(cbcs.add(child1)); + assertTrue(cbcs.add(child2)); + + File serFile = serializeCBCS(cbcs, "cbcs_2"); + cbcs = deserializeCBCS(serFile); + + assertFalse(cbcs.isEmpty()); + assertEquals(2, cbcs.size()); + } + + /** + * Serailize BC which has Peer and two child, children should NOT be serialized. + */ + public void testSerializationWithChildren_Peer() throws IOException, ClassNotFoundException { + BeanContextPeer bcp = new BeanContextPeer(); + ControlBeanContextSupport cbcs = new ControlBeanContextSupport(bcp); + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextChildSupport child1 = new ControlBeanContextChildSupport(); + ControlBeanContextChildSupport child2 = new ControlBeanContextChildSupport(); + + assertTrue(cbcs.add(child1)); + assertTrue(cbcs.add(child2)); + + File serFile = serializeCBCS(cbcs, "cbcs_2p"); + cbcs = deserializeCBCS(serFile); + + // when peer is present children should not be serialized. + assertTrue(cbcs.isEmpty()); + } + + /** + * Serialization test with property change listerner's registered. + */ + public void testSerializationWithListeners() throws IOException, ClassNotFoundException { + ControlBeanContextSupport cbcs = getContext(); + + ControlBeanContextChildSupport child1 = new ControlBeanContextChildSupport(); + ChangeListener cl1 = new ChangeListener(); + child1.addPropertyChangeListener("beanContext", cl1); + + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextChildSupport child2 = new ControlBeanContextChildSupport(); + ChangeListener cl2 = new ChangeListener(); + child2.addPropertyChangeListener("beanContext", cl2); + + assertTrue(cbcs.add(child1)); + assertTrue(cbcs.add(child2)); + + File serFile = serializeCBCS(cbcs, "cbcs_3"); + cbcs = deserializeCBCS(serFile); + + assertFalse(cbcs.isEmpty()); + assertEquals(2, cbcs.size()); + + // todo: this is about all the further to test, none of our event listeners + // can be accessed in their deserialized state (dont have a reference to them) + // should add additional tests to make sure everything works as expected. + } + + /** + * Test serialization with registered BeanContextMembershipListeners + */ + public void testSerializationWithMembershipListeners() throws IOException, ClassNotFoundException { + ControlBeanContextSupport cbcs = getContext(); + MembershipListener ml = new MembershipListener(); + cbcs.addBeanContextMembershipListener(ml); + + ControlBeanContextChildSupport child1 = new ControlBeanContextChildSupport(); + assertTrue(cbcs.add(child1)); + + File serFile = serializeCBCS(cbcs, "cbcs_4"); + cbcs = deserializeCBCS(serFile); + + assertFalse(cbcs.isEmpty()); + assertEquals(1, cbcs.size()); + } + + /** + * Test serialization with a child which is not serializable. + */ + public void testSerializationWithNonSerializableChild() throws IOException, ClassNotFoundException { + org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport cbcs = getContext(); + ControlBeanContextChildSupport child1 = new ControlBeanContextChildSupport(); + assertTrue(cbcs.add(child1)); + VisibilityImpl child2 = new VisibilityImpl(); + assertTrue(cbcs.add(child2)); + + File serFile = serializeCBCS(cbcs, "cbcs_5"); + cbcs = deserializeCBCS(serFile); + assertFalse(cbcs.isEmpty()); + + // cbcs's size should only be 1 since one of its children was not Serializable + assertEquals(1, cbcs.size()); + } + + // + // helper methods + // + protected org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport getContext() { + return new ControlBeanContextSupport(); + } + + private File serializeCBCS(ControlBeanContextSupport cbcs, String serFileName) throws IOException { + File serFile = File.createTempFile(serFileName, "ser"); + ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(serFile)); + oos.writeObject(cbcs); + oos.close(); + return serFile; + } + + private org.apache.beehive.controls.runtime.webcontext.ControlBeanContextSupport deserializeCBCS(File serFile) throws IOException, ClassNotFoundException { + ObjectInputStream ois = new ObjectInputStream(new FileInputStream(serFile)); + try { + return (ControlBeanContextSupport) ois.readObject(); + } finally { + ois.close(); + serFile.delete(); + } + } + + public static Test suite() { + return new TestSuite(ControlBeanContextSupportTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/ControlExtensionTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/ControlExtensionTest.java new file mode 100644 index 0000000..523f4f8 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/ControlExtensionTest.java @@ -0,0 +1,296 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.test.controls.extension.ExtensibleControl; +import org.apache.beehive.controls.test.controls.extension.SubControl; +import org.apache.beehive.controls.test.controls.extension.SubControlBean; + +/** + * A TeseCase that tests control inheritance by instantiating a _subcontrol and invoking the methods + * and getting/setting the properties. + * All tests on controls instantiated declaratively are deactivated until this feature is supported. + */ +public class ControlExtensionTest extends ControlTestCase { + + /** + * A control extending ExtensibleControl in the same package + */ + @Control + private SubControlBean _subcontrol; + + /** + * Tests getting/setting a property declared on super control interface + * that is annotated with @Inherited + */ + public void testAnnotatedInheritedProperty() throws Exception { + String theBirthplace = _subcontrol.getBirthplace(); + assertNotNull(theBirthplace); + assertEquals("ExtensibleControl", theBirthplace); + + _subcontrol.setBirthplace("JUNIT"); + assertEquals("JUNIT", _subcontrol.getAnnotatedInheritedPropertyByContext()); + } + + + /** + * Tests invoking a method inherited by the _subcontrol + */ + public void testInheritedMethod() throws Exception { + assertEquals("Hello from super control", _subcontrol.hello()); + } + + /** + * Tests invoking a method inherited by the _subcontrol. + * The _subcontrol is instantiated programmically + */ + public void testInheritedMethod2() throws Exception { + + SubControlBean sub = (SubControlBean) java.beans.Beans.instantiate(Thread.currentThread().getContextClassLoader(), + "org.apache.beehive.controls.test.controls.extension.SubControlBean"); + assertEquals("Hello from super control", sub.hello()); + } + + /** + * Tests invoking a method declared on the _subcontrol + */ + public void testExtendedMethod() throws Exception { + assertEquals("Hello from subcontrol", _subcontrol.hello2()); + } + + /** + * Tests invoking a method declared on the _subcontrol + * The _subcontrol is instantiated programmically + */ + public void testExtendedMethod2() throws Exception { + SubControlBean sub = (SubControlBean) java.beans.Beans.instantiate(Thread.currentThread().getContextClassLoader(), + "org.apache.beehive.controls.test.controls.extension.SubControlBean"); + assertEquals("Hello from subcontrol", sub.hello2()); + } + + /** + * Tests getting propertySet inherited from ExtensibleControl from a _subcontrol instance. + * The property is retrieved via control context. + * The _subcontrol is instantiated declaratively + */ + public void testGettingInheritedPropertyByContext() throws Exception { + assertEquals("In_ExtensibleControl_Interface", _subcontrol.accessInheritedProperty()); + } + + /** + * Tests getting the propertySet inherited from ExtensibleControl from a _subcontrol instance + * The property is retrieved via control context. + * The _subcontrol is instantiated programmatically + */ + public void testGettingInheritedPropertyByContext2() throws Exception { + SubControlBean sub = (SubControlBean) java.beans.Beans.instantiate(Thread.currentThread().getContextClassLoader(), + "org.apache.beehive.controls.test.controls.extension.SubControlBean"); + assertEquals("In_ExtensibleControl_Interface", sub.accessInheritedProperty()); + } + + /** + * Tests getting an inherited property from a _subcontrol instance. + * The property is retrieved via getter. + * The _subcontrol is instantiated declaratively + */ + public void testGettingInheritedPropertyByGetter() throws Exception { + assertEquals(ExtensibleControl.CURRENT_POSITION, _subcontrol.getPosition()); + } + + /** + * Tests getting an inherited property from a _subcontrol instance + * The property is retrieved via getter. + * The _subcontrol is instantiated programmatically + */ + public void testGettingInheritedPropertyByGetter2() throws Exception { + SubControlBean sub = (SubControlBean) java.beans.Beans.instantiate( + Thread.currentThread().getContextClassLoader(), + "org.apache.beehive.controls.test.controls.extension.SubControlBean"); + assertEquals(ExtensibleControl.CURRENT_POSITION, sub.getPosition()); + } + + /** + * Tests setting an inherited property from a _subcontrol instance. + * The property is retrieved via getter. + * The _subcontrol is instantiated declaratively + */ + public void testSettingInheritedPropertyBySetter() throws Exception { + + _subcontrol.setPosition("A_NEW_POSITION"); + assertEquals("A_NEW_POSITION", _subcontrol.accessInheritedProperty()); + } + + /** + * Tests setting an inherited property from a _subcontrol instance + * The property is retrieved via getter. + * The _subcontrol is instantiated programmatically + */ + public void testSettingInheritedPropertyBySetter2() throws Exception { + + SubControlBean sub = (SubControlBean) java.beans.Beans.instantiate( + Thread.currentThread().getContextClassLoader(), + "org.apache.beehive.controls.test.controls.extension.SubControlBean"); + + sub.setPosition("A_NEW_POSITION"); + assertEquals("A_NEW_POSITION", sub.accessInheritedProperty()); + } + + /** + * Tests getting the reconfigured and inherited property.(A property declared on super control, + * but reconfigured on sub control) + * The reset property is retrieve by context. + * The _subcontrol is instantiated declaratively + */ + public void testGetReconfiguredPropertyByContext() throws Exception { + assertEquals("On_SubControl_Interface_Layer", _subcontrol.getLayerByContext()); + } + + /** + * Tests getting the reconfigured and inherited property.(A property declared on super control, + * but reconfigured on sub control) + * The reset property is retrieve by context. + * The _subcontrol is instantiated programmatically + */ + public void testGetReconfiguredPropertyByContext2() throws Exception { + SubControlBean sub = (SubControlBean) java.beans.Beans.instantiate(Thread.currentThread().getContextClassLoader(), + "org.apache.beehive.controls.test.controls.extension.SubControlBean"); + assertEquals("On_SubControl_Interface_Layer", sub.getLayerByContext()); + } + + /** + * Tests getting a reconfigured inherited property.(The property is declared on super control + * but reconfigured on sub control interface). + * The _subcontrol is instantiated declaratively + */ + public void testGetReconfiguredPropertyByGetter() throws Exception { + assertEquals("On_SubControl_Interface_Layer", _subcontrol.getLayer()); + } + + /** + * Tests getting a reconfigured inherited property.(The property is declared on super control + * but reconfigured on sub control interface). + * The _subcontrol is instantiated programmatically + */ + public void testGetReconfiguredPropertyByGetter2() throws Exception { + SubControlBean sub = (SubControlBean) java.beans.Beans.instantiate( + Thread.currentThread().getContextClassLoader(), + "org.apache.beehive.controls.test.controls.extension.SubControlBean"); + assertEquals("On_SubControl_Interface_Layer", sub.getLayer()); + } + + /** + * Tests setting the reconfigured and inherited property using bean setter + * The _subcontrol is instantiated declaratively + */ + public void testSetReconfiguredPropertyBySetter() throws Exception { + _subcontrol.setLayer("NEW_VALUE_FOR_LAYER"); + assertEquals("NEW_VALUE_FOR_LAYER", _subcontrol.getLayerByContext()); + } + + /** + * Tests setting the reconfigured and inherited property using bean setter + * The _subcontrol is instantiated programmatically + */ + public void testSetReconfiguredPropertyBySetter2() throws Exception { + SubControlBean sub = (SubControlBean) java.beans.Beans.instantiate( + Thread.currentThread().getContextClassLoader(), + "org.apache.beehive.controls.test.controls.extension.SubControlBean"); + sub.setLayer("NEW_VALUE_FOR_LAYER"); + assertEquals("NEW_VALUE_FOR_LAYER", sub.getLayerByContext()); + } + + /* More tests to be added on getting property value reconfigured on _subcontrol + * by declaration. + * The above tests testGetReconfiguredPropertyByContext(2) gets the value using an + * inherited method. + * Once testExtendedMethod passes, we need to add one or two tests to + * get the reconfigured value using an extended method on _subcontrol + * + * Like: testGetReconfigurePropertyBySubImpl + * While the above two methods are really: testGetReconfiguredPropertyBySuperImpl + */ + + /** + * Tests getting the property declared on SubControl interface. + * The value is retrieved by control context. + * The _subcontrol is instantiated declaratively. + */ + public void testGetExtendedPropertyByContext() throws Exception { + assertEquals("New Property Declared by Sub Control", _subcontrol.getExtendedPropertyByContext()); + } + + /** + * Tests getting the property declared on SubControl interface. + * The property is retrieved by control context. + * The _subcontrol is instantiated programmatically. + */ + public void testGetExtendedPropertyByContext2() throws Exception { + + SubControlBean sub = (SubControlBean) java.beans.Beans.instantiate( + Thread.currentThread().getContextClassLoader(), + "org.apache.beehive.controls.test.controls.extension.SubControlBean"); + assertEquals("New Property Declared by Sub Control", sub.getExtendedPropertyByContext()); + } + + /** + * Tests getting the property declared SubControl interface. + * The value is retrieved by getter on _subcontrol bean + * The _subcontrol is instantiated declaratively + */ + public void testGetExtendedPropertyByGetter() throws Exception { + assertEquals(SubControl.A_MESSAGE, _subcontrol.getMessage()); + } + + /** + * Tests getting the property declared on SubControl interface + * The value is retrieved by getter on the _subcontrol bean. + * The _subcontrol is instantiated programmatically + */ + public void testGetExtendedPropertyByGetter2() throws Exception { + SubControlBean sub = (SubControlBean) java.beans.Beans.instantiate( + Thread.currentThread().getContextClassLoader(), + "org.apache.beehive.controls.test.controls.extension.SubControlBean"); + assertEquals(SubControl.A_MESSAGE, sub.getMessage()); + } + + /** + * Tests setting the property declared SubControl interface. + * The value is changed by setter on _subcontrol bean + * The _subcontrol is instantiated declaratively + */ + public void testSetExtendedPropertyBySetter() throws Exception { + _subcontrol.setMessage("NEW_VALUE_FOR_EXTENDED_PROPERTY"); + assertEquals("NEW_VALUE_FOR_EXTENDED_PROPERTY", _subcontrol.getExtendedPropertyByContext()); + } + + /** + * Tests setting the property declared on SubControl interface + * The value is changed by setter on the _subcontrol bean. + * The _subcontrol is instantiated programmatically + */ + public void testSetExtendedPropertyBySetter2() throws Exception { + SubControlBean sub = (SubControlBean) java.beans.Beans.instantiate( + Thread.currentThread().getContextClassLoader(), + "org.apache.beehive.controls.test.controls.extension.SubControlBean"); + sub.setMessage("NEW_VALUE_FOR_EXTENDED_PROPERTY"); + assertEquals("NEW_VALUE_FOR_EXTENDED_PROPERTY", sub.getExtendedPropertyByContext()); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/ControlMethodOverloadTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/ControlMethodOverloadTest.java new file mode 100644 index 0000000..121ea32 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/ControlMethodOverloadTest.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.test.controls.overload.HelloControlBean; + +/** + * Test invoking overloaded methods on controls + */ +public class ControlMethodOverloadTest extends ControlTestCase { + /** + * A control with overloaded methods + */ + @Control + private HelloControlBean _helloBean; + + /** + * Tests invoking overloaded methods on a control + */ + public void testOverload() throws Exception { + assertEquals("Good morning", _helloBean.hello("Good morning")); + assertEquals("99", _helloBean.hello(99)); + + boolean bytes[] = {true, false, true, false}; + assertEquals("truefalsetruefalse", _helloBean.hello(bytes)); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/ControlServicesTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/ControlServicesTest.java new file mode 100644 index 0000000..d98ce60 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/ControlServicesTest.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit; + +import org.apache.beehive.controls.test.controls.beancontextservices.BCSCheckServices; +import org.apache.beehive.controls.api.bean.Control; + +/** + * Test that a control can retieve a list of service classes from a control bean context. + */ +public class ControlServicesTest extends ControlTestCase { + + @Control + private BCSCheckServices _ctrl; + + public void testServices() throws Exception { + + assertNotNull(_ctrl); + _ctrl.checkServices(); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/DeclarativeTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/DeclarativeTest.java new file mode 100644 index 0000000..ffae9e7 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/DeclarativeTest.java @@ -0,0 +1,133 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.test.junit; + +import java.io.ByteArrayOutputStream; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.api.events.EventHandler; +import org.apache.beehive.controls.test.controls.composition.OuterControl; +import org.apache.beehive.controls.test.controls.composition.OuterControlBean; +import org.apache.beehive.controls.test.controls.composition.InnerControlBean; +import org.apache.beehive.controls.test.junit.utils.ControlTestUtils; + +/** + * A TestCase that tests control composition. + * The outer control is instantiated declaratively, and the outer + * control instantiates the nested control declaratively + * + * Instantiating controls declaratively is not supported currently. + * All tests are deactivated until this is supported + */ +public class DeclarativeTest + extends ControlTestCase + implements java.io.Serializable { + + @Control + private OuterControlBean _outerControl; + + private String _onReportMessage; + + @EventHandler(field="_outerControl", eventSet=OuterControl.OuterEvents.class, eventName="report") + public int onReport( String msg ) { + _onReportMessage = msg; + return 0; + } + + /** + * Tests outer control instantiats nested control by declaration + */ + public void testInstantiation() + throws Exception { + assertNotNull(_outerControl); + assertNotNull(_outerControl.getDeclaredNestedControl()); + assertNotNull(_outerControl.getDeclaredNestedControl2()); + } + + /** + * Tests outer control getting inner control property from control context + */ + public void testGetPropertyByContext() { + assertNotNull(_outerControl); + + InnerControlBean innercontrol=_outerControl.getDeclaredNestedControl(); + assertNotNull(innercontrol); + assertEquals("Bob",innercontrol.getNameFromContext()); + assertNull(innercontrol.getJobFromContext()); + } + + /** + * Tests reconfigured property. + * Outer control reconfigures the inner control's property when instantiating it + */ + public void testReconfiguredProperty() { + assertNotNull(_outerControl); + InnerControlBean innercontrol=_outerControl.getDeclaredNestedControl2(); + assertNotNull(innercontrol); + assertEquals("Bob",innercontrol.getNameFromContext()); + assertEquals("farmer",innercontrol.getJobFromContext()); + } + + /** + * Tests outer control receiving events from nested control using + * EventHandler + */ + public void testEventHandler() { + assertNotNull(_outerControl); + assertEquals("0",_outerControl.testActivityWakeup()); + assertEquals("0",_outerControl.testActivityReadMessage()); + assertEquals("0",_outerControl.testActivityReport()); + assertEquals("0",_outerControl.testActionShopping()); + assertEquals("0",_outerControl.testActionDostuff()); + } + + /** + * Tests outer control firing events to us + */ + public void testOuterEvents() { + //System.out.println( "_onReportMessage=" + _onReportMessage ); + + assertNotNull(_outerControl); + + _outerControl.fireOuterEvents("this is the reported msg"); + assertEquals("this is the reported msg", _onReportMessage ); + //System.out.println( "_onReportMessage=" + _onReportMessage ); + } + + /** + * Test to ensure that control identifiers and relationships are maintained correctly after + * serializing and deserializing a control tree. + */ + public void testControlIDs() + throws Exception { + + assertEquals("_outerControl", _outerControl.getControlID()); + assertEquals("_outerControl/innerControl", _outerControl.getDeclaredNestedControl().getControlID()); + + ByteArrayOutputStream baos = ControlTestUtils.serialize(_outerControl); + + Object object = ControlTestUtils.deserialize(baos); + assertTrue(object instanceof OuterControlBean); + OuterControlBean outerControlCopy = (OuterControlBean)object; + + assertFalse(outerControlCopy == _outerControl); + assertEquals("_outerControl", outerControlCopy.getControlID()); + assertEquals("_outerControl/innerControl", outerControlCopy.getDeclaredNestedControl().getControlID()); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/EncodingTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/EncodingTest.java new file mode 100644 index 0000000..33458a3 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/EncodingTest.java @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit; + +import junit.framework.TestCase; + +import java.io.ByteArrayOutputStream; +import java.io.ByteArrayInputStream; +import java.beans.XMLEncoder; +import java.beans.XMLDecoder; + +import org.apache.beehive.controls.test.controls.property.NestPropsBean; +import org.apache.beehive.controls.test.controls.property.Props; +import org.apache.beehive.controls.test.controls.property.PropsBean; + +/** + * A TestCase that tests encoding/decoding control state to/from XML. + */ +public class EncodingTest extends TestCase { + + /** + * An Exception listener class that will catch encoding/decoding exceptions, dump the + * failure stack, and then flag a test failure. + */ + private class ExceptionDump + implements java.beans.ExceptionListener { + public void exceptionThrown(Exception e) { + e.printStackTrace(); + fail(); + } + } + + /** + * Helper method that will take a given object, encode it using XMLEncoder, then decode + * it using XmLMDecoder. + */ + private T encodeDecode(T obj) + throws Exception { + // + // Validate decode ability by running through a decoder + // + ByteArrayOutputStream baos = null; + XMLEncoder encoder = null; + try { + baos = new ByteArrayOutputStream(); + encoder = new XMLEncoder(baos); + encoder.setExceptionListener(new org.apache.beehive.controls.test.junit.EncodingTest.ExceptionDump()); + encoder.writeObject(obj); + baos.flush(); + } + finally { + if(encoder != null) + encoder.close(); + if(baos != null) + baos.close(); + } + + ByteArrayInputStream bais = null; + XMLDecoder decoder = null; + T returnObj = null; + try { + bais = new ByteArrayInputStream(baos.toByteArray()); + decoder = new XMLDecoder(bais); + decoder.setExceptionListener(new org.apache.beehive.controls.test.junit.EncodingTest.ExceptionDump()); + returnObj = (T)decoder.readObject(); + } + finally { + if(decoder != null) + decoder.close(); + if(bais != null) + bais.close(); + } + + bais.close(); + return returnObj; + } + + /** + * Tests encoding a NestPropsBean instance for validating of property state, nesting, + * and listener registration. + */ + public void testNestPropsBean() throws Exception + { + NestPropsBean propsBean = new NestPropsBean(null, "myID", null); + propsBean.setSimpleInt(3); + propsBean.getControlPropertySet(Props.SimpleProps.class); + + PropsBean nestedBean = new NestPropsBean(null, "nested", null); + propsBean.getControlBeanContext().add(nestedBean); + nestedBean.setSimpleInt(4); + + // Run the bean through the encoder/decoder, then test equivalence + NestPropsBean newPropsBean = encodeDecode(propsBean); + assertEquals(newPropsBean.getSimpleInt(),propsBean.getSimpleInt()); + + PropsBean newNestedBean = (NestPropsBean)(newPropsBean.getControlBeanContext().getBean("nested")); + assertNotNull(newNestedBean); + assertEquals(newNestedBean.getSimpleInt(), nestedBean.getSimpleInt()); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/InstantiationTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/InstantiationTest.java new file mode 100644 index 0000000..f3ee690 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/InstantiationTest.java @@ -0,0 +1,109 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.api.bean.Controls; +import org.apache.beehive.controls.api.properties.BeanPropertyMap; +import org.apache.beehive.controls.test.controls.instantiate.BoundExtPropertySet; +import org.apache.beehive.controls.test.controls.instantiate.BoundPropertyControlBean; +import org.apache.beehive.controls.test.controls.instantiate.HelloControlBean; +import org.apache.beehive.controls.test.controls.instantiate.SingleProperty; +import org.apache.beehive.controls.test.controls.instantiate.SinglePropertyBean; + +/** + * A TestCase that tests instantiating controls in different ways + * All tests on controls instantiated declaratively are deactivated until this feature is supported. + */ +public class InstantiationTest extends ControlTestCase { + + private static String EXPECTED_GREETING = "Good evening!"; + + /** + * A simple control with one method, no property declared + */ + @Control + private HelloControlBean _myHelloBean; + + + /** + * A simple control with one property declared + * Resets the property value at declaration + */ + @Control + @SingleProperty.Greeting(GreetWord = "Good evening!") + private SinglePropertyBean _myPropertyBean; + + /** + * Tests instantiating a custom control programmatically + */ + public void testProgrammaticInstantiation() throws Exception { + HelloControlBean hc = (HelloControlBean) java.beans.Beans.instantiate( + Thread.currentThread().getContextClassLoader(), + "org.apache.beehive.controls.test.controls.instantiate.HelloControlBean"); + + assertNotNull(hc); + assertEquals("check", hc.hello("check")); + } + + /** + * Tests instantiating a custom control declaratively + */ + public void testDeclarativeInstantiation() throws Exception { + assertNotNull(_myHelloBean); + assertEquals("check", _myHelloBean.hello("check")); + } + + /** + * Tests declaratively instantiating a custom control with propertySet + */ + public void testDeclareWithProperty() throws Exception { + assertEquals(EXPECTED_GREETING, _myPropertyBean.sayHello()); + } + + /** + * Tests programmically instantiating a control with propertySet + */ + public void testProgramWithProperty() throws Exception { + BeanPropertyMap greetAttr = new BeanPropertyMap(SingleProperty.Greeting.class); + greetAttr.setProperty(SinglePropertyBean.GreetWordKey, "Good afternoon!"); + + SinglePropertyBean spbean = (SinglePropertyBean) Controls.instantiate( + Thread.currentThread().getContextClassLoader(), + "org.apache.beehive.controls.test.controls.instantiate.SinglePropertyBean", + greetAttr); + + assertEquals("Good afternoon!", spbean.sayHello()); + } + + /** + * Tests programmically instantiating a control with an external declared propertySet + */ + public void testProgramWithExtProperty() throws Exception { + BeanPropertyMap greetAttr = new BeanPropertyMap(BoundExtPropertySet.class); + greetAttr.setProperty(BoundPropertyControlBean.AgeKey, Integer.valueOf(10)); + + BoundPropertyControlBean bbean = (BoundPropertyControlBean) Controls.instantiate( + Thread.currentThread().getContextClassLoader(), + "org.apache.beehive.controls.test.controls.instantiate.BoundPropertyControlBean", + greetAttr); + assertEquals(10, bbean.getAge()); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/InterfaceHintTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/InterfaceHintTest.java new file mode 100644 index 0000000..97475f2 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/InterfaceHintTest.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.test.junit; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.test.controls.interfaceHint.c.BarControl; + +/** + * Test that the proper control is being associated with the control reference. + * There are two controls with the same name but in different java packages. + */ +public class InterfaceHintTest + extends ControlTestCase { + + @Control + private BarControl _barControl; + + public void testFooType() { + assertNotNull(_barControl); + assertTrue(_barControl.getFooBean() instanceof org.apache.beehive.controls.test.controls.interfaceHint.b.FooControlBean); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/MethodOverrideAptTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/MethodOverrideAptTest.java new file mode 100644 index 0000000..59cdcd4 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/MethodOverrideAptTest.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.test.junit; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.test.controls.methodOverride.CustomerDao; + +/** + * Junit tests for making sure that APT can properly generate a control bean when + * the control's interface overrides methods in a super interface. + * + * If this doesn't work compilation will fail, all thats really necessary here is + * to verify the controls can be initialized. + */ +public class MethodOverrideAptTest + extends ControlTestCase { + + @Control + private CustomerDao _customer; + + public void testMethodOverride() { + assertNotNull(_customer); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/PropertyTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/PropertyTest.java new file mode 100644 index 0000000..1ee7db4 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/PropertyTest.java @@ -0,0 +1,142 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + $Header:$ +*/ +package org.apache.beehive.controls.test.junit; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.BeanInfo; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; + +import org.apache.beehive.controls.api.bean.Control; + +import org.apache.beehive.controls.test.controls.propertiessimple.Property; +import org.apache.beehive.controls.test.controls.propertiessimple.PropertyBean; +import org.apache.beehive.controls.test.controls.propertiesoptional.OptionalPropertySetBean; +import org.apache.beehive.controls.test.controls.interfacegetter.InterfaceGetterSetterBean; +import org.apache.beehive.controls.test.controls.interfacegetter.CtrlExtensionBean; + +/** + * + */ +public class PropertyTest + extends ControlTestCase { + + @Control + @Property.Text(value = "Test value override") + private PropertyBean _propertyControl; + + @Control + private OptionalPropertySetBean _optionalControl; + + @Control + private InterfaceGetterSetterBean _getterSetterControl; + + @Control + private CtrlExtensionBean _ctrlExtensionControl; + + private boolean _eventHandlerCalled = false; + + public void testDeclarativePropertyInstantiation() { + assertEquals("Test value override", _propertyControl.getValue()); + } + + public void testPropertyChange() { + Property property = (Property)instantiateControl(PropertyBean.class.getName()); + PropertyBean propertyBean = (PropertyBean)property; + + + propertyBean.addPropertyChangeListener("value", + new PropertyChangeListener() { + public void propertyChange(PropertyChangeEvent event) { + _eventHandlerCalled = true; + } + } + ); + + propertyBean.setValue("does this work?"); + assertEquals("does this work?", propertyBean.getValue()); + assertTrue(_eventHandlerCalled); //, "Appears that the event handler wasn't called!"); + } + + /** + * Verify that members of a PropertySet marked optional do not have property descriptors for + * their getter methods. + * + * @throws Exception + */ + public void testOptionalPropertySet() throws Exception { + BeanInfo bi = Introspector.getBeanInfo(_optionalControl.getClass()); + PropertyDescriptor[] pds = bi.getPropertyDescriptors(); + + // There should not be a PropertyDescriptor for a property set which has optional=true and hasSetters=false + // (no getter or setter for property), so there should only be 2 PropertyDescriptors for this control + assertEquals(2, pds.length); + + assertEquals("value", pds[1].getName()); + assertNull(pds[1].getReadMethod()); + assertNotNull(pds[1].getWriteMethod()); + } + + /** + * Verify that the generated BeanInfo class contains property descriptors for getters/setters declared in + * a control interface. + * + * @throws Exception + */ + public void testGetterSetterPropertyGeneration() throws Exception { + BeanInfo bi = Introspector.getBeanInfo(_getterSetterControl.getClass()); + PropertyDescriptor[] pds = bi.getPropertyDescriptors(); + + assertEquals(3, pds.length); + + assertEquals("count", pds[1].getName()); + assertNotNull(pds[1].getReadMethod()); + assertNull(pds[1].getWriteMethod()); + + assertEquals("text", pds[2].getName()); + assertNotNull(pds[2].getReadMethod()); + assertNotNull(pds[2].getWriteMethod()); + } + + /** + * Verify that the generated BeanInfo class contains property descriptors for getters/setters declared in + * a control interface for an extensible control. + * + * @throws Exception + */ + public void testGetterSetterExtPropertyGeneration() throws Exception { + BeanInfo bi = Introspector.getBeanInfo(_ctrlExtensionControl.getClass()); + PropertyDescriptor[] pds = bi.getPropertyDescriptors(); + + assertEquals(4, pds.length); + + assertEquals("count", pds[1].getName()); + assertNotNull(pds[1].getReadMethod()); + assertNotNull(pds[1].getWriteMethod()); + + assertEquals("text", pds[2].getName()); + assertNotNull(pds[2].getReadMethod()); + assertNotNull(pds[2].getWriteMethod()); + + assertEquals("textExt", pds[3].getName()); + assertNotNull(pds[3].getReadMethod()); + assertNull(pds[3].getWriteMethod()); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/SimpleLifecycleTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/SimpleLifecycleTest.java new file mode 100644 index 0000000..9ca8620 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/SimpleLifecycleTest.java @@ -0,0 +1,52 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + $Header:$ +*/ +package org.apache.beehive.controls.test.junit; + +import java.util.List; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.test.controls.lifecycle.ControlLifecycle; + +/** + * + */ +public class SimpleLifecycleTest + extends ControlTestCase { + + @Control + private ControlLifecycle _lifecycleControl; + + public void testSimple1() { + assertNotNull(_lifecycleControl); + assertNotNull(_lifecycleControl.getTheControlBeanContext()); + assertNotNull(_lifecycleControl.getTheResourceContext()); + + //System.out.println(_lifecycleControl.echo("foo")); + List events = _lifecycleControl.getLifecycleEvents(); + assertEquals(2, events.size()); + assertEquals("onCreate", events.get(0)); + assertEquals("onAcquire", events.get(1)); + + _lifecycleControl.clearLifecycleEvents(); + + _lifecycleControl.echo("bar"); + events = _lifecycleControl.getLifecycleEvents(); + assertEquals(0, events.size()); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/SimpleSerializationTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/SimpleSerializationTest.java new file mode 100644 index 0000000..feec5bf --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/SimpleSerializationTest.java @@ -0,0 +1,126 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + $Header:$ +*/ +package org.apache.beehive.controls.test.junit; + +import java.util.List; +import java.io.FileOutputStream; +import java.io.ObjectOutputStream; +import java.io.FileInputStream; +import java.io.ObjectInputStream; +import java.io.File; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.api.context.ControlContainerContext; +import org.apache.beehive.controls.test.controls.serialization.ControlSerialization; +import org.apache.beehive.controls.test.controls.serialization.ControlSerializationBean; +import org.apache.beehive.controls.test.container.ControlTestContainerContext; +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * Test serialization of a simple control. + */ +public class SimpleSerializationTest + extends ControlTestCase { + + @Control + private ControlSerialization _serializationControl; + + public void setUp() { + /* intentionally, this does not call super */ + } + + public void tearDown() { + /* intentionally, this does not call super */ + } + + public void testSimpleSerialization() throws Exception { + + // + // start the context + // + getControlContainerContextManager().beginContext(); + + initializeControls(); + assertNotNull(_serializationControl); + + _serializationControl.setControlState(6); + _serializationControl.clearLifecycleEvents(); + + ControlContainerContext ccc = getControlContainerContext(); + + // + // end the context + // + getControlContainerContextManager().endContext(); + + // + // serialize the object + // + File serFile = File.createTempFile("controls", "ser"); + ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(serFile)); + ControlTestContainerContext ctcc = (ControlTestContainerContext)ccc; + oos.writeObject(ctcc); + oos.close(); + + // + // deserialize the ctcc contents + // + ObjectInputStream ois = new ObjectInputStream(new FileInputStream(serFile)); + ctcc = (ControlTestContainerContext)ois.readObject(); + ois.close(); + serFile.delete(); + + // + // find the deserialized instance in the ctcc + // + Object[] ctrls = ctcc.toArray(); + ControlSerialization deserializedControl = null; + for (Object c : ctrls) { + if (c instanceof ControlSerializationBean) { + deserializedControl = (ControlSerialization)c; + break; + } + } + + // + // start the context + // + getControlContainerContextManager().beginContext(); + + assertNotNull(deserializedControl); + assertFalse(deserializedControl == _serializationControl); + assertEquals(6, deserializedControl.getControlState()); + List events = deserializedControl.getLifecycleEvents(); + + // onRelease should have been invoked before the context was first ended + assertEquals("onRelease", events.get(0)); + assertEquals("onAcquire", events.get(1)); + + getControlContainerContextManager().endContext(); + } + + public static Test suite() { + return new TestSuite(SimpleSerializationTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/VersionRequiredTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/VersionRequiredTest.java new file mode 100644 index 0000000..06846c8 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/VersionRequiredTest.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.api.versioning.VersionRequired; +import org.apache.beehive.controls.test.controls.versioning.HelloBean; + +public class VersionRequiredTest extends ControlTestCase +{ + /** + * A control that declares a version requirement + */ + @Control + @VersionRequired(major=2) + public HelloBean helloBean; + + + public void testRequiredVersion() throws Exception + { + assertNotNull(helloBean); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/assembly/AssemblyTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/assembly/AssemblyTest.java new file mode 100644 index 0000000..feaaa76 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/assembly/AssemblyTest.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit.assembly; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.api.bean.ControlReferences; +import org.apache.beehive.controls.test.controls.assembly.AssemblyTestControl; +import org.apache.beehive.controls.test.controls.assembly.AssemblyTestControl2; +import org.apache.beehive.controls.test.junit.ControlTestCase; + +@ControlReferences({AssemblyTestControl2.class}) +public class AssemblyTest extends ControlTestCase { + @Control + private AssemblyTestControl atc; + + /** + * Test that a Class generated at assembly time is available. + */ + public void testAssemblyDeclaritive() throws Exception { + try { + Class c = Class.forName("org.apache.beehive.controls.test.assembly" + + ".generated.AssemblyTestGenerated"); + assertNotNull(c.newInstance()); + } + catch (ClassNotFoundException cnfe) { + fail(cnfe.toString()); + } + } + + /** + * Test that a control type specified via @ControlReference participates in assembly. + */ + public void testAssemblyViaReferences() throws Exception { + try { + Class c = Class.forName("org.apache.beehive.controls.test.assembly" + + ".generated.AssemblyTest2Generated"); + assertNotNull(c.newInstance()); + } + catch (ClassNotFoundException cnfe) { + fail(cnfe.toString()); + } + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/beaninfo/BeanInfoTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/beaninfo/BeanInfoTest.java new file mode 100644 index 0000000..be4df95 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/beaninfo/BeanInfoTest.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit.beaninfo; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; + +import junit.framework.TestCase; +import org.apache.beehive.controls.test.controls.beaninfo.InfoTestBean; +import org.apache.beehive.controls.test.junit.utils.ControlTestUtils; + + +/** + * A TestCase that tests generated BeanInfo + *

    + * TO GET LIVE BEANINFO DATA, EXECUTE THE FOLLOWING FROM THE CONTROLS/TEST DIR: + * java -classpath build/classes/beans:../build/jars/controls.jar org.apache.beehive.controls.test.controls.util.ControlIntrospector org.apache.beehive.controls.test.controls.beaninfo.InfoTestBean + */ +public class BeanInfoTest extends TestCase { + + private static final String BEANINFO = "org/apache/beehive/controls/test/junit/beaninfo/InfoTestBean.beaninfo"; + + public void testBeanInfo() throws Exception { + + File tempFile = File.createTempFile(getClass().getSimpleName(), ".beaninfo"); + boolean same = ControlTestUtils.compareBeanInfo(BEANINFO, tempFile, InfoTestBean.class); + + if(!same) + fail("Generated beaninfo file " + tempFile + " differs from expected beaninfo " + BEANINFO + " in classloader"); + else tempFile.delete(); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/beaninfo/InfoTestBean.beaninfo b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/beaninfo/InfoTestBean.beaninfo new file mode 100644 index 0000000..27df070 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/beaninfo/InfoTestBean.beaninfo @@ -0,0 +1,196 @@ + + + + + + + + + + + + org.apache.beehive.controls.test.controls.beaninfo.InfoTestBean + + + + + public abstract void org.apache.beehive.controls.test.controls.beaninfo.InfoTest.infoTestMethod(int,java.lang.Class) + + + + + + anIntArg + + + + + + + aClassArg + + + + + + + + + + + + + + type="int" + isBound=true + isConstrained=false + isDefault=false> + + public int org.apache.beehive.controls.test.controls.beaninfo.InfoTestBean.getProp1() + + + public synchronized void org.apache.beehive.controls.test.controls.beaninfo.InfoTestBean.setProp1(int) + + + + + + + + + type="java.lang.String" + isBound=false + isConstrained=false + isDefault=false> + + public java.lang.String org.apache.beehive.controls.test.controls.beaninfo.InfoTestBean.getControlImplementation() + + + public synchronized void org.apache.beehive.controls.test.controls.beaninfo.InfoTestBean.setControlImplementation(java.lang.String) + + + + controlImplementation + + + + + type="boolean" + isBound=false + isConstrained=false + isDefault=false> + + public boolean org.apache.beehive.controls.test.controls.beaninfo.InfoTestBean.isProp2() + + + public synchronized void org.apache.beehive.controls.test.controls.beaninfo.InfoTestBean.setProp2(boolean) + + + + prop2 + + + + + + + + org.apache.beehive.controls.test.controls.beaninfo.InfoTest$TestEvents + + + public synchronized void org.apache.beehive.controls.test.controls.beaninfo.InfoTestBean.addTestEventsListener(org.apache.beehive.controls.test.controls.beaninfo.InfoTest$TestEvents) throws java.util.TooManyListenersException + + + public synchronized void org.apache.beehive.controls.test.controls.beaninfo.InfoTestBean.removeTestEventsListener(org.apache.beehive.controls.test.controls.beaninfo.InfoTest$TestEvents) + + + public synchronized org.apache.beehive.controls.test.controls.beaninfo.InfoTest$TestEvents[] org.apache.beehive.controls.test.controls.beaninfo.InfoTestBean.getTestEventsListeners() + + + + public abstract void org.apache.beehive.controls.test.controls.beaninfo.InfoTest$TestEvents.eventMethod1() + + + + + + + + + + public abstract int org.apache.beehive.controls.test.controls.beaninfo.InfoTest$TestEvents.eventMethod2(java.lang.String) + + + + + + stringArg + + + + + + + eventMethod2 + + + + + + + testEvents + + + + + diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/composition/ComposerTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/composition/ComposerTest.java new file mode 100644 index 0000000..f8bce79 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/composition/ComposerTest.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit.composition; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.test.junit.ControlTestCase; +import org.apache.beehive.controls.test.controls.composition.ComposerBean; + +import java.util.Arrays; + +/** + * A TestCase that tests controls context services + */ +public class ComposerTest extends ControlTestCase { + @Control + private ComposerBean _composer; + + /** + * Tests basic Context events for Controls + */ + public void testNestedControlEvents() throws Exception { + _composer.invokeNestedControls(); + String expected[] = {"nested1ReturnVoid", "nested1ReturnInt", "nested1ReturnString"}; + assertTrue(Arrays.equals(expected, _composer.getEventLog())); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/composition/ProgrammaticTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/composition/ProgrammaticTest.java new file mode 100644 index 0000000..c673edb --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/composition/ProgrammaticTest.java @@ -0,0 +1,150 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit.composition; + +import junit.framework.Assert; +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.api.bean.Controls; +import org.apache.beehive.controls.test.controls.composition.InnerControlBean; +import org.apache.beehive.controls.test.controls.composition.OuterControlBean; +import org.apache.beehive.controls.test.junit.ControlTestCase; + +/** + * A TeseCase that tests control composition. The outer control is instantiated programmatically, and the outer + * control instantiates the nested control programmatically + */ +public class ProgrammaticTest extends ControlTestCase { + + @Control + private OuterControlBean _outer; + + /** + * A control that contains a nested control + */ + private OuterControlBean outerControl; + private OuterControlBean outerControl2; + + + /* Instantiate the outerControl once*/ + public void setUp() throws Exception { + super.setUp(); + + outerControl = (OuterControlBean) java.beans.Beans.instantiate(Thread.currentThread().getContextClassLoader(), + "org.apache.beehive.controls.test.controls.composition.OuterControlBean"); + + outerControl2 = (OuterControlBean) Controls.instantiate(Thread.currentThread().getContextClassLoader(), + "org.apache.beehive.controls.test.controls.composition.OuterControlBean", null); + } + + /** + * Tests outer control instantiats nested control by declaration + */ + public void testInstantiate() { + assertNotNull(outerControl); + assertNotNull(outerControl.instantiateNestedControlProgrammatically()); + + InnerControlBean innerBean = outerControl.instantiateNestedControlWithProperty(); + assertNotNull(innerBean); + assertEquals(innerBean.getName(), "ken"); + assertEquals(innerBean.getJob(), "engineer"); + assertTrue(innerBean.getRank() == 2); + assertNotNull(outerControl2); + } + + /** + * Tests outer control getting inner control property from control context + */ + public void testGetProppertyByContext() { + assertNotNull(outerControl); + InnerControlBean innercontrol = outerControl.instantiateNestedControlProgrammatically(); + assertNotNull(innercontrol); + assertEquals("Bob", innercontrol.getNameFromContext()); + assertNull(innercontrol.getJobFromContext()); + } + + /** + * Tests outer control getting inner control property by getter + */ + public void testGetProppertyByGetter() { + assertNotNull(outerControl); + InnerControlBean innercontrol = outerControl.instantiateNestedControlProgrammatically(); + assertNotNull(innercontrol); + assertEquals("Bob", innercontrol.getName()); + assertNull(innercontrol.getJob()); + } + + /** + * Tests outer control setting inner control property by setter + */ + public void testSetProppertyBySetter() { + assertNotNull(outerControl); + InnerControlBean innercontrol = outerControl.instantiateNestedControlProgrammatically(); + assertNotNull(innercontrol); + innercontrol.setName("new name"); + innercontrol.setJob("new job"); + assertEquals("new name", innercontrol.getNameFromContext()); + assertEquals("new job", innercontrol.getJobFromContext()); + } + + /** + * Tests reconfigured property. + * Outer control reconfigures the inner control's property when instantiating it + * Deactivated by CR190302 + */ + public void testReconfiguredProperty() { + assertNotNull(outerControl); + InnerControlBean innercontrol = outerControl.instantiateNestedControlWithProperty(); + assertNotNull(innercontrol); + assertEquals("ken", innercontrol.getNameFromContext()); + assertEquals("engineer", innercontrol.getJobFromContext()); + } + + /** + * Tests outer control receiving events from nested control using + * EventHandler + * This is deactivated, as declarative instantiating control in java is not supported + */ + public void testEventHandler() { + assertNotNull(outerControl); + assertEquals("0", outerControl.testActivityWakeup()); + assertEquals("0", outerControl.testActivityReadMessage()); + assertEquals("0", outerControl.testActivityReport()); + assertEquals("0", outerControl.testActionShopping()); + assertEquals("0", outerControl.testActionDostuff()); + } + + /** + * Tests outer control receiving events from nested control using + * inner class + */ + public void testEventInnerClass() { + assertNotNull(outerControl); + assertEquals("0", outerControl.testInnerClassListener()); + } + + /** + * Tests outer control receiving events from nested control using + * event listener + */ + public void testEventListener() { + assertNotNull(outerControl); + assertEquals("0", outerControl.testEventListener()); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/context/ContextParamTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/context/ContextParamTest.java new file mode 100644 index 0000000..20af3cb --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/context/ContextParamTest.java @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit.context; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.test.controls.context.ContextParam; +import org.apache.beehive.controls.test.controls.context.ContextParamExt; +import org.apache.beehive.controls.test.controls.context.ContextParamExtBean; +import org.apache.beehive.controls.test.junit.ControlTestCase; + +import java.lang.reflect.Method; + +/** + * A TestCase that tests controls context services + */ +public class ContextParamTest extends ControlTestCase { + + @Control + private ContextParamExtBean paramBean; + + /** + * Tests context access to parameter names + */ + public void testContextParamNames() throws Exception { + String [] paramNames; + Method intfMethod = ContextParam.class.getMethod("paramNameTest", Method.class); + Method extMethod = ContextParamExt.class.getMethod("valueTest", String.class, Integer.TYPE, Integer.TYPE, + Integer.TYPE, Integer.TYPE); + + // Try to read parameter names from methods declared on a base ControlInterface + paramNames = paramBean.paramNameTest(intfMethod); + assertNotNull(paramNames); + assertTrue(paramNames.length == intfMethod.getParameterTypes().length); + assertEquals(paramNames[0], "m"); + + // Try to read parameter names from methods declared on a ControlExtension + paramNames = paramBean.paramNameTest(extMethod); + assertNotNull(paramNames); + assertEquals(paramNames.length, extMethod.getParameterTypes().length); + assertEquals(paramNames[0], "paramName"); + assertEquals(paramNames[1], "firstArg"); + assertEquals(paramNames[2], "anotherArg"); + assertEquals(paramNames[3], "hasNoParam"); + assertEquals(paramNames[4], "lastArg"); + } + + /** + * Tests context access to parameter annotations + */ + public void testContextParamAnnotations() throws Exception { + Method extMethod = ContextParamExt.class.getMethod("valueTest", String.class, Integer.TYPE, Integer.TYPE, + Integer.TYPE, Integer.TYPE); + + ContextParam.Param [] paramAnnots = paramBean.paramAnnotTest(extMethod); + assertNotNull(paramAnnots); + assertEquals(paramAnnots.length, extMethod.getParameterTypes().length); + assertNotNull(paramAnnots[0]); + assertEquals(paramAnnots[0].value(), "paramName"); + assertNotNull(paramAnnots[1]); + assertEquals(paramAnnots[1].value(), "firstArg"); + assertNotNull(paramAnnots[2]); + assertEquals(paramAnnots[2].value(), "anotherArg"); + assertNull(paramAnnots[3]); + assertNotNull(paramAnnots[4]); + assertEquals(paramAnnots[4].value(), "lastArg"); + } + + /** + * Tests context access to parameter values by name + */ + public void testContextParamValues() throws Exception { + + assertEquals(0, paramBean.valueTest("firstArg", 0, 1, 2, 3)); + assertEquals(1, paramBean.valueTest("anotherArg", 0, 1, 2, 3)); + assertEquals(2, paramBean.valueTest("hasNoParam", 0, 1, 2, 3)); + assertEquals(3, paramBean.valueTest("lastArg", 0, 1, 2, 3)); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/context/ContextTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/context/ContextTest.java new file mode 100644 index 0000000..24caed7 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/context/ContextTest.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit.context; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.test.controls.context.BaseContextBean; +import org.apache.beehive.controls.test.junit.ControlTestCase; + +import java.util.Arrays; + +/** + * A TestCase that tests controls context services + */ +public class ContextTest extends ControlTestCase { + + @Control + private BaseContextBean _contextBean; + + /** + * Tests basic Context events for Controls + */ + public void testContextEventSingle() throws Exception { + + _contextBean.hello("kyle"); + String [] expectedEvents = new String []{"BaseContextImpl.onCreate", "BaseContextImpl.onAcquire", + "BaseContextImpl.hello kyle"}; + assertTrue(Arrays.equals(expectedEvents, _contextBean.getEventLog())); + + } + + /** + * Tests basic Context events for Controls for multiple invocations in the same context + */ + public void testContextEventMultiple() throws Exception { + + _contextBean.hello("ken"); + _contextBean.hello("mike"); + _contextBean.hello("lawrence"); + + String[] expectedEvents = new String []{"BaseContextImpl.onCreate", "BaseContextImpl.onAcquire", + "BaseContextImpl.hello ken", "BaseContextImpl.hello mike", + "BaseContextImpl.hello lawrence"}; + assertTrue(Arrays.equals(expectedEvents, _contextBean.getEventLog())); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/context/GetServiceTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/context/GetServiceTest.java new file mode 100644 index 0000000..137b9dc --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/context/GetServiceTest.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit.context; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.test.controls.context.ServiceGetterBean; +import org.apache.beehive.controls.test.junit.ControlTestCase; + +/** + * When a control is instantiated the web tier or a JWS, the Control runtime automatically associates + * it with the current active context. + * When a control is instantiated in the java test case, there is no active context. + * One approach is to use the MiltonControlContext that gets used in other places... + * A MiltonControlContext needs to be called to startContext before instantiating the control, + * then any newly instantiated control in the Java test will be associated with it. + */ +public class GetServiceTest extends ControlTestCase { + /** + * A control that exposes a function to access available services + * via the control context service + */ + @Control + private ServiceGetterBean _serviceGetter; + + /** + * Tests accessing ControlBeanContext via controls' context service. + * In java environment, this should be an instanceof ControlBeanContext + * The control is instantiated by declaration + */ + public void testGetServiceFromContextByDeclaration() throws Exception { + assertNotNull(_serviceGetter); + assertNotNull(_serviceGetter.getBeanContext()); + assertNotNull(_serviceGetter.getControlBeanContext()); + } + + /** + * Tests accessing servlet service via controls' context service + * In java environment, this should be "NULL" + * The control is instantiated programmatically + */ + public void testGetServiceFromContextByProgram() throws Exception { + ServiceGetterBean getterbean = (ServiceGetterBean) java.beans.Beans.instantiate( + Thread.currentThread().getContextClassLoader(), + "org.apache.beehive.controls.test.controls.context.ServiceGetterBean"); + assertNotNull(getterbean); + assertNotNull(getterbean.getBeanContext()); + assertNotNull(getterbean.getControlBeanContext()); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/event/Event2Listener.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/event/Event2Listener.java new file mode 100644 index 0000000..3dfb9b0 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/event/Event2Listener.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit.event; + +import org.apache.beehive.controls.test.controls.event.Hello; + +/** + * A listener class for Hello.EventSet2 event + */ +public class Event2Listener implements Hello.EventSet2 +{ + private String method1Result=""; + private String method2Result=""; + private String overloadMethod1=""; + private String overloadMethod2=""; + + + public void method1(){ + //Event received, flip the counter + method1Result="0"; + } + public int set2Method2(){ + //Event received, flip the counter + method2Result="0"; + return 0; + } + public boolean set2OverloadedMethod(){ + //Event received, flip the counter + overloadMethod1="0"; + return true; + } + public boolean set2OverloadedMethod(int anArg){ + //Event received, flip the counter + overloadMethod2="0"; + return true; + } + + public String getMethod2Result(){ + + return method2Result; + } + + public String getAllResult(){ + + return method1Result+method2Result+overloadMethod1+overloadMethod2; + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/event/EventHandlerTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/event/EventHandlerTest.java new file mode 100644 index 0000000..7d37eb9 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/event/EventHandlerTest.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit.event; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.api.events.EventHandler; +import org.apache.beehive.controls.test.controls.event.HelloBean; +import org.apache.beehive.controls.test.junit.ControlTestCase; + +/** + * A TestCase that tests receiving events from a control by @EventHandler + * All tests on controls instantiated declaratively are deactivated until this feature is supported. + */ +public class EventHandlerTest extends ControlTestCase { + private boolean event1Received = false; + private boolean event2Received = false; + + /** + * A control that raises events + */ + @Control + private HelloBean myHellobean; + + /** + * EventHandler that receives EventSet1 from myHelloBean + */ + @EventHandler(field = "myHellobean", + eventSet = HelloBean.EventSet1.class, + eventName = "method1") + public void myHelloBeanMessageHandler() { + // Invoked with event is received + event1Received = true; + } + + /** + * EventHandler that receives EventSet2 from myHelloBean + */ + @EventHandler(field = "myHellobean", + eventSet = HelloBean.EventSet2.class, + eventName = "set2Method2") + public int myHelloBeanMessageHandler2() { + // Invoked when event is received + event2Received = true; + return 0; + } + + /** + * Triggers the events and waits for the arrivals of the events + */ + public void testHandlerReceiveEvents() throws Exception { + assertNotNull(myHellobean); + + // Invokes the method on the control while will trigger the events + myHellobean.triggerEvents(); + + /*Wait for the events*/ + Thread.sleep(1000); + + /*Verified result*/ + assertTrue(event1Received); + assertTrue(event2Received); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/event/EventSetInheritanceTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/event/EventSetInheritanceTest.java new file mode 100644 index 0000000..f8d2973 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/event/EventSetInheritanceTest.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit.event; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.api.events.EventHandler; +import org.apache.beehive.controls.test.controls.eventsetInheritance.CtrlExt; +import org.apache.beehive.controls.test.junit.ControlTestCase; + +/** + * Junit test to verify that eventset inheritance is working correctly at both compile time and run time. + */ +public class EventSetInheritanceTest + extends ControlTestCase { + + @Control + private CtrlExt _ctrlExt; + + private boolean _handlerInvoked; + + public void setUp() throws Exception { + super.setUp(); + _handlerInvoked = false; + } + + /** + * Test event set inheritance. + */ + public void testEventSetInheritance() { + assertNotNull(_ctrlExt); + _ctrlExt.runTest(); + assertTrue(_handlerInvoked); + } + + @EventHandler(field="_ctrlExt", eventSet=CtrlExt.CtrlExtCallback.class, eventName="baseEventSetMethod") + public void myHandler() { + _handlerInvoked = true; + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/event/EventsetAptTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/event/EventsetAptTest.java new file mode 100644 index 0000000..befdecc --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/event/EventsetAptTest.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.test.junit.event; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.test.controls.eventsetApt.MulticastExt; +import org.apache.beehive.controls.test.controls.eventsetApt.UnicastExt; +import org.apache.beehive.controls.test.controls.eventsetApt.NoMethodsExt; +import org.apache.beehive.controls.test.controls.eventsetControlExt.EventExt; +import org.apache.beehive.controls.test.controls.emptyeventset.EmptyEvent; +import org.apache.beehive.controls.test.junit.ControlTestCase; + +/** + * Junit tests for making sure that APT can generate controls with eventsets when + * the extended controls event set has the same name as the base control's event set. + * + * If this doesn't work compilation will fail, all thats really necessary here is + * to verify the controls can be initialized. + */ +public class EventsetAptTest + extends ControlTestCase { + + @Control + private MulticastExt _multicastEvts; + + @Control + private UnicastExt _unicastEvts; + + @Control + private NoMethodsExt _noMethods; + + @Control + private EmptyEvent _emptyEvent; + + @Control + private EventExt _eventExt; + + /** + * Test multicast event set. + */ + public void testMulticastEvtApt() { + assertNotNull(_multicastEvts); + } + + /** + * Test unicast event set. + */ + public void testUnicastEvtApt() { + assertNotNull(_unicastEvts); + } + + /** + * Test to verify that a control extension whose base class contains an event set is + * properly generated by apt. Failure results in a compilation error. + */ + public void testEventExt() { + assertNotNull(_unicastEvts); + } + + /** + * test case for extended control with no interface methods, + * but an event set with an annotated member. This is + * an apt compilation test only. + */ + public void testNoMethodsEvtSet() { + assertNotNull(_noMethods); + } + + /** + * Test compilation of an event set with no methods. + */ + public void testEmptyEventSet() { + assertNotNull(_emptyEvent); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/event/ListenerTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/event/ListenerTest.java new file mode 100644 index 0000000..8c41b86 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/event/ListenerTest.java @@ -0,0 +1,110 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit.event; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.test.controls.event.Hello; +import org.apache.beehive.controls.test.controls.event.HelloBean; +import org.apache.beehive.controls.test.junit.ControlTestCase; + +/** + * A Testcase that tests receiving events from a control with an inner class or + * an instance of listener class. + * All tests on controls instantiated declaratively are deactivated until this feature is supported. + */ +public class ListenerTest extends ControlTestCase { + + /** + * A control that raises events + */ + @Control + private HelloBean _myHellobean; + private boolean innerClassReceiveEvent = false; + private Event2Listener event2listener; + + /* + * 1. Instantiates a control bean programmatically; + * 2. Registers two event listeners to the bean instance; + * 3. Invokes the method on the bean instance that triggers the event1 and event2 + */ + public void testListenerReceiveEventsProgram() throws Exception { + HelloBean hellobean = (HelloBean) java.beans.Beans.instantiate( + Thread.currentThread().getContextClassLoader(), + "org.apache.beehive.controls.test.controls.event.HelloBean"); + receiveEventsHelper(hellobean, false); + } + + // todo: control handles not currently supported by the ControlTestContainer +// public void testListenerReceiveEventsProgramUsingHandle() +// throws Exception { +// HelloBean hellobean = (HelloBean) java.beans.Beans.instantiate( +// Thread.currentThread().getContextClassLoader(), +// "org.apache.beehive.controls.test.controls.event.HelloBean"); +// receiveEventsHelper(hellobean, true); +// } + + /* + * 1. Instantiates a control bean by declaration; + * 2. Registers two event listeners to the bean instance; + * 3. Invokes the method on the bean instance that triggers the event1 and event2 + */ + public void testListenerReceiveEventsDeclare() throws Exception { + receiveEventsHelper(_myHellobean, false); + } + + // todo: control handles not currently supported by the ControlTestContainer +// public void testListenerReceiveEventsDeclareUsingHandle() throws Exception { +// receiveEventsHelper(_myHellobean, true); +// } + + /* + * Main body of test logic used by the various programmatic and declarative tests + */ + private void receiveEventsHelper(HelloBean hellobean, boolean useHandle) throws Exception { + + assertNotNull(hellobean); + + // Register an inner class as listener for event1 + hellobean.addEventSet1Listener( + new Hello.EventSet1() { + public void method1() { + innerClassReceiveEvent = true; + } + }); + + // Creates a listener for event2 and register it + event2listener = new Event2Listener(); + hellobean.addEventSet2Listener(event2listener); + + // Invokes methods on myHelloBean to trigger the events + if (!useHandle) { + hellobean.triggerEvents(); + } + else { + hellobean.triggerEventsUsingHandle(); + } + + Thread.sleep(1000); + + assertTrue(innerClassReceiveEvent); + assertNotNull(event2listener); + assertEquals("0000", event2listener.getAllResult()); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/generic/GenericTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/generic/GenericTest.java new file mode 100644 index 0000000..faa035f --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/generic/GenericTest.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit.generic; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.api.events.EventHandler; +import org.apache.beehive.controls.test.controls.generic.ListControl; +import org.apache.beehive.controls.test.controls.generic.ListControlBean; +import org.apache.beehive.controls.test.junit.ControlTestCase; + +import java.util.ArrayList; +import java.util.LinkedList; + +/** + * A TestCase that tests control composition. + * The outer control is instantiated declaratively, and the outer + * control instantiates the nested control declaratively + *

    + * Instantiating controls declaratively is not supported currently. + * All tests are deactivated until this is supported + */ +public class GenericTest extends ControlTestCase { + /** + * A control that contains a nested control + */ + @Control + @ListControl.ListProps(listClass = ArrayList.class) + private ListControlBean> stringBean; + + /** + * Declare a specific bound event handler to process events. Note that the parameter and + * return type are bound to 'String', based upon the field declaration binding + * (E -> String) above + */ + @EventHandler(field = "stringBean", eventSet = ListControl.ListEvents.class, eventName = "onAdd") + public String onAdd(String addString) { + _addString = addString; + return addString; + } + + private String _addString; + + /** + * Tests usage of a generic control type/event handler that are declaratively instantiated + */ + public void testDeclarative() throws Exception { + // Test invoking a bound operation, this should also result in the above event + // handler being called in a bound fashion + stringBean.add("foo"); + assertEquals("foo", _addString); + } + + private int _newInt; + + /** + * Tests usage of a generic control type/event handler that are programmatic instantiated + */ + public void testProgrammatic() throws Exception { + ListControlBean> intBean = new ListControlBean>(); + intBean.setListClass(LinkedList.class); + intBean.addListEventsListener( + new ListControl.ListEvents() { + public Integer onAdd(Integer newInt) { + _newInt = newInt; + return newInt; + } + } + ); + intBean.add(3); + assertEquals(3, _newInt); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/generic/SimpleControlTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/generic/SimpleControlTest.java new file mode 100644 index 0000000..fbe4d71 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/generic/SimpleControlTest.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit.generic; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.test.controls.generic.SimpleControlBean; +import org.apache.beehive.controls.test.junit.ControlTestCase; + +import java.util.Vector; + +/** + * A TestCase that tests Java generics on controls + */ +public class SimpleControlTest extends ControlTestCase +{ + /** + * A control that contains a nested control + */ + @Control + private SimpleControlBean stringBean; + + /** + * Tests instantiating SimpleControlBean declaratively + */ + public void testDeclarative() throws Exception + { + // Test invoking a bound operation, this should also result in the above event + // handler being called in a bound fashion + Vector strings=new Vector(); + strings.add("One"); + strings.add("Two"); + + stringBean.setThem(strings); + + assertEquals("One", stringBean.getTheFirst()); + } + + /** + * Tests instantiating SimpleControlBean programmatically + */ + public void testProgrammatic() throws Exception + { + Vector strings=new Vector(); + strings.add("One"); + strings.add("Two"); + + + SimpleControlBean sbean=(SimpleControlBean)java.beans.Beans.instantiate( + Thread.currentThread().getContextClassLoader() , + "org.apache.beehive.controls.test.controls.generic.SimpleControlBean"); + + sbean.setThem(strings); + assertEquals("One", sbean.getTheFirst()); + } + +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/inherit/Ext1Bean.beaninfo b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/inherit/Ext1Bean.beaninfo new file mode 100644 index 0000000..8d10029 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/inherit/Ext1Bean.beaninfo @@ -0,0 +1,893 @@ + + + + + Ext1Bean + + + + + + + org.apache.beehive.controls.test.controls.inherit.Ext1Bean + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.AddIn.addInOperation1() + + + + + addInOperation1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.AddIn.addInOperation2() + + + + + addInOperation2 + + + + + public abstract int[] org.apache.beehive.controls.test.controls.inherit.Ext1.ext1Operation1() + + + + + ext1Operation1 + + + + + public abstract int[] org.apache.beehive.controls.test.controls.inherit.Ext1.ext1Operation2() + + + + + ext1Operation2 + + + + + public abstract int org.apache.beehive.controls.test.controls.inherit.Intf1.intf1Operation1() + + + + + intf1Operation1 + + + + + public abstract int org.apache.beehive.controls.test.controls.inherit.Intf1.intf1Operation2() + + + + + intf1Operation2 + + + + + public abstract int org.apache.beehive.controls.test.controls.inherit.Intf2.intf2Operation1() + + + + + intf2Operation1 + + + + + public abstract int org.apache.beehive.controls.test.controls.inherit.Intf2.intf2Operation2() + + + + + intf2Operation2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Root.rootOperation1() + + + + + rootOperation1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Root.rootOperation2() + + + + + rootOperation2 + + + + + + + type="java.lang.String" + isBound=false + isConstrained=false + isDefault=false> + + public java.lang.String org.apache.beehive.controls.test.controls.inherit.Intf1Bean.getControlImplementation() + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf1Bean.setControlImplementation(java.lang.String) + + + + controlImplementation + + + + + type="int" + isBound=false + isConstrained=false + isDefault=false> + + public int org.apache.beehive.controls.test.controls.inherit.Intf1Bean.getIntf1Prop1() + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf1Bean.setIntf1Prop1(int) + + + + intf1Prop1 + + + + + type="int" + isBound=false + isConstrained=false + isDefault=false> + + public int org.apache.beehive.controls.test.controls.inherit.Intf1Bean.getIntf1Prop2() + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf1Bean.setIntf1Prop2(int) + + + + intf1Prop2 + + + + + type="int" + isBound=false + isConstrained=false + isDefault=false> + + public int org.apache.beehive.controls.test.controls.inherit.Intf2Bean.getIntf2Prop1() + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf2Bean.setIntf2Prop1(int) + + + + intf2Prop1 + + + + + type="int" + isBound=false + isConstrained=false + isDefault=false> + + public int org.apache.beehive.controls.test.controls.inherit.Intf2Bean.getIntf2Prop2() + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf2Bean.setIntf2Prop2(int) + + + + intf2Prop2 + + + + + + + + org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2NewEvents + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf2Bean.addIntf2NewEventsListener(org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2NewEvents) throws java.util.TooManyListenersException + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf2Bean.removeIntf2NewEventsListener(org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2NewEvents) + + + public synchronized org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2NewEvents[] org.apache.beehive.controls.test.controls.inherit.Intf2Bean.getIntf2NewEventsListeners() + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.AddIn$AddInEvents.addInEvent1() + + + + + addInEvent1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.AddIn$AddInEvents.addInEvent2() + + + + + addInEvent2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2NewEvents.intf2NewEvent1() + + + + + intf2NewEvent1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2NewEvents.intf2NewEvent2() + + + + + intf2NewEvent2 + + + + + + + intf2NewEvents + + + + + org.apache.beehive.controls.test.controls.inherit.Ext1$Ext1NewEvents + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Ext1Bean.addExt1NewEventsListener(org.apache.beehive.controls.test.controls.inherit.Ext1$Ext1NewEvents) throws java.util.TooManyListenersException + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Ext1Bean.removeExt1NewEventsListener(org.apache.beehive.controls.test.controls.inherit.Ext1$Ext1NewEvents) + + + public synchronized org.apache.beehive.controls.test.controls.inherit.Ext1$Ext1NewEvents[] org.apache.beehive.controls.test.controls.inherit.Ext1Bean.getExt1NewEventsListeners() + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Ext1$Ext1NewEvents.ext1NewEvent1() + + + + + ext1NewEvent1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Ext1$Ext1NewEvents.ext2NewEvent2() + + + + + ext2NewEvent2 + + + + + + + ext1NewEvents + + + + + org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf1Bean.addIntf1EventsListener(org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events) + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf1Bean.removeIntf1EventsListener(org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events) + + + public synchronized org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events[] org.apache.beehive.controls.test.controls.inherit.Intf1Bean.getIntf1EventsListeners() + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events.intf1Event1() + + + + + intf1Event1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events.intf1Event2() + + + + + intf1Event2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Root$RootEvents.rootEvent1() + + + + + rootEvent1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Root$RootEvents.rootEvent2() + + + + + rootEvent2 + + + + + + + intf1Events + + + + + org.apache.beehive.controls.test.controls.inherit.Ext1$Ext1Events + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Ext1Bean.addExt1EventsListener(org.apache.beehive.controls.test.controls.inherit.Ext1$Ext1Events) + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Ext1Bean.removeExt1EventsListener(org.apache.beehive.controls.test.controls.inherit.Ext1$Ext1Events) + + + public synchronized org.apache.beehive.controls.test.controls.inherit.Ext1$Ext1Events[] org.apache.beehive.controls.test.controls.inherit.Ext1Bean.getExt1EventsListeners() + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.AddIn$AddInEvents.addInEvent1() + + + + + addInEvent1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.AddIn$AddInEvents.addInEvent2() + + + + + addInEvent2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Ext1$Ext1Events.ext1Event1() + + + + + ext1Event1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Ext1$Ext1Events.ext1Event2() + + + + + ext1Event2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events.intf1Event1() + + + + + intf1Event1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events.intf1Event2() + + + + + intf1Event2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2Events.intf2Event1() + + + + + intf2Event1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2Events.intf2Event2() + + + + + intf2Event2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Root$RootEvents.rootEvent1() + + + + + rootEvent1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Root$RootEvents.rootEvent2() + + + + + rootEvent2 + + + + + + + ext1Events + + + + + org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1NewEvents + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf1Bean.addIntf1NewEventsListener(org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1NewEvents) throws java.util.TooManyListenersException + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf1Bean.removeIntf1NewEventsListener(org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1NewEvents) + + + public synchronized org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1NewEvents[] org.apache.beehive.controls.test.controls.inherit.Intf1Bean.getIntf1NewEventsListeners() + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1NewEvents.intf1NewEvent1() + + + + + intf1NewEvent1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1NewEvents.intf1NewEvent2() + + + + + intf1NewEvent2 + + + + + + + intf1NewEvents + + + + + org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2Events + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf2Bean.addIntf2EventsListener(org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2Events) + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf2Bean.removeIntf2EventsListener(org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2Events) + + + public synchronized org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2Events[] org.apache.beehive.controls.test.controls.inherit.Intf2Bean.getIntf2EventsListeners() + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.AddIn$AddInEvents.addInEvent1() + + + + + addInEvent1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.AddIn$AddInEvents.addInEvent2() + + + + + addInEvent2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events.intf1Event1() + + + + + intf1Event1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events.intf1Event2() + + + + + intf1Event2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2Events.intf2Event1() + + + + + intf2Event1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2Events.intf2Event2() + + + + + intf2Event2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Root$RootEvents.rootEvent1() + + + + + rootEvent1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Root$RootEvents.rootEvent2() + + + + + rootEvent2 + + + + + + + intf2Events + + + + + diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/inherit/Ext2Bean.beaninfo b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/inherit/Ext2Bean.beaninfo new file mode 100644 index 0000000..0ce1d03 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/inherit/Ext2Bean.beaninfo @@ -0,0 +1,1364 @@ + + + + + Ext2Bean + + + + + + + org.apache.beehive.controls.test.controls.inherit.Ext2Bean + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.AddIn.addInOperation1() + + + + + addInOperation1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.AddIn.addInOperation2() + + + + + addInOperation2 + + + + + public abstract int[] org.apache.beehive.controls.test.controls.inherit.Ext1.ext1Operation1() + + + + + ext1Operation1 + + + + + public abstract int[] org.apache.beehive.controls.test.controls.inherit.Ext1.ext1Operation2() + + + + + ext1Operation2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Ext2.ext2Operation1() + + + + + ext2Operation1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Ext2.ext2Operation2() + + + + + ext2Operation2 + + + + + public abstract int org.apache.beehive.controls.test.controls.inherit.Intf1.intf1Operation1() + + + + + intf1Operation1 + + + + + public abstract int org.apache.beehive.controls.test.controls.inherit.Intf1.intf1Operation2() + + + + + intf1Operation2 + + + + + public abstract int org.apache.beehive.controls.test.controls.inherit.Intf2.intf2Operation1() + + + + + intf2Operation1 + + + + + public abstract int org.apache.beehive.controls.test.controls.inherit.Intf2.intf2Operation2() + + + + + intf2Operation2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Root.rootOperation1() + + + + + rootOperation1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Root.rootOperation2() + + + + + rootOperation2 + + + + + + + type="java.lang.String" + isBound=false + isConstrained=false + isDefault=false> + + public java.lang.String org.apache.beehive.controls.test.controls.inherit.Intf1Bean.getControlImplementation() + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf1Bean.setControlImplementation(java.lang.String) + + + + controlImplementation + + + + + type="int" + isBound=false + isConstrained=false + isDefault=false> + + public int org.apache.beehive.controls.test.controls.inherit.Intf1Bean.getIntf1Prop1() + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf1Bean.setIntf1Prop1(int) + + + + intf1Prop1 + + + + + type="int" + isBound=false + isConstrained=false + isDefault=false> + + public int org.apache.beehive.controls.test.controls.inherit.Intf1Bean.getIntf1Prop2() + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf1Bean.setIntf1Prop2(int) + + + + intf1Prop2 + + + + + type="int" + isBound=false + isConstrained=false + isDefault=false> + + public int org.apache.beehive.controls.test.controls.inherit.Intf2Bean.getIntf2Prop1() + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf2Bean.setIntf2Prop1(int) + + + + intf2Prop1 + + + + + type="int" + isBound=false + isConstrained=false + isDefault=false> + + public int org.apache.beehive.controls.test.controls.inherit.Intf2Bean.getIntf2Prop2() + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf2Bean.setIntf2Prop2(int) + + + + intf2Prop2 + + + + + + + + org.apache.beehive.controls.test.controls.inherit.Ext2$Ext2SkipEvents + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Ext2Bean.addExt2SkipEventsListener(org.apache.beehive.controls.test.controls.inherit.Ext2$Ext2SkipEvents) + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Ext2Bean.removeExt2SkipEventsListener(org.apache.beehive.controls.test.controls.inherit.Ext2$Ext2SkipEvents) + + + public synchronized org.apache.beehive.controls.test.controls.inherit.Ext2$Ext2SkipEvents[] org.apache.beehive.controls.test.controls.inherit.Ext2Bean.getExt2SkipEventsListeners() + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.AddIn$AddInEvents.addInEvent1() + + + + + addInEvent1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.AddIn$AddInEvents.addInEvent2() + + + + + addInEvent2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Ext2$Ext2SkipEvents.extSkip2Event1() + + + + + extSkip2Event1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Ext2$Ext2SkipEvents.extSkip2Event2() + + + + + extSkip2Event2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events.intf1Event1() + + + + + intf1Event1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events.intf1Event2() + + + + + intf1Event2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2Events.intf2Event1() + + + + + intf2Event1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2Events.intf2Event2() + + + + + intf2Event2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Root$RootEvents.rootEvent1() + + + + + rootEvent1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Root$RootEvents.rootEvent2() + + + + + rootEvent2 + + + + + + + ext2SkipEvents + + + + + org.apache.beehive.controls.test.controls.inherit.Ext2$Ext2NewEvents + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Ext2Bean.addExt2NewEventsListener(org.apache.beehive.controls.test.controls.inherit.Ext2$Ext2NewEvents) throws java.util.TooManyListenersException + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Ext2Bean.removeExt2NewEventsListener(org.apache.beehive.controls.test.controls.inherit.Ext2$Ext2NewEvents) + + + public synchronized org.apache.beehive.controls.test.controls.inherit.Ext2$Ext2NewEvents[] org.apache.beehive.controls.test.controls.inherit.Ext2Bean.getExt2NewEventsListeners() + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Ext2$Ext2NewEvents.ext2NewEvent1() + + + + + ext2NewEvent1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Ext2$Ext2NewEvents.ext2NewEvent2() + + + + + ext2NewEvent2 + + + + + + + ext2NewEvents + + + + + org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2NewEvents + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf2Bean.addIntf2NewEventsListener(org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2NewEvents) throws java.util.TooManyListenersException + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf2Bean.removeIntf2NewEventsListener(org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2NewEvents) + + + public synchronized org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2NewEvents[] org.apache.beehive.controls.test.controls.inherit.Intf2Bean.getIntf2NewEventsListeners() + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.AddIn$AddInEvents.addInEvent1() + + + + + addInEvent1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.AddIn$AddInEvents.addInEvent2() + + + + + addInEvent2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2NewEvents.intf2NewEvent1() + + + + + intf2NewEvent1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2NewEvents.intf2NewEvent2() + + + + + intf2NewEvent2 + + + + + + + intf2NewEvents + + + + + org.apache.beehive.controls.test.controls.inherit.Ext1$Ext1NewEvents + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Ext1Bean.addExt1NewEventsListener(org.apache.beehive.controls.test.controls.inherit.Ext1$Ext1NewEvents) throws java.util.TooManyListenersException + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Ext1Bean.removeExt1NewEventsListener(org.apache.beehive.controls.test.controls.inherit.Ext1$Ext1NewEvents) + + + public synchronized org.apache.beehive.controls.test.controls.inherit.Ext1$Ext1NewEvents[] org.apache.beehive.controls.test.controls.inherit.Ext1Bean.getExt1NewEventsListeners() + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Ext1$Ext1NewEvents.ext1NewEvent1() + + + + + ext1NewEvent1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Ext1$Ext1NewEvents.ext2NewEvent2() + + + + + ext2NewEvent2 + + + + + + + ext1NewEvents + + + + + org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf1Bean.addIntf1EventsListener(org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events) + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf1Bean.removeIntf1EventsListener(org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events) + + + public synchronized org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events[] org.apache.beehive.controls.test.controls.inherit.Intf1Bean.getIntf1EventsListeners() + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events.intf1Event1() + + + + + intf1Event1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events.intf1Event2() + + + + + intf1Event2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Root$RootEvents.rootEvent1() + + + + + rootEvent1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Root$RootEvents.rootEvent2() + + + + + rootEvent2 + + + + + + + intf1Events + + + + + org.apache.beehive.controls.test.controls.inherit.Ext1$Ext1Events + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Ext1Bean.addExt1EventsListener(org.apache.beehive.controls.test.controls.inherit.Ext1$Ext1Events) + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Ext1Bean.removeExt1EventsListener(org.apache.beehive.controls.test.controls.inherit.Ext1$Ext1Events) + + + public synchronized org.apache.beehive.controls.test.controls.inherit.Ext1$Ext1Events[] org.apache.beehive.controls.test.controls.inherit.Ext1Bean.getExt1EventsListeners() + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.AddIn$AddInEvents.addInEvent1() + + + + + addInEvent1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.AddIn$AddInEvents.addInEvent2() + + + + + addInEvent2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Ext1$Ext1Events.ext1Event1() + + + + + ext1Event1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Ext1$Ext1Events.ext1Event2() + + + + + ext1Event2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events.intf1Event1() + + + + + intf1Event1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events.intf1Event2() + + + + + intf1Event2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2Events.intf2Event1() + + + + + intf2Event1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2Events.intf2Event2() + + + + + intf2Event2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Root$RootEvents.rootEvent1() + + + + + rootEvent1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Root$RootEvents.rootEvent2() + + + + + rootEvent2 + + + + + + + ext1Events + + + + + org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1NewEvents + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf1Bean.addIntf1NewEventsListener(org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1NewEvents) throws java.util.TooManyListenersException + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf1Bean.removeIntf1NewEventsListener(org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1NewEvents) + + + public synchronized org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1NewEvents[] org.apache.beehive.controls.test.controls.inherit.Intf1Bean.getIntf1NewEventsListeners() + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1NewEvents.intf1NewEvent1() + + + + + intf1NewEvent1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1NewEvents.intf1NewEvent2() + + + + + intf1NewEvent2 + + + + + + + intf1NewEvents + + + + + org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2Events + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf2Bean.addIntf2EventsListener(org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2Events) + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf2Bean.removeIntf2EventsListener(org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2Events) + + + public synchronized org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2Events[] org.apache.beehive.controls.test.controls.inherit.Intf2Bean.getIntf2EventsListeners() + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.AddIn$AddInEvents.addInEvent1() + + + + + addInEvent1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.AddIn$AddInEvents.addInEvent2() + + + + + addInEvent2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events.intf1Event1() + + + + + intf1Event1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events.intf1Event2() + + + + + intf1Event2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2Events.intf2Event1() + + + + + intf2Event1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2Events.intf2Event2() + + + + + intf2Event2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Root$RootEvents.rootEvent1() + + + + + rootEvent1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Root$RootEvents.rootEvent2() + + + + + rootEvent2 + + + + + + + intf2Events + + + + + org.apache.beehive.controls.test.controls.inherit.Ext2$Ext2Events + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Ext2Bean.addExt2EventsListener(org.apache.beehive.controls.test.controls.inherit.Ext2$Ext2Events) + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Ext2Bean.removeExt2EventsListener(org.apache.beehive.controls.test.controls.inherit.Ext2$Ext2Events) + + + public synchronized org.apache.beehive.controls.test.controls.inherit.Ext2$Ext2Events[] org.apache.beehive.controls.test.controls.inherit.Ext2Bean.getExt2EventsListeners() + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.AddIn$AddInEvents.addInEvent1() + + + + + addInEvent1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.AddIn$AddInEvents.addInEvent2() + + + + + addInEvent2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Ext1$Ext1Events.ext1Event1() + + + + + ext1Event1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Ext1$Ext1Events.ext1Event2() + + + + + ext1Event2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Ext2$Ext2Events.ext2Event1() + + + + + ext2Event1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Ext2$Ext2Events.ext2Event2() + + + + + ext2Event2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events.intf1Event1() + + + + + intf1Event1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events.intf1Event2() + + + + + intf1Event2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2Events.intf2Event1() + + + + + intf2Event1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2Events.intf2Event2() + + + + + intf2Event2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Root$RootEvents.rootEvent1() + + + + + rootEvent1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Root$RootEvents.rootEvent2() + + + + + rootEvent2 + + + + + + + ext2Events + + + + + diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/inherit/InheritTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/inherit/InheritTest.java new file mode 100644 index 0000000..768ef76 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/inherit/InheritTest.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit.inherit; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.FileInputStream; + +import junit.framework.TestCase; +import org.apache.beehive.controls.test.junit.utils.ControlTestUtils; + +/** + * A TestCase that tests control interface, extension, and implementation inheritance + */ +public class InheritTest extends TestCase { + + /** + * Verifies the generated BeanInfo for Intf1 + */ + public void testIntf1BeanInfo() throws Exception { + validateBeanInfo("Intf1Bean"); + } + + /** + * Verifies the generated BeanInfo for Intf2 + */ + public void testIntf2BeanInfo() throws Exception { + validateBeanInfo("Intf2Bean"); + } + + /** + * Verifies the generated BeanInfo for Ext1 + */ + public void testExt1BeanInfo() throws Exception { + validateBeanInfo("Ext1Bean"); + } + + /** + * Verifies the generated BeanInfo for Ext2 + */ + public void testExt2BeanInfo() throws Exception { + validateBeanInfo("Ext2Bean"); + } + + private void validateBeanInfo(String simpleName) + throws Exception { + + String beanClassName = "org.apache.beehive.controls.test.controls.inherit." + simpleName; + String beanInfo = "org/apache/beehive/controls/test/junit/inherit/" + simpleName + ".beaninfo"; + + File tempFile = File.createTempFile(simpleName, ".beaninfo"); + boolean same = ControlTestUtils.compareBeanInfo(beanInfo, tempFile, Class.forName(beanClassName)); + + if(!same) + fail("Generated beaninfo file " + tempFile + " differs from expected beaninfo " + beanInfo + " in classloader"); + else tempFile.delete(); + } + /* + + File tempFile = null; + FileOutputStream fos = null; + try { + tempFile = File.createTempFile(shortName, ".beaninfo"); + fos = new FileOutputStream(tempFile); + + Class beanClass = Class.forName(beanClassName); + ControlIntrospector ci = new ControlIntrospector(beanClass, fos); + ci.introspect(); + } + finally { + if(fos != null) + fos.close(); + } + + InputStream expected = null; + InputStream actual = null; + try { + expected = getClass().getClassLoader().getResourceAsStream(beanInfo); + + if (expected == null) + fail("Could not locate expected beaninfo file \"" + beanInfo + "\""); + + actual = new FileInputStream(tempFile); + + boolean same = ControlTestUtils.compareFiles(expected, actual); + + if(!same) + fail("File " + tempFile.getName() " differs from expected file " + beanInfo + " in classloader"); + } + finally { + if(expected != null) + expected.close(); + if(actual != null) + actual.close(); + } + + // Pass, so remove the temporary output file + tempFile.delete(); + } + */ +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/inherit/Intf1Bean.beaninfo b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/inherit/Intf1Bean.beaninfo new file mode 100644 index 0000000..e9285b1 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/inherit/Intf1Bean.beaninfo @@ -0,0 +1,293 @@ + + + + + Intf1Bean + + + + + + + org.apache.beehive.controls.test.controls.inherit.Intf1Bean + + + + + public abstract int org.apache.beehive.controls.test.controls.inherit.Intf1.intf1Operation1() + + + + + intf1Operation1 + + + + + public abstract int org.apache.beehive.controls.test.controls.inherit.Intf1.intf1Operation2() + + + + + intf1Operation2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Root.rootOperation1() + + + + + rootOperation1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Root.rootOperation2() + + + + + rootOperation2 + + + + + + + type="java.lang.String" + isBound=false + isConstrained=false + isDefault=false> + + public java.lang.String org.apache.beehive.controls.test.controls.inherit.Intf1Bean.getControlImplementation() + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf1Bean.setControlImplementation(java.lang.String) + + + + controlImplementation + + + + + type="int" + isBound=false + isConstrained=false + isDefault=false> + + public int org.apache.beehive.controls.test.controls.inherit.Intf1Bean.getIntf1Prop1() + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf1Bean.setIntf1Prop1(int) + + + + intf1Prop1 + + + + + type="int" + isBound=false + isConstrained=false + isDefault=false> + + public int org.apache.beehive.controls.test.controls.inherit.Intf1Bean.getIntf1Prop2() + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf1Bean.setIntf1Prop2(int) + + + + intf1Prop2 + + + + + + + + org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf1Bean.addIntf1EventsListener(org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events) + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf1Bean.removeIntf1EventsListener(org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events) + + + public synchronized org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events[] org.apache.beehive.controls.test.controls.inherit.Intf1Bean.getIntf1EventsListeners() + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events.intf1Event1() + + + + + intf1Event1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events.intf1Event2() + + + + + intf1Event2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Root$RootEvents.rootEvent1() + + + + + rootEvent1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Root$RootEvents.rootEvent2() + + + + + rootEvent2 + + + + + + + intf1Events + + + + + org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1NewEvents + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf1Bean.addIntf1NewEventsListener(org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1NewEvents) throws java.util.TooManyListenersException + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf1Bean.removeIntf1NewEventsListener(org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1NewEvents) + + + public synchronized org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1NewEvents[] org.apache.beehive.controls.test.controls.inherit.Intf1Bean.getIntf1NewEventsListeners() + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1NewEvents.intf1NewEvent1() + + + + + intf1NewEvent1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1NewEvents.intf1NewEvent2() + + + + + intf1NewEvent2 + + + + + + + intf1NewEvents + + + + + diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/inherit/Intf2Bean.beaninfo b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/inherit/Intf2Bean.beaninfo new file mode 100644 index 0000000..bb12b23 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/inherit/Intf2Bean.beaninfo @@ -0,0 +1,629 @@ + + + + + Intf2Bean + + + + + + + org.apache.beehive.controls.test.controls.inherit.Intf2Bean + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.AddIn.addInOperation1() + + + + + addInOperation1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.AddIn.addInOperation2() + + + + + addInOperation2 + + + + + public abstract int org.apache.beehive.controls.test.controls.inherit.Intf1.intf1Operation1() + + + + + intf1Operation1 + + + + + public abstract int org.apache.beehive.controls.test.controls.inherit.Intf1.intf1Operation2() + + + + + intf1Operation2 + + + + + public abstract int org.apache.beehive.controls.test.controls.inherit.Intf2.intf2Operation1() + + + + + intf2Operation1 + + + + + public abstract int org.apache.beehive.controls.test.controls.inherit.Intf2.intf2Operation2() + + + + + intf2Operation2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Root.rootOperation1() + + + + + rootOperation1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Root.rootOperation2() + + + + + rootOperation2 + + + + + + + type="java.lang.String" + isBound=false + isConstrained=false + isDefault=false> + + public java.lang.String org.apache.beehive.controls.test.controls.inherit.Intf1Bean.getControlImplementation() + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf1Bean.setControlImplementation(java.lang.String) + + + + controlImplementation + + + + + type="int" + isBound=false + isConstrained=false + isDefault=false> + + public int org.apache.beehive.controls.test.controls.inherit.Intf1Bean.getIntf1Prop1() + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf1Bean.setIntf1Prop1(int) + + + + intf1Prop1 + + + + + type="int" + isBound=false + isConstrained=false + isDefault=false> + + public int org.apache.beehive.controls.test.controls.inherit.Intf1Bean.getIntf1Prop2() + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf1Bean.setIntf1Prop2(int) + + + + intf1Prop2 + + + + + type="int" + isBound=false + isConstrained=false + isDefault=false> + + public int org.apache.beehive.controls.test.controls.inherit.Intf2Bean.getIntf2Prop1() + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf2Bean.setIntf2Prop1(int) + + + + intf2Prop1 + + + + + type="int" + isBound=false + isConstrained=false + isDefault=false> + + public int org.apache.beehive.controls.test.controls.inherit.Intf2Bean.getIntf2Prop2() + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf2Bean.setIntf2Prop2(int) + + + + intf2Prop2 + + + + + + + + org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2NewEvents + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf2Bean.addIntf2NewEventsListener(org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2NewEvents) throws java.util.TooManyListenersException + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf2Bean.removeIntf2NewEventsListener(org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2NewEvents) + + + public synchronized org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2NewEvents[] org.apache.beehive.controls.test.controls.inherit.Intf2Bean.getIntf2NewEventsListeners() + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.AddIn$AddInEvents.addInEvent1() + + + + + addInEvent1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.AddIn$AddInEvents.addInEvent2() + + + + + addInEvent2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2NewEvents.intf2NewEvent1() + + + + + intf2NewEvent1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2NewEvents.intf2NewEvent2() + + + + + intf2NewEvent2 + + + + + + + intf2NewEvents + + + + + org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf1Bean.addIntf1EventsListener(org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events) + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf1Bean.removeIntf1EventsListener(org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events) + + + public synchronized org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events[] org.apache.beehive.controls.test.controls.inherit.Intf1Bean.getIntf1EventsListeners() + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events.intf1Event1() + + + + + intf1Event1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events.intf1Event2() + + + + + intf1Event2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Root$RootEvents.rootEvent1() + + + + + rootEvent1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Root$RootEvents.rootEvent2() + + + + + rootEvent2 + + + + + + + intf1Events + + + + + org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1NewEvents + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf1Bean.addIntf1NewEventsListener(org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1NewEvents) throws java.util.TooManyListenersException + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf1Bean.removeIntf1NewEventsListener(org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1NewEvents) + + + public synchronized org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1NewEvents[] org.apache.beehive.controls.test.controls.inherit.Intf1Bean.getIntf1NewEventsListeners() + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1NewEvents.intf1NewEvent1() + + + + + intf1NewEvent1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1NewEvents.intf1NewEvent2() + + + + + intf1NewEvent2 + + + + + + + intf1NewEvents + + + + + org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2Events + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf2Bean.addIntf2EventsListener(org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2Events) + + + public synchronized void org.apache.beehive.controls.test.controls.inherit.Intf2Bean.removeIntf2EventsListener(org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2Events) + + + public synchronized org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2Events[] org.apache.beehive.controls.test.controls.inherit.Intf2Bean.getIntf2EventsListeners() + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.AddIn$AddInEvents.addInEvent1() + + + + + addInEvent1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.AddIn$AddInEvents.addInEvent2() + + + + + addInEvent2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events.intf1Event1() + + + + + intf1Event1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf1$Intf1Events.intf1Event2() + + + + + intf1Event2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2Events.intf2Event1() + + + + + intf2Event1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Intf2$Intf2Events.intf2Event2() + + + + + intf2Event2 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Root$RootEvents.rootEvent1() + + + + + rootEvent1 + + + + + public abstract void org.apache.beehive.controls.test.controls.inherit.Root$RootEvents.rootEvent2() + + + + + rootEvent2 + + + + + + + intf2Events + + + + + diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/packaging/EventSetInfoTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/packaging/EventSetInfoTest.java new file mode 100644 index 0000000..78cd276 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/packaging/EventSetInfoTest.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit.packaging; + +import org.apache.beehive.controls.test.junit.ControlTestCase; +import org.apache.beehive.controls.test.controls.packaging.HelloBean; +import org.apache.beehive.controls.api.bean.Control; + +import java.beans.BeanInfo; +import java.beans.EventSetDescriptor; +import java.beans.Introspector; + +/** + * A TestCase that tests controls EventInfo + *

    + * EventInfo annotation on control interface is saved into controlBeanInfo class + * when the control is packaged. + */ +public class EventSetInfoTest extends ControlTestCase { + + @Control + private HelloBean _hBean; + + /** + * Test getting FeatureInfo from ControlBeanInfo class + */ + public void testGetEventSetInfo() throws Exception { + + BeanInfo beanInfo = Introspector.getBeanInfo(Class.forName( + "org.apache.beehive.controls.test.controls.packaging.HelloBean")); + EventSetDescriptor[] descriptors = beanInfo.getEventSetDescriptors(); + + // Find and inspect EventSet descriptor declared on HelloBean. + EventSetDescriptor descriptor = findEventSet(descriptors, "eventSet0"); + assertNotNull(descriptor); + assertTrue(descriptor.isInDefaultEventSet()); + assertFalse(descriptor.isUnicast()); + + descriptor = findEventSet(descriptors, "eventSet1"); + assertNotNull(descriptor); + assertTrue(descriptor.isInDefaultEventSet()); + assertFalse(descriptor.isUnicast()); + + descriptor = findEventSet(descriptors, "eventSet2"); + assertNotNull(descriptor); + assertTrue(descriptor.isInDefaultEventSet()); + assertTrue(descriptor.isUnicast()); + } + + private EventSetDescriptor findEventSet(EventSetDescriptor[] array, String eventname) { + EventSetDescriptor result = null; + for (EventSetDescriptor anArray : array) { + result = anArray; + if (result.getName().equals(eventname)) { + break; + } + else { + result = null; + } + } + return result; + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/packaging/FeatureInfoTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/packaging/FeatureInfoTest.java new file mode 100644 index 0000000..a572347 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/packaging/FeatureInfoTest.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit.packaging; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.test.controls.packaging.FeatureInfoControlBean; +import org.apache.beehive.controls.test.junit.ControlTestCase; + +import java.beans.BeanDescriptor; +import java.beans.BeanInfo; +import java.beans.Introspector; + +/** + * A TestCase that tests controls FeatureInfo in controls packaging + *

    + * FeatureInfo annotation on control interface is saved into controlBeanInfo class + * when the control is packaged. + *

    + * The tests in this class get feature info from controlBeanInfo class after the + * control is packaged into jar, in order to verify this part of control packaging + * process. + */ +public class FeatureInfoTest extends ControlTestCase { + + @Control + private FeatureInfoControlBean _ficBean; + + /** + * Test getting FeatureInfo from ControlBeanInfo class + */ + public void testGetClassLevelFeatureInfo() throws Exception { + + BeanInfo beanInfo = Introspector.getBeanInfo(Class.forName( + "org.apache.beehive.controls.test.controls.packaging.FeatureInfoControlBean")); + + BeanDescriptor descriptor = beanInfo.getBeanDescriptor(); + assertEquals("FeatureInfoControlBean", descriptor.getName()); + assertEquals("A Control to test packaging", descriptor.getDisplayName()); + assertEquals("This control is to test control packaging", descriptor.getShortDescription()); + assertTrue(descriptor.isExpert()); + assertTrue(descriptor.isHidden()); + assertTrue(descriptor.isPreferred()); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/packaging/PropertyInfoTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/packaging/PropertyInfoTest.java new file mode 100644 index 0000000..b94577f --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/packaging/PropertyInfoTest.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit.packaging; + +import junit.framework.TestCase; + +import java.beans.BeanInfo; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.test.controls.packaging.BoundPropertyControlBean; + +/** + * A TestCase that tests controls PropertyInfo + *

    + * PropertyInfo annotation on control interface is saved into controlBeanInfo class + * when the control is packaged. + *

    + * The tests in this class get property info from controlBeanInfo class after the + * control is packaged into jar, in order to verify this part of control packaging + * process. + */ +public class PropertyInfoTest extends TestCase { + + @Control + private BoundPropertyControlBean _bpcBean; + + /** + * Test getting FeatureInfo from ControlBeanInfo class + */ + public void testGetPropertyInfo() throws Exception { + BeanInfo beanInfo = Introspector.getBeanInfo(Class.forName( + "org.apache.beehive.controls.test.controls.packaging.BoundPropertyControlBean")); + PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors(); + + // Find and inspect property descriptor declared on BoundPropertyControlBean. + PropertyDescriptor descriptor = findProperty(descriptors, "Brand"); + assertNotNull(descriptor); + assertTrue(descriptor.isBound()); + assertFalse(descriptor.isConstrained()); + + descriptor = findProperty(descriptors, "Material"); + assertNotNull(descriptor); + assertFalse(descriptor.isBound()); + assertTrue(descriptor.isConstrained()); + + descriptor = findProperty(descriptors, "Quality"); + assertNotNull(descriptor); + assertTrue(descriptor.isBound()); + assertTrue(descriptor.isConstrained()); + + descriptor = findProperty(descriptors, "age"); + assertNotNull(descriptor); + assertTrue(descriptor.isBound()); + assertFalse(descriptor.isConstrained()); + + descriptor = findProperty(descriptors, "height"); + assertNotNull(descriptor); + assertFalse(descriptor.isBound()); + assertTrue(descriptor.isConstrained()); + } + + private PropertyDescriptor findProperty(PropertyDescriptor[] array, String propertyname) { + + PropertyDescriptor result = null; + for (PropertyDescriptor anArray : array) { + result = anArray; + if (result.getName().equals(propertyname)) + break; + else + result = null; + } + return result; + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/property/ClientAccessTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/property/ClientAccessTest.java new file mode 100644 index 0000000..6c03cd5 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/property/ClientAccessTest.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit.property; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.test.controls.property.PropertyControl; +import org.apache.beehive.controls.test.controls.property.PropertyControlBean; +import org.apache.beehive.controls.test.junit.ControlTestCase; + +import java.beans.Beans; + +/** + * Test accessing control's propertySet by control bean's getter/setter + */ + +public class ClientAccessTest extends ControlTestCase { + /** + * A control that declares some propertySet in its control interface + */ + @Control + private PropertyControlBean _myControl; + + /** + * Accesses property value by getter of the control bean instance. + * The ccontrol bean is instantiated declaratively + */ + public void testGetterByDeclare() throws Exception { + assertEquals(PropertyControl.DEFAULT_ATTRIBUTE_VALUE1, _myControl.getAttribute1()); + assertEquals(PropertyControl.DEFAULT_ATTRIBUTE_VALUE3, _myControl.getPropertyTwoAttribute3()); + } + + /** + * Accesses property value by getter og control bean instance. + * The control bean is instantiated programmatically + */ + public void testGetterByProgram() throws Exception { + PropertyControlBean sbean = (PropertyControlBean) Beans.instantiate( + Thread.currentThread().getContextClassLoader(), + "org.apache.beehive.controls.test.controls.property.PropertyControlBean"); + + assertEquals(PropertyControl.DEFAULT_ATTRIBUTE_VALUE1, sbean.getAttribute1()); + assertEquals(PropertyControl.DEFAULT_ATTRIBUTE_VALUE3, sbean.getPropertyTwoAttribute3()); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/property/ClientImplTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/property/ClientImplTest.java new file mode 100644 index 0000000..4643219 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/property/ClientImplTest.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit.property; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.test.controls.property.Hello; +import org.apache.beehive.controls.test.controls.property.HelloBean; +import org.apache.beehive.controls.test.controls.property.PropertyControlBean; +import org.apache.beehive.controls.test.junit.ControlTestCase; + +import java.beans.Beans; + +/** + * A TestCase that tests accessing control's propertySet by both impl and client + */ + +public class ClientImplTest extends ControlTestCase { + /** + * A control that declares some propertySets in its control interface + */ + @Control + private PropertyControlBean myControl; + + @Control + private HelloBean myHelloControl; + + /** + * Resets control's property value using setters on the bean class and + * retrieves the new value using control context on control's impl. + * This method instantiates HelloBean by declaration + */ + public void testResetPropertyByDeclare() throws Exception { + myControl.setAttribute1("New value for attribute1"); + myControl.setPropertyTwoAttribute3("New value for attribute3"); + + assertEquals("New value for attribute1", myControl.getAttribute1ByContext()); + assertEquals("New value for attribute3", myControl.getAttribute3ByContext()); + } + + /** + * Resets control's property value using setters on the bean class and + * retrieves the new value using control context on control's impl. + * This method instantiates HelloBean by program + */ + public void testResetPropertyByProgram() throws Exception { + PropertyControlBean sbean = (PropertyControlBean) Beans.instantiate( + Thread.currentThread().getContextClassLoader(), + "org.apache.beehive.controls.test.controls.property.PropertyControlBean"); + + sbean.setAttribute1("New value for attribute1"); + sbean.setPropertyTwoAttribute3("New value for attribute3"); + + assertEquals("New value for attribute1", sbean.getAttribute1ByContext()); + assertEquals("New value for attribute3", sbean.getAttribute3ByContext()); + } + + /** + * Verifies the fix of JIRA-149 + */ + public void testHelloControl() throws Exception { + Hello.Gender theGender = myHelloControl.getGender(); + assertEquals(Hello.GenderType.NEUTRAL, theGender.value()); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/property/DefaultValueTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/property/DefaultValueTest.java new file mode 100644 index 0000000..d208e33 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/property/DefaultValueTest.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit.property; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.test.controls.property.SingleProperty; +import org.apache.beehive.controls.test.controls.property.SinglePropertyBean; +import org.apache.beehive.controls.test.junit.ControlTestCase; + +/** + * Test objective: + * JSR175 provides a mechanism for assigning a default value as part of a member definition. + * The default value must be type consistent with the return type of the methods and it cannot be null. + * If there is no default value defined, then the declaration of the annotation must include the member + * (or a compile error will be generated). + */ +public class DefaultValueTest extends ControlTestCase { + /** + * If the property has a default value,property annoatation doesn't have the member + * and should not cause a compile error + */ + @Control + @SingleProperty.Greeting + private SinglePropertyBean myControl; + + /** + * If the property doesn't have a default value,property annoatation has the member + * no compile error + */ + @Control + @SingleProperty.Identity(name = "a control") + private SinglePropertyBean myControl2; + + + /** + * Accesses property value by getter of the control bean instance. + * The ccontrol bean is instantiated declaratively + */ + public void testPropertyValue() throws Exception { + assertNotNull(myControl.getGreetWord()); + assertEquals("a control", myControl2.getName()); + } + + /** + * Accesses property of primitve type by getter + */ + public void testPremitiveType() throws Exception { + assertEquals(20, myControl.getAge()); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/property/ImplAccessTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/property/ImplAccessTest.java new file mode 100644 index 0000000..bb1032e --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/property/ImplAccessTest.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit.property; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.test.controls.property.PropertyControl; +import org.apache.beehive.controls.test.controls.property.PropertyControlBean; +import org.apache.beehive.controls.test.junit.ControlTestCase; + +import java.beans.Beans; + +/** + * A TestCase that tests accessing property values via control context in control impl + * All tests on controls instantiated declaratively are deactivated until this feature is supported. + */ +public class ImplAccessTest extends ControlTestCase { + + /** + * A control that declares some propertySets in its control interface. + * It has a method that allow accessing these property values via control context. + */ + @Control + private PropertyControlBean myControl; + + /** + * Tests accessing property values via control context. + * By invoking sayHello method, the property value is retrieved via control context. + * The control bean is instantiated by declaration. + */ + public void testContextAccessByDeclare() throws Exception { + assertEquals(PropertyControl.DEFAULT_ATTRIBUTE_VALUE1, myControl.getAttribute1ByContext()); + assertEquals(PropertyControl.DEFAULT_ATTRIBUTE_VALUE3, myControl.getAttribute3ByContext()); + } + + /** + * Tests accessing property values via control context. + * By invoking sayHello method, the property value is retrieved via control context. + * The control bean is instantiated programmatically. + */ + public void testContextAccessByProgram() throws Exception { + PropertyControlBean sbean = (PropertyControlBean) Beans.instantiate( + Thread.currentThread().getContextClassLoader(), + "org.apache.beehive.controls.test.controls.property.PropertyControlBean"); + + assertEquals(PropertyControl.DEFAULT_ATTRIBUTE_VALUE1, sbean.getAttribute1ByContext()); + assertEquals(PropertyControl.DEFAULT_ATTRIBUTE_VALUE3, sbean.getAttribute3ByContext()); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/property/PropEventsTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/property/PropEventsTest.java new file mode 100644 index 0000000..9341128 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/property/PropEventsTest.java @@ -0,0 +1,310 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit.property; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.test.controls.property.PropEvents; +import org.apache.beehive.controls.test.controls.property.PropEventsBean; +import org.apache.beehive.controls.test.junit.ControlTestCase; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyVetoException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; + +/** + * This test case validates bound and constrained property behaviors, w.r.t. to the delivery + * of PropertyChange events for bound and constrained events + */ +public class PropEventsTest extends ControlTestCase { + @Control + private PropEventsBean _eventBean; + + /** + * This base class hold a queue of property change events and makes them accessible + * for event validation. + */ + abstract static class QueueListener { + QueueListener() { + initEvents(); + } + + /** + * Resets/initializes the internal event queue + */ + public void initEvents() { + eventQueue = new ArrayList(); + } + + /** + * Returns the collection of events + */ + public Collection getEvents() { + return eventQueue; + } + + protected ArrayList eventQueue; + } + + static class ChangeTestListener extends org.apache.beehive.controls.test.junit.property.PropEventsTest.QueueListener + implements PropEvents.ImplPropertyChange // + java.beans.PropertyChangeListener + { + /** + * Implementation of PropertyChangeListener.propertyChange(). Will enqueue + * the received event. + */ + public void propertyChange(PropertyChangeEvent pce) { + eventQueue.add(pce); + } + } + + static class VetoableTestListener extends org.apache.beehive.controls.test.junit.property.PropEventsTest.QueueListener + implements PropEvents.ImplVetoableChange // + java.beans.VetoableChangeListener + { + VetoableTestListener(boolean doVeto) { + _doVeto = doVeto; + } + + /** + * Implementation of PropertyChangeListener.propertyChange(). Will enqueue + * the received event. + */ + public void vetoableChange(PropertyChangeEvent pce) throws PropertyVetoException { + eventQueue.add(pce); + + // Veto attempts to set even values + if (_doVeto && (((Integer) pce.getNewValue()).intValue() & 1) == 0) + throw new PropertyVetoException("Sorry", pce); + } + + boolean _doVeto; + } + + private void validatePropertyEvents(Collection events) { + // Now validate the received properties + int i = 0; + for (PropertyChangeEvent pce : events) { + assertEquals(_eventBean, pce.getSource()); + assertEquals("boundInt", pce.getPropertyName()); + assertEquals(i, pce.getOldValue()); + assertEquals(i+1, pce.getNewValue()); + i++; + } + assertEquals(99, i); + } + + /** + * Basic test: setting/reading property values by a control client + */ + public void testPropertyChange() throws Exception { + // Set the test property to a well-defined initial value + _eventBean.setBoundInt(0); + + // Create a new test listener and register it on the test bean + ChangeTestListener extChange = new ChangeTestListener(); + _eventBean.addPropertyChangeListener(extChange); + + // Create an test listener and register it to indirectly from impl callbacks + ChangeTestListener implChange = new ChangeTestListener(); + _eventBean.addImplPropertyChangeListener(implChange); + + // Call the bound property setter on the bean 100 times + for (int i = 1; i < 100; i++) { + _eventBean.setBoundInt(i); + } + + // Validate the events received by the external listener + validatePropertyEvents(extChange.getEvents()); + + // Validate the events received by the implementation via the context + validatePropertyEvents(implChange.getEvents()); + + // Reset the event queues + extChange.initEvents(); + implChange.initEvents(); + + // Change an unbound property and verify that no property change event was delivered + _eventBean.setBasicInt(0); + assertEquals(0, extChange.getEvents().size()); + assertEquals(0, implChange.getEvents().size()); + + // Remove the external event listener, change a bound property, and verify no event is + // delivered on it, but is delivered to the implentation + _eventBean.removePropertyChangeListener(extChange); + _eventBean.setBoundInt(0); + + assertEquals(0, extChange.getEvents().size()); + assertTrue(implChange.getEvents().size() > 0); + } + + /** + * Validate the expected set of change and veto events received during the testVetoChange + * test. This is factored out so it can be used to validate events delivered to both + * the implementation and an external listener (which should match) + */ + private void validateVetoEvents(Iterator changeIter, + Iterator vetoIter) { + // Now validate the received properties, there should be one per vetoed property, + // two per allowed change + int i = 1; + int expected = 0; + boolean expectVeto; + while (vetoIter.hasNext()) { + PropertyChangeEvent vce = vetoIter.next(); + + expectVeto = (i & 1) == 0; + + assertEquals(vce.getSource(), _eventBean); + assertEquals("constrainedInt", vce.getPropertyName()); + assertEquals(expected, vce.getOldValue()); + assertEquals(i, vce.getNewValue()); + + if (expectVeto) { + // If a veto occurred, then there should be a 2nd vetoable change event that + // goes from the vetoed value back to the last valid value + assertTrue(vetoIter.hasNext()); + + // + // Pull the next event, which should revert from the attempted change back + // to the last accepted value + // + vce = vetoIter.next(); + assertEquals(_eventBean, vce.getSource()); + assertEquals("constrainedInt", vce.getPropertyName()); + assertEquals(i, vce.getOldValue()); + assertEquals(expected, vce.getNewValue()); + } + else { + // Expected to succeed so look for the corresponding PropertyChange + assertTrue(changeIter.hasNext()); + + PropertyChangeEvent pce = changeIter.next(); + assertEquals(_eventBean, pce.getSource()); + assertEquals("constrainedInt", pce.getPropertyName()); + assertEquals(expected, pce.getOldValue()); + assertEquals(i, pce.getNewValue()); + expected = i; + } + + i++; + } + assertEquals(99, expected); + } + + /** + * Basic test: setting/reading property values by a control client + */ + public void testVetoChange() throws Exception { + // Set the test property to a well-defined initial value + _eventBean.setConstrainedInt(0); + + // Create a test listener and register it to indirectly receive impl callbacks + // but not to veto anything + VetoableTestListener implVeto = new VetoableTestListener(false); + _eventBean.addImplVetoableChangeListener(implVeto); + + // Create a test listener and register it as an external listener that will veto + VetoableTestListener extVeto = new VetoableTestListener(true); + _eventBean.addVetoableChangeListener(extVeto); + + // Create an test listener and register it to indirectly from impl callbacks + ChangeTestListener implChange = new ChangeTestListener(); + _eventBean.addImplPropertyChangeListener(implChange); + + // Create an external change listener and register it... this will be used to validate the + // property changes that were not vetoed + ChangeTestListener extChange = new ChangeTestListener(); + _eventBean.addPropertyChangeListener(extChange); + + // + // Change the property multiple times, validating that veto exceptions propogate as + // expected and that the retrieved property value matches the expected value (whether + // accepted or vetoed) + // + int expected = 0; + for (int i = 1; i < 100; i++) { + boolean vetoed = false; + boolean expectVeto = (i & 1) == 0; + try { + _eventBean.setConstrainedInt(i); + } + catch (PropertyVetoException pve) { + vetoed = true; + } + + if (vetoed) { + assertTrue(expectVeto); + } + else { + assertFalse(expectVeto); + expected = i; + } + + // + // Read back the property and see if it was successfully changed or vetoed + assertEquals(expected, _eventBean.getConstrainedInt()); + } + + // Validate the events generated on the implementation + validateVetoEvents(implChange.getEvents().iterator(), implVeto.getEvents().iterator()); + + // Validate the events generated on the external listener + validateVetoEvents(extChange.getEvents().iterator(), extVeto.getEvents().iterator()); + + // Reset the event queues + extVeto.initEvents(); + extChange.initEvents(); + implVeto.initEvents(); + implChange.initEvents(); + + // + // Change an unbound property and verify that no property change events were delivered + // + _eventBean.setBasicInt(0); + + if (implVeto.getEvents().size() != 0 || implChange.getEvents().size() != 0) + fail("Unexpected impl event delivered on unbound property change"); + + if (extVeto.getEvents().size() != 0 || extChange.getEvents().size() != 0) + fail("Unexpected external event delivered on unbound property change"); + + // + // Remove the external veto event listener but not the impl veto listener change listener, + // change a constrained property, and verify no external veto event is delivered but an + // impl veto and external change event is delivered + // + _eventBean.removeVetoableChangeListener(extVeto); + _eventBean.removeImplPropertyChangeListener(implChange); + _eventBean.setConstrainedInt(1); + + if (extVeto.getEvents().size() != 0) + fail("Unexpected external event delivered after listener removed"); + + if (implVeto.getEvents().size() == 0) + fail("No impl event delivered after external listener removed"); + + if (extChange.getEvents().size() != 1) + fail("External change event not delivered after listener removed"); + + if (implChange.getEvents().size() != 0) + fail("Unexpected Impl change event delivered after listener removed"); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/property/PropTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/property/PropTest.java new file mode 100644 index 0000000..1a5809b --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/property/PropTest.java @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit.property; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.api.properties.BeanPropertyMap; +import org.apache.beehive.controls.api.properties.PropertyKey; +import org.apache.beehive.controls.api.properties.PropertyMap; +import org.apache.beehive.controls.test.controls.property.ExtPropertySet; +import org.apache.beehive.controls.test.controls.property.NestPropsBean; +import org.apache.beehive.controls.test.controls.property.Props; +import org.apache.beehive.controls.test.controls.property.PropsBean; +import org.apache.beehive.controls.test.controls.property.PropsExtension; +import org.apache.beehive.controls.test.controls.property.PropsExtensionBean; +import org.apache.beehive.controls.test.junit.ControlTestCase; + +import java.util.Arrays; + +public class PropTest extends ControlTestCase { + + @Control + private PropsBean _propsBean; + + @Control + private PropsExtensionBean _propsExtBean; + + @Control + private NestPropsBean _nestPropsBean; + + public void testIntProperty() throws Exception { + assertEquals(Props.INT_DEFAULT, _propsBean.getSimpleInt()); + _propsBean.setSimpleInt(237); + assertEquals(237, _propsBean.getSimpleInt()); + } + + public void testStringProperty() throws Exception { + assertEquals(Props.STRING_DEFAULT, _propsBean.getSimpleString()); + _propsBean.setSimpleString("howdy"); + assertEquals("howdy", _propsBean.getSimpleString()); + } + + public void testClassProperty() throws Exception { + assertEquals(Props.CLASS_DEFAULT, _propsBean.getSimpleClass()); + Class testSimpleClass = java.util.Vector.class; + _propsBean.setSimpleClass(testSimpleClass); + assertEquals(testSimpleClass, _propsBean.getSimpleClass()); + } + + public void testEnumProperty() throws Exception { + assertEquals(Props.ENUM_DEFAULT, _propsBean.getSimpleEnum()); + _propsBean.setSimpleEnum(Props.SimpleEnum.ChoiceB); + assertEquals(Props.SimpleEnum.ChoiceB, _propsBean.getSimpleEnum()); + } + + public void testIntArrayProperty() throws Exception { + int [] arrayInt = _propsBean.getArrayInt(); + assertNotNull(arrayInt); + assertEquals(Props.ARRAY_INT_DEFAULT.length, arrayInt.length); + assertTrue(Arrays.equals(Props.ARRAY_INT_DEFAULT, arrayInt)); + + int [] testArrayInt = {1, 2, 3, 4, 5}; + _propsBean.setArrayInt(testArrayInt); + arrayInt = _propsBean.getArrayInt(); + assertNotNull(arrayInt); + assertEquals(testArrayInt.length, arrayInt.length); + assertTrue(Arrays.equals(testArrayInt, arrayInt)); + } + + public void testStringArrayProperty() throws Exception { + String [] arrayString = _propsBean.getArrayString(); + assertNotNull(arrayString); + assertEquals(Props.ARRAY_STRING_DEFAULT.length, arrayString.length); + assertTrue(Arrays.equals(Props.ARRAY_STRING_DEFAULT, arrayString)); + + String [] testArrayString = {"fee", "fi", "fo", "fum"}; + _propsBean.setArrayString(testArrayString); + arrayString = _propsBean.getArrayString(); + assertNotNull(arrayString); + assertEquals(testArrayString.length, arrayString.length); + assertTrue(Arrays.equals(testArrayString, arrayString)); + } + + public void testClassArrayProperty() throws Exception { + Class [] arrayClass = _propsBean.getArrayClass(); + assertNotNull(arrayClass); + assertEquals(Props.ARRAY_CLASS_DEFAULT.length, arrayClass.length); + assertTrue(Arrays.equals(Props.ARRAY_CLASS_DEFAULT, arrayClass)); + + Class [] testArrayClass = {Integer.class, Long.class, Short.class, Float.class, + Double.class, Character.class, Boolean.class}; + _propsBean.setArrayClass(testArrayClass); + arrayClass = _propsBean.getArrayClass(); + assertNotNull(arrayClass); + assertEquals(testArrayClass.length, arrayClass.length); + assertTrue(Arrays.equals(testArrayClass, arrayClass)); + } + + public void testEnumArrayProperty() throws Exception { + Props.SimpleEnum [] arrayEnum = _propsBean.getArrayEnum(); + assertNotNull(arrayEnum); + assertEquals(Props.ARRAY_ENUM_DEFAULT.length, arrayEnum.length); + assertTrue(Arrays.equals(Props.ARRAY_ENUM_DEFAULT, arrayEnum)); + + Props.SimpleEnum [] testArrayEnum = + {Props.SimpleEnum.ChoiceB, Props.SimpleEnum.ChoiceC, Props.SimpleEnum.ChoiceA}; + _propsBean.setArrayEnum(testArrayEnum); + arrayEnum = _propsBean.getArrayEnum(); + assertNotNull(arrayEnum); + assertEquals(testArrayEnum.length, arrayEnum.length); + assertTrue(Arrays.equals(testArrayEnum, arrayEnum)); + } + + public void testAnnotationProperties() throws Exception { + + Props.SimpleProps simpleAnnot = _propsBean.getSimpleAnnot(); + assertNotNull(simpleAnnot); + assertEquals(Props.ANNOT_INT_DEFAULT, simpleAnnot.simpleInt()); + assertEquals(Props.ANNOT_STRING_DEFAULT, simpleAnnot.simpleString()); + assertEquals(Props.ANNOT_CLASS_DEFAULT, simpleAnnot.simpleClass()); + assertEquals(Props.ANNOT_ENUM_DEFAULT, simpleAnnot.simpleEnum()); + + + PropertyMap simpleAnnotMap = new BeanPropertyMap(Props.SimpleProps.class); + Integer testAnnotInt = 5150; + simpleAnnotMap.setProperty(new PropertyKey(Props.SimpleProps.class, "simpleInt"), testAnnotInt); + String testAnnotString = "abracadabra"; + simpleAnnotMap.setProperty(new PropertyKey(Props.SimpleProps.class, "simpleString"), testAnnotString); + Class testAnnotClass = org.apache.beehive.controls.api.bean.Control.class; + simpleAnnotMap.setProperty(new PropertyKey(Props.SimpleProps.class, "simpleClass"), testAnnotClass); + + _propsBean.setSimpleAnnot(simpleAnnotMap.getPropertySet(Props.SimpleProps.class)); + simpleAnnot = _propsBean.getSimpleAnnot(); + assertNotNull(simpleAnnot); + assertEquals((int) testAnnotInt, simpleAnnot.simpleInt()); + assertEquals(testAnnotString, simpleAnnot.simpleString()); + assertEquals(testAnnotClass, simpleAnnot.simpleClass()); + } + + public void testExternalPropertySet() throws Exception { + int age = _propsBean.getAge(); + assertEquals(ExtPropertySet.AGE_DEFAULT, age); + _propsBean.setAge(60); + age = _propsBean.getAge(); + assertEquals(60, age); + } + + + /** + * Basic test: Reading property values inside implementation via ControlBeanContext API + */ + public void testImplAccess() throws Exception { + Props.SimpleProps simpleProps = (Props.SimpleProps) _propsExtBean.getControlPropertySet(Props.SimpleProps.class); + assertEquals(PropsExtension.SIMPLE_INT_VALUE, simpleProps.simpleInt()); + + simpleProps = (Props.SimpleProps) _propsExtBean.getPropertySetOnMethod1(Props.SimpleProps.class); + assertEquals(PropsExtension.SIMPLE_CLASS_VALUE1, simpleProps.simpleClass()); + + simpleProps = (Props.SimpleProps) _propsExtBean.getPropertySetOnMethod2(Props.SimpleProps.class); + assertEquals(PropsExtension.SIMPLE_CLASS_VALUE2, simpleProps.simpleClass()); + + simpleProps = (Props.SimpleProps) _nestPropsBean.getNestedPropertySet(Props.SimpleProps.class); + assertEquals("A field annotation value", simpleProps.simpleString()); + + String [] arrayExpect = {"One", "Two", "Three"}; + Props.ArrayProps arrayProps = (Props.ArrayProps) _nestPropsBean.getExtensionControlPropertySet(Props.ArrayProps.class); + String [] arrayString = arrayProps.arrayString(); + assertEquals(arrayExpect.length, arrayString.length); + assertTrue(Arrays.equals(arrayExpect, arrayString)); + + simpleProps = (Props.SimpleProps) _nestPropsBean.getExtensionControlPropertySet(Props.SimpleProps.class); + assertEquals(PropsExtension.SIMPLE_INT_VALUE, simpleProps.simpleInt()); + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/threading/CompositeTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/threading/CompositeTest.java new file mode 100644 index 0000000..f34b7c1 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/threading/CompositeTest.java @@ -0,0 +1,132 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit.threading; + +import org.apache.beehive.controls.test.controls.threading.nested.CompositeMThreadControlBean; +import org.apache.beehive.controls.test.junit.ControlTestCase; +import org.apache.beehive.controls.api.bean.Control; + +public class CompositeTest extends ControlTestCase { + + @Control + private CompositeMThreadControlBean sBean; + + public void testNestedSingleThread() throws Exception { + + DriveNestedSingleThread singleThreadStarter = new DriveNestedSingleThread("single thread starter", sBean, false); + DriveNestedSingleThread singleThreadStopper = new DriveNestedSingleThread("single thread stopper", sBean, true); + + singleThreadStarter.start(); + + try { + Thread.sleep(2000); + } + catch (InterruptedException e) { + fail("InterruptedException!"); + } + + singleThreadStopper.start(); + + try { + Thread.sleep(500); + } + catch (InterruptedException e) { + fail("InterruptedException!"); + } + + assertEquals(0, singleThreadStopper.getResult()); + } + + public void testNestedMultiThread() throws Exception { + + DriveNestedMultiThread multiThreadStarter = new DriveNestedMultiThread("multi thread starter", sBean, false); + DriveNestedMultiThread multiThreadStopper = new DriveNestedMultiThread("multi thread stopper", sBean, true); + + multiThreadStarter.start(); + + try { + Thread.sleep(2000); + } + catch (InterruptedException e) { + } + + multiThreadStopper.start(); + + try { + Thread.sleep(500); + } + catch (InterruptedException e) { + } + + assertTrue(multiThreadStopper.getResult() > 0); + } + + private class DriveNestedSingleThread extends Thread { + + private CompositeMThreadControlBean _myControl; + private boolean _isStopperRole = false; + private int _result = 0; + + public DriveNestedSingleThread(String name, CompositeMThreadControlBean bean, boolean role) { + super(name); + _myControl = bean; + _isStopperRole = role; + } + + public void run() { + if (_isStopperRole) { + _result = _myControl.stopSingleThreadNestedControl(); + } + else { + _result = _myControl.startSingleThreadNestedControl(); + } + } + + public int getResult() { + return _result; + } + } + + private class DriveNestedMultiThread extends Thread { + + private CompositeMThreadControlBean _myControl; + private boolean _isStopperRole = false; + private int _result = 0; + + public DriveNestedMultiThread(String name, CompositeMThreadControlBean bean, boolean role) { + super(name); + _myControl = bean; + _isStopperRole = role; + } + + public void run() { + if (_isStopperRole) { + _result = _myControl.stopMultiThreadNestedControl(); + } + else { + _result = _myControl.startMultiThreadNestedControl(); + } + } + + public int getResult() { + return _result; + } + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/threading/MultiThreadTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/threading/MultiThreadTest.java new file mode 100644 index 0000000..55afb54 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/threading/MultiThreadTest.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit.threading; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.test.controls.threading.MultiThreadControlBean; +import org.apache.beehive.controls.test.junit.ControlTestCase; + +public class MultiThreadTest extends ControlTestCase { + + @Control + private MultiThreadControlBean sBean; + + /** + * Makes an instance of a single threaded control, passes it to two different + * threads and run both threads. + */ + public void testMultiThread() throws Exception { + + DriveMultiThread driver1 = new DriveMultiThread("MultiThread-driver1", sBean, true); + DriveMultiThread driver2 = new DriveMultiThread("MultiThread-driver2", sBean, false); + driver1.start(); + + try { + Thread.sleep(2000); + } + catch (InterruptedException e) { + fail(e.getMessage()); + } + driver2.start(); + + try { + Thread.sleep(2000); + } + catch (InterruptedException e) { + fail(e.getMessage()); + } + assertTrue(driver2.getResult() > 0); + } + + private class DriveMultiThread extends Thread { + + public final static int LOOPS = 20; + private MultiThreadControlBean _myControl; + private boolean _role; + private long _result = 0; + + public DriveMultiThread(String name, MultiThreadControlBean bean, boolean role) { + super(name); + _myControl = bean; + _role = role; + } + + public void run() { + _result = _myControl.doSlowIncrement(_role); + } + + public long getResult() { + return _result; + } + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/threading/SingleThreadTest.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/threading/SingleThreadTest.java new file mode 100644 index 0000000..378639a --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/threading/SingleThreadTest.java @@ -0,0 +1,125 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ + +package org.apache.beehive.controls.test.junit.threading; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.test.controls.threading.DefaultThreadControlBean; +import org.apache.beehive.controls.test.controls.threading.SingleThreadControlBean; +import org.apache.beehive.controls.test.junit.ControlTestCase; + +public class SingleThreadTest extends ControlTestCase { + + + @Control + private DefaultThreadControlBean sBean; + + @Control + private SingleThreadControlBean stBean; + + public void testDefaultThread() throws Exception { + + DriveDefaultThread driver1 = new DriveDefaultThread("DefaultThread-driver1", sBean, true); + DriveDefaultThread driver2 = new DriveDefaultThread("DefaultThread-driver2", sBean, false); + + driver1.start(); + try { + Thread.sleep(2000); + } + catch (InterruptedException e) { + fail(e.getMessage()); + } + driver2.start(); + + try { + Thread.sleep(2000); + } + catch (InterruptedException e) { + fail(e.getMessage()); + } + assertEquals(0, driver2.getResult()); + } + + /** + * Makes an instance of a single threaded control, passes it to two different + * threads and run both threads. + */ + public void testSingleThread() throws Exception { + + DriveSingleThread driver1 = new DriveSingleThread("SingleThread-driver1", stBean, true); + DriveSingleThread driver2 = new DriveSingleThread("SingleThread-driver2", stBean, false); + driver1.start(); + + try { + Thread.sleep(2000); + } + catch (InterruptedException e) { + fail(e.getMessage()); + } + driver2.start(); + + try { + Thread.sleep(2000); + } + catch (InterruptedException e) { + fail(e.getMessage()); + } + assertEquals(0, driver2.getResult()); + } + + private class DriveDefaultThread extends Thread { + private boolean _role; + private long _result = 0; + private DefaultThreadControlBean _myControl; + + public DriveDefaultThread(String name, DefaultThreadControlBean bean, boolean role) { + super(name); + _myControl = bean; + _role = role; + } + + public void run() { + _result = _myControl.doSlowIncrement(_role); + } + + public long getResult() { + return _result; + } + } + + private class DriveSingleThread extends Thread { + private SingleThreadControlBean _myControl; + private boolean _role; + private long _result = 0; + + public DriveSingleThread(String name, SingleThreadControlBean bean, boolean role) { + super(name); + _myControl = bean; + _role = role; + } + + public void run() { + _result = _myControl.doSlowIncrement(_role); + } + + public long getResult() { + return _result; + } + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/utils/ControlIntrospector.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/utils/ControlIntrospector.java new file mode 100644 index 0000000..5f23aba --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/utils/ControlIntrospector.java @@ -0,0 +1,394 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.test.junit.utils; + +import java.beans.BeanDescriptor; +import java.beans.BeanInfo; +import java.beans.EventSetDescriptor; +import java.beans.FeatureDescriptor; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.MethodDescriptor; +import java.beans.ParameterDescriptor; +import java.beans.PropertyDescriptor; +import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.lang.reflect.Method; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +/** + * A utility class for introspecting Control beans + */ +final class ControlIntrospector { + + private static String LINE_SEPARATOR = System.getProperty("line.separator"); + + private Class _beanClass; + private int _indentLevel = 0; + private PrintWriter _pw; + + public ControlIntrospector(Class beanClass, OutputStream output) { + _beanClass = beanClass; + _pw = new PrintWriter(output); + } + + private void indent() { + _indentLevel++; + } + + private void unindent() { + _indentLevel--; + } + + private void printf(String format, Object ...args) { + for (int i = 0; i < _indentLevel; i++) + _pw.append(" "); + _pw.printf(format, args); + _pw.printf(LINE_SEPARATOR); + } + + private void printElement(String name, String value) { + printf("<%s>", name); + indent(); + printf("%s", value); + unindent(); + printf("", name); + } + + /** + * Introspects the target class and writes the formatted results from introspection to + * the provided output stream + */ + public void introspect(int flags) + throws IntrospectionException { + + BeanInfo beanInfo = Introspector.getBeanInfo(_beanClass, flags); + if (beanInfo == null) + throw new IntrospectionException("No BeanInfo for " + _beanClass); + + introspectBeanInfo(beanInfo); + + _pw.flush(); + } + + public void introspect() + throws IntrospectionException { + introspect(Introspector.USE_ALL_BEANINFO); + } + + private void introspectBeanInfo(BeanInfo beanInfo) { + printf("", beanInfo.getBeanDescriptor().getBeanClass().getName()); + indent(); + { + introspectBeanDescriptor(beanInfo.getBeanDescriptor()); + + MethodDescriptor [] methodDescs = beanInfo.getMethodDescriptors(); + if (methodDescs != null && methodDescs.length != 0) { + printf(""); + indent(); + introspectMethodDescriptors(methodDescs); + unindent(); + printf(""); + } + else printf(""); + + PropertyDescriptor [] propDescs = beanInfo.getPropertyDescriptors(); + if (propDescs != null && propDescs.length != 0) { + printf("", beanInfo.getDefaultPropertyIndex()); + indent(); + for (int i = 0; i < propDescs.length; i++) + introspectPropertyDescriptor(propDescs[i], + i == beanInfo.getDefaultPropertyIndex()); + unindent(); + printf(""); + } + else printf(""); + + EventSetDescriptor [] eventSetDescs = beanInfo.getEventSetDescriptors(); + if (eventSetDescs != null && eventSetDescs.length != 0) { + printf("", + beanInfo.getDefaultEventIndex()); + indent(); + for (int i = 0; i < eventSetDescs.length; i++) + introspectEventSetDescriptor(eventSetDescs[i], + i == beanInfo.getDefaultEventIndex()); + unindent(); + printf(""); + } + else printf(""); + + BeanInfo [] additionalBeanInfo = beanInfo.getAdditionalBeanInfo(); + if (additionalBeanInfo != null && additionalBeanInfo.length != 0) { + printf(""); + indent(); + { + for (int i = 0; i < additionalBeanInfo.length; i++) + introspectBeanInfo(additionalBeanInfo[i]); + } + unindent(); + printf(""); + } + else printf(""); + } + unindent(); + printf(""); + } + + private void introspectBeanDescriptor(BeanDescriptor beanDesc) { + printf("", beanDesc.getDisplayName()); + indent(); + { + introspectFeatureDescriptor(beanDesc); + ; + printElement("bean-class", beanDesc.getBeanClass().getName()); + Class customizerClass = beanDesc.getCustomizerClass(); + if (customizerClass != null) + printElement("customizer-class", customizerClass.getName()); + } + unindent(); + printf(""); + } + + private void introspectFeatureDescriptor(FeatureDescriptor featureDesc) { + printf("", featureDesc.isPreferred()); + + printElement("short-description", featureDesc.getShortDescription()); + + Enumeration attrNames = featureDesc.attributeNames(); + if (attrNames != null && attrNames.hasMoreElements()) { + SortedSet sortedNames = new TreeSet(); + while (attrNames.hasMoreElements()) + sortedNames.add(attrNames.nextElement()); + printf(""); + indent(); + { + for (String attrName : sortedNames) { + // Convert the attribute value to a String, but drop any object ID + // that is going to fail an equivalence comparison + String attrValue = featureDesc.getValue(attrName).toString(); + int atIndex = attrValue.indexOf('@'); + if (atIndex > 0) + attrValue = attrValue.substring(0, atIndex + 1); + + printf("", + attrName, attrValue); + } + } + unindent(); + printf(""); + } + } + unindent(); + printf("", featureDesc.getDisplayName()); + } + + /** + * Provides a predictable ordering of method descriptors, based upon the underlying + * java.lang.reflect.Method attributes. Uses the following tests: + * - compare method names. If equal, then: + * - compare parameter list lengths. If equals, then: + * - compare parameter type names, in order, until they are unequal + */ + static private class MethodDescriptorComparator + implements Comparator { + + public int compare(MethodDescriptor md1, MethodDescriptor md2) { + Method m1 = md1.getMethod(); + Method m2 = md2.getMethod(); + int retval = m1.getName().compareTo(m2.getName()); + if (retval == 0) { + Class [] parms1 = m1.getParameterTypes(); + Class [] parms2 = m1.getParameterTypes(); + if (parms1.length < parms2.length) + retval = -1; + else if (parms1.length > parms2.length) + retval = 1; + else { + for (int i = 0; i < parms1.length; i++) { + retval = parms1[i].getName().compareTo(parms2[i].getName()); + if (retval != 0) + break; + } + } + } + return retval; + } + + public boolean equals(Object o) { + return o != null && o instanceof MethodDescriptorComparator; + } + } + + /** + * Sorts an input array of MethodDescriptors + */ + private Set sortMethodDescriptors(MethodDescriptor [] methodDescs) { + Set sortedMethodDescs = + new TreeSet(new MethodDescriptorComparator()); + for (int i = 0; i < methodDescs.length; i++) + sortedMethodDescs.add(methodDescs[i]); + return sortedMethodDescs; + } + + private void introspectMethodDescriptors(MethodDescriptor [] methodDescs) { + Set sortedMethodDescs = sortMethodDescriptors(methodDescs); + for (MethodDescriptor methodDesc : sortedMethodDescs) + introspectMethodDescriptor(methodDesc); + } + + private void introspectMethodDescriptor(MethodDescriptor methodDesc) { + printf(""); + indent(); + for (int i = 0; i < paramDescs.length; i++) + introspectParameterDescriptor(paramDescs[i]); + unindent(); + printf(""); + } + else + printf(""); + introspectFeatureDescriptor(methodDesc); + } + unindent(); + printf(""); + } + + private void introspectParameterDescriptor(ParameterDescriptor paramDesc) { + printf("", paramDesc.getDisplayName()); + indent(); + introspectFeatureDescriptor(paramDesc); + unindent(); + printf("", paramDesc.getDisplayName()); + } + + private void introspectPropertyDescriptor(PropertyDescriptor propDesc, boolean isDefault) { + printf("", propDesc.getDisplayName()); + indent(); + { + printf("type=\"%s\"", propDesc.getPropertyType().getName()); + printf("isBound=%b", propDesc.isBound()); + printf("isConstrained=%b", propDesc.isConstrained()); + printf("isDefault=%b>", isDefault); + + Method readMethod = propDesc.getReadMethod(); + if (readMethod != null) + printElement("read-method", readMethod.toGenericString()); + + Method writeMethod = propDesc.getWriteMethod(); + if (writeMethod != null) + printElement("write-method", writeMethod.toGenericString()); + + Class propertyEditorClass = propDesc.getPropertyEditorClass(); + if (propertyEditorClass != null) + printElement("property-editor-class", propertyEditorClass.getName()); + introspectFeatureDescriptor(propDesc); + } + unindent(); + printf("", propDesc.getDisplayName()); + } + + private void introspectEventSetDescriptor(EventSetDescriptor eventDesc, boolean isDefault) { + printf("", isDefault); + printElement("listener-type", eventDesc.getListenerType().getName()); + + Method meth = eventDesc.getAddListenerMethod(); + if (meth != null) + printElement("add-listener-method", meth.toGenericString()); + + meth = eventDesc.getRemoveListenerMethod(); + if (meth != null) + printElement("remove-listener-method", meth.toGenericString()); + + meth = eventDesc.getGetListenerMethod(); + if (meth != null) + printElement("get-listener-method", meth.toGenericString()); + + MethodDescriptor [] methodDescs = eventDesc.getListenerMethodDescriptors(); + if (methodDescs != null && methodDescs.length != 0) { + printf(""); + indent(); + introspectMethodDescriptors(methodDescs); + unindent(); + printf(""); + } + else printf(""); + introspectFeatureDescriptor(eventDesc); + } + unindent(); + } + + public static void main(String[] args) + throws Exception { + + if (args.length < 1) + System.err.println("Usage: java org.apache.beehive.controls.test.controls.util.ControlIntrospector [-path ] beanClass"); + + String className = null; + String outputPath = null; + for (int i = 0; i < args.length; i++) { + if (args[i].equals("-outputPath")) { + if (i + 1 < args.length) + outputPath = args[i + 1]; + else throw new RuntimeException("Invalid command line; unable to find value for \"-outputPath\""); + } + } + + className = args[args.length - 1]; + System.out.println("Create .beaninfo for class \"" + className + "\""); + if (outputPath != null) + System.out.println("Write .beaninfo to file \"" + outputPath + "\""); + + Class beanClass = Class.forName(className); + PrintStream ps = System.out; + try { + if (outputPath != null) + ps = new PrintStream(new FileOutputStream(new File(outputPath))); + + ControlIntrospector ci = new ControlIntrospector(beanClass, ps); + ci.introspect(); + } + finally { + if (ps != null && ps != System.out) + ps.close(); + } + } +} diff --git a/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/utils/ControlTestUtils.java b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/utils/ControlTestUtils.java new file mode 100644 index 0000000..aaed712 --- /dev/null +++ b/controls/test/src/junit-tests/org/apache/beehive/controls/test/junit/utils/ControlTestUtils.java @@ -0,0 +1,132 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ +package org.apache.beehive.controls.test.junit.utils; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +public final class ControlTestUtils { + + public static ByteArrayOutputStream serialize(Object object) + throws IOException { + // Test the relationships and identifiers are preserved across serialization and deserialization + ByteArrayOutputStream baos = null; + ObjectOutputStream oos = null; + try { + baos = new ByteArrayOutputStream(); + oos = new ObjectOutputStream(baos); + + oos.writeObject(object); + oos.close(); + } + finally { + if(oos != null) + oos.close(); + if(baos != null) + baos.close(); + } + return baos; + } + + public static Object deserialize(ByteArrayOutputStream baos) + throws IOException, ClassNotFoundException { + + Object object = null; + + ByteArrayInputStream bais = null; + ObjectInputStream ois = null; + try { + bais = new ByteArrayInputStream(baos.toByteArray()); + ois = new ObjectInputStream(bais); + object = ois.readObject(); + } + finally { + if(ois != null) + ois.close(); + if(bais != null) + bais.close(); + } + + return object; + } + + /** + Compare two bean info files. Two InputStream instances are created given the parameters + and compared byte-by-byte. Any difference between these comparisons will result in a + return value of false. + + @param expectedBeanInfo the String path to an expected beaninfo file that must be available in classloader + @param tempFile the location of a temporary file into which the actual beaninfo will be generated + @param controlBeanClass the type of control bean to introspect + @return false if the files differ by any byte; true otherwise + */ + public static boolean compareBeanInfo(String expectedBeanInfo, File tempFile, Class controlBeanClass) + throws Exception { + + assert controlBeanClass != null; + assert tempFile != null; + + FileOutputStream fos = null; + try { + fos = new FileOutputStream(tempFile); + ControlIntrospector ci = new ControlIntrospector(controlBeanClass, fos); + ci.introspect(); + } + finally { + if (fos != null) + fos.close(); + } + + boolean fail = false; + InputStream valid = null; + InputStream current = null; + try { + valid = controlBeanClass.getClassLoader().getResourceAsStream(expectedBeanInfo); + current = new FileInputStream(tempFile); + + assert valid != null; + assert current != null; + + int validVal; + int currentVal; + do { + validVal = valid.read(); + currentVal = current.read(); + + if(validVal != currentVal) + return false; + } while (validVal != -1); + } + finally { + if (current != null) + current.close(); + if (valid != null) + valid.close(); + } + + return true; + } +} diff --git a/distribution.xml b/distribution.xml new file mode 100644 index 0000000..23831b3 --- /dev/null +++ b/distribution.xml @@ -0,0 +1,735 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + distribution name: ${dist.name} + + + + + + + + + distribution directory: ${dist.dir} + distribution name: ${dist.name} + + + + + + + + + + + + Run RAT on ${dist.base.dir}/${dist.lib.name}. Output in build/rat-${dist.lib.name}.txt + + + + + Run RAT on ${dist.base.dir}/${dist.name}. Output in build/rat-${dist.name}.txt + + + + + Run RAT on ${dist.base.dir}/${dist.src.name}. Output in build/rat-${dist.src.name}.txt + + + + + Run RAT on ${dist.base.dir}/${dist.docs.name}. Output in build/rat-${dist.docs.name}.txt + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/build.xml b/docs/build.xml new file mode 100644 index 0000000..be3d879 --- /dev/null +++ b/docs/build.xml @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/dist-docs/README.txt b/docs/dist-docs/README.txt new file mode 100644 index 0000000..0ac43cc --- /dev/null +++ b/docs/dist-docs/README.txt @@ -0,0 +1,35 @@ + + +APACHE BEEHIVE + + Welcome to Beehive! + + +What is Beehive? +================ + + The goal of Beehive is to make J2EE programming easier by using JSR-175 metadata annotations + to simplify the most complex J2EE coding tasks. Beehive is divided into three + sub-projects: + + Page Flows -- Page Flows are built on top of Struts. The JSR-175 programming model + allows for automatic updating of Struts configuration files as well as + easy tooling inside of IDEs. + + Controls -- Controls are a framework for building lightweight J2EE components. + + Web Services -- The web services project implements JSR-181, a metadata annotation + driven programming model for web services. + +Documentation +============= + + Complete documentation, including a users guide, tutorials, and instructions for running samples, + is available locally at + + BEEHIVE_HOME/docs/index.html + + and online at + + http://beehive.apache.org/index.html + diff --git a/docs/dist-docs/rev-readme-trailer.txt b/docs/dist-docs/rev-readme-trailer.txt new file mode 100644 index 0000000..7e44be0 --- /dev/null +++ b/docs/dist-docs/rev-readme-trailer.txt @@ -0,0 +1,5 @@ + +Revisions +--------- +This distribution includes Apache Beehive SVN revision @BEEHIVE_REV@. + diff --git a/docs/dist-docs/toplvl-readme-trailer.txt b/docs/dist-docs/toplvl-readme-trailer.txt new file mode 100644 index 0000000..5145b42 --- /dev/null +++ b/docs/dist-docs/toplvl-readme-trailer.txt @@ -0,0 +1,9 @@ + + Download + ------------ + Please download + apache-beehive-svn-snapshot-*.{tar.gz or zip} + apache-beehive-svn-snapshot-lib-*.{tar.gz or zip} + + And also a local copy of the documentation if you wish + apache-beehive-svn-snapshot-docs-*.{tar.gz or zip} diff --git a/docs/forrest/build.xml b/docs/forrest/build.xml new file mode 100644 index 0000000..fc2b230 --- /dev/null +++ b/docs/forrest/build.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/forrest/release/build.xml b/docs/forrest/release/build.xml new file mode 100644 index 0000000..d034502 --- /dev/null +++ b/docs/forrest/release/build.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/forrest/release/forrest.properties b/docs/forrest/release/forrest.properties new file mode 100644 index 0000000..f4c6df2 --- /dev/null +++ b/docs/forrest/release/forrest.properties @@ -0,0 +1,129 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +############## +# Properties used by forrest.build.xml for building the website +# These are the defaults, un-comment them only if you need to change them. +############## + +# Prints out a summary of Forrest settings for this project +#forrest.echo=true + +# Project name (used to name .war file) +#project.name=my-project + +# Specifies name of Forrest skin to use +# See list at http://forrest.apache.org/docs/skins.html +#project.skin=pelt + +# Descriptors for plugins and skins +# comma separated list, file:// is supported +#forrest.skins.descriptors=http://forrest.apache.org/skins/skins.xml,file:///c:/myskins/skins.xml +#forrest.plugins.descriptors=http://forrest.apache.org/plugins/plugins.xml,http://forrest.apache.org/plugins/whiteboard-plugins.xml + +############## +# behavioural properties +#project.menu-scheme=tab_attributes +#project.menu-scheme=directories + +############## +# layout properties + +# Properties that can be set to override the default locations +# +# Parent properties must be set. This usually means uncommenting +# project.content-dir if any other property using it is uncommented + +#project.status=status.xml +#project.content-dir=src/documentation +#project.raw-content-dir=${project.content-dir}/content +#project.conf-dir=${project.content-dir}/conf +#project.sitemap-dir=${project.content-dir} +#project.xdocs-dir=${project.content-dir}/content/xdocs +#project.resources-dir=${project.content-dir}/resources +#project.stylesheets-dir=${project.resources-dir}/stylesheets +#project.images-dir=${project.resources-dir}/images +#project.schema-dir=${project.resources-dir}/schema +#project.skins-dir=${project.content-dir}/skins +#project.skinconf=${project.content-dir}/skinconf.xml +#project.lib-dir=${project.content-dir}/lib +#project.classes-dir=${project.content-dir}/classes +#project.translations-dir=${project.content-dir}/translations + +############## +# validation properties + +# This set of properties determine if validation is performed +# Values are inherited unless overridden. +# e.g. if forrest.validate=false then all others are false unless set to true. +#forrest.validate=true +#forrest.validate.xdocs=${forrest.validate} +#forrest.validate.skinconf=${forrest.validate} +#forrest.validate.sitemap=${forrest.validate} +#forrest.validate.stylesheets=${forrest.validate} +#forrest.validate.skins=${forrest.validate} +#forrest.validate.skins.stylesheets=${forrest.validate.skins} + +# *.failonerror=(true|false) - stop when an XML file is invalid +#forrest.validate.failonerror=true + +# *.excludes=(pattern) - comma-separated list of path patterns to not validate +# e.g. +forrest.validate.xdocs.excludes=netui/references/taglib/**,samples/subdir/**,samples/faq.xml +#forrest.validate.xdocs.excludes= + + +############## +# General Forrest properties + +# The URL to start crawling from +#project.start-uri=linkmap.html + +# Set logging level for messages printed to the console +# (DEBUG, INFO, WARN, ERROR, FATAL_ERROR) +#project.debuglevel=ERROR + +# Max memory to allocate to Java +#forrest.maxmemory=64m + +# Any other arguments to pass to the JVM. For example, to run on an X-less +# server, set to -Djava.awt.headless=true +#forrest.jvmargs= + +# The bugtracking URL - the issue number will be appended +#project.bugtracking-url=http://issues.apache.org/bugzilla/show_bug.cgi?id= +#project.bugtracking-url=http://issues.apache.org/jira/browse/ + +# The issues list as rss +#project.issues-rss-url= + +#I18n Property. Based on the locale request for the browser. +#If you want to use it for static site then modify the JVM system.language +# and run once per language +#project.i18n=true + +# The names of plugins that are required to build the project +# comma separated list (no spaces) +# You can request a specific version by appending "-VERSION" to the end of +# the plugin name. If you exclude a version number the latest released version +# will be used, however, be aware that this may be a development version. In +# a production environment it is recomended that you specify a known working +# version. +# Run "forrest available-plugins" for a list of plug-ins currently available +project.required.plugins=org.apache.forrest.plugin.output.pdf + +# Proxy configuration +# proxy.host= +# proxy.port= diff --git a/docs/forrest/release/src/documentation/README.txt b/docs/forrest/release/src/documentation/README.txt new file mode 100644 index 0000000..9bc261b --- /dev/null +++ b/docs/forrest/release/src/documentation/README.txt @@ -0,0 +1,7 @@ +This is the base documentation directory. + +skinconf.xml # This file customizes Forrest for your project. In it, you + # tell forrest the project name, logo, copyright info, etc + +sitemap.xmap # Optional. This sitemap is consulted before all core sitemaps. + # See http://forrest.apache.org/docs/project-sitemap.html diff --git a/docs/forrest/release/src/documentation/classes/CatalogManager.properties b/docs/forrest/release/src/documentation/classes/CatalogManager.properties new file mode 100644 index 0000000..6e9436c --- /dev/null +++ b/docs/forrest/release/src/documentation/classes/CatalogManager.properties @@ -0,0 +1,57 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#======================================================================= +# CatalogManager.properties for Catalog Entity Resolver. +# +# This is the default properties file for your project. +# This facilitates local configuration of application-specific catalogs. +# If you have defined any local catalogs, then they will be loaded +# before Forrest's core catalogs. +# +# See the Apache Forrest documentation: +# http://forrest.apache.org/docs/your-project.html +# http://forrest.apache.org/docs/validation.html + +# verbosity: +# The level of messages for status/debug (messages go to standard output). +# The setting here is for your own local catalogs. +# The verbosity of Forrest's core catalogs is controlled via +# main/webapp/WEB-INF/cocoon.xconf +# +# The following messages are provided ... +# 0 = none +# 1 = ? (... not sure yet) +# 2 = 1+, Loading catalog, Resolved public, Resolved system +# 3 = 2+, Catalog does not exist, resolvePublic, resolveSystem +# 10 = 3+, List all catalog entries when loading a catalog +# (Cocoon also logs the "Resolved public" messages.) +verbosity=1 + +# catalogs ... list of additional catalogs to load +# (Note that Apache Forrest will automatically load its own default catalog +# from main/webapp/resources/schema/catalog.xcat) +# Use either full pathnames or relative pathnames. +# pathname separator is always semi-colon (;) regardless of operating system +# directory separator is always slash (/) regardless of operating system +catalogs=../resources/schema/catalog.xcat + +# relative-catalogs +# If false, relative catalog URIs are made absolute with respect to the +# base URI of the CatalogManager.properties file. This setting only +# applies to catalog URIs obtained from the catalogs property in the +# CatalogManager.properties file +# Example: relative-catalogs=[yes|no] +relative-catalogs=no diff --git a/docs/forrest/release/src/documentation/content/xdocs/beehive/guide.xml b/docs/forrest/release/src/documentation/content/xdocs/beehive/guide.xml new file mode 100644 index 0000000..df83426 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/beehive/guide.xml @@ -0,0 +1,52 @@ + + + +

    + Putting the Pieces Together +
    + +
    + How Do NetUI, Controls, and Web Services Fit Together? +

    NetUI makes building Java web applications easy and intuitive. When programming with NetUI, the developer writes Java classes and pages -- that's it. There is very little occasion to work with configuration files or other components. NetUI programming is not only simple, it is also excells at separating the presentation logic from the data processing logic. This results in uncluttered JSP code which is easy to understand and edit. Moreover, many of the most difficult programming tasks, such as security and validation, are handled with a simple declarative programming model using Java annotations.

    +
    +
    + How Does NetUI Work? +

    A NetUI "page flow" consists of a single directory containing a Java class, called the "controller", and any number of pages (often JSPs). + The role of the pages is to present a visual interface for users of the web application. The role of the controller class is to coordinate all of the things that can happen when a user visits a web site. These duties include: handling user requests, fashioning responses to user requests, preserving session state, and coordinating back-end resources (such as databases and web services).

    +

    The JSP files use special tags (the <netui> tags) and databinding expressions which bind the user interface to objects and actions in the controller class. +

    +

    tbd: need diagram here

    +

    The action methods in the controller class implement code that can result in site navigation, passing data, or invoking back-end business logic via controls. + Significantly, the business logic in the controller class is separate from the presentation code defined in the JSP files. + The overall purpose of a page flow is to provide you with an easy-to-use framework for building dynamic, sophisticated web applications. + While page flows give you access to advanced features of J2EE, you do not have to be a J2EE expert to quickly develop and deploy Java-based applications built on page flows.

    +

    The programming model: annotations, data binding expressions, <netui> tags, etc.

    +
    + +
    + Submitting Data: Form Beans, and Data Binding +
    +
    + Processing Data +
    +
    + Displaying Data +
    +
    + Accessing Back-End Resources with Controls +
    +
    + Validation +
    +
    + Security +
    + +
    + Java, J2EE, and JCP are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.
    + © 2004, Apache Software Foundation +
    +
    + diff --git a/docs/forrest/release/src/documentation/content/xdocs/controls/annotations/control_annotations.xml b/docs/forrest/release/src/documentation/content/xdocs/controls/annotations/control_annotations.xml new file mode 100644 index 0000000..ddc4435 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/controls/annotations/control_annotations.xml @@ -0,0 +1,56 @@ + + + +
    + Control Annotations +
    + +
    + Controls Annotations +

    @AnnotationConstraints.AllowExternalOverride

    +

    @AnnotationConstraints.MembershipRule

    +

    @AnnotationConstraints.MembershipRuleValues

    +

    @AnnotationConstraints.RequiredRuntimeVersion

    +

    @AnnotationMemberTypes.Date

    +

    @AnnotationMemberTypes.Decimal

    +

    @AnnotationMemberTypes.FilePath

    +

    @AnnotationMemberTypes.Int

    +

    @AnnotationMemberTypes.JndiName

    +

    @AnnotationMemberTypes.JndiName.ResourceType

    +

    @AnnotationMemberTypes.Optional

    +

    @AnnotationMemberTypes.QName

    +

    @AnnotationMemberTypes.Text

    +

    @AnnotationMemberTypes.URI

    +

    @AnnotationMemberTypes.URL

    +

    @AnnotationMemberTypes.XML

    +

    @BaseProperties

    +

    @BeanInfo

    +

    @Client

    +

    @Context

    +

    @Control

    +

    @ControlExtension

    +

    @ControlImplementation

    +

    @ControlInterface

    +

    @ControlReferences

    +

    @EventHandler

    +

    @EventSet

    +

    @EventSetInfo

    +

    @ExternalPropertySets

    +

    @FeatureAttribute

    +

    @FeatureInfo

    +

    @ManifestAttribute

    +

    @ManifestAttributes

    +

    @PropertyInfo

    +

    @PropertySet

    +

    @Threading

    +

    @Version

    +

    @VersionRequired

    +

    @VersionSupported

    +
    + +
    + Java, J2EE, and JCP are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.
    + © 2004, Apache Software Foundation +
    +
    +
    \ No newline at end of file diff --git a/docs/forrest/release/src/documentation/content/xdocs/controls/containment.xml b/docs/forrest/release/src/documentation/content/xdocs/controls/containment.xml new file mode 100644 index 0000000..e0a0677 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/controls/containment.xml @@ -0,0 +1,239 @@ + + + + +
    + Controls Containment +
    + + +
    Overview + +

    This document describes the basic architecture for how Beehive Controls interact with the + runtime container they are executing within. Examples of runtime containers for Controls + include: +

    + +
      +
    • Servlet Container
    • +
    • EJB Container
    • +
    • Web Services (WSM)
    • +
    • Client JVM
    • +
    • JUnit Test Container (standalone testing)
    • +
    • ...
    • +
    + +

    The base runtime comes with a sample container integration for the servlet container, but the container integration model is flexible enough to support any and all of the above containers, as well as enabling the list above to be extended or customized in new and interesting ways. The model makes it possible to author controls that run in a wide variety of containers, as well as ones that expect and leverage the capabilities of a specific container (where desirable). +

    + +

    This is possible because there is a basic architecture for how Controls will interact with their container. This includes the interfaces for how a new type of container can be constructed, or for how an existing runtime environment can be extended to act as a container of controls. +

    + +

    There are two target audiences for this document:

    + +
      +
    • A Control author who wants a deeper understanding of how controls interact with their runtime environment for resource management, configuration, contextual services, etc.
    • +
    • A Control container developer who wants to define a new type of Control container to integrate support for Beehive Controls into an existing environment. +
    • +
    + +
    + +
    Basic Architecture + +

    This section outlines the basic implementation architecture for Control containment. Containment is based upon an existing JavaBean standard for bean composition and services, and build atop this to provide additional features that are unique to Controls. +

    + +
    + The Foundation: JavaBeans Containment + +

    The basic foundation of Control Containment is the Extensible Runtime Containment and Services Protocol For JavaBeans", a little known but useful containment model for JavaBeans that has been part of J2SE since 1.2. The intent of the protocol (actually, a set of interfaces and supporting implementation classes) was to add a simple containment model for JavaBeans, as well as a mechanism for allowing beans to discover, request, and use services provided by their container. All of the APIs defined by the protocol live in the java.beans.beancontext package. +

    + +

    This diagram shows the basic architecture for this protocol:

    + +

    + +

    + +

    The basic concepts shown in the diagram are: +

    + +
      +
    • A JavaBean can be nested within a BeanContext that acts as a container for one (or more) beans.
    • +
    • A BeanContext can itself be nested within another BeanContext, enabling hierarchical composition.
    • +
    • A BeanContext can provide the JavaBean with access to services. These services may be directly implemented by the BeanContext, or the BeanContext may simply act as a discovery mechanism/bridge to services provided by the runtime environment of the BeanContext.
    • +
    + +

    Some of the key classes are described in the following sections: +

    + +
    BeanContext + +

    The java.beans.beancontext.BeanContext interface defines the basic interface for a container of JavaBeans. It derives from the java.util.Collection interface, so the standard Collection APIs can be used to add, remove, and iterate over the JavaBeans contained within the context. It also extends the java.beans.beancontext.BeanContextChild interface (see next section), meaning it is possible for one BeanContext to be nested within another BeanContext, forming a hierarchical structure. +

    + +

    Whenever you see word "BeanContext" throughout this document or in API names, mentally replace it with "JavaBeans Container". +

    + +
    + +
    BeanContextChild + +

    The java.beans.beancontext.BeanContextChild interface defines the basic interface that will be implemented (directly or indirectly via java.beans.beancontext.BeanContextProxy) by a JavaBean that wants to be contained within/access the services of a BeanContext. It defines the basic mechanism for setting/retrieving the parent BeanContext for a JavaBean, as well as the APIs for listening to / vetoing property changes on the nested bean. +

    + +
    + +
    BeanContextServices + +

    The java.beans.beancontext.BeanContextServices interface derives from the BeanContext interface and defines a BeanContext that is capable of providing services to the JavaBeans contained within it. It defines a model for how services can be discovered and used by the contained JavaBeans, as well as a model for how service providers can register themselves with the context so their services will be available. +

    + +

    Service discovery is hierarchical; if a particular BeanContext does not implement a service requested by a contained JavaBean, but is itself contained within another BeanContext, it will delegate the request upwards to see if any parent context can provide the requested service. +

    + +
    + +
    + +
    Building Up: Controls Containment + +

    The Beehive Controls runtime builds atop the base JavaBeans BeanContext model by adding a set of interfaces and support classes that provide containment and composition services that are unique to Controls. This section provides an overview of this functionality, and a subsequent section on Control Container Services will describe them in more detail. +

    + +
    ControlBeanContext + +

    The org.apache.beehive.controls.api.context.ControlBeanContext interface extends the base java.bean.BeanContextServices interface to add the unique services available to JavaBeans that are Beehive Controls. These include access to control property values bound by annotations, external configuration, or client invocation of property accessors, as well as a unique set of lifecycle events. +

    + +

    Every Control is guaranteed to have an associated peer ControlBeanContext that can be used to query Control properties, nest other controls (either declaratively or programmatically), and to receive lifecycle events. This is true even if the Control is not itself nested within a parent context. +

    +

    This peer ControlBeanContext can be obtained by declaring:

    + + + + @Context ControlBeanContext myContext; + + +

    within the Control Implementation class, or by calling the org.apache.beehive.controls.api.bean.ControlBean.getControlBeanContext() API on a Control bean instance. +

    + +
    Control Identifiers + +

    The ControlBeanContext interface goes beyond the simple java.util.Collection collection capabilities of the base BeanContext class to also manage a unique identifier associated with each contained Control. This identifier can come from a number of different sources: +

    + +
      +
    • An argument to the bean constructor
    • +
    • The field name, for an instance field annotated with @Control. In the example above, the Control ID would be "myContext"
    • +
    • The ControlBeanContext will autogenerate a unique one, if none is provided
    • +
    + +

    Because Controls can be hierarchically nested inside one another, a given Control instance actually has two IDs: the local (or BeanContext relative) ID that was provided by one of the mechanisms above and a full (or absolute) ID that is built by concatenating the IDs of all Controls from the root BeanContext down to the control, using a forward slash ('/') as a separator. +

    + +

    For example, the Control ID "foo/bar" refers to the Control with a local ID of "bar" that is nested inside the control with a local ID of "foo" in the root context. +

    + +

    An absolute Control ID is effectively a unique address that allows a control within a BeanContext hierarchy to be located by traversing the ownership path of Controls defined by this composite identifier. +

    + +

    This is useful in a number of contexts:

    + +
      +
    • To enable external configuration based upon identifier (usage context) rather than just a type.
    • +
    • To locate a specific control instance within a hieararchy by navigating the BeanContext tree based upon the ID. This can be useful in scenarios such as an external event dispatch.
    • +
    + +
    + +

    The org.apache.beehive.controls.runtime.bean.ControlBeanContext class provides a concrete implementation of the ControlBeanContext interface for the Controls runtime. +

    +

    This class is used:

    +
      +
    • To provide the basic set of services for Controls. Every instantiated Control will have an associated ControlBeanContext to provide access to properties, or to contain nested Controls.
    • +
    • As a base class for other types of Control containers. These common services are also available for other types of containers that want to support controls. A later section describes this in more detail.
    • +
    + +
    + +
    ControlBean + +

    The org.apache.beehive.controls.api.bean.ControlBean interface defines a base interface implemented by all Controls. It provides accessors for: +

    + +
      +
    • The parent BeanContext of the Control
    • +
    • The peer ControlBeanContext providing property access and containment for nested controls
    • +
    • The (absolute) Control ID of the Control
    • +
    • The public interface (@ControlInterface or @ControlExtension) implemented by the Control.
    • +
    + +

    The org.apache.beehive.controls.runtime.bean.ControlBean class provides a concrete implementation of the ControlBean interface, and is used as the base class for all code-generated Control JavaBeans. +

    + +
    + +
    ControlContainerContext + +

    The + org.apache.beehive.controls.runtime.bean.ControlContainerContext class extends the base ControlBeanContext class to define a base integration model (and default implementation, where appropriate) of containment and services to integrate an external container type with the Controls runtime. Examples of existing external containers for controls are the Servlet container, + the EJB container, the Spring bean container, ... +

    + +

    An external container can provide additional services to Controls that are running within its scope, such as a definition of how long it is OK for Controls to acquire and hold resources, the integration of a native container configuration model, or contextual services that are unique and specific to the container. +

    + +

    For any given container, a custom subclass of the ControlContainerContext class can be provided that defines the unique attributes and semantics of the container for controls executing within it. For example, the ServletBeanContext class provided as part of the Controls runtime provides control containment for the web tier. The ServletBeanContext defines the resource scope for Controls such that any control instance can hold a resource (connection, session, ...) for the lifetime of a single http request (but no longer). Additionally, it exposes web-tier-specific contextual services, such as access to the current ServletContext or active HttpServletRequest instance. +

    + +

    The following section on Control Container Services describes many of the services and behaviors that can be customized by a ControlContainerContext subclass. +

    + +

    A ControlContainer context is intended to be the root context which will contain (either directly, or indirectly via nested BeanContexts) all Controls used within the scope of a container instance. Generally speaking, the relationship between container instances and ControlContainerContext instances will be one-to-one. +

    + +

    Impl Note: there really should be an org.apache.beehive.controls.spi.context.ControlContainerContext interface that defines the basic interface for Controls containment, with the above class acting as the concrete implementation thereof. This follows the pattern used everywhere else, and decouples the declaration of control container requirements from its implementation. +

    + +
    + +
    + +
    + +
    Control Container Services + +

    The interactions between a control and its container are best expressed in terms of the set of functional services that the container provides to the control. This provides a basic framework for understanding what happens at runtime when a Control uses those services (for the Control author) as well as the effort required to integrate these services into a specific container (for the Control container developer). +

    + + + +
    + +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/controls/index.xml b/docs/forrest/release/src/documentation/content/xdocs/controls/index.xml new file mode 100644 index 0000000..9ad94e9 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/controls/index.xml @@ -0,0 +1,36 @@ + + + +
    + Controls: Getting Started +
    + +

    + To get started developing and using controls, see the user's guide topics: +

    + +

    + The following project template will help you get a Control project started: +

    + +

    + The following tutorial will familiarize you with the steps for building and testing a Control: +

    + + +
    + + Java, J2EE, and JCP are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. +
    + © 2004, Apache Software Foundation +
    +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/controls/overview.xml b/docs/forrest/release/src/documentation/content/xdocs/controls/overview.xml new file mode 100644 index 0000000..3220185 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/controls/overview.xml @@ -0,0 +1,768 @@ + + + +
    + Controls Overview +
    + +
    + Overview +
    + The Problem with J2EE: Complexity +

    + J2EE provides a rich set of component types, protocols, and system services that can be used to + assemble an application or service. But as the scope of the J2EE architectural design space has + grown, the complexity of assembling solutions has also grown. This has created a problem for + developers who are not J2EE experts: J2EE solutions are often too complex for non-experts to + effectively utilize them. +

    +

    + An objective of the Beehive community is to expand beyond the systems software developer who has + traditionally built J2EE solutions to enfranchise those developers who may have less experience with + object-oriented design, building distributed systems, and Java/J2EE. +

    +

    + + The goal is to enable a new collaboration where the base J2EE distributed system architecture + and back-end components can be designed and built by the J2EE system software developer, then + assembled into exposed web user interfaces, web services, or applications by the application + developer. + +

    +

    + Without this new collaboration, the application developer might have to learn a variety of new + technologies and APIs to work within the architecture. +

    +

    + Consider a simple example: A systems developer has built a distributed system where services are + exposed as Enterprise JavaBeans and JMS queues. An application developer new to J2EE is tasked with + building a web user interface that integrates with these services. +

    +

    To accomplish this task, the application developer now has to learn how to:

    +
      +
    • + Create a JNDI context and lookup resources. If resources are app-scoped, then he must learn how + to provide the appropriate deployment descriptor configuration. +
    • +
    • + Use interfaces of exposed EJBs to access methods, including understanding differences in usage + depending upon whether the exposed EJBs are Stateless Session Beans, Stateful Session Beans, or + Entity Beans. +
    • +
    • Obtain JMS connections/sessions, and references to queues.
    • +
    • Construct and enqueue a JMS message.
    • +
    • + Properly manage the resources associated with the above, such that vital system resources (such + as connections) are used efficiently and correctly. The cost of a subtle mistake can be poor + system performance or even system failure. +
    • +
    +

    + What initially appears to be a simple task in the abstract (call these EJBs or enqueue a message + that looks like this) can devolve into hours or days of reading J2EE HowTo books and Javadoc API + references, getting the right deployment descriptor values configured, and calling all the right + APIs, at all of the right times, in the right order. In the resulting application or service, often + the directly application-related code (i.e. calling the method or building message contents) is a + small fraction of the total code required to accomplish the task. +

    +

    + Here is an example of the code required to invoke a single method (buy()) on an exposed EJB using standard J2EE APIs: +

    + + + +

    + A common solution to this problem is often to task the J2EE professional developer with constructing + facades or custom frameworks that hide some of the underlying complexity of the resource access + mechanisms and provides appropriate guarantees that system resources (connections, sessions, + handles, etc) are utilized properly. But constructing these intermediate abstractions is an + inefficient use of (often scarce and expensive) systems development resources. Depending upon the + "thickness" of the intermediate abstractions, this approach can also have performance or application + deployment footprint implications. +

    +
    +
    + Solution: Controls: A Unified Client Programming Model +

    + Controls reduce the complexity and learning curve associated with acting as a client of J2EE + resources by providing a unified client model that can provide access to diverse types of resources. + Controls provide the following features for reducing the learning curve for non-expert developers: +

    +
      +
    1. + To a Control client, Controls appear as JavaBeans that can be instantiated and used for resource + access. Controls present operations on the J2EE resource as methods on a JavaBean interface. +
    2. +
    3. + Properties that parameterize resource access can be set using Java 5 metadata. + This configuration mechanism is consistent across all J2EE resource types. +
    4. +
    5. + Controls provide a consistent model for discovering the resource's configuration options and + operations. +
    6. +
    7. + Controls can also provide transparent (to the client) resource management of connections, + sessions, or other resources to be obtained on behalf of the client, held for an appropriate + resource scope to achieve best performance, and then released. This resource management + mechanism frees the client from having to learn or understand the acquisition mechanisms, and + from having to directly participate in guaranteeing their release. The Controls architecture + provides this functionality by defining a simple resource management contract that can cooperate + with an outer container to manage resources at the appropriate scope (for example, bounded to a + transaction context or outer container operation or request scope). +
    8. +
    +

    + Using a Control to expose the Trader EJB in the earlier example, the code to invoke the buy() method + can become: +

    + + + +

    + The Trader Control fully encapsulates the JNDI lookup as well as the home/bean interface operations + needed to get an instance of the Trader EJB and invoke the buy() method on it, and exposes the JNDI + name of the EJB as a property that can be set via a metadata annotation. +

    +

    + Controls also provide an extensibility model that allows customized views of a resource to be + constructed, with discrete operations defined as methods on the control. For example, it is possible + to define a custom operation on a Control type representing a JMS queue resource that uses metadata + attributes to define the format of the message with message contents set from message parameters. + This enables an application developer to construct new customized facades for resource access + with less effort. +

    +

    + The goal of the Controls architecture is not to define the standards for how specific resource types + will be exposed; rather, it is to guarantee that when exposed they will have a commonality in + mechanism that makes them easier to understand and use by developers. +

    +
    +
    + Another Problem: Tooling Challenges +

    + Beyond adding to overall complexity, the diversity of J2EE resource types and access mechanisms also + makes it difficult for tools to offer assistance to developers who need to use them. +

    +

    + + For existing client models, the configuration of resource access is often some combination of + resource-specific API usage and deployment descriptor entries. This generally requires custom + IDE code that knows how to generate the right (resource-specific) code or configuration entries. + +

    +

    + Specific resource types often need custom code in order to define wizards or property-driven user + interface that aids in the process of defining a client of the resource. There is no common + mechanism for discovering the potential set of configurable attributes for a resource type. This + means that any graphical presentation of client attributes or wizards must be custom-authored based + upon resource type. +

    +

    + Once configured, there is the secondary problem of how the IDE represents a configured client + resource in source form. There are at least two potential options: save the attributes as generated + source code and/or deployment descriptor entries that are resource-specific or define a canonical + representation that is native to the IDE. Both are problematic. Two-way editing can be difficult, if + the canonical format is generated source code or descriptors are visible to the end user and + directly editable. Using some IDE-specific canonical representation (either based upon a closed + framework or configuration data) means the configured client abstraction isn't portable to other + development environments or editable outside of the IDE. +

    +

    + Using the IDE to develop directly to native resource APIs or descriptor formats is also lacking in + that it doesn't necessary have an associated constraint or extensibility model. If a resource should + be consistently accessed with a particular configuration or expected semantics, there is no good way + to describe resource constraints for clients or to enforce that they are followed. A concrete + example is a JMS queue where it is expected that messages will always conform to a specific format + or contain an expected set of properties. There is no good way of representing this constraint to + the client, short of runtime errors when the message does not comply with the constraint. +

    +

    + The lack of a single canonical representation also makes it difficult for the systems developer to + collaborate with the application developer, short of constructing and exposing custom facades for + client access. But even then, there is the IDE problem of knowing what facades are available, and + how they should be configured and used once selected. +

    +

    + + Without any well-defined source format for representing client resource configuration, packaging + models, or discovery mechanisms, there is no non-proprietary way for the IDE to present the + notion of configured resources, nor to pre-configure client access to resources. + +

    +
    +
    + Solution: A Unified Tooling Model +

    + Controls, like the JavaBeans upon which they are built, are designed for tooling. Beyond the common + programming model presented to developers, Controls also offer resource discovery and property + introspection mechanisms that allow an IDE to locate available Controls and present and + interactively configure their properties. +

    +

    + + Because Controls expose operations, events, and properties using common mechanisms, an IDE can + support client use cases based upon these mechanisms as well as a common authoring model for + defining new types of Controls, without the need for a large amount of resource-specific code. + +

    +

    + Using a common client model allows a single base of IDE code to allow the use of a variety of + resource types, based upon introspection. Using a shared model (and code) for presenting and + configuring client access also results in a consistent user experience when working with resources, + both on the client and authoring side. While the developer might be using a diverse set of resources + in the course of building a user interface, service, or application, the learning curve from a user + interaction perspective can be reduced in the same way that it is reduced from an API perspective by + having a common model. +

    +

    + + Controls extend the base properties support of JavaBeans to add support for metadata + annotations, constraints, and an extensibility model, allowing an IDE to define new Control + types that are pre-configured for specific resource access use cases. + +

    +

    + The earlier programming example showed a simple customized Control defined to access an Enterprise + JavaBean advertised at a particular JNDI location. This example could easily have been constructed + by an IDE using JMX to explore advertised EJBs on a J2EE server, and then generating the necessary + Control definition that exposes the EJB with the specific home/business interfaces represented as + operations on the bean and the correct JNDI location pre-configured as an attribute. +

    +

    + The Controls architecture supports the definition of configuration options list for a particular + Control type. This lists the base set of properties that are associated with the type and can be + used to: +

    +
      +
    • + Specify the attributes in the set that can be configured using metadata annotations, and the + syntax for doing so. This enables an IDE to present property-style selection of metadata-based + attributes and values, as well as providing the ability to validate the annotations on any usage + of the type and relationships between annotations. +
    • +
    • + Specify the attributes in the set that should be settable dynamically using property + getters/setters on instances of the type. This can be used to support auto-generation of Control + types with property accessors based upon the attribute set. +
    • +
    • + Derive a schema for representing the configuration of the attribute set using XML. These can be + used in common tools for state management (to persist the representation of a Control instance + and its attributes as XML) as well as in an externalized configuration mechanism that allows + attributes to be bound externally using deployment descriptor-style configuration files. This + makes the construction of instance introspectors and administrative tools much more + straightforward, as compared to using ad-hoc deployment descriptor formats. +
    • +
    +

    + Controls also provide a JAR-based packaging mechanism, for how Control types can be discovered + within a jar. +

    +

    + + The Controls architecture provides a well-defined packaging model that enables system vendors, + 3rd party providers, or J2EE system developers (in the collaborative scenario) to distribute + controls that offer client access to provided services or components. An IDE can then discover + packaged controls to present them in a palette or list of available resource types for client + use. + +

    +
    +
    +
    + The Controls Architecture +

    + The following picture shows the basic runtime architecture and the relationships between a resource + client, the associated Control, and the accessed J2EE resource: +

    +

    + +

    +

    + The Resource Client represents user code in a web application, service, or application that needs access + to the J2EE resource. The Resource Client and supporting Control will always live in the same virtual + machine and communicate directly using local Java method invocation. The accessed resource may or may + not reside within the same virtual machine, depending upon the nature of the resource and the + application server environment. +

    +

    + Dynamic property accessors and resource operations are exposed on the Control and used by the client to + initiate resource access. Data from the resource may be returned as return values from operations or + fired as events on the bean event interface to registered listeners. +

    +

    + Resource access may be parameterized by metadata annotations declared directly on the Control instance, + class, or method declarations, or by properties provided to the factory-based constructor. In addition + to this, there is an external configuration model for how properties can be bound from external + configuration (ex. deployment descriptors), enabling deploy-time binding of attributes. Examples of + resource attributes that might be parameterized by metadata or external configuration or JNDI names + associated with resources, resource or protocol configuration, message formats, etc. +

    +

    + The Control itself will often hold a reference to a resource proxy associated with the accessed + resource, and will use the proxy to enact operations requested by the client. Examples of resource + proxies are EJB home or remote stubs, JMS connections or sessions, web service client proxies, etc. The + Control manages the state and lifetime of this proxy reference, coordinated by a set of resource + management notification events that are provided to it indicating how long the proxy resources can be + held by an outer container that determines the resource scope. +

    +

    + The actual communication between the resource proxy and the resource itself is generally a function of + the underlying resource. For EJBs, it might reflect communication via RMI or local Java invocation, for + web services it might be service invocation based upon the exchange of XML documents over standard web + protocols. +

    +

    + The following sections describes some of the key features and attributes of the Controls Architecture: +

    +
    + Public Interface / Private Implementation / ControlBean Wrapper +

    + The definition of a new resource type in the Control architecture is composed of three distinct + classes: +

    +
      +
    • + The public Control Public Interface defines the set of operations and events that are exposed + for the resource type. For example, if you were authoring a control for database access, the + class DatabaseControl would be the public resource interface for the database resource. Clients + to the database control would call the methods on this class to get resources from the database. +
    • + + +
    • + The private Control Private Implementation class provides the implementation of resource + operations as well as proxy resource management. In the case of a database control, the class + DatabaseControlImpl would provide the implementation of the various methods that access the + database resource. +
    • + +
    • + The Control Bean Wrapper class is the JavaBean wrapper around the implementation class that + provides the property accessor implementation (for example, through the definition of metadata + annotations), per-instance storage of dynamic properties, and property resolution services. It + also performs initialization of contextual services and nested Controls. (Note that the control + author is not responsible for authoring this class directly: it is an artifact of the Beehive + controls build process.) +
    • +
    +

    The relationship and functions of these classes is summarized in the following diagram:

    +

    + +

    +

    + The following picture shows how these 3 classes work together to fulfill the runtime + responsibilities shown in the earlier architecture diagram: +

    +

    + +

    + +
    +
    + A Flexible Property Model +

    + A key aspect of the Controls architecture is a flexible configuration model for how resource access + attributes will be resolved. Properties can be used to parameterize resource access, providing + attributes such as JNDI names for local resources, web service URLs, connection attributes, etc. +

    +

    + It is possible to introspect a bean and set the available set of properties. Additionally, Controls + move beyond the traditional property setter/getter to provide some additional capabilities: +

    +
      +
    • + Enables the assignment of Control properties using metadata annotations on Control classes, + instances, or methods. +
    • + +
    • + Provides a consistent externalized property binding model, so resource attributes can be managed + without requiring changes to source code. +
    • +
    +

    + The three property configuration mechanisms (programmatic property accessors on the Control, + metadata annotations on Control declarations, and external deployment descriptor-style + configuration) have a well-defined property resolution precedence that is implemented and enforced + by the Control base implementation. The precedence (from highest to lowest) is: +

    +
      +
    • Programmatically set property value
    • + +
    • Externally configured property value
    • + +
    • Metadata-defined property value
    • +
    +

    + In other words, the resource client can override a value defined by either externalized + configuration or metadata, and a value defined in externalized configuration can override a + metadata-defined value. +

    +

    + To ensure that this flexibility is not misused where it is not desirable, it is also possible to + declaratively specify the mechanisms that can be used to set attribute values. So an attribute could + be marked as 'read-only' from a programmatic perspective, and would only have a getter and not a + setter, or a metadata-based attribute could be marked as bound in a 'final' way that prevents + override by either external configuration or programmatic mechanisms. This is useful in the + previously described collaborative scenario, where the J2EE Systems Developer who is responsible for + resource access definitions via Controls might want to constrain the flexibility that the Control + consumer has in modifying those definitions upon use. +

    +

    + In the DatabaseControl example, an attribute might exist to set the JNDI data source of the resource + database. For this attribute, it might be desirable to set the value programmatically, externally, + or using metadata annotations. +

    +

    The declaration of the DatabaseControl metadata annotation and member might look something like:

    + + + +

    + This defines a metadata attribute (@ConnectionDataSource) that has a String member value named + 'jndiName'. +

    +

    + An example of setting the jndiName member of the DatabaseControl metadata attribute inside of client + code might look like: +

    + + + +

    The DatabaseControl will also advertise the following JavaBean property accessor methods:

    + + + +

    This accessor could be used from client code, as in the following example:

    + + + +

    + The configuration of the jndiName member based upon external configuration can take the shape of a + traditional XML configuration file: +

    + + + someJndiDataSource + +]]> + +

    + Note that you can turn off programmatic access and external configuration of control properties + through the + hasSetters + and + externalConfig + properties on @PropertySet: +

    + + + +

    By default, these properties are set to true.

    +

    + Also, @AnnotationConstraints.AllowExternalOverride allows an annotation author to configure a single + annotation as externally overridable without changing the shape of the ControlBean. This is + especially useful when individual method- and parameter-level annotations need to be configured + externally. This is in contrast to + @PropertySet(hasSetters=true) + which causes the generated ControlBean to have getter/setter methods for *every* annotation + attribute. +

    +
    +
    + Resource Views: Extensibility by Interface +

    + Controls also support an extensibility model that allows operations on a resource to be defined + using a customized interface that extends the base public resource interface, and defines + metadata-annotated operations on the resource. This enables the construction of "views" or specific + resource use cases, defining a more-specific set of resource operations or events. +

    +

    + As an example, take the basic DatabaseControl that provides simplified database access using JDBC, + and hides and manages the details of how JDBC connections are acquired and released from the client + programmer. +

    +

    + This DatabaseControl could also define an extensibility model that allows the execution of JDBC + prepared statements as operations on an extended interface, and marshals the returned ResultSet back + to native Java types. When extended in this manner, the resulting extended control presents a view + of the JDBC resource as a set of methods that result in the execution of predefined + PreparedStatements. +

    +

    An example of the customized interface for this Control might look like:

    + + + +

    + In this simple example, each operation on the interface corresponds to a SQL prepared statement to + be executed. Metadata annotations on the methods are used to define the additional semantics + required, in this case the actual SQL statement to invoke. +

    +

    + Support for Extensibility by Interface is optional. The Control author has full control of whether + extensibility is or is not supported, as well as the ability to define and implement + resource-specific semantics associated with extended operations on the control type. +

    +
    +
    + Contextual Services +

    + Given their use case (resource access), it is possible to use Controls from a variety of different + runtime contexts: within web tier containers (servlets, JSP, JSF), within web services, standalone + Java applications, even from within EJBs. Given this diverse set of contexts, Controls have a + flexible model for how they integrate with any outer container or component model and for how + services will be obtained from them. +

    +

    + Controls may need access to contextual services to support resources. One example of client-side + contextual services might be security services to access a credential repository or to provide data + encryption/decryption services. Services may be contextual, because the actual implementation might + vary based upon the type of container in which the Control is running. As an example, a security + contextual service might provide different implementations for Controls running in the EJB tier (by + delegating to an enclosing EJBContext) vs. Controls running in the Servlet container vs. Controls + running in a standalone Java application. +

    +

    + Contextual services can also define an event model, so contextual services can also declare and fire + events on Controls that have registered in interest. As an example, a basic ControlContext + contextual service is provided as part of the base Controls architecture. This contextual service + provides common services for Controls, such as access to properties, as well as a set of lifecycle + events for Controls. +

    +

    + The discovery and implementation model for Controls Contextual Services will be based upon the + JavaBeans Runtime Containment and Services Protocol (Glasgow) ( + + http://java.sun.com/products/javabeans/glasgow/#containment + + ) that is already shipping as part of J2SE. +

    +
    +
    + Resource Management +

    + The Controls architecture defines a unique set of lifecycle events and a resource management + contract between Controls and the execution container they are running within. There are three + primary motivations for this: +

    +
      +
    • + To enable the Control implementation to implicitly obtain supporting client-side resources + (connections, sessions, etc) on behalf of the client. +
    • + +
    • + To enable the Control to hold these client-side resources for an appropriate resource scope + (across multiple client invocations) to achieve optimal performance and utilization of resources +
    • + +
    • + To ensure that client-side resources obtains on behalf of the client are consistently released + at the end of the appropriate resource scope. +
    • +
    +

    + The key is that resource management should be transparent to the client. The Control resource + management design makes the Control implementation class the responsible party, instead of placing + this burden upon the client of the resource which is the common approach associated with most J2EE + resource types. +

    +

    + This is achieved by defining two basic lifecycle events that will be delivered to the Control + Implementation Class: +

    +
      +
    • + onAcquire: the onAcquire event is delivered to a resource implementation on the first client + invocation within a resource scope. This provides an opportunity to obtain any basic client-side + resources necessary to support operations on the Control. For example, a Control that was + providing access to a JMS queue might use the onAcquire event to obtain a JMS connection, + session, and a reference to the target queue. +
    • +
    • + onRelease: the onRelease event is guaranteed to be delivered to every control implementation + instance that has received an onAcquire event during the current resource scope, at the end of + that scope. This provides the opportunity to release any of the resources obtained during + onAcquire event processing. For example, a JMS connection and session could be appropriately + closed and the queue reference reset to null. +
    • +
    +

    + The definition of resource scope is delegated to the outer container within which the Control is + executing. For example, if the Control is executing within the web tier, the resource scope might be + bounded by the duration of processing of the current http request. For a Control running in the EJB + tier, the resource scope might be the current EJB method invocation or possibly even by the current + transaction context. +

    +

    The following diagram shows the basic mechanics of this contract:

    +

    + +

    +

    + The Client Container has two basic responsibilities: to maintain an accumulated list of Controls + that have acquired resources, and to invoke releaseResources API on each of them at the end of the + appropriate resource scope. The Control Bean is responsible for delivering the onAcquire event to + the Control Implementation instance, for notifying the Client Container that resources have been + obtained, and for delivering the onRelease event to the implementation when notified by the Client + Container. +

    +

    + This diagram also demonstrates the transparency of resource management to client code itself; the + client is only invoking operations, and all of the necessary underlying resource management is done + by interactions between the Client Container, Control Bean, and Control Implementation. +

    + +
    +
    + Composition Model +

    + The Controls architecture also supports a composition model, so it is possible to define a Control + type that nests another Control type. This makes it possible to extend a physical resource + abstraction with a logical abstraction that lives entirely on the client side. Composition is useful + for the construction of facades or to add additional client side operations, events, or state to the + nested Control abstraction. +

    +

    + Composition of Controls is supported using the mechanisms defined by the JavaBeans Runtime + Containment and Services Protocol (Glasgow). +

    +
    +
    + Packaging Model +

    + The Controls architecture provides a simple JAR-based packaging model that enables Controls to be + packaged for distribution. The model defines a simple manifest file that describes the set of + Controls within a jar. Tools can quickly introspect and build palettes of available controls based + upon this packaging model. +

    +

    + It is possible to place Control jar files at a variety of classloader scopes (system, application, + or module) for client use cases. +

    + +
    +
    +
    + The Controls Client Model +

    + The Controls architecture actually offers two related client models with slight different + characteristics: +

    +
      +
    • + A programmatic client model, where the client explicitly specifies Control instance attributes to + factory-based constructors, and does direct registration of event listeners and event handling. +
    • + +
    • + A declarative client model, where Control instance attributes are specified using metadata + annotations, and event routing is implicit based upon a set of basic naming conventions. +
    • +
    +

    + The two offer the same basic functionality; but in the programmatic model the client takes explicit + responsibility for construction of Control instances and event routing; in the declarative model, the + Control container provides initialization and routing services on behalf of the client. The programmatic + model directly exposes the details of how initialization and event handling takes place; it is likely a + more comfortable environment for the professional J2EEdeveloper or one who is already comfortable with + constructing and handling events from JavaBeans. The declarative model hides many of these details, + making it much easier for less experienced developers (and development tools) to quickly declare and + configure Control instances and create event handling code to service events. +

    +

    +
    + Programmatic Client Model Example +

    + The programmatic client model follows the basic pattern of JavaBeans construction and event + handling: +

    + + + +

    + In the example above, a factory-based instantiation API (Controls.instantiate()) is used to + construct a new instance of the DatabaseControl. It is programmatically initialized to the desired + configuration. +

    + +
    +
    + Declarative Programming Model Example +

    + The following example is equivalent to the preceding example, but uses declarative style + construction: +

    + + + +

    + In this example, the DatabaseControl instance is declared with attributes specified using metadata + annotations. There is no implicit construction of the bean instance; the client container for the + ControlBean will recognize the presence of the Control declaration and will implicitly initialize + the instance. +

    +
    +
    + +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/controls/programming.xml b/docs/forrest/release/src/documentation/content/xdocs/controls/programming.xml new file mode 100644 index 0000000..5435e5d --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/controls/programming.xml @@ -0,0 +1,2434 @@ + + + +
    + Controls Programming +
    + +
    + Overview +

    + The Control architecture is a lightweight component framework based upon JavaBeans, + which exposes a simple and consistent client model for accessing a variety of resource + types. Controls take the base functionality of JavaBeans and add in the following + unique new capabilities: +

    +
      +
    • + Enhanced authoring model: uses a public interface contract and an associated + implementation class to enable generation of a supporting JavaBean class for + handling the details of property management and initialization. +
    • +
    • + Extensibility model: enables the construction of views and custom operations + (with implied semantics) on the Control using metadata-annotated interfaces. +
    • +
    • + metadata attributes and external configuration data: provides an + enhanced configuration model for resource access. +
    • +
    +

    + This document focuses on the Controls programming and configuration model from + two distinct perspectives: +

    +
      +
    • + The authoring and extensibility model for defining a new type of Control +
    • +
    • + The client access model for declaring and using Controls +
    • +
    +

    + An overview of the Control architecture and toolable access models can be found in + the companion document entitled Control Overview: + Providing Simplified and Unified Access to J2EE Resources +

    +
    +
    + An Example +

    + In the course of describing the programming model for Controls, this document builds + upon an example Control that simplifies the enqueueing of JMS messages with a + specific format and set of properties. Once completed, client code to accomplish + this should be as straightforward as: +

    +

    + Enqueueing using OrderQueueBean (Client Code) +

    +OrderQueueBean orderBean = (OrderQueueBean) + +java.beans.Beans.instantiate("org.apache.beehive.controls.examples.OrderQueueBean"); +Order order = new Order(myID, new String [ ] {"item1", "item2"}); +OrderBean.submitOrder(order, "01-28-2004"); + +

    + This document starts with a brief overview of the Control Authoring and Client + Programming Models to establish some basic context, eventually building to enable + the example above. +

    +
    +
    + The Control Authoring Model +

    + This section describes the basic authoring model for Controls. This includes a + description of the following elements: +

    +
      +
    • + Control Public Interface: source file that defines the set of operations, events, + extensibility model, and properties associated with the Control type. +
    • +
    • + Control Implementation Class: source file that provides the implementation of the + operations and extensibility model described by the Control Public Interface. +
    • +
    • + ControlBean Generated Class: code-generated JavaBean class that is derived from the + Control Public Interface and the Control Implementation Class by a Control compiler. +
    • +
    +

    + This authoring model is a departure from the traditional JavaBeans programming model, + which is largely based upon a set of conventions that a bean author is expected to follow when constructing a new + JavaBean type. In the Controls model, the author defines operations, events, and properties in an interface + (Control Public Interface) and builds an underlying implementation (Control Implementation Class). A Control + compiler takes these two elements and generates a specialized type of JavaBean (ControlBean Generated Class), + which represents the full client programmer’s view of the Control. +

    +

    + There are two primary advantages of this model: +

    +
      +
    • + Simplicity. A key goal of any ease-of-use programming model is to free the + developer from worrying about plumbing. Managing property values, event listener lists, and + other basic JavaBean functions are fairly rote from implementation to implementation. The + Controls architecture employs a unique variant of the Inversion of Control (IoC) design + pattern based on metadata annotations. This enables a Control Implementation Class to + declaratively specify the events or services it requires to provide its semantics. The + ControlBean Generated Class acts as a lightweight container to provide contextual hookup and + implementation details.
    • +
    • + Consistency. Instead of trying to provide consistency through convention, the Control compiler + provides both verification and code generation services to ensure that the resulting implementation provides + consistent APIs and behaviors for clients, tools, and application deployers or administrators. +
    • +
    +

    + Diagram: Control Architecture Elements and Flow +

    +

    + +

    +

    + The client will interact with the Control by invoking operations defined on the Control Public Interface or dynamic + property accessor methods on a ControlBean instance. The client can also express interest in any events the Control + might generate by registering a listener to receive them. +

    +

    + The following diagram represents the relationship between the Control Public Interface, the Control Implementation + Class, and the ControlBean Generated Class: +

    +

    + Diagram: Relationships between Control Interface and Classes +

    +

    + +

    +

    + The Control Public Interface defines the operations on the Control and will be implemented by both the Control + Implementation Class and the ControlBean Generated Class. The ControlBean Generated Class will also define property + accessor methods and internally will maintain the state of property values. It will also maintain a reference to + one (and only one) Control Implementation instance. The Control Implementation instance, wrapped by a bean instance, + provides the actual implementation of resource semantics for the Control. +

    +

    + The subsequent sections will outline the various characteristics of Controls: +

    +
      +
    • Declaration / Instantiation
    • +
    • Operations
    • +
    • Events
    • +
    • Contextual Services
    • +
    • Properties
    • +
    • Extensibility
    • +
    • Composition
    • +
    • Context Events
    • +
    +

    + Where applicable, the aspects of each of these characteristics will be explored in two dimensions: from the + perspective of a Control author who is defining a new type of Control, and from the perspective of a Control client + that is using the services of an available Control type. +

    +

    + To make the descriptions more concrete, the characteristics will be presented within the context of a sample Control: + the JmsMessageControl. This Control will provide a simplified client access model for enqueuing messages to a JMS + queue or topic, freeing the client from having to learn the nuances of JMS client programming. +

    +
    +
    + The Control Client Models +

    + There are actually two distinct programming models that may be available to clients of Controls: +

    +
      +
    • Declarative Model. Uses a metadata-based variant of the Inversion of Control (IoC) design pattern to allow a component author to declare Control instances, contextual services, and event handlers using annotated fields and methods. The declarative model simplifies client programming, because many of the details of initialization and event routing are left to an external container supporting the model. A declarative programming style is also more toolable, since it is much easier for tools to manage and manipulate metadata rather than code.
    • +
    • Programmatic Model. Uses the traditional JavaBean-style APIs for acting as a client of a bean, including factory-based constructor and event listeners. The programmatic model may be more comfortable to the traditional Java programmer, who wants to see and be in control of all the details. It also enables client use cases where there is no supporting container for the declarative model.
    • +
    +

    + The programmatic client model is generally available in all contexts where Controls might be used. It offers full + generality, but leaves many of the details up to the client programmer, such as initialization, composition, and + event handling wire-up. +

    +

    + The declarative model hides many of these details. Based upon its use of metadata it is also more tool friendly, + allowing tools to present a view of the client code without code analysis. +

    +

    + The declarative model requires support of an outer container or construction-time code that fulfills the contract + implied by annotations on a client class. +

    +

    + The ControlBean itself provides this support, so the Control Authoring Model is oriented towards using the + declarative model, although programmatic equivalents are generally available. +

    +
    +
    + Defining a New Control Type +

    + Controls are designed to make it very easy for users (and tools) to define new types of Controls. Control authors + might be: +

    +
      +
    • + System vendors exposing specific types of resources +
    • +
    • + Application developers defining new types of logical resources (possibly based upon physical ones) +
    • +
    • + Third-party software vendors, using Controls as a mechanism to interface to components or subsystems they provide. +
    • +
    +

    + In all instances, the goal of the Controls authoring model is to provide a basic set of conventions and supporting + tools to make it easy to author a new Control type. +

    +

    + To get started, a Control author would define the two basic artifacts: +

    +
      +
    • + the Control Public Interface +
    • +
    • + the Control Implementation Class +
    • +
    +

    + For the JmsMessageControl, the declaration of the public interface might look like: +

    +

    + Interface Declaration (Control Public Interface) +

    +package org.apache.beehive.controls.examples; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +@ControlInterface +public interface JmsMessageControl +{ + ... +} +

    + The only basic rule for a Control Public Interface is that it must be annotated by the + org.apache.beehive.controls.api.bean.ControlInterface marker interface. +

    +

    + The second source artifact a Control author would create to define a new type of Control is the Control + Implementation Class. This declaration of the implementation class for our JmsMessageControl would look like: +

    +

    + Class Declaration (Control Implementation Class) +

    +package org.apache.beehive.controls.examples; + +import org.apache.beehive.controls.api.bean.ControlImplementation; + +@ControlImplementation(isTransient=true) +public class JmsMessageControlImpl implements JmsMessageControl +{ + ... +} +

    + The basic rules for a Control Implementation Class are: +

    +
      +
    • + It must be annotated with org.apache.beehive.controls.api.bean.ControlImplementation. +
    • +
    • + It must implement its associated Control Public Interface. +
    • +
    • + It must either (1) implement the java.io.Serializable interface or (2) set the isTransient attribute of @ControlImplementation to true. +
    • +
    +

    + From these two source files, the Control compiler will create a third artifact, the + ControlBean Generated Class. This class need not necessarily ever appear within an + application in source code form; but for the purposes of explaining the overall + architecture and client model, we will present source examples of the derived ControlBean + Generated Class. +

    +

    + A Controls standard would focus only on the conventions for the external attributes of + ControlBean Generated Classes, not upon the internal implementation. +

    +

    + The ControlBean Generated Class for the JmsMessageControl would look like: +

    +

    + Class Declaration (ControlBean Generated Class) +

    +package org.apache.beehive.controls.examples; + +public class JmsMessageControIBean implements JmsMessageControl +{ + private JmsMessageControlImpl _impl; + + ... +} +

    + As shown above, the ControlBean Generated Class will also implement the Control Public Interface. The sample also + shows that the bean will hold a private reference to an implementation instance used to support the bean. +

    +
    +
    + Instantiating a Control +

    + This section covers the client mechanisms for creating a new instance of a Control. This can be done either + programmatically or declarative, if running inside a container that support declarative initialization. +

    +
    + Declarative Instantiation +

    + The client model for Controls supports a declarative model for instantiating a Control instance, when running in + containers that support this model. In this model, the client class can annotate fields on the class using a + special marker annotation (org.apache.beehive.controls.api.bean.Control) that indicates that the fields should be + initialized to a ControlBean instance of the requested type. +

    +

    + Here is an example of declarative instantiation: +

    +

    + Declarative Instantiation (Client Code) +

    +package org.apache.beehive.controls.examples; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.examples.JmsMessageControl; + +@ControlImplementation(isTransient=true) +public class PublisherControlImpl implements PublisherControl +{ + @Control + public JmsMessageControlBean myJmsBean; + + ... + + public void someOperation() + { + myJmsBean.sendTextMessage("A Text Message"); + } +} +

    + This example shows a second Control Implementation Class (PublisherControlImpl) that internally uses the services + of JmsMessageControl to enqueue a JMS message. The child Control field is not explicitly initialized within the + PublisherControl implementation class; by the time someOperation() is called, it is guaranteed that the myJmsControl + reference has been initialized by the wrapping PublisherControl that contains the implementation. +

    +

    + It is also possible to parameterize a Control at construction time, again using metadata + attributes. These attributes can be placed on the field declaration (in addition to the @Control annotation) + and will be used to do construction-time initialization. +

    +

    + The second example below shows initialization of the myJmsControl field again. In this case, an initial value of + the @Destination "name" attribute is also provided using metadata annotations: +

    +

    + Declarative Instantiation with Properties (Client Code) +

    +@ControlImplementation +public class PublisherControlImpl implements PublisherControl +{ + @Control + @Destination(name="InvoiceQueue") + public JmsMessageControlBean myJmsBean; +

    This example performs + exactly the same initialization as the earlier declarative example, but + does so using annotation attribute syntax instead of passing parameters to a factory-based + constructor.

    +

    + The Controls architecture includes a mechanism for defining the expected set of annotations that might appear on + a Control field. This mechanism is described in greater detail in the section on Properties. +

    +
    +
    + Programmatic Instantiation +

    + The client model for Controls supports instantiation of a new Control instance using the same factory-based model + supported by JavaBeans. For example, the following code could be used to create a new instance of the + JmsMessageControlBean generated class: +

    +

    + Programmatic Instantiation (Client Code) +

    +JmsMessageControlBean myJmsBean = + (JmsMessageControlBean) java.beans.Beans.instantiate( + cl, "org.apache.beehive.controls.examples.JmsMessageControlBean" + ); +

    + The Control runtime also provides an extended factory model that allows metadata attributes to be passed into the + factory constructor: +

    +

    + Programmatic Instantiation with Properties (Client Code) +

    +import org.apache.beehive.controls.api.bean.Controls; +import org.apache.beehive.controls.api.properties.PropertyKey; +import org.apache.beehive.controls.api.properties.PropertyMap; +import org.apache.beehive.controls.api.properties.BeanPropertyMap; + +PropertyMap jmsAttr = new BeanPropertyMap(JmsControl.Destination.class); +jmsAttr.setProperty(new PropertyKey(JmsControl.Destination.class, "name"), "InvoiceQueue"); +JmsMessageControlBean myJmsBean = (JmsMessageControlBean) Controls.instantiate( + cl, "org.apache.beehive.controls.examples.JmsMessageControlBean", jmsAttr +); +

    + In this example, the JmsMessageControlBean is being constructed with the Destination "name" property set to "InvoiceQueue". + The AttributeMap class is a simple helper class that can hold a set of name-value pairs of a Control’s properties, which + are initialized by the factory-based constructor. More details on Controls properties are provided in a later section. +

    +
    +
    +
    + Operations +

    + Operations are actions that can be performed by a Control at the client’s request. This section describes the + authoring model for declaring and implementing a Control operation, as well as the client model for invoking + operations on a ControlBean instance. +

    +
    + Declaring and Implementing Operations for a Control +

    + All methods declared or inherited (via extension) by the Control Public Interface are considered to be Control + operations. The following example shows the definition of two operations on the JmsMessageControl that will + enqueue messages when invoked: +

    +

    + Declaring Operations (Control Public Interface) +

    +package org.apache.beehive.controls.examples; + +import java.io.Serializable; +import org.apache.beehive.controls.api.bean.ControlInterface + +@ControlInterface +public interface JmsMessageControl +{ + public void sendTextMessage(String text); + public void sendObjectMessage(Serializable object); + + ... +} +

    + The Control Implementation Class implements the public interface for the Control, defining the operation methods, + and the body of these methods. +

    +

    + Implementing Operations (Control Implementation Class) +

    +package org.apache.beehive.controls.examples; + +import java.io.Serializable; +import org.apache.beehive.controls.api.bean.ControlImplementation; + +@ControlImplementation(isTransient=true) +public class JmsMessageControlImpl implements JmsMessageControl +{ + public void sendTextMessage(String text) + { + // Code to send a TextMessage to the destination + ... + } + + public void sendObjectMessage(Serializable object) + { + // Code to send an ObjectMessage to the destination + ... + } +} + +

    + Finally, the ControlBean Generated Class will also implement all operations (since it also implements the Control + Public Interface). It will always delegate to the implementation class for the actual implementation of the + operation; it might also perform additional container-specific pre/post invocation processing. +

    +

    + Here is a skeleton of what the generated ControlBean code might look like for an operation: +

    +

    + Implemented Operations (ControlBean Generated Class) +

    +package org.apache.beehive.controls.examples; + +public class JmsMessageControlBean implements JmsMessageControl +{ + private JmsMessageControlImpl _impl; + + public void sendTextMessage(String text) + { + ... + _impl.sendTextMessage(text); + ... + } + + public void sendObjectMessage(Serializable object) + { + ... + _impl.sendObjectMessage(object); + ... + } + + +
    +
    + Invoking Operations on a Control +

    + The client model for invoking an operation on a Control is very straightforward: simply call the method on a + held ControlBean instance as demonstrated by the following example: +

    +

    + Invoking an Operation (Client Code) +

    +package org.apache.beehive.controls.examples; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.examples.JmsMessageControl; + +@ControlImplementation(isTransient=true) +public class PublisherControlImpl implements PublisherControl +{ + @Control + public JmsMessageControlBean myJmsBean; + + ... + + public void someOperation() + { + myJmsBean.sendTextMessage("A Text Message"); + } +} +

    + The invocation model for operations is the same, whether the Control instance was created using declarative or + programmatic mechanisms. +

    +
    +
    +
    + Events +

    + Events are notifications sent by the Control back to its client whenever some condition has been met or internal + event has taken place. A client can express interest in a Control’s events by registering (either explicitly or + implicitly) to receive them, and can write event handler code to be called when the event has taken place. +

    +

    + This section describes the declaration model for events, how an authored Control delivers them to a registered + client, and the client code necessary to register and receive events. +

    +
    + Declaring Events +

    + Events are declared on an inner interface of the Control Public Interface, which is annotated with the + org.apache.beehive.controls.api.events.EventSet annotation. The following example shows the declaration + of an event interface for the JmsMessageControl, with a single event (onMessage): +

    +

    + Declaring Events (Control Public Interface) +

    +package org.apache.beehive.controls.examples; + +import java.io.Serializable; +import javax.jms.Message; +import org.apache.beehive.controls.api.events.EventSet; +import org.apache.beehive.controls.api.bean.ControlInterface; + +@ControlInterface +public interface JmsMessageControl +{ + public void sendTextMessage(String text); + public void sendObjectMessage(Serializable object); + + @EventSet + public interface Callback + { + void onMessage(Message m); + } + + ... +} +

    + If a Control Public Interface has defined an EventSet interface, then the associated ControlBean Generated + Class will have two public methods supporting client listener management: +

    +

    + Event Listener Registration Methods (ControlBean Generated Class) +

    +package org.apache.beehive.controls.examples; + +import java.util.TooManyListenersException; + +public class JmsMessageControIBean implements JmsMessageControl +{ + ... + + /** Registers a new client listener for this bean instance */ + public void addCallbackListener(Callback listener) + throws TooManyListenersException + { + ... + } + + /** Deregisters a client listener for this bean instance */ + public void removeCallbackListener(Callback listener) + { + ... + } +} +

    + The name of the listener registration methods are based upon the name of the associated EventSet interface. In + the previous example, the EventSet interface was named Callback, so the associated listener registration method + was addCallbackListener(), and the deregistration method was removeCallbackListener(). +

    +

    + A Control Public Interface can have more than one inner interface that is annotated as an EventSet interface. + Each declared EventSet will have its own independently managed list of registered listeners. +

    +
    +
    + Firing Events +

    + This section describes the mechanism available to a Control author to deliver events to any registered client + listener. An initialized event proxy is created when the Control Implementation Class declares a field + of an EventSet interface type, and annotates it with the org.apache.beehive.controls.events.Client annotation + type. The containing ControlBean will initialize this reference to a valid proxy implementing the + EventSet interface, and the Control Implementation Class can use this proxy to fire events back to any registered + client. +

    +

    + This is demonstrated in the following sample code from the JmsControlBean implementation class, which will fire + an onMessage event back to any registered client any time a message is enqueued: +

    +

    + Firing Events (Control Implementation Class) +

    +package org.apache.beehive.controls.examples; + +import java.io.Serializable; +import javax.jms.TextMessage; +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.events.Client; + +@ControlImplementation(isTransient=true) +public class JmsMessageControlImpl implements JmsMessageControl +{ + @Client Callback client; + + public void sendTextMessage(String text) + { + // Code to construct and send a TextMessage to the destination + TextMessage m = ...; + ... + client.onMessage(m); + } + ... +} +
    +
    + Listening for Events +

    + The client of a Control can express an interest in receiving events from a Control and write client event handlers + to service them once delivered. Two basic event handling mechanisms are supported: Java event listeners or + declarative event handlers (where supported by the client container). +

    +
    + Declarative Implementation of Event Handling +

    + If the client code is implemented in a container that supports the declarative programming model for Controls + (such as the Control Implementation Class itself), it can use a simplified convention for authoring event + handlers for a declared Control instance. +

    +

    + If a Control is declared using the @Control marker interface, then the user can declare event handlers + for the Control by using the EventHandler annotation type. These annotated methods will be + considered an event handler for the Control event, and the container will automatically register for events + and deliver them to this handler. +

    +

    + The previous example could be rewritten using the declarative event handling style as: +

    +

    + Declarative Handling of Events (Client Code) +

    +package org.apache.beehive.controls.examples; + +import javax.jms.Message; +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.events.EventHandler; +import org.apache.beehive.controls.examples.JmsMessageControl; + +@ControlImplementation(isTransient=true) +public class PublisherControlImpl implements PublisherControl +{ + @Control + public JmsMessageControlBean myJmsBean; + + @EventHandler ( + field="myJmsBean", + eventSet= JmsMessageControl.Callback.class, + eventName="onMessage") + public void myJmsBeanMessageHandler(Message m) + { + // Code implementing onMessage event handler + } + ... +} + +
    +
    + Programmatic Implementation of Event Handling +

    + The programmatic style follows the traditional Java event listener pattern. The client expresses its interest + in receiving the event and also authors a (often anonymous inner) class that implements the event interface + to receive events when delivered. +

    +

    + This is shown by the following sample code: +

    +

    + Programmatic Handling of Events (Client Code) +

    +myJmsBean.addCallbackListener( + new JmsMessageControl.Callback() + { + public void onMessage(Message m) + { + // Code implementing on Message event handler + } + } +); +

    + There is no requirement that an anonymous inner class be used. One alternative would be to delegate to an + instance of another class (as long as that class implements the Callback interface). In the preceding + example, if event listening was implemented for the purposes of logging sent messages, and MessageLogger + class could be declared (implementing the Callback interface), multiple beans could delegate to a single + instance of this logging listener. +

    +
    +
    +
    +
    + Contextual Services +

    + The Control authoring model makes use of contextual services to provide access to services from the current runtime + environment of the ControlBean. The model for contextual services is based upon the existing standards for services + in JavaBeans: The JavaBeans Runtime Containment and Services Protocol. This protocol provides a base mechanism for + a JavaBean to locate and use services from the runtime environment, as well as an extensible service provider model + to enable new (or environment-specific) types of services to be authored and made available to JavaBeans/Controls. +

    +

    + A key aspect of this service model is that it can be contextual; for example, it might be possible to write a basic + security service interface that provides logical role-checking functionality. The actual implementation of this + interface might vary for different runtime contexts: for example, the role check might be done differently for a + Control running within the context of an EJB container (by delegating to the containing EJBContext) vs. a Control + running within the Web tier (by delegating to ServletHttpRequest services). +

    +

    + Having an extensibility and service provider location model is important to enable the following scenarios: +

    +
      +
    • + The Control’s implementation is designed to run in a wide variety of environments. It uses the contextual service + mechanism to declare its prerequisites and receive a provider implementation that is appropriate to the current + runtime context. +
    • +
    • + The Control’s implementation is designed to run in a very specific context (for example, only in the http servlet + tier) and wants access to services that are very specific to that context (for example, session state or request + query parameters). It should not be possible to instantiate this Control in other contexts (for example, from + within an EJB). +
    • +
    +

    + One key contextual service for Controls that is guaranteed to be available in all contexts is the + org.apache.beehive.controls.api.context.ControlBeanContext service interface. This service provides a common + set of generic services that are available to Control authors, such as the ability to query property values on the + current instance, or to receive a set of basic lifecycle or resource management events. The ControlBeanContext + interface extends the java.beans.beancontext.BeanContextServices interface, so it also provides access to services + provided by the JavaBeans bean context APIs. Later sections describe an overview of the internal architecture for + contextual services, APIs to support property resolution, and lifecycle events. +

    +
    + Declarative Access to Contextual Services +

    + Suppose the following Destination property set was added to the control: +

    +

    + Declarative Access to Context Services (Control Public Interface) +

    +package org.apache.beehive.controls.examples; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.properties.PropertySet; + +@ControlInterface +public interface JmsMessageControl +{ + ... + + public enum DestinationType { QUEUE, TOPIC } + + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.FIELD, ElementType.TYPE}) + public @interface Destination + { + public DestinationType type() default DestinationType.QUEUE; + public String name(); + } +} +

    + To signal the desire to access a contextual service, a Control author only needs to declare a field of the desired + context interface and annotate it with the org.apache.beehive.controls.api.context.Context marker annotation. + The following example shows how the JmsMessageControlImpl class would use the declarative model to access its + ControlBeanContext: +

    +

    + Declarative Access to Context Services (Control Implementation Class) +

    +package org.apache.beehive.controls.examples; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; + +@ControlImplementation(isTransient=true) +public class JmsMessageControlImpl implements JmsMessageControl +{ + @Context ControlBeanContext context; + + public void sendTextMessage(String text) + { + JmsMessageControl.Destination destProp = + context.getControlPropertySet(JmsMessageControl.Destination.class); + ... + } +} +

    + In this example, the JmsMessageControl implementation class expresses its desire to access ControlBeanContext + services via the annotated declaration of the context field; when code in sendTextMessage operation is invoked, + this contextual service has already been initialized by the containing ControlBean instance. +

    +

    + The ControlBeanContext for an authored Control is always accessed using the declarative mechanism. Other contextual + services may be accessed declaratively, or using the programmatic mechanisms described in the following section. +

    + +
    +
    + Programmatic Access to Contextual Services +

    + The ControlBeanContext service also provides the base mechanism to discover and use other services programmatically. + The following code fragment shows an example of how to use this API to obtain access to a service provider that + provides the javax.servlet.ServletContext interface. +

    +

    + Programmatic Access to Context Services (Control Implementation Class) +

    +package org.apache.beehive.controls.examples; + +import javax.servlet.ServletContext; +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; + +@ControlImplementation(isTransient=true) +public class JmsMessageControlImpl implements JmsMessageControl +{ + @Context ControlBeanContext context; + + public void sendTextMessage(String text) + { + ServletContext servletContext = + context.getService(ServletContext.class, null); + if (servletContext == null) + { + // no ServletContext provider is available + } + ... + } +} +

    + The code in the sample uses the ControlBeanContext.getService API to request that it provide a ServletContext + service. The parameters to this method are the Class of the requested service, and an (optional) service-specific + selector that can be used to parameterize the service. +

    +

    + The ServletContext service is contextual because it is available only to controls running in the web tier. If the + above sample control was running anywhere else, the call to ControlBeanContext.getService() would return null. +

    +
    +
    + Tradeoffs between Declarative and Programmatic Access +

    + Declarative access to context services is always available to a Control Implementation Class, and generally + results in less code associated with accessing services. Why then, would using programmatic access ever be + useful? There is a key difference between the two: +

    +
      +
    • + When using the declarative model for accessing a contextual service, the Control is effectively saying + that the service is required for it to function; if not available in a particular runtime environment, then + construction of an instance of the Control will fail. Essentially, the annotated context acts as a + notification to the runtime factory that this prerequisite must be satisfied. +
    • +
    • + Use of the programmatic model allows a Control Implementation Class to implement conditional behavior + based upon whether a contextual service is or is not available. The Control Implementation Class can + use the programmatic accessor, and then make a decision how to proceed based upon whether the requested + service is available. +
    • +
    +
    +
    +
    + Properties +

    + This section describes Control properties. Properties provide the basic mechanism for parameterizing the behavior + of a Control instance. +

    +

    + The Controls architecture takes the basic JavaBeans notion of properties and extends it to support two new + capabilities: +

    +
      +
    • A declarative annotation model where properties can be preconfigured on a ControlBean using + metadata annotations
    • +
    • + An administrative model where the value of ControlBean properties can be externally defined or overridden. +
    • +
    +

    + The external configuration and administrative model for Controls will be described in a separate document. +

    +
    + Declaring Properties for a Control Type +

    + For Controls, the set of properties is explicitly declared on the Control Public Interface. + This makes the available parameterization of a Control type readily visible to both code + and tools. +

    +

    + Properties are grouped together into related groups called PropertySets. All Properties within a + PropertySet will have a common set of attributes (such as where they can be declared, the access + model for JavaBean accessors, etc) and will have property names based upon a common naming + convention. +

    +

    A PropertySet is declared as a metadata attribute interface within the Control Public + Interface, which is also decorated with the + org.apache.beehive.controls.api.properties.PropertySet meta-attribute. Each of the + members within a PropertySet will refer to a distinct property within the set, and the return + value of the member defines the property type.

    +

    + Here is a sample declaration of the Destination PropertySet for the JmsMessageControl, which can + be used to configure the target JMS destination for the Control: +

    +

    + Declaring Properties (Control Public Interface) +

    +package org.apache.beehive.controls.examples; + +import org.apache.beehive.controls.api.bean.ControlInterface +import org.apache.beehive.controls.api.properties.PropertySet; + +import java.lang.annotation.ElementType; +import java.lang.annotations.Retention; +import java.lang.annotations.RetentionPolicy; +import java.lang.annotations.Target; + +@ControlInterface +public interface JmsMessageControl +{ + ... + + public enum DestinationType { QUEUE, TOPIC } + + @PropertySet(prefix="Destination") + @Target({ElementType.FIELD, ElementType.TYPE}) + @Retention(RetentionPolicy.RUNTIME) + public @interface Destination + { + public DestinationType type() default DestinationType.QUEUE; + public String name(); + } + ... +} +

    + This declaration defines the PropertySet named ‘Destination’ that includes two properties: type and name. + The type property is based upon the DestinationType enumerated type, which is also defined in the public interface. + The name attribute is a simple String property. +

    +

    + Meta-attributes on a PropertySet or property declaration can be used to provide additional details about the + properties and how they may be used. In the above example, the standard java.lang.annotations.Target annotation + is used to define the places where the @Destination property set can appear (in this case in either an extension + class or field declaration). +

    +

    + The full set of meta-attributes that can decorate PropertySet or Property declarations are TBD. + They can be used to define constraint models for property values, or relationships between + properties (such as exclusive or, where one is set or the other, but never both). These + meta-attributes can be read and used by development or administrative tools to aid in the + selection of property values. They can also be used by the runtime for runtime validation of + property values when set dynamically. The current set of property constraint mechanisms + is implemented by the @AnnotationConstraints annotation. See + Defining Property Constraints below for details. +

    +
    +
    + Accessing Properties from Client Code +

    + The properties defined in the Control Public Interface will be exposed to the client programmer using traditional + JavaBean setter/getter methods on the ControlBean Generated Class. These methods will follow a simple naming + pattern based upon the PropertySet interface name, and optional PropertySet prefix, and property member name. +

    +

    + The basic pattern for these accessors is: +

    +

    + Property Accessor Generation (Conventions) +

    + public void set<PropertySetPrefix><MemberName>(<MemberType>); + public <MemberType> get<PropertySetPrefix><MemberName>(); +

    + The PropertySetPrefix refers to the optional prefix attribute of the PropertySet annotation. If unspecified, it + will default to an empty string (no prefix). The MemberName refers to the PropertySet method name that declares + the property, with the first character converted to uppercase, and the MemberType refers to the return value type + of this method declaration. +

    +

    + So for the Destination PropertySet interface shown in the example above, the resulting ControlBean Generated Class + would expose the following accessors: +

    +

    + Property Accessors (ControlBean Generated Class) +

    +package org.apache.beehive.controls.examples; + +import java.util.TooManyListenersException; + +public class JmsMessageControIBean implements JmsMessageControl +{ + ... + public void setDestinationType(DestinationType type) { ... } + public DestinationType getDestinationType() { ...} + public void setDestinationName(String name) { ...} + public String getDestinationName(); +} +

    + Client code to set the Destination properties on a JmsMessageControlBean instance would look like: +

    +

    + Using Property Accessors (Client Code) +

    + @Control JmsMessageControlBean jmsBean; + + ... + + jmsBean.setDestinationType(DestinationType.QUEUE); + jmsBean.setDestinationName("myTargetQueue"); +
    +
    + Accessing Properties from Control Implementation code +

    + The Control Implementation class contains code that executes from within the context of the Control JavaBean that + is generated to host the control. The generated bean will automatically manage the resolution of properties + values from annotations, external configuration, or dynamic values set by the client. +

    +

    + Access to these properties is provided by the ControlBeanContext instance associated with the Control + Implementation Class. This interface provides a set of property accessors that allow the implementation to + query for property values: +

    +

    + ControlBeanContext APIs for Property Access +

    +package org.apache.beehive.controls.api.context; + +public interface ControlBeanContext + extends java.beans.beancontext.BeanContextServices +{ + ... + public <T extends Annotation> T + getControlPropertySet(Class<T> propertySet); + public <T extends Annotation> T + getMethodPropertySet(Method m, Class<T> propertySet); + public <T extends Annotation> T + getParameterPropertySet(Method m, index I, Class<T> propertySet); + ... +} +

    + The propertySet argument passed to these methods must be a valid PropertySet interface associated with the + ControlInterface. The ControlBeanContext will return the current value for properties in the PropertySet, or + will return null if no PropertySet value has been associated with this control instance. +

    +

    + Here is a simple example of using ControlBeanContext.getControlPropertySet() to query a property set: +

    +

    + Acccessing Control Properties (Client Implementation Class) +

    +package org.apache.beehive.controls.examples; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; + +@ControlImplementation(isTransient=true) +public class JmsMessageControlImpl implements JmsMessageControl +{ + @Context ControlBeanContext context; + + public void sendTextMessage(String text) + { + ... + Destination destProperty = (Destination) context.getControlPropertySet( Destination.class ); + if( destProperty == null ) { + System.out.println( "Dest Property NOT Set" ); + } else { + System.out.println( "Dest Property Set" ); + } + } +} +

    + This code above queries for the value of the JmsMessageControl.Destination PropertySet on the current + JmsMessageControl instance. +

    +

    + These query methods will return the value of resolved properties for the Control instance, method, or method + argument, respectively. Control implementations should never use Java reflection metadata accessors directly on + Control classes or methods; these accessors won’t reflect any property values that have been set dynamically by + ControlBean client accessor methods or externally using administrative configuration mechanisms. + The ControlBeanContext provides a consistent resolution of source annotation, client-provided, and external values. +

    +

    + A simple example of using the ControlBeanContext property accessor methods for accessing Method and Parameter + properties is provided in the section on Extensibility. +

    +
    +
    + External Configuration of Control Properties +

    + Controls also support an administrative model that allows Control property values to be bound using external + configuration syntax. The enables Control behavior to be parameterized externally to the code, and using a + consistent mechanism that is well-defined and structured to enable tooling. +

    +

    + The specifics of this administrative model are not covered within this document. +

    +
    +
    + Defining Property Constraints +

    + You can set up constraints on control properties using the + @AnnotationConstraints + annotation. @AnnotationConstraints allows you to set up + rules related to (1) the instantiation of the control properties + by client code, (2) external overriding of the control, and (3) + the Beehive runtime version required by the control. +

    +

    + Note: the constraint rules are enforced at build time, + when controls are declared in client code by @Control. There is no runtime + enforcement of the rules. +

    +

    + For example the following constraints require that +

    +
      +
    • + all attributes must be referenced when declaring the control BookControl +
    • +
    • + the values of the "title" and "subject" attributes must not exceed 10 characters in length +
    • +
    • + the value of the "content" attribute must not exceed 200 characters in length +
    • +
    +import java.lang.annotation.*; + +import org.apache.beehive.controls.api.bean.AnnotationContstraints.MembershipRule; +import org.apache.beehive.controls.api.bean.AnnotationContstraints.MembershipRuleValues; +import org.apache.beehive.controls.api.properties.PropertySet; + +@ControlInterface +public interface BookControl +{ + ... + + /** + * The user must set all attribute values when + * instantiating controls declaratively. + */ + @PropertySet + @Target ({ElementType.FIELD, ElementType.TYPE}) + @Retention(RetentionPolicy.RUNTIME) + @AnnotationConstraints.MembershipRule( + AnnotationConstraints.MembershipRuleValues.ALL_IF_ANY) + public @interface Intro + { + @AnnotationMemberTypes.Text(maxLength=10) + public String title(); + @AnnotationMemberTypes.Text(maxLength=10) + public String subject(); + @AnnotationMemberTypes.Text(maxLength=200) + public String content(); + } + + ... +} +

    + The following client code will cause a compile error, because it violates two of the constraints: +

    +
      +
    • + The "all if any" constraint on the BookControl.Intro annotation is violated + because only two (title and subject) of the three attributes (title, subject, + and content) are referenced. +
    • +
    • + The subject attribute's value exceeds 10 characters in length. +
    • +
    + @Control + @BookControl.Intro( title="title", subject="subject of the book" ) + BookControlBean myBook +

    Not all Java types are supported by @AnnotationMemberTypes. For a list of the supported types + see Interface AnnotationMemberTypes.

    +
    +
    +
    + Extensibility +

    + The Controls architecture supports an extensibility model that enables the declarations of user-defined operations or + events, based upon a predefined set of semantics defined by the author of the Control type. The extensibility + mechanism enables the definition of an interface to the resource where operations (or events) have very specific + context. +

    +

    + For example, in the JmsMessageControl sample, the extensibility mechanism will be used to raise the level of + abstraction: instead of a low-level mechanism to enqueue messages to a topic or queue, the Control enables + extensibility where operations can be defined that correspond to enqueuing messages with a very specific format and + set of properties, and where message or property content is derived from method parameters. This creates a + logical view of the resource (in this case a queue or topic) where the operations available on it have very specific + (and constrained) semantics. +

    +

    + For this section, we’ll start with the how an extension is defined, look at the authoring model for defining an + extensible Control type, and finally show the client view of using an extended type. +

    +
    + Defining an Extended Interface for a Control Type +

    + An extension to a base Control type that defines a specific resource use case is + created by defining a new Control type that derives from the original type and is annotated with the + ControlExtension annotation type: +

    +

    + Declaring a Control Extension (Control Extension Interface) +

    +package org.apache.beehive.controls.examples; + +import org.apache.beehive.controls.api.bean.ControlExtension; + +import org.apache.beehive.controls.examples.JmsMessageControl.*; + +@ControlExtension +@Destination(type=DestinationType.QUEUE, name="queue.orders") +public interface OrderQueue extends JmsMessageControl +{ + ... +} +

    + This example shows how property values can be configured on the extended interface to further parameterize the use + case. In this case, the InvoiceQueue interface is being designed for a very specific use case: to enable orders + to be enqueued to a JMS queue named "queue.orders". +

    +

    + Once defined, the Control extension author can now begin to define additional operations on it, in this case the + ability to enqueue messages to the OrderQueue by calling methods on it. +

    +

    + Declaring Extended Operations with Properties (Control Extension Interface) +

    +package org.apache.beehive.controls.examples; + +import org.apache.beehive.controls.api.bean.ControlExtension; + +@ControlExtension +@Destination(type=JmsMessageControl.QUEUE, name="queue.orders") +public interface OrderQueue extends JmsMessageControl +{ + public class Order implements java.io.Serializable + { + public Order(int buyer, String[] list){ + buyerID = buyer; + itemList list; + } + private int buyerID; + private String[ ] itemList; + } + + @Message (MessageType.OBJECT) + public void submitOrder( + @Body Order order, + @Property ( name="DeliverBy" ) String deliverBy + ); +} +

    + This interface defines a single operation, submitOrder, that enqueues an ObjectMessage containing a new order. + The body of the message will be a single instance of the Order class, and it will have a single StringProperty + with the expected delivery date (enabling message selector-based queries for orders that are past due). +

    +

    The message format (in this case an ObjectMessage) and the mapping of operation parameters to + message content and/or properties are all defined using metadata annotations on the method or + its parameters. This format makes it very easy for tools to assist in the creation and + presentation of extension interfaces.

    +

    + How does the extension author (or tool) know about the set of annotations that can be used on the extension + interface? This is the topic of the next section. +

    +
    +
    + Defining Extension Semantics for a Control Type +

    + A Control author is responsible for defining the extensibility semantics for a particular type, since ultimately + they are responsible for providing the implementation that fulfills the semantics. +

    +

    The extension semantics for a Control are part of the public contract for the Control, and thus + are defined on the Control Public Interface as well. As with Control properties, these are + defined in the form of metadata annotation interfaces, as show in the following sample code + from the JmsMessageControl Public Interface:

    +

    + Declaring Extension Semantics (Control Public Interface) +

    +package org.apache.beehive.controls.examples; + +import java.io.Serializable; +java.lang.annotation.ElementType +import java.lang.annotations.Retention; +import java.lang.annotations.RetentionPolicy; +import java.lang.annotations.Target; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +@ControlInterface +public interface JmsMessageControl +{ + ... + public enum MessageType { BYTES, MAP, OBJECT, STREAM, TEXT } + + @Target({ElementType.METHOD}) + @Retention(RetentionPolicy.RUNTIME) + public @interface Message + { + public MessageType value() default MessageType.TEXT; + } + + @Target({ElementType.PARAMETER} + @Retention(RetentionPolicy.RUNTIME) + public @interface Body {} + + @Target({ElementType.PARAMETER}) + @Retention(RetentionPolicy.RUNTIME) + public @interface Property + { + public String name(); + } +} +

    + The JmsMessageMessageControl defines three annotation types: Message, Body, and Property. The @Target annotation + on the Message declaration specifies that Message can be placed on the method declaration to indicate the type of + JMS message that will be enqueued by the operation. The Body annotation is used to indicate the method parameter + that contains the contents of the message (and must have a type that is compatible with the specified MessageType). + The Property annotation on a method parameter indicates that the parameter’s value should be stored as a property + on the enqueue message, with the property name coming from the value of the annotation and the property type + derived from the type of the method parameter. +

    +

    + The key is that the Control Public Interface contains sufficient details about the expected annotations that a + tool can support the construction. It also makes it possible for the Control compiler (that converts the + extended interface to an associated bean implementation) to perform validation of interface and method annotations. +

    +

    + More details on how these extension semantics are implemented are described in the next section. +

    +
    +
    + Authoring an Extensible Control Type +

    + The author of a Control type is responsible for providing the code that implements the extension semantics for + the Control. Support for extensibility is optional; so a Control author indicates extensibility of a type by + declaring that that the Control Implementation Class implements the org.apache.beehive.controls.api.bean.Extensible + interface. This interface has a single method named invoke(). +

    +

    + The skeleton of this code for the JmsMessageControlImpl class is shown below: +

    +

    + Implementing Extended Operations (Control Implementation Class) +

    +package org.apache.beehive.controls.examples; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; +import org.apache.beehive.controls.api.bean.Extensible; +import java.lang.reflect.Method; + +@ControlImplementation(isTransient=true) +public class JmsMessageControlImpl implements JmsMessageControl, Extensible +{ + @Context ControlBeanContext context; + + public Object invoke(Method m, Object [] args) throws Throwable + { + // Extensibility implementation + ... + } +} + +

    + The invoke() method on the Control Implementation Class will be called any time an operation defined on an + extension interface is called on the Control by its client. The implementation of this method has responsibility + for examining the current set of properties for the Control instance, methods, and parameters and using them to + parameterize the behavior of the Control. +

    +

    + This is demonstrated by the code below, which shows a portion of the implementation of invoke() for the + JmsMessageControlImpl class: +

    +

    + Accessing Method Properties Using the Context (Control Implementation) +

    +Object invoke(Method m, Object [] args) throws Throwable +{ + ... + int bodyIndex = 1; + for (int i= 0; i < args.length; i++) + if (context.getArgumentPropertySet(m, i, JMMessageControl.Body.class) != null) + bodyIndex = i; + + // + // Create a message of the appropriate type + // + Message msg = null; + JMSMessageControl.Message msgProp = + context.getMethodPropertySet(m, JMSMessageControl.Message.class); + switch(msgProp.value()) + { + case MessageType.OBJECT: + msg = session.createObjectMessage(args[bodyIndex]); + break; + ... + } + + // + // Decorate the message with properties defined by any arguments + // + for (int i= 0; i < args.length; i++) + { + JMSMessageControl.Property jmsProp = + context.getParameterPropertySet(m,i, JmsMessageControl.Property.class); + if (jmsgProp != null) + { + String name = jmsProp.value(); + if (args[I] instanceof String) + msg.setStringProperty(name, ((String)args[i]); + else if (args[I] instanceof Integer) + ... + else + msg.setObjectProperty(name, args[I); + } +} +

    + In the sample code above, the Control Implementation Class uses the ControlBeanContext getMethodProperty and + getParameterProperty APIs to query properties of the invoked method and its argument. These query methods will + return null if the property is not found and no default was defined for the attribute member. +

    +
    +
    + Client Model for Using an Extended Control Type +

    + The client model for using an extended Control type is exactly the same as the model for using a base Control type. + The same set of declarative and programmatic instantiation mechanisms (described in the previous section) will be + used, and operations or events are handled the same way. +

    +

    + Below is sample code that uses the OrderQueue extended type (using declarative client model): +

    +

    + Using a Control Extension (Client Code) +

    + @Control org.apache.beehive.controls.examples.OrderQueueBean orderBean; + ... + Order order = new OrderQueue.Order(); + order.buyerID = myID; + order.itemList = new String [] {"item1", "item2"}; + orderBean.submitOrder(order, "12-31-2004"); + +

    + Looking closely at the example, you’ll notice that a derived ControlBean type (OrderQueueBean) is generated by + the Control compiler, just as it is for a base Control type. The skeleton of this ControlBean Generated Class is + shown below: +

    +

    + Implementation of Extended Operations (ControlBean Generated Class) +

    +package org.apache.beehive.controls.examples; + +public class OrderQueueBean + extends JmsMessageControlBean + implements OrderQueue +{ + JmsMessageControlImpl _impl; + ... + public void submitOrder(Object order, String deliveryBy) + { + ... + _impl.invoke(submitOrderMethod, new Object [] {order, deliveryBy}; + ... + } +} +

    + There are several attributes worth noting about the extended ControlBean Generated Class: +

    +
      +
    • + Its implementation will be a subclass of the base type ControlBean, so implementation of base type operations + is inherited. +
    • +
    • + The extended bean will implement the extended Control interface, meaning all extended operations will be + implemented by the bean. +
    • +
    +

    + The implementation of these extended operations will always delegate down to the base Control Implementation Class + by calling the Extensible.invoke() method. +

    +
    +
    +
    + Composition +

    + The Controls architecture supports a composition model, based upon the JavaBeans Runtime Containment and Services + Protocol. This means that it is possible for new types of ControlBeans to be defined that are built through + composition of one or more other types. +

    +
    + Composition Using Declarative Instantiation +

    + Additionally, the ControlBeans authoring model makes composition very simple based upon the declarative + instantiation model. Within any ControlBean implementation, any @Control fields will automatically be + initialized as children of the local bean’s context. +

    +

    + Here’s a simple example based upon our previous OrderQueue example. Let’s say that we want to create a logical + Control that can be used to submit orders. This Control will submit to one of two different queues, depending + upon whether the order needs to ship in less than 30 days, or greater than 30 days. +

    +

    + The implementation of this Control could look like: +

    +

    + Composition Using Declarative Instantiation (Control Implementation Class) +

    +package org.apache.beehive.controls.examples; + +@ControlImplementation(isTransient=true) +public class OrderRouterImpl implements OrderRouter +{ + @Control @Destination(Name="RushOrders") + OrderQueueBean rushOrders; + + @Control @Destination(Name="Orders") + OrderQueueBean orders; + + ... + + public void submitOrder(Order order, String deliverBy) + { + if (needsRushDelivery(deliveryBy)) + rushOrders.submitOrder(order, deliverBy); + else + orders.submitOrder(order, deliverBy); + } +} + +

    + In this example, the OrderRouterImpl Control itself uses the services of two different OrderQueue Controls + referencing two different queues, and uses a helper method (needsRushDelivery) to decide where to enqueue a + particular order. The new Control has the same operations exposed as the original Controls; but now uses the + services of one or the other of its children to satisfy the request. +

    +

    + The next section describes doing an equivalent composition using mechanisms to instantiate and build the Control + hierarchy. +

    +
    + Composition using Programmatic Mechanisms +

    + Because the ControlBeans architecture is built using the JavaBeans Runtime Containment protocol, which defines + a base composition model for JavaBeans, it is also possible to manually instantiate and Controls using the APIs + it defines. The ControlBeanContext API extends the java.beans.beancontext.BeanContext API, which provides + support for adding children to the current bean’s context. +

    +

    + Here’s the previous sample, rewritten to use programmatic composition: +

    +

    + Composition Using Programmatic Instantiation (Control Implementation Class) +

    +package org.apache.beehive.controls.examples; + +@ControlImplementation(isTransient=true) +public class OrderRouterImpl implements OrderRouter +{ + // no @Control annotation, so no auto-init + OrderQueueBean rushOrders; + // no @Control annotation, so no auto-init + OrderQueueBean orders; + @Context ControlBeanContext context; + ... + + public void context_onCreate() + { + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + rushOrders = + (OrderQueueBean)Beans.instantiate(cl, + "org.apache.beehive.controls.examples.OrderQueueBean"); + rushOrders.setDestinationName("RushOrders"); + context.add(rushOrders); + orders = + (OrderQueueBean)Beans.instantiate(cl, + "org.apache.beehive.controls.examples.OrderQueueBean"); + orders.setDestinationName("Orders"); + context.add(orders); + } + + public void submitOrder(Order order, String deliverBy) + { + ... + } +} + +
    +
    +
    + Internal Architecture for Composition and Services +

    + The JavaBeans Runtime Containment and Services Protocol provides the base composition model for Control + composition and containment. In this model, JavaBeans are associated with a BeanContext that manages the + composition hierarchy and also manages any contextual services requested by the contained beans. +

    +

    + In the Control architecture, a ControlBean will potentially be related to two different BeanContexts: a parent + context that represents the outer container for the bean, and a peer context that provides containment and + services to other beans nested within that Control. +

    +

    + These context relationships from the previous sample are shown in the following diagram: +

    +

    + +

    +

    + In the diagram, the two OrderQueueBean instances created by OrderRouterBean are nested within the + ControlBeanContext; while not shown, these two beans would also have a peer ControlBeanContext providing them + with contextual services. +

    +

    + The peer ControlBeanContext provides localized generic services to the associated Control Implementation instance, + such as ability to resolve property values from the local bean instance or externalized configuration, and the + delivery of lifecycle events. The ControlBean architecture uses a delegation model for service discovery. If + an implementation instance requests a service that is not implemented by the peer BeanContext, it will delegate up + to the parent context to find a provider for the service. +

    +

    + At the root of the bean composition hierarchy is an instance of a ContainerBeanContext. This context represents + the external runtime environment, within which the ControlBean is running. This might represent an EJB, servlet, web + service, Java application, or any ControlBean-capable container. The ContainerBeanContext is responsible for the + initialization and provisioning of service providers that are specific to runtime environment with which it is + associated. +

    +

    + Whether ContainerBeanContext or ControlBeanContext, the BeanContext instances also provide the basic hierarchy of + composition, as shown by the parent-child relationships above. +

    +
    +
    +
    + Inheritance +

    + The Controls architecture also makes it possible to extend the functionality of existing Controls using standard Java + inheritance. While more complex scenarios are possible, a common model for extending a Control type using + inheritance involves extending both public interface and the implementation to extend base functionality by adding + new operations, events, or properties. +

    +

    + The following code sample shows the basic structure: +

    +

    + Basic Inheritance Sample Code +

    +// A.java: The base control interface +@ControlInterface +public interface A { ... } + +// AImpl.java: The implementation of the base control interface +@ControlImplementation +public class AImpl implements A { ... } + +// B.java: The extension of the base interface that adds +// operations, properties, and/or events +@ControlInterface +public interface B extends A { ... } + +// BImpl.java: The implementation of the extended control interface +@ControlImplementation +public class BImpl implements B { ... } + +

    + In the example above, the BBean JavaBean class that results from processing of B.java will expose the operations, + properties, and events defined by both the A and B control interfaces. The BImpl class would need to implement all + operations defined by the B interface, and could also choose to override some, all, or none of the operations defined + by A. +

    +

    + Inheritance is also supported for extensible control types. If AImpl implements the Extensible interface, then BImpl + could choose to define additional extensibility PropertySets and implement a new Extensible.invoke() method to provide + their semantics (delegating to AImpl.invoke() as appropriate). It could also choose not to extend the extensibilty + semantics and allow all operations defined within a ControlExtension derived from B to be handled by AImpl.invoke(). +

    +
    +
    + Context and Resource Events +

    + The Controls programming model includes two contextual services that provide a set of supporting life cycle and + resource events to assist the author of a Control Implementation. This section describes the events exposed by + these services: +

    +
    + Life Cycle Events +

    + The ControlBeanContext life cycle events provide notification to the associated ControlBean derived class and + Control Implementation Class (and potentially other interested listeners) of significant events related to the + peer bean instance. +

    +

    + The Control programming model exposes a basic set of lifecycle events to enable the Control to perform efficient + initialization and state management. These events are delivered by the peer ControlBeanContext associated with + a ControlBean instance. A listener can register to receive these events using the addLifeCycleListener API on + ControlBeanContext; the actual LifeCycle event interface itself is defined there as well: +

    +

    + Context Life Cycle Events +

    +package org.apache.beehive.controls.api.context; + +public interface ControlBeanContext + extends java.beans.beancontext.BeanContextServices +{ + ... + @EventSet + public interface LifeCycle + { + public void onCreate(); + public void onPropertyChange(PropertyChangeEvent pce); + public void onVetoablePropertyChange(PropertyChangeEvent pce) + throws PropertyVetoException; + } + + public void addLifeCycleListener(LifeCycle listener); + public void removeLifeCycleListener(LifeCycle listener); +} +

    + The specific life cycle and resource events are described in the following section: +

    +
    + The onCreate Event +

    + The onCreate event is delivered when the Control Implementation instance associated with the ControlBean has + been constructed and all declarative initialization has been completed. This provides an opportunity for the + implementation instance to perform any additional initialization required; implementation instances should + generally use the onCreate event instead of writing constructor code. +

    +
    +
    + The onPropertyChange Event +

    + The onPropertyChange event is delivered to a registered listener any time a bound property is changed on the + ControlBean. This provides an opportunity for the Control Implementation to change any internal state that + might be dependent upon a property value. +

    +
    +
    + The onVetoableChange Event +

    + The onVetoableChange event is delivered to a registered listener any time a constrained property is changed + on the ControlBean. This provides an opportunity for the Control Implementation to validate the set value + and veto any client-initiated change if necessary (by throwing a VetoException +

    +
    +
    +
    + Resource Events +

    + The Control programming model exposes a set of resource events to enable the control to manage external resources + (connections, sessions, ...) that it needs to provide its services. The model enables resources to be acquired + and held for a resource scope that is determined by the container in which the Controls are executing. For + example, in the servlet container, the scope might enable resources to be held for the duration of processing a + single http request. +

    +package org.apache.beehive.controls.api.context; + +public interface ResourceContext +{ + ... + @EventSet + public interface ResourceEvents + { + public void onAcquire(); + public void onRelease(); + } + + public void addResourceEventsListener(ResourceEvents listener); + public void removeResourceEventsListener(ResourceEvents listener); +} +
    + The onAcquire Event +

    + The onAcquire event is delivered to a registered listener the first time a ControlBean operation is invoked + within a particular resource scope. It provides an opportunity for the Control Implementation instance (or + other related entities, such as a contextual service provider) to acquire any short-term resources + (connections, sessions, etc) needed by the ControlBean. +

    +

    + The onAcquire event is guaranteed to be delivered once (and only once) prior to invocation of any operation + within a resource scope; it is also guaranteed that a paired onRelease event will be delivered when the + resource scope ends. +

    +

    + For more details on resource management, refer to the Control Overview. +

    +
    +
    + The onRelease Event +

    + The onRelease event is the companion event to onAcquire. It is guaranteed to be called once (and only once) + on any bean instance that has received an onAcquire event, when its associated resource scope has ended. It + acts as the signal that any short-term resources (connections, sessions, etc) acquired by the Control should + be released. +

    +
    +
    +
    + Receiving Life Cycle or Resource Events +

    + For a Control Implementation Class, the model for receiving context life cycle or resource events is consistent + with the general client model for event registration and delivery. Both declarative and programmatic mechanisms + are supported. +

    +
    + Declarative Access to events +

    + A Control Implementation Class can receive Life Cycle or Resource Events simply by declaring the annotated + @Context Context interface and then defining event handlers that follow the <contextFieldName>_<eventName> + convention. +

    +

    + The following sample code shows the JmsMessageControl registering to receive onAcquire and onRelease events: +

    +

    + Declarative Handling of Life Cycle Events (Control Implementation Class) +

    +package org.apache.beehive.controls.examples; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ResourceContext; +import org.apache.beehive.controls.api.events.EventHandler; + +@ControlImplementation(isTransient=true) +public class JmsMessageControlImpl implements JmsMessageControl +{ + @Context ResourceContext resourceContext; + + @EventHandler( + field="resourceContext", + eventSet=ResourceContext.ResourceEvents.class, + eventName="onAcquire" + ) + public void onAcquire() + { + // Code to acquire JMS connection/session/destination/writers + ... + } + + @EventHandler( + field="resourceContext", + eventSet=ResourceContext.ResourceEvents.class, + eventName="onRelease" + ) + public void onRelease() + { + // Code to release JMS connection/session/destination/writer + ... + } +} +

    + When using the declarative mechanism, a Control Implementation Class is free to implement only a subset of + the events; it is not necessary that it provide a handler for all events. +

    +
    +
    + Programmatic Access to Events +

    + An external entity (such as contextual service provider or even a client) is also able to register for life + cycle events on a ControlBean instance as well. This is done by obtaining a reference to the peer + ControlBeanContext for the instance using the getControlBeanContext API, and then using the + addLifeCycleListener API to register a lifecycle event listener. +

    +

    + This is shown by the following code: +

    +

    + Programmatic Handling of Life Cycle Events (Control Implementation Class) +

    + JmsMessageControlBean myJmsBean = ...; + + ControlBeanContext peerContext = myBean.getControlBeanContext(); + peerContext.addLifeCycleListener( + new ControlBeanContext.LifeCycle() + { + public void onCreate() { ... }; + public void onPropertyChange(PropertyChangeEvent pce) { ... }; + public void onVetoableChange(PropertyChangeEvent pce) { ... }; + } + ); +
    +
    +
    + JavaBean Context Events +

    + The org.apache.beehive.controls.api.context.ControlBeanContext API extends the following standard JavaBean context APIs: +

    +
      +
    • java.beans.BeanContextChild
    • +
    • java.beans.BeanContext
    • +
    • java.beans.BeanContextServices
    • +
    +

    + These APIs provide access to a standard set of JavaBean events that the Control Implementation Class can register + an interest in. +

    + +
    + PropertyChange Events +

    + The java.beans.BeanContextChild interface provides the addPropertyChangeListener() and + addVetoableChangeListener() APIs to register for notification when a property is modified. +

    +
    +
    + Membership Events +

    + The java.beans.BeanContext interface provides the addMembershipChangeListener() API to register for + notification whenever a child is added or removed from the BeanContext. +

    +
    +
    + Context Services Events +

    + The java.beans.BeanContextServices interface provides the addBeanContextServicesListener API to register for + notification when new contextual services become available or are revoked. +

    +
    +
    +
    +
    + Appendix A: The JmsMessageControl Public Interface + package org.apache.beehive.controls.examples; + +import org.apache.beehive.controls.api.bean.ControlInterface; +import org.apache.beehive.controls.api.events.EventSet; +import org.apache.beehive.controls.api.properties.PropertySet; + +import javax.jms.Session; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * The JmsMessageControl defines a basic Control to enable messages + * to be enqueued to a JMS queue or topic. Using Control properties, + * you can configure the connection, session, and destination attributes + * that should be used to connect to the JMS provider. The Control + * will transparently connect to the JMS provider and obtain any + * necessary resources to enqueue the messages. The Control will + * also sure that the resources are properly released at the end of the + * current resource scope associated with the Control’s runtime + * environment. + * + * The Control provides a basic set of operations that allow a simple text + * or object message to be written to the configured destination. It also + * provides an extensibility mechanism that allows new operations to be + * defined by extending this interface. Extended operations define the + * enqueueing of message with a specific type + * (TextMessage, ObjectMessage, ...) where operation parameters can be + * mapped to message properties or content. + */ +@ControlInterface +public interface JmsMessageControl +{ + // OPERATIONS + + /** + * Sends a simple TextMessage to the Control’s destination + * @param text the contents of the TextMessage + */ + public void sendTextMessage(String text) throws javax.jms.JMSException; + + /** + * Sends a simple ObjectMessage to the Control’s destination + * @param object the object to use as the contents of the message + */ + public void sendObjectMessage(java.io.Serializable object) throws javax.jms.JMSException; + + // EVENTS + + /** + * The Callback interface defines the events for the JmsMessageControl. + */ + @EventSet + public interface Callback + { + /** + * The onMessage event is delivered to a registered + * client listener whenever a + * message has been sent by the Control. + * @param msg the message that was sent + */ + public void onMessage(javax.jms.Message msg); + } + + // PROPERTIES + + /** + * The Connection property defines the attributes of the connection + * and session used to enqueue the message. This annotation + * can appear on both class and Control type declarations. + */ + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.FIELD, ElementType.TYPE}) + public @interface Connection + { + public String factoryName(); + public boolean transacted() default true; + public int acknowledgeMode() default Session.CLIENT_ACKNOWLEDGE; + } + + /** An enumeration that defines the value set of destination types */ + public enum DestinationType { QUEUE, TOPIC } + + /** + * The Destination property defines the attributes + * of the JMS destination that should + * be the target of any enqueued messages. + */ + @PropertySet + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.FIELD, ElementType.TYPE}) + public @interface Destination + { + public DestinationType type() default DestinationType.QUEUE; + public String name(); + } + + // EXTENSIBILITY ATTRIBUTES + + /** + * The set of supported message types for extended operations + */ + public enum MessageType { TEXT, OBJECT, BYTES } + + /** + * The Message attribute can be placed on an + * extended operation to describe the format + * of the message that should be enqueued when + * the operation is invoked. The method is + * expected to have a least parameter annotated + * with the Body attribute, and zero or more + * parameters with the Property attribute + * defining message properties. + */ + @Target({ElementType.METHOD}) + public @interface Message + { + public MessageType value() default MessageType.TEXT; + } + + /** + * The Body attribute indicates that the associated + * method parameter on an extended operation + * contains the message body. + */ + @Target({ElementType.PARAMETER}) + public @interface Body {} + + /** + * The Property attribute can be used to define + * operation parameters that should be used to + * set properties on the message. The type of + * property to set will be inferred based upon + * the type of the parameter. + */ + @Target({ElementType.PARAMETER}) + public @interface Property + { + public String name(); + } +} +
    + +
    + Appendix B: The JmsMessageControl Implementation Class + package org.apache.beehive.controls.examples; + +import org.apache.beehive.controls.api.bean.ControlImplementation; +import org.apache.beehive.controls.api.bean.Extensible; +import org.apache.beehive.controls.api.context.Context; +import org.apache.beehive.controls.api.context.ControlBeanContext; +import org.apache.beehive.controls.api.context.ResourceContext; +import org.apache.beehive.controls.api.ControlException; +import org.apache.beehive.controls.api.events.Client; +import org.apache.beehive.controls.api.events.EventHandler; + +import javax.jms.JMSException; +import javax.jms.Queue; +import javax.jms.QueueConnection; +import javax.jms.QueueConnectionFactory; +import javax.jms.QueueSession; +import javax.jms.QueueSender; +import javax.jms.Topic; +import javax.jms.TopicConnection; +import javax.jms.TopicConnectionFactory; +import javax.jms.TopicPublisher; +import javax.jms.TopicSession; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +import java.lang.reflect.Method; + +/** + * The JmsMessageControlImpl class is the + * Control Implementation Class for the JmsMessageControl. + * It implements two basic operations + * (sendTextMessage and sendObjectMessage) + * as well as an extensibility model that enables custom + * message formats to be defined and associated with + * extended method signatures. + */ +@ControlImplementation(isTransient=true) +public class JmsMessageControlImpl implements JmsMessageControl, Extensible +{ + /** + * The peer BeanContext instance associated with the Control + */ + @Context ControlBeanContext context; + + /** + * The client callback event router for this Control + */ + @Client Callback client; + + /** + * The fields are used to hold transient JMS resources + * that are acquired and held for + * the resource scope associated with the Control + */ + transient javax.jms.Connection _connection; + transient javax.jms.Session _session; + transient javax.jms.MessageProducer _producer; + transient javax.jms.Destination _dest; + + /** + * The Resourceontext instance associated with the Control + */ + @Context ResourceContext resourceContext; + + /* + * The onAcquire event handler + * This method will be called prior to any operation with + * a given resource scope. It is responsible for + * obtaining the connection, session, destination, and appropriate + * writer instance, for use within the operation. + */ + @EventHandler( + field="resourceContext", + eventSet=ResourceContext.ResourceEvents.class, + eventName="onAcquire" + ) + public void onBeanAcquire() + { + // + // Acquire the property values needed for initialization + // + Destination destProp = + (Destination)context.getControlPropertySet(Destination.class); + Connection connProp = + (Connection)context.getControlPropertySet(Connection.class); + + try + { + // + // Obtain the JMS Destination instance based upon the Destination property + // + InitialContext jndiContext = new InitialContext(); + _dest = (javax.jms.Destination)jndiContext.lookup(destProp.name()); + + // + // Obtain Connection, Session, and MessageProducer resources based upon the + // destination type and the values in the Connection PropertySet + // + if (destProp.type() == JmsMessageControl.DestinationType.QUEUE) + { + javax.jms.QueueConnectionFactory connFactory = + (QueueConnectionFactory)jndiContext.lookup(connProp.factoryName()); + _connection = connFactory.createQueueConnection(); + _session = ((QueueConnection)_connection).createQueueSession( + connProp.transacted(), + connProp.acknowledgeMode()); + _producer = ((QueueSession)_session).createSender((Queue)_dest); + } + else + { + javax.jms.TopicConnectionFactory connFactory = + (TopicConnectionFactory)jndiContext.lookup(connProp.factoryName()); + _connection = connFactory.createTopicConnection(); + _session = ((TopicConnection)_connection).createTopicSession( + connProp.transacted(), + connProp.acknowledgeMode()); + _producer = ((TopicSession)_session).createPublisher((Topic)_dest); + + } + } + catch (javax.naming.NamingException ne) + { + throw new ControlException("Unable to locate JNDI object", ne); + } + catch (ClassCastException ce) + { + throw new ControlException("JNDI object did not match expected type", ce); + } + catch (JMSException jmse) + { + throw new ControlException("Unable to acquire JMS resources", jmse); + } + } + + /* + * The onRelease event handler for the associated context + * This method will release all resource acquired by onAcquire. + */ + @EventHandler ( + field="resourceContext", + eventSet=ResourceContext.ResourceEvents.class, + eventName="onRelease" + ) + public void onRelease() + { + try + { + if (_producer != null) + { + _producer.close(); + _producer = null; + } + if (_session != null) + { + _session.close(); + _session = null; + } + if (_connection != null) + { + _connection.close(); + _connection = null; + } + } + catch (JMSException jmse) + { + throw new ControlException("Unable to release JMS resource", jmse); + } + } + + /** + * Helper method used to send a message once constructed + */ + private void sendMessage(javax.jms.Message msg) throws JMSException + { + client.onMessage(msg); + if (_producer instanceof javax.jms.QueueSender) + ((QueueSender)_producer).send(msg); + else + ((TopicPublisher)_producer).publish(msg); + } + + + /** + * Sends a simple TextMessage to the Control’s destination + * @param text the contents of the TextMessage + */ + public void sendTextMessage(String text) throws JMSException + { + javax.jms.TextMessage msg = _session.createTextMessage(text); + sendMessage(msg); + } + + /** + * Sends a simple ObjectMessage to the Control’s destination + * @param object the object to use as the contents of the message + */ + public void sendObjectMessage(java.io.Serializable object) throws JMSException + { + javax.jms.ObjectMessage msg = _session.createObjectMessage(object); + sendMessage(msg); + } + + /** + * Implements the Extensible.invoke() interface for this Control + * This method uses the Message property to determine the type + * of message to construct, and then uses the Body and Property + * attributes of method parameters to supply message + * content and properties. + */ + public Object invoke(Method m, Object [] args) throws Throwable + { + int bodyIndex = -1; + for (int i= 0; i < args.length; i++) + { + if (context.getParameterPropertySet(m, i, JmsMessageControl.Body.class) != null) + { + bodyIndex = i; + break; + } + } + if (bodyIndex == -1) + throw new ControlException( + "No @Body argument defined for operation: " + + m.getName() + ); + + // + // Create a message based upon the value of the Message property of the method + // + javax.jms.Message msg = null; + Message msgProp = context.getMethodPropertySet(m, JmsMessageControl.Message.class); + try + { + switch(msgProp.value()) + { + case TEXT: + msg = _session.createTextMessage((String)args[bodyIndex]); + break; + + case OBJECT: + msg = _session.createObjectMessage((java.io.Serializable)args[bodyIndex]); + break; + case BYTES: + javax.jms.BytesMessage bmsg; + msg = bmsg = _session.createBytesMessage(); + bmsg.writeBytes((byte []) args[bodyIndex]); + break; + } + } + catch (ClassCastException cce) + { + throw new ControlException("Invalid type for Body parameter", cce); + } + + // + // Now decorate the message with any Property-annotated parameters + // + for (int i= 0; i < args.length; i++) + { + JmsMessageControl.Property prop = + context.getParameterPropertySet(m, i, JmsMessageControl.Property.class); + if (prop != null) + { + String propName = prop.name(); + if (args[i] instanceof String) + msg.setStringProperty(propName, (String)args[i]); + else if (args[i] instanceof Integer) + msg.setIntProperty(propName, ((Integer)args[i]).intValue()); + else if (args[i] instanceof Short) + msg.setShortProperty(propName, ((Short)args[i]).shortValue()); + else if (args[i] instanceof Boolean) + msg.setBooleanProperty(propName, ((Boolean)args[i]).booleanValue()); + else if (args[i] instanceof Float) + msg.setFloatProperty(propName, ((Float)args[i]).floatValue()); + else if (args[i] instanceof Double) + msg.setDoubleProperty(propName, ((Double)args[i]).doubleValue()); + else + msg.setObjectProperty(propName, args[i]); + } + } + + // + // Send it + // + sendMessage(msg); + return msg; + } +} +
    + + +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/controls/projects.xml b/docs/forrest/release/src/documentation/content/xdocs/controls/projects.xml new file mode 100644 index 0000000..72e87dd --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/controls/projects.xml @@ -0,0 +1,137 @@ + + + + +
    + Building Controls +
    + +
    + Overview +

    + Beehive Controls are a JavaBean resource abstraction layer for enterprise Java applications. + The source artifacts for Controls are simply .java files that can be built along with an + enterprise Java module / project or as part of a standalone JAR file. This document describes + how to build Controls in each of these project types. +

    +

    + Because Controls use Java annotations as a metadata model, Controls require the + annotation processing features available in J2SE 5.0. As such, a special Ant + build macro is used to process annotations and produce any build-time configuration + artifacts (such as XML files and deployment descriptors) and binary class files. The API for + the Controls annotation processor is described here. This build macro + can be used to compile Control sources for a project. It can be used in an Ant build file as: +

    + + + + ]]> + +

    + This will build the Control sources from src/ into classes/ and perform code generation of + Control beans into tmp/ using the classpath project.classpath. The resulting .class files + can then be used in your Java projects just as any other .class files. +

    +
    +
    + JAR Projects +

    + It is often useful to build Beehive Controls into a standalone JAR that can be copied into or shared among many + Java projects. This can be done by first building the controls and then JAR-ing them into a standard .jar + file. The Controls runtime also provides an Ant + task that + is used to perform additional processing for JARs that contain Controls. The Control JAR task can be used like this + example: +

    + + + + + + + + + + + + + + ]]> + +

    + The <coontrol-jar> task also merges any .manifest files that were generated while + processing control annotations. Use of this Ant task is not required, but it should be used any time Control + manifest attributes need to be merted into a META-INF/MANIFEST.MF file. +

    +
    +
    + Integrating into Existing Projects +

    + Controls can also be used in existing Java projects by adding both the <build-controls> call to + build Control sources. Optionally, the <control-jar> can be used to build the result into a + JAR file; while this is best practice, it is not required. If Beehive Controls are added to existing Java + projects, take care to resolve source file dependencies correctly. Because Controls perform code generation + of Control Bean classes, clients of Control Bean classes need to be compiled after Controls + have been built. +

    +
    +
    + Source Control +

    + In order to correctly add a Controls project to source control, several resources need to be checked in. Both required + and optional resources are listed in the table below: +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameJAR fileVersionRequired
    Beehive Controlsbeehive-controls.jardistributionYes
    Beehive EJB Controlbeehive-ejb-control.jardistributionYes; if using EJB control functionality
    Beehive JDBC Controlbeehive-jdbc-control.jardistributionYes; if using JDBC control functionality
    Beehive JMS Controlbeehive-jms-control.jardistributionYes; if using JMS control functionality
    Commons Codeccommons-codec-1.3.jardistributionYes
    Jakarta Velocity-depvelocity-dep-1.4.jardistributionYes; required at build time
    +

    + The Velocity JARs are used by Controls for code-generation and do not need to be committed to SCM if they are + referenced from a Beehive distribution. They are not required at runtime. The system control JARs are needed + only if they are used in an application. +

    +
    + +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/controls/samples/controlsBlank.xml b/docs/forrest/release/src/documentation/content/xdocs/controls/samples/controlsBlank.xml new file mode 100644 index 0000000..c535f84 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/controls/samples/controlsBlank.xml @@ -0,0 +1,62 @@ + + + +
    + Control Project Template +
    + +
    + Introduction +

    +Use the "blank" Control sample (located at <BeehiveRoot>/samples/controls-blank) as a +template for building your own Control projects. +

    + + <BeehiveRoot> refers to the top-level directory of your Beehive installation. + A typical value for <BeehiveRoot> would be /apache/apache-beehive-1.0. +

    The template contains a basic 'Hello World' control to get you started. Control projects can be + archived in a JAR file and then imported into multiple applications. Simply import the JAR archive + into the application's WEB-INF/lib directory.

    + +
    +
    + Using the Control Project Template +

    The following instruction assume that you have completed the basic Beehive set up procedure + at Set Up the Dev Environment.

    +

    To use the template:

    +

    (1) Copy the contents of <BeehiveRoot>/samples/controls-blank into your + project folder (referred to as <Project-Folder> below). (Or copy controls-blank + to another location and rename it as <Project-Folder>.)

    +

    (2) In the file controls-blank/build.properties, + edit the beehive.home property so it points to + <BeehiveRoot> (the top-level folder of your + beehive installation). For example, if your beehive installation + resides at /apache/apache-beehive-1.0, then your build.properties file + would appear as follows.

    + +

    build.properties

    + beehive.home=/apache/apache-beehive-1.0 +

    An Ant build file is included + in the template, which will compile your control project into a distributable JAR + file. After you have copied the contents of + controls-blank into your project folder, the following directory structure should exist:

    +<Project-Folder> + src + build.properties + build.xml +

    The following Ant command will compile the control template.

    +ant -f <Path-to-Project-Folder>\build.xml build +

    This will produce a distributable JAR file at: <Project-Folder>/build/mycontrols.jar.

    +

    To use the JAR in your other projects (like a web project or a web service project), copy + mycontrols.jar into the project's WEB-INF/lib directory.

    +

    (To change the name of the generated JAR file, edit the following line in + build.xml.)

    + <property name="build.jar" value="mycontrols.jar"/> +
    + +
    + Java, J2EE, and JCP are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.
    + © 2004, Apache Software Foundation +
    +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/controls/testing.xml b/docs/forrest/release/src/documentation/content/xdocs/controls/testing.xml new file mode 100644 index 0000000..7fe26e3 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/controls/testing.xml @@ -0,0 +1,122 @@ + + + +
    + Testing Controls +
    + +
    + Overview +

    + A Beehive Control can be tested either inside of an application + container or outside in a standalone Java environment. The latter can be particularly useful + running unit tests or during test driven development (TDD). This document describes how to unit + test a Beehive Control using JUnit. +

    +
    +
    + The JUnit Controls Container +

    + The Controls JAR file beehive-controls.jar provides build time, run time, and test time + support for developing Controls. This makes it very easy to begin unit testing Controls that + are built as part of an application. Out of the box, Controls provides integration into the + JUnit test framework via the + ControlTestCase + base class. This base class provides a Control container that hosts a Control for the duration + of a Control test. It also provides help in instantiating a Control declaratively via the + @Control annotation. +

    +

    + To author a JUnit Controls test using the base class, the test case should be declared as: +

    + +public class FooTest + extends ControlTestCase { +... +} + +

    + For each test case with a name method matching the JUnit naming convention test*, the + JUnit container will start and stop the + ControlTestContainerContext. + The beginContext method will be called at the beginning of each test in the setUp() + method, and the endContext method will be called at the end of each test in the tearDown() + method. This will simulate a interaction lifetime with the control where multiple Control instances can + be invoked multiple times. The Control will hold any resources it acquires for the duration of the test method. + As an example, this begin / end Context lifetime represents the same lifetime as that for a single HttpServletRequest + in the web tier. Any resources loaded from the ControlTestContainerContext are loaded from the current + thread's context class loader. +

    +

    + For a single test, once the ControlTestContainerContext has been initialized, the controls in the + JUnit test class are declaratively instantiated via the ClientInitializer that was generated for the + test case. +

    + + In order to use a ClientInitializer, the JUnit test cases must have been processed with the + Controls annotation processor via the <build-controls> Ant macro. + +

    + In cases where a test needs to provide a custom implementation of a Controls container, a new container + implementation will be created by overriding the + + initializeControlContainerContext() method. +

    +

    + In cases where a test needs to override the base setUp and tearDown JUnit lifecycle + methods, the test author should remember to call super.setUp() and super.tearDown() + from the overridden methods. +

    +
    +
    + Control Instantiation +

    + Controls declared with the @Control annotation will be declaratively instantiated by the + JUnit container. These references will be valid for the duration of the JUnit test. +

    +
    +
    + Using another Base Class +

    + In cases where tests are unable to extend the ControlTestCase base class, the Control + container and its lifecycle can be implemented using utilities available in the class + + ControlContainerContextManager. This class provides methods to begin and end a Context, to + instantiate controls, and to get the Context object itself. To implement a ControlContainerContext + for a single test case, the following code can be added to a test case method: +

    + +public void testFoo() { + ControlContainerContext ccc = new ControlTestContainerContext(); + ControlContainerContextManager cccManager = ControlContainerContextManagerFactory.getInstance(ccc); + cccManager.beginContext(); + cccManager.instantiateControls(this); + + ... test code ... + + cccManager.endContext(); +} + +

    + The same ControlContainerContext methods could be added to the JUnit test lifecycle methods + setUp() and tearDown(). +

    +
    +
    + Running the JUnit Tests +

    + The JUnit tests for a Control can be executed in a variety of ways including via Ant or from and IDE + like IntelliJ or Eclipse. Ant can run these JUnit tests in the usual means by executing them directly + or by using the optional Ant tasks to support running and reporting results for JUnit tests. +

    +

    + To run Controls JUnit tests from an IDE, the command line build to code generate the Controls support + classes often needs to be run so that the Control support classes are available in classpath. Once + these classes have been generated, an IDE's JUnit integration should successfully. While this is + inconvenient, as support for annotations and APT improves in IDEs, this process should become easier. +

    +
    + +
    \ No newline at end of file diff --git a/docs/forrest/release/src/documentation/content/xdocs/controls/tutorial.xml b/docs/forrest/release/src/documentation/content/xdocs/controls/tutorial.xml new file mode 100644 index 0000000..4c303e1 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/controls/tutorial.xml @@ -0,0 +1,315 @@ + + + +
    + Beehive Controls Tutorial +
    + +
    + Introduction +

    + The Controls Tutorial is a good way to become familiar with the concepts of Beehive Controls. This describes + how to write, build, package, and test a simple Hello Control. The following concepts will be convered here: +

    +
      +
    • Creating a standalone Beehive Control project
    • +
    • Creating a Control interface and implementation
    • +
    • Compiling a Control
    • +
    • Packaging a Control into a JAR file
    • +
    • Testing a Control using JUnit
    • +
    +

    + For a technical description of Controls, see the Controls programming guide. +

    +
    +
    + Step 1: Setup Control Development +
    + Install Beehive +

    + Complete all of the required and optional steps to install and setup Beehive here. +

    +
    +
    + Install JUnit +

    + In this tutorial, JUnit is the test framework used. In order to use JUnit, download a JUnit release + here and unzip it into a local + directory. +

    +
    +
    + Create a Control Project +

    + Copy the directory <BeehiveRoot>/samples/controls-blank to a location of your choice. For example, you might copy + to the following location: /beehive-projects/controls-blank. +

    +

    + Rename controls-blank to controls_tutorial. +

    +

    + Edit the file controls_tutorial/build.properties so that the property beehive.home points + to the top level folder of your Beehive distribution. +

    +

    + Add the property junit.home to the file and ensure that it points to your JUnit installation. +

    +

    + For example, if Beehive distribution is located in /apache/apache-beehive-1.0 + and JUnit is located in /test-tools/junit, then your build.properties file + would appear as follows: +

    + +beehive.home=/apache/apache-beehive-1.0 + +junit.home=/test-tools/junit + + Properties files should use the '/' character to separate drive, directory, and file names. + +
    +
    +
    + Step 2: Compile Control Interface and Implementation Source Files +
    + Introduction +

    + A Beehive Control consists of two source files -- an interface file and an implementation file. The interface + file is the public API of a control and provides all of the methods that can be invoked by a Control user (or client). + The implementation file contains the implementation code for the methods listed in the interface file. +

    +
    +
    + A Control's Source Files +

    Open the file /controls_tutorial/src/pkg/HelloImpl.java.

    +

    The implementation file appears as follows. (There is no need to edit the file at this point in the tutorial.)

    + package pkg; + +import org.apache.beehive.controls.api.bean.ControlImplementation; + +@ControlImplementation(isTransient=true) +public class HelloImpl + implements Hello { + + public String hello() { + return "Hello!"; + } +} +

    + Open the file controls_tutorial/src/pkg/Hello.java. The interface file should appear appears as follows. +

    + package pkg; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +@ControlInterface +public interface Hello { + String hello(); +} +
    +
    + Set a Name for the Hello Control JAR +

    + This step sets the name of the JAR file created when compiling the Hello and HelloImpl interface + and implementation. +

    +

    + Edit the file controls_tutorial/build.xml to set the build.jar property to the name + helloControl.jar. The property should appear as: +

    + +<project name="controls_tutorial" default="usage" basedir="."> +... + <property name="build.jar" value="helloControl.jar"/> +... +<project> +
    +
    + Build and Package the Control +

    + Now, compile the control and build the Control's JAR file. The following Ant command should be run from the + controls_tutorial project directory; at the command prompt, enter: +

    + ant clean build +

    + The Control's classes are generated in build/classes, and the Control's JAR file is created in build/helloControl.jar. +

    +
    +
    +
    + Step 3: Create a JUnit Test for the Control +
    + Create a JUnit Test Class +

    + Now that the control builds successfully, it's time to write a JUnit test case to ensure that the + Control operates as it is intended. To do this, create a test directory to contain + the JUnit test cases for the control. The directory should be created under controls_tutorial/test + with the command: +

    + mkdir test +

    + In this directory, create a Java package to contain the source of a JUnit test with: +

    + mkdir test/testpackage +

    + Now, create a JUnit test case called HelloControlTest.java. This class wil declare an instance of the + Hello control and unit test its API. This class should appear as follows: +

    + package testpackage; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.test.junit.ControlTestCase; + +import pkg.Hello; + +public class HelloControlTest + extends ControlTestCase { + + @Control + private Hello _helloControl; + + public void testHello() + throws Exception { + String message = _helloControl.hello(); + + assertEquals("Failed to receive message \"Hello!\"", "Hello!", message); + } +} +
    +
    + Edit build.xml to Compile and Run the JUnit Test +

    + Now that the test has been written, the Ant build.xml file still needs to change to support building + and running JUnit tests. To do this, add the following test target to the build.xml file: +

    + <target name="test"> + <property name="test.src" location="test"/> + <property name="test.classes" location="${build.dir}/test-classes"/> + <property name="test.beansrc" location="${build.dir}/test-beansrc"/> + + <mkdir dir="${test.classes}"/> + <mkdir dir="${test.beansrc}"/> + + <path id="test.classpath"> + <path refid="build.classpath"/> + <pathelement location="${build.dir}/${build.jar}"/> + <pathelement location="${junit.home}/junit.jar"/> + </path> + + <build-controls srcdir="${test.src}" + destdir="${test.classes}" + tempdir="${test.beansrc}" + classpathref="test.classpath"/> + + <path id="test-run.classpath"> + <path refid="test.classpath"/> + <pathelement location="${test.classes}"/> + <pathelement location="${beehive.home}/lib/common/commons-discovery-0.2.jar"/> + <pathelement location="${beehive.home}/lib/common/commons-logging-1.0.4.jar"/> + </path> + + <java classname="junit.textui.TestRunner" + classpathref="test-run.classpath"> + <arg line="testpackage.HelloControlTest"/> + </java> +</target> +

    + This target first builds the test source files. Then, it runs the JUnit tests, reporting errors + if tests fail. +

    + + There are lots of ways to run JUnit tests in Ant including the use of the <junit> + Ant tasks. This tutorial has taken a simple approach to running JUnit; this example test should + run in other JUnit execution environments as well. For information on configuring Ant's JUnit + tasks, see here. + +
    +
    + Run the Test +

    In your command shell, ensure that you are in the directory controls_tutorial/

    +

    Run the following Ant command to test the control.

    + +ant clean build test + +
    +
    +
    + Step 4: Edit the Control and Re-test +
    + Edit the Control Source Files +

    Edit the file HelloImpl.java so it appears as follows. Code to add appears in bold

    + package pkg; + +import org.apache.beehive.controls.api.bean.ControlImplementation; + +@ControlImplementation(isTransient=true) +public class HelloImpl + implements Hello { + + public String hello() { + return "Hello!"; + } + +public String hello(String name) { + return "Hello, " + name + "!"; + } +} +

    Edit the file Hello.java so it appears as follows. Code to add appears in bold

    + package pkg; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +@ControlInterface +public interface Hello { + String hello(); + + String hello(String name); +} +
    +
    + + Add a Test Case for the New Control Method + +

    Edit the file Tests.java so it appears as follows. Code to add appears in bold.

    + package testpackage; + +import org.apache.beehive.controls.api.bean.Control; +import org.apache.beehive.controls.test.junit.ControlTestCase; + +import pkg.Hello; + +public class Tests + extends ControlTestCase { + + @Control + private Hello _helloControl; + + public void testHello() + throws Exception { + + String message = _helloControl.hello(); + assertEquals("Failed to receive message \"Hello!\"", "Hello!", message); + } + + public void testParam() + throws Exception { + String message = _helloControl.hello("World"); + + assertEquals("Failed to receive message \"Hello, World!\"", "Hello, World!", message); + } +} +
    +
    + Run the Test +

    + Test the control according to the previous instructions here. +

    +
    +
    + +
    + + Java, J2EE, and JCP are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. +
    © 2006, Apache Software Foundation +
    +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/glossary.xml b/docs/forrest/release/src/documentation/content/xdocs/glossary.xml new file mode 100644 index 0000000..91a0be0 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/glossary.xml @@ -0,0 +1,128 @@ + + + +
    + Glossary of Terms +
    + +
    + Glossary: Controls +
    +
    Control
    +
    + Controls are designed to make it easier to integrate complex resources into your Java application. Controls + consist of two Java files: a Control implementation file, and a Control interface file. +
    +
    +
    +
    Control Bean
    +
    + A Control Bean is a file that is generated while running the Controls annotation processing. The Control Bean + is the glue between a control interface and a control implementation. When using a Control from a Control client, + either the Control's interface or the Control Bean may be used to refer to declare a Control. The Control Bean + provides access to methods supporting adding / removing event listeners and getting / setting Control properties. +
    +
    +
    +
    System Control
    +
    + System controls are those that are low-level abstractions atop typical system resources such as EJB, JMS, JDBC, and web services. +
    +
    +
    +
    + Glossary: NetUI +
    +
    page flow
    +
    + A page flow consists of one controller class and one or more pages, + all associated with a single directory path. A web project can contain many page flows. +
    +
    +
    +
    page flow controller
    +
    + A controller class is a Java class that defines actions, exception handlers, state, etc. related to a + page flow. Configuration information is defined through annotations on methods, + fields, and the class itself. +
    +
    +
    +
    shared flow
    +
    + A shared flow is a class that defines actions, exception handlers and state which can be shared by + page flow controllers. +
    +
    +
    +
    data binding
    +
    +

    + Data binding used to bind UI widgets to data in the web-tier environment. The data objects can be located in various places throughout + the web application: +

    +
      +
    • in the page flow controller class
    • +
    • in container provided JSP implicit objects
    • +
    • in NetUI framework-provided JSP implicit objects
    • +
    +

    + More details about data binding can be found here. +

    +
    +
    +
    +
    form bean
    +
    +

    + Typically, a form bean is a server-side representation of the data in an HTML <form> tag. A form bean follows ordinary + Java Bean syntax: each form bean is a class consisting of any number of properties, each property having a setter and a getter + method associated with it. Form bean classes normally implement java.io.Serializable in order to facilitate persistence + of form bean instances. The sample form bean below has two properties; each one has a getter and setter method associated with it. +

    + +public class ProfileFormBean + implements java.io.Serializable { + + private int age; + private String name; + + public void setAge(int age) { + this.age = age; + } + + public int getAge() { + return this.age; + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } +} +

    + Form beans are most often used to pick up data that is submitted from a <netui:form> tag. + Once the POST data has been mapped to a form bean instance, the form bean is passed to a Page Flow action method. + Note that form beans can be either standalone Java files or inner classes of a page flow controller. +

    +
    +
    +
    +
    NetUI JSP Tag Library
    +
    + The JSP library for NetUI web applications. The <netui> tag library uses JSP 2.0 and NetUI databinding expressions to + bind UI to data provided by the page flow controller and other web application data/resources. +
    +
    +
    + +
    + + Java, J2EE, and JCP are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.
    + © 2004, Apache Software Foundation +
    +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/index.xml b/docs/forrest/release/src/documentation/content/xdocs/index.xml new file mode 100644 index 0000000..fb9cca4 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/index.xml @@ -0,0 +1,83 @@ + + + +
    + Beehive SVN Documentation +
    + +

    + Welcome to Beehive! Apache Beehive is a project focused on building ease-of-use frameworks for enterprise Java applications. + Using Java 5.0 annotations for configuration and declarative programming, Beehive reduces the amount of coding necessary for + building enterprise applications. +

    +

    + Beehive consists of several projects which can be used either together or seprately depending on the requirements of an application. + These include: +

    +
      +
    • + NetUI: A project that includes Page Flow and a powerful set of JSP tags. Page Flow is + an annotation-driven web application programming framework built on Struts, including + first-class integration with JavaServer Faces and Struts itself. It centralizes navigation logic, + state, metadata, and exception handling in a single + Page Flow Controller class. The NetUI JSP tag set is + Page Flow-aware, and provides tags for rendering HTML / XHTML and higher-level UI constructs such as + data grids and trees. +
    • +
    • + Controls: A lightweight, metadata-driven component framework for building that reduces the + complexity of being a client of enterprise resources. Controls provide a unified client abstraction that + can be implemented to access a diverse set of enterprise resources using a single configuration model. +
    • +
    +

    + In addition, Beehive includes a set of system controls that are abstractions for low-level J2EE resource APIs such + as EJB, JMS, JDBC, and web services. +

    +

    + The Beehive documentation package contains tutorials, user guies, samples, and project templates for getting started building + various kinds of applications. If you are new to Beehive, the overview documentation for NetUI and Controls are good starting + points: +

    + +

    + To get started building Beehive-enabled projects, follow the Setup instructions and look at the + Beehive project templates which are skeletons for building new Beehive-enabled web applications and control + projects: +

    + +

    + More detailed information on starting projects is available in the getting started guides: +

    + +

    + The tutorials are end-to-end examples of how to build projects with Beehive features: +

    + +

    + The samples are another good starting point for learning about Beehive. +

    + + +
    + + © 2005, Apache Software Foundation + +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/infra/beehive-ant-macros.xml b/docs/forrest/release/src/documentation/content/xdocs/infra/beehive-ant-macros.xml new file mode 100644 index 0000000..3d8c735 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/infra/beehive-ant-macros.xml @@ -0,0 +1,184 @@ + + + +
    + Beehive Ant Macros +
    + +
    + Overview +

    The Beehive distribution includes several Ant macros to assist developers creating Ant build files for + NetUI Page Flow, Controls and Web Services. These macros are located in the + <BeehiveHome>/ant/beehive-tools.xml file.

    +

    To use any of these macros import the beehive-tools file into your Ant script:

    + <import file="${beehive.home}/ant/beehive-tools.xml"/> +
    +
    + The build-controls Ant Macro +

    This macro uses the Java 5 Annotation Processing Tool (apt) for + control generation and compilation. Any .java files generated by this macro can be found in the + directory specifed by the tempdir parameter. +

    +

    build-controls accepts the following parameters:

    + + + + + + + + + + + + + + + + + + + + + + +
    Parameter NameRequiredDescription
    srcdirYesThe directory containing the controls to build.
    destdirYesThe destination directory for the compiled controls files.
    tempdirYesA temporary directory for any generated java files.
    classpathrefYesA classpath reference for building the controls. Required.
    +

    +
    + Sample +

    + The following project has a source directory, a destination directory, and a temporary directory for + generated files. +

    + +project + build + classes + src + tempsrc +

    + For this project, the build-controls call would look like this: +

    + +<build-controls srcdir="project/src" + destdir="project/build/classes" + tempdir="project/tempsrc" + classpathref="build.classpath"/> +
    +
    +
    + The build-pageflows Ant Macro + +

    This macro is intended for the compilation of the Page Flow portions of a web application. + This macro will not compile controls inside of a web application. If the web application + contains controls, they must be compiled first using the build-controls macro (see above). + 0nce the compilation of the controls is complete, the page flows within the web app can be compiled.

    + +

    build-pageflows accepts the following pararmeters:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Parameter NameRequiredDescription
    srcdirYesThe root directory which will be scanned for source files.
    classpathrefYesThe classpath reference for building page flows.
    sourcepathrefNoA reference to a path that contains all the source roots. Defaults to a path that + contains ${srcdir} and ${srcdir}/WEB-INF/src.
    webcontentdirNoThe root location for web content (e.g., JSPs, web.xml, etc.). Defaults to ${srcdir}.
    destdirNoThe directory for compiled classes and generated resources. Defaults to ${srcdir}/WEB-INF/classes.
    tempdirNoThe directory for temporary .java files, copied from page flows (etc.) with non-.java extensions. + Defaults to ${srcdir}/WEB-INF/.tmpbeansrc.
    + +
    + Samples +

    + Consider a simple project with the following structure: +

    + +project + WEB-INF + classes + lib + src + web.xml +

    + For this project, the build-pageflows call would look like this: +

    + +<build-pageflows srcdir="project" classpathref="webapp.build.classpath"/> +

    + In a more complex project, web content, source, and the target (build) directory may be in different + places: +

    + +project + src + web + WEB-INF + lib + web.xml +build + webapp +

    + In this case, the build-pageflows call would be: +

    + +<build-pageflows srcdir="project/src" + webcontentdir="project/web" + destdir="project/build/webapp/WEB-INF/classes" + classpathref="webapp.build.classpath"/> +
    +
    + +
    + The build-schemas Ant Macro +

    This macro can be used to parse an XML Schema or Apache XMLBeans xsdconfig file into + Apache XMLBeans. It is really just a wrapper for the XMLBean schema compiler which is part + of the Apache XMLBeans distribution.

    +

    build-schemas accepts the following pararmeters:

    + + + + + + + + + + + + +
    Parameter NameRequiredDescription
    srcdirYesThe directory containing XML Schemas or XMLBeans xsdconfig files to build.
    destdirYesThe directory to use for files generated during an XSD build.
    + +
    + Sample +

    + In this example, schemas are being built from a webapp's WEB-INF/schemas to WEB-INF/classes. +

    + <build-schemas srcdir="WEB-INF/schemas" destdir="WEB-INF/classes"/> +
    +
    + +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/installation.xml b/docs/forrest/release/src/documentation/content/xdocs/installation.xml new file mode 100644 index 0000000..36fb880 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/installation.xml @@ -0,0 +1,44 @@ + + + +
    + Installation +
    + +

    + This document explains how to install a Beehive distribution on your machine. Once you have completed the basic + setup steps, your environment will be setup for building Beehive applications. +

    +

    (1) The following software is required for developing Beehive applications:

    + +

    (2) Make sure that the following environmental variables are set in your shell.

    +
      +
    • ANT_HOME
    • +
    • JAVA_HOME
    • +
    +

    Example values for these variables could be:

    + +ANT_HOME = /home/foo/java/apache-ant-1.6.2 +JAVA_HOME = /home/foo/java/jdk1.5.0_04 + +

    (3) Ensure that $JAVA_HOME/bin and $ANT_HOME/bin are on your $PATH.

    +

    + You are now ready to begin developing Beehive applications! + If you plan on running the Beehive tutorials, follow the tutorial specific steps + here. +

    +

    + Information on tutorials and samples is here. +

    + +
    + + Java, J2EE, and JCP are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.
    © 2004, Apache Software Foundation +
    +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/actions.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/actions.xml new file mode 100644 index 0000000..01e9632 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/actions.xml @@ -0,0 +1,295 @@ + + + +
    + Actions in NetUI +
    + +
    + Introduction +

    + Actions are a core piece of the NetUI framework. They are Page Flow methods or + annotations which make navigational decisions and execute controller + logic. This document shows how to create and invoke actions. +

    +
    +
    + Creating Actions +

    + There are two ways to create an action in a Page Flow (or Shared Flow) + controller: +

    +
      +
    • through an annotation, or
    • +
    • through a method.
    • +
    + +
    + Creating an action through an annotation +

    + The simplest way to create an action is through the + + @Jpf.SimpleAction + + annotation at the class level of a Page Flow or Shared Flow controller: +

    + +@Jpf.Controller( + simpleActions={ + @Jpf.SimpleAction(name="someAction", path="somePage.jsp") + } +) +

    + In the above example, the action someAction will navigate to + somePage.jsp when it is invoked. As you can imagine, this simple + form of the annotation is useful when an action only needs to navigate + somewhere, without running complex logic. +

    +

    + The @Jpf.SimpleAction annotation also has a more powerful form that + lets you define conditions that cause navigation do different places. + The conditions are defined using JSP 2.0-style expressions. Consider the + following annotation: +

    + +@Jpf.SimpleAction( + name="someAction", + path="default.jsp", + conditionalForwards={ + @Jpf.ConditionalForward(condition="${pageFlow.advancedMode}", path="advanced.jsp"), + @Jpf.ConditionalForward(condition="${param.alternate=='yes'}", path="alternate.jsp") + } +) +

    + Here, if the page flow's advancedMode property is + true (i.e., it has a public method getAdvancedMode + which returns true), then someAction will navigate to + advanced.jsp. If there is a request URL parameter "alternate" set + to "yes", then alternate.jsp will be the destination. Finally, if + neither of these conditions is true, then the default destination + default.jsp is used. +

    +

    + For a list of implicit objects available for these expressions, see + + JSP Implicit Objects + + and + NetUI Implicit Objects. + Note that page-related implicit objects pageContext, + pageScope, and pageInput are not available here. +

    +
    +
    + Creating an action through a method +

    + To create an action through a method, you make a method that returns + + Forward + + and which is annotated with + + @Jpf.Action + , e.g., +

    + +@Jpf.Action( + forwards={ + @Jpf.Forward(name="somePage", path="somePage.jsp") + } +) +public Forward someAction() +{ + return new Forward("somePage"); +} +

    + This action someAction forwards to somePage.jsp. The method has access to + any member state in the controller class, and it can of course perform any other logic it needs to + perform. +

    + + You do not have to return a + + Forward + + object. If your action returns null, then no navigation will occur. + As an example, the following action method writes out "hello" to the response + without navigating to another page: +
    +
    +     @Jpf.Action
    +     public Forward writeResponse()
    +     {
    +         getResponse().getWriter().print("hello");
    +         return null;
    +     } +
    +

    + To create an action that accepts a form bean, simply add a single form + bean argument: +

    + +@Jpf.Action( + forwards={ + @Jpf.Forward(name="somePage", path="somePage.jsp") + } +) +public Forward submitForm(MyFormBean bean) +{ + // perform logic that uses the form bean + return new Forward("somePage"); +} +

    + Here, MyFormBean is just any JavaBean class; there are no particular + requirements on it. For information on how to post data to a form bean from a JSP, + see NetUI JSP Overview. +

    +
    +
    +
    + Raising Actions +

    + You can raise actions through NetUI JSP tags, through components/command-handlers in + JavaServer Faces pages, from other actions in the same page flow, or, in + general, through URLs. +

    +
    + Raising actions through NetUI JSP tags +

    + The following tags all support the action attribute: +

    + +

    + In general, you set the action attribute to the desired action, which will be raised + when you click the link, submit the form, etc. +

    + +<netui:anchor action="someAction">Click me to run someAction<netui:anchor> +
    +
    + Raising actions from JavaServer Faces components/command-handlers +

    + If you have NetUI/JSF integration enabled according to instructions + here, you can simply raise actions using the action + attribute on JSF command* components, e.g., +

    + +<h:commandLink action="someAction" value="Raise action someAction"/> +

    + You can even raise a Page Flow action from a command handler. Say you + have a JSF commandLink component that binds to method myCommandHandler + in the page's backing bean: +

    + +<h:commandLink action="#{backing.myCommandHandler}" value="Raise an action"/> +

    + Now, your command handler method can choose which Page Flow action to raise: +

    + +private SearchForm searchForm = ...; + +@Jpf.CommandHandler( + raiseActions = { + @Jpf.RaiseAction(action="actionOne"), + @Jpf.RaiseAction(action="actionTwo", outputFormBean="searchForm") + } +) +public String myCommandHandler() +{ + if (...) + return "actionOne"; + else + return "actionTwo"; +} +

    + For more information on NetUI/JSF integration, see the documentation + and the sample. +

    +
    +
    + Raising actions from other actions +

    + To raise an action from another action in the same controller class ("action chaining"), + simply use the action attribute on a + + @Jpf.Forward + + or a + + @Jpf.SimpleAction + + annotation, e.g., +

    + +@Jpf.Forward(name="toAnotherAction", action="anotherAction") +

    + or, +

    + +@Jpf.SimleAction(name="chain", action="anotherAction") +
    +
    + Raising actions through URLs +

    + In general, you can raise an action through a URL of the following pattern: +

    + +http://myserver/mywebapp/page-flow-directory/action-name.do +

    + For example, if your page flow is in directory /foo/bar within the webapp, an action + URL for someAction would look like this: +

    + +http://myserver/mywebapp/foo/bar/someAction.do +

    + Of course, if your browser URL bar is already on a page in /foo/bar, then an action + URL for someAction would simply be: +

    + +someAction.do +
    +
    + +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/alteringPageFlow.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/alteringPageFlow.xml new file mode 100644 index 0000000..5a9fdda --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/alteringPageFlow.xml @@ -0,0 +1,205 @@ + + + +
    + Altering a Page Flow +
    + + +
    + Introduction + +

    + In the previous pages, you were shown how to stitch together a controller class + and a set of JSPs. One of the most powerful features of the Beehive way + of building applications is being able to change the flow by editing only the + controller class file, without having to touch the JSPs. +

    + +
    + +
    + Logical Flow Change + +

    + Sometime after deploying the application, it is decided that before allowing a + user to login, they must first be presented a page describing the terms of + service for using the application. Additionally, a decision is made to remove the + thanks.jsp file and have + the "Sign Up" action automatically log-in the new user so they don't have + to traverse the login screen. In short, after (successfully) completing signup.jsp, the user + is taken directly to mypage.jsp. +

    + +

    + The original logical flow looked like this: +

    + +

    + logical flow, before alteration +

    + +

    + After these changes, the logical flow now resembles: +

    + +

    + logical flow, after alteration +

    + +
    + +
    + Implementation Flow Change + +

    + To accommodate the new logical flow, the implementation flow model originally looked like this: +

    + +

    + logical flow, after alteration +

    + +

    + After removing thanks.jsp, adding terms.jsp, adding an + acceptTerms() method, and re-routing the post-signup flow, looks like: +

    + +

    + logical flow, after alteration +

    + +
    + +
    + Changes Required in the JSPs + +

    + Strictly speaking, no changes to JSP content are required. Only deletion of the + unused thanks.jsp and creation of the terms.jsp is + all that is required. +

    + +

    + Note:, The signup.jsp page + that previously would direct a user to thanks.jsp but will now + send him to mypage.jsp requires absolutely no changes. +

    + +

    + The terms.jsp page would include a link through a new acceptTerms() + controller method, similar to: +

    + + <netui:anchor action="acceptTerms">Accept these Terms of Service</netui:anchor> + + +
    + +
    + Changes Required in the Controller Class + +

    + To change the flow, a few simple edits of the controller class are all that is required. +

    + +
    + Redirect <code>login()</code> + +

    + Previously, the login() controller method was defined to statically + return the forward to login.jsp. +

    + + + @Jpf.Action( + forwards={ + @Jpf.Forward(name="success", path="login.jsp") + } + ) + public Forward login() + { + return new Forward( "success" ); + } + + +

    + By changing the path property of the Jpf.Forward associated + with this page, all links that previously took the user to login.jsp will + now direct him to terms.jsp. +

    + + + @Jpf.Action( + forwards={ + @Jpf.Forward(name="success", path="terms.jsp") + } + ) + public Forward login() + { + return new Forward( "success" ); + } + + +

    + The terms.jsp page links through a new acceptTerms() + controller method which simply is a static forward to login.jsp. +

    + + + @Jpf.Action( + forwards={ + @Jpf.Forward(name="success", path="login.jsp") + } + ) + public Forward acceptTerms() + { + return new Forward( "success" ); + } + + +

    + This biggest change in the controller class is in the processSignUp() + controller method. Instead of just recording the user's information, it now must + also perform the logic of logging in the user automatically. Additionally, the + forward returned by it will send the user directly to mypage.jsp + instead of the now unused thanks.jsp page. +

    + + + @Jpf.Action( + forwards={ + @Jpf.Forward(name="success", path="mypage.jsp") + } + ) + public Forward processSignUp(SignUpForm form) + { + // record the user's sign-up information. + ... + + // perform automatic login for the user. + getSession().setAttribute( "authenticated_user", form.getUsername() ); + return new Forward( "success" ); + } + + +

    + The flow has successfully be altered to now include a jump through the site's + terms-of-service and automatically logging-in newly signed-up users. +

    + +
    + +
    + + + + + +
    + + Java, J2EE, and JCP are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.
    + © 2004, Apache Software Foundation +
    +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/annotations/pageflow_annotations.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/annotations/pageflow_annotations.xml new file mode 100644 index 0000000..5eb9529 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/annotations/pageflow_annotations.xml @@ -0,0 +1,2372 @@ + + + +
    + Page Flow Annotations +
    + +
    + Description +

    + These annotations configure elements of a NetUI web application: page flows, shared flows, etc. + All Page Flow annotations come from the annotation interface + + org.apache.beehive.netui.pageflow.annotations.Jpf + . To use any of these annotations, include the following import statement in your source file: +

    + import org.apache.beehive.netui.pageflow.annotations.Jpf +
    + +
    + Page Flow Annotations +

    @Jpf.Action

    +

    @Jpf.ActionOutput

    +

    @Jpf.Catch

    +

    @Jpf.CommandHandler

    +

    @Jpf.ConditionalForward

    +

    @Jpf.Controller

    +

    @Jpf.ExceptionHandler

    +

    @Jpf.FacesBacking

    +

    @Jpf.FormBean

    +

    @Jpf.Forward

    +

    @Jpf.MessageArg

    +

    @Jpf.MessageBundle

    +

    @Jpf.MultipartHandler

    +

    @Jpf.NavigateTo

    +

    @Jpf.PageFlowField

    +

    @Jpf.RaiseAction

    +

    @Jpf.SharedFlowField

    +

    @Jpf.SharedFlowRef

    +

    @Jpf.SimpleAction

    +

    @Jpf.ValidatableBean

    +

    @Jpf.ValidatableProperty

    +

    @Jpf.ValidateCreditCard

    +

    @Jpf.ValidateCustomRule

    +

    @Jpf.ValidateCustomVariable

    +

    @Jpf.ValidateDate

    +

    @Jpf.ValidateEmail

    +

    @Jpf.ValidateMask

    +

    @Jpf.ValidateMaxLength

    +

    @Jpf.ValidateMinLength

    +

    @Jpf.ValidateRange

    +

    @Jpf.ValidateRequired

    +

    @Jpf.ValidateType

    +

    @Jpf.ValidateValidWhen

    +

    @Jpf.ValidationLocaleRules

    +

    @Jpf.ValidatorVersion

    +

    @Jpf.ViewProperties

    +
    + + +
    + Java, J2EE, and JCP are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.
    + © 2004, Apache Software Foundation +
    +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/annotations/pageflow_class_annotations.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/annotations/pageflow_class_annotations.xml new file mode 100644 index 0000000..c9019c0 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/annotations/pageflow_class_annotations.xml @@ -0,0 +1,249 @@ + + + +
    + Page Flow Class Annotations +
    + +
    + Table of Contents + +
    +
    + + <code>Jpf.Controller</code> + + +

    Jpf.Controller is the annotation used to both + mark a class as a page-flow controller and may + additionally contain other annotations which + participate in the configuration.

    +

    When used simply as a marker, it must simply be placed directly + in front of the class definition.

    + @Jpf.Controller public class Controller + extends PageFlowController { ... ... } +

    The Jpf.Controller annotation also has several + configuration properties.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    PropertyTypeDescription
    + loginRequired + + boolean + Checks user authentication and possibly throws NotLoggedInException
    + readOnly + + boolean + Flag to indicate this action does not modify state
    + rolesAllowed + + String[] + List of roles allowed to invoke this action. Implies + loginRequired=true.
    + nested + + boolean + Flag the pageflow as nested
    + singleton + + boolean + Flag the pageflow as singleton
    + @Jpf.Controller { rolesAllowed = { "admin" }; + nested = true; } public class AddNewUserController { + ... } +

    The above controller, notably not named + Controller, is a nested pageflow that requires the + admin role to be invoked.

    +
    + Jpf.Controller with Jpf.SimpleAction + +

    In addition to being a marker, simple configuration can + occur using the Jpf.SimpleAction annotation. +

    + +@Jpf.Controller { + simpleActions = { + @Jpf.SimpleAction( name="mypage", path="mypage.jsp" ), + @Jpf.SimpleAction( name="terms", path="terms.jsp" ) + } +} +public class Controller + extends PageFlowController +{ + ... + ... +} + +

    The combination of Jpf.Controller and + Jpf.SimpleAction operates as short-hand for + the more verbose equivelent class using + Jpf.Controller as a marker with explicitly + defined controller methods with + Jpf.Action and Jpf.Forward.

    + +@Jpf.Controller +public class Controller + extends PageFlowController +{ + @Jpf.Action { + forwards = { + @Jpf.Forward( name="success", path="mypage.jsp" ); + } + } + public Forward mypage() + { + return new Forward( "success" ); + } + + @Jpf.Action { + forwards = { + @Jpf.Forward( name="success", path="terms.jsp" ); + } + } + public Forward terms() + { + return new Forward( "success" ); + } +} + +
    +
    + Jpf.Controller with Jpf.Forward + +

    Global named forwards can be defined within the + Controller class annotations.

    + +@Jpf.Controller { + forwards = { + @Jpf.Forward( name="error", path="/error.jsp" ) + } +} +public class Controller +{ + public Forward doSomething() + { + ... + if ( error ) + { + return new Forward( "error" ); + } + } +} + +
    +
    + Jpf.Controller with Jpf.Catch and + Jpf.ExceptionHandler + +

    Global exception-handlers can be configured within the + Controller class annotations.

    + +@Jpf.Controller { + catches = { + @Jpf.Catch { type=com.myco.FailedLoginException.class, method="failedLoginHandler" } + } +} +public class Controller +{ + @Jpf.ExceptionHandler { + forwards = { + @Jpf.Forward { name="try_again", path="/try_again.jps" } + } + } + protected Forward failedLoginHandler(FailedLoginException e, + String actionName, + String message, + LoginForm form) + { + ... + return new Forward( "try_again" ); + } +} + +
    +
    + +
    + + Java, J2EE, and JCP are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.
    + © 2004, Apache Software Foundation +
    +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/annotations/pageflow_method_annotations.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/annotations/pageflow_method_annotations.xml new file mode 100644 index 0000000..bbea89d --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/annotations/pageflow_method_annotations.xml @@ -0,0 +1,172 @@ + + + +
    + Page Flow Annotations +
    + + +
    + Table of Contents + +
    + +
    + Jpf.Action + + + +

    + The + + @Jpf.Action + + annotation adorns action methods of the Controller + class. It serves as a container for further configuration annotations and properties. +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    PropertyTypeDescription
    loginRequiredbooleanChecks user authentication and possibly throws NotLoggedInException
    readOnlybooleanFlag to indicate this action does not modify state
    rolesAllowedString[]List of roles allowed to invoke this action. Implies loginRequired=true.
    useFormBeanStringName of a member to use as multi-page form
    + +

    + In this example, the collectBasicUserInformation action is called + on one page of a multi-page form flow. For each form page submitted, the same + NewUserForm is used, to allow for collection of data across several + pages into a single usable form. The data is stored in the NewUserForm + member variable named newUserForm. +

    + +

    + The rolesAllowed property specifies that only users with the admin + role can invoke this action. +

    + + +@Jpf.Controller +public class Controller +{ + private NewUserForm newUserForm; + + @Jpf.Action { + rolesAllowed = { "admin" }, + useFormBean = "newUserForm"; + } + public Forward collectBasicUserInformation(NewUserForm form) + { + .. + } +} + + +
    + Jpf.Action with Jpf.Forward + + + + +@Jpf.Controller +public class Controller +{ + @Jpf.Action { + forwards = { + @Jpf.Forward{ name="success", path="/mypage.jsp" } + } + } + public Forward login(LoginForm form) + { + ... + return new Forward( "success" ); + } +} + + +
    + +
    + Jpf.Action with Jpf.Catch and Jpf.ExceptionHandler + + + + +@Jpf.Controller +public class Controller +{ + @Jpf.Action { + catches = { + type=com.myco.FailedLoginException.class, method="failedLoginHandler" + } + } + public Forward login(LoginForm form) + throws FailedLoginException + { + ... + } + + @Jpf.ExceptionHandler { + forwards = @Jpf.Forward( name="try_again", path="/try_again.jps" } + } + protected Forward failedLoginHandler(FailedLoginException e, + String actionName, + String message, + LoginForm form) + { + ... + return new Forward( "try_again" ); + } +} + + + +
    + +
    + + + + +
    + + Java, J2EE, and JCP are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.
    + © 2004, Apache Software Foundation +
    +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/annotations/pageflow_validation_annotations.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/annotations/pageflow_validation_annotations.xml new file mode 100644 index 0000000..cfdc16b --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/annotations/pageflow_validation_annotations.xml @@ -0,0 +1,2204 @@ + + + +
    + Page Flow Validation Annotations +
    + +
    + Jpf.ValidatableBean +

    + Javadoc: + + Jpf.ValidatableBean +

    +

    + Description +

    +

    The @Jpf.ValidatableBean annotation is an attribute of the @Jpf.Controller + annotation. It refers to a JavaBean class that is to be subject to validation.

    +

    + Attributes +

    + + + + + + + + + + + + + + + + +
    AttributeTypeDescription
    + type + + Class + Required. The type of the JavaBean decorated by this + annotation.
    + validatableProperties + + + @Jpf.ValidatableProperty[] + + Required. Comma-separated list of @Jpf.ValidatableProperty + elements.
    +

    Example

    +

    In this example, three bean properties are validated: three Strings representing the date, + a credit card, and an email address.

    + @Jpf.Controller( + validatableBeans={ + @Jpf.ValidatableBean( + type=Controller.MyForm.class, + validatableProperties={ + @Jpf.ValidatableProperty( + propertyName="date", + displayName="This field", + validateRequired=@Jpf.ValidateRequired(), + validateDate=@Jpf.ValidateDate(pattern="M-d-y") + ), + @Jpf.ValidatableProperty( + propertyName="creditCard", + displayName="This field", + validateRequired=@Jpf.ValidateRequired(), + validateCreditCard=@Jpf.ValidateCreditCard() + ), + @Jpf.ValidatableProperty( + propertyName="email", + displayName="This field", + validateRequired=@Jpf.ValidateRequired(), + validateEmail=@Jpf.ValidateEmail() + ) + } + ) + } +) +public class Controller extends PageFlowController +{ + ... + + public static class MyForm implements Serializable + { + private String _date; + + public String getDate() + { + return _date; + } + + public void setDate( String str ) + { + _date = str; + } + + private String _creditCard; + + public String getCreditCard() + { + return _creditCard; + } + + public void setCreditCard( String str ) + { + _creditCard = str; + } + + private String _email; + + public String getEmail() + { + return _email; + } + + public void setEmail( String str ) + { + _email = str; + } + } +} +
    +
    + Jpf.ValidatableProperty +

    + Javadoc: + + Jpf.ValidatableProperty +

    +

    + Description +

    +

    The @Jpf.ValidatableProperty annotation is an attribute of the @Jpf.Controller or + @Jpf.Action annotations, or it can decorate a method in a form bean. It refers to a form field (or bean property) + that is to be subject to validation.

    +

    + Attributes +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AttributeTypeDescription
    + displayName + + String + [todo]
    + displayNameKey + + String + [todo]
    + localeRules + + @Jpf.ValidationLocaleRules[] + A comma-separated list of @Jpf.ValidationLocaleRules annotations.
    + propertyName + + String + [todo]
    + validateCreditCard + + @Jpf.ValidateCreditCard + A @Jpf.ValidateCreditCard annotation.
    + validateCustom + + @Jpf.ValidateCustom + A @Jpf.ValidateCustom annotation.
    + validateDate + + @Jpf.ValidateDate + A @Jpf.ValidateDate annotation.
    + validateEmail + + @Jpf.ValidateEmail + A @Jpf.ValidateEmail annotation.
    + validateMask + + @Jpf.ValidateMask + A @Jpf.ValidateMask annotation.
    + validateMaxLength + + @Jpf.ValidateMaxLength + A @Jpf.ValidateMaxLength annotation.
    + validateMinLength + + @Jpf.ValidateMinLength + A @Jpf.ValidateMinLength annotation.
    + validateRange + + @Jpf.ValidateRange + A @Jpf.ValidateRange annotation.
    + validateRequired + + @Jpf.ValidateRequired + A @Jpf.ValidateRequired annotation.
    + validateType + + @Jpf.ValidateType + A @Jpf.ValidateType annotation.
    + validateValidWhen + + @Jpf.ValidateValidWhen + A @Jpf.ValidateValidWhen annotation.
    +

    Example

    +

    In this example, a date String is validated.

    + @Jpf.Controller( + validatableBeans={ + @Jpf.ValidatableBean( + type=Controller.MyForm.class, + validatableProperties={ + @Jpf.ValidatableProperty( + propertyName="date", + displayName="This field", + validateRequired=@Jpf.ValidateRequired(), + validateDate=@Jpf.ValidateDate(pattern="M-d-y") + ) + } + ) + } +) +public class Controller extends PageFlowController +{ + ... + + public static class MyForm implements Serializable + { + private String _date; + + public String getDate() + { + return _date; + } + } +} +
    +
    + Jpf.ValidateCreditCard +

    + Javadoc: + + Jpf.ValidateCreditCard +

    +

    + Description +

    +

    The @Jpf.ValidateCreditCard annotation... [todo].

    +

    + Attributes +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AttributeTypeDescription
    + arg0 + + String + [todo]
    + arg0Key + + String + [todo]
    + arg1 + + String + [todo]
    + arg1Key + + String + [todo]
    + arg2 + + String + [todo]
    + arg2Key + + String + [todo]
    + arg3 + + String + [todo]
    + arg3Key + + String + [todo]
    + enabled + + boolean + [todo]
    + message + + String + [todo]
    + messageKey + + String + [todo]
    + variables + + @Jpf.ValidateCustomVariable[] + A comma-separated list of @Jpf.ValidateCustomVariable annotations.
    +

    Example

    + public static class ValidatedForm implements Serializable + { + private String _creditCard; + + @Jpf.ValidatableProperty( + displayName="This field", + validateRequired=@Jpf.ValidateRequired(), + validateCreditCard=@Jpf.ValidateCreditCard() + ) + public String getCreditCard() + { + return _creditCard; + } + + public void setCreditCard( String str ) + { + _creditCard = str; + } + } + +
    +
    + Jpf.ValidateCustom +

    + Javadoc: + + Jpf.ValidateCustom +

    +

    + Description +

    +

    The @Jpf.ValidateCustom annotation... [todo].

    +

    + Attributes +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AttributeTypeDescription
    + rule + + String + Required. [todo]
    + arg0 + + String + [todo]
    + arg0Key + + String + [todo]
    + arg1 + + String + [todo]
    + arg1Key + + String + [todo]
    + arg2 + + String + [todo]
    + arg2Key + + String + [todo]
    + arg3 + + String + [todo]
    + arg3Key + + String + [todo]
    + enabled + + boolean + [todo]
    + message + + String + [todo]
    + messageKey + + String + [todo]
    + variables + + @Jpf.ValidateCustomVariable[] + A comma-separated list of @Jpf.ValidateCustomVariable annotations.
    +

    Example

    + + [todo] + +
    +
    + Jpf.ValidateCustomVariable +

    + Javadoc: + + Jpf.ValidateCustomVariable +

    +

    + Description +

    +

    The @Jpf.ValidateCustomVariable annotation... [todo].

    +

    + Attributes +

    + + + + + + + + + + + + + + + + +
    AttributeTypeDescription
    + name + + String + Required. [todo]
    + value + + String + Required. [todo]
    +

    Example

    + + [todo] + +
    + +
    + Jpf.ValidateDate +

    + Javadoc: + + Jpf.ValidateDate +

    +

    + Description +

    +

    The @Jpf.ValidateDate annotation... [todo].

    +

    + Attributes +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AttributeTypeDescription
    + pattern + + String + Required. [todo]
    + arg0 + + String + [todo]
    + arg0Key + + String + [todo]
    + arg1 + + String + [todo]
    + arg1Key + + String + [todo]
    + arg2 + + String + [todo]
    + arg2Key + + String + [todo]
    + arg3 + + String + [todo]
    + arg3Key + + String + [todo]
    + enabled + + boolean + [todo]
    + message + + String + [todo]
    + messageKey + + String + [todo]
    + strict + + boolean + [todo]
    +

    Example

    + public static class ValidatedForm implements Serializable + { + private String _date; + + @Jpf.ValidatableProperty( + displayName="This field", + validateRequired=@Jpf.ValidateRequired(), + validateDate=@Jpf.ValidateDate(pattern="M-d-y") + ) + public String getDate() + { + return _date; + } + + public void setDate( String str ) + { + _date = str; + } + } +
    +
    + Jpf.ValidateEmail +

    + Javadoc: + + Jpf.ValidateEmail +

    +

    + Description +

    +

    The @Jpf.ValidateEmail annotation... [todo].

    +

    + Attributes +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AttributeTypeDescription
    + arg0 + + String + [todo]
    + arg0Key + + String + [todo]
    + arg1 + + String + [todo]
    + arg1Key + + String + [todo]
    + arg2 + + String + [todo]
    + arg2Key + + String + [todo]
    + arg3 + + String + [todo]
    + arg3Key + + String + [todo]
    + enabled + + boolean + [todo]
    + message + + String + [todo]
    + messageKey + + String + [todo]
    +

    Example

    + public static class ValidatedForm implements Serializable + { + private String _email; + + @Jpf.ValidatableProperty( + displayName="This field", + validateRequired=@Jpf.ValidateRequired(), + validateEmail=@Jpf.ValidateEmail() + ) + public String getEmail() + { + return _email; + } + + public void setEmail( String str ) + { + _email = str; + } + } + +
    +
    + Jpf.ValidateMask +

    + Javadoc: + + Jpf.ValidateMask +

    +

    + Description +

    +

    The @Jpf.ValidateMask annotation... [todo].

    +

    + Attributes +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AttributeTypeDescription
    + regex + + String + Required. [todo]
    + arg0 + + String + [todo]
    + arg0Key + + String + [todo]
    + arg1 + + String + [todo]
    + arg1Key + + String + [todo]
    + arg2 + + String + [todo]
    + arg2Key + + String + [todo]
    + arg3 + + String + [todo]
    + arg3Key + + String + [todo]
    + enabled + + boolean + [todo]
    + message + + String + [todo]
    + messageKey + + String + [todo]
    +

    Example

    + public static class ValidatedForm implements Serializable + { + private String _mask; + + @Jpf.ValidatableProperty( + displayName="This field", + validateRequired=@Jpf.ValidateRequired(), + validateMask=@Jpf.ValidateMask(regex="a*b") + ) + public String getMask() + { + return _mask; + } + + public void setMask( String str ) + { + _mask = str; + } + } +
    +
    + Jpf.ValidateMaxLength +

    + Javadoc: + + Jpf.ValidateMaxLength +

    +

    + Description +

    +

    The @Jpf.ValidateMaxLength annotation... [todo].

    +

    + Attributes +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AttributeTypeDescription
    + chars + + int + Required. [todo]
    + arg0 + + String + [todo]
    + arg0Key + + String + [todo]
    + arg1 + + String + [todo]
    + arg1Key + + String + [todo]
    + arg2 + + String + [todo]
    + arg2Key + + String + [todo]
    + arg3 + + String + [todo]
    + arg3Key + + String + [todo]
    + enabled + + boolean + [todo]
    + message + + String + [todo]
    + messageKey + + String + [todo]
    +

    Example

    + public static class ValidatedForm implements Serializable + { + private String _maxLength; + + @Jpf.ValidatableProperty( + displayName="This field", + validateRequired=@Jpf.ValidateRequired(), + validateMaxLength=@Jpf.ValidateMaxLength(chars=2) + ) + public String getMaxLength() + { + return _maxLength; + } + + public void setMaxLength( String str ) + { + _maxLength = str; + } + } +
    +
    + Jpf.ValidateMinLength +

    + Javadoc: + + Jpf.ValidateMinLength +

    +

    + Description +

    +

    The @Jpf.ValidateMinLength annotation... [todo].

    +

    + Attributes +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AttributeTypeDescription
    + chars + + int + Required. [todo]
    + arg0 + + String + [todo]
    + arg0Key + + String + [todo]
    + arg1 + + String + [todo]
    + arg1Key + + String + [todo]
    + arg2 + + String + [todo]
    + arg2Key + + String + [todo]
    + arg3 + + String + [todo]
    + arg3Key + + String + [todo]
    + enabled + + boolean + [todo]
    + message + + String + [todo]
    + messageKey + + String + [todo]
    +

    Example

    + public static class ValidatedForm implements Serializable + { + private String _minLength; + + @Jpf.ValidatableProperty( + displayName="This field", + validateRequired=@Jpf.ValidateRequired(), + ValidateMinLength=@Jpf.ValidateMinLength(chars=2) + ) + public String getMinLength() + { + return _minLength; + } + + public void setMinLength( String str ) + { + _minLength = str; + } + } +
    +
    + Jpf.ValidateRange +

    + Javadoc: + + Jpf.ValidateRange +

    +

    + Description +

    +

    The @Jpf.ValidateRange annotation... [todo].

    +

    + Attributes +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AttributeTypeDescription
    + arg0 + + String + [todo]
    + arg0Key + + String + [todo]
    + arg1 + + String + [todo]
    + arg1Key + + String + [todo]
    + arg2 + + String + [todo]
    + arg2Key + + String + [todo]
    + arg3 + + String + [todo]
    + arg3Key + + String + [todo]
    + enabled + + boolean + [todo]
    + maxFloat + + double + [todo]
    + maxInt + + int + [todo]
    + message + + String + [todo]
    + messageKey + + String + [todo]
    + minFloat + + double + [todo]
    + minInt + + int + [todo]
    +

    Example

    + public static class ValidatedForm implements Serializable + { + private String _range; + + @Jpf.ValidatableProperty( + displayName="This field", + validateRequired=@Jpf.ValidateRequired(), + validateRange=@Jpf.ValidateRange(minInt=1, maxInt=10) + ) + public String getRange() + { + return _range; + } + + public void setRange( String str ) + { + _range = str; + } + } +
    +
    + Jpf.ValidateRequired +

    + Javadoc: + + Jpf.ValidateRequired +

    +

    + Description +

    +

    The @Jpf.ValidateRequired annotation... [todo].

    +

    + Attributes +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AttributeTypeDescription
    + arg0 + + String + [todo]
    + arg0Key + + String + [todo]
    + arg1 + + String + [todo]
    + arg1Key + + String + [todo]
    + arg2 + + String + [todo]
    + arg2Key + + String + [todo]
    + arg3 + + String + [todo]
    + arg3Key + + String + [todo]
    + enabled + + boolean + [todo]
    + message + + String + [todo]
    + messageKey + + String + [todo]
    +

    Example

    + public static class ValidatedForm implements Serializable + { + private String _range; + + @Jpf.ValidatableProperty( + displayName="This field", + validateRequired=@Jpf.ValidateRequired(), + validateRange=@Jpf.ValidateRange(minInt=1, maxInt=10) + ) + public String getRange() + { + return _range; + } + + public void setRange( String str ) + { + _range = str; + } + } +
    +
    + Jpf.ValidateType +

    + Javadoc: + + Jpf.ValidateType +

    +

    + Description +

    +

    The @Jpf.ValidateType annotation... [todo].

    +

    + Attributes +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AttributeTypeDescription
    + type + + Class + Required. [todo]
    + arg0 + + String + [todo]
    + arg0Key + + String + [todo]
    + arg1 + + String + [todo]
    + arg1Key + + String + [todo]
    + arg2 + + String + [todo]
    + arg2Key + + String + [todo]
    + arg3 + + String + [todo]
    + arg3Key + + String + [todo]
    + enabled + + boolean + [todo]
    + message + + String + [todo]
    + messageKey + + String + [todo]
    +

    Example

    + public static class ValidatedForm implements Serializable + { + private String _typeInt; + + @Jpf.ValidatableProperty( + displayName="This field", + validateRequired=@Jpf.ValidateRequired(), + validateType=@Jpf.ValidateType(type=int.class) + ) + public String getTypeInt() + { + return _typeInt; + } + + public void setTypeInt( String str ) + { + _typeInt = str; + } + } +
    +
    + Jpf.ValidateValidWhen +

    + Javadoc: + + Jpf.ValidateValidWhen +

    +

    + Description +

    +

    The @Jpf.ValidateValidWhen annotation... [todo].

    +

    + Attributes +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AttributeTypeDescription
    + condtion + + String + Required. [todo]
    + arg0 + + String + [todo]
    + arg0Key + + String + [todo]
    + arg1 + + String + [todo]
    + arg1Key + + String + [todo]
    + arg2 + + String + [todo]
    + arg2Key + + String + [todo]
    + arg3 + + String + [todo]
    + arg3Key + + String + [todo]
    + enabled + + boolean + [todo]
    + message + + String + [todo]
    + messageKey + + String + [todo]
    +

    Example

    + public static class ValidatedForm implements Serializable + { + private String _validWhenPageFlowProp; + + @Jpf.ValidatableProperty( + displayName="This field", + validateRequired=@Jpf.ValidateRequired(), + validateValidWhen=@Jpf.ValidateValidWhen(condition="${pageFlow.str==actionForm.validWhenPageFlowProp}", message="pageFlow.str must be the same as this") + ) + public String getValidWhenPageFlowProp() + { + return _validWhenPageFlowProp; + } + + public void setValidWhenPageFlowProp( String str ) + { + _validWhenPageFlowProp = str; + } + } +
    +
    + Jpf.ValidationLocaleRules +

    + Javadoc: + + Jpf.ValidationLocaleRules +

    +

    + Description +

    +

    The @Jpf.ValidationLocaleRules annotation... [todo].

    +

    + Attributes +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AttributeTypeDescription
    + applyToUnhandledLocales + + boolean + [todo]
    + country + + String + [todo]
    + language + + String + [todo]
    + validateCreditCard + + @Jpf.ValidateCreditCard + A @Jpf.ValidateCreditCard annotation.
    + validateCustom + + @Jpf.ValidateCustom + A @Jpf.ValidateCustom annotation.
    + validateDate + + @Jpf.ValidateDate + A @Jpf.ValidateDate annotation.
    + validateEmail + + @Jpf.ValidateEmail + A @Jpf.ValidateEmail annotation.
    + validateMask + + @Jpf.ValidateMask + A @Jpf.ValidateMask annotation.
    + validateMaxLength + + @Jpf.ValidateMaxLength + A @Jpf.ValidateMaxLength annotation.
    + validateMinLength + + @Jpf.ValidateMinLength + A @Jpf.ValidateMinLength annotation.
    + validateRange + + @Jpf.ValidateRange + A @Jpf.ValidateRange annotation.
    + validateRequired + + @Jpf.ValidateRequired + A @Jpf.ValidateRequired annotation.
    + validateType + + @Jpf.ValidateType + A @Jpf.ValidateType annotation.
    + validateValidWhen + + @Jpf.ValidateValidWhen + A @Jpf.ValidateValidWhen annotation.
    + variant + + String + [todo]
    +

    Example

    + [todo] +
    + +
    + Java, J2EE, and JCP are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.
    + © 2004, Apache Software Foundation +
    +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/config/beehive-netui-config.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/config/beehive-netui-config.xml new file mode 100644 index 0000000..7edfa77 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/config/beehive-netui-config.xml @@ -0,0 +1,1303 @@ + + + +
    + Reference Documentation: beehive-netui-config.xml File +
    + +
    + Description +

    + The beehive-netui-config.xml file configures the runtime behavior of your + NetUI web application. It lives under the WEB-INF directory. +

    +

    + Use beehive-netui-config.xml to declare interceptor classes, override the + default handler classes, etc. +

    + + Currently, when you want to add your own settings, you cannot + simply create the beehive-netui-config.xml file in WEB-INF. You need to + create a file that includes the default settings. See + Default Settings. + +
    +
    + Default Settings +

    + To start with a file that includes the default settings, use + this version. +

    +
    +
    + General Structure +<netui-config> + <expression-languages> + <default-language> + <expression-language> + <name> + <factory-class> + <binding-contexts> + <binding-context> + <name> + <factory-class> + <pageflow-action-interceptors> + <global> + <simple-action-interceptor> + <intercept-path> + <after-action> + <action-interceptor> + <interceptor-class> + <custom-property> + <name> + <value> + <per-pageflow> + <pageflow-uri> + <simple-action-interceptor> + <intercept-path> + <after-action> + <action-interceptor> + <interceptor-class> + <custom-property> + <per-action> + <action-name> + <simple-action-interceptor> + <intercept-path> + <after-action> + <action-interceptor> + <interceptor-class> + <custom-property> + <pageflow-handlers> + <action-forward-handler> + <handler-class> + <custom-property> + <exceptions-handler> + <handler-class> + <custom-property> + <forward-redirect-handler> + <handler-class> + <custom-property> + <login-handler> + <handler-class> + <custom-property> + <reloadable-class-handler> + <handler-class> + <custom-property> + <pageflow-config> + <enable-self-nesting> + <max-forwards-per-request> + <max-nesting-stack-depth> + <ensure-secure-forwards> + <throw-session-expired-exception> + <multipart-handler> + <prevent-cache> + <module-config-locators> + <module-config-locator> + <description> + <locator-class> + <pageflow-factories> + <flowcontroller-factory> + <factory-class> + <custom-property> + <faces-backing-bean-factory> + <factory-class> + <custom-property> + <default-shared-flow-refs> + <shared-flow-ref> + <name> + <type> + <type-converters> + <type-converter> + <type> + <converter-class> + <jsp-tag-config> + <doctype> + <id-javascript> + <tree-image-location> + <tree-renderer-class> + <url-config> + <url-encode-urls> + <html-amp-entity> + <templated-url-formatter-class> + <iterator-factories> + <iterator-factory> + <name> + <factory-class> + <request-interceptors> + <global> + <request-interceptor> + <interceptor-class> + <custom-property> + <prefix-handlers> + <prefix-handler> + <name> + <handler-class> +
    +
    + Elements + +
    <action-forward-handler> +

    Syntax

    + <action-forward-handler> + <handler-class> xsd:string </handler-class> [occurrences: 1] + <custom-property> + <name> xsd:string </name> [occurrences: 1] + <value> xsd:string </value> [occurrences: 1] + </custom-property> [occurrences: 0-*] +</action-forward-handler> +

    Parents:

    +

    <pageflow-handlers>

    +

    Children:

    +

    <handler-class>, + <custom-property>

    + +
    <action-interceptor> +

    Syntax

    + <action-interceptor> + <interceptor-class> xsd:string </interceptor-class> [occurrences: 1] + <custom-property> + <name> xsd:string </name> [occurrences: 1] + <value> xsd:string </value> [occurrences: 1] + </custom-property> [occurrences: 0-*] +</action-interceptor> +

    Parents:

    +

    <global>, + <per-pageflow>, + <per-action>

    +

    Children:

    +

    + <interceptor-class>, + <custom-property>

    +
    +
    <action-name> +

    Syntax

    + <action-name> xsd:string <action-name> [occurrences: 1] +

    Parents:

    +

    <per-action>

    +

    Children:

    +

    none

    +
    <after-action> +

    Syntax

    + <after-action> xsd:boolean <after-action> [occurrences: 0-1] +

    Parents:

    +

    <simple-action-interceptor> +

    +

    Children:

    +

    none

    + +
    <binding-context> +

    Syntax

    + <binding-context> [occurrences: 0-*] + <name> xsd:string </name> [occurrences: 1] + <factory-class> xsd:string </factory-class> [occurrences: 1] +</binding-context> +

    Parents:

    +

    <binding-contexts>

    +

    Children:

    +

    <name>, + <factory-class>

    +
    <binding-contexts> +

    Syntax

    + </binding-contexts> [occurrences: 0-1] + <binding-context> [occurrences: 0-*] + <name> xsd:string </name> [occurrences: 1] + <factory-class> xsd:string </factory-class> [occurrences: 1] + </binding-context> +</binding-contexts> +

    Parents:

    +

    <expression-language>

    +

    Children:

    +

    <binding-context>

    +
    <converter-class> +

    Syntax

    + <converter-class> xsd:string </converter-class> [occurrences: 1] +

    Parents:

    +

    <type-converter>

    +

    Children:

    +

    none

    + +
    <custom-property> +

    Syntax

    + <custom-property> + <name> xsd:string </name> [occurrences: 1] + <value> xsd:string </value> [occurrences: 1] +</custom-property> +

    Parents:

    +

    <action-interceptor>, + <request-interceptor>, + <action-forward-handler>, + <exceptions-handler>, + <forward-redirect-handler>, + <login-handler>, + <reloadable-class-handler> + <flowcontroller-factory> + <faces-backing-bean-factory> +

    +

    Children:

    +

    <name>, + <value>

    + +
    <default-language> +

    Syntax

    + <default-language> xsd:string </default-language> [occurrences: 1] +

    Parents:

    +

    <expression-language>

    +

    Children:

    +

    none

    +
    <default-shared-flow-refs> +

    Allows JSPs to access shared flows even when there is no page flow that + declares the shared flow. This configuration element declares + default shared flow references that can be used across the web app.

    +

    Syntax

    + <default-shared-flow-refs> + <shared-flow-ref> + <name> xsd:string </name> [occurrences: 1] + <type> xsd:string </type> [occurrences: 1] + </shared-flow-ref> [occurrences: 0-*] +</default-shared-flow-refs> +

    Parents:

    +

    <netui-config>

    +

    Children:

    +

    <shared-flow-ref>

    + +
    <description> +

    Syntax

    + <description> xsd:string </description> [occurrences: 0-1] +

    Parents:

    +

    <module-config-locator>

    +

    Children:

    +

    none

    +
    <doctype> +

    Sets the WebApp default HTML format. The currently supported formats are + HTML 4.01 Transitional DTD (Loose), HTML 4.01 Transitional DTD with Quirks mode on, + and XHTML 1.0 Transitional. The default value is html4-loose-quirks. +

    +

    Syntax

    + <doctype> [ html4-loose | html4-loose-quirks | xhtml1-transitional ] </doctype> [occurrences: 0-1] +

    Parents:

    +

    <jsp-tag-config>

    +

    Children:

    +

    none

    +
    <enable-self-nesting> +

    + When this value is set to false (the default), a nested page flow that is + anywhere on the nesting stack will be reactivated if one of its actions is hit, + and all page flows higher up the stack will be destroyed. When this value is set to + true, a new instance of the nested page flow will end up at the top of the + stack. As an example, consider the following stack of page flows: +

    + A, B, C (top) +

    + When an action in B is hit, one of two things will happen: +

    +
      +
    • If enable-self-nesting is set to false, then B will be + reactivated and C will be destroyed. The nesting stack will look like this: + A, B (top) +
    • +
    • If enable-self-nesting is set to true, then a new instance of B + will be at the top of the stack, which will look like this: + A, B, C, B (top) +
    • +
    +

    + Note that setting this value to true is not back-button-friendly. + Hitting a Page Flow action after using the browser back button can often end up executing an + action on a nested page flow in the middle of the nesting stack. +

    +

    Syntax

    + <enable-self-nesting> xsd:boolean </enable-self-nesting> [occurrences: 0-1] +

    Parents:

    +

    <pageflow-config>

    +

    Children:

    +

    none

    +
    <ensure-secure-forwards> +

    For some server implementations, security checks are executed only when an URL is called + directly, while security checks for server forwards are ignored.

    +

    When this element is set to true, server forwards are guaranteed to be checked.

    +

    Syntax

    + <ensure-secure-forwards> xsd:boolean </ensure-secure-forwards> [occurrences: 0-1] +

    Parents:

    +

    <pageflow-config>

    +

    Children:

    +

    none

    + +
    <exceptions-handler> +

    Typically, exceptions thrown by the controller class are delivered in a wrapper exception + class. The class named here, can be used to unwrap these exceptions and handle + the underlying exception in a more fine-grained manner.

    +

    Syntax

    + <exceptions-handler> + <handler-class> xsd:string </handler-class> [occurrences: 1] + <custom-property> + <name> xsd:string </name> [occurrences: 1] + <value> xsd:string </value> [occurrences: 1] + </custom-property> [occurrences: 0-*] +</exceptions-handler> +

    Parents:

    +

    <pageflow-handlers>

    +

    Children:

    +

    <handler-class>, + <custom-property>

    + +
    <expression-language> +

    Syntax

    + <expression-language> [occurrences: 1-*] + <name> xsd:string </name> [occurrences: 1] + <factory-class> xsd:string </factory-class> [occurrences: 1] + <binding-contexts> binding-contexts </binding-contexts> [occurrences: 0-1] + </expression-language> +

    Parents:

    +

    <pageflow-handlers>

    +

    Children:

    +

    <name>, + <factory-class>, + <binding-contexts>

    +
    <expression-languages> +

    Syntax

    + <expression-languages> [occurrences: 1] + <default-language> xsd:string </default-language> [occurrences: 1] + <expression-language> [occurrences: 1-*] + <name> xsd:string </name> [occurrences: 1] + <factory-class> xsd:string </factory-class> [occurrences: 1] + <binding-contexts> binding-contexts </binding-contexts> [occurrences: 0-1] + </expression-language> +</expression-languages> +

    Parents:

    +

    <netui-config>

    +

    Children:

    +

    <default-language>, + <expression-language> +

    + + +
    + <faces-backing-bean-factory> +

    + This setting configures a factory for creating "backing beans" for + JavaServer Faces pages. The referenced class must extend + + org.apache.beehive.netui.pageflow.FacesBackingBeanFactory + +

    + +

    Syntax

    + + <faces-backing-bean-factory> [occurrences: 0-*] + <factory-class> xsd:string </factory-class> [occurrences: 1] + <custom-property> [occurrences: 0-*] + <name> xsd:string </name> [occurrences: 1] + <value> xsd:string </value> [occurrences: 1] + </custom-property> + </faces-backing-bean-factory> + +

    Parents:

    +

    <pageflow-factories>

    +

    Children:

    +

    + <factory-class>, + <custom-property> +

    +
    + +
    + <factory-class> +

    + This setting configures a factory class and its custom properties. +

    + +

    Syntax

    + + <factory-class> xsd:string </factory-class> [occurrences: 1] + +

    Parents:

    +

    + <binding-contexts>, + <expression-language>, + <iterator-factory> + <flowcontroller-factory>, + <faces-backing-bean-factory> +

    +

    Children:

    +

    + None. +

    +
    + + + +
    + <flowcontroller-factory> +

    + This setting configures a factory for creating page flows and shared flows. + The referenced class must extend + + org.apache.beehive.netui.pageflow.FlowControllerFactory + +

    + +

    Syntax

    + + <flowcontroller-factory> [occurrences: 0-*] + <factory-class> xsd:string </factory-class> [occurrences: 1] + <custom-property> [occurrences: 0-*] + <name> xsd:string </name> [occurrences: 1] + <value> xsd:string </value> [occurrences: 1] + </custom-property> + </flowcontroller-factory> + +

    Parents:

    +

    <pageflow-factories>

    +

    Children:

    +

    + <factory-class>, + <custom-property> +

    +
    + + +
    <forward-redirect-handler> +

    Syntax

    + <forward-redirect-handler> + <handler-class> xsd:string </handler-class> [occurrences: 1] + <custom-property> + <name> xsd:string </name> [occurrences: 1] + <value> xsd:string </value> [occurrences: 1] + </custom-property> [occurrences: 0-*] +</forward-redirect-handler> +

    Parents:

    +

    <pageflow-handlers>

    +

    Children:

    +

    Children:

    +

    <handler-class>, + <custom-property>

    + +
    <global> +

    Syntax

    + <global> [occurrences: 0-1] + <simple-action-interceptor> + <intercept-path> xsd:string </intercept-path> [occurrences: 1] + <after-action> xsd:boolean </after-action> [occurrences: 0-1] + </simple-action-interceptor> [occurrences: 0-*] + <action-interceptor> + <interceptor-class> xsd:string </interceptor-class> [occurrences: 1] + <custom-property> + <name> xsd:string </name> [occurrences: 1] + <value> xsd:string </value> [occurrences: 1] + </custom-property> [occurrences: 0-*] + </action-interceptor> [occurrences: 0-*] +</global> + +<global> + <request-interceptor> + <interceptor-class> xsd:string </interceptor-class> [occurrences: 1] + <custom-property> + <name> xsd:string </name> [occurrences: 1] + <value> xsd:string </value> [occurrences: 1] + </custom-property> [occurrences: 0-*] + </request-interceptor> [occurrences: 0-*] +</global> +

    Parents:

    +

    <pageflow-action-interceptors>, + <request-interceptors>

    +

    Children:

    +

    <simple-action-interceptor>, + <action-interceptor>, + <request-interceptor>

    + +
    <handler-class> +

    Syntax

    + <handler-class> xsd:string </handler-class> [occurrences: 1] +

    Parents:

    +

    <action-forward-handler>, + <exceptions-handler>, + <forward-redirect-handler>, + <login-handler>, + <reloadable-class-handler>, + <prefix-handler>

    +

    Children:

    +

    none

    + + +
    <html-amp-entity> +

    +The url parameter separators of & (single amphersand) are encoded to &amp; (ampersand followed by amp;) by default +according to the html 401 specifications set forth by W3C. This item +can be set to false and the parameter separators will not be encoded. +

    + +

    Syntax

    +

    Syntax

    + <html-amp-entity> xsd:boolean </html-amp-entity> [occurrences: 0-1] +

    Parents:

    +

    <url-config>

    +

    Children:

    +

    none

    + + + + +
    <id-javascript> +

    This configuration setting will change the type of support for JavaScript. The default is + to output only the Beehive NetUI JavaScript support. There are two legacy mode options that output + pre-Beehive JavaScript support. When id-javaScript is set to legacy + the pre-Beehive lookup methods are written out along with the current Beehive lookup methods. + When the value is set to legacyOnly + only the pre-beehive lookup methods are written out. This is a pure backward compatibility mode + for pre-beehive NetUI behavior. +

    +

    Syntax

    + <id-javascript> [ default | legacy | legacyOnly ] </id-javascript> [occurrences: 0-1] +

    Parents:

    +

    <jsp-tag-config>

    +

    Children:

    +

    none

    + +
    <interceptor-class> +

    Syntax

    + <interceptor-class> xsd:string <interceptor-class> [occurrences: 1] +

    Parents:

    +

    <action-interceptor>, + <request-interceptor>

    +

    Children:

    +

    none

    + +
    <intercept-path> +

    Syntax

    + <intercept-path> xsd:string </intercept-path> [occurrences: 1] +

    Parents:

    +

    <simple-action-interceptor>

    +

    Children:

    +

    none

    + +
    <iterator-factories> +

    Syntax

    + <iterator-factories> + <iterator-factory> [occurrences: 0-*] + ... + </iterator-factory> +</iterator-factories> +

    Parents:

    +

    <netui-config>

    +

    Children:

    +

    <iterator-factory>

    + +
    <iterator-factory> +

    Syntax

    + <iterator-factory> [occurrences: 0-*] + <name> xsd:string </name> [occurrences: 1] + <factory-class> xsd:string </factory-class> [occurrences: 1] +</iterator-factory> +

    Parents:

    +

    <iterator-factories>

    +

    Children:

    +

    <name>, + <factory-class>

    + +
    <jsp-tag-config> +

    Syntax

    + <jsp-tag-config> + <doctype> xsd:string </doctype> [occurrences: 0-1] + <id-javascript> [ default | legacy | legacyOnly ] </id-javascript> [occurrences: 0-1] + <tree-image-location> xsd:string </tree-image-location> [occurrences: 0-1] +</jsp-tag-config> +

    Parents:

    +

    <netui-config>

    +

    Children:

    +

    <doctype>, + <id-javascript>, + <tree-image-location>,

    + +
    <locator-class> +

    Syntax

    + <locator-class> xsd:string </locator-class> [occurrences: 1] +

    Parents:

    +

    <module-config-locator>

    +

    Children:

    +

    none

    + +
    <login-handler> +

    Syntax

    + <login-handler> + <handler-class> xsd:string </handler-class> [occurrences: 1] + <custom-property> + <name> xsd:string </name> [occurrences: 1] + <value> xsd:string </value> [occurrences: 1] + </custom-property> [occurrences: 0-*] +</login-handler> +

    Parents:

    +

    <pageflow-handlers>

    +

    Children:

    +

    <handler-class>, + <custom-property>

    + +
    <max-forwards-per-request> +

    If the number of server + forwards exceeds the given count, an error is written to the response and no further + forwarding is excuted. This is mainly to prevent infinite loops of server forwards. + To reproduce the error, invoke this action in a page flow:

    + + + +

    If this element is omitted, the error will be written to the response after 25 server forwards within a single request. +

    +

    When an application is in development, a descriptive error is sent; for deployed applications, a 500 response is sent.

    +

    Syntax

    + <max-forwards-per-request> xsd:int </max-forwards-per-request> [occurrences: 0-1] +

    Parents:

    +

    <pageflow-config>

    +

    Children:

    +

    none

    +
    + +
    <max-nesting-stack-depth> +

    + This parameter sets the maximum size of the Page Flow nesting stack. + If page flows are repeatedly nested until the stack size exceeds the specified value, + an error is written to the response object and any further nesting is not allowed. + This helps prevent the nesting stack from consuming large amounts of resources.

    +

    When an application is in development, a descriptive error is sent; for deployed applications, a 500 response is sent.

    +

    Syntax

    + <max-nesting-stack-depth> xsd:int </max-nesting-stack-depth> [occurrences: 0-1] +

    Parents:

    +

    <pageflow-config>

    +

    Children:

    +

    none

    +
    + +
    <module-config-locator> +

    Syntax

    + <module-config-locator> [occurrences: 0-*] + <description> xsd:string </description> [occurrences: 0-1] + <locator-class> xsd:string </locator-class> [occurrences: 1] +</module-config-locator> +

    Parents:

    +

    <module-config-locators>

    +

    Children:

    +

    <description>, + <locator-class>

    + +
    <module-config-locators> +

    Names a class or group of classes that know the location of the web application's + Struts module configuration files. By default these configuation files are saved to + WEB-INF/classes/_pageflow/. In cases where this default location + has been overridden or augmented by a custom compilation process, use + <module-config-locators> to point to a Java class that knows the + new location.

    +

    Syntax

    + <module-config-locators> [occurrences: 0-1] + <module-config-locator> [occurrences: 0-*] + <description> xsd:string </description> [occurrences: 0-1] + <locator-class> xsd:string </locator-class> [occurrences: 1] + </module-config-locator> +</module-config-locators> +

    Parents:

    +

    <pageflow-config>

    +

    Children:

    +

    <module-config-locator>

    + +
    <multipart-handler> +

    By default multi-part file uploading is disabled for NetUI web applications. + To turn it on, you must (1) explicitly set this element to memory + or disk, or (2) set the multipartHandler attribute on + a page flow's @Jpf.Controller annotation. Doing (1) will enable file uploading across + the entire web applcation; doing (2) enables file uploading on a + controller-by-controller basis.

    +

    Also see:

    +

    + + Attribute multipartHandler on annotation interface org.apache.beehive.netui.pageflow.annotations.Jpf + +

    +

    Syntax

    + <multipart-handler> [ disabled | memory | disk ] </multipart-handler> [occurrences: 0-1] +

    Parents:

    +

    <pageflow-config>

    +

    Children:

    +

    none

    + +
    <name> +

    Syntax

    + <name> xsd:string </name> [occurrences: 1] +

    Parents:

    +

    <expression-language>, + <iterator-factory>, + <binding-context>, + <custom-property>, + <shared-flow-ref>, + <prefix-handler>

    +

    Children:

    +

    none

    + +
    + <netui-config> +

    + The top-level element in the beehive-netui-config.xml file.

    +

    Syntax

    + <netui-config> + <expression-languages> ... </expression-languages> [occurrences: 1] + <pageflow-action-interceptors> ... </pageflow-action-interceptors> [occurrences: 0-1] + <pageflow-handlers> ... </pageflow-handlers> [occurrences: 0-1] + <pageflow-factories> ... </pageflow-factories> [occurrences: 0-1] + <pageflow-config> ... </pageflow-config> [occurrences: 0-1] + <default-shared-flow-refs> ... </default-shared-flow-refs> [occurrences: 0-1] + <type-converters> ... </type-converters> [occurrences: 0-1] + <jsp-tag-config> ... </jsp-tag-config> [occurrences: 0-1] + <url-config> ... </url-config> [occurrences: 0-1] + <iterator-factories> ... </iterator-factories> [occurrences: 0-1] + <request-interceptors> ... </request-interceptors> [occurrences: 0-1] + <prefix-handlers> ... </prefix-handlers> [occurrences: 0-1] +</netui-config> +

    Parents:

    +

    +

    Children:

    +

    <expression-languages>, + <pageflow-action-interceptors>, + <pageflow-handlers>, + <pageflow-factories>, + <pageflow-config>, + <default-shared-flow-refs>, + <type-converters>, + <jsp-tag-config>, + <url-config>, + <iterator-factories>, + <request-interceptors>, + <prefix-handlers>

    +
    + +
    + <pageflow-action-interceptors> +

    To run code before or after Page Flow actions, +you configure a <pageflow-action-interceptor> group. +A simple example of this would be a monitoring infrastructure +that keeps track of the number of actions raised. To keep track of the number of actions raised, +register an interceptor +that runs the counting code before going to any action. A more complex example +is an interceptor that "injects" a page flow before allowing you +to go to the current one; for instance, it might decide (on the fly) to take you to a nested page flow +that asks you to fill out a "satisfaction survey" before sending you to the +destination page flow.

    +

    + The action-intercepting class is run twice: both before and after the execution of the + action. When run before an action, it can do three things: +

    +
      +
    • change the destination URI and thus prevent the action from running, or,
    • +
    • set the destination URI to null (no forwarding) and thus prevent the action from running, or,
    • +
    • + "inject" an entire nested page flow to run before the action is invoked. If the override forward URI + is a nested page flow, then it will run until it raises one of its return actions. At that point, + afterNestedIntercept is called on this interceptor, which can again choose to override + the forward or allow the original action to run. +
    • +
    +

    When run after an action, it can do two things:

    +
      +
    • change the destination URI that was returned by the action, or,
    • +
    • set the destination URI to null (no forwarding).
    • +
    +

    Also see:

    +

    Interface org.apache.beehive.netui.pageflow.interceptor.ActionInterceptor

    +

    Syntax

    + <pageflow-action-interceptors> + <global> [occurrences: 0-1] + <simple-action-interceptor> ... </simple-action-interceptor> [occurrences: 0-*] + <action-interceptor> ... </action-interceptor> [occurrences: 0-*] + </global> + <per-pageflow> [occurrences: 0-*] + <pageflow-uri> xsd:string </pageflow-uri> [occurrences: 1] + <simple-action-interceptor> ... </simple-action-interceptor> [occurrences: 0-*] + <action-interceptor> ... </action-interceptor> [occurrences: 0-*] + <per-action> [occurrences: 0-*] + <action-name> xsd:string </action-name> [occurrences: 1] + <simple-action-interceptor> ... </simple-action-interceptor> [occurrences: 0-*] + <action-interceptor> ... </action-interceptor> [occurrences: 0-*] + </per-action> + </per-pageflow> +</pageflow-action-interceptors> +

    Parents

    +

    <netui-config>

    +

    Children

    +

    <global>, <per-pageflow>

    +
    + +
    + <pageflow-config> +

    Syntax

    + <pageflow-config> + <enable-self-nesting> xsd:boolean </enable-self-nesting> [occurrences: 0-1] + <max-forwards-per-request> xsd:int </max-forwards-per-request> [occurrences: 0-1] + <max-nesting-stack-depth> xsd:int </max-nesting-stack-depth> [occurrences: 0-1] + <ensure-secure-forwards> xsd:boolean </ensure-secure-forwards> [occurrences: 0-1] + <throw-session-expired-exception> xsd:boolean </throw-session-expired-exception> [occurrences: 0-1] + <multipart-handler> [ disabled | memory | disk ] </multipart-handler> [occurrences: 0-1] + <prevent-cache> [ default | always | inDevMode ] </prevent-cache> [occurrences: 0-1] + <module-config-locators> ... </module-config-locators> [occurrences: 0-1] +</pageflow-config> +

    Parents:

    +

    <netui-config>

    +

    Children:

    +

    <enable-self-nesting>, + <max-forwards-per-request>, + <max-nesting-stack-depth>, + <ensure-secure-forwards>, + <throw-session-expired-exception>, + <multipart-handler>, + <prevent-cache>, + <module-config-locators> +

    +

    +Configures the NetUI +runtime across the webapp. If you want to disable file-upload, for instance, +you set the multipart-handler to "disabled".

    + +
    + <pageflow-handlers> +

    +These settings let you override base framework behavior. +A good example is the LoginHandler. By default, standard Servlet +APIs are used to determine whether a user is logged in, and +server-specific APIs are used to actually log in a user when +login() is called inside a page flow. +If you want to replace this behavior with your own login scheme +(which may look at a User database table for login information), +you can provide your own LoginHandler that defines methods like +login() and isUserInRole(). +

    + +

    Syntax

    + <pageflow-handlers> + <action-forward-handler> [occurrences: 0-*] + <handler-class> xsd:string </handler-class> [occurrences: 1] + <custom-property> [occurrences: 0-*] + <name> xsd:string </name> [occurrences: 1] + <value> xsd:string </value> [occurrences: 1] + </custom-property> + </action-forward-handler> + <exceptions-handler> [occurrences: 0-*] + <handler-class> xsd:string </handler-class> [occurrences: 1] + <custom-property> [occurrences: 0-*] + <name> xsd:string </name> [occurrences: 1] + <value> xsd:string </value> [occurrences: 1] + </custom-property> + </exceptions-handler> + <forward-redirect-handler> [occurrences: 0-*] + <handler-class> xsd:string </handler-class> [occurrences: 1] + <custom-property> [occurrences: 0-*] + <name> xsd:string </name> [occurrences: 1] + <value> xsd:string </value> [occurrences: 1] + </custom-property> + </forward-redirect-handler> + <login-handler> [occurrences: 0-*] + <handler-class> xsd:string </handler-class> [occurrences: 1] + <custom-property> [occurrences: 0-*] + <name> xsd:string </name> [occurrences: 1] + <value> xsd:string </value> [occurrences: 1] + </custom-property> + </login-handler> + <reloadable-class-handler> [occurrences: 0-*] + <handler-class> xsd:string </handler-class> [occurrences: 1] + <custom-property> [occurrences: 0-*] + <name> xsd:string </name> [occurrences: 1] + <value> xsd:string </value> [occurrences: 1] + </custom-property> + </reloadable-class-handler> +</pageflow-handlers> +

    Parents:

    +

    <netui-config>

    +

    Children:

    +

    <action-forward-handler>, + <exceptions-handler>, + <forward-redirect-handler>, + <login-handler>, + <reloadable-class-handler>

    + +
    + <pageflow-factories> +

    + These settings let you override the default factories for creating + page flows, shared flows, and JavaServer Faces backing beans. +

    + +

    Syntax

    + + <pageflow-factories> + <flowcontroller-factory> [occurrences: 0-*] + <factory-class> xsd:string </factory-class> [occurrences: 1] + <custom-property> [occurrences: 0-*] + <name> xsd:string </name> [occurrences: 1] + <value> xsd:string </value> [occurrences: 1] + </custom-property> + </flowcontroller-factory> + <faces-backing-bean-factory> [occurrences: 0-*] + <factory-class> xsd:string </factory-class> [occurrences: 1] + <custom-property> [occurrences: 0-*] + <name> xsd:string </name> [occurrences: 1] + <value> xsd:string </value> [occurrences: 1] + </custom-property> + </faces-backing-bean-factory> + </pageflow-factories> + +

    Parents:

    +

    <netui-config>

    +

    Children:

    +

    + <flowcontroller-factory>, + <faces-backing-bean-factory> +

    +
    + + +
    <pageflow-uri> +

    Syntax

    + <pageflow-uri> xsd:string </pageflow-uri> [occurrences: 1] +

    Parents:

    +

    <per-pageflow>

    +

    Children:

    +

    none

    + +
    <per-action> +

    Syntax

    + <per-action> [occurrences: 0-*] + <action-name> xsd:string </action-name> [occurrences: 1] + <simple-action-interceptor> netui:simple-action-interceptor </simple-action-interceptor> [occurrences: 0-*] + <action-interceptor> netui:action-interceptor </action-interceptor> [occurrences: 0-*] +</per-action> +

    Parents:

    +

    <global>

    +

    Children:

    +

    <action-name>, + <simple-action-interceptor>, + <action-interceptor>

    + +
    <per-pageflow> +

    Syntax

    + <per-pageflow> [occurrences: 0-*] + <pageflow-uri> xsd:string </pageflow-uri> [occurrences: 1] + <simple-action-interceptor> netui:simple-action-interceptor </simple-action-interceptor> [occurrences: 0-*] + <action-interceptor> netui:action-interceptor </action-interceptor> [occurrences: 0-*] + <per-action> [occurrences: 0-*] + <action-name> xsd:string </action-name> [occurrences: 1] + <simple-action-interceptor> netui:simple-action-interceptor </simple-action-interceptor> [occurrences: 0-*] + <action-interceptor> netui:action-interceptor </action-interceptor> [occurrences: 0-*] + </per-action> +</per-pageflow> +

    Parents:

    +

    <global>

    +

    Children:

    +

    <pageflow-uri>, + <simple-action-interceptor>, + <action-interceptor>, + <per-action>

    + + +
    <prefix-handler> +

    Syntax

    + <prefix-handler> + <name> xsd:string </name> [occurrences: 1] + <handler-class> xsd:string </handler-class> [occurrences: 1] +</prefix-handler> +

    Parents:

    +

    <prefix-handlers>

    +

    Children:

    +

    <name>, + <handler-class>

    + +
    <prefix-handlers> +

    Syntax

    + <prefix-handlers> + <prefix-handler> [occurrences: 0-*] + <name> xsd:string </name> [occurrences: 1] + <handler-class> xsd:string </handler-class> [occurrences: 1] + </prefix-handler> +</prefix-handlers> +

    Parents:

    +

    <netui-config>

    +

    Children:

    +

    <prefix-handler>

    + + + + + +
    <prevent-cache> +

    + This setting configures browser caching behavior for pages returned from Page Flow actions. + Setting it to always causes no-cache headers to be added to the HTTP response, + specifying that pages are never cached. Setting it to inDevMode + means that pages may be cached only when the server is in production mode. +

    +

    Syntax

    + <prevent-cache> [ default | always | inDevMode ] </prevent-cache> [occurrences: 0-1] +

    Parents:

    +

    <pageflow-config>

    +

    Children:

    +

    none

    + +
    <reloadable-class-handler> +

    Syntax

    + <reloadable-class-handler> + <handler-class> xsd:string </handler-class> [occurrences: 1] + <custom-property> + <name> xsd:string </name> [occurrences: 1] + <value> xsd:string </value> [occurrences: 1] + </custom-property> [occurrences: 0-*] +</reloadable-class-handler> +

    Parents:

    +

    <pageflow-handlers>

    +

    Children:

    +

    <handler-class>, + <custom-property>

    + +
    + <request-interceptor> +

    Syntax

    + <request-interceptor> + <interceptor-class> xsd:string </interceptor-class> [occurrences: 1] + <custom-property> + <name> xsd:string </name> [occurrences: 1] + <value> xsd:string </value> [occurrences: 1] + </custom-property> [occurrences: 0-*] +</request-interceptor> +

    Parents:

    +

    <global>

    +

    Children:

    +

    <interceptor-class>, + <custom-property>

    + +
    + <request-interceptors> +

    Syntax

    + <request-interceptors> + <global> [occurrences: 0-1] + <request-interceptor> [occurrences: 0-*] + <interceptor-class> xsd:string </interceptor-class> [occurrences: 1] + <custom-property> ... </custom-property> [occurrences: 0-*] + </request-interceptor> + </global> +</request-interceptors> +

    Parents:

    +

    <netui-config>

    +

    Children:

    +

    <global>

    + +
    + <shared-flow-ref> +

    Syntax

    + <shared-flow-ref> + <name> xsd:string </name> [occurrences: 1] + <type> xsd:string </type> [occurrences: 1] +</shared-flow-ref> +

    Parents:

    +

    <default-shared-flow-refs>

    +

    Children:

    +

    <name>, + <type>

    + +
    <simple-action-interceptor> +

    Syntax

    + <simple-action-interceptor> + <intercept-path> xsd:string </intercept-path> [occurrences: 1] + <after-action> xsd:boolean </after-action> [occurrences: 0-1] +</simple-action-interceptor> +

    Parents:

    +

    <netui-config>

    +

    Children:

    +

    none

    + +
    <templated-url-formatter-class> +

    +This setting allows you to override the default url formatting class. +The default value is org.apache.beehive.netui.pageflow.internal.DefaultTemplatedUrlFormatter. +

    +

    Syntax

    + <templated-url-formatter-class> xsd:string </templated-url-fomatter-class> [occurrences: 0-1] +

    Parents:

    +

    <url-config>

    +

    Children:

    +

    none

    + +
    <throw-session-expired-exception> +

    + When set to true (the default), this causes a SessionExpiredException to + be thrown in place of some other Page Flow exceptions when the root cause is most likely the + expiration of the user session. +

    +

    Also see:

    +

    + + Class org.apache.beehive.netui.pageflow.SessionExpiredException + +

    +

    Syntax

    + <throw-session-expired-exception> xsd:boolean </throw-session-expired-exception> [occurrences: 0-1] +

    Parents:

    +

    <pageflow-config>

    +

    Children:

    +

    none

    + +
    <tree-image-location> +

    This configuration sets a path for looking up the default images used by the tree tags. + The default location of resources changed in Beehive NetUI from pre-Beehive NetUI. This + element allows you to set an absolute path to these image resources. +

    +

    Syntax

    + <tree-image-location> xsd:string </tree-image-location> [occurrences: 0-1] +

    Parents:

    +

    <jsp-tag-config>

    +

    Children:

    +

    none

    + +
    <tree-renderer-class> +

    Refers to a custom tree renderer class that overrides the default TreeRenderer. +

    +

    Syntax

    + <tree-renderer-class> xsd:string </tree-renderer-class> [occurrences: 0-1] +

    Parents:

    +

    <jsp-tag-config>

    +

    Children:

    +

    none

    + +
    <type> +

    Syntax

    + <type> xsd:string </type> [occurrences: 1] +

    Parents:

    +

    <type-converter>, + <shared-flow-ref>

    +

    Children:

    +

    none

    + +
    <type-converter> +

    Syntax

    + <type-converter> [occurrences: 0-*] + <type> xsd:string </type> [occurrences: 1] + <converter-class> xsd:string </converter-class> [occurrences: 1] +</type-converter> +

    Parents:

    +

    <type-converters>

    +

    Children:

    +

    <type>, + <converter-class>

    + +
    <type-converters> +

    Syntax

    + <type-converters> + <type-converter> [occurrences: 0-*] + <type> xsd:string </type> [occurrences: 1] + <converter-class> xsd:string </converter-class> [occurrences: 1] + </type-converter> +</type-converters> +

    Parents:

    +

    <netui-config>

    +

    Children:

    +

    <type-converter>

    + +
    <url-config> +

    Syntax

    + <url-config> + <url-encode-urls> xsd:boolean </url-encode-urls> [occurrences: 0-1] + <html-amp-entity> xsd:boolean </html-amp-entity> [occurrences: 0-1] + <templated-url-formatter-class> xsd:string </templated-url-formatter-class> [occurrences: 0-1] +</url-config> +

    Parents:

    +

    <netui-config>

    +

    Children:

    +

    <url-encode-urls>, + <html-amp-entity>, + <templated-url-formatter-class>

    + +
    <url-encode-urls> +

    +This setting allows you to override the default of encoding the urls for +tags with href attributes so that already encoded urls will not be re-encoded. +

    +

    Syntax

    + <url-encode-urls> xsd:boolean </url-encode-urls> [occurrences: 0-1] +

    Parents:

    +

    <url-config>

    +

    Children:

    +

    none

    + +
    <value> +

    Syntax

    + <value> xsd:string </value> [occurrences: 1] +

    Parents:

    +

    <custom-property>

    +

    Children:

    +

    none

    +
    +
    + Example +

    + Use the following example netui-config.xsd file as a guide.

    + + + + + + netuiel + + netuiel + org.apache.beehive.netui.script.el.ExpressionEvaluatorImpl$NetUIELEngineFactory + + + + + + + + example.GlobalInterceptor + + someCustomProperty + someValue + + + + + /example/intercepted1/Controller.java + + + /example/nested/SomeNestedController.java + + + + + + + example.CustomLoginHandler + + + + + memory + + + + html4-loose + Legacy-JavaScript-Only + + + + + + + + ]]> +
    + + + +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/databinding.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/databinding.xml new file mode 100644 index 0000000..9b2f71c --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/databinding.xml @@ -0,0 +1,563 @@ + + + +
    + Data binding to NetUI Implicit Objects +
    + +
    + Introduction +

    + In NetUI, data binding allows JSP tags or other UI technologies to read and write data + available in the web-tier environment. This document discusses both the implicit objects that + are available via NetUI to the JSP author and the expression languages that are used to bind UI + objects to those implicit objects. +

    +

    + NetUI tags support binding to both read-only and read-write data. Read-only data is usually + bound to tag attributes that simply display information on a page. Read-write data is bound with the intention + of being updated from a web browser. Often, read-write data is displayed within an HTML form tag and bound to + HTML text boxes, radio buttons, select boxes, and other HTML widget types. Each of these types of binding + use the syntax of the JSP 2.0 Expression Language (EL) to express a binding from JSP tag to JavaBean property, + Map member, List item, array element, and so on. The JSP 2.0 Expression Language is used to bind read-only + data to tag attributes. This language is documented in detail here. For example, + this example binds a NetUI span tag to a value from a JSP's PageContext attribute map: +

    + ]]> +

    + Here, the JSP container evaluates the expression and invokes the span tag's setValue + attribute method to pass the result to the tag. The JSP 2.0 EL is also able to perform simple arithmetic + and boolean operations in expressions. +

    +

    + When using the NetUI JSP tags, read-write data is bound to NetUI JSP tags differently. NetUI tags use a derivation + of the JSP 2.0 EL to refer to implicit objects in a JSP, but unlike the JSP 2.0 EL, the syntax is slightly different. + For example, when binding a NetUI textBox tag to data that is meant to be read and then updated during an + HTML form POST, the textBox tag might look like: +

    + ]]> +

    + This expression syntax is used on NetUI JSP tag attributes named dataSource. The expression syntax is + necessary to allow the NetUI tags to know both the value of the expression and the expression text. The + expression text is needed in order to write the tag's name in the HTML rendered to a web browser. For example, + with a userName of "foo", the JSP tag above will render: +

    + ]]> +

    + The expression text is used by the <netui:textBox> tag to render the value of the HTML input's + name attribute, and when the containing HTML form POSTs, this name is used to detect the presence of + a NetUI expression that can then be used to update a property on a JavaBean or other data structure. +

    + + In order to prevent POSTing data into JSP implicit objects such as requestScope or sessionScope, + only a few NetUI implicit objects should be used in read/write expressions. These include pageFlow, + sharedFlow, and actionForm. + +

    +

    +
    +
    + JSP Implicit Objects +

    + A JSP 2.0+ container exposes a set of implicit objects for use by JSP authors. These implicit objects are documented + here. These can be used on any of the NetUI JSP tag attributes that accept runtime expressions. + For example, in a webapp called foo the following JSP snippet uses the pageContext implicit object + as a JavaBean to build a fully-qualified image path: +

    + ]]> +

    + This renders the following HTML markup: +

    + ]]> +

    + The JSP container also makes implicit objects available that provide access to the attribute maps for the page context, + request, session, and servlet context. By adding attributes to the page context, request, and session, webapp + developers can add their own implicit objects. In the following example, a JavaBean of type Widget is + added to the request in a page flow action: +

    + getRequest().setAttribute("widget", fooWidget); +

    + Then, this JSP snippet uses the expression language to data bind to the Widget's density property: +

    + The density is: ${widget.density} +

    + This is effectively the same as writing code that does: +

    + ]]> +
    +
    + NetUI Implicit Objects +

    + In addition to the implicit objects that the JSP container provides, the NetUI runtime provides an additional set + of objects that are available when using certain NetUI features. Not all of the implicit objects are + always available -- for example, the actionForm implicit object is only available when used inside of + a <netui:form tag for accessing the form's associated form bean. +

    +

    + A summary of the NetUI implicit objects is shown in the table below; details are available further down this document. +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Implicit ObjectContextDescription
    actionFormWithin the <netui:form> tagProvides access to the properties of a JavaBean used as the form bean for an HTML form.
    bundleInside of a JSP where the + + <netui-data:declareBundle> + tag is used to refer to a resource bundle or where a JSP is part of a page flow that has + resource bundles declared with the + + @Jpf.MessageBundle + + annotation.Provides access to message strings contained in a Java properties file. Strings are referred to by name in the expression.
    containerThe container implicit object is available inside of several NetUI JSP tags that "repeat" over data sets + including the + + <netui-data:dataGrid, + + <netui-data:repeater, + + <netui-data:cellRepeater, + + <netui:select, + + <netui:checkBoxGroup, and + + <netui:radioButtonGroup, + Provides access to the JavaBean properties exposed by the + + IDataAccessProvider interface. Implementations + of this interface are made available to the PageContext during rendering so that tag bodies can access information about + the current data item, the item's index, and so on. +
    pageFlowAvailable to any JSP that is part of a page flow.The pageFlow implicit object provides access to the + current page flow controller instance as a JavaBean. This allows a page flow controller to expose properties to JSPs. +
    pageInput + Available to any JSP that was reached by a page flow + Forward + object that had page inputs attached to the Forward. + + Page flows allow action outputs to be attached to Forward objects as a way to provide a data contract between a page flow action + and a page. This ensures that all actions that forward to JSPs provide the JSP with the appropriate data and that all JSPs receive + the correct data. This data contract is validated at both the action and at the JSP when using the + + <netui-data:declarePageInput>. + tag. +
    sharedFlowAvailable to any JSP that is part of a + + page flow which references + + shared flows.The sharedFlow implicit object provides access to any JavaBean properties on Shared Flows associated + with the current page flow. This allows Shared Flows to expose properties to JSPs. +
    +
    + NetUI Implicit Object Details +

    +

    +
    +
    + actionForm +

    + The actionForm implicit object is a convenient way to explicitly reference a JavaBean used for authoring + HTML forms. This implicit object is available only inside of <netui:form> tags with action + attributes that reference page flow actions accepting a JavaBean. The actionForm implicit object allows + data binding to JavaBean properties, Map attributes, Lists, and arrays as with any other implicit object. This example + shows a JSP that contains a form which POSTs to a page flow action that accepts a JavaBean NameForm. +

    +

    The JavaBean:

    + public class NameForm { + private String _name; + public String getName() { + return _name; + } + + public void setName(String name) { + _name = name; + } +} +

    + The JSP: +

    + +
    + +]]> +

    + The page flow action submitNameForm: +

    + @Jpf.Action() +public Forward submitNameForm(NameForm form) { + ... +} +

    + Here, the dataSource's actionForm.name expression refers to the value of the + NameForm's name property. The result is data bound to the textBox tag. + When the form is submitted to the server, the request parameter {actionForm.name} is applied + to the action form which is then passed to the submitNameForm action. +

    +
    +
    + bundle +

    + The bundle implicit object is useful for binding UI to localized message strings. The bundle + implicit object is available in one of two situations: +

    + +

    + The declareBundle JSP tag is used to make a specific resource bundle available to a JSP. For example, + given the following resource bundle and JSP, a page can data bind to messages in the resource bundle using the + JSP 2.0 EL. +

    +

    + The resource bundle, which is located in WEB-INF/classes/org/foo/messages.properties: +

    + +

    + The JSP can declare this resource bundle to be available to the page using this JSP snippet: +

    + + +]]> +

    + Finally, messages in the JSP can be data bound with JSP literal text and tags: +

    + + +${bundle.fooMessages.message2}]]> +

    + The expressions above contain a reference to the bundle implicit object. Then, the specific + bundle name is referred to with fooMessages; this name must match the value of a name + attribute of a declareBundle tag or the name of a bundle declared in a page flow controller. Finally, the + expressions use message1 and message2 to refer to message keys in the + messages.properties file. +

    +

    + Resource bundles can also be registered with the bundle implicit object by using the + + @Jpf.MessageBundle + + class-level annotation. This allows a page flow to also integrate with the implicit message resources object which is + available via a Struts module. These resource bundles will be available to all JSPs that are part of a page flow without having + to use the declareBundle JSP tag. Because a default resource bundle can be associated with a Struts module, the + bundle name default is reserved for referencing this bundle. For example, the following page flow controller declares + the resource bundle above as the default page flow bundle: +

    + @Jpf.Controller( + forwards = {...} + messageBundles = { + @Jpf.MessageBundle(bundlePath="org.foo.messages") + } +) +public class Controller + extends PageFlowController { + ... +} +

    + Message strings from this bundle can be referred to in JSPs with an expression like: +

    + +

    + A resource bundle can also be registered with a specific name by adding an annotation like: +

    + @Jpf.Controller( + forwards = {...} + messageBundles = { + @Jpf.MessageBundle(bundleName="jpfBundle", bundlePath="org.foo.messages") + } +) +public class Controller + extends PageFlowController { + ... +} +

    + Then, the same message strings from the previous two examples are available with an expression like +

    + ${bundle.jpfBundle.message1} +

    + Each of these three ways to register a resource bundle (JSP tag, implicit page flow bundle, and explicit page flow bundle) + can be used together in a single page flow. +

    +
    +
    + container +

    + The container implicit object is available to a JSP when inside of several NetUI tags that repeat over + a Map, List, array, or various other kinds of data sets. Generally, JSP tags that can be bound to data sets iterate through them + from start to end as in a Java for loop. Such JSP tags include: +

    + +

    + The container implicit object provides access to the current item in the data set and to metadata about the current + iteration. This access is based on the properties available on the IDataAccessProvider interface and includes: +

    + + + + + + + + + + + + + +
    Property NameDescription
    itemRefers to the current data item. In an array of Widget beans, the JavaBean propeties of widget can + be accessed with an expression like ${container.item.density}
    indexRefers to the current index of iteration. Tags are free to define their own rules for the the value of the + index property, but in general, this is a zero-based index that increments each time the + JSP tag renders its body / iterates to the next data item. +
    containerRefers to an outer repeating container. This value is used when two repeating containers are + nested and the inner container needs to access the current item in the outer container. For example, + this might be used when rendering hierarchical data sets. +
    +

    + The following example uses the NetUI <netui-data:repeater> to iterate over an array of Widget + beans displaying each Bean's name and density properties and their index in the array. +

    + + + + + + + +
    IndexNameDensity
    ${container.index}${container.item.name}${container.item.density}
    ]]> +

    + Notice in this example how the repeater tag has a dataSource attribute that references + the data set to iterate through. The dataSource attribute requires the use of the NetUI Expression + Language because the repeater can be used to render editing UI for data sets. For example, in the case + of rendering a shopping cart, the repeater can be used to render each item in the cart with a <netui:textBox> + for editing the quantity of each item. An example of this can be found in the Beehive sample webapp called + netui-samples under the ui/repeaterediting/ directory. +

    +
    +
    + pageFlow +

    + The pageFlow implicit object is used to refer to the current page flow controller as a JavaBean. If there is no page flow + present, the pageFlow implicit object will not be available for data binding. For example, if a page flow controller + exposes a username property as: +

    + @Jpf.Controller( + forwards={@Jpf.Forward(name="index", path="index.jsp")} +) +public class Controller { + private String _username = null; + + public String getUsername() { + return _username; + } + + @Jpf.Action() + public Forward begin() { + _username = "Foo Bar"; + return new Forward("index"); + } +} +

    + The username property can be data bound in index.jsp as: +

    + + + Because mutable JavaBean properties can be updated via an HTML form POST, JavaBean properties exposed by a page flow should usually + be read-only unless the page flow itself is being used as a form bean. + +
    +
    + pageInput +

    + The pageInput implicit object is used to refer to a Map of objects that are passed via a + Forward from a page flow action to a JSP. Use of Page Inputs consists of two parts -- the first are called + action outputs and the second are called page inputs. Action outputs are passed from page flow actions + to pages via the action's Forward object. page flow actions use Java annotations to declare a validatable + data contract that ensures that an action passes the correct data via a Forward. At the page, this data + is called a page input and can again be checked to ensure that the page receives the data necessary to render + successfully. +

    +

    + This example shows a page flow action that passes an action output of type Widget to a JSP which + data binds to the density property on the Widget. +

    +

    + The page flow controller: +

    + @Jpf.Controller() +public class Controller + extends PageFlowController { + + @Jpf.Action( + forwards={@Jpf.Forward(name="success", + path="index.jsp", + actionOutputs={@Jpf.ActionOutput(name="theWidget", type=Widget.class, required=true)} + ) + } + ) + protected Forward begin() { + Widget widget = new Widget(); + widget.setDensity(3.14); + Forward f = new Forward("success"); + f.addActionOutput("theWidget", widget); + return f; + } +} +

    + Notice here that the action has added an action output to the Forward via the addActionOutput + method call. The NetUI runtime will then validate the data contract declared in the annotations against the + returned forward object. If validation fails, a runtime error will be displayed in the browser. +

    +

    + The JSP: +

    + + + + +${pageInput.theWidget.density}]]> +

    + Notice here that the page has used a declarePageInput tag to ensure that the Widget + entering the page is both present in the set of page inputs and is non-null. Given this information, the JSP + then refers to properties on the Widget via the expression language. +

    +

    + Action outputs and page inputs can be used with or without validation; to disable action output validation, simply remove + any action output annotations from a page flow action. To disable page input validation in a JSP, remove any + declarePageInput tags from the JSP. The APIs to add action outputs to Forward objects + and to refer to them via the pageInput implicit object will continue to work without any data contract + validation. +

    +
    +
    + sharedFlow +

    + The sharedFlow implicit object is used to refer to properties of shared flow objects that are associated with + the current page flow. If there is no page flow present, the sharedFlow implicit object will not be available + for data binding. In order for a shared flow to be available for data binding, it must be registered with a page flow by + type; additionally, it is registered with a name that will uniquely identify it in the set of shared flows associated with a + page flow. More information on shared flows can be found here. +

    +

    + The following example shows a shared flow, a page flow that uses the Shared Flow, and a JSP that uses the JSP 2.0 EL + to data bind to a JavaBean propety of the shared flow. +

    +

    + The Shared Flow: +

    + package org.foo; + +import org.apache.beehive.netui.pageflow.SharedFlowController; + +@Jpf.Controller() +public class SharedFlow + extends SharedFlowController { + + private String _sharedMessage = null; + + public String getSharedMessage() { + return _sharedMessage; + } +} +

    + The page flow controller: +

    + @Jpf.Controller( + sharedFlowRefs={@Jpf.SharedFlowRef(name="aSharedFlow", type=org.foo.SharedFlow.class)} +) +public class Controller + extends PageFlowController { + + ... +} + +

    + Above, the page flow controller adds an explicit reference to the shared flow controller org.foo.SharedFlow defined above. +

    +

    + The JSP: +

    + +

    + In a JSP whose current page flow controller is the Controller class defined above, the JSP has access to + all of the shared flows associated to the page flow via its + + @Jpf.SharedFlowRef + + annotation. The shared flow can then be referenced by the name attribute of the SharedFlowRef annotation. + In this case, the name aSharedFlow is used in the JSP 2.0 expression to refer to the sharedFlow's + sharedMessage property. +

    +
    +
    +
    + Expression Language Details +

    + Due to limitations in the JSP 2.0 Expression Language specification, expressions can not be used to reference + read-write data because the JSP tag itself can never obtain both the expression text and the value of the + expression. In NetUI, both the value and expression text are required to bind to editable data because the + expression text is written into the JSP as the HTML name attribute of HTML form input + fields. +

    +
    + +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/devMode.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/devMode.xml new file mode 100644 index 0000000..3d28d75 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/devMode.xml @@ -0,0 +1,84 @@ + + + +
    + Development and Production Modes +
    + +
    + Development and Production Modes +

    Beehive applications can be run in either development or + production mode:

    +

    In development mode, if the tag <netui:exceptions showDevModeStackTrace="true"/> + is present on a JSP and an exception occurs, then the stack trace will be + displayed.

    +

    In production mode, the opposite is true: if the tag <netui:exceptions showDevModeStackTrace="true"/> + is present and an exception occurs, then the stack trace won't be + displayed.

    +

    By default, applications run in production mode, i.e., exception stack traces are not + shown.

    +

    Similarly, assertions are + disabled by default.

    + If you want to display the stack trace for exceptions in all cases (whether you're in production mode or development mode), you can + set the <netui:exceptions> tag's showStackTrace attribute + to "true". +

    + <netui:exceptions showStackTrace="true"> +
    +
    +
    Controlling the Visibility of Assertions and Exceptions +

    Beehive uses two switches to control the visibility of assertions and exceptions.

    +
    -ea
    +
    Controls whether assertions are enabled or not. Assertions are + disabled by default. If assertions are enabled, then Beehive + assumes development mode as well: i.e., exception stack traces are + made visible. (See below for + enabling assertions but disabling exception stack traces.)
    +
    -beehive.productionmode
    +
    Controls whether exception stack traces are displayed by the tag + <netui:exceptions showDevModeStackTrace="true"/>. + By default, stack traces are not displayed. +
    +
    +
    + + export JAVA_OPTS= + +
    +
    Same as the 'default' setting. In Tomcat, this leaves assertions disabled and + results in Beehive assuming production mode. If you have + <netui:exceptions showDevModeStackTrace="true"/> in a page and + an exception occurs, you won't see the stack trace.
    +
    +
    +
    + + export JAVA_OPTS=-ea + +
    +
    Using this setting for Tomcat, assertions are enabled and Beehive + assumes + development mode. If you have <netui:exceptions + showDevModeStackTrace="true"/> in one of your pages and an + exception occurs, then you will see the stack trace.
    +
    +
    +
    + + export JAVA_OPTS="-ea -Dbeehive.productionmode=true" + +
    +
    This is a case + where the assumption made by Beehive is overridden: assertions are + enabled, but Beehive will run in production mode. If you have + <netui:exceptions showDevModeStackTrace="true"/> in a page and + an exception occurs, you won't see the stack trace.
    +
    +
    + +
    + Java, J2EE, and JCP are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.
    + © 2004, Apache Software Foundation +
    +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/exceptionHandling.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/exceptionHandling.xml new file mode 100644 index 0000000..a530b85 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/exceptionHandling.xml @@ -0,0 +1,366 @@ + + + +
    + Exception Handling in NetUI +
    + +
    + Introduction +

    + Declarative exception handling is a powerful feature offered by NetUI. It allows you to define handling + for expected and unexpected exceptions without cluttering your controller logic. Consider the + following action method: +

    + +@Jpf.Action( + forwards={ + @Jpf.Forward(name="success", path="nextPage.jsp"), + @Jpf.Forward(name="errorPage1", path="error1.jsp"), + @Jpf.Forward(name="errorPage2", path="error2.jsp") + } +) +public Forward someAction() +{ + try + { + someBusinessControl.executeSomeBusinessLogic(); + return new Forward("success"); + } + catch (Exception1 e) + { + logger.error("Error 1 occurred while executing business logic.", e); + return new Forward("errorPage1"); + } + catch (Exception2 e) + { + logger.error("Error 2 occurred while executing business logic.", e); + return new Forward("errorPage2"); + } +} +

    + As you can see, the controller logic (executing the business logic and forwarding to "success") is + overwhelmed by exception-handling code. The method should really look like this: +

    + +@Jpf.Action( + forwards={ + @Jpf.Forward(name="success", path="nextPage.jsp") + } +) +public Forward someAction() throws Exception1, Exception2 +{ + someBusinessControl.executeSomeBusinessLogic(); + return new Forward("success"); +} +

    + Here, exception handling is left to a mechanism outside of the action method. Read on to find out how + this works. +

    +
    +
    + Declaring Exceptions to Handle +

    + The way to declare that a particular exception type should be handled is the + + @Jpf.Catch + + annotation. Using this annotation, you can specify one of two ways to handle the exception: +

    +
      +
    • by forwarding to some path, or
    • +
    • by running an exception-handler method.
    • +
    +

    + Here are two @Jpf.Catch annotations which deal with an exception type + MyException; the first one forwards to error.jsp and the second invokes an + exception-handler method handleMyException: +

    + +@Jpf.Catch(type=MyException.class, path="error.jsp") +@Jpf.Catch(type=MyException.class, method="handleMyException") +

    + You can put this annotation in a number of places (in order of precedence): +

    +
      +
    • + Inside a + + @Jpf.Action + + annotation, which means that the exception is handled only for that action. +
    • +
    • + Inside a + + @Jpf.SimpleAction + + annotation, which means that the exception is handled only for that action. +
    • +
    • + Inside a + + @Jpf.Controller + + annotation, which means that the exception is handled for any action in the controller + class, or, if this is a page flow controller, for any page in the page flow. +
    • +
    • + Inside a + + @Jpf.Controller + + annotation in a base class controller, which means that the exception is handled for any + action in any derived controller. If this is a page flow controller, the exception is + handled for any page in the page flow. +
    • +
    • + Inside a + + @Jpf.Controller + + annotation in a shared flow controller that is referenced by + the current page flow controller. This means the exception is handled for any action or any page in + the current page flow. +
    • +
    +

    + Here is an example of a page flow controller class that uses @Jpf.Catch at the class level + and at the action method level: +

    + +@Jpf.Controller( + catches={ + @Jpf.Catch(type=Exception1.class, path="error1.jsp"), + @Jpf.Catch(type=Exception2.class, path="error2.jsp") + } +) +public class MyPageFlow extends PageFlowController +{ + @Jpf.Action( + forwards={ + @Jpf.Forward(name="success", path="success.jsp") + } + ) + public Forward begin() throws Exception1, Exception2 + { + return new Forward("success"); + } + + @Jpf.Action( + forwards={ + @Jpf.Forward(name="success", path="success.jsp") + }, + catches={ + @Jpf.Catch(type=Exception1.class, path="specialErrorPage.jsp") + } + ) + public Forward specialAction() throws Exception1, Exception2 + { + return new Forward("success"); + } +} +

    + Throughout this page flow, Exception1 and Exception2 are handled by navigating + to error1.jsp and error2.jsp, respectively. When the action + specialAction runs, it will forward to specialErrorPage.jsp if + Exception1 occurs. +

    + + If you have a set of + + @Jpf.Catch + + annotations, and more than one of them applies to a thrown + exception, then the most specific one in that set will win. Consider the following: +
    +
    +     catches={
    +         @Jpf.Catch(type=Exception.class, path="error1.jsp"),
    +         @Jpf.Catch(type=NullPointerException.class, path="error2.jsp"),
    +     }
    +
    + In this case, if NullPointerException is thrown, then error2.jsp will be + shown. +
    + +
    +
    + Handling Exceptions with Methods +

    + When you use the + + method + + attribute on @Jpf.Catch, you are signalling that you want an exception to be handled with + an exception-handler method. To make such a method, you use the + + @Jpf.ExceptionHandler + + annotation on a method with the following signature: +

    + +public Forward method-name(exception-type ex, String actionName, String message, Object formBean) +

    + The exception-type is the specific type of the exception you want to handle (or any superclass + type). +

    +

    + In general, an exception-handler method is much like an action method: it has access to member data in + the controller class, can perform logic, and chooses a navigation destination. Here is an example of + handling an exception through a method, which increments a count, logs the error, and navigates back to + the current page: +

    + +@Jpf.Controller( + catches={ + @Jpf.Catch(type=MyException.class, method="handleMyException") + } +) +public class MyPageFlow extends PageFlowController +{ + private int myExceptionsCount = 0; + + ... + + @Jpf.ExceptionHandler( + forwards={ + @Jpf.Forward(name="backToCurrent", navigateTo=Jpf.NavigateTo.currentPage) + } + ) + public Forward handleMyException(MyException e, String actionName, String message, Object formBean) + { + ++myExceptionsCount; + logger.error("My exception occurred.", e); + return new Forward("backToCurrent"); + } +} +
    +
    + Sharing Exception Handling +

    + Exception handling works well with the Page Flow inheritance + and Shared Flow features, both of which allow you to share + exception handling across multiple page flows. The documentation gives guidelines on when to use each + one. +

    +
    +
    + Displaying Exception Information +

    + There are two main ways to display exceptions using the NetUI JSP tags: +

    + +
    + The <code>Exceptions</code> tag +

    + The + + Exceptions + + tag is a simple way to display raw exception information. You can use it to show the exception + message and/or the exception stack trace. For example, the following page displays just the + exception message: +

    + +An exception occurred: + <netui:exceptions showMessage="true" showStackTrace="false"/> +
    +
    + The <code>Error</code> and <code>Errors</code> tags +

    + The + + Error + + or + + Errors + + tags are used to display localizable messages for exceptions. By default, you must have a + message resource whose name is the class name of the thrown exception in order to display + the message. Consider the following page flow controller: +

    + +@Jpf.Controller( + catches={ + @Jpf.Catch(type=IllegalStateException.class, path="error.jsp") + }, + messageBundles={ + @Jpf.MessageBundle(bundlePath="example.MyMessages") + } +) +public class Controller extends PageFlowController +{ + @Jpf.Action + public Forward begin() + { + throw new IllegalStateException("Throwing intentionally..."); + } +} +

    + Here, an IllegalStateException is thrown in the begin action, and + caught/forwarded to error.jsp, which has the following markup: +

    + +An error occurred: <netui:errors/> +

    + This will display the message named java.lang.IllegalStateException + in /WEB-INF/classes/example/MyMessages.properties. You could also use the + netui:error tag to refer to the specific exception message: +

    + +An error occurred: <netui:error key="java.lang.IllegalStateException"/> +

    + If you want to use your own message key (instead of java.lang.IllegalStateException), + you use the + + messageKey + + attribute on @Jpf.Catch: +

    + +@Jpf.Catch(type=IllegalStateException.class, path="error.jsp", messageKey="myMessageKey") +

    + Now, you would see the message under key myMessageKey in + MyMessages.properties. +

    +

    + Finally, you can also specify a hardcoded message, or a JSP 2.0-style expression, instead of a + message key. +

    + +@Jpf.Controller( + catches={ + @Jpf.Catch(type=IllegalStateException.class, path="error.jsp", message="This is a hardcoded message."), + @Jpf.Catch(type=NullPointerException.class, path="error.jsp", message="${pageFlow.class.name}") + } +) +

    + In the first case, the error tags would display the string "This is a hardcoded message". In the + second case, they would display the class name of the current page flow controller. +

    +
    +
    + +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/faq.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/faq.xml new file mode 100644 index 0000000..d9342d8 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/faq.xml @@ -0,0 +1,58 @@ + + + +
    + Frequently Asked Questions +
    + +
    How Do I Ensure that JSPs are Accessible Only Through the Controller Class? +

    To prevent users from navigating directly to a JSP +page, register the following filter class. The filter class will intercept direct requests for JSPs +and redirect the user to the Controller class in the JSP's parent directory.

    +package example; + +import java.io.IOException; +import javax.servlet.*; +import javax.servlet.http.*; + +public class JspToPageFlowFilter implements Filter +{ + public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain ) + throws IOException, ServletException + { + // Redirect to the begin method in the parent directory + String pagePath = ( ( HttpServletRequest ) request ).getContextPath() + ( ( HttpServletRequest ) request ).getServletPath(); + int lastSlash = pagePath.lastIndexOf( '/' ); + String parentDir = pagePath.substring( 0, lastSlash + 1 ); + String beginAction = parentDir + "begin.do"; + ( ( HttpServletResponse ) response ).sendRedirect( beginAction ); + } + + public void init( FilterConfig filterConfig ) + throws ServletException + { + } + + public void destroy() + { + } +} +

    Register the class in WEB-INF/web.xml as shown below:

    + <filter> + <filter-name>JspToPageFlowFilter</filter-name> + <filter-class>example.JspToPageFlowFilter</filter-class> + </filter> + + <filter-mapping> + <filter-name>JspToPageFlowFilter</filter-name> + <url-pattern>*.jsp</url-pattern> + <dispatcher>REQUEST</dispatcher> + </filter-mapping> +
    + +
    + Java, J2EE, and JCP are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.
    + © 2004, Apache Software Foundation +
    +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/index.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/index.xml new file mode 100644 index 0000000..2c612ee --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/index.xml @@ -0,0 +1,42 @@ + + + +
    + NetUI: Getting Started +
    + +

    For an introduction to the basic concepts of NetUI (Page Flow and the JSP tags), see the users guide topics:

    + +

    The following tutorial will familiarize with the basic development cycle NetUI web applications:

    + +

    + The following sample demonstrates a complete NetUI web application that uses + multiple, modular page flows, and Controls for back-end resource access:

    + +

    The following sample demonstrates individual NetUI features:

    + +

    The following sample demonstrates integration with Java Server Faces:

    + +

    The following project template will help you get a NetUI project started:

    + + +
    + Java, J2EE, and JCP are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.
    + © 2004, Apache Software Foundation +
    +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/jsf.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/jsf.xml new file mode 100644 index 0000000..3d7893b --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/jsf.xml @@ -0,0 +1,78 @@ + + + +
    + Java Server Faces +
    + +
    + Introduction +

    + JavaServer Faces is + technology for building web application user interfaces. It allows development of + very rich component- and event-based pages. NetUI Page Flow treats JSF pages as + first-class citizens. In addition to allowing the use of "straight" JSF + features, it integrates in the following ways: +

    +
      +
    • When a JSF page is accessed directly or from a Page Flow action, an + associated "backing bean" class is looked up. If it exists, an instance is + created and managed by the framework. This bean can contain JSF component + references, event handlers, etc., and it can raise Page Flow actions, + with or without form beans attached. Its lifetime is tied to the lifetime of + the JSF page. +
    • +
    • + Components in JSF pages can also raise Page Flow actions directly, with or + without form beans attached, using the built-in action attribute. +
    • +
    • + Pages can databind to NetUI objects using JSF-style expressions like + #{pageFlow.someProperty} or + #{pageInput.somePageInput.someProperty}. +
    • +
    • + A page can databind to properties in its associated backing bean through a + "backing" context, e.g., #{backing.someProperty}. +
    • +
    • When returning to a JSF page through the + navigateTo + feature, the page's component tree and its backing bean are restored. +
    • +
    +

    + The NetUI / JSF Sample demonstrates these features. +

    + +
    + +
    + Enabling Java Server Faces +

    To enable Java Server Faces in a Beehive web application, complete the following steps:

    +
    + Integrate JSF Tags in Your Web App +

    + Integrate JSF into your webapp. You can use either MyFaces v1.0.9 or later, or + the JSF Reference Implementation v1.1_01. +

    +
    +
    + Configure Your Web Application +

    Add the following snippet to your WEB-INF/faces-config.xml file:

    + <factory> + <application-factory> + org.apache.beehive.netui.pageflow.faces.PageFlowApplicationFactory + </application-factory> +</factory> +

    This goes underneath the <application> element and before the <navigation-rule> element(s).

    + +
    +
    + +
    + + Java, J2EE, and JCP are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States + and other countries.
    © 2004, Apache Software Foundation +
    +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/jspOverview.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/jspOverview.xml new file mode 100644 index 0000000..b27f59d --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/jspOverview.xml @@ -0,0 +1,206 @@ + + + +
    + NetUI JSP Overview +
    + +
    + Introduction +

    NetUI adds three tag libraries to normal JSP usage to assist with the + binding of the JSPs to the controller class. These tag libraries add a number of features such + as HTML form controls, data grids, and trees. For a detailed overview of the tag libraries + and their usage see the NetUI Tag Library Overview. The + tag library API documentation + describes all of the details. +

    +

    The tag libraries provided by NetUI are: +

    +
      +
    • <netui:xxx> -- + This is the primary tag library supporting HTML, including the form controls. In addition, + it contains the Tree support.
    • +
    • <netui-data:xxx> -- + This tag library provides binding to relational data, providing the Data Grid.
    • +
    • <netui-template:xxx> -- + This tag library provides a very simple templating facility, allowing common elements such + as headers, footers, etc.
    • +
    +

    NetUI also makes extensive use of data binding expressions + to bind the JSPs to data in the controller class. For a detailed explanation + of databinding expressions see + Databinding: Passing Data Between Controller Classes and JSPs +

    +
    +
    + Starting a NetUI JSP +

    NetUI JSPs that act as stand alone HTML pages, can use the following template as the basis + for a new page. Using this template will insure that the structure of the HTML page is valid + and that all of the features in the tag library are enabled. +

    +

    Simple NetUI JSP Template

    + +<%@ taglib prefix="netui" uri="http://beehive.apache.org/netui/tags-html-1.0"%> + + + Page Title + + + + +]]> + +

    + As with Page Flow Controllers, a certain amount + of common boilerplate text is required in each page. The first two lines should set + the content-type, the encoding, and import the base NetUI tag library. The taglib + binds the NetUI tags to the netui prefix. +

    + <%@ page language="java" contentType="text/html;charset=UTF-8"%> +<%@ taglib prefix="netui" uri="http://beehive.apache.org/netui/tags-html-1.0"%> + +

    After the common prolog, the JSP can be written like most any other JSPs. The NetUI HTML tags can + be configured to support both the HTML 4.01 spec and XHTML. See the + HTML to NetUI Tag topic to see how the NetUI tags relate to HTML. In addition to the prolog and + using the HTML tags to represent the HTML structure, <netui:base> + should be present within the <head> element. This will ensure that relative URIs are + resolved correctly. +

    +

    The resulting general + form of a NetUI JSP is as follows: +

    + <%@ page language="java" contentType="text/html;charset=UTF-8"%> +<%@ taglib uri="http://beehive.apache.org/netui/tags-html-1.0" prefix="netui"%> +<netui:html> + <head> + <title>...</title> + <netui:base/> + </head> + <netui:body> + .. + .. + .. + </netui:body> +</netui:html> +
    + +
    + Simple Linking +

    + The <netui:anchor> tag replaces the normal <a> + HTML anchor tag. A plain HTML <a> links directly from one URL to + another and doesn't provid the controller an opportunity to perform any conditional + logic. Using the <netui:anchor> tag you can specify an action in a + Page Flow controller which will run when the link is pressed. +

    +

    While it may seem silly to use NetUI tags for simple + constant forward methods, the advantage is that if a page + gets renamed or you wish to change the flow through an application, + the destination only needs to be changed once, within the controller. + Otherwise, you may have to edit a handful of JSPs manually + changing the URLs inside normal <a> tags. +

    +

    In addition, the <netui:anchor> tag supports many additional features such as submitting + forms and popup windows. +

    +
    + Linking Example +

    Initially, we will examine simple linking through a controller to another JSP using the + Page Flow controller introduced earlier. +

    +

    implementation page flow +

    +

    If your application changes and you desire to show a + terms-of-service before allowing login, you can simply alter the login() + controller method to send a user to terms_of_service.jsp before + further sending him to the actual login screen. Instead of specifying the URL to another + page using the HTML <a> tag, we use the <netui:anchor> and specify the name of the action + on the controller to call. +

    +

    Instead of using <a> +

    + + <a href="login.jsp">Login!</a> + +

    Use <netui:anchor> +

    + + <netui:anchor action="login">Login!</netui:anchor> + +

    When the link is displayed on-screen, clicking it will cause control to + go through the Controller's login() method, + which will return the correct forward to select the actual next page to + display. +

    +

    If you want to add the term-of-service page, you can simply modify the action in the + Page Flow controller to go to the newly created JSP. The advantage is that the + flow of control is stored in the Page Flow controller and not in the pages themselves. +

    +
    +
    + +
    + Handling Forms +

    To post data from forms to Page Flow controller's action handling the form post, + the <netui:form> container tag, along with + specialized NetUI form control tags that replace the normal form elements are used within + a JSP. Similar to how <netui:anchor> replaces + normal HTML <a> tags, the <netui:form> + tag replaces the typical HTML <form> tag. In addition, + the NetUI form control tags replace the typical HTML form controls. +

    + +
    + Form Example +

    Instead of using <form> +

    + + <form action="LoginServlet" method="POST"> + +

    Use <netui:form> +

    + + <netui:form action="processLogin" method="POST"> + +

    The other tags typically used with a <form> also have + replacements from the NetUI tag library. +

    +

    For the processLogin(...) form-processing method, the matching JSP form would be: +

    + + +<netui:form action="processLogin" method="POST"> + <netui:textBox dataSource="actionForm.username" size="20"/> + <netui:textBox dataSource="actionForm.password" size="20" password="true"/> + <netui:button type="submit" value="Login"/> +</netui:form> + +

    When the user submits the form by clicking upon the Login button, an instance of + the LoginForm subclass of FormData is created and passed to the + processLogin(LoginForm form) method of the controller class. +

    +
    +
    + +
    + Next... + +

    + Next, learn about how to compile and package up a complete web project. +

    + + +
    + + + +
    + + Java, J2EE, and JCP are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.
    + © 2004, Apache Software Foundation +
    +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/lifecycleAndState.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/lifecycleAndState.xml new file mode 100644 index 0000000..96efd97 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/lifecycleAndState.xml @@ -0,0 +1,231 @@ + + + +
    + NetUI State Management and Lifecycle +
    + +
    + Introduction + +
    + State Management +
    + Page Flow State Management +

    + When you hit the URL for a page flow (or any of its actions, or any of its pages) for the first + time, an instance of the controller class is created and stored in the user session. By default, + it stays in the session as the current page flow until you hit another page flow. + This means that while you continue to hit URLs in the page flow's URL space, it + remains the current page flow. When you do hit another page flow, the original controller + instance is destroyed. In other words, by default there is only a single page flow + controller stored in the session at one time. +

    + + Nested page flows have special rules + associated with them: when you hit a nested page flow, the current page flow is pushed aside, + and it is restored when you return from the nested page flow. You can also abnormally + exit a nested page flow by hitting a "regular" (non-nested) page flow while you're still + in the nested flow. In that case, the original page flow (the one that was pushed aside) is + discarded. + +

    + The auto-cleanup of a controller instance is normally helpful in keeping your session small and + focused on the task at hand. In some cases, you may want to create a "long-lived" page flow + controller that never gets destroyed (until the session itself ends). In this case, + you simply set the + + longLived + + attribute to true on + + @Jpf.Controller: +

    + +@Jpf.Controller(longLived=true) +public class MyLongLivedPageFlow extends PageFlowController +{ + ... +} +

    + Now, whenever this page flow is hit for the first time, it is stored in the session, and is not + removed even when another page flow becomes the current page flow. Each time you hit the URL for + this page flow (or any of its actions, or any of its pages), the same instance is + restored. +

    +

    + You can remove this long-lived controller instance explicitly by calling its + + remove() + + method. +

    +
    +
    + Shared Flow State Management +

    + Whenever you hit a page flow, each of its referenced + shared flow controllers + is created and stored in the session. If a shared flow controller of the right type already + exists in the session, that instance is used instead. Once one is created, it is not removed + unless you call its + + remove() + + method, or + + PageFlowUtils.removeSharedFlow(). +

    +
    +
    + State Management for JavaServer Faces "Backing Beans" +

    + When you hit a JSF page (e.g., "/mydir/mypage.faces"), the NetUI runtime looks for a class + with the same name and package (e.g., mydir.mypage). If this class exists, is + annotated with + + @Jpf.FacesBacking, and extends + + FacesBackingBean, then an instance is created and stored in the session. + It is removed from the session on the next request that is not for the same page. +

    +

    + See Java Server Faces for more details on JSF + integration with NetUI. +

    +
    +
    + +
    + Lifecycle +

    + All NetUI-managed objects (page flow controllers, shared flow controllers, JavaServer Faces + "backing beans") are driven through a lifecycle, with callbacks in the appropriate places. + This lifecycle always includes: +

    +
      +
    • + onCreate - when the object is created by the runtime. +
    • +
    • + onDestroy - when the object is "destroyed" (removed) by the + runtime. +
    • +
    +

    + To run code at either of these points in the lifecycle, you simply override the appropriate method + (onCreate + or + onDestroy), e.g., +

    + +@Jpf.Controller +public class MyPageFlow extends PageFlowController +{ + protected void onCreate() + { + // do something to initialize this page flow controller + } + + ... +} +
    + Controller Lifecycle +

    + Flow controllers (page flow controllers and shared flow controllers) have additional methods as + part of their lifecycle: +

    + +

    + Again, to run code at either of these points, override the appropriate method, e.g., +

    + +@Jpf.Controller +public class MyPageFlow extends PageFlowController +{ + protected void beforeAction() + { + log.debug("before action " + getCurrentActionName() + ", request " + getRequest().getRequestURI()); + } + + ... +} +

    + Additionally, nested page flows have + an additional lifecycle method: +

    + +
    +
    + JavaServer Faces "Backing Bean" Lifecycle +

    + JSF backing beans (extended from + + FacesBackingBean) + have one additional lifecycle method: +

    + +
    +
    +
    + +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/nestedPageFlow.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/nestedPageFlow.xml new file mode 100644 index 0000000..6b298c1 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/nestedPageFlow.xml @@ -0,0 +1,386 @@ + + + +
    + Nested Page Flows +
    + +
    + Introduction +

    + By default, executing an action in a new page flow causes the current page flow to be discarded. This + behavior allows you to create separate controllers for different sections of your project, and it + minimizes the amount of data kept in the user session at one time. Each page flow manages its own state + and logic. "Nested page flows" give you an even greater ability to break up your project into separate, + self-contained bits of functionality. At its heart, "nesting" is a way of pushing aside the current + page flow temporarily and transferring control to another page flow with the intention of coming back + to the original one. +

    +

    + So when would you use this? Nesting is useful when you want to do one of the following tasks: +

    +
      +
    • + gather data from the user, for use in the current + page flow; +
    • +
    • + allow the user to correct errors or supply + additional information en route to executing a + desired action; +
    • +
    • + show an alternate view of data represented in the + current page flow; +
    • +
    • bring the user through a "wizard";
    • +
    • + show the user information that will be useful in the + current page flow (e.g., help screens can be easily + implemented as nested page flows); and +
    • +
    • + in general, to further break up your application + into separate (and in many cases reusable) pieces. +
    • +
    +
    +
    + Basics +

    + Let's start with a very simple example. You can find the code for this under basicNesting + in the NetUI Samples application. Here, we have a "main" + page flow which forwards to a nested page flow, which later returns to the main page flow. The flow + looks like this: +

    +

    + main page flow +

    +

    + Here is the code for the main page flow: +

    + +@Jpf.Controller( + simpleActions={ + @Jpf.SimpleAction(name="begin", path="index.jsp"), + @Jpf.SimpleAction(name="goNested", path="../nested/NestedFlow.jpf"), + @Jpf.SimpleAction(name="nestedDone", path="success.jsp") + } +) +public class MainFlow extends PageFlowController +{ +} +

    + As you can see, the begin action forwards to index.jsp, which allows you to + raise the goNested action. This action enters the nested page flow simply by + forwarding to it. Any time you hit the URL for a nested page flow (or any one of its actions or + pages), you enter the nested page flow, and the current one is pushed aside. +

    +

    + When the nested page flow returns, it causes the nestedDone action to run, and this action + simply forwards to success.jsp +

    +

    + So how does the nested page flow return to the current one, and raise the nestedDone + action? Here is the code for the nested flow: +

    + +@Jpf.Controller( + nested=true, + simpleActions={ + @Jpf.SimpleAction(name="begin", path="index.jsp"), + @Jpf.SimpleAction(name="done", returnAction="nestedDone") + } +) +public class NestedFlow extends PageFlowController +{ +} +

    + Note the + + nested + =true, + which defines this as a nested page flow. Also note the + + returnAction + + attribute on the simple action done. When this action is executed, it returns to the + original page flow (MainFlow) and raises its nestedDone action. This is + called an exit point of the nested page flow. +

    +

    + The nested flow looks like this: +

    +

    + nested page flow +

    +
    +
    + More Nested Page Flow Features +

    + Often, you want to do more than simply invoke and return from a nested page flow. For instance, you may + want to gather data from a nested page flow, for use in the current page flow. In the example below + (found under nesting in the NetUI Samples + project), the user is forwarded to a nested page flow + (/nesting/chooseAirport/chooseAirport.jpf), + which is a wizard that helps the user find an airport. The nested page flow returns the chosen airport + to the original page flow, which continues with its sequence. First, here is a diagram of the main page + flow: +

    +

    + main page flow +

    +

    + This page flow demonstrates two new features related to nesting: +

    +
      +
    • + The nested page flow returns a form bean (ChooseAirport.Results) when it raises the + chooseAirportDone action. +
    • +
    • + If the nested page flow raises a chooseAirportCancelled action, the page flow will go + back to the most recent page shown to the user., whatever that page is. +
    • +
    +
    + Returning data from a nested page flow +

    + Here is a diagram of the nested page flow ChooseAirport.jpf, with the "happy path" to + the chooseAirportDone return-action hightlighted in red: +

    +

    + Choose Airport nested page flow +

    +

    + During the course of this page flow, a member variable called _currentResults, of type + ChooseAirport.Results is kept. As the user moves through the page flow, possibly re-trying + and changing the desired result, this member variable is kept up-to-date. In the end, it is + returned as an "output form bean" along with the chooseAirportDone return-action, + using the + + outputFormBean + + attribute. This is what it looks like in the annotations: +

    + + @Jpf.SimpleAction(name="confirmResults", returnAction="chooseAirportDone", outputFormBean="_currentResults") +

    + This annotation simply specifies that the value of _currentResults will be sent along with + the return-action chooseAirportDone. +

    + + You do not have to return a member variable as an output form bean. If you just want to return a + local variable, you would use the + + outputFormBeanType + + attribute instead, and you would pass the bean on the + + Forward + + object returned from an action method, like this: +
    +
    +     @Jpf.Action(
    +         forwards={
    +      +         @Jpf.Forward(name="done", + returnAction="chooseAirportDone", outputFormBeanType=Results.class) + +
    +         }
    +     )
    +     public Forward confirmResults()
    +     {
    +         Results results = initialize a Results object
    +         return new Forward("done", results);
    +     } +
    +

    + In the original page flow, there is a + chooseAirportDone method that accepts this form bean as an argument, like this: +

    + +@Jpf.Action( + ... +) +protected Forward chooseAirportDone(ChooseAirport.Results results) +{ + ... +} +

    + As you can see, the page flow handles this returned form bean just like it would handle a form + bean posted from a page. +

    +
    + +
    + Passing Data to a Nested Page Flow +

    + Sometimes you will want to pass data into a nested page flow. While this may be less common than + returning data from a nested page flow, it is useful for initializing data in the flow. To do this, + you will add a form bean to the begin action of the nested page flow, and in the + calling page flow you will pass an instance of this bean on the + + Forward + + object that is sent to the nested page flow. +

    +
    + Add a form bean to the nested page flow's <code>begin</code> action +

    + To add a form bean, simply add a single argument to a begin action method: +

    + +@Jpf.Action( + forwards={ + @Jpf.Forward(name="index", path="index.jsp") + } +) +public Forward begin(InitBean initBean) +{ + ... +} +

    + The bean type can be any class of your choosing; for instance, you can make it a + String, which means that the nested page flow requires a String to + be initialized: +

    + +@Jpf.Action( + forwards={ + @Jpf.Forward(name="index", path="index.jsp") + } +) +public Forward begin(String initString) +{ + ... +} +
    +
    + Pass the form bean from the calling page flow to the nested page flow +

    + You can pass the initialization bean to the nested page flow by adding it to the + + Forward + + object that is sent to the nested page flow: +

    + +@Jpf.Action( + forwards={ + @Jpf.Forward(name="nestedFlow", path="/nested/NestedFlow.jpf", outputFormBeanType=InitBean.class) + } +) +public Forward goNested() +{ + InitBean initBean = initialize the bean + return new Forward("nestedFlow", initBean); +} +

    + Note that the + + outputFormBeanType + + annotation attribute is optional; it mainly helps tools understand the output of the action, and + it ensures that an incompatible type will not be passed. +

    +
    +
    +
    +
    + Other Notes +

    + Here are some other notes about using nested page flows: +

    +
      +
    • + Aside from the + + nested=true + + on the + + @Jpf.Controller + + annotation, and defining exit points through + + returnAction, + nested page flows are built just like other non-nested page flows. +
    • +
    • + You enter a nested page flow by hitting its URL, by hitting the URL for any of its actions, or by + hitting the URL for any of its pages (pages in the same directory path). When nesting occurs, the + original page flow is pushed onto the "nesting stack", and is popped off the stack when the nested + page flow hits an exit point (through a + + returnAction + + attribute). +
    • +
    • + Nested page flows can nest themselves. +
    • +
    • + + While in a nested page flow, you can get a reference to the calling page flow through + + PageFlowUtils.getNestingPageFlow(). +
    • +
    +
    + + +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/overview.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/overview.xml new file mode 100644 index 0000000..4464d66 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/overview.xml @@ -0,0 +1,581 @@ + + + +
    + NetUI Overview +
    + +
    + Introduction +

    + NetUI is the piece of Beehive used to build the + front-end of a web application. It contains two pieces: + Page Flow and a powerful set of JSP tags. +

    +
    +
    + Why Use NetUI? +

    + Simply put, NetUI (Page Flow and a powerful set of JSP + tags) helps you build a well-structured web application + using a simple programming model. +

    +

    + First, because NetUI is an MVC framework (built on + Apache Struts + ), it separates navigational control from presentation. + This avoids: +

    +
      +
    • Limited reuse of navigational/flow logic.
    • +
    • Cluttered, hard-to-maintain JSP source code.
    • +
    • + Difficulty in understanding the flow of an + application. +
    • +
    • + Unintended exposure of controller-logic code to team + members who focus on other aspects of web + development, such as content writers and visual + designers. +
    • +
    +

    + Second, NetUI provides the Page Flow programming model + which allows you to create + modular + "page flows" that can be inserted (and reused) inside of + other flows. At root, it unifies the controller + logic, state, and metadata for a piece of your + application into a single class. On the View side, it + offers a rich set of tags, such as the + Tree + and the + Datagrid + . +

    +
    +
    + NetUI Features +

    + NetUI makes building Java web applications easy and + intuitive. When building applications with NetUI, the + developer writes Java classes and pages --that's it. + There is very little occasion to work with configuration + files, or other components. NetUI also excels at + separating presentation logic from data processing + logic, resulting in uncluttered JSP code which is easy + to understand and edit. Data processing and the web + application configurables are handled in a single Java + class using a simple declarative programming model. +

    +

    + Declarative Programming +

    +

    + Many common web app programming tasks are accomplished + through a declarative programming model using + "annotations", a new feature in Java 5. Annotations put + configuration information (in general, "metadata") right + alongside your code, alleviating the need for + independent configuration files. Navigation, exception + handling, validation, and other tasks are all defined in + a single Java class: the Page Flow "controller" class + that drives a piece of your web application. +

    +

    + Stateful Page Flows +

    +

    + When a user enters a page flow (by hitting an URL in the + page flow's URL space), an instance of the page flow's + controller class is created. While the user is in the + page flow, the controller instance simply stores the + flow-related state in member variables. Methods within + the class -- particularly action methods and exception + handlers -- have access to the member state. By default, + the state is + automatically cleaned up + when the user leaves the page flow to enter another one. + This behavior can be configured per-page flow, but + auto-cleanup helps keep your session small, and focused + on the task at hand. +

    +

    + Modular Page Flows +

    +

    + A single web application can have multiple page flows + within it, allowing you to break up the application into + separate, self-contained chunks of functionality. For an + example, see the + + Petstore Sample + + , which has different page flows for browsing the + Petstore, buying products, and handling user accounts. +

    +

    + Inheritance and Shared Flow +

    +

    + Page Flow inheritance is a powerful way to share actions, + exception handlers, configuration, etc. among controller classes. It is normal Java inheritance, + plus the ability to inherit/merge annotations. +

    +

    + Shared Flow provides an alternative way to make actions and + exception handlers available to multiple page flows. The feature is useful for accessing shared state, + for shared/templated user interface, and when you cannot change your controller class hierarchy. +

    +

    + Nested Page Flows +

    +

    + An entire page flow can be inserted, or "nested", inside of another page flow. At its heart, + nesting + is a way of pushing aside the current page flow temporarily and transferring control to another (nested) + page flow with the intention of coming back to the original one. Nesting is useful when you want to do + one of the following tasks: +

    +
      +
    • + gather data from the user, for use in the current + page flow; +
    • +
    • + allow the user to correct errors or supply + additional information en route to executing a + desired action; +
    • +
    • + show an alternate view of data represented in the + current page flow; +
    • +
    • bring the user through a "wizard";
    • +
    • + show the user information that will be useful in the + current page flow (e.g., help screens can be easily + implemented as nested page flows); and +
    • +
    • + in general, to further break up your application + into separate (and in many cases reusable) pieces. +
    • +
    +

    + NetUI also offers special integration between nested + page flows and + popup windows. +

    +

    + + Declarative Exception Handling and Validation + +

    +

    + Exception handling and + data validation + are accomplished through a declarative programming + model. The desired exception handling and validation + behaviors are declared in the controller class + (and additionally on form bean classes, for validation) + alongside your Java code in the form of metadata + annotations. This allows for single file editing and + eliminates the need for separate configuration files. +

    +

    + Powerful JSP Tags +

    +

    + NetUI provides three tag libraries: (1) one library + represents the core HTML tags, (2) another renders data + grids and complex data sets as HTML, and (3) a third + library provides page templating functionality. +

    +

    + The NetUI tags also support data binding (1) to JSP + implicit objects (through the JSP 2.0 Expression + Language) and (2) to other NetUI implicit objects. Note + that many tags possess read-write access to these + implicit objects. +

    +

    + + First-class Integration with JavaServer Faces + +

    +

    + NetUI has solid integration with JavaServer Faces. It treats JSF as a + first-class view tier, where, for example, JSF components and command handlers can raise Page Flow + actions, can databind to NetUI implicit objects, etc. +

    +

    + Struts Integration +

    +

    + Page Flow is built on top of Apache Struts 1.1. Each + Page Flow controller is compiled into a Struts module. + As a result, NetUI and Struts applications can work + closely together. +

    +

    + Struts modules and page flows can co-habitate and + interact with one another inside a web app. To forward + from a page flow to a (pure) Struts module, simply + reference the desired action within the Struts module. + The same goes for the reverse direction: from a Struts + module, simply configure an action to point to the + desired method in the page flow. + +

    +

    + You can also use the Struts merge feature to read + configuration data from a pure Struts app into your Page + Flow app's configuration files. Ordinarily, your Page + Flow's configuration files are generated entirely from + your application's JAVA source files (specifically from + the + metadata annotations + that decorate the controller classes). But, in cases + where you want to integrate a Struts module into your + application, you can specify that the configuration + files be generated from + both + the JAVA source files + and + the Struts module's configuration files, allowing you to + change or add + any tag + in the generated configuration file. For example, + suppose you want to override an action form's default + scoping from request-scoping to session-scoping. To do + this, you simply create a Struts configuration file that + overrides the appropriate parts of the Page Flow's + configuration file, and then refer to this override file + from within the Page Flow's JAVA source file (= the + controller class) using a special annotation. In + particular, you would specify the override file to state + that such-and-such an action form should have + session-scope rather then request-scope (so that the + action form can now be shared with the Struts app). +

    +
    +
    + The Logical Flow + +

    + Writing traditional web applications without a Page Flow + controller class requires a fair amount of logic to be + applied within the application's pages. For example, a + site that provides a "My Page" functionality for logged + in users would have to include logic on the home page to + determine if the "My Page" link should take the user to + the login form or directly to their customized page. +

    + +

    + Using a page flow, the home page of the application + would not link directly to either the login page + or + the user's "My Page" location, but rather would point + back into Java code that makes the decision. +

    + +

    + For the rest of this overview, the following + logical page flow + will be used: +

    + +

    + logical page flow +

    + +

    + This flow supports several routes from the home page of + the application to the user's "My Page": +

    + +
      +
    1. +

      + The user may directly navigate from + index.jsp + to + mypage.jsp + (by clicking a link), if the user is already + logged in. +

      +
    2. +
    3. +

      + If the user is not already logged in, attempts + to navigate from + index.jsp + to + mypage.jsp + will be intercepted and the user will be taken + to the + login.jsp + instead. After successfully logging in, the user + will be automatically taken to + mypage.jsp +

      +
    4. +
    5. +

      + The user may directly navigate from + index.jsp + to + login.jsp + (by clicking a link). After logging in, the user + will be automatically taken to + mypage.jsp + . +

      + +

      + In the event of a login failure, + login.jsp + will be redisplayed to give them another + opportunity to authenticate themselves. +

      +
    6. +
    7. +

      + If the user desires to register with the site, + he can click a link that will take him to + signup.jsp + . One signed up, the + thanks.jsp + will be displayed which offers a link to the + login.jsp + page. +

      +
    8. +
    + +
    + +
    + + The Implementation of the Flow: Controllers and Actions + + +

    + In the above + logical flow + there are several + if + statements that cause the user flow to vary depending on + their previous actions and other state. +

    + +
      +
    • + If the user is not logged in... +
    • +
    • + If the user is logged in... +
    • +
    • + If the user's login attempt fails... +
    • +
    + +

    + NetUI moves this condition logic out of the JSPs and + into a Java class that controls the movement through the + application. This Java class is the + controller + portion of the + Model-View-Controller + (MVC) pattern. This allows a page to be written, for + example, that appears to link directly from the home + page of the application to the user's "My Page". The + controller is given the opportunity to intercept the + navigation between the two and redirect the user to the + login page, if required. +

    + +

    + Each of the interception points is an + action + of the particular controller class. Actions perform + common application tasks. Here are some of the things + that an action can do: +

    + +
      +
    • navigate the user to a specified JSP
    • +
    • perform conditional logic
    • +
    • handle submitted data
    • +
    • validate submitted data
    • +
    • handle exceptions that arise in the application
    • +
    + +

    + Note that controller classes, and the actions they + contain, are + URL addressable + . Hitting the following URL creates an instance of the + controller class + foo.MyControllerClass + and runs its + begin + action. (When no other action is specified, the + begin + method is run by default.) +

    + + http://some.domain.com/foo/MyControllerClass.java + +

    + Hitting the following URL creates an instance of + foo.MyControllerClass + (if it doesn't already exist) and invokes the + someAction + action. Note that the controller class isn't mentioned + by name: it's assumed that only one controller class + exists in the directory, so there is only one candidate + controller class to instantiate. +

    + + http://some.domain.com/foo/someAction.do + + To make a Page Flow controller handle a default + directory URL, e.g., +
    +
    +     http://some.domain.com/myApp/myPageFlow +
    +
    + you will need to add the page flow's URL to the + welcome-file-list + in + /WEB-INF/web.xml + : +
    +
    +     <welcome-file-list> +
    +       <welcome-file>Controller.jpf</welcome-file> +
    +       <welcome-file>index.jsp</welcome-file> +
    +     </welcome-file-list> +
    +
    + This would cause the following URL to be hit for the + above example: +
    +
    +     http://some.domain.com/myApp/myPageFlow/Controller.jpf +
    +
    + On some servers (like Tomcat), you would also need to + make sure that a + file + called + Controller.jpf + also exists in the web content under + /myPageFlow + , even though the class + myPageFlow.Controller + actually handles the request. (The file can be blank.) +
    + +

    + Actions may perform any required complex logic. For + example, if a user clicks on the "My Page" link, the + action may check if the user is logged in, and if so, + navigate the user to the + mypage.jsp + page; otherwise it will navigate the user to the + login.jsp + page. +

    + +

    + With normal HTML pages, each page is linked directly to + other pages. +

    + +
      +
    • + page > page > page > page +
    • +
    + +

    + When using page flows, pages and actions are interwoven, + transparently. +

    + +
      +
    • + + page > action > page > action > page + > action > page + +
    • +
    + +

    + The above + logical page flow + can be redrawn with Page Flow controller actions in + mind, as: +

    + +

    + implementation page flow +

    + +

    + Now it is apparent that to navigate from + index.jsp + to + mypage.jsp + , the user traverses across the + myPage + action. This action performs the necessary check to + determine if the user has already been authenticated. If + the user has logged in already, it will direct the user + straight to + mypage.jsp + ; otherwise it will direct the user to + login.jsp + . +

    +
    +
    + Next... + +

    + Next, learn about writing a + controller + class with actions. +

    + + +
    + +
    + + Java, J2EE, and JCP are trademarks or registered trademarks + of Sun Microsystems, Inc. in the United States and other + countries. +
    + © 2004, Apache Software Foundation +
    +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/pageFlowControlContainer.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/pageFlowControlContainer.xml new file mode 100644 index 0000000..f7f55f4 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/pageFlowControlContainer.xml @@ -0,0 +1,104 @@ + + + +
    + NetUI Control Container +
    + +
    + Introduction +

    This document describes how the NetUI page flow runtime implements the container for hosting + controls. Controls run within a runtime container which provides services to controls. Within the page flow + runtime, the + org.apache.beehive.controls.api.context.ControlBeanContext is the base class that provides the extended + services to contained controls. The container is managed by the page flow runtime. This document describes the + details of the contract that is maintained for controls hosted in page flows by the implementation. +

    +
    +
    + Description of the Control Container +

    This section describes the implementation of the Control container within the page flow runtime. +

    +
    + Scope of the Control +

    There are three scopes that the control container implementation provides for controls. The first is + at the page flow level. Each page flow, PageFlowController, provides its own + ControlBeanContext to the controls which are defined within the scope of that page flow. The + second scope is the shared flows, SharedFlowController. All shared flows and the + GlobalApp share a single ControlBeanContext. The final scope is for JSF Backing + Beans, FacesBackingBean. Just as with page flows, faces backing beans have a + ControlBeanContext that is scoped to their life time. The result is that the + ControlBeanContext containing controls has the same lifetime as the object that defines + and uses the control instances. +

    +
    +
    + Single Threaded Page Flow Code +

    There are three places in the handling of a request where page flow code provides synchronization of multiple + threads. Page flows and shared flows are scoped into a ServletSession. It is possible to have + multiple threads running. This can happen if you have multiple browser windows sharing a session, or if you have + multiple requests from a single page containing frames. + Multiple requests can be generated through HTML frames or AJAX calls. The + page flow runtime insures that multiple threads are not executing code inside of a page flow. A shared flow can + potentially have multiple threads running through it which will be described below. +

    +

    + There are three synchronization points in the page flow runtime: +

    +
      +
    • onCreate -- The onCreate event is synchronized and only one thread will ever pass through + this method during the life of the page flow. +
    • +
    • beforeAction / action / afterAction -- These three methods are run in a single synchronization block meaning + these method will run together within one thread, without another thread running through the page flow. +
    • +
    • JSP Rendering -- The page flow runtime synchronizes on the current page flow during JSP rendering. This + prevents a thread from running and action on a page flow while another thread is rendering a JSP which may be + accessing page flow state. +
    • +
    +

    Each of these synchronization points will run the resource events on the controls contained inside + of the container. This will cause the onAcquire and onRelease resources events + to be triggered on all of the controls within the container. These events will be run on the current page + flow and also the shared flow. In reality, the onAcquire method is run before the first + method invocation is done on a control. onRelease will only be run if the onAcquire + mehtod has been run. The shared flow ControlBeanContext has a lock associated with it that + must be obtained before user code can be run. +

    +

    The synchronization point result in the following, all access to a control is single threaded. If a + control acquires a resource such as a JDBC connection, it will only be used for a single request. This model + also ensures that shared flows are accessed in a single threaded model when there is an instance of a control + in any shared flow because of the lock associated with the shared flow ControlBeanContext. + Finally, if there is a shared flow ControlBeanContext we will serialize all threads within a session + when they run through user code. This ensures a single threaded model for controls defined in shared flows. +

    +
    +
    + Programatic Creation of Controls +

    The ControlBeanContext is lazily created when possible. When a page flow is created, the page flow is searched + for fields with @control annotations. If any of these are found, the ControlBeanContext + is created. The shared flow ControlBeanContext is created when the first shared flow containing a + control annotation is created. +

    +

    For page flows that want to create a control programmatically using java.beans.Beans.instantiate, + you must ensure that the context has been created. The following two lines of code will create the + ControlBeanContext and make sure the beginContext method is called correctly. +

    + +PageFlowControlContainer pfcc = + PageFlowControlContainerFactory.getControlContainer(getRequest(),getServletContext()); +pfcc.createAndBeginControlBeanContext(this,getRequest(),getResponse(),getServletContext()); + +
    +
    + +
    + + Java, J2EE, and JCP are trademarks or registered trademarks + of Sun Microsystems, Inc. in the United States and other + countries. +
    + © 2006, Apache Software Foundation +
    +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/pageFlowControllers.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/pageFlowControllers.xml new file mode 100644 index 0000000..fcb1adc --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/pageFlowControllers.xml @@ -0,0 +1,721 @@ + + + +
    + Page Flow Controllers +
    + + +
    + Introduction + +

    + This topic explains the basics behind implementing controller files and + actions. + As introduced in the previous topic (NetUI Overview) the + following web application schematic will be used. +

    + +

    + implementation page flow +

    + +
    + +
    + Starting the Controller Class +

    + The first step to writing a controller class is to create a new basic class + named Controller.java. +

    + +public class Controller +{ +} + + +import org.apache.beehive.netui.pageflow.PageFlowController; + +public class Controller + extends PageFlowController +{ +} + +

    + Additionally, Beehive weaves magic into controller classes using metadata annotations. + The + + @Jpf.Controller + + annotation is a required marker on any NetUI controller class. The @Jpf.Controller + annotation alerts the compiler that this class is a special Page Flow controller class, instead + of a typical Java class. +

    + + +import org.apache.beehive.netui.pageflow.PageFlowController; +import org.apache.beehive.netui.pageflow.annotations.Jpf; + +@Jpf.Controller +public class Controller + extends PageFlowController +{ +} + +

    +

    + Now we have the beginnings of a controller implementation. +

    + +
    + +
    + Fleshing Out the Controller + +

    + Now that the boilerplate Controller.java is in place, we can begin + to implement the actions that determine which JSP should actually be displayed. + In the above + model, there are 5 actions, plus one more action required by all Controller classes, the + begin method. (Details about the begin method appear below.) +

    + +
      +
    • begin
    • +
    • login
    • +
    • myPage
    • +
    • signUp
    • +
    • processLogin
    • +
    • processSignUp
    • +
    + + +

    There are two basic ways to implement actions: you can implement an action either as a + (1) simple action + or as an + (2) action method.

    + +

    Simple Actions are class-level annotations, that is, annotations that decorate the + controller class. (You can also think of simple actions as configurations + of the controller class. If you are familiar with Struts, it might help you to know that + simple actions turn into <action> elements in the struts-config.xml file that is + automatically generated when a controller class is compiled.) Syntactically they appear as follows:

    + + @Jpf.Controller( + simpleActions={ + @Jpf.SimpleAction( name="someName", path="somePage.jsp", [...other properties...] ) + } +) +public class Controller +{ +... +} + +

    Simple actions can handle navigation, form submission, and form validation. + If that is all your action needs to accomplish, you should implement the action as + a simple action. What simple actions can't do is handle decision logic. If your action + needs to make a decision and conditionally execute code based on that decision, you should + implement the action as an action method.

    + +

    Action Methods are Java methods that have been endowed with all of the magic of + actions: that is, they can navigate users around the page flow, handle form submissions, validate form + data, handle decision logic, etc. (You can also think of the action methods as + configurations of individual methods, in contrast to simple actions, which configure the + entire class. Again, if you are familiar with Struts, know that + action methods, just like simple actions, are complied as <action> elements in the + struts-config.xml file.) Syntactically speaking, an action method is a Java method that + (1) returns the type + + Forward + + and (2) is + decorated with the + + @Jpf.Action + + annotation: +

    + @Jpf.Action( + forwards = { + @Jpf.Forward( name="someName", path="somePath.jsp", [...other properties...] ) + } + ) + public Forward someMethod() + { + ... + } +
    + Simple Actions +

    + Three of our five actions are purely navigational, and, as such, + implementable as simple actions. + Those actions are begin, login, and signUp. + The remaining actions require object oriented programming, + so they will be implemented as action methods. +

    + +

    The simple action implementations appear below. The following + + @Jpf.SimpleAction + + annotations define a set of mappings between action names + and JSP destinations. When a particular action is invoked, + the user is carried to the corresponding JSP.

    + Each Controller class requires a simple action or action method named + begin--without it the class will not compile. The begin action + functions as the entry-point into the page flow. In this case the begin action + simply navigates the user to the index.jsp page. + +import org.apache.beehive.netui.pageflow.PageFlowController; +import org.apache.beehive.netui.pageflow.annotations.Jpf; + +@Jpf.Controller( + simpleActions={ + @Jpf.SimpleAction(name="begin", path="index.jsp"), + @Jpf.SimpleAction(name="login", path="login.jsp"), + @Jpf.SimpleAction(name="signUp", path="signup.jsp"), + } +) +public class Controller + extends PageFlowController +{ +} + + +
    + + +
    + Action Methods + +

    + Now it is time to re-implement the three action methods: login, + processLogin, and processSignUp. +

    +

    + The myPage action + must determine if the user has already authenicated himself or not and the action must + behave differently depending on the + result of that determination. If the user + has already been authenticated, then the page myPage.jsp will be displayed; + if the user has not been authenticated yet, then the page login.jsp will + be displayed. +

    + +

    We will implement this behavior in two steps: (1) first will implement a rudimentary action + method, (2) second we will add the conditional navigational behavior to the method.

    + +
    + Rudimentary Action Methods: Constant Forwards + +

    + An action method must have two features: + (1) it must the type + + Forward + + and (2) must be decorated with the + + @Jpf.Action + + annotation. +

    +

    + The first step in the re-implementation process is to remove the simple action named + mypage and replace it with a method named myPage(). By returning a + + Forward + + object, the method indicates which page to + display to the user. +

    + +import org.apache.beehive.netui.pageflow.Forward; +import org.apache.beehive.netui.pageflow.PageFlowController; +import org.apache.beehive.netui.pageflow.annotations.Jpf; + +@Jpf.Controller( + simpleActions={ + @Jpf.SimpleAction(name="begin", path="index.jsp"), + @Jpf.SimpleAction(name="login", path="login.jsp"), + @Jpf.SimpleAction(name="signUp", path="signup.jsp"), + @Jpf.SimpleAction(name="processLogin", path="mypage.jsp"), + @Jpf.SimpleAction(name="processSignUp", path="thanks.jsp") + } +) +public class Controller + extends PageFlowController +{ + + public Forward myPage() + { + ... + } + +} + + +

    + To help with configuration and to avoid having JSP + names within the body of a controller method, Beehive once + again uses annotations. The Jpf.Action and + Jpf.Forward annotations are used on each action method to + build a mapping between forward names and + JSPs. The method + then works only in terms of the forward name, and doesn't + directly refer to the JSP path. +

    + +

    + The general form the of Jpf.Action/Jpf.Forward annotations are: +

    + + +@Jpf.Action( + forwards = { + @Jpf.Forward( name="...", path="..." ), + @Jpf.Forward( name="...", path="..." ), + @Jpf.Forward( name="...", path="..." ) + } +) + + +

    + By convention, forward names such as success and failure + are used, but by no means are required. It is good practice, though, to avoid naming the + forward based upon the JSP name since doing so would remove some of the decoupling that + Beehive applications attempt to achieve. +

    + + +import org.apache.beehive.netui.pageflow.Forward; +import org.apache.beehive.netui.pageflow.PageFlowController; +import org.apache.beehive.netui.pageflow.annotations.Jpf; + +@Jpf.Controller( + ... +) +public class Controller + extends PageFlowController +{ + @Jpf.Action( + forwards = { + @Jpf.Forward( name="success", path="mypage.jsp" ) + } + ) + public Forward myPage() + { + ... + } +} + + +

    + All that is left is a return + statement to return the appropriate Forward object. This is accomplished + simply by constructing a new Forward with the appropriate name. +

    + + +import org.apache.beehive.netui.pageflow.Forward; +import org.apache.beehive.netui.pageflow.PageFlowController; +import org.apache.beehive.netui.pageflow.annotations.Jpf; + +@Jpf.Controller( + ... +) +public class Controller + extends PageFlowController +{ + @Jpf.Action( + forwards = { + @Jpf.Forward( name="success", path="mypage.jsp" ) + } + ) + public Forward myPage() + { + return new Forward( "success" ); + } +} + +

    Now we have re-implemented one of our simple actions as an action method. However, our new action method +doesn't do anything more than the original simple action. The new action method remains a purely navigational +action: it is not yet capable of any decision logic and conditional execution. In the next section we will +endow the action method with conditional navigational behavior. +

    + +
    + +
    + Advanced Action Methods: Conditional Forwards + +
    +

    + The first step in adding conditional navigational behavior is to define two forwards + named authenticated and not_authenticated, + which are mapped to mypage.jsp and login.do respectively. + +

    + + +import org.apache.beehive.netui.pageflow.Forward; +import org.apache.beehive.netui.pageflow.PageFlowController; +import org.apache.beehive.netui.pageflow.annotations.Jpf; + +@Jpf.Controller( + ... +) +public class Controller + extends PageFlowController +{ + @Jpf.Action( + forwards = { + @Jpf.Forward( name="authenticated", path="mypage.jsp" ), + @Jpf.Forward( name="not_authenticated", path="login.do" ) + } + ) + public Forward myPage() + { + ... + } +} + + +

    But how does the method decide which forward to invoke? + In this case, the determination of authentication is performed by checking a + session attribute + to see if the authenticated_user attribute has been set.

    + + +import org.apache.beehive.netui.pageflow.Forward; +import org.apache.beehive.netui.pageflow.PageFlowController; +import org.apache.beehive.netui.pageflow.annotations.Jpf; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +@Jpf.Controller( + ... +) +public class Controller + extends PageFlowController +{ + @Jpf.Action( + forwards = { + @Jpf.Forward( name="authenticated", path="mypage.jsp" ), + @Jpf.Forward( name="not_authenticated", path="login.do" ) + } + ) + public Forward myPage() + { + HttpServletRequest request = getRequest(); + HttpSession session = request.getSession(); + + if ( session.getAttribute( "authenticated_user" ) != null ) + { + return new Forward( "authenticated" ); + } + + return new Forward( "not_authenticated" ); + } +} + +

    + Now that we have a method with two possible navigation outcomes, the flow diagram + appears as follows. Notice the two named arrows exiting the myPage() method. +

    +

    conditional forwards

    +

    + You may notice that the body of myPage() has no particular logic regarding + the JSP "myPage.jsp" itself. It simply operates in terms of authentication and generically + named Forward objects. This presents a possibility of sharing this logic + with other controller methods that are concerned with authentication. + + . +

    +
    +
    + Handling Forms + +

    + Handling form data works similar to other controller methods. By providing a parameter + to the controller method the HTML form data is made available to the controller method. In the above model, controller methods that process forms have been named + with the processXXX(..) convention. +

    + +
      +
    • processLogin(...)
    • +
    • processSignUp(...)
    • +
    + +

    + First, define a JavaBean to represent the HTML form to be submitted. This JavaBean can be of + any Java type, as long as it conforms to standard JavaBean syntax. +

    +

    The JavaBean may be defined (1) as a static inner class of the controller itself + (see example below) or (2) as a stand-alone Java class in a separate file. The + JavaBean class follows normal JavaBean conventions and requires no special annotations. +

    + + +import org.apache.beehive.netui.pageflow.Forward; +import org.apache.beehive.netui.pageflow.PageFlowController; +import org.apache.beehive.netui.pageflow.annotations.Jpf; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +@Jpf.Controller +public class Controller + extends PageFlowController +{ + ... + ... + + public static class LoginForm implements java.io.Serializable + { + private String username; + private String password; + + public void setUsername(String username) + { + this.username = username; + } + + public String getUsername() + { + return this.username; + } + + public void setPassword(String password) + { + this.password = password; + } + + public String getPassword() + { + return this.password; + } + } +} + + +

    + Defining the processLogin(...) method to take a LoginForm + parameter is all that is required to have a controller method that can + operate upon the submitted form. +

    + + +import org.apache.beehive.netui.pageflow.Forward; +import org.apache.beehive.netui.pageflow.PageFlowController; +import org.apache.beehive.netui.pageflow.annotations.Jpf; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +@Jpf.Controller +public class Controller + extends PageFlowController +{ + ... + ... + + public Forward processLogin(LoginForm form) + { + ... + } + + + public static class LoginForm + { + ... + ... + } +} + + +

    + Once again, processLogin(...) is a conditional forward controller method. + If a user has entered a correct username and password, then they should be directed + to mypage.jsp, otherwise they will be returned back to the login.jsp + for another attempt. Checking username and password is outside of the scope of Page Flow, + and in this example, we rely upon a mythical MyAppUtils class to perform + this logic. +

    + + +import org.apache.beehive.netui.pageflow.Forward; +import org.apache.beehive.netui.pageflow.PageFlowController; +import org.apache.beehive.netui.pageflow.annotations.Jpf; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +@Jpf.Controller +public class Controller + extends PageFlowController +{ + ... + ... + + @Jpf.Action( + forwards = { + @Jpf.Forward( name="login_success", path="mypage.jsp" ), + @Jpf.Forward( name="login_failure", path="login.jsp" ) + } + ) + public Forward processLogin(LoginForm form) + { + if ( MyAppUtils.authenticate( form.getUsername(), + form.getPassword() ) ) + { + HttpServletRequest request = getRequest(); + HttpSession session = request.getSession(); + + session.setAttribute( "authenticated_user", + form.getUsername() ); + + return new Forward( "login_success" ); + } + + return new Forward( "login_failure" ); + } +} + +

    Having fleshed out the processLogin() action method, the diagram appears as follows.

    +

    implementation page flow

    +

    + Similar implementation would be done for processSignUp(...), involving another + form class such as SignUpForm. + +

    + +
    + + +
    + Handling Exceptions +

    + Suppose a new user completes the signup form and submits her user profile. But when the profile is processed, + it is discovered that the username has already been taken by another user. What then?

    +

    A natural design choice would be to have the + processSignUp action throw an exception and then have the controller class handle the + exception by returning the user to + the original signup page. + The following diagram shows how you can interweave exception handling into the page flow to + further refine the paths through the flow. +

    +

    + page flow exception handling +

    +

    + You can implement exception handling using the + + @Jpf.Catch + + and + + @Jpf.ExceptionHandler + + annotations. The + + @Jpf.Catch + + defines some exception to handle should it arise within the controller class. + + @Jpf.ExceptionHandler + + annotation is used to define a dedicated method for handling the exception.

    + @Jpf.Controller( + catches={ + @Jpf.Catch(type=AccountAlreadyExistsException.class, method="handleAccountAlreadyExistsException") + }, + simpleActions={ + ... + } +) +public class Controller + extends PageFlowController +{ + ... + ... + + @Jpf.ExceptionHandler( + forwards={ + @Jpf.Forward(name="signup", path="signup.jsp") + } + ) + protected Forward handleAccountAlreadyExistsException(AccountAlreadyExistsException ex, String actionName, String message, Object form) + { + return new Forward("signup"); + } + +} + +

    To protect a method with this error handling system, you only need to specify that the method throws the + appropriate sort of exception, in this case, AccountAlreadyExistsException.

    + + @Jpf.Controller( + catches={ + @Jpf.Catch(method="handleAccountAlreadyExistsException", type=AccountAlreadyExistsException.class) + }, + simpleActions={ + ... + } +) +public class Controller + extends PageFlowController +{ + ... + ... + + public Forward processSignUp(SignUpForm form) + throws AccountAlreadyExistsException + { + ... + } + + @Jpf.ExceptionHandler( + forwards={ + @Jpf.Forward(name="signup", path="signup.jsp") + } + ) + protected Forward handleAccountAlreadyExistsException(AccountAlreadyExistsException ex, String actionName, String message, Object form) + { + return new Forward("signup"); + } + +} + +
    +
    +
    Form Validation +

    + For details on form validation see the topic + Data Validation +

    + +
    +
    + Next... + +

    + Next, learn about linking this controller class to the JSPs to allow for + the interception to occur. +

    + + +
    + + + +
    + + Java, J2EE, and JCP are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.
    + © 2004, Apache Software Foundation +
    +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/pageFlowInheritance.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/pageFlowInheritance.xml new file mode 100644 index 0000000..c523b52 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/pageFlowInheritance.xml @@ -0,0 +1,337 @@ + + + +
    + Page Flow Inheritance +
    + +
    + Introduction +

    + Page Flow inheritance is a powerful way to share actions, exception handlers, configuration, etc. among + controller classes. The basic idea is simple: you use Java inheritance to share pieces + of controller classes. This document shows ways in which you might use the feature, and also shows + areas that go beyond what you might expect from standard Jave inheritance. +

    + + Both inheritance and Shared Flow + offer ways to share actions and exception handlers. See + Shared Flow vs. Inheritance for + some guidelines on when to use each one. + + +
    +
    + Basic Inheritance +

    +

    + Inheriting Plain Members +

    + If you derive from a base class, you inherit all its public/protected member variables and methods. + Just as usual. +

    +
    +
    + Inheriting Annotated Members +

    + If you derive from a base class, then you inherit all its public/protected annotated + members, like action methods + (@Jpf.Action), exception handler methods + (@Jpf.ExceptionHander), or shared flow fields + (@Jpf.SharedFlowField). + This is not surprising, but it is important to point out. Inheriting an action method means that + you inherit the action. In the following example, DerivedFlow inherits its + begin action from BaseFlow. +

    + +package base; +... +@Jpf.Controller +public class BaseFlow extends PageFlowController +{ + @Jpf.Action( + forwards={ + @Jpf.Forward(name="index", path="index.jsp") + } + ) + public Forward begin() + { + return new Forward("index"); + } +} + +package derived; +... +@Jpf.Controller +public class DerivedFlow extends BaseFlow +{ +} +

    + As usual, hitting /derived/DerivedFlow.jpf in your browser will execute the begin + action on DerivedFlow. In this case, it executes the inherited + begin action. Pretty simple. +

    + + You may have noticed that "index.jsp" is a local path, and you may have wondered whether hitting + /derived/DerivedFlow.jpf will take you to /base/index.jsp or /derived/index.jsp. The page flow can + actually be configured to work either way; see Local Paths, below. + +
    +
    + Inheriting the <code>@Jpf.Controller</code> annotation +

    + When you extend a base class controller, you inherit its + + @Jpf.Controller + + annotation + in a special way: it is merged with the @Jpf.Controller annotation on your + derived class. Here is a very simple example: +

    + +package base; +... +@Jpf.Controller(nested=true) +public class BaseFlow extends PageFlowController +{ + ... +} + +package derived; +... +@Jpf.Controller( + simpleActions={ + @Jpf.SimpleAction(name="begin", path="index.jsp") + } +) +public class DerivedFlow extends BaseFlow +{ +} +

    + The controller DerivedFlow inherits + + nested=true + from the base class, and still keeps its simpleActions. It is as if + DerivedFlow defined the following + + @Jpf.Controller + + annotation: +

    + +@Jpf.Controller( + nested=true, + simpleActions={ + @Jpf.SimpleAction(name="begin", path="index.jsp") + } +) +

    + A more common example involves merging of arrays of annotations, like + + @Jpf.SimpleAction + + or + + @Jpf.Forward + + . In the following example, ChildFlow inherits the + simple action baseAction and a catch for LoginException. +

    + +package parent; +... +@Jpf.Controller( + simpleActions={ + @Jpf.SimpleAction(name="begin", path="page1.jsp"), + @Jpf.SimpleAction(name="baseAction", navigateTo=Jpf.NavigateTo.previousPage) + }, + catches={ + @Jpf.Catch(type=LoginException.class, path="loginError.jsp") + } +) +public class ParentFlow extends PageFlowController +{ +} + +package child; +... +@Jpf.Controller( + simpleActions={ + @Jpf.SimpleAction(name="begin", path="index.jsp") + }, + catches={ + @Jpf.Catch(type=Exception.class, path="error.jsp") + } +) +public class ChildFlow extends ParentFlow +{ +} +

    + It is as if ChildFlow was defined with the following + + @Jpf.Controller + + annotation: +

    + +@Jpf.Controller( + simpleActions={ + @Jpf.SimpleAction(name="begin", path="index.jsp"), + @Jpf.SimpleAction(name="baseAction", navigateTo=Jpf.NavigateTo.previousPage) + }, + catches={ + @Jpf.Catch(type=LoginException.class, path="loginError.jsp"), + @Jpf.Catch(type=Exception.class, path="error.jsp") + } +) +

    + The basic rule is that attributes (e.g, nested=true) are inherited, while arrays + (e.g., simpleActions={...}) are inherited and merged. When there are conflicts, values + from the derived controller override values from the base controller, as you would expect. +

    +
    +
    +
    + Advanced Inheritance +
    + Overriding +

    + You may have noticed from the ParentFlow/ChildFlow example above that + the begin action in ChildFlow overrode the one in ParentFlow. + The simple rule is that any annotation or attribute within your + + @Jpf.Controller + + will override one of the same name/type in the base class. In the following example, the + + @Jpf.Catch + + for LoginException is overridden in DerivedFlow. +

    + +package base; +... +@Jpf.Controller( + catches={ + @Jpf.Catch(type=LoginException.class, path="loginError.jsp") + } +) +public class BaseFlow extends PageFlowController +{ +} + +package derived; +... +@Jpf.Controller( + catches={ + @Jpf.Catch(type=LoginException.class, method="handleLoginException") + } +) +public class DerivedFlow extends BaseFlow +{ + @Jpf.ExceptionHandler( + forwards={ + @Jpf.Forward(name="errorPage", path="error.jsp") + } + ) + public Forward handleLoginException(LoginException ex, String actionName, String message, Object formBean) + { + ... + return new Forward("errorPage"); + } +} +
    +
    + Abstract base classes +

    + If you make your base controller class abstract, then you are free from some usual + restrictions: +

    +
      +
    • Even if it is a page flow controller, it does not need to have a begin action.
    • +
    • + Even if it has + + nested=true + in @Jpf.Controller, it does not have to have at least one + + @Jpf.Forward + + or + + @Jpf.SimpleAction + + with a + + returnAction + + attribute. This would normally be required. +
    • +
    • + If you have a local path (e.g., "index.jsp", which does not start with "/"), you will + not receive a warning if the file does not exist. A derived page flow may have a + local file with this name. +
    • +
    • + It is not required to have the + + @Jpf.Controller + + annotation. +
    • +
    +
    +
    +
    + Local Paths +

    + In a derived controller class, you may inherit an action that forwards to a local path (a path that + does not begin with a "/"). In the following example, DerivedFlow inherits a + begin action that forwards to "index.jsp": +

    + +package base; +... +@Jpf.Controller( + simpleActions={ + @Jpf.SimpleAction(name="begin", path="index.jsp") + } +) +public class BaseFlow extends PageFlowController +{ +} + +package derived; +... +@Jpf.Controller +public class DerivedFlow extends BaseFlow +{ +} +

    + If you hit /derived/DerivedFlow.jpf, where do you end up? /base/index.jsp or /derived/index.jsp? + By default, you end up at /derived/index.jsp; the local path is relative to the current page flow + (/derived/DerivedFlow.jpf). You can change this behavior, though, by setting + inheritLocalPaths=true in your derived class's + + @Jpf.Controller + + annotation, e.g., +

    + +package derived; +... +@Jpf.Controller(inheritLocalPaths=true) +public class DerivedFlow extends BaseFlow +{ +} +

    + Now, if you hit /derived/DerivedFlow.jpf, you will see the content of /base/index.jsp. +

    + + Even when inheritLocalPaths=true, you won't leave (destroy) the current page flow by + going to a path that's inherited from a base class. + +
    + +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/popupWindows.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/popupWindows.xml new file mode 100644 index 0000000..4a189ed --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/popupWindows.xml @@ -0,0 +1,283 @@ + + + +
    + Popup Windows +
    + +
    + Introduction +

    + The following topic explains how to collect data from a + nested page flow and 'return' the data to the + nesting/main page flow. The nested page flow can appear as a popup window if so desired. +

    +
    +
    + Submit/Display Cycle in a Single Page Flow +

    Before we get to nested page flows and popup windows, lets first take a look at the + basic page flow submission cycle. Below is a diagram of the basic cycle.

    +

    singlepageflow

    +

    Below is the code for the basic cycle: (1) index.jsp contains the form for + collecting data, (2) the submission is handled by the method submit(), + and (3) the submitted data is displayed by results.jsp.

    +

    index.jsp

    + <netui:form action="submit"> + Name: <netui:textBox dataSource="actionForm.name"/> + Favorite Color: <netui:textBox dataSource="actionForm.color"/> + <br/> + <netui:button type="submit" value="submit"/> + </netui:form> +

    Controller.java

    + ... + +@Jpf.Controller( + simpleActions={ + @Jpf.SimpleAction(name="begin", path="index.jsp") + } +) +public class Controller + extends PageFlowController +{ + + @Jpf.Action( + forwards={ + @Jpf.Forward( + name = "success", + path = "results.jsp" + ) + } + ) + protected Forward submit(SubmitForm form) + { + return new Forward("success", "form", form ); + } + + public static class SubmitForm + { + private String _name; + private String _color; + + public String getName() + { + return _name; + } + + public void setName(String value) + { + _name = value; + } + + public String getColor() + { + return _color; + } + + public void setColor(String value) + { + _color = value; + } + } +} +

    results.jsp

    + Submitted Name: ${pageInput.form.name} + <br/> + Submitted Color: ${pageInput.form.color} + <br/> + <br/> + <netui:anchor action="begin">[start over]</netui:anchor> +
    +
    + Submit/Display Cycle with Nested Page Flow +

    In this section we introduce a nested page flow to help collect data from the user.

    +

    When the user clicks the "get color" button (see the index.jsp + page below), an instance of a nested page flow is created (GetColor.java). + When the user submits the form within the nested page flow, the data is 'returned' + to populate the form within the main/nesting page flow.

    +

    The diagram below shows how the user moves into the nested page flow, and + then back into the main/nesting page flow.

    +

    nested_2

    +

    The code for the main and nested page flow follows.

    +

    index.jsp

    + <netui:form action="submit"> + Name: <netui:textBox dataSource="actionForm.name"/> + Favorite Color: <netui:textBox dataSource="actionForm.color"/> + <br/> + <netui:button type="submit" value="get color" action="getColor"/> + <netui:button type="submit" value="submit"/> + </netui:form> +

    Controller.java

    +... + +public class Controller + extends PageFlowController +{ + + ... + + /** + * This action forwards to the nested page flow to gather the favorite color. + */ + protected Forward getColor(SubmitForm form) + { + return new Forward("getColorFlow"); + } + + @Jpf.Action( + forwards={ + @Jpf.Forward( + name="success", + navigateTo=Jpf.NavigateTo.currentPage + ) + } + ) + protected Forward colorSuccess( String color ) + { + SubmitForm previousForm = ( SubmitForm ) getPreviousFormBean(); + previousForm.setColor( color ); + return new Forward( "success", previousForm ); + } + + ... + +} +

    results.jsp

    +[unchanged from above] +

    getColor/index.jsp

    + <netui:form action="submitColor"> + Color:<br/> + <netui:select dataSource="actionForm.color" size="5"> + <netui:selectOption value="red" /> + <netui:selectOption value="blue" /> + <netui:selectOption value="green" /> + <netui:selectOption value="yellow" /> + <netui:selectOption value="orange" /> + </netui:select> + <br/>  + <netui:button type="submit" value="submit"/> + </netui:form> +

    getColor/GetColor.java

    +package getColor; + +import javax.servlet.http.HttpSession; +import org.apache.beehive.netui.pageflow.PageFlowController; +import org.apache.beehive.netui.pageflow.Forward; +import org.apache.beehive.netui.pageflow.annotations.Jpf; +import javax.servlet.http.HttpServletRequest; +import org.apache.struts.action.ActionMapping; + + +@Jpf.Controller( + nested=true, + simpleActions={ + @Jpf.SimpleAction(name="begin", path="index.jsp") + } +) +public class GetColor extends PageFlowController +{ + @Jpf.Action( + forwards={ + @Jpf.Forward( + name="done", + returnAction="colorSuccess", + outputFormBeanType=String.class) + } + ) + protected Forward submitColor( ColorForm form ) + { + return new Forward( "done", form.getColor() ); + } + + public static class ColorForm + { + private String _color; + + public String getColor() + { + return _color; + } + + public void setColor(String value) + { + _color = value; + } + } +} +
    +
    + Submit/Display Cycle with Nested Page Flow (Popup Window Enabled) +

    This section explains how to make the nested page flow appear as a popup window.

    + +
    The <netui:configurePopupTag> +

    Use the <netui:configurePopup> + tag to determine the shape of the popup window.

    + <netui:button type="submit" value="Pick Color" action="getColor" popup="true"> + <netui:configurePopup location="false" width="550" height="150"> + </netui:configurePopup> + </netui:button> +
    +
    The <netui:retrievePopupOutput> +

    To access values returned by the nested page flow use the <netui:retrievePopupOutput> tag, +for example,

    + <netui:retrievePopupOutput dataSource="outputFormBean.color" tagIdRef="colorField"/> +

    Include multiple instances of the tag to set multiple fields.

    +

    Note - the <netui:retrievePopupOutput> tag must be nested inside + the <netui:configurePopup> tag even if the <netui:configurePopup> tag has no attributes

    +

    The <netui:retrievePopupOutput> tag has two attributes, dataSource + and tagIdRef, both of which are required. Both accept expressions that + can be evaluated at runtime.

    +

    Note - 'outputFormBean' is a special databinding context + that applies in this situation. It is the "return value" of the nested page + flow: It receives the value generated by the 'outputFormBean' + (or 'outputFormBeanType') in the returnAction forward from the nested page flow. + This databinding context is only legal when used in the <netui:retrievePopupOutput> tag.

    +
    +
    The <code>_auto</code> Global Forward +

    If you are returning data from the nested flow it is passed as a bean to + the action in the nesting page flow, for example

    + @Jpf.Action() + public Forward nestedPageFlowGotColor(GetColor.ColorForm colorForm) + { + return new Forward("_auto"); + } +

    Here is what the code looks like in the nested page flow

    + @Jpf.Action( + forwards={ + @Jpf.Forward(name="success", + returnAction="nestedPageFlowGotColor", + outputFormBeanType=ColorForm.class + ) + } + ) + public Forward done( ColorForm returnForm ) + { + return new Forward("success", returnForm); + } +

    +The bean returned to the nesting flow is accessed in the page using the special data binding +context, outputFormBean

    + + +
    +
    + +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/projects.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/projects.xml new file mode 100644 index 0000000..a7f1660 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/projects.xml @@ -0,0 +1,358 @@ + + + +
    + NetUI Web App Project Model +
    + +
    + Introduction +

    + A NetUI enabled web application consists of the same resources as a Struts, servlet, or other J2EE webapp. + The elements that make a NetUI web application different are the build steps for processing annotated Java + files and the JARs / resources that comprise the NetUI webapp runtime. This document discusses several topics + including possible web project layouts, the Ant tasks used to build Page Flows, the JARs / resources in + a NetUI web application, and the files that must be added to source control in order to commit a NetUI-enabled + web project into SCM. +

    +
    +
    + Project Layout +

    + J2EE web projects can be structured in a nearly limitless number of ways. Virtually all webapps have both + source files and web addressable content. In addition, there are a variety of configuration files and + deployment descriptors that are often stored in the WEB-INF/ directory. A fundamental + difference in how web projects are structured is where the web-addressable content and the source files live. + One web project model stores the source files in a sub-directory the web addressable content; another stores + source files as a peer to the web addressable content. When building Page Flows, the project layout affects + the Ant calls used to build the annotated Java files. Both project layouts and the Ant used to build are + discussed here. +

    +
    + Source Files peer to Web Content Root +

    + The classic web project layout is described by Tomcat here + and has the directories containing web-addressable content and web project source in peer directories. For example, the following + directory structure uses this layout and stores the Ant build file in the project's root directory: +

    + +fooWebProject/ + build/ + src/ + Controller.java + web/ + page1.jsp + page2.jsp + WEB-INF/ + web.xml + build.xml + build.properties + +

    + When using this layout, the source files in src/ are often built into the build/ directory under WEB-INF/classes. + Page Flows can be added to this project in either the src/ or web/ directory. When Page Flows are added to the src/ + directory, the following Ant can be used to build them into build/WEB-INF/classes: +

    + + + + + ... + + + ]]> +

    + While unconventional, because a Page Flow is URL addressable and "owns" its JSPs it is sometimes useful to store Page Flow files in the + web/ directory. This makes it easier to visualize the Page Flow as both the pages and the controller source file. In this case, + the Ant build changes slightly: +

    + + + + + ... + + + ]]> +

    + Be careful of the dependencies between the src/ and web/ directories when adding Page Flows to the + web/ directory as building both source roots separately can be difficult they have circular dependencies on + each other. +

    +

    + In both of the above project layouts, the tempdir is used as a destination for artifacts generated by the + Beehive annotation processors including both resources and Java source files. These are then compiled by the annotation + processor into the classes stored in build/WEB-INF/classes. This behavior can be changed by tweaking + the build files to build into a different temporary directory or to create a JAR for the class files. Also, the build/ + directory is often deployed to an application container during development. +

    +
    +
    + Source Files in the Web Content Root +

    + An alternate web project layout stores Java sources in the WEB-INF/src sub-directory. This project layout might look like: +

    + +fooWebProject/ + page1.jsp + page2.jsp + WEB-INF/ + web.xml + src/ + Controller.java + build.xml + build.properties + +

    + When building this type of web project, classes are often generated into the WEB-INF/classes directory and the webapp deployed + from the fooWebProject directory. This is different from the previous project models which build and deploy an external build/ + directory. The Ant used to build Page Flows in this project structure might appear as: +

    + + + + + ... + + + ]]> +

    + The difference between this <build-pageflows> call and the previous examples is that the webcontentdir and + destdir directories are implicitly set by only using the srcdir attribute. This causes the web project + to build directly into the fooWebProject/ directory and to generate classes into fooWebProject/WEB-INF/classes. +

    +
    +
    +
    + Creating a new NetUI Project +

    + A new NetUI project can be created from a Beehive distribution by running two commands to first create a NetUI-enabled web project and + then copy the Beehive runtime JARs into that project. +

    + /samples/netui-samples +ant -f /ant/beehive-runtime.xml -Dwebapp.dir= deploy.beehive.webapp.runtime + ]]> +

    + This command will create a webapp using the project layout described here. This webapp is + essentially a copy of the <beehive-root>/samples/netui-blank web application. +

    +
    +
    + Runtime JARs / Resources +

    + All web applications require runtime resources. Often, these are stored in a web project's WEB-INF/lib + directory. In order to use NetUI in a J2EE web application, a variety of JARs must be stored in this + directory. +

    +
    + JARs +

    + Since NetUI is built atop Struts, the Struts JARs must be present in order + for the web application to function. This table lists both the Struts and Beehive JARs; all of these JARs are + available as part of the Beehive distribution. +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameJAR fileVersionRequired
    Beehive Controlsbeehive-controls.jardistributionYes
    Beehive NetUIbeehive-netui-core.jardistributionYes for NetUI JSP tag support; no otherwise
    Beehive NetUIbeehive-netui-tags.jardistributionNo
    Jakarta Commons Bean Utilscommons-beanutils.jar1.6Yes
    Jakarta Commons Codeccommons-codec-1.3.jar1.3Yes
    Jakarta Commons Collectionscommons-collections.jar2.1.1Yes
    Jakarta Commons Digestercommons-digester.jar1.6Yes
    Jakarta Commons Discoverycommons-discovery-0.2.jar0.2Yes
    Jakarta Commons ELcommons-el.jar1.0Yes
    Jakarta Commons File Uploadcommons-fileupload.jar1.0Yes
    Jakarta Commons Loggingcommons-logging.jar1.0.4Yes
    Jakarta Commons OROjakarta-oro.jar2.0.7Yes
    Jakarta Commons Validatorcommons-validator.jar1.1.4Yes
    JSTL 1.1jstl.jar1.1.0-D13Yes for JSTL tag support; no otherwise
    JSTL 1.1standard.jar1.1.0-D13Yes for JSTL support; no otherwise
    Log4Jlog4j-1.2.8.jar1.2.8No
    Strutsstruts.jar1.2.7Yes
    + + For the 1.0 release, the NetUI runtime can not be shared between multiple web applications; the runtime + for every web application must be isolated inside of its own web application classloader. This is because in some + cases, NetUI caches information in statics or class instances rather than in the ServletContext. + +
    +
    + Other Resources +

    + NetUI also uses several additional XML files used to configure various NetUI and Struts sub-systems. These are detailed + in the table below. +

    + + + + + + + + + + + + + +
    NameLocationRequired
    beehive-netui-validator-rules.xml<beehive-root>/samples/netui-blank/web/WEB-INF/Yes
    validator-rules.xml<beehive-root>/samples/netui-blank/web/WEB-INF/Yes
    beehive-netui-config.xmlSee here for more information.No (unless modified)
    +

    + Also, the NetUI runtime requires a set of web.xml entries to register the Page Flow servlet, filters, and mappings. + In any NetUI-enabled web project, be sure that these entries are present. +

    +
    +
    + NetUI-enabled Web Projects and Source Control +

    + When adding a NetUI-enabled web project to source control, all resources marked Required in the JAR table and + the resources table should be checked into SCM. In addition, the optional resources may be required for certain + features to function correctly. If a web project uses the Beehive System Controls, those JARs should also be checked into source control. +

    +
    +
    +
    + Building a Web Project +

    + When a NetUI enabled web project builds, two processing steps happen to the Page Flow annotated Java files. The first is + annotation processing which produces a Struts module config file and the second is a Java class file for the Controller class. + For example, given a Page Flow in some directory: +

    + +foo/ + Controller.java + page1.jsp + page2.jsp + +

    + in any of the project models above, the following artifacts will be produced by the build: +

    + +WEB-INF/classes/ + foo/ + Controller.class + _pageflow/ + struts-config-foo.xml + +

    + By default, the Struts module config file is placed in the WEB-INF/.pageflow-struts-generated directory and the + Java class file is placed in WEB-INF/classes/. In cases where these values need to change, the Beehive Ant + build macros are documented here. +

    +
    +
    + Deploying a Web Project +

    + Once built, a Beehive web project can be deployed to a Servlet container just as with any other J2EE web application. On + Tomcat, this can be done by copying the web project directory to $CATALINA_HOME/webapps or by using the + Tomcat deployer to deploy the webapp. See your application container's documentation for details on how to deploy + web applications. +

    +
    + +
    + + Java, J2EE, Servlet, and JCP are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States + and other countries.
    © 2005, Apache Software Foundation +
    +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/samples/index.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/samples/index.xml new file mode 100644 index 0000000..ab1f7a2 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/samples/index.xml @@ -0,0 +1,184 @@ + + + +
    + Beehive Sample: NetUI Samples +
    + +
    + Introduction +

    These samples show individual NetUI features, including:

    + +
    +
    + Running the Samples on Tomcat 5 +

    The following explains how to run the samples on Tomcat 5. The sample + will run on other web containers, but we have chosen Tomcat 5 for convenience.

    +
    + To Set up the Environment +

    Before proceeding, complete all of the necessary and optional steps in the + following topic: + Beehive Installation and Setup

    +

    Open a command shell and confirm that you have set following variables:

    +
      +
    • ANT_HOME
    • +
    • JAVA_HOME
    • +
    • CATALINA_HOME
    • +
    +

    Also ensure that the following elements are on your PATH:

    +
      +
    • ANT_HOME/bin
    • +
    • JAVA_HOME/bin
    • +
    +
    +
    + To Copy the Application to a Project + Folder (Optional Step) +

    To keep your Beehive distribution directory + pristine, you should copy the + <BeehiveRoot>/samples/netui-samples folder to another location before + proceeding.

    + + <BeehiveRoot> refers to the top-level directory of your Beehive installation. + A typical value for <BeehiveRoot> would be /apache/apache-beehive-1.0. +

    The following instructions assume that you have + copied the folder netui-samples into the + directory /beehive_projects, + resulting in the following directory structure.

    + / + beehive_projects + netui-samples + Strictly speaking, you do not need to copy the netui-samples + directory to another location. If you wish to leave the netui-samples directory + in place, in the instructions below you must + replace occurrences of the path element /beehive_projects + with this path element: <BeehiveRoot>/samples. +

    + For example, to build the sample, run the following Ant command: +

    +    ant -f <BeehiveRoot>/samples/netui-samples/src/WEB-INF/build.xml clean build war +

    + To delete the sample's build directory, run the clean target: +

    +    ant -f <BeehiveRoot>/samples/netui-samples/src/WEB-INF/build.xml clean
    +
    +
    Edit the <code>build.properties</code> File +

    In this section you will edit the build.properties file--the file + that sets the build-related properties for your web application.

    +

    Open the file /beehive_projects/netui-samples/WEB-INF/src/build.properties + in a text editor.

    +

    Edit the file so that the beehive.home property points to the + top-level folder of your beehive installation. For example, if your beehive installation + resides at /apache/apache-beehive-1.0, then your build.properties file + would appear as follows.

    + beehive.home=/apache/apache-beehive-1.0 + +servlet-api.jar=${os.CATALINA_HOME}/common/lib/servlet-api.jar +jsp-api.jar=${os.CATALINA_HOME}/common/lib/jsp-api.jar + +context.path=netui-samples +Windows users must use forwardslashes (/) not backslashes (\) in the + build.properties file. + +
    +
    + To Compile the NetUI Samples Application +

    To compile the NetUI samples app, enter the following Ant command:

    +ant + -f /beehive_projects/netui-samples/WEB-INF/src/build.xml + clean + build + war + +Copy and Paste version: +ant -f /beehive_projects/netui-samples/WEB-INF/src/build.xml clean build war + +
    +
    + To Start Tomcat +

    To start Tomcat, run the following command:

    + %CATALINA_HOME%\bin\startup.bat +

    Or, on non-Windows systems,

    + $CATALINA_HOME/bin/startup.sh +
    +
    + To Deploy to Tomcat +

    To deploy the samples, copy the WAR file to Tomcat's webapps directory.

    +

    On Windows:

    + copy C:\beehive_projects\netui-samples.war %CATALINA_HOME%\webapps /Y + + On Windows, there are file-locking issues that Tomcat versions 5.5.x and above are sensitive to. + In particular, any web application that uses Struts will fail to redeploy if you + copy in a new .war file as described here. The Commons Digester team is adding a workaround for the + issue (see + this bug), but in the meantime, + you can work around it with the antiResourceLocking option in Tomcat. Just add a file + called context.xml in a directory called META-INF inside the + web application directory before building (so it will end up as META-INF/context.xml + in your controls_tutorial.war): +
    +
    +     <?xml version="1.0" encoding="UTF-8"?>
    +     <Context antiResourceLocking="true">
    +     </Context> +
    +

    Everywhere else:

    + cp /beehive_projects/netui-samples.war $CATALINA_HOME/webapps +
    +
    + Running +

    To browse the various feature samples: visit the following link in a browser:

    +

    http://localhost:8080/netui-samples

    + +
    +
    + +
    + Java, J2EE, and JCP are trademarks or registered trademarks of + Sun Microsystems, Inc. in the United States and other + countries.
    © 2004, Apache Software Foundation
    +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/samples/jsfIntegration.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/samples/jsfIntegration.xml new file mode 100644 index 0000000..a568143 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/samples/jsfIntegration.xml @@ -0,0 +1,182 @@ + + + +
    + NetUI: JSF Integration +
    + +
    + Introduction +

    This sample shows how to integrate JSF (Java Server Faces) into your NetUI + web app; specifically, how to use JSF pages as the View tier with NetUI Page Flow + as the Controller tier. For more information + see Java Server Faces.

    +
    +
    + Running the Sample on Tomcat 5 +

    The following instructions explain how to run the sample on Tomcat 5. The sample + will run on other web containers, but we have chosen Tomcat 5 for convenience.

    +
    + To Set up the Environment +

    Before proceeding, complete all of the necessary and optional steps in the + following topic: + Beehive Installation and Setup

    +

    Open a command shell and confirm that you have set following variables:

    +
      +
    • ANT_HOME
    • +
    • JAVA_HOME
    • +
    • CATALINA_HOME
    • +
    +

    Also ensure that the following elements are on your PATH:

    +
      +
    • ANT_HOME/bin
    • +
    • JAVA_HOME/bin
    • +
    +
    +
    + To Copy the Application to a Project + Folder (Optional Step) +

    To keep your Beehive distribution directory + pristine, you should copy the folder + <BeehiveRoot>/samples/netui-jsf to another location before + proceeding.

    + + <BeehiveRoot> refers to the top-level directory of your Beehive installation. + A typical value for <BeehiveRoot> would be /apache/apache-beehive-1.0. +

    The following instructions assume that you have + copied the folder netui-jsf into the + directory /beehive_projects, + resulting in the following directory structure.

    + / + beehive_projects + netui-jsf + Strictly speaking, you do not need to copy the netui-jsf + directory to another location. If you wish to leave the netui-jsf directory + in place, in the instructions below you must + replace occurrences of the path element /beehive_projects + with this path element: <BeehiveRoot>/samples. +

    + For example, to build the sample, run the following Ant command: +

    +    ant -f <BeehiveRoot>/samples/netui-jsf/src/WEB-INF/build.xml clean build war +

    + To delete the sample's build directory, run the clean target: +

    +    ant -f <BeehiveRoot>/samples/netui-jsf/src/WEB-INF/build.xml clean
    +
    +
    To Download a JSF Implementation +

    Download and install one of the following JSF implementations:

    + +
    +
    To Edit the <code>build.properties</code> File +

    In this section you will edit the build.properties file--the file + that sets the build-related properties for your web application.

    +

    Open the file /beehive_projects/netui-jsf/WEB-INF/src/build.properties + in a text editor.

    +

    Edit the file so that the beehive.home property points to the + top-level folder of your beehive installation.

    +

    Also uncomment one of the properties myfaces.dir or jsf-ri.dir. + Point the uncommented property at the appropriate directory.

    +

    For example, if your beehive installation + resides at /apache/apache-beehive-1.0 + and you have installed the JSF Reference Implementation, + then your build.properties file + would appear as follows.

    + beehive.home=/apache/apache-beehive-1.0 + +servlet-api.jar=${os.CATALINA_HOME}/common/lib/servlet-api.jar +jsp-api.jar=${os.CATALINA_HOME}/common/lib/jsp-api.jar + +context.path=netui-jsf + +# TODO: +# if using MyFaces, uncomment the 'myfaces.dir' property and set it to a directory that contains +# myfaces.jar (MyFaces v1.0.9 or later). +#myfaces.dir= + +# TODO: +# If using the JavaServer Faces Reference Implementation, uncomment the 'jsf-ri.dir' property and +# set it to a directory that contains jsf-api.jar and jsf-impl.jar (JSF RI v1.1_01). +jsf-ri.dir=/java/jsf-1_1_01/lib +Windows users must use forwardslashes (/) not backslashes (\) in the + build.properties file. + +
    +
    + To Compile the Application +
    ...If Using JSF Reference Implementation
    +

    If you are using the JSF Reference Implementation, enter the following Ant + command:

    +ant + -f /beehive_projects/netui-jsf/WEB-INF/src/build.xml + clean + build-jsf-ri + war + +Copy and Paste version: +ant -f /beehive_projects/netui-jsf/WEB-INF/src/build.xml clean build-jsf-ri war +
    ...If Using MyFaces +

    If you are using MyFaces, enter the following Ant + command:

    +ant + -f /beehive_projects/netui-jsf/WEB-INF/src/build.xml + clean + build-myfaces + war + +Copy and Paste version: +ant -f /beehive_projects/netui-jsf/WEB-INF/src/build.xml clean build-myfaces war + +
    +

    Both of these targets build a WAR file and save it to:

    + /beehive_projects/netui-jsf.war +
    +
    + To Start Tomcat +

    To start Tomcat, run the following command:

    + %CATALINA_HOME%\bin\startup.bat +

    On non-Windows systems:

    + $CATALINA_HOME/bin/startup.sh +
    +
    + To Deploy to Tomcat +

    To deploy the samples, copy the WAR file to Tomcat's webapps directory.

    +

    On Windows:

    + copy C:\beehive_projects\netui-jsf.war %CATALINA_HOME%\webapps /Y + + On Windows, there are file-locking issues that Tomcat versions 5.5.x and above are sensitive to. + In particular, any web application that uses Struts will fail to redeploy if you + copy in a new .war file as described here. The Commons Digester team is adding a workaround for the + issue (see + this bug), but in the meantime, + you can work around it with the antiResourceLocking option in Tomcat. Just add a file + called context.xml in a directory called META-INF inside the + web application directory before building (so it will end up as META-INF/context.xml + in your controls_tutorial.war): +
    +
    +     <?xml version="1.0" encoding="UTF-8"?>
    +     <Context antiResourceLocking="true">
    +     </Context> +
    +

    Everywhere else:

    + cp /beehive_projects/netui-jsf.war $CATALINA_HOME/webapps +
    +
    + Running +

    To browse the JSF sample, visit the following link in a browser:

    +

    http://localhost:8080/netui-jsf

    + +
    +
    + +
    + Java, J2EE, and JCP are trademarks or registered trademarks of + Sun Microsystems, Inc. in the United States and other + countries.
    © 2004, Apache Software Foundation
    +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/samples/netuiBlank.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/samples/netuiBlank.xml new file mode 100644 index 0000000..d107253 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/samples/netuiBlank.xml @@ -0,0 +1,130 @@ + + + +
    + NetUI Project Template +
    + +
    + Introduction +

    + NetUI enabled web applications require a set of JARs, XML configuration files, and web.xml entries. + In order to make it easy to get started with a NetUI web application, the samples/netui-blank project + template is available in the Beehive distribution. Use this as a starting point for building new NetUI-enabled + applications. This document describes how to build a new NetUI-enabled application from the netui-blank + project template. +

    + + In the documentation below, <beehive-root> refers to the top-level directory of your local Beehive installation. + A typical value for <beehive-root> would be /apache/apache-beehive-1.0. + +
    +
    + Using the NetUI Webapp Template +

    + The following instruction assume that you have completed all of required and optional steps in the Beehive set up procedure at + Installation and Setup. +

    +

    + To use the netui-blank template, follow these steps: +

    +
    + Create a New Webapp +

    + A new NetUI web project can be created by running the following Ant command from <beehive-root: +

    + ant -f beehive-imports.xml new.netui.webapp +

    + This will prompt you for a fully-qualified path for your web project. For example, the following path + /projects/fooWeb would create a project layout similar to that described + here. + This project will include the runtime, configuration files / entries, and a basic Ant build.xml file. + The description below assumes that you have created the NetUI-enabled web project fooWeb under a + projects/ directory. +

    +
    +
    + Configure the Webapp's Build Properties +

    + In this section you will edit the build.properties file in order to set build-related + paths and values for your web project. +

    +

    + Open the file /projects/fooWeb/build.properties in a text editor and edit the following + properties: +

    +
      +
    • Set the beehive.home property to point to the top-level folder of your Beehive installation.
    • +
    • + Set the context.path property to some value that is appropriate to your web application. This + value is used when the web-project is built into a .war archive. When deploying the + .war archive, it also often determines thecontext path for the web project when deployed to the server. +
    • +
    +

    + For example, if Beehive is installed at /apache/apache-beehive-1.0, and you created a project named + fooWeb then your build.properties file might appear as follows: +

    +beehive.home=/apache/apache-beehive-1.0 + +servlet-api.jar=${os.CATALINA_HOME}/common/lib/servlet-api.jar +jsp-api.jar=${os.CATALINA_HOME}/common/lib/jsp-api.jar + +context.path=fooWeb + + Properties files should use the '/' character to separate drive, directory, and file names. + + + This .properties file also assumes that you are using Tomcat as your Servlet container. + If you are not using Tomcat, set the paths to the Servlet and JSP API classes appropriately for your + container. In some cases, these may point to the same JAR. + +
    +
    + Build the Webapp +

    + By default, the build associated with a new NetUI-enabled webapp stores the Ant build.xml file + in the project's root directory; in the example above, this is the projects/fooWeb directory. +

    +

    + To build the webapp, run ant build. This will create a build/ + directory into which the webapp's resources are copied and Java source files are compiled. This + build directory will be archived when creating a .war file. It can also + be deployed, exploded directly to the server. +

    +

    + To clean the webapp, run ant clean. +

    +

    + To create a .war file, run ant war. +

    +

    + To update the JSPs when doing iterative development, run ant copy.jsps. +

    +
    +
    + Deploy and Run the Webapp +

    + If you are using Tomcat, the web application can be deployed by copying the built .war file + from projects/fooWeb/fooWeb.war to Tomcat's webapps directory. +

    +

    + If you are using a different Servlet container, follow your container's deployment instructions for deploying + a .war web projct arcive. +

    +

    + Once the web application is deployed, you can run your web application by accessing the following URL from + a browser: http://localhost:8080/fooWeb/ . You should see a page with the text "New Web + Application Page". +

    +
    +
    + +
    + + Java, J2EE, and JCP are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other + countries.
    © 2004-2005, Apache Software Foundation +
    +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/servletContainerAdapters.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/servletContainerAdapters.xml new file mode 100644 index 0000000..29eb42c --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/servletContainerAdapters.xml @@ -0,0 +1,52 @@ + + + +
    + Servlet Container Adapters +
    + +
    Writing a Servlet Container Adapter +

    + Certain NetUI features (like the default behavior for FlowController.login()) depend on + container-specific capabilities. NetUI uses "servlet container adapters" to take advantage of + container-specific functionality. +

    +

    To write an adapter:

    +
      +
    1. + Write a class that implements + + org.apache.beehive.netui.pageflow.ServletContainerAdapter. + You can extend + org.apache.beehive.netui.pageflow.DefaultServletContainerAdapter. +
    2. +
    3. + Package the class in a JAR file which also contains a text file in directory + META-INF/services called + org.apache.beehive.netui.pageflow.ServletContainerAdapter. + The text file should have a single line that is the full class name of your + ServletContainerAdapter +
    4. +
    5. + Drop the JAR into the WEB-INF/lib directory of your web application. The NetUI + runtime will automatically pick up the first "discovered" adapter that answers true + when its accept method is called. +
    6. +
    + + + Note: the default ServletContainerAdapter defines "production mode" as the state where + assertions are disabled. (See Development and Production Modes for details.) + Even if you do not want to use existing adapters for container-specific features, you may want to write + your own adapter that defines production mode + (ServletContainerAdapter.isInProductionMode()) + according to your own requirements. + +
    + +
    + Java, J2EE, and JCP are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.
    + © 2004, Apache Software Foundation +
    +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/sharedFlow.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/sharedFlow.xml new file mode 100644 index 0000000..5d9ac7a --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/sharedFlow.xml @@ -0,0 +1,226 @@ + + + +
    + Shared Flow +
    + +
    + Introduction +

    + A shared flow (a kind of controller class) provides a place for actions, exception handlers and data + that the developer wants to make available to multiple page flows. Shared flows are most useful for + accessing shared state, for shared/templated user interface, and when you cannot change your controller + class hierarchy. +

    +

    + Shared flows can reside anywhere in your web app, and can be referenced from other controller files or + from pages. +

    + + Both shared flows and Page Flow Inheritance offer ways to share + actions and exception handlers. See + Shared Flow vs. Inheritance for some guidelines on + when to use each one. + +
    +
    + Shared Flow Basics +

    + The Shared Flow feature has the following basic properties, which are described in + more detail below. +

    +
      +
    • + A shared flow is referenced by any page flow that wants to share its + actions, exception handlers, and data. +
    • +
    • + When you hit a page flow, you are guaranteed to have access to a single + instance of each of its referenced shared flows. These shared flow + instances are stored in the user session, and they are not destroyed until the + session ends, or until they are destroyed explicitly. +
    • +
    • + A page flow or any of its JSPs can raise actions on any referenced shared flow. +
    • +
    • + Unhandled exceptions in the page flow are automatically tried on all + referenced shared flows, until one of them handles the exception. +
    • +
    +
    +
    + Creating a Shared Flow +

    To create a shared flow controller class:

    +
      +
    1. + add the + + @Jpf.Controller + + annotation to the class, and +
    2. +
    3. + extend the + SharedFlowController + class. +
    4. +
    +

    For example:

    + +import org.apache.beehive.netui.pageflow.annotations.Jpf; +import org.apache.beehive.netui.pageflow.SharedFlowController; + +@Jpf.Controller +public class MySharedFlow extends SharedFlowController +{ + ... +} +

    + You can add actions and + exception handling just like you would in + a page flow controller. +

    +
    +
    + Referencing Shared Flows from Page Flows +

    + To share actions, exception handlers, and state from a shared flow, a page flow needs to declare a + reference in its controller class, using the + + @Jpf.SharedFlowRef + + annotation. The following example shows two shared flow references being declared for page flow + controller SomeController: +

    + +@Jpf.Contoller( + sharedFlowsRefs={ + @Jpf.SharedFlowRef(name="sharedFlowOne", type=example.SharedFlowClassOne.class), + @Jpf.SharedFlowRef(name="sharedFlowTwo", type=example.SharedFlowClassTwo.class) + } +) +public class SomeController extends PageFlowController +

    + Notice that this declaration assigns a name to each referenced shared flow. This name will be + used throughout the page flow to shared actions and state. Throughout this document, we will refer to + this as the shared flow name. +

    +
    + +
    + Shared Actions +

    + You can raise Shared Flow actions through NetUI JSP tags, through components/command-handlers in + JavaServer Faces pages, from other actions in the same page flow, or, in general, through URLs. + Basic instructions for raising actions can be found + here. The only difference between + raising a shared flow action and raising a normal action is that you include the shared flow name along with + the action name. For example, the following JSP tag raises someAction on + example.SharedFlowClassOne: +

    + + <netui:anchor action="sharedFlowOne.someAction"/> +

    + Notice that the pattern is shared-flow-name.action-name. As + another example, the following page flow action (part of SomeController in the above example) + raises action anotherAction on example.ShardFlowClassTwo: +

    + +@Jpf.Action( + forwards={ + @Jpf.Forward(name="sharedAction", action="sharedFlowTwo.anotherAction") + } +) +public Forward doSharedAction() +{ + return new Forward("sharedAction"); +} +

    + You always use the shared flow name, not its classname, to refer to it. This allows page flows + to choose their own namespaces for shared flow actions, thus avoiding conflicts in action names. +

    +
    +
    + Shared Flow Exception Handling +

    + When an exception occurs and your page flow does not handle it (using + + @Jpf.Catch + ), every referenced shared flow gets a chance to handle it. The list of + + @Jpf.SharedFlowRef + + annotations is traversed in order, and the first shared flow with a matching @Jpf.Catch + handles the exception. +

    +

    + For more information on exception handling, see + this document. +

    +
    +
    + Databinding to Shared Flow Properties +

    + If your shared flow controller exposes properties, you can databind to those properties from JSPs or from + JavaServer Faces pages, using the sharedFlow implicit object. The basic pattern is: + sharedFlow.shared-flow-name.property-name. + For example, the following JSP fragment displays the value of the someProperty property on + example.SharedFlowClassOne (for the page flow definition, see the example in + Referencing, above): +

    + +This is the value: ${sharedFlow.sharedFlowOne.someProperty} +

    + To be clear, what will be shown is the result of a method getSomeProperty on class + example.SharedFlowClassOne. In another example, the following text box pushes a value into + the writableProperty property when its form is submitted: +

    + +Edit this: <netui:textBox dataSource="sharedFlow.sharedFlowOne.writableProperty"/> +

    + Of course, you can do the same kind of binding from JavaServer Faces pages, using the JSF Expression + Language: +

    + +<h:panelGrid rendered="#{sharedFlow.sharedFlowOne.showDetails}"> + ... +

    + In that example, a panelGrid component decides whether to be rendered based on the value of + the showDetails property in example.SharedFlowOneClass +

    +
    +
    + Accessing a Shared Flow Directly +

    + If you want, you can declare a member variable in your page flow controller which will be automatically + initialized with a reference to a shared flow controller. This is optional; you do not have to + do this in order to use a shared flow controller. If you do want to access the shared flow controller + object directly, you annotate a member field using the + + @Jpf.SharedFlowField + + annotation. For example, the following page flow controller gets its mySharedFlow field + automatically initialized: +

    + +@Jpf.Contoller( + sharedFlowsRefs={ + @Jpf.SharedFlowRef(name="sharedFlowOne", type=example.SharedFlowClassOne.class) + } +) +public class SomeController extends PageFlowController +{ + @Jpf.SharedFlowField(name="sharedFlowOne") + private example.SharedFlowClassOne mySharedFlow; +} +

    + Note that you use the name of the shared flow reference in order to initialize the field. Once + you have done this, you can use the shared flow controller object in any way you like (access its state, + call methods, etc.). +

    +
    + +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/sharedFlowVsInheritance.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/sharedFlowVsInheritance.xml new file mode 100644 index 0000000..228f27c --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/sharedFlowVsInheritance.xml @@ -0,0 +1,150 @@ + + + +
    + Shared Flow vs. Inheritance +
    + +
    + Introduction +

    Page Flow supports both inheritance and + Shared Flow. At first glance the two seem similar; both allow you to share + actions and exception handlers. The general guideline for which to use is simple: use Page Flow + inheritance whenever you can. It allows you to share more than just actions and exception handlers + (e.g., you inherit everything in the base class + + @Jpf.Controller + + annotation), and it uses a + familiar Java concept in order to do it. This document mainly explains the (important) cases where you + would want to use Shared Flow. +

    +
    +
    + When to Use Shared Flow +

    + There are three main cases where you would want to use Shared Flow: for accessing shared state, for + shared/templated user interface, and when you cannot change your controller class hierarchy. +

    +
    + Accessing shared state +

    + You want to share actions or exception handlers that use a single copy of some shared + state. For example, the following shared flow action switchToLargePictures sets a + single flag that can be used by many page flows: +

    + +@Jpf.Controller +public class MySharedFlow extends SharedFlowController +{ + private boolean _usingLargePictures = false; + + @Jpf.Action( + forwards={ + @Jpf.Forward(name="cur", navigateTo=Jpf.NavigateTo.currentPage) + } + ) + public Forward switchToLargePictures() + { + _usingLargePictures = true; + return new Forward("cur"); + } + + public boolean isUsingLargePictures() + { + return _usingLargePictures; + } +} + +

    + There is only one instance of a given shared flow per user, so any page flow which references + MySharedFlow will have access to the single value of this flag. For example, + the following page flow references MySharedFlow under the name "mySharedFlow": +

    + +@Jpf.Controller( + sharedFlowRefs={ + @Jpf.SharedFlowRef(name="mySharedFlow", type=MySharedFlow.class) + } +) +public class ExamplePageFlow extends PageFlowController +{ +} + +

    + It can access the shared flow's usingLargePictures property in one of two ways: +

    +
      +
    • + In its JSPs, through databinding, e.g., + +<c:if test="${sharedFlow.mySharedFlow.usingLargePictures}"> + ... +</c:if> + +
    • +
    • + Directly, through an annotated field in the page flow controller class: + +@Jpf.SharedFlowField(name="mySharedFlow") +private MySharedFlow _mySharedFlow; // This field is auto-initialized. + +@Jpf.Action(...) +public Forward someAction() +{ + if (_mySharedFlow.isUsingLargePictures()) + { + ... + } +} + +
    • +
    +

    + There is a simple reason you would not want to put a flag like isUsingLargePictures + in a base class. If you did, you would end up with a separate copy of the value in each + derived controller class, thus making it more difficult to share the flag. +

    +
    +
    + + Shared actions and exception handlers for shared user interface + +

    + Say you are sharing some bit of user interface, like a menu bar. You may be using the NetUI + + Template + + tags, or you may be using Page Flow's support for + Tiles. In either case, the user + interface you're sharing will likely have its own actions (and possibly exception handlers) + associated with it. It usually does not make sense to be forced to extend a different + page flow controller, just to get the shared actions for something like a menu bar. You may + be including lots of shared user interface (navigation bar, header, footer, etc.), and it + would be bad for each one to require its own base class. Instead, each one can have an associated + shared flow, which you reference in your page flow using a + + @Jpf.SharedFlowRef. +

    + + The NetUI Samples show shared flows being used with both the Template + tags and with Tiles. + +
    +
    + You cannot change the inheritance hierarchy for your page flow controller +

    + In some cases, you simply cannot change the base class for your page flow controller. You may have + a prescribed base class, yet you still want to share some separate group of actions. When this + happens, you can always reference a shared flow, using a + + @Jpf.SharedFlowRef. +

    +

    + Is this a sneaky way to support multiple inheritance? We leave it for you to decide. +

    +
    +
    + +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/tags/datagrid.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/tags/datagrid.xml new file mode 100644 index 0000000..8f4e214 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/tags/datagrid.xml @@ -0,0 +1,475 @@ + + + +
    + Beehive NetUI Data Grids +
    + +
    + Overview +

    +The NetUI data grid tag library is a high-level abstraction for rendering grids of data in HTML. This tag library +supports rendering uses from simple tables to complex sortable, filterable, pageable, and updatable grids of data. The +<netui-data:dataGrid> is +part of NetUI's <netui-data:xxx> tag +library. +

    +
    +
    + A Simple Data Grid +

    + The simplest data grid will render a List of JavaBeans into a basic HTML table. Such a grid might look like: +

    + + + + + + + + +]]> +

    + This data grid binds to a List of PetBean objects stored in the PageContext's attribute map and renders an HTML table + that is four cells wide (i.e., four columns) containing the petId, name, description, and price fields. The rendered table + would appear as: +

    +

    + Simple data grid +

    +

    +The values for the cells are specified with a JSP 2.0 expression and can reference any implicit object. In this case, an +expression like ${container.item.petId} references an implicit object called container that the +<netui-data:rows> tag provides. This implicit object has an item property that references +the current item from data set bound to the dataSource attribute of the <netui-data:dataGrid> +tag. +

    +
    +
    + Data Grid Cells +

    +The data grid tags use cell based rendering. This means that their structure is not defined in terms of columns +but rather in terms of cells in the table. This allows for greater flexibility to have cells span columns and rows as +needed. Cells can be placed in two regions of the data grid -- the header and the body. The header of the grid is the +region that renders at the top of the rows containing data and often has column titles, sorting / filtering links, and +paging UI. Cells in the body of the data grid are used to render the grid's data; the spanCell tags in the +simple example above are an example of this. +

    +
    + Body Cells +

    +Body cells are used to render rows that display data. For example: +

    + + + + + + + + + + +]]> +

    +This data grid displays three columns of text with a fourth column containing HTML anchors. +Though it's not visible in the image, each anchor contains an HTTP request parameter +with name id and value ${container.item.petId}. +

    +

    + Data Grid with Anchor +

    +
    +
    + Header Cells +

    +Header cells are used to render HTML table cells at the top of a data grid. For example: +

    + + + + + + + + + + + + + + +]]> +

    +The data grid rendered here will have a single HTML table row that contains header cells +with titles for the data columns. This table might appear as: +

    +

    + Data Grid with Header +

    +
    +
    + Formatting Cells +

    +The NetUI formatter tags can also be applied to data grid cells. For example, a cell containing +a Date object could be formatted using: +

    + + + + + + + + + + + + +]]> +

    +which would render a data grid where the formatted column has dates in M/dd/yy format: +

    +

    + Data Grid with Formatter +

    +
    +
    +
    + Adding Styles to the Data Grid +

    +The data grid has three ways to apply styles to the rendered HTML elements including table rows, +cells, captions, and the HTML table itself. By default, the data grid renders a set of HTML +style class names which can be used in conjunction with a user-provided CSS file to automatically +apply styles to the grid. The default CSS names for various data grid regions are listed in +a table below. +
    +In addition, the style information can be customized by the page author in two ways via the +style and styleClass attributes. Many of the data grid tags provide +these attributes and set the HTML style and class attributes on +rendered HTML elements. +

    +
    + Style Attributes +

    +The style attribute can be used to apply a specific style to a specifc data grid +region. For example, the font in a column can be changed to red and bold by using the style +color:red;font-weight:bold; style on the spanCell as: +

    + + + + + + + +]]> +

    +renders a data grid that looks like: +

    +

    + Data Grid with Style +

    +
    +
    + CSS Attributes +

    +CSS files can also be used to apply styles to the data grid by matching names style class attribute names +rendered on data grid HTML markup with names in a correctly linked .css file. For example, +alternating row styles can be applied to a data grid with a datagrid.css file containing: +

    + +

    +and a data grid: +

    + + + + + + + + +]]> +

    +renders a data grid that looks like: +

    +

    + Data Grid with CSS +

    +

    +Notice that the <netui-data:dataGrid> tag does not have any special attributes that +enable style class rendering; the default style names are always rendered. The default style +prefix of datagrid can be changed by setting the dataGrid's styleClassPrefix +attribute. For example, if the above CSS is changed to: +

    + +

    +and the data grid changed to: +

    + + + + + + + + +]]> +

    +then the data grid will render with the same alternating row colors as above. Rendering of style class +names can be completely disabled by setting the <netui-data:dataGrid>'s styleClassPolicy +attribute to the value none. For example: +

    + + + + + + + +]]> +

    +will render a plain HTML table with no HTML class or style attributes. +

    +

    +The data grid renders several default style names onto various HTML table regions. These values include: +

    + + + + + + + + + + + + + + + + + + + +
    Data grid regionStyle name
    Tabledatagrid
    Table Captiondatagrid-caption
    Header Rowsdatagrid-header
    Header Table Cells (ths)datagrid
    Even Data Rowsdatagrid-even
    Odd Data Rowsdatagrid-odd
    Data Table Cells (tds)datagrid
    Footer Rowdatagrid-footer
    Header Row Groupdatagrid
    Data Row Groupdatagrid
    Footer Row Groupdatagrid
    Sortable Header Cell Classdatagrid-sortable
    Sorted Header Cell Classdatagrid-sorted
    Sorted Data Cell Classdatagrid-sorted
    + Notes:
    +
      +
    • Row numbering is zero based, so the first data row is even, the second odd, and so on.
    • +
    • When using a styleClassPrefix on the dataGrid tag, the datagrid + part of the style name can be replaced with the value of the styleClassPrefix.
    • +
    +
    +
    +
    +
    + Customizing the Data Grid's Pager +

    +In order to effectively display a large data set, the data grid provides a paging mechansim that +lets the grid display a subset of the data set on each "page". The default pager shows links for +navigating to the previous and next pagers. For example, if the pageScope.pets data +set contains more than ten items, the following data grid: +

    + + + + + + + + + +]]> +

    +generates a pager that contains the current and total page count along with links that navigate to the +previous and next pages: +

    +

    + Data Grid with Default Pager +

    +

    +If the data set is smaller than ten items, the default pager will simply show a pager with the message +Page 1 of 1. To change the default page size, use the <netui-data:configurePager> +tag to set the page size explicitly. For example: +

    + +]]> +

    +The appearance of a data grid's can also be configured through the pageFormat attribute. +Included with the data grid are pagers of two formats: +

    + + + + +
    Pager NamePager Format
    prevNextprevious / next
    firstPrevNextLastfirst / previous next / last
    +

    +The firstPrevNextLast pager can be configured by using the configurePager tag as: +

    + + + + + + + + + +]]> +

    +which will render a pager as: +

    +

    + Data Grid with FPNL Pager +

    +
    + Defining Custom Pagers +

    +In addition to the pre-defined pager formats, the data grid exposes a set of implicit JavaBean objects into +the JSP's PageContext that can be used when rendering a custom pager. These implicit objects provide access +to the number of pages, the size of the page, the total size of the data set, and other properties that can be +displayed or used to otherwise build a pager. For example, to define a custom label for a pager, the following +example uses the dataGrid implicit object that is available in the PageContext. This JavaBean +exposes a set of state that can be referenced via the JSP 2.0 EL to access additional information about the +data grid itself. The dataGrid object provides access to the grid's pager state and could be used +as: +

    + + + + Displaying item ${dataGrid.state.pagerModel.row+1} to ${dataGrid.state.pagerModel.lastRowForPage+1} + of ${dataGrid.state.pagerModel.dataSetSize} matching items. +
    + +
    +
    + + + + + + + + + + + + + +]]> +

    +to render a data grid: +

    +

    + Data Grid with Implicit Object Pager +

    +

    It can also be useful to disable the data grid's automatic rendering of the pager by setting the +disableDefaultPager as: +

    + +]]> +

    +With this attribute set, the data grid will not render any pager UI. The page author can then explicitly place the +pager inside of the grid using the <netui-data:renderPager> tag. For example, the pager can be placed +in the footer of the data grid with: +

    + + + + + + + + + + + + +]]> +

    +With the pager disabled, custom pager UI can be built anywhere inside of the data grid tags using the grid's +implicit objects. The following example builds a custom pager that provides "jump to page" functionality via an HTML select box, +for example: +

    + + + + + + + + + + + + + + + + + + +
    + Jump to Page: + + + + + + +]]> +
    +
    + +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/tags/datagridSortAndFilter.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/tags/datagridSortAndFilter.xml new file mode 100644 index 0000000..b08f439 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/tags/datagridSortAndFilter.xml @@ -0,0 +1,287 @@ + + + +
    + Sorting and Filtering in a Data Grid +
    + +
    + Overview +

    + The NetUI data grid JSP tags support maintaining and displaying UI based on an abstract set of + sorts and filters applied to a data set. Sorts and filters are Java objects that can be created manually or can be inferred + from state that is encoded in a URL. These objects represent an abstract notion of a sort and filter that are not coupled to + any specific query language. As such, they can be used to programmatically sort or filter a data set or to parameterize a + query string in a specific query language like SQL, XQuery, EJB-QL, and so on. +

    +

    + The data grid is related to sorting and filtering, but the data grid itself does not actually sort or filter a data set. While + this feature could be supported in the future, the goal of sorts and filters are to support loose coupling of the process used + to sort and filter while allowing the data grid to track the states of sorts and filters. The data grid supports sorts and + filters through setting CSS class names on columns that are sorted and filtered and by supporting UI gestures -- such as clicking + on a column header -- to sort and filter data. Because the sort and filter information is exposed from the + DataGridState object, + the JSP 2.0 expression language can be used to configure the user interface based on the sort, filter, and paged state + of a data set displayed in a data grid. +

    +

    + This document describes the structure of sort and filter objects and discusses how they can be created, used to sort a data set, + and how they relate to the data grid. A concrete example that demonstrates some of the sort and filter features can be found + in a Beehive sample available in samples/netui-samples/web/ui/datagrid/sortandfilter. This sample demonstrates the + data grid's support for sorting data by clicking on a grid's header cell and for filtering data using an HTML form. +

    +

    + For the sake of concrete descriptions, this documentation applies abstract Sort and Filter objects to SQL in order to make the + examples interesting. It is possible to build a mapping from the Sort and Filter objects to any other query language. +

    +
    +
    + Sorts +

    + A data grid sort is represented by the + Sort class which has several properties: +

    + + + + + + + + + + +
    Property NameDescription
    sortExpressionThe sort expression is a String that describes the data to be sorted.
    sortDirection + The sort direction is an enumeration value that describes the order in which data should be sorted. In the general case, this + is one of ASCENDING + or DESCENDING. +
    +

    + In more concrete terms, a sort expression of "name" and sort direction of SortDirection.ASCENDING could be used to produce + a SQL ORDER BY fragment like ORDER BY name ASC. +

    +
    + Data grid Support for Sorting +

    + The data grid JSP tags can be used to manipulate the sort state for a data grid in a URL. This allows a URL to explicitly + describe the sort appearance of a data grid and makes for easy, transparent bookmarking. A sort is often applied to a + column in a data grid and can be specified by setting the sortExpression attribute for any data grid + headerCell tag. By default, a sort can be activated by clicking on a column's header in the rendered data grid; + this will cycle the sorted state through a series of states from NONE to ASCENDING to DESCENDING. The change in state + can be observed by watching the URL. By default, a sort appears in the URL as: +

    + netui_sort=<namespace>;(|-)<sortExpression> +

    + The namespace is taken from the data grid's name + attribute in order to scope a sort to a particular data grid. + The sort expression is explicitly in the parameter value; the default sort direction is ASCENDING unless a - is + present to change the sort direction to DESCENDING. +

    +

    + The list of Sort(s) available on the URL can be read using a + DataGridState + object that parses state information from a query string and can return the list of states. This can be done using the following + code: +

    + DataGridState dataGridState = DataGridStateFactory.getInstance(httpServletRequest).getDataGridState("<namespace>"); +List sorts = dataGridState.getSortModel().getSorts(); +

    + Although the data grid may use a sort expression, the data will not be sorted until code executes to actually sort the data. + The data grid does not automatically sort data. In order to sort data, controller code must be implemented to + apply Sort objects to a data grid. +

    +

    + The sort state of a particular sort expression can also be used to configure the styles of a data grid column's header cell and + data cells. When a column is sorted, it will render a sorted style for both the header and data cells. +

    +
    +
    + Sorting a Data Set +

    + Sorts must be manually applied to a data set in order to cause data to be sorted in a particular direction. This sorting can + be implemented in several ways including converting a Sort object into a query language fragment and letting a query engine sort + a data set or manually writing code to sort a data set. To convert Sort(s) into a query language fragment, a converter must be + built to produce the fragment from the Sort(s). A simple SQL converter called + SQLSupport + can be used for this purpose. A sort of the form netui_sort=customers;-customerid will be converted into a + SQL fragment of the form ORDER BY customerid DESC using the code: +

    + List sorts = dataGridState.getSortModel().getSorts(); +String sort = SQLSupport.getInstance().createOrderByClause(sorts); +

    + A list of Sort(s) can also be used to manually filter a data set, particularly when sorting on a single sort expression (column + of data). In this case, a reasonably sized data set can be sorted in-memory quickly using a custom Comparator + and the java.util.Collections.sort(...) method. An example of this is available in the data grid sort / filter + sample in the distribution. +

    +
    +
    + Creating a Sort +

    + Sort objects can also be created programmatically. When creating a Sort object manually, the Sort object should be created + from the DataGridConfig + object for a data grid. The DataGridConfig object is used as a configuration object + that can be used in its default state or can be extended to provide, extend, or change the operation of the data grid. In + most cases, the DataGridConfig object can be created with: +

    + +

    + And, the DataGridConfig can be used to create a Sort with: +

    + +

    + Once a Sort is created, it can be configured by setting its JavaBean properties and can be applied to a data set + as described here. +

    +
    +
    +
    + Filters +

    + A data grid filter is represented by the Filter + JavaBea which has several properties: +

    + + + + + + + + + + + + + + + + + + + + + + +
    Property NameDescription
    filterExpressionThe filter expression is a String that describes a property from the data set to filter.
    filterOperationA query language specific representation of a filter operation. A filter operation may provide an operator that is used + when building a query string. For example, some languages may represent equals as '=' or as 'eq'.
    filterOperationHintA query language neutral hint of the type operation to perform. Not all operation hints will be supported for all query languages.
    typeHintA hint provided to describe the type of the filter value to a query engine. This is needed in order to correctly build a query string + describing a filter or to correctly filter a value of a particular type. For example, when building a filter expression for a String, + the String value may need to be wrapped in quotes to be interpreted by a query engine. +
    valueThe value of an operation that provides a constraint to a fliter. For example, when filtering to a specific integer value, this + is the value of that integer. +
    +

    + The filter operation hint can be one of many values that represent filtering options such as: +

    + +

    + As a concrete example, a filter on a value of "companyname" with an operator of "contains" and a value "wheel" with type String + could be used to produce a SQL WHERE clause like WHERE companyname LIKE '%wheel%'. +

    +
    + Data grid Support for Filtering +

    + The data grid's support for filtering is different than that for sorting; the data grid itself does not provide logic for + filtering and instead has the ability to mark a column of data as filtered and leaves the construction of filter UI + to the developer. A common pattern for building filter UI is to provide an embedded filter form or a filter pop-up that + implements filter logic. A data grid header cell can be linked to a filter expression using the filterExpression attribute + on the headerCell. +

    +

    + The data grid APIs support reading filter information that is encoded in the URL. One benefit of adding this information + to a query string as query parameters is that a filtered data grid can be bookmarked, which can make it easy to return to + a specific view into a data set. The default format for filters in the URL is: +

    + netui_filter=<namespace>;<filterExpression>~<filterOperation>~<value> +

    + The namespace of the filter is taken from the data grid's + name attribute, and + the filter's expression, operation type, and value are encoded in the remainder of the query parameter. The filters on a URL + query string can be read using a + DataGridState + which is used to manage a grid's state from some state source. The filters can be extracted from the query string using the + following code: +

    + DataGridState dataGridState = DataGridStateFactory.getInstance(httpServletRequest).getDataGridState("<namespace>"); +List filters = dataGridState.getFilterModel().getFilters(); +

    + Filters can be placed on the URL by JavaScript in the page or by extending the data grid itself to support filtering. +

    +
    +
    + Creating a Filter +

    + Filter objects can be created programmatically and applied to a data set either manually or by converting Filter{s) into + query fragments to be executed by a query engine. A + DataGridConfig + object can be used get a factory that can provide a Filter object for a specific type of data grid. This can + usually be created with: +

    + +

    + And, the DataGridConfig can be used to create a Filter with: +

    + +

    + This Filter object can be configuerd usints its JavaBean properties to set the expression, type hint, value, and operation hint. + Then, the filter can be used to filter a data set as described in here +

    +
    +
    + Filtering a Data Set +

    + Once a set of Filter objects have been obtained, they can be used to filter a data set by using a query engine or by manually filtering a data set. + A query engine can be used by converting a set of Filter objects into a fragment of a query string. For example, a filter can be configured + and converted into a SQL WHERE clause WHERE companyname LIKE '%wheel%' using the following code: +

    + // create the DataGridConfig object for a grid + DataGridConfig dataGridConfig = DataGridConfigFactory.getInstance(); + + // configure the filter + Filter filter = dataGridConfig.createFilter(); + filter.setFilterExpression("companyname"); + filter.setOperation(SQLSupport.mapFilterHintToOperation(FilterOperationHint.CONTAINS); + filter.setTypeHint(FilterTypeHint.STRING); + filter.setValue("wheel"); + List filterList = new LinkedList(); + filterList.add(filter); + + // create the WHERE clause + String whereClause = SQLSupport.getInstance().createWhereClause(filters); + + + If the Filter(s) are encoded in the URL, the Filter creation / configuration above can be replaced by the code + to parse filters from the query string. + +

    + Notice that the type hint is explicitly specified in the example above; the type of the companyname could be read + from a relational database's DatabaseMetaData object, but this is a very expensive way to determine the type of a column + of data. Once the where clause has been obtained, it can be used to parameterize a SQL query statement. +

    +

    + It is also possible to programmatically filter a data set. As an example, a simple set of filter predicate objects + are available in the Beehive sample listed above. In this case, the filters are created manually, and a data set is filtered + in-memory to provide a subset matching the filter criteria that should be rendered. +

    +
    +
    + +
    \ No newline at end of file diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/tags/formControls.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/tags/formControls.xml new file mode 100644 index 0000000..da49555 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/tags/formControls.xml @@ -0,0 +1,596 @@ + + + +
    + NetUI Form Control Tags +
    + +
    + Introduction +

    + The following table summarizes the basic NetUI tags which render as form controls. There + are basic types, simple controls and group controls. The simple controls map directly + to a single HTML element. The group controls map to more than one HTML element, for example + the <select> and <option> elements represent a select box. +

    +

    + The table summarizes the natural data type the control is usually bound to. + Typically, a form will post to an action that receives a subclass of FormData + which is populated with the values from the form by the framework before the action is called. +

    + + + + + + + + + + + + + + + + + + +
    NetUI Form ControlBinding Data Type
    <netui:anchor>None
    <netui:button>None
    <netui:checkBox>boolean or java.lang.Boolean or + java.lang.String
    <netui:checkBoxGroup>java.lang.String[]
    <netui:checkBoxOption>None, See the checkBoxGroup tag
    <netui:fileUpload>org.apache.struts.upload.FormFile
    <netui:form>None
    <netui:hidden>java.lang.String or java.lang.String[]
    <netui:imageButton>None
    <netui:radioButtonGroup>java.lang.String
    <netui:radioButtonOption>None, See the radioButtonGroup tag
    <netui:select>java.lang.String or java.lang.String[]
    <netui:selectOption>None, See the select tag
    <netui:textArea>java.lang.String[]
    <netui:textBox>java.lang.String[]
    +
    + +
    + Anchor +

    Though not technically a form control, the <netui:anchor> can be used to + submit a form. It does this through a JavaScript function that is dynamically added to the page. + In the following example the anchor is found inside of the <netui:form>, which + is a requirement for using a anchor to submit a form. In order to submit a form, the + formSubmit attribute is set to true. In addition, there + is no requirement to set an action or href on the anchor. It is possible + to submit a form when the anchor appears outside of the form. This requires setting the + getJavaScript attribute on the <netui:form> tag. Then you need + to add the following code to the anchor onClick="anchor_submit_form(name-of-form, action);return false;". +

    +

    The anchor does not bind to a dataSource of any type. +

    + +<netui:form> + ... + <netui:anchor formSubmit="true">Submit Form Through a Link</netui:anchor> +</netui:form> +

    There is a bit of generated JavaScript in the rendered page that will submit the form. + See Tags Support for JavaScript for details + on how the framework generated JavaScript is supported. Below is the rendered + HTML <a> tag, which calls the framework + generated anchor_submit_form function. +

    + +<a href="/dev/formControls/submit.do" + onclick="anchor_submit_form('Netui_Form_0','/dev/formControls/submit.do');return false;">Submit Form Through a Link</a> +
    +
    + Button +

    The <netui:button> tag acts as the standard button used to submit a form. + As a default the button acts as an HTML type="submit" button. (The type + attribute may also have a value of reset or button.) + In the example below, when the users presses the generated button it will cause the form + to be submitted. The button must appear within the <netui:form> +

    +

    The button does not bind to a dataSource of any type. +

    + +<netui:form> + ... + <netui:button type="submit">Submit the Form</netui:button> +</netui:form> +
    +
    + CheckBox +

    The <netui:checkBox> binds a boolean value to a dataSource. + The <netui:checkBox> will generate an <input type="checkbox"> HTML element. + The natural data binding type for the dataSource is a + boolean or java.lang.Boolean. In addition, it is possible + to bind to a java.lang.String. +

    +

    + In the following example, there are three checkboxes which are bound to a boolean, + java.lang.Boolean and a java.lang.String. +

    + + CheckBox [boolean] + + CheckBox [java.lang.Boolean] + + CheckBox [java.lang.String] + + +]]> +

    The NetUI tags above bind to the following three FormData properties. +

    + + private boolean checkBox; + private Boolean checkBoxBoolean; + private String checkBoxString; + + public boolean isCheckBox() { + return checkBox; + } + public void setCheckBox(boolean checkBox) { + this.checkBox = checkBox; + } + + public Boolean getCheckBoxBoolean() { + return checkBoxBoolean; + } + public void setCheckBoxBoolean(Boolean checkBoxBoolean) { + this.checkBoxBoolean = checkBoxBoolean; + } + + public String getCheckBoxString() { + return checkBoxString; + } + public void setCheckBoxString(String checkBoxString) { + this.checkBoxString = checkBoxString; + } + +
    +
    + CheckBoxGroup +

    The <netui:checkBoxGroup> creates a group of boolean values. Multiple + values may be selected at one time. The natural type for the dataSource + is a java.lang.String[]. Each <netui:checkBoxOption> contains a + value that will be posted back if the item is selected. See the + CheckBoxOption for more information on how options are specified. In addition, + the repeating version of the <netui:checkBoxGroup> is covered in the advanced topic + on Repeating CheckBoxGroup. +

    +

    There are two methods for creating the options which create the items inside of the + group. The body of the tag may contain <netui:checkBoxOption> tags or + the optionsDataSource may bind to an array of values. When using the + optionsDataSource this tag may act as a + repeater. This allows for + control of both the layout and the presentation of the options. +

    +

    In the following example, a <netui:checkBoxGroup> contains four children defined + through <netui:checkBoxOptions>. When the form is posted, all of the values that are selected + (checked) will be posted back to an array in the FormData. +

    + + + + + + +]]> +

    The following property in the FormData will recieve the results of the + posted CheckBoxGroup. +

    + +private String[] checkBoxGroup; + +public String[] getCheckBoxGroup() { + return checkBoxGroup; +} +public void setCheckBoxGroup(String[] checkBoxGroup) { + this.checkBoxGroup = checkBoxGroup; +} + +
    +
    + CheckBoxOption +

    The <netui:checkBoxOption> is a tag that defines an item within a + <netui:checkBoxGroup>. The tag has a required value attribute + which defines the value that will be posted back when the generated checkbox is + selected. There is also an optional label attribute that defines + a text label for the checkbox. If the label is not specified the + value attributes value will be used. +

    +

    In the CheckBoxGroup defined below, there are four <netui:checkBoxOption> + tags. All of them specify just the value attribute which is used for both + the value and label in the generated HTML. +

    + + + + + + +]]> +
    +
    + FileUpload +

    The <netui:fileUpload> tag allows a file to be uploaded to the server. By + default, this tag is not enabled because multipart request handling is disabled. + The only supported + data type that can be bound to is org.apache.struts.upload.FormFile. If + multipart handling is enabled, when the form is submitted, the contents of the file + will be posted to the server. +

    +

    By default, multipart request handling is disabled. There are two ways to enable + handling: (1) you may turn it on for the WebApp by setting a configuration option in the + beehive-netui-config.xml file or (2) you may turn it on for a page flow + by setting the Jpf.MultipartHandler annotation. (These two options are detailed below.) +

    +

    In the example below, the <netui:fileUpload> tag is used to upload + a file to the server. In order to use the file upload tag you must set the + enctype on the <netui:form> to multipart/form-data. + This is required to enable multipart data. The dataSource is bound + to a property of type org.apache.struts.upload.FormFile. +

    + +<netui:form action="submit" enctype="multipart/form-data"> + ... + <netui:fileUpload dataSource="actionForm.fileUpload"/> +</netui:form> + +

    The following FormData properties will receive the + information and data associated with the uploaded file. +

    + +private FormFile fileUpload; + +public FormFile getFileUpload() { + return fileUpload; +} +public void setFileUpload(FormFile fileUpload) { + this.fileUpload = fileUpload; +} + +

    In this example, multipart handling was enabled for in-memory support using + an annotation on the page flow. +

    + +@Jpf.Controller( + simpleActions={ + @Jpf.SimpleAction(name="begin", path="formTest.jsp") + }, + multipartHandler=Jpf.MultipartHandler.memory +) + +

    The following modification to the beehive-netui-config.xml file will + turn on in-memory processing of multipart requests for the entire WebApp. See + the beehive-netui-config.xml File Reference + for information on creating an initial beehive-netui-config.xml. +

    + +<pageflow-config> + <multipart-handler>memory</multipart-handler> +</pageflow-config> + +
    +
    + Form +

    The <netui:form> tag creates the HTML <form> element. + It specifies the action to run in the page flow. If the action specifies a + parameter that is a + subclass of FormData a bean will be populated by the page flow framework + with values posted by the controls contained in the form. In the example below, + the form will call the page flow's submit action. +

    + +<netui:form action="submit"> + ... +</netui:form> + +

    NOTE: the enctype="multipart/form-data" from the + FileUpload example is present because the <netui:fileUpload> tag is + being used + and requires multipart request handling. This is typically not used for simple + form posting. +

    +

    The following action defined in the page flow controller will be called when the + form is submitted. An instance of FormBean is created and populated + by the contents of the request. +

    + +@Jpf.Action( + forwards={@Jpf.Forward(name="success", + path="results.jsp", + actionOutputs={@Jpf.ActionOutput(name="bean", type=FormBean.class, required=true)} + ) + } +) +public Forward submit(FormBean formBean) { + Forward fwd = new Forward("success", "bean", formBean); + return fwd; +} + +
    +
    + Hidden +

    The <netui:hidden> tag creates the HTML <input type="hidden"> + element. There is no visual representation of a hidden field, but it's value + will be posted to the server when the form is posted. The <netui:hidden> + is a bit different than other form controls. It contains both a dataInput + and a dataSource attribute. This allows binding a value from a source + that differs from what is posted back to the server. If the dataInput is + not set, the dataSource is used as a read/write binding. +

    +

    In the example below, there are a number of hidden fields defined. All of them bind + values out of the pageFlow implicit object (see the + Data binding to NetUI Implicit Objects for more + information.) In the example, the hidden fields bind to different types of data objects. + The first simply binds the value back to a java.lang.String + value. The second and third hidden fields bind to the same array of + java.lang.Strings. The final hidden field binds to a boolean value. +

    + + Hidden + + Hidden Array[0] + + Hidden Array[1] + + Hidden + + +]]> +

    The following properties are defined in the FormData and are set + by the above hidden elements when the form is submitted. +

    + +// hidden +private String hidden; +private String[] hiddenArray; +private boolean hiddenBoolean; + +public String getHidden() { + return hidden; +} +public void setHidden(String hidden) { + this.hidden = hidden; +} + +public String[] getHiddenArray() { + return hiddenArray; +} +public void setHiddenArray(String hiddenArray[]) { + this.hiddenArray = hiddenArray; +} + +public boolean isHiddenBoolean() { + return hiddenBoolean; +} +public void setHiddenBoolean(boolean hiddenBoolean) { + this.hiddenBoolean = hiddenBoolean; +} + +
    +
    + ImageButton +

    The <netui:imageButton> creates the HMTL <input type="image"> + element. The result is an image used to submit the form. The source of the image + is specified in the src attribute. The <netui:imageButton> does not bind to any + data. In addition, it must appear inside of the form. +

    + +<netui:form> + ... + <netui:imageButton src="insert.gif"/> +</netui:form> + +
    +
    + RadioButtonGroup +

    The <netui:radioButtonGroup> is similar to the + <netui:checkBoxGroup>. It binds to + a group of boolean values, but instead of allowing multiple selection it only allows + a single selection. The underlying HTML produced is a set of HTML + <input type="radio"> elements where the name is the same value for each option, + thus creating + a group of radio buttons, of which only one may be selected at a time. The natural + binding for the <netui:radioButtonGroup> is a java.lang.String. See the + RadioButtonOption topic for information on creating + the options. In addition, + the repeating version of the <netui:radioButtonGroup> is covered in the advanced topic + on Repeating RadioButtonGroup. + +

    +

    There are two methods for creating the options which render the radio buttons + inside of the group. The body of the tag may contain <netui:RadioButtonOptions> + tags or the optionsDataSource my bind to an array of values. When using the + optionsDataSource, this tag may act as a + repeater. This allows for control of both + the layout and presentation of the options. +

    +

    In the following example, the <netui:radioButtonGroup> contains four options defined through + the <netui:radioButtonOption> tags. When the form is posted, if one of the options + is selected, its value will be posted back. +

    + + + + + + +]]> +

    The natural binding for a <netui:radioButtonGroup> is a + java.lang.String. The following property defined in the FormData + receives the results of posting the form. +

    + +private String radioButtonGroup; + +public String getRadioButtonGroup() { + return radioButtonGroup; +} +public void setRadioButtonGroup(String radioButtonGroup) { + this.radioButtonGroup = radioButtonGroup; +} + +
    +
    + RadioButtonOption +

    The <netui:radioButtonOption> is a tag that defines an item within + a <netui:radioButtonGroup>. The tag has a required value + attribute which defines the value that will be posted back when the radio button + option is selected. +

    +

    In the RadioButtonGroup defined below, there are four <netui:radioButtonOption + tags. All of them specify just the value attribute which is used for both the value and label + in the generated HTML. +

    + + Radio One + Radio Two + Radio Three + Radio Four +]]> +
    +
    + Select +

    The <netui:select> is a control allowing a user to select one + or more items from a list of items. There + are two primary modes, single selection and multiple selections. There are two ways to + specify the items of the select control, you may use <netui:selectOption> tags + or the optionsDataSource attribute. For more information on using <netui:selectOption> tags + see the SelectOption topic. In addition, the select supports a + repeating mode that allows control over the order of the options when using the + optionsDataSource. For more information see the + Repeating Select topic. +

    +
    + Single Selection +

    Single selection is the default behavior for a select control. It allows a single + value from the list to be selected. The natural data type that is bound to is + a java.lang.String. +

    +

    In the example below, a select box contains four options. +

    + + Select One + Select Two + Select Three + Select Four + +]]> +

    When the above select control is posted it is bound to a java.lang.String + property on the FormData. +

    + +private String singleSelect; + +public String getSingleSelect() { + return singleSelect; +} +public void setSingleSelect(String singleSelect) { + this.singleSelect = singleSelect; +} + +
    +
    + Multiple Selection +

    To create a multiple select control you specify multiple="true" in + the <netui:select> tag. A multiple select control allows zero or + more items to be selected and posted back to the server. The natural binding type + is java.lang.String[]. +

    +

    The example below defines a multiple select control by setting the + multiple attribute to true. This selection + has four options. +

    + + Select One + Select Two + Select Three + Select Four + +]]> +

    The above select control will post zero or more values into the following + property on the FormData. +

    + +private String[] multiSelect; + +public String[] getMultiSelect() { + return multiSelect; +} +public void setMultiSelect(String[] multiSelect) { + this.multiSelect = multiSelect; +} + +
    +
    +
    + SelectOption +

    The <netui:selectOption> is used to create statically defined options + for a <netui:select> control. The value attribute is required + and specifies the value that will be posted if the option is selected. In addition, + the body of the tag may contain a value that will be used to display the option in + the select control. If the body is empty, then the value will be used. +

    + + Select One + Select Two + Select Three + Select Four + +]]> +
    +
    + TextArea +

    The <netui:textArea> creates a multiple line text entry control. It maps + to the HTML <textArea> element. It is very common to set the rows + and cols attributes to set the size of the text area on the page. The natural + data type that is bound to is java.lang.String. In the code below a text area + is defined and binds to a property in the actionForm. +

    + +<netui:textArea dataSource="actionForm.textArea" /> + +

    The following property of the FormData receives the posted value: +

    + +private String textArea; + +public String getTextArea() { + return textArea; +} +public void setTextArea(String textArea) { + this.textArea = textArea; +} + +
    +
    + TextBox +

    The <netui:textBox> creates a single line text entry control. The + tag supports + either text or password by setting the type attribute. + The default is text. The natural + data type bound to by a text box is java.lang.String. The code below creates + a text box and binds it to a property in the actionForm +

    + +<netui:textBox dataSource="actionForm.textBox" /> + +

    The following property of the FormData receives the posted value: +

    + +private String textBox; + +public String getTextBox() { + return textBox; +} +public void setTextBox(String textBox) { + this.textBox = textBox; +} + +
    + +
    \ No newline at end of file diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/tags/formControlsExample.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/tags/formControlsExample.xml new file mode 100644 index 0000000..df8b0fb --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/tags/formControlsExample.xml @@ -0,0 +1,391 @@ + + + +
    + Form Controls Example +
    + +
    + Form Controls Example +

    This is a full example of all of the NetUI form control tags. In the exampe, the + formTest.jsp page defines a single form containing all of the + NetUI form controls. When this form is posted, the submit + action is called. This will simply pass the form as a page input to the results.jsp + where the full results are displayed. The example contains table layout to make the + example a bit more readable. +

    +
    +
    + <code>Controller.jpf</code> +

    +

    + +
    +
    + formText.jsp +

    +

    + +<%@ taglib uri="http://beehive.apache.org/netui/tags-html-1.0" prefix="netui" %> +<%@ taglib uri="http://beehive.apache.org/netui/tags-databinding-1.0" prefix="db"%> + + + + Form Test + + + +

    Form Test

    +

    This test maps all of the basic types of NetUI form controls to their + underlying data types. +

    + + + + + + + + + +
    +

    CheckBox

    + + + + +
    CheckBox [boolean]
    CheckBox [java.lang.Boolean]
    CheckBox [java.lang.String]
    +
    +

    CheckBoxGroup

    + + +
    CheckBoxGroup + + + + + + +
    +
    +

    FileUpload

    + + +
    FileUpload
    +
    +

    Hidden

    + + + + + +
    Hidden
    Hidden Array[0]
    Hidden Array[1]
    Hidden
    +
    +

    RadioButtonGroup

    + + +
    RadioButtonGroup + + + + + + +
    +
    +

    Select

    + + + +
    SingleSelect + + Select One + Select Two + Select Three + Select Four + +
    MulitSelect + + Select One + Select Two + Select Three + Select Four + +
    +
    +

    TextArea

    +

    +
    +

    TextBox

    +

    +
    ButtonSubmit the Form
    ImageButton
    AnchorSubmit Form Through a Link
    +
    +
    +
    + + +]]> +
    +
    + results.jsp +

    +

    + +<%@ taglib uri="http://beehive.apache.org/netui/tags-html-1.0" prefix="netui" %> +<%@ taglib uri="http://beehive.apache.org/netui/tags-databinding-1.0" prefix="netui-data"%> + + + + Form Post Results + + + +

    Form Post Requests

    +

    This page displays the results of the form post. The posted form + is passed to the page as a PageInput. We then bind to the pageInput and display all + of the resulting values. +

    + + + + + +
    +

    CheckBox

    + + + + +
    CheckBox [boolean]${pageInput.bean.checkBox}
    CheckBox [java.lang.Boolean]${pageInput.bean.checkBoxBoolean}
    CheckBox [java.lang.String]${pageInput.bean.checkBoxString}
    +
    +

    CheckBoxGroup

    + + + + +
    ${container.item}
    +
    +

    FileUpload

    +

    + File Name: ${pageInput.bean.fileUpload.fileName}
    + File Size: ${pageInput.bean.fileUpload.fileSize}
    +

    +
    +

    Hidden

    + + + + + +
    Hidden${pageInput.bean.hidden}
    Hidden Array[0]${pageInput.bean.hiddenArray[0]}
    Hidden Array[1]${pageInput.bean.hiddenArray[1]}
    HiddenBoolean${pageInput.bean.hiddenBoolean}
    +
    +

    RadioButtonGroup

    + + + + +
    ${container.item}
    +
    +

    Select

    + + + + +
    SingleSelect${pageInput.bean.singleSelect}
    SingleSelect + + + + +
    ${container.item}
    +
    +
    +

    TextArea

    +

    + ${pageInput.bean.textArea}
    +

    +
    +

    TextBox

    +

    + ${pageInput.bean.textBox}
    +

    +
    + Return to Form +
    +
    + +]]> +
    + +
    \ No newline at end of file diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/tags/formRepeating.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/tags/formRepeating.xml new file mode 100644 index 0000000..534990a --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/tags/formRepeating.xml @@ -0,0 +1,479 @@ + + +
    + NetUI Repeating Form Control Tags +
    + +
    + Introduction +

    The three NetUI group tags offer a repeating mode that increases the control + the developer has over their output. For the <netui:checkBoxGroup> + and the <netui:radioButtonGroup> tags the control extends to the layout of the resulting + markup. For the <netui:select> tag the developer can control the order of + the options and the value and label when an optionsDataSource + is being used. +

    +

    This is an advanced tag topic. For more information on the basic operations of these tags + see the NetUI Form Control Tags topic. +

    +
    +
    + CheckBoxGroup and RadioButtonGroup +

    This section demonstrates how to control the markup generated by both the <netui:checkBoxGroup> + and <netui:radioButtonGroup> tags. Both tags have an attribute repeater + which, when set to true, turns the tag into a repeating tag. The tag will then loop + over each element found in the optionsDataSource and evaluate the tag's body against the item. + Before the body is evaluated, the implicit object container is setup. For more + information see the data binding container implicit object + topic. +

    +

    This gives the developer more ability to control the layout and style associated with the options + when they are using an optionsDataSource. Below are examples of both the <netui:checkBoxGroup> + and the <netui:radioButtonGroup> tags. +

    +
    + CheckBoxGroup +

    This example will create a horizontal layout for a set of checkboxes. Individual styles + will be applied to the labels of the checkbox. The layout is done using an HTML table. +

    +

    CheckBoxGroup with horizontal layout

    +

    In the JSP fragment below, the <netui:checkBoxGroup> tag is bound + to an optionsDataSource in the page flow. The optionsDataSource + is an array of a class that contains the style, label value and option value for each + element to be displayed in the group. Notice that inside the body of the checkBoxGroup + all the binding expressions start with ${container.item.XXX}. The body will be + repeated for each element in the optionsDataSource. +

    +

    Note: The dataSource + also directly binds to a page flow variable. Typically, the dataSource + would bind to an actionForm variable. +

    + +CheckBox Group + + + +   + + + +]]> +

    The following style information is found in the JSP. These styles affect the + presentation of label output. This is done by setting the styles on the + <netui:span> tags that act as the labels for the generated + checkboxes. +

    + + .normalAttr {color: #cc0099;font-family:Verdana; font-size:8pt;margin:0,0,0,0;} + .normal {color: #cc9999;font-family:Verdana; font-size:8pt;margin:0,0,0,0;} + .normal2 {color: #00cc99;font-family:Verdana; font-size:8pt;margin:0,0,0,0;} + .normal3 {color: #99cc99;font-family:Verdana; font-size:8pt;margin:0,0,0,0;} + +]]> +

    Below is the page flow controller that supports the example above. In the + onCreate method, we initialize the optionsDataSource. + In addition, we provide a java.lang.String[] that will recieve the + results of posting the form back. Finally, an inner class defines a Java bean + that contains the information used by the options. +

    + +package repeating; + +import org.apache.beehive.netui.pageflow.PageFlowController; +import org.apache.beehive.netui.pageflow.Forward; +import org.apache.beehive.netui.pageflow.annotations.Jpf; + +@Jpf.Controller( + simpleActions={ + @Jpf.SimpleAction(name="begin", path="index.jsp") + } +) +public class Controller extends PageFlowController +{ + private Options[] opts; + private String[] results; + + public Options[] getOpts() + { + return opts; + } + + public void setOpts(Options[] opts) + { + this.opts = opts; + } + + public String[] getResults() + { + return results; + } + + public void setResults(String[] resultsOne) + { + this.results = resultsOne; + } + + protected void onCreate() + { + // initialize the opts + opts = new Options[3]; + opts[0] = new Options("Option One","opt-1", "normal"); + opts[1] = new Options("Option Two","opt-2", "normal2"); + opts[2] = new Options("Option Three","opt-3", "normal3"); + } + + /** + * @jpf:action + * @jpf:forward name="index" path="Results.jsp" + */ + @Jpf.Action( + forwards = { + @Jpf.Forward( + name = "index", + path = "Results.jsp") + }) + protected Forward post() + { + return new Forward("index"); + } + + public static class Options implements java.io.Serializable { + private String _name; + private String _optionValue; + private String _style; + + public Options(String name, String value, String style) { + _name = name; + _optionValue = value; + _style = style; + } + + public void setName(String name) { + _name = name; + } + public String getName() { + return _name; + } + + public void setOptionValue(String optionValue) { + _optionValue = optionValue; + } + public String getOptionValue() { + return _optionValue; + } + + public void setStyle(String style) { + _style = style; + } + public String getStyle() { + return _style; + } + } +} + +
    +
    + RadioButtonGroup +

    Note: This example is very similar to the previous example using the + CheckBoxGroup. The only real difference is that the + layout of the radio buttons is vertical. For a detailed discussion, you should + read that example. +

    +

    RadioButtonGroup with vertical layout

    +

    Below is a fragment of a JSP that will layout a RadioButtonGroup in a table vertically. + All of the options have an individually applied style. Notice that the + repeater attribute is set on the <netui:radioButtonGroup> + tag to repeat over the items defined in the optionsDataSource. +

    + + RadioButton Group + + + + + + + +]]> +

    This example can use the same page flow controller as the previous example with one simple + modification. A radio button group will post back a single value. By modifying the + results property on the page flow controller we convert if from a + String[] to just a String. +

    + + private String results; + public String getResults() + { + return results; + } + public void setResults(String resultsOne) + { + this.results = resultsOne; + } + +
    +
    +
    + Select +

    Repeating in a <netui:select> is much different than repeating in + either the <netui:checkBoxGroup> or <netui:radioButtonGroup>. + There is no layout or style information applied to the individual options because typically + they are displayed as a single select box control inside the browser. +

    +

    Repeating in the <netui:select> enables the developer to control the order + of the options and to control the HTML <option> element rendered + for each type of option. A <netui:select> + tag actually creates it's options by iterating over multiple sets of data. For each unique + value found, an HTML <option> element is rendered. + The following table + describes each source of data that can be used to create the output options. +

    + + + + + + + + + + +
    Stage NameSource propertyDescription
    optionoptionsDataSourceThis is an array of some class. Each element of the array will be output + as an option. Typically the class can just be a String or it may be a Java + bean.
    defaultdefaultValueThis is a single value that will be output as an option. This value is always a + String
    dataSourcedataSourceWhen the select is rendered, if the variable bound to contains data, it + will be added to the options. This value may be a single String + or an array of Strings.
    nullnullableOptionTextThis is a special value that indicates a null value. You must set + the nullable attribute to true to enable this.
    +
    + Select Example +

    The following example is a complex Select control <netui:select> + that controls both the order and how each of the HTML <option> + elements are rendered. The source for the JSP is followed by the controller. +

    +

    Note: The select box posts its value back to the page + flow. The typical use would be to post a value back through a FormData + subclass. +

    +

    index.jsp

    + +<%@ taglib uri="http://beehive.apache.org/netui/tags-html-1.0" prefix="netui"%> +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> + + + Order Repeating Select + + + +

    Order Repeating Select

    +

    This example demonstrates using a repeating select. +

    + + + + + ${container.item.name} + + + + + ${container.item} + + + + [Nothing] + + +

    Submit

    +
    +
    +
    +]]> +

    The <netui:select> defines the dataSource, + defaultValue, and an optionsDataSource. These may + all be used to add values to the displayed options. In addition, the "null" + option is also set because the nullable attribute is set to true. + These are the four sources of options. The repeater attribute is set + to true. For this reason, the body of the select will be repeated + for each option to be rendered. Finally, the order of the options is specified + using the repeatingOrder attribute. This is a comma separated list + of the stage names from the table above. In this case, the order of the option + will be "null", "default, "option" and the "dataSource" will not be displayed. +

    + +<netui:select dataSource="pageFlow.results" defaultValue="default Value" + optionsDataSource="${pageFlow.opts}" repeater="true" + repeatingOrder="null, default, option" nullable="true"> + +

    The example uses JSTL logic tags to control the evaluation of expressions for each of the + stages. To include the JSTL core use the following tag library declaration in the JSP. +

    + +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> + +

    The body of the <netui:select> will be evaluted once for each + option to be rendered. In the body, we use the JSTL if tag to control + the evalutation of each option. This is done to prevent expression evaluation errors + when the JSP EL expressions are being evalated for each case. In the container + implicit object, the current stage name is exposed within the metadata. There + is a boolean property for each stage that is true only when options for that stage are being + generated. These boolean properties are optionStage, defaultStage, + dataSourceStage, and nullStage. +

    + +<c:if test="${container.metadata.optionStage}"> + <netui:selectOption repeatingType="option" + value="${container.item.optionValue}" styleClass="normalAttr"> + ${container.item.name} + </netui:selectOption> +</c:if> +<c:if test="${container.metadata.defaultStage}"> + <netui:selectOption repeatingType="default" + value="${container.item}" styleClass="normalAttr"> + ${container.item} + </netui:selectOption> +</c:if> +<netui:selectOption repeatingType="null" value="null-opt" + styleClass="normalAttr"> + [Nothing] +</netui:selectOption> + +

    + The code within the following JSTL if tag will execute only when the + optionsDataSource is being evaluated. This allows + the expressions used to set the properties to be evaluated against a known type and allows + other stages to use different types. +

    + +<c:if test="${container.metadata.optionStage}"> + ... +</c:if> + +

    Within the JSTL if tag, there is a <netui:selectOption>. + The option must identify which stage is being run; this is done by + setting the repeatingType attribute to the stage name. The rest of the + values are set using the container implicit object. This is set to + each item defined for that stage. In this case, it will iterate over the + optionsDataSource. +

    + +<netui:selectOption repeatingType="option"> + value="${container.item.optionValue}" styleClass="normalAttr"> + ${container.item.name} +</netui:selectOption> + +

    The option for the nullable value does not contain any expressions and therefore + does not appear inside a JSTL if tag. It will only render an option + when the stage becomes null and will be ignored in for all other options. +

    + +<netui:selectOption repeatingType="null" value="null-opt" + styleClass="normalAttr"> + [Nothing] +</netui:selectOption> + +

    The page flow controller is a simple controller that contains the properties + exposing the options and a property that will be set when the form is posted. + The options are built in the onCreate method. For the + optionsDataSource each option is defined through an instance + of the Options class. +

    +

    Controller.jpf

    + +package select; + +import org.apache.beehive.netui.pageflow.PageFlowController; +import org.apache.beehive.netui.pageflow.Forward; +import org.apache.beehive.netui.pageflow.annotations.Jpf; + +@Jpf.Controller( + simpleActions={ + @Jpf.SimpleAction(name="begin", path="index.jsp") + } +) +public class Controller extends PageFlowController +{ + private Options[] opts; + private String results; + + public Options[] getOpts() + { + return opts; + } + + public void setOpts(Options[] opts) + { + this.opts = opts; + } + + public String getResults() + { + return results; + } + public void setResults(String value) + { + this.results = value; + } + + protected void onCreate() + { + // initialize the opts + opts = new Options[3]; + opts[0] = new Options("Option One","opt-1"); + opts[1] = new Options("Option Two","opt-2"); + opts[2] = new Options("Option Three","opt-3"); + } + + @Jpf.Action( + forwards = { + @Jpf.Forward( + name = "index", + path = "Results.jsp") + }) + protected Forward post() + { + return new Forward("index"); + } + + public static class Options implements java.io.Serializable { + private String _name; + private String _optionValue; + + public Options(String name, String value) { + _name = name; + _optionValue = value; + } + + public void setName(String name) { + _name = name; + } + public String getName() { + return _name; + } + + public void setOptionValue(String optionValue) { + _optionValue = optionValue; + } + public String getOptionValue() { + return _optionValue; + } + } +} + +
    +
    + +
    \ No newline at end of file diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/tags/htmlMapping.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/tags/htmlMapping.xml new file mode 100644 index 0000000..37ecdaa --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/tags/htmlMapping.xml @@ -0,0 +1,106 @@ + + + +
    + HTML to NetUI Tag Mapping +
    + +
    + HTML to NetUI Tag Mapping +

    The following table maps HTML elements to NetUI Tags. Most of NetUI tags produce HTML elements + directly, which is summerized below. There is a brief description and links to more details in + the tag user documentation. +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Html TagNetUI TagDescriptionLinks
    <a>netui:anchorCreate an anchorSimple Linking, + Form Controls
    <a><img></a>netui:imageAnchorA composite set of HTML elements with an anchor surrounding an image
    <area>netui:areaSpecify a geometric region of an image map and the link associated with it
    <base>netui:baseSpecify the absolute URI for resolving relative URIs
    <body>netui:bodyCreate the body containing the document contentHTML/XHTML
    <form>netui:formA form containing a set of controls that can be posted to the serverForm Controls
    <html>netui:htmlThe containing HTML tagXHTML/HTML
    <input type=checkbox>netui:checkBoxForm Control allowing a binary valueForm Controls
    <input type=checkbox>netui:checkBoxGroupA group of checkboxesForm Controls, + Repeating
    <input type=file>netui:fileUploadForm Control allowing a file to be uploadedForm Controls
    <input type=hidden>netui:hiddenForm Control that posts a value backForm Controls
    <input type=image>netui:imageButtonForm Control that creates a graphical buttonForm Controls
    <input type=radio>netui:radioButtonGroupForm Control creating a single selection radio button groupForm Controls, + Repeating
    <input type={submit, button, reset}>netui:buttonCreate a button, supports submit, button and resetForm Controls
    <input type={text, password}netui:textBoxForm Control creating either a text or password fieldForm Controls
    <img>netui:imageEmbed an image into a document
    <label>netui:labelCreate a label to attach information to a Form Control
    <option>netui:selectOptionCreate an item inside of a select controlForm Controls
    <script>netui:scriptBlockCreate a client side JavaScript blockJavaScript, + XHTML/HTML
    <select>netui:selectForm Control that creates a single or multiple selectionForm Controls, + Repeating
    <span>netui:spanCreate an inline span element
    <textArea>netui:textAreaForm Control creating a multiple line text input fieldForm Controls
    +
    + +
    \ No newline at end of file diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/tags/index.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/tags/index.xml new file mode 100644 index 0000000..6b5667d --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/tags/index.xml @@ -0,0 +1,112 @@ + + + +
    + NetUI Tag Library Overview +
    + +
    + NetUI Tag Library Overview +

    This topic provides an overview of the NetUI JSP tag libraries. NetUI provides three tag + libraries, the core HTML tags, the data grid tags and a simple set of template tags. +

    + + + + + +
    Tag Library URIPrefixDescription
    http://beehive.apache.org/netui/tags-html-1.0netui + This is the primary tag library supporting HTML, including the form controls. It provides a number + of features, used throughout the tag libraries, such as error reporting and base tags. In addition, + it contains the Tree support.
    http://beehive.apache.org/netui/tags-databinding-1.0netui-data + This tag library provides binding to relational data, providing the Data Grid. The feature + spans uses from simple tables, to sortable, filterable, pageable and updateable grids. +
    http://beehive.apache.org/netui/tags-template-1.0netui-template + This tag library provides a very simple templating facility, allowing common elements such + as headers, footers, etc.
    +

    The prefix is the prefix used within the documentation set and obviously can be changed.

    +

    In a typical JSP, the following lines would be used to include each of the NetUI tag libraries:

    + +<%@ taglib uri="http://beehive.apache.org/netui/tags-html-1.0" prefix="netui"%> +<%@ taglib uri="http://beehive.apache.org/netui/tags-databinding-1.0" prefix="netui-data"%> +<%@ taglib uri="http://beehive.apache.org/netui/tags-template-1.0" prefix="netui-template"%> +

    For more information on JSPs with NetUI see the JSP Files + topic. In particular, there is a very simple template + providing a starting point for developing NetUI enabled JSPs. +

    +

    The NetUI tags support binding values from implicit object to attributes through the + JSP 2.0 Expression Language (EL). This + support is for read-only data. In addition, many tags support read-write + access to implicit objects. This support is almost always done through the dataSource + attribute on the tags. In addition, there are a number of binding contexts introduced to allow + binding to page flows and other NetUI implicit objects. + For more information on data binding see the + Data binding to NetUI Implicit Objects topic. +

    +
    +
    + Runtime Error Reporting +

    The tag libraries report runtime errors in a common way. In the page fragment below, a set of + anchors have invalid attribute values. There is an error reported where the tag would normally + have rendered HTML. In addition, there is a table rendered at the end of the document that + contains the details of the errors. In many cases, runtime errors in the tags result in the + tag reporting an error and rendering continues on. This means that multiple errors will be + reported. In addition, many tags will report multiple errors. Typically, errors wouldn't occur in + production because they would be fixed during development. The error reporting is intended to + make developing new pages easier by making errors obvious. +

    +

    Runtime Errors Reported in a Rendered Page

    +

    Runtime Errors produced by the tags

    +
    +
    + Core HTML Tags +

    The core HTML tag library provides the core HTML elements. These include both the HTML + structure and the HTML form controls. In addition, the tags provide a number of core + features that are used by all of the NetUI tag libraries. +

    +

    The HTML tags have a simple and expected mapping to the HTML elements that they generate. See + the HTML to NetUI Tag Mapping for details. In addition, + the HTML controls, called form controls in this document, have additional details in the + NetUI Form Control Tags topic. +

    +

    The HTML tags can support multiple versions of the HTML specifications, including HTML 4.01 + and XHTML 1.0 Transitional. The default format is specified for a WebApp and may be overridden + for an individual document. For more information see the + HTLM and XHTML Support topic. +

    +

    NetUI provides the ability to build pages that are part of a larger composite page such as + a portal. Part of this support is the ability to scope the HTML id attributes. + In order to allow client side JavaScript to run, the core tags provide support for accessing + the generated id and name values based upon a local name. For + more information on JavaScript support see the + Tags Support for JavaScript topic. +

    +

    Finally, the core tags provides a set of tags and classes that can be used to build complex + tree representations. See the Tree Tags topic for information + on creating trees. +

    +
    +
    + Data Tags +

    + The NetUI data tag library provides tags that render complex, high-level HTML markup in a page or + that support data binding in JSPs. The library supports a range of features from simple tables + rendered with the repeater to complex data grids rendered with the data grid tag set. The data grid + includes support for sortable columns, filtering, paging and updatable grids. Styles can be applied + to the grids to customize their presentation. For more information on the data grid see + Beehive NetUI Data Grids. For more information on the repeater tags, see + Repeating JSP Tags. +

    +
    +
    + Template Tags +

    The template tags represent a very simple templating system. The tags allow for a very simple + template page to be created. Content pages then include their template to form the resulting + rendered page. The content pages are written as sections of content that are inserted into defined + points inside the template. For more information on the template tags see the + NetUI Template Tags topic. +

    +
    + +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/tags/javascript.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/tags/javascript.xml new file mode 100644 index 0000000..1647e79 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/tags/javascript.xml @@ -0,0 +1,499 @@ + + + +
    + Tags Support for JavaScript +
    + +
    + Introduction +

    The following topic explains how the NetUI JSP tags provide support for client side + JavaScript development. + The primary JavaScript support provides the ability to looking up HTML DOM elements + produced by the tags. Lookup may be done by either the id or + name attributes. In addition, the NetUI tags provide the ability to + generate unique values for + the HTML id attribute. +

    +

    NetUI owns the value of the + name attribute generated for the HTML form controls. + It's very common to write JavaScript that would like to access these control DOM elements + using the name. The NetUI JavaScript support provides a mapping between the local name and the + generated name. +

    +

    In addition, NetUI provides scoping facilities that ensure the HTML + id attribute is unique + as required by the HTML specifications. In a simple page, this is usually not a problem because all + of the + id attributes are specified in a single source file. There are situations, + such as content within a portal, where a NetUI page is generated as a portion of a larger page. + In these cases, unique + id values must be generated when the page is generated. The JavaScript support + in NetUI allows for looking up DOM elements in JavaScript using a "local" name and scope. This allows + JavaScript to be written as if the page was a simple page and for it to become part of a composite + page without modification. +

    +

    Note: The pre-Beehive NetUI tags provided a different set of routines for looking + up DOM elements. A configuration option is available which will turn this mode on. For more information see the + id-javascript section of the configuration reference page. +

    +
    +
    + Backward Compatibility +

    There are two JavaScript functions intended to support client side JavaScript, + lookupIdByTagId() and lookupNameByTagId(). These are the public + interfaces provided to lookup HTML DOM elements and Beehive will maintain backward compatibility + on these methods. All of the other JavaScript methods and the values of the HTML name + and id attributes output into the generated HTML may change over time. Developers + should not build dependencies on these values. In some cases, this document describes the details + of these low level features for explanation purposes. +

    +
    +
    + JSP Tags and Attribute +

    This section describes the primary NetUI JSP tags and attributes used to support JavaScript.

    +
    + tagId +

    The NetUI tags usually do not allow setting the + id attribute directly. Instead, + the generated HTML elements are given "local" names using the + tagId attribute. + The value of this attribute is used to generate the + id attribute of the resulting + HTML elements. In addition, for form controls, a mapping is maintained from the + tagId value to the generated name. +

    +
    +
    + ScriptContainer +

    Scoping of the generated HTML + id attributes is done by the + ScriptContainer tags. A ScriptContainer provides either + an explicit name or a uniquely generated name. All of the tagId values found in its + decedents will have this name prefixed to their tagId value when their qualified id + value is created. +

    +

    There are two NetUI JSP tags that are ScriptContainers, <netui:scriptContainer> and + <netui:html>. The ScriptContainer tag represents the basic features. The Html + tag is a subclass of ScriptContainer and provides additional HTML specific features. + ScriptContainers may be nested. The + id value is generated by prefixing + all of the ancestor ScriptContainer names to the value of the + tagId. +

    +

    The ScriptContainer tags support two attributes for creating a name, + idScope and generateIdScope. The + idScope sets an explicit value for the generated scope. The + generateIdScope, when true, + will cause a unique id scope name to be generated. This value is unique for the request. +

    +

    The NetUI tags dynamically generate JavaScript in certain situations. + The top most ScriptContainer gathers up generated JavaScript then renders it into the HTML + document. There isn't a requirement to have a ScriptContainer for most of the JavaScript + enabled features; this includes the lookup methods. If the ScriptContainer is not present, + the generated + JavaScript will be output inline with the tags. The result is duplicate JavaScript will be + rendered throughout the page for features like setting + tagId or image + rollovers. The advantages of using a ScriptContainer is this JavaScript is not duplicated + and will be written out in a single script block in the generated HTML file. +

    +

    + Note: the generated id scope may not be the same from request to request on + the same page. It may change if content preceding the JSP changes from request to + request, or some conditional logic on the page, such as JSTL, changes the number or order + of ScriptContainers. +

    +
    +
    + ScriptBlock +

    The <netui:scriptBlock> tag is used to position user provided JavaScript in relationship + to the framework generated JavaScript. This tag supports inserting JavaScript before + or after + the framework generated JavaScript. When you want to create valid XHTML or HTML this tag is + required. See the HTLM and XHTML Support topic + for more information + on creating valid XHTML and HTML using the NetUI JSP tags and information on the + ScriptBlocks role. +

    +
    +
    +
    + Simple Example +

    This section presents a very simple example which demonstrates the use of the + tagId + attribute, scoping ids, and the lookup methods. In this example + there is a simple form containing a checkbox. The document is automatically scoped to generate + unique ids within the document. +

    +
    + JSP Code +

    This JSP file demonstrates the use of + tagId and scoping. + It also contains JavaScript that looks up DOM elements and dynamically creates some output + verifying these elements are found. The screen shot at the end of this document + displays the expected dynamically generated content. +

    +

    tagIdSupport.jsp

    + +<%@ taglib prefix="netui" uri="http://beehive.apache.org/netui/tags-html-1.0"%> + + + tagIdSupport + + + + + + Checkbox: +   + +
    +

    + The following calls the generated JavaScript support to lookup DOM elements. +

    +

    + + + // find the element that will provide the output

    and the scope for lookup scope + var p = document.getElementById("javaOut"); + var scope = document.getElementById("scopeOneSpan"); + + // create the contents of the output paragraph + var val = "Lookup the Form by name and id

    "; + var form = document.getElementById(lookupIdByTagId("form",scope)); + val = val + "Form by id is: " + + form.id + ", type: " + form.nodeName + "
    "; + form = document[lookupNameByTagId("form",scope)]; + val = val + "Form by name is: " + + form .name + ", type: " + form.nodeName + "
    "; + + val = val + "
    Lookup Checkbox by name and id

    "; + var check = document.getElementById(lookupIdByTagId("check",scope)); + val = val + "Checkbox by id is: " + + check.id + ", type: " + check.nodeName + "
    "; + check = form[lookupNameByTagId("check",scope)]; + val = val + "Checkbox) by name is: " + + check .name + ", type: " + check.nodeName + "
    "; + p.innerHTML = val; + + + + +]]> +

    In the JSP code, the <netui:form> and <netui:checkbox> elements are both named + using the + tagId attribute. The values of the tagId ("form" and "check") + are the local name of these elements. +

    + +<netui:form tagId="form" action="begin"> +<netui:checkBox tagId="check" dataSource="pageFlow.check" /> + +

    In this example, the <netui:html> tag generates a scope name for all + tagId values. This scoping isn't required in this example, but + demonstrates the use of scoping within a page. The + generateIdScope + attribute on the <netui:html> tag will automatically generate a unique "name" for the scope + defined by the tag. The fully qualified + name for each DOM element is creating by prefixing the local name with each scope name + defined by all ancestor ScriptContainer JSP tags. Prefixing is done moving up the hierarchy + until the root is found. In this example, the <netui:html> tag will generate a name of + n0. + The generated name for the <netui:form> tag will then become + n0.form. + The '.' character is used to separate the names. +

    + +<netui:html generateIdScope="true"> + +

    The source JavaScript in the page is found inside of a ScriptBlock. The reason for using + a ScriptBlock is to control the placement of the script in relationship to the framework + generated lookup functions. In this example the + placement attribute is set + to the value + after indicating that the contents of this block should appear + after the framework generated JavaScript. This is required because the JavaScript contains calls + to functions which are generated by the framework. +

    + +<netui:scriptBlock placement="after"> + +

    When one of the NetUI JSP tags contains a + tagId attribute, the framework will + generate some JavaScript which supports looking up DOM elements based upon the local name and + a scope. There are two primary JavaScript functions generated, + lookupIdByTagId + and + lookupNameByTagId. The former will return the real id of a DOM element based upon + the tagId value and the later will return the real name based upon the tagId value. In the + example, we lookup the form based upon by id. Then we lookup the DOM input element + representing the checkbox based upon its name. +

    + +var form = document.getElementById(lookupIdByTagId("form",scope)); +check = form[lookupNameByTagId("check",scope)]; + +
    +
    + Controller +

    The Page Flow controller simply supports the sample. It defines the + required begin action and a property bound to by the <netui:checkbox>. +

    +

    + Controller.java +

    + +
    +
    + Generated HTML +

    This section contains the generated HTML page sent to the browser. The output of the + NetUI JSP tags and the literal content are contained in the page. The tagId has been used to name + HTML elements and the framework generated JavaScript is present. +

    +

    + Generate HTML on Client Browser +

    + + + + + + tagIdSupport + + + + + + Checkbox: +   + +
    +

    + The following calls the generated JavaScript support to lookup DOM elements. +

    +

    + + + + + +]]> +

    In the generated HTML, the names and ids of the form and checkbox input + elements have been generated by the NetUI JSP tags. The n0 portion of the + name is prefixed + to the tagId because the <netui:html> tag generated that value. For the checkbox, the name + is generated by the JSP tag and contains an expression allowing the NetUI + check property to be updated by the NetUI framework. +

    + +<form name="n0.form" id="n0.form" action="/dev/tagIdSupport/begin.do" method="post"> +<input type="checkbox" name="wlw-checkbox_key:{pageFlow.check}" id="n0.check"> + +

    In addition, the framework generated JavaScript and the JavaScript defined in the JSP have + the proper relationship with each other. The framework JavaScript precedes the JSP defined + JavaScript. +

    +

    Finally, the <html> element has an additional attribute name spaced into NetUI. In many + cases the NetUI tags generate additional attributes on some HTML elements to provide information + to JavaScript. These attributes will always be name spaced into the netui name + space. In this + case, the netui:idScope attribute is used by the lookup code to create the fully + qualified name. +

    + +<html lang="en" netui:idScope="n0"> + +
    +
    + Framework Generated JavaScript +

    This section describes the details of the framework generated JavaScript. This JavaScript + was generated because NetUI tags used the tagId attribute. This JavaScript + will not be generated in pages that do not use tagId. +

    +

    Framework Generated JavaScript

    + +

    There are two JavaScript functions intended to support user JavaScript, + lookupIdByTagId and lookupNameByTagId. Both methods + take a name and scope. The name should be the local name of the DOM element you want to + lookup. The scope is some type of DOM element that is found in the same scope as + the element that is to be looked up. This is typically a button or link that is + found in the same scope. +

    + +<a onclick="someFunction(this);return false;" href="#"> + +

    The user defined JavaScript function someFunction receives a reference + to the anchor DOM element that can then be used to lookup other DOM elements in the same + scope. +

    +

    These two methods act as the public interface to the framework lookup code. NetUI will + maintain backward compatibility for these two methods. The other code generated by the + framework and the value of the name and id + attributes may change over time. These features should be considered "internal". + Developers should not build dependence on these features + of the framework generated JavaScript support. +

    +

    Note: In the example, we are using an element found in the document using + the id attribute value. This is actually not a typical usage because + the id value is not scoped by the framework. This JSP could not be included twice + in a composite page because it would result in the same id appearing multiple times. +

    +
    +
    + Browser Results +

    This section contains a screen shot of the page from the browser. The dynamically generated + content can be seen. +

    +

    + Page as seen in a browser +

    +

    + JavaScript result in the browser +

    +
    + +
    + +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/tags/repeater.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/tags/repeater.xml new file mode 100644 index 0000000..09e60c5 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/tags/repeater.xml @@ -0,0 +1,140 @@ + + + + +
    + Repeating JSP Tags +
    + +
    + Overview +

    + The NetUI JSP tag library contains a set of JSP tags used to repeat over a data set rendering + HTML markup for each item in the set. There are three sets of these tags: +

    +
      +
    • Repeater -- used to render table rows, lists, and other repeating blocks of markup
    • +
    • Cell Repeater -- used to render markup in cells of a table of fixed or variable size
    • +
    • Data Grid -- used to render complex pageable, sortable, filterable data grids
    • +
    +
    +
    + Repeater +

    + The repeater is used similar to a for loop for iterating over a data set. In general, the repeater + renders blocks of markup repeatedly for each item in a data set. It is also possible to create a header and footer + inside of the repeater that render before and after the data set is rendered, respectively. Each of these regions + is offset from the others by JSP tags that mark rendering boundaries inside of the repeater. Repeaters + are often used to render table rows, ordered and unordered lists, repeating divs and so on. The + cell repeater is useful for repeating over a data set to render table cells, and the + data grid is useful for rendering complex data sets. In the simple cases of + displaying read-only data, the repeater is similar to the JSTL forEach tag. In complex read / write + cases, the repeater can participate with the other NetUI tags to create UI for editing entire data sets. For example, + the repeater can be used to render HTML for editing quantities of items in a shopping cart. +

    +
    + Read only Data +

    + The repeater binds to a data set using its dataSource attribute. The simplest repeater would render + a TODO list as an unordered list like: +

    + +
      + +
    • ${container.item.taskName} -- ${container.item.description}
    • +
      +
    +]]> +

    + The container implicit object is available for data binding with the JSP 2.0 Expression Language + and contains several properties including index and item which provide access to the + index of the current item in the data set and to the current data item, respectively. +

    +

    + A header and footer can be added to the repeater by using the repeaterHeader and the repeaterFooter + tags. For example, the above unordered list could be encapsulated in the repeater as: +

    + + + +
      + + +
    • ${container.item.taskName} -- ${container.item.description}
    • + + +
    + +
    +]]> +

    + The repeater can also display a default message when no data is available by setting the defaultText + attribute. Additionally, when rendering sparse data sets, it is often useful to ignore null members; this + can be enabled by setting the ignoreNulls attribute to true. +

    +
    +
    + Read / write Data +

    + The repeater tags can also be used to render read / write HTML markup. A simple example is displaying a user interface + to change the quantity of each item in a shopping cart. The samples/netui-samples/ui/repeaterediting/ + sample in a Beehive distribution contains such an example. In this sample, the repeater appears as: +

    + + + + ${container.item.name} + + + + + + +
    + + + + + + +
    + +]]> +

    + In this sample, the repeater binds to an array of Item objects with a set of simple JavaBean properties + price, quantity, and giftWrap. The quantity and giftWrap + properties are rendered using the <netui:textBox> tag and <netui:checkBox> tags which + allow the browser to edit the values of those properties when the page POSTs. +

    +

    + This is possible because the NetUI form element tags work in cooperation with the repeater to rewrite expressions such + as container.item.giftWrap into an expression that is used for the name of a check box in the form + actionForm.items[1].giftWrap. The value of container.index for each item in the array is used + to index into the actionForm.items array, and the property giftWrap is added to the end to form + the new expression. The result is an expression that can POST to the server and can be used to look-up a specific form + property on a specific item in the Item JavaBean array. +

    +
    +
    +
    + Cell Repeater +

    + The cell repeater is a JSP tag that is used to render the contents of each cell in an HTML table. This user interface + pattern is common in catalogs and shopping carts and is often used to display a single item per cell. The cell + repeater can be constrained to render a table with a fixed length, a fixed width, or both a fixed length and width. + For example, the following sample will display a table of PetBean objects, one per cell in a table two cells wide: +

    + + ID:
    + Name:
    + Description:
    + Price:
    + + ]]> +
    + +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/tags/template.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/tags/template.xml new file mode 100644 index 0000000..5f38c28 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/tags/template.xml @@ -0,0 +1,224 @@ + + +
    + NetUI Template Tags +
    + +
    + Introduction +

    The NetUI template tags provide a very simple templating mechanism. The basic concept + is to create a template page that contains the layout and information you want on + each page within a site or page flow. Then content pages are created which provide + the content and represent the pages of the site. You directly access the content + pages and they pull in their template to produce the final rendered document. +

    +
    +
    + Template Page +

    The following JSP page defines a simple template. This template provides the + overall layout of the site and places to drop content. There are two types of + content <netui-temp:includeSection> and <netui-temp:attribute>. + The <netui-temp:includeSection> tag is the primary placeholder for content. The + content page will provide sections of content that fit into the placeholders defined + in the template. In addition, the <netui-temp:attribute> tags + is a named attribute that represents some type of value. These may be found in + more than one place in the page. +

    +

    template.jsp

    + +<%@ taglib uri="http://beehive.apache.org/netui/tags-template-1.0" prefix="netui-temp" %> +<%@ taglib uri="http://beehive.apache.org/netui/tags-html-1.0" prefix="netui" %> + + + <netui-temp:attribute name="title"/> + + + + + + + + +
    + +
    +
    + +
    +
    + +
    +
    +
    +]]> +

    In the template above there is an <netui-temp:attribute> which + defines the named attribute title. This attribute is used in two + places, the first place is the within the HTML <title> in the header. + The second place this is used is the visual title on the page. +

    + +<title><netui-temp:attribute name="title"/></title> +... +<caption> + <span style="font-size: large;color:blue"><netui-temp:attribute name="title"/></span> +</caption> + +

    There are two section defined for this page. These sections will contain the primary + content of the page. The <netui-temp:includeSection> tag defines the + placement of the section and gives a name to it. A content page will define the contents + of each section. In the example there are two sections defined left and + right. +

    + +<td width="200pt" style="border: 1pt solid black"> + <div style="height: 300pt"> + <netui-temp:includeSection name="left"/> + </div> +</td> +<td valign="top" style="padding:0,10"> + <netui-temp:includeSection name="right"/> +</td></tr> + +
    +
    + Content Page +

    The content pages provide the content displayed within a template. The content pages also + act as the addressable artifacts. This means that index.jsp can be directly accessed and + the template will be applied when the content is rendered. Below is a typical content page. + This content page will define a set of links which are displayed in the left + section and some content that is displayed in the right section. +

    +

    The template page may be located anywhere in the site. It does not have to be located in + the same location as the content page. The templatePage attribute specifies the + template page an may be either absolute to the webapp root or relative to content page. + +

    +

    index.jsp

    + +<%@ taglib uri="http://beehive.apache.org/netui/tags-databinding-1.0" prefix="netui-data"%> +<%@ taglib uri="http://beehive.apache.org/netui/tags-html-1.0" prefix="netui"%> +<%@ taglib uri="http://beehive.apache.org/netui/tags-template-1.0" prefix="netui-temp" %> + + + +

    Links

    +
    + + ${container.item.name}
    +
    +
    +
    + +

    ${pageFlow.content}

    +
    +
    +]]> +

    All of the rendered content inside of a content page appears inside of tags. The + <netui-temp:template> tag defines the name of the template to apply + to the content. In this example the template.jsp is the template applied + to the content defined. +

    + +<netui-temp:template templatePage="template.jsp"> + +

    Next all of the attributes defined inside of the template are defined. The + <netui-temp:setAttribute> tag provides the value for a named attribute. The + name and value attributes must both be set. +

    + +<netui-temp:setAttribute name="title" value="Basic Template Example"/> + +

    Finally, the content of the two sections is provided. The body of the + <netui-temp:seciton> provides the content for the named section. You + must set the name attribute to match one of the sections defined in the + template. +

    + +<netui-temp:section name="left"> + <h4>Links</h4> + <div style="padding:0,0,0,10pt;color:gray;"> + <netui-data:repeater dataSource="pageFlow.links"> + <netui:anchor href="http://${container.item.href}">${container.item.name}</netui:anchor><br> + </netui-data:repeater> + </div> +</netui-temp:section> + +
    +
    + Page Flow Controller +

    This example uses a very simple page flow controller that simply provides + some read-only properties that are bound to by the content pages. Notice that + the begin action goes to the content page index.jsp. +

    +

    Controller.jpf

    + +package template; + +import org.apache.beehive.netui.pageflow.PageFlowController; +import org.apache.beehive.netui.pageflow.annotations.Jpf; + +@Jpf.Controller( + simpleActions={ + @Jpf.SimpleAction(name="begin", path="index.jsp") + }, + multipartHandler=Jpf.MultipartHandler.memory +) +public class Controller extends PageFlowController +{ + private Link[] links; + + private String content = + "<h4>Today's Content</h4>" + + "<p>This is some content that would be found in a database or content managment system of some" + + "type. For this example it's just hardwired into the page flow."; + + protected void onCreate() + { + links = new Link[5]; + links[0] = new Link("ESPN", "www.espn.com"); + links[1] = new Link("Google", "www.google.com"); + links[2] = new Link("CNN", "www.cnn.com"); + links[3] = new Link("BEA", "www.bea.com"); + links[4] = new Link("gmail", "www.google.com/gmail"); + } + + public Link[] getLinks() { + return links; + } + public String getContent() { + return content; + } + + + public static class Link { + private String name; + private String href; + + public Link(String name, String link) + { + this.name = name; + this.href = link; + } + + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + public String getHref() { + return href; + } + public void setHref(String href) { + this.href = href; + } + } +} + +
    + +
    \ No newline at end of file diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/tags/tree.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/tags/tree.xml new file mode 100644 index 0000000..aeaaf47 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/tags/tree.xml @@ -0,0 +1,438 @@ + + + +
    + Tree Tags +
    + +
    + Introduction +

    The following topic explains the tree tags and classes and how they are used to create + and render trees. A tree is rendered in an HTML page based upon an + object representation of the tree. NetUI defines a set of classes which + create the tree structure which is rendered. The object representation may be created + either through NetUI JSP tags found in a JSP or may be created programmatically + in a page flow or shared flow. This means that there are parallel representations + of a tree. In a JSP, a set of JSP tags represent the tree. This representation is + then transformed into a tree data structure defined by a set of tree classes. +

    + +
    +
    + Simple Example +

    This section presents a sample of the most basic tree. The tree is created in a JSP and + displays a simple tree on the page. The tree itself has a root node with three children. The + root may be expanded and collapsed. Any of the tree nodes may be selected. +

    +
    + Simple Example Code +

    + simpleTree.jsp +

    + +<%@ taglib uri="http://beehive.apache.org/netui/tags-html-1.0" prefix="netui"%> + + + SimpleTree + + + + + + 0 + + 0.0 + + 0.1 + 0.2 + + + + +]]> +

    The <netui:tree> tag is the JSP tag that adds a tree to the page. It is responsible + for rendering the tree in the generated HTML page. In this example, the contents of the tree + itself are also + defined in the <netui:tree> tag by using the <netui:treeItem> + tags and nesting them + in a tree structure. In this simple case, the tree has a root (0) with three children (0.0, + 0.1, and 0.2). +

    +

    There are three required attributes on the <netui:tree> tag, + dataSource, tagId + and + selectionAction. The dataSource is used to bind to a + TreeElement based data structure representing the tree to be displayed. + The selectionAction is the action that will be called when a node is selected + in the tree. In some cases, it may also be called when a node in the tree is expanded or + collapsed. In addition, the tagId attribute is also required. If + runAtClient is true then you must also specify the name of the + tree by setting the tagId. +

    +

    + Note: In the example above, the leaf nodes are defined in two manners. The + first child (0.0) uses the <netui:treeLabel> to set the nodes label. The next two + children (0.1 and 0.2) are defined with the label as the body of the <netui:treeItem>. The + <netui:treeItem> supports setting the label value from the body of the + <netui:treeItem> if it is a leaf in the tree. You are required to use + the <netui:treeLabel> for all interior nodes or nodes with children. In other + words, <netui:treeItem> does not support mixed content; meaning that interior nodes must use + <netui:treeLabel> to set the label value and all text inside the body is ignored. +

    +

    + Controller.jpf +

    + +

    This very simple Page Flow controller supports displaying a tree. There is a single property + "simpleTree" which holds a reference to a TreeElement. This TreeElement represents the root + of the underlying tree object structure which is rendered by the <netui:tree> tag. + There are two actions defined, the standard + begin action and the + postback + action. The + postback action is called when a selection or expansion link is selected + in the rendered tree. +

    +
    +
    + Simple Sample Lifecycle +

    This section describes the basic tree lifecycle using the SimpleTree example above. The + following figure represents the basic lifecycle of a tree being rendered by a <netui:tree> + tag. +

    +

    + Tree Tag Lifecycle +

    +

    The dataSource attribute is a required attribute on all trees. It binds + to an instance of a TreeElement (defined in + org.apache.beehive.netui.tags.tree). All trees are represented as tree data + structure with a single root. The dataSource attribute binds to this root. +

    +

    When the <netui:tree> tag begins processing it checks to see if the variable + bound to by the dataSource is equal to null. If it is, then the tree will + process it's body content to create the tree data structure. If the + dataSource is not null, then that tree's data structure is used to render content. + If you want to programmatically (or dynamically) create a tree, you may create the tree structure + before the bound variable is accessed. Typically this would be done in the onCreate + method of a shared flow or page flow. +

    +

    In the simpleTree sample, the first time the page is displayed the body of the tree tag is + processed because the page flow's property + simpleTree is null. This creates the initial + tree data structure which is then rendered. When the page is requested + again, for example when a tree element is selected, the tree data structure created on the first + request continues to be used and the body of the <netui:tree> tag is ignored. +

    +

    Note: A very common development task is to iteratively develop the + <netui:tree>'s body content. In order for any changes to be reflected when the tree is + rendered, the variable bound to by + dataSource must be null. It is + common to add an action to the page flow that will reset the value to null and call + that from a link on a page. If variable is not null, changes to the JSP will not be + reflected in the rendered tree. +

    +
    +
    +
    + Tag and Classes +

    + This section describes the primary JSP tags and how they relate to the classes which + define the underlying data structure representing the tree. + All of the tree features are available both in the tree tags as well as the underlying tree classes (described below). +

    +
    + Tag to Class Mapping +

    There are a number of JSP tags that allow creation of tree through JSPs. These tags build + the underlying data structures representing the tree. This section describes the mapping + between the JSP tags and the actual classes that represent the tree. +

    +

    + Note: in many cases, this document describes setting attributes on the tree + JSP tags to enable features. In reality, the attributes are passed through to the + TreeElement class which usually has a corresponding property. Other tags + map their values to properties of the + TreeElement. If you + are programmatically creating a tree by building the tree hierarchy using TreeElements, you + directly set properties on the tree classes. +

    +

    The following list describes the mapping of the tree JSP tags to underlying tree classes: +

    +
      +
    • Tree -- The <netui:tree> tag doesn't create + a TreeElement. It binds to + a TreeElement representing the root of the tree data structure. The <netui:tree> + tag does create the initial TreeRenderState object representing how the tree is rendered. +
    • +
    • TreeItem -- The <netui:treeItem> tag will create a + TreeElement. If the <netui:treeItem> is the root of a tree, then the + TreeRootElement will be created. +
    • +
    • TreeLabel -- The <netui:treeLabel> tag sets + the value of the label which is stored as a property of a TreeElement. + Using this tag is required for non-leaf nodes. For leaf nodes + the body content of the <netui:treeItem> will be used as the label value as long as that body does + not contain other JSP tags (mixed content). +
    • +
    • TreeContent -- The <netui:treeContent> tag sets the + value of the content for a TreeElement. The content is a property of the + TreeElement. +
    • +
    • TreeProperyOverride -- The <netui:treePropertyOverride> + tag is used to override various attributes on the tree such as the selection action and images. + This tag will create an InheritableState object and set it on the + TreeElement. +
    • +
    • TreeHtmlAttribute -- The <netui:treeHtmlAttribute> + tag is used to set additional attributes on the HTML generated when rendering the node. + This tag will create a TreeHtmlAttributeInfo class that is set on the + TreeElement. +
    • +
    +
    +
    + ITreeRootElement +

    In the SimpleTree example above, we described the tree data structure as being a + hierarchy of TreeElement nodes. Many advanced features, including runAtClient, of the tree + require the root of the tree to implement the interface ITreeRootElement. + The class TreeRootElement extends TreeElement and implements + ITreeRootElement, providing a default implementation. In the SimpleTree example, + when the body + of the <netui:tree> is processed, the root <netui:treeItem> is created as a + TreeRootElement and all other <netui:treeItem>'s are created as TreeElements. +

    +

    The following features require the root element in a tree to implement ITreeRootElement: +

    +
      +
    • runAtClient -- Allows the tree to be expanded and + collapsed on the client without round trips to the server. +
    • +
    • Root Images -- Allows setting different expand and collapse images + on the root node of the tree. +
    • +
    +

    The following additional state is tracked by the root element: +

    +
      +
    • Selection -- Direct access to the currently selected tree element. +
    • +
    • Tree State -- Access to the InheritableState and TreeRenderState + defined on the tree (explained below). +
    • +
    • Images -- Allows different expand and collapse images to be set on the root + supporting the Root Images feature. +
    • +
    +
    +
    +
    + Tree Features +

    This section describes the basic features of the NetUI Tree. The SimpleTree example introduces the + basic mechanics for creating a tree in a page flow. A tree is output into the HTML page as + a hierarchy of TreeElements. The SimpleTree example renders the following: +

    +

    + Tree Tag Display +

    +

    The root of the tree supports expanding and collapsing. The children of a node appear + at the same level. Trees appear commonly in applications such as file system explorers and + are good at representing limited hierarchical data sets. +

    +
    + runAtClient +

    The <netui:tree> tag has an attribute + runAtClient which when + set to + true will enabled expanding and collapsing the tree on the client + without server round trips. When runAtClient is on, the tree will be completely rendered + into the generated HTML. Client side JavaScript will then collapse and expand nodes when + the user interacts with the tree. The following image describes the interactions between + the server and client. +

    +

    + Flow of the tree when runAtClient is true +

    +

    runAtClient uses + XmlHttpRequest to update the underlying state on the server + as the user interacts with the tree on the client. This mode requires JavaScript and XmlHttpRequest + support in the client browser. This mode of operation is commonly referred to as AJAX + (Asynchronous JavaScript and XML). It minimizes the amount of information sent between + the client and server when the + user is exploring the tree itself. +

    +

    In the diagram above, when the tree is rendered, all of the nodes will be rendered into the + HTML document generated. JavaScript on the client will then process the tree when the + HTML document is loaded. The JavaScript will turn off display of tree nodes which + are collapsed so that the tree appears in the expected state. As the user interacts with + the tree by expanding and/or collapsing nodes, JavaScript will continue to turn on and off + the display of tree nodes (and their children). In order to update the state of the tree + stored on the server, the client also use XmlHttpRequest to send messages to the server + indicating the nodes that are being expanded and collapsed. The next full server request + will display the tree properly because the internal state has been updated as the user + interacted with the tree. +

    +
    +
    + expandOnServer +

    When a tree has the runAtClient attribute set, then individual elements + can indicate that they need to be expanded on the server by setting the + expandOnServer attribute on the <netui:treeItem> tag. When + expandOnServer is enabled, if the node is in a collapsed state, + the node itself will be rendered in the generated HTML, but + all children nodes will not. When the user expands the node, an XmlHttpRequest is made + to the server and the children (and possibly their children) will be rendered into HTML + and sent back to the client. JavaScript will update the DOM and cause the children to be + displayed. Once the children are received, all further expand and collapse operations happen + on the client. +

    +

    runAtClient and expandOnServer can be used together to optimize the amount of tree state + rendered into the initial request and then to minimize the amount of state transferred + when the user is exploring the tree. It is very common for people to drill + into one or two areas of a tree after searching the top level nodes. To optimize for + this type of browsing, render out the top few levels of a tree and then create a layer + of children that set expandOnServer to true. The top few layers will be initially rendered + and when a user goes deep into one, the server provides the branch asynchronously when requested. +

    +
    +
    + TreeElement Rendered Contents +

    This section describes the markup written out to represent a tree node in the + rendered HTML document. The basic Markup looks like this: +

    +

    [Tree Markup] [Expand/Collapse Icon] [Anchor - [Icon][Label]] [Content] +

    +
      +
    • Tree Markup [ + lineJoin.gif - lineJoin.gif, + lastLineJoin.gif - lastLineJoin.gif, + verticalLine.gif -verticalLine.gif, + spacer.gif] -- + There are four images that represent the "structure" of the tree. These are + used to create the visual hiearchical representation of the tree. +
    • +
    • Expand/Collapse Icon [ + nodeCollapsed.gif - nodeCollapsed.gif, + lastNodeCollapsed.gif - lastNodeCollapsed.gif + rootCollapsed.gif - rootCollapsed.gif, + nodeExpanded.gif - nodeExpanded.gif, + lastNodeExpanded.gif - lastNodeExpanded.gif + rootExpanded.gif - rootExpanded.gif + ] -- There are six images that represent the expand and collapse links on an interior + node. The root images are only available if the root of the tree implements ITreeRootElement. +
    • +
    • Icon [ + folder.gif - folder.gif, + ] -- This Icon and the Label represent the node in the tree. Either act as a selectable + link that will call the selection action. +
    • +
    • Label -- The label is a text item representing the node. This is a + property of the TreeElement. This is a selectable link that will call the selection action.
    • +
    • Content -- This is an optional text item that may appear after the label. + It is not selectable. +
    • +
    +

    The tree supports setting a default location where the images are picked from within a + WebApp. All of the images are found by default in the resources\beehive\version1\images + directory. It is possible to change both the default location for finding the images + in addition to the images themselves by explicitly setting the name of the image on the Tree. +

    +
    +
    + Using a Custom TreeRenderer Implementation +

    + The HTML markup for the tree is handled by the TreeRenderer class. By default, TreeRenderer handles tree rendering + across the web application, unless another rendering class is specified. +

    +

    + You can override the rendering behavior of the default TreeRenderer class with a custom renderer class. A custom TreeRenderer class is + especially useful for precise control of whitespace, line breaks, and image placement in the rendered tree. +

    +

    + To override the default TreeRenderer class: +

    +
      +
    1. extend the TreeRenderer class and override any of the formatting methods + that are appropriate to your purposes
    2. +
    3. configure NetUI to use your extended class to render the tree
    4. +
    +

    + An example custom TreeRenderer class appears below. This class overrides the method + renderConnectionImageSuffix() so that a new line is not added after the + <img> element for the connetcting expand/collapse image and + renderSelectionLinkPrefix() so that no white space indentation is placed + before the anchor used to select a node. Also, the methods renderItemIconPrefix() and renderItemIconSuffix() + are overridden to wrap a <span> around the <img> element for the node icon. A <span> + might be used to incorporate CSS styles or a call to a JavaScript routine. +

    + +package mytree.renderer; + +import org.apache.beehive.netui.tags.rendering.AbstractRenderAppender; +import org.apache.beehive.netui.tags.tree.TreeElement; +import org.apache.beehive.netui.tags.tree.TreeRenderer; + +public class MyTreeRenderer extends TreeRenderer +{ + protected void renderConnectionImageSuffix(AbstractRenderAppender writer, + TreeElement node) + { + } + + protected void renderSelectionLinkPrefix(AbstractRenderAppender writer, + TreeElement node) + { + } + + protected void renderItemIconPrefix(AbstractRenderAppender writer, + TreeElement node) + { + writer.append("<span ID=\"myItemIcon\" style=\"cursor:pointer;\""); + writer.append(" onClick=\"doSomething()\">"); + } + + protected void renderItemIconSuffix(AbstractRenderAppender writer, + TreeElement node) + { + writer.append("</span>"); + } + + // more overridden methods... +} + + +

    + To configure NetUI to use your custom TreeRenderer, edit the <tree-renderer-class> element of the beehive-netui-config.xml file + to refer to your custom class: +

    + <tree-renderer-class>mytree.renderer.MyTreeRenderer</tree-renderer-class> +
    +
    + +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/tags/xhtml.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/tags/xhtml.xml new file mode 100644 index 0000000..6d85de4 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/tags/xhtml.xml @@ -0,0 +1,142 @@ + + + +
    + HTLM and XHTML Support +
    + +
    + Introduction +

    The following topic explains the support for creating valid XHTML and HTML from the NetUI tags. + The NetUI tags currently support three levels of the XHTML and HTML specs, HTML 4.01 Loose + (Transitional DTD), + HTML 4.01 Loose Quirks mode and XHTML 1.0 Transitional. By + default, the tags support HTML 4.01 Loose, Quirks mode. +

    +

    Future versions of NetUI may support HTML 4.01 Strict and XHTML Strict. This is currently not + supported because + there are a number of visual presentation attributes supported by the NetUI HTML tags, which are not + supported by HTML 4.01 Strict DTD (for example <netui:body>'s bgcolor attribute). In order + to support these strict modes, the NetUI tags would need to report runtime errors when the deprecated + attributes are set. +

    +
    +
    + Basic Tag Structure +

    The minimum JSP should be of the following structure:

    +

    Basic JSP

    + +<%@ taglib prefix="netui" uri="http://beehive.apache.org/netui/tags-html-1.0"%> + + + Page Title + + + + + +]]> +

    There are two primary tags that create the valid HTML structure and provide the core services of + the NetUI tag library, <netui:html> and <netui:body>. These two tags are related to each + other. Together they work together to create valid HTML. The page above represents the typical + minimum page. The html tag will output the HTML html element. The <head> + contains a title and the <netui:base> tag which is used to locate resources and links on the page. + The body tag will then output the HTML body element. +

    +
    + Html Tag +

    The <netui:html> JSP tag typically acts as a top level container and in this role is responsible + for rendering the result of many of the core services of the tags. These services + include gathering up JavaScript and runtime errors and then renders them at the end of the page. + For more information on the Html tag see the + ScriptContainers topic. +

    +

    Typically if the html tag rendered this content it would be illegal + because the end tag </body> immediately precedes the </html> end tag and there is + no legal content allowed between these two end tags. In order + to create legal HTML, the <netui:body> tag defers to the Html tag to render content to the + generated page before the body end tag is rendered. If the <netui:body> tag is not present, + then the Html tag will render JavaScript and any runtime errors right before the </html> end + tag. +

    +
    +
    + Body Tag +

    The <netui:body> JSP tag will output the HTML body tag. In addition, it works with the + <netui:html> tag to render the JavaScript and runtime errors before the </body> end + tag. In addition, it will also work with the <netui:scriptBlock> tag to position any + JavaScript that must be positioned either before or after the framework generated JavaScript. + For more information see the ScriptBlock + information in the JavaScript Support topic. +

    +
    +
    + ScriptBlock Tag +

    The primary role of the <netui:scriptBlock> is to render HTML <script> tags and position + JavaScript on the page in relationship to the framework generated JavaScript. + The ScriptBlock requires both the <netui:html> and <netui:body> tag to position the + output. Without these two tags, the JavaScript is written out inline. + For more information see the ScriptBlock + information in the JavaScript Support topic. +

    +
    +
    +
    + Specifying the HTML Format +

    This section describes the methods for setting the default HTML format for a WebApp. Further, the + format can be set on a JSP to override the WebApp default. +

    +
    + Format Identifiers +

    The Html tags currently support three HTML formats. These are identified by the following + indentifier values: +

    +
      +
    • html4-loose -- HTML 4.01 Transitional DTD (loose)
    • +
    • html4-loose-quirks -- HTML 4.01 Transitional DTD, with Quirks mode turned on
    • +
    • xhtml1-transitional -- XHTML 1.0 Transitional
    • +
    +

    The identifier values are used set the HTML format in both the tags and in the configuration + file. +

    +
    +
    + Setting the WebApp Format +

    By default, all WebApps use html4-loose-quirks as the format. In order + to override the default format, you set the WebApp default in the beehive-netui-config.xml. + The default is set by specifying the doctype value inside + of the jsp-tag-config element. + For information on the NetUI Configuration file see the + Reference Documentation: beehive-netui-config.xml File topic. +

    +

    In the following example, the default format for the WebApp is changed to the HTML 4.01 + Transitional DTD. This value is found in the beehive-netui-config.xml file. + The value of the <doctype> element must be one of the values + specified above for the identifiers. +

    + +<jsp-tag-config> + <doctype>html4-loose</doctype> +</jsp-tag-config> + +
    +
    + Setting the Document Format +

    It is possible to override the HTML format on a document by document basis. This is + done by setting the documentType of the <netui:html> tag to one of the + identifiers above. In the example below, the output format for the document will be + XHTML 1.0 Transitional. It will override the default value for the WebApp. +

    + +<%@ page language="java" contentType="text/html;charset=UTF-8"%> +<%@ taglib uri="http://beehive.apache.org/netui/tags-html-1.0" prefix="netui"%> +<netui:html documentType="xhtml1-transitional"> + ... +</netui:html> + +
    +
    + +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/tilesSupport.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/tilesSupport.xml new file mode 100644 index 0000000..81805f7 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/tilesSupport.xml @@ -0,0 +1,123 @@ + + + +
    + Tiles Support +
    + +
    + Introduction +

    + Often, within your web application there are shared components such as a + menu bar, banner or header, footer, and copyright. NetUI provides a couple + of mechanisms to support layout management for assembling presentation pages + from separate components. First, there are the + NetUI Template Tags, a simple templating mechanism, defining a + template page that contains the layout and information you want on each + page within a site or page flow. The other option is to use the + + Tiles framework support built into NetUI. +

    +

    + Support for Tiles is achieved by incorporating the Tiles plugin and providing + Tiles related "annotations" in the NetUI declarative programming model for + the page flow "controller" class. +

    +

    + The following is a brief description of the annotations and the steps + required to use the Tiles support in NetUI. +

    +
    +
    + Declaring Tiles Definitions +

    + First, create your Tiles definitions and the corresponding layout templates. + Place your Tiles definition configuration file(s) in the WEB-INF directory. + A Tiles definition file can also be located in the same directory as the page flow + controller; however, if it is placed locally, you should avoid including it in the + deployed webapp (or, if you are deploying your web project in place, you should + add a Servlet Filter to prevent the file from being externally visible). +

    +

    + The definitions you declared should use webapp-relative paths to the JSP files + that will be the template(s) for the layout, using <tiles:insert> tags from + the tiles tag library, and the common component JSP files such as header, + footer, menu, etc. used by the templates. The example definition below + illustrates the use of a template JSP ("/layout/page.jsp") and common + component files for the header, menu, and footer. The definitions that extend + "defaultLayout" define the actual content that should be inserted as the + content of the "body" component in the page. +

    +

    /WEB-INF/tiles-defs.xml

    + + + + + + + + + + + + + + + + + + + ... + +]]> +

    + To use the definitions in a page flow, add the tilesDefinitionsConfigs + attribute to your + + @Jpf.Controller + + annotation. This attribute takes an array of paths to support the use of multiple + Tiles-definitions files if desired. The following is an example of how the + annotation and attribute would be written for a single configuration file + named "tiles-defs.xml" and located in the WEB-INF directory. +

    +@Jpf.Controller( + tilesDefinitionsConfigs = { "/WEB-INF/tiles-defs.xml" }, + ... +) +
    +
    + Using Tiles Definitions as Forwards in a Page Flow Controller +

    + For any + + @Jpf.Forward + , + + @Jpf.SimpleAction + , or + + @Jpf.ConditionalForward + + annotation you've defined in the actions of your controller, you can define + the Tiles definition for the @Jpf.Forward. Rather than set the + path attribute for a JSP, you set the attribute, tilesDefinition. + This value of the attribute should be the name of a Tiles definition. Using + the definitions defined above, the following is an example of a Forward + annotation with the tilesDefinition. +

    +@Jpf.Action( + forwards = { + @Jpf.Forward( + name = "continue", + tilesDefinition = "flow2") + }) +

    + Review the NetUI samples for a concrete + example of using Tiles support to share a common UI component across page flows. +

    +
    + +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/tutorial.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/tutorial.xml new file mode 100644 index 0000000..dd6f464 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/tutorial.xml @@ -0,0 +1,1435 @@ + + + +
    + Beehive NetUI Tutorial +
    + +
    + Introduction +

    + The NetUI tutorial is provided as a way to become familiar with NetUI's Page Flow controllers and JSP + tags. The tutorial walks through creating, building, and deploying a sample project page flow that + submits data from a browser to the server. +

    +
    + Tutorial Goals +
      +
    • How to create a basic NetUI web application.
    • +
    • + How to perform simple user navigation with the + + @Jpf.SimpleAction + + annotation. +
    • +
    • + How to coordinate user navigation with the + + @Jpf.Forward + + annotation and the + + Forward + + object. +
    • +
    • + How to handle data submission and processing with + databinding and form beans. +
    • +
    • + How to create a user interface with the + NetUI JSP tag library. +
    • +
    • How page flows help to separate data processing and data presentation.
    • +
    • How to make a web application a client of a Java control.
    • +
    • + How to use + declarative validation with data submission. +
    • +
    • + How to collect data from a + nested page flow and 'return' it to the + calling page flow. +
    • +
    • How to make an action available to multiple page flows.
    • +
    +
    +
    +
    + Step 1: Set up a Beehive-enabled Web Application +
    + Set Shell Variables +

    Complete all of the necessary and optional steps in the following topic: Beehive Installation and Setup

    +
    +
    + Create a Beehive-enabled Web Project +

    + In order to follow the steps in this tutorial, it's necessary to create a Beehive-enabled web application. Beehive-enabled web applications + are described here. A skeleton Beehive-enabled web project is provided in the samples/ directory as + netui-blank. This contains a basic Ant build file and an example Page Flow controller. To create the + tutorial's project, we'll copy and then rename the netui-blank project using these steps: +

    +
      +
    1. Create a directory /beehive_projects (on Windows, this would be C:\beehive_projects).
    2. +
    3. Run this Ant target to create a new NetUI project: + ant -f <beehive-root>/beehive-imports.xml new.netui.webapp and provide a fully-qualified web project root directory + named netui-tutorial. Note, <beehive-root> is the directory that contains a + Beehive distribution; a typical value might be /apache/apache-beehive-1.0.
    4. +
    5. Before continuing, confirm that the following directory structure exists:
    6. +
    + + beehive_projects/ + netui-tutorial/ + src/ + Controller.java + web/ + index.jsp + resources/ + WEB-INF/ + build.properties + build.xml + +

    + Note, this directory structure is just an example; you are free to put the netui-tutorial + directory anywhere on disk. In the remainder of this tutorial, the directory beehive_projects/netui-tutorial + will simply be referred to as netui-tutorial. +

    +
    +
    + Configure Build Properties +

    + The build.properties file contains several project-related properties that must + be set in order to build the web application. Specifically, the paths to your Beehive distribution and + to the JSP / Servlet API JARs for your application container must be set. The following steps will set these properties + for the netui-tutorial webapp. +

    +
      +
    1. Open the file netui-tutorial/build.properties in a text editor.
    2. +
    3. Edit the beehive.home property so it points to the top-level directory of your Beehive distribution.
    4. +
    5. Edit the context.path to use the value netui-tutorial.
    6. +
    + + The context.path property determines both (1) the name of the application WAR file and (2) the application URL. +

    + If context.path=netui-tutorial, then the following WAR file will be produced: +

    +     netui-tutorial.war +

    + and the following URL will invoke the web application: +

    +     http://<some server>/netui-tutorial +
    +

    For example, if your Beehive distribution is located in /apache/apache-beehive-1.0, + then your build.properties file would appear as follows.

    + +beehive.home=/apache/apache-beehive-1.0 + +servlet-api.jar=${os.CATALINA_HOME}/common/lib/servlet-api.jar +jsp-api.jar=${os.CATALINA_HOME}/common/lib/jsp-api.jar + +context.path=netui-tutorial + Properties files should use the '/' character to separate drive, directory, and file names. +

    + If you are using an application container other than Tomcat, be sure to set the servlet-api.jar and + jsp-api.jar properties to reference the JAR your server provides which contains the JSP and Servlet + API classes. +

    +
    +
    + Start the Server +

    If you are using Tomcat, enter the following at the command prompt:

    + $CATALINA_HOME/bin/startup.bat +

    If you aren't using Tomcat, start your application container as per its directions.

    +
    +
    + Using URLs in the Examples +

    + In the Beehive tutorials, you will often encounter URLs like http://localhost:8080/netui-tutorial/myFlow/Controller.jpf. + When you see these URLs, they are meant to be accessed via your web browser to demonstrate functionality built in the + tutorial. These URLs are set up to run on Tomcat, so if you are unable to run these URLs, be sure that they are appropriate + for your application server. Specifically, check the port numbers to make sure that your server is running on the + referenced port. +

    +
    +
    +
    + Step 2: Create your First Page Flow Controller +
    + Overview +

    + In this step you will create a controller class and a JSP. These are the basic files in + a Beehive NetUI web application. Each page flow contains one controller class and any + number of pages -- JSPs in this case. A controller class is a Java class that + controls how your web application functions and what it does. The methods and annotations in the + controller class determine how users navigate from page + to page, how user requests are handled, and how the web application accesses back-end + resources. The JSPs determine what a visitor to the web application sees in the browser. +

    +

    + In terms of the Model-View-Controller paradigm for web applications, the Controller.java + file is the Controller (naturally) and the JSPs are the View. The web application's + Model in this tutorial is very simple: it consists of a JavaBean with three fields that represent the + user's name, age and selected sport activity. + +

    +

    + Controller classes contain actions, which are methods or annotations. An action may do + something simple, such as forward a user from one JSP to another; or it may do a complex set of tasks, + such as receive user input from a JSP, interact with back-end resources based on the + user input, and forward the user to a JSP where the results are displayed. + +

    +

    + The controller class in this step contains one action. This simple navigational action forwards users + to the index.jsp page. In the next step, you will create a more complex action. +

    +
    +
    + Create the Page Flow Files +

    + You will create two files in a new page flow: Controller.java and index.jsp. + First, create a directory called myFlow under the src directory. Then add + the following page flow controller class: +

    +

    src/myFlow/Controller.java

    + +package myFlow; + +import org.apache.beehive.netui.pageflow.annotations.Jpf; +import org.apache.beehive.netui.pageflow.PageFlowController; + +@Jpf.Controller( + simpleActions={ + @Jpf.SimpleAction(name="begin", path="index.jsp") + } +) +public class Controller + extends PageFlowController +{ +} +

    Every Page Flow controller class must extend + + PageFlowController + + and be decorated by the annotation + + @Jpf.Controller. + The class you created is the simplest controller possible; it has a single begin action that + forwards to index.jsp. +

    +

    The controller class is activated when a user hits it via the URL:

    + http://localhost:8080/netui-tutorial/myFlow/Controller.jpf +

    The URL above means this: "Run the begin action of the Controller class + in the myFlow directory of the netui-tutorial web application."

    +

    + Now, create a directory called myFlow under the web directory. + Then, create the index.jsp that will be shown when you hit the page flow: +

    +

    web/myFlow/index.jsp

    + +<%@ taglib uri="http://beehive.apache.org/netui/tags-html-1.0" prefix="netui"%> + + + Web Application Page + + + +

    + New Web Application Page +

    +
    +
    +]]> + + + Note, we placed the pages in a parallel web content directory. NetUI assumes that the pages in web/myFlow go with the controller class in src/myFlow. + +
    +
    + Compile and Deploy the Web Application +

    You are now ready to compile the page flow and deploy it to Tomcat.

    +

    The following Ant command assumes that you are in the netui-tutorial/ directory. At the command prompt, enter:

    + +ant clean build war + +

    + This will build the webapp by running the Beehive annotation processors and will produce class files in WEB-INF/classes. + Now, the application is ready to deploy to your server. On Tomcat, copy the WAR file into Tomcat's $CATALINA_HOME/webapps + directory.

    +

    On Windows:

    + +copy netui-tutorial.war %CATALINA_HOME%\webapps /Y + + On Windows, there are file-locking issues that Tomcat versions 5.5.x and above are sensitive to. + In particular, any web application that uses Struts will fail to redeploy if you + copy in a new .war file as described here. The Commons Digester team is adding a workaround for the + issue (see + this bug), but in the meantime, + you can work around it with the antiResourceLocking option in Tomcat. Just add a file + called context.xml in a directory called META-INF inside the + web directory before building (so it will end up as META-INF/context.xml + in your netui-tutorial.war): +
    +
    +     <?xml version="1.0" encoding="UTF-8"?>
    +     <Context antiResourceLocking="true">
    +     </Context> +
    +

    Everywhere else:

    + +cp netui-tutorial.war $CATALINA_HOME/webapps + +

    If you are asked to overwrite the old WAR file, enter 'yes'. Note, when doing redeployment, you may have to wait a few seconds + for Tomcat to redeploy the WAR file. Once deployment or redeployment has completed, the webapp can be accessed through a browser.

    +

    If you are not using Tomcat, follow your server's web application deployment instructions to deploy the webapp.

    +
    +
    + Test the NetUI Web Application +

    Visit the following address:

    +

    http://localhost:8080/netui-tutorial/myFlow/Controller.jpf

    +

    You will be directed to the index.jsp page.

    +
    +
    + +
    + Step 4: Submitting Data +
    + Create a Submission Form +

    + This step illustrates the use of NetUI tags to render an HTML form tag and link it to a Page Flow action. + In a later step, the new action (processData) will be added to the controller class to handle the data submission. +

    +

    Edit the file web/myFlow/page2.jsp so it appears as follows.

    +

    page2.jsp

    + +<%@ page language="java" contentType="text/html;charset=UTF-8"%> +<%@ taglib uri="http://beehive.apache.org/netui/tags-html-1.0" prefix="netui"%> +<netui:html> + <head> + <title>page2.jsp</title> + <netui:base/> + </head> + <netui:body> + <p> + Welcome to page2.jsp! + </p> + <p> + <netui:form action="processData"> + Name: <netui:textBox dataSource="actionForm.name"/> + <br/> + Age: <netui:textBox dataSource="actionForm.age"/> + <br/> + <netui:button type="submit" value="Submit"/> + </netui:form> + </p> + </netui:body> +</netui:html> +

    Save page2.jsp.

    +
    +
    + Create a Server Side Representation of the Submission Form (a.k.a. Create a Form Bean) +

    In this step you will create a Java class that accepts data from the JSP submission form created in the previous task. When the form data is submitted, the Java class will be instantiated, and the form data will be loaded into the JavaBean properties of the new instance.

    +

    In the directory src create a directory named forms.

    +

    In the directory src/forms create a JAVA file named ProfileForm.java.

    +

    + Edit src/forms/ProfileForm.java so it contains getters and setters for + two JavaBean properties (name and age), as follows. +

    + +

    ProfileForm.java

    + +package forms; + +public class ProfileForm + implements java.io.Serializable { + + private int age; + private String name; + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + + public void setAge(int age) { + this.age = age; + } + + public int getAge() { + return this.age; + } +} +

    Save and close ProfileForm.java.

    +
    +
    + Edit the Controller Class to Handle the Submitted Data +

    Now you will add a new action and use your new form bean to handle the data + submitted from the HTML form.

    +

    Open the file src/myFlow/Controller.java +

    +

    Edit Controller.java so it appears as follows. Code to add appears in bold type.

    + +

    Controller.java

    + +package myFlow; + +import org.apache.beehive.netui.pageflow.annotations.Jpf; +import org.apache.beehive.netui.pageflow.PageFlowController; +import org.apache.beehive.netui.pageflow.Forward; +import forms.ProfileForm; + +@Jpf.Controller( + simpleActions={ + @Jpf.SimpleAction(name="begin", path="index.jsp"), + @Jpf.SimpleAction(name="toPage2", path="page2.jsp") + } +) +public class Controller + extends PageFlowController +{ + + @Jpf.Action( + forwards = { + @Jpf.Forward(name="success", path="page2.jsp") + } + ) + public Forward processData(ProfileForm form) { + System.out.println("Name: " + form.getName()); + System.out.println("Age: " + form.getAge()); + + Forward fwd = new Forward("success"); + return fwd; + } +} + +

    Save Controller.java.

    +
    +
    + Recompile and Redeploy the Web Application +

    Compile and (re)deploy the web application using the same steps as described here.

    +
    +
    + Test the NetUI Web Application +

    Visit the following link: +

    +

    http://localhost:8080/netui-tutorial/myFlow/Controller.jpf

    +

    You will be directed to the index.jsp page.

    +

    Click the link.

    +

    You will be directed to page2.jsp.

    +

    Enter values in the Name and Age fields, and click Submit.

    +

    Notice the name and age values you entered are displayed in the Tomcat console.

    +
    +
    +
    + Step 5: Processing and Displaying Data +
    + Create a JSP to Display Submitted Data +

    In this step you will create a new JSP to present the results from processing the data submission.

    +

    In the directory web/myFlow create a file named + displayData.jsp.

    +

    + Edit displayData.jsp so it appears as follows. The "page inputs" that are being + displayed will come from the action in your page flow (next step). +

    + +

    displayData.jsp

    + +<%@ taglib uri="http://beehive.apache.org/netui/tags-html-1.0" prefix="netui"%> + + + displayData.jsp + + + +

    + You submitted the following information: +

    +

    + Name: ${pageInput.name} +
    + Age: ${pageInput.age} +

    +
    +
    +]]> +

    Save and close displayData.jsp.

    +
    +
    + Process the Submitted Data +

    + Edit the processData method in the Controller.java file so it appears as follows. Code to add appears in bold. + Change the value of the path attribute in the Forward annotation to displayData.jsp. + Note that the "action outputs" you are adding here will be read as "page inputs" on the page. +

    + +

    Controller.java

    + + ... + + @Jpf.Action( + forwards = { + @Jpf.Forward(name="success", path="displayData.jsp") + } + ) + public Forward processData(ProfileForm form) { + System.out.println("Name: " + form.getName()); + System.out.println("Age: " + form.getAge()); + + Forward fwd = new Forward("success"); + fwd.addActionOutput("name", form.getName()); + fwd.addActionOutput("age", form.getAge()); + return fwd; + } + + ... + +

    Save Controller.java.

    +
    +
    + Recompile and Redeploy the Web Application +

    Compile and (re)deploy the web application using the same steps as described here.

    +
    +
    + Test the NetUI Web Application +

    Visit the following link: +

    +

    http://localhost:8080/netui-tutorial/myFlow/Controller.jpf

    +

    You will be directed to the index.jsp page.

    +

    Click the link.

    +

    You will be directed to page2.jsp.

    +

    Enter values in the Name and Age fields. Click the Submit button.

    +

    You will be forwarded to the displayData.jsp page. Notice the values you entered are displayed.

    + + In this step, you used "action outputs" and "page inputs" to get data from your page flow controller + to your JSP. You can get more formal about both by declaring expected types and whether the values + are required; to do this, you use annnotations and JSP tags as described + here. + +
    +
    +
    + Step 6: Add a Control +

    In this step you will add a simple 'Hello World' control to your web application.

    +

    You will edit the web application to become a client of the control. The web app will pass the user submitted + name to the control, and the control will return a simple 'Hello World' message back to the web app. + For more details on how this control works see the control tutorial.

    +
    + Create the HelloWorld Control +

    Inside the netui-tutorial/src directory, create a new directory named controls.

    +

    Inside the directory netui-tutorial/src/controls, create a new file named HelloWorldImpl.java

    +

    Edit HelloWorldImpl.java so it appears as follows:

    + package controls; + +import org.apache.beehive.controls.api.bean.ControlImplementation; + +@ControlImplementation(isTransient=true) +public class HelloWorldImpl implements HelloWorld { + + public String hello() { + return "hello!"; + } + + public String helloParam(String name) { + return "Hello, " + name + "!"; + } +} +

    Inside the directory netui-tutorial/src/controls, create a new file named HelloWorld.java

    +

    Edit HelloWorld.java so it appears as follows:

    + package controls; + +import org.apache.beehive.controls.api.bean.ControlInterface; + +@ControlInterface +public interface HelloWorld { + + String hello(); + + String helloParam(String name); +} +
    +
    + Edit the Page Flow Controller +

    Edit the page flow Controller file so it appears as follows. Code to add appears in bold:

    + package myFlow; + +import org.apache.beehive.netui.pageflow.annotations.Jpf; +import org.apache.beehive.netui.pageflow.PageFlowController; +import org.apache.beehive.netui.pageflow.Forward; +import forms.ProfileForm; + +import org.apache.beehive.controls.api.bean.Control; +import controls.HelloWorld; + +@Jpf.Controller( + simpleActions={ + @Jpf.SimpleAction(name="begin", path="index.jsp"), + @Jpf.SimpleAction(name="toPage2", path="page2.jsp") + } +) +public class Controller + extends PageFlowController +{ + @Control + private HelloWorld helloWorld; + + @Jpf.Action( + forwards = { + @Jpf.Forward(name="success", path="displayData.jsp") + } + ) + public Forward processData(ProfileForm form) { + System.out.println("Name: " + form.getName()); + System.out.println("Age: " + form.getAge()); + + Forward fwd = new Forward("success"); + fwd.addActionOutput("name", form.getName()); + fwd.addActionOutput("age", form.getAge()); + fwd.addActionOutput("message", helloWorld.helloParam(form.getName())); + return fwd; + } +} +
    +
    + Add a New pageInput +

    Add new pageinput to displayData.jsp. Code to add appears in bold:

    + <%@ page language="java" contentType="text/html;charset=UTF-8"%> +<%@ taglib uri="http://beehive.apache.org/netui/tags-html-1.0" prefix="netui"%> +<netui:html> + <head> + <title>displayData.jsp</title> + <netui:base/> + </head> + <netui:body> + <p> + You submitted the following information: + </p> + <p> + Name: ${pageInput.name} + <br/> + Age: ${pageInput.age} + <br/> + Message: ${pageInput.message} + </p> + </netui:body> +</netui:html> + +
    +
    + Recompile and Redeploy the Web Application +

    Compile and (re)deploy the web application using the same steps as described here.

    +
    +
    + Test the NetUI Web Application +

    Visit the following link: +

    +

    http://localhost:8080/netui-tutorial/myFlow/Controller.jpf

    +

    You will be directed to the index.jsp page.

    +

    Click the link.

    +

    You will be directed to page2.jsp.

    +

    Enter values in the Name and Age fields. Click the Submit button.

    +

    You will be forwarded to the displayData.jsp page. Notice the values you entered are displayed along with a 'Hello World' message based on the name you submitted.

    +
    +
    +
    + Step 7: Input Validation +
    + Add Declarative Validation to the Form Bean +

    In this step you will use declarative validation to define the set of rules for each + field, to be applied during input validation. You will add a + + ValidatableProperty + + annotation for the name property of the form so that it will (1) be required, and + (2) have a maximum length of 30 characters. The age property + must have a value in the range 1 to 130.

    +

    Open the file src/forms/ProfileForm.java

    +

    + Add validation annotations. Code to add appears in bold (notice the additional import statement and the FormBean annotation). +

    +

    src/forms/ProfileForm.java

    + package forms; + +import org.apache.beehive.netui.pageflow.annotations.Jpf; + +@Jpf.FormBean() +public class ProfileForm + implements java.io.Serializable { + + private int age; + private String name; + + public void setName(String name) { + this.name = name; + } + + @Jpf.ValidatableProperty( + displayName = "Name", + validateRequired = @Jpf.ValidateRequired(), + validateMaxLength = @Jpf.ValidateMaxLength(chars = 30) + ) + public String getName() { + return this.name; + } + + public void setAge(int age) { + this.age = age; + } + + @Jpf.ValidatableProperty( + displayName = "Age", + validateRange = @Jpf.ValidateRange(minInt = 1, maxInt = 130) + ) + public int getAge() { + return this.age; + } +} +

    Save and close ProfileForm.java.

    + + The validation annotations above do not produce localized messages. If you want + your messages to be localizable, you would do two things: (1) add the + + messageBundle + + attribute to the + + @Jpf.FormBean + + annotation on the ProfileForm class, with its + value set to a valid message bundle, and (2) use the + + displayNameKey + + attribute instead of + + displayName + + on your validation annotations. +
    +
    + If you don't want to use the default validation messages provided by NetUI, you can use the + + message + + or + + messageKey + + attributes on any of the validation annotations. +
    + +

    + Next, add a + + validationErrorForward + + to the processData action in src/myFlow/Controller.java. Code to add appears in bold. Don't forget the comma after the forwards={...} element! +

    +

    src/myFlow/Controller.java

    + package myFlow; + +import org.apache.beehive.netui.pageflow.annotations.Jpf; +import org.apache.beehive.netui.pageflow.PageFlowController; +import org.apache.beehive.netui.pageflow.Forward; +import forms.ProfileForm; + +import org.apache.beehive.controls.api.bean.Control; +import controls.HelloWorld; + +@Jpf.Controller( + simpleActions={ + @Jpf.SimpleAction(name="begin", path="index.jsp"), + @Jpf.SimpleAction(name="toPage2", path="page2.jsp") + } +) +public class Controller + extends PageFlowController +{ + @Control + private HelloWorld helloWorld; + + @Jpf.Action( + forwards = { + @Jpf.Forward(name="success", path="displayData.jsp") + }, + validationErrorForward=@Jpf.Forward(name="fail", path="page2.jsp") + ) + public Forward processData(ProfileForm form) { + System.out.println("Name: " + form.getName()); + System.out.println("Age: " + form.getAge()); + + Forward fwd = new Forward("success"); + fwd.addActionOutput("name", form.getName()); + fwd.addActionOutput("age", form.getAge()); + fwd.addActionOutput("message", helloWorld.helloParam(form.getName())); + return fwd; + } +} +

    Save Controller.java.

    +

    + The annotation you just added causes navigation to flow back to page2.jsp if any + validation error occurs in the form bean for action processData. +

    +
    +
    + Modify the JSP to Display Validation Errors +

    Add the <netui:error> tag to display validation error messages on the page.

    +

    Edit the file web/myFlow/page2.jsp so it appears as follows.

    +

    web/myFlow/page2.jsp

    + <%@ page language="java" contentType="text/html;charset=UTF-8"%> +<%@ taglib uri="http://beehive.apache.org/netui/tags-html-1.0" prefix="netui"%> +<netui:html> + <head> + <title>page2.jsp</title> + <netui:base/> + </head> + <netui:body> + <p> + Welcome to page2.jsp! + </p> + <p> + <netui:form action="processData"> + Name: <netui:textBox dataSource="actionForm.name"/> + <netui:error key="name"/> + <br/> + Age: <netui:textBox dataSource="actionForm.age"/> + <netui:error key="age"/> + <br/> + <netui:button type="submit" value="Submit"/> + </netui:form> + </p> + </netui:body> +</netui:html> +

    Save and close page2.jsp.

    +

    + Now, any validation error that happens for the name property will appear next to the + "Name:" input field. Likewise for the age property. +

    +
    +
    + Recompile and Redeploy the Web Application +

    Compile and (re)deploy the web application using the same steps as described here.

    +
    +
    + Test the NetUI Web Application +

    Visit the following link:

    +

    http://localhost:8080/netui-tutorial/myFlow/Controller.jpf

    +

    You will be directed to the index.jsp page.

    +

    Click the link.

    +

    You will be directed to page2.jsp.

    +

    Leave the Name field empty and enter a negative integer value in the Age field. Click the Submit button.

    +

    You will be returned to the page2.jsp page. Notice the error messages for the values you entered.

    +
    +
    +
    + Step 8: Collect Data from a Nested Page Flow +

    + Nested page flows allow you to insert + entire flows in the middle of the current flow. One use for this is to collect data in another + flow, but still come back to the current flow to use the data. +

    + +
    + Update the Form Bean +

    + In this task you will update the Java class that represents the submission form with the + additional data field created in the previous task. When the nested page flow returns, + the new member of the Form Bean class instance can be loaded with the value collected. +

    +

    + Edit src/forms/ProfileForm.java and add the following member variable and methods. +

    +

    ProfileForm.java

    + + ... + + private String sport; + + public void setSport(String sport) { + this.sport = sport; + } + + public String getSport() { + return this.sport; + } + + ... + +

    Save and close ProfileForm.java.

    +
    +
    + To Launch and Return from the Nested Page Flow +

    In this task you will add Action methods: one to handle forwarding to the nested page flow and another to + implement the return Action when the nested page flow completes.

    +

    Open the file src/myFlow/Controller.java

    +

    Edit Controller.java so it appears as follows. Code to add appears + in bold type. Don't forget to add the useFormBean property to the + + @Jpf.Action + + annotation of the processData method. The + ProfileForm is page flow-scoped for this example, using the same Form Bean + instance in multiple Action methods.

    +

    src/myFlow/Controller.java

    + +package myFlow; + +import org.apache.beehive.netui.pageflow.annotations.Jpf; +import org.apache.beehive.netui.pageflow.PageFlowController; +import org.apache.beehive.netui.pageflow.Forward; +import forms.ProfileForm; + +import org.apache.beehive.controls.api.bean.Control; +import controls.HelloWorld; + +@Jpf.Controller( + simpleActions={ + @Jpf.SimpleAction(name="begin", path="index.jsp"), + @Jpf.SimpleAction(name="toPage2", path="page2.jsp") + } +) +public class Controller + extends PageFlowController +{ + + @Control + private HelloWorld helloWorld; + + private ProfileForm profileForm; + + /** + * This action forwards to the nested page flow to collect the sport + * name. Note that it takes a ProfileForm so we can update the form + * with the sport name returned from the nested page flow, but we've + * explicitly turned validation off for this action, since the form + * may be incomplete. + */ + @Jpf.Action( + useFormBean="profileForm", + forwards={ + @Jpf.Forward(name="getSportFlow", path="sports/SportsController.jpf") + }, + doValidation=false + ) + protected Forward getSport(ProfileForm form) { + return new Forward("getSportFlow"); + } + + /** + * This action takes the sport name returned from the nested page flow + * and updates the field in the form and returns to the original page. + */ + @Jpf.Action( + forwards={ + @Jpf.Forward(name="success", navigateTo=Jpf.NavigateTo.currentPage) + } + ) + protected Forward sportSelected(String sport) { + profileForm.setSport(sport); + Forward success = new Forward("success", profileForm); + return success; + } + + @Jpf.Action( + useFormBean="profileForm", + forwards = { + @Jpf.Forward(name="success", path="displayData.jsp") + }, + validationErrorForward = @Jpf.Forward(name="fail", path="page2.jsp") + ) + public Forward processData(ProfileForm form) { + System.out.println("Name: " + form.getName()); + System.out.println("Age: " + form.getAge()); + + Forward fwd = new Forward("success"); + fwd.addActionOutput("name", form.getName()); + fwd.addActionOutput("age", form.getAge()); + fwd.addActionOutput("message", helloWorld.helloParam(form.getName())); + fwd.addActionOutput("sport", form.getSport()); + return fwd; + } +} + +

    Save Controller.java.

    +
    +
    + Create a Nested Page Flow +

    In this task you will create a nested page flow with actions to select and confirm + the data to return to the main ("nesting") page flow. The new nested controller class + contains an inner Form Bean classs for the data collection. It has only a single + field for the user's choice of sport activity. The options to be displayed are + declared as member data of this nested page flow. After the user confirms the + data, the nested page flow returns a String to the main page flow.

    +

    + In the directory src/myFlow create a directory named sports. +

    +

    + In the directory src/myFlow/sports create a Java file named + SportsController.java. +

    +

    Edit src/myFlow/sports/SportsController.java so it appears as follows.

    + +

    SportsController.java

    + +package myFlow.sports; + +import org.apache.beehive.netui.pageflow.annotations.Jpf; +import org.apache.beehive.netui.pageflow.PageFlowController; +import org.apache.beehive.netui.pageflow.Forward; + +@Jpf.Controller( + nested = true, + simpleActions = { + @Jpf.SimpleAction(name="begin", path="index.jsp") + } +) +public class SportsController + extends PageFlowController { + + private String selectedSport; + private String[] sports = {"sailing", "surfing", "diving", "volleyball", "bicycling"}; + + public String[] getSports() { + return sports; + } + + public String getSelectedSport() { + return selectedSport; + } + + @Jpf.Action( + forwards = { + @Jpf.Forward(name="confirm", path="confirm.jsp") + } + ) + public Forward selectSport(SportForm form) { + selectedSport = form.getSport(); + return new Forward("confirm"); + } + + @Jpf.Action( + forwards = { + @Jpf.Forward( + name="success", + returnAction="sportSelected", + outputFormBeanType=String.class) + } + ) + public Forward confirm() { + return new Forward("success", selectedSport); + } + + public static class SportForm + implements java.io.Serializable { + + private String sport; + + public void setSport(String sport) { + this.sport = sport; + } + + public String getSport() { + return this.sport; + } + } +} + +

    Save and close SportsController.java.

    +
    +
    + To Present and Collect Data using a Form +

    This task illustrates the use of custom tags to render a radio button group in an HTML form and + link it to the nested page flow selectSport Action method.

    +

    In the directory web/myFlow create a directory named sports.

    +

    In the directory web/myFlow/sports, create a file named index.jsp.

    +

    Edit index.jsp so it appears as follows.

    +

    index.jsp

    + +<%@ taglib uri="http://beehive.apache.org/netui/tags-html-1.0" prefix="netui"%> + + + Select Sport + + + +

    + Select Sport Activity +

    +

    + + + + + + +
    Sports: + +
    + Submit +
    +

    +
    +
    ]]> + +

    Save index.jsp.

    +
    +
    + Confirm the Selected Data +

    In the directory web/myFlow/sports, create a file named confirm.jsp.

    +

    Edit confirm.jsp so it appears as follows.

    +

    confirm.jsp

    + +<%@ taglib uri="http://beehive.apache.org/netui/tags-html-1.0" prefix="netui"%> + + + Confirm Sport Activity + + + +

    + Confirm Sport Activity +

    +

    + Sport: ${pageFlow.selectedSport} +

    + + + +
    +
    +]]> +

    Save confirm.jsp.

    +
    +
    + Update the JSP to Display Submitted Data +

    In this step you will update the JSP to present the results from processing the data submission.

    +

    In the directory web/myFlow update the file named + displayData.jsp and add code to display the additional data. + The code to add appears in bold type.

    +

    Edit displayData.jsp so it appears as follows.

    + +

    displayData.jsp

    + <%@ page language="java" contentType="text/html;charset=UTF-8"%> +<%@ taglib uri="http://beehive.apache.org/netui/tags-html-1.0" prefix="netui"%> +<netui:html> + <head> + <title>displayData.jsp</title> + <netui:base/> + </head> + <netui:body> + <p> + You submitted the following information: + </p> + <p> + Name: ${pageInput.name} + <br/> + Age: ${pageInput.age} + <br/> + Message: ${pageInput.message} + <br/> + Sport: ${pageInput.sport} + </p> + </netui:body> +</netui:html> +

    Save and close displayData.jsp.

    +
    +
    + Recompile and Redeploy the Web Application +

    Compile and (re)deploy the web application using the same steps as described here.

    +
    +
    + To Test the NetUI Web Application +

    Visit the following link:

    +

    http://localhost:8080/netui-tutorial/myFlow/Controller.jpf

    +

    You will be directed to the index.jsp page.

    +

    Click the link.

    +

    You will be directed to page2.jsp.

    +

    Click the "Select Sport" button.

    +

    You will be directed to sports/index.jsp in the nested page flow.

    +

    Click a radio button and then the Submit button.

    +

    You will be directed to sports/confirm.jsp in the nested page flow.

    +

    Click the Confirm button.

    +

    You will be returned to the page2.jsp page. Notice that the value you selected is + displayed in the Sport field.

    +
    +
    +
    + Step 9: Adding Actions to a Shared Flow +
    + To Create a Common Destination JSP +

    In the directory web, create a file named help.jsp.

    +

    Edit help.jsp so it appears as follows.

    +

    help.jsp

    + +<%@ taglib uri="http://beehive.apache.org/netui/tags-html-1.0" prefix="netui"%> + + + Help Page + + + +

    + Welcome to the Help Page +

    +
    +
    ]]> + +

    Save help.jsp.

    +
    +
    + Make an Action available to multiple Page Flows +

    In this task you will add a Simple Action to the existing Shared Flow. The Action forwards to the + help page created in the previous task and will be available to multiple page flows in the application.

    +

    Open the existing Shared Flow file src/shared/SharedFlow.java

    +

    + Edit the + + @Jpf.Controller + + annotation for the Shared Flow controller class, SharedFlow, in the SharedFlow.java file and add the simpleActions property. Code to add appears in bold. Don't forget the comma after the catches={...} element!

    +

    SharedFlow.java

    + +... + +@Jpf.Controller( + catches={ + @Jpf.Catch(type=PageFlowException.class, method="handlePageFlowException"), + @Jpf.Catch(type=Exception.class, method="handleException") + }, + simpleActions={ + @Jpf.SimpleAction(name="showHelp", path="/help.jsp") + } +) +public class SharedFlow + extends SharedFlowController { + ... +} + +

    Save SharedFlow.java.

    +
    +
    + Reference the Shared Flow from the Page Flow +

    + Declare a shared flow reference in the page flow controller class, using the + + @Jpf.SharedFlowRef + + annotation. The declaration assigns a name to the referenced shared flow. This name can be used throughout the page flow to reference shared actions and state. +

    +

    Open the file src/myFlow/Controller.java.

    +

    Edit Controller.java so it appears as follows. The code to add appears in bold type.

    +

    Controller.java

    + +package myFlow; + +import org.apache.beehive.netui.pageflow.annotations.Jpf; +import org.apache.beehive.netui.pageflow.PageFlowController; +import org.apache.beehive.netui.pageflow.Forward; +import forms.ProfileForm; + +import org.apache.beehive.controls.api.bean.Control; +import controls.HelloWorld; + +@Jpf.Controller( + simpleActions={ + @Jpf.SimpleAction(name="begin", path="index.jsp"), + @Jpf.SimpleAction(name="toPage2", path="page2.jsp") + }, + sharedFlowRefs={ + @Jpf.SharedFlowRef(name="shared", type=shared.SharedFlow.class) + } +) +public class Controller + extends PageFlowController +{ + ... +} + +

    Save Controller.java.

    +
    + +
    + Recompile and Redeploy the Web Application +

    Compile and (re)deploy the web application using the same steps as described here.

    +
    +
    + Test the NetUI Web Application +

    Visit the following link:

    +

    http://localhost:8080/netui-tutorial/myFlow/Controller.jpf

    +

    You will be directed to the index.jsp page.

    +

    Click the help link.

    +

    A popup window with the help.jsp page will be displayed.

    +
    +
    + +
    + Java, J2EE, and JCP are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.
    + © 2005, Apache Software Foundation +
    +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/netui/validation.xml b/docs/forrest/release/src/documentation/content/xdocs/netui/validation.xml new file mode 100644 index 0000000..6b0317d --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/netui/validation.xml @@ -0,0 +1,293 @@ + + + +
    + Data Validation +
    + +
    + Introduction +
    +

    NetUI offers a declarative validation model. This means that validation tasks are + configured using metadata annotations within Page Flow controller classes. + Annotations for common validation tasks are already provided: e.g., + @Jpf.ValidateCreditCard, + @Jpf.ValidateDate, etc.

    + +
    Validation Annotations +

    Validation annotations can appear in three different places:

    +
      +
    • Form Bean Getter Methods
    • +
    • Action Methods
    • +
    • Controller Class
    • +
    + + If you are using Struts 1.1 in your project, then you need to add an additional build step in order for + these annotations to take effect. All generated Validator XML config files must be copied out of + /WEB-INF/classes/_pageflow and into /_pageflow: +
    +
    +     <delete dir="${web.build.dir}/_pageflow"/>
    +     <mkdir dir="${web.build.dir}/_pageflow"/>
    +     <copy todir="${web.build.dir}/_pageflow">
    +         <fileset dir="${web.build.dir}/WEB-INF/classes/_pageflow" includes="*-validation*.xml"/>
    +     </copy>
    +
    +
    + Additionally, it is a good idea to make these files inaccessible from a web browser by adding the following + entries in web.xml: +
    +
    +     <filter>
    +         <filter-name>PageFlowForbiddenFilter</filter-name>
    +         <filter-class>org.apache.beehive.netui.pageflow.PageFlowForbiddenFilter</filter-class>
    +         <init-param>
    +             <param-name>response-code</param-name>
    +             <param-value>404</param-value>
    +         </init-param>
    +     </filter>
    +
    +     ...
    +
    +     <filter-mapping>
    +         <filter-name>PageFlowForbiddenFilter</filter-name>
    +         <url-pattern>/_pageflow/*</url-pattern>
    +         <dispatcher>REQUEST</dispatcher>
    +     </filter-mapping>
    +
    +
    + By default, NetUI projects are configured with Struts 1.2. This workaround is only + necessary when using Struts 1.1. +
    + +
    ...on the Form Bean Getter Methods +

    + Form bean getter methods are the simplest place to put validation annotations: +

    + public static class MyForm implements Serializable + { + private String _date; + + @Jpf.ValidatableProperty( + displayName="This field", + validateRequired=@Jpf.ValidateRequired(), + validateDate=@Jpf.ValidateDate(pattern="M-d-y") + ) + public String getDate() + { + return _date; + } + + public void setDate(String str) + { + _date = str; + } + } +
    +
    ...on the Action Method +

    When the validation annotations are applied to the Action Method, you must + specify the Form Bean field to which validation will apply. (You don't need to + specify the Form Bean class, because it is already specified by the + Bean parameter of the Action Method.)

    +

    @Jpf.ValidatableProperty(propertyName) + specifies the Form Bean field.

    + + @Jpf.Action( + forwards={ + @Jpf.Forward(name="success", path="success.jsp") + }, + validatableProperties={ + @Jpf.ValidatableProperty( + propertyName="date", + displayName="This field", + validateRequired=@Jpf.ValidateRequired(), + validateDate=@Jpf.ValidateDate(pattern="M-d-y") + ) + }, + validationErrorForward=@Jpf.Forward(name="fail", path="input.jsp") + ) + public Forward submitForm(MyForm form) + { + return new Forward("success"); + } +
    +
    ...on the Controller Class +

    The following class-level annotation says that anytime that an instance of + MyForm is submitted, then its date field will be validated + (against the pattern M-d-y).

    +

    When the validation annotations decorate the Controller class, + you must specify the Form Bean class and the Form Bean field to which validation + will apply.

    +

    @Jpf.ValidateableBean(type) specifies the Form Bean class.

    +

    @Jpf.ValidatableProperty(propertyName) specifies the Form Bean field.

    +

    Note that the propertyName must match the setter/getter field name + in the Bean. In the example below, the setter/getter + field name is date (because the setter/getter methods are + setDate(...)/getDate()).

    + @Jpf.Controller( + validatableBeans={ + @Jpf.ValidatableBean( + type=Controller.MyForm.class, + validatableProperties={ + @Jpf.ValidatableProperty( + propertyName="date", + displayName="This field", + validateDate=@Jpf.ValidateDate(pattern="M-d-y") + ) + } + ) + } +) +public class Controller extends PageFlowController +{ + ... + + public static class MyForm implements Serializable + { + private String _date; + + public String getDate() + { + return _date; + } + + public void setDate(String str) + { + _date = str; + } + } +} +
    +
    +
    Handling Validation Errors +
    Default Error Messages +

    If validation fails, then an ActionMessage is written describing the error + under the key propertyNameValue. +

    + @Jpf.ValidatableProperty( + propertyName="propertyNameValue", + ... + ) +

    This error is retreivable + by the <netui:error> tag, using the matching key value.

    + <netui:form action="handleSubmit"> + Enter the date (MM-dd-YYYY): + <netui:textBox dataSource="actionForm.date"/> + <netui:error key="propertyNameValue"/> + <br/><netui:button value="Submit"/> + </netui:form> +

    The propertyName prepends a string to the error message produced.

    + @Jpf.ValidatableProperty( + propertyName="propertyNameValue", + displayName="This field", + ) +

    For example, if validation fails for a date field, the error message produced would + be "This field" + "is not a date."

    +
    +
    Other Message Resources +

    Other message resources can be specified through the + message/messageKey/messageArgs + attributes.

    + @Jpf.ValidatableProperty( + propertyName = "item3", + validateMinLength = + @Jpf.ValidateMinLength( + chars = 6, + message = "{0} {1} for {2} is {3} characters.", + messageArgs = { + @Jpf.MessageArg( + arg = "The minimum", + position = 0 + ), + @Jpf.MessageArg( + arg = "length" + ), + @Jpf.MessageArg( + arg = "this field" + ), + @Jpf.MessageArg( + arg = "six" + ) + } + ) + +

    If the message/messageKey attributes are not present, then the + default message key will be used ("errors.date" for + @Jpf.ValidateRequired, "errors.minLength" for + @Jpf.ValidateMinLength, etc.)

    +

    If the arg0/arg0Key, etc... attributes are present, + it is used as the first argument to the message; otherwise, the + displayName/displayNameKey attribute on the + @Jpf.ValidatableProperty is resolved for the first argument.

    +

    Message resources can be associated with a Form Bean class:

    + @Jpf.FormBean(defaultMessageBundle="myFormBean.errors") +public static class MyFormBean +

    The <netui:error> and <netui:errors> tags will resolve validation messages in the + following order:

    +
      +
    1. The default message bundle associated with the Controller class +@Jpf.Controller( + messageBundles = { + @Jpf.MessageBundle(bundlePath = "validation.messages.messages") + },
    2. +
    3. The message bundle associated with the current Form Bean
    4. +
    5. The fallback message bundle in beehive-netui-pageflow.jar. + This contains values for default validation messages (e.g., "This field + is not a date.")
    6. +
    +
    +
    Internationalization of Validation Rules +

    In some cases the parameters to rules (and even the rules themselves) may change + depending on the locale. Rules internationalization is supported through + the language, country, and variant attributes on + @Jpf.ValidationRules:

    + @Jpf.ValidatableProperty( + localeRules={ + @Jpf.ValidationLocaleRules( + language="fr", + validateDate=@Jpf.ValidateDate(pattern="DD/MM/YYYY") + ), + @Jpf.ValidationLocaleRules( + language="fr", + country="CA", + variant="Quebec", + validateDate=@Jpf.ValidateDate(pattern="MM/DD/YYYY") + ) + }, + validateRequired=@Jpf.ValidateRequired() // this one applies to all locales + ) + public String getDate() + { + ... +
    +
    Required Fields +

    Required fields can be marked using the validateRequired attribute.

    + @Jpf.ValidatableProperty( + propertyName="propertyNameValue", + displayName="This field", + validateRequired=@Jpf.ValidateRequired(), + ... + ) +
    +
    Post-Error Navigation +

    The action method handling the submit, specifies the JSP to go to, if the validation + fails.

    +

    Typically, the user is returned to the same submission page, where the error message + can prompt the user to correct the invalid submission.

    + + @Jpf.Action( + forwards={ + @Jpf.Forward(name="success", path="success.jsp") + }, + validationErrorForward=@Jpf.Forward(name="fail", path="input.jsp") + ) + public Forward handleSubmit(MyForm form) +
    +
    + +
    + Java, J2EE, and JCP are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.
    + © 2004, Apache Software Foundation +
    +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/release-notes.xml b/docs/forrest/release/src/documentation/content/xdocs/release-notes.xml new file mode 100644 index 0000000..f54ccd6 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/release-notes.xml @@ -0,0 +1,111 @@ + + + +
    + Beehive SVN -- Release Notes +
    + +
    + Noteworthy Changes +

    + Changes from the last release that represent a fundamental behavior change or are not backward compatible. +

    +
      +
    • + Some PageFlowController and FlowController methods were changed... + To improve application security, the public version of a few methods in PageFlowController and FlowController have been renamed so they aren't picked up as JavaBean properties from within JSP pages. + See BEEHIVE-1069. +
    • +
    • + Session mutex and the HttpSessionMutexListener... + An optional HttpSessionListener has been implemented to facilitate a design change to the way NetUI does user-wide locking. + It will create a session-wide mutex object that can be used to serialize a change in the session. +
    • +
    • + Plug points for handling AJAX requests (.xhr) for the Tree and DivPanel in NetUI... + The API changes include a new Chain of Responsibility (CoR) / command pattern for servicing AJAX requests. + This is a new command handling infrastructure that can be used to handle requests to render markup or data to a client. + At a high level, this is done by implementing command handler classes that are composed together using + the Chain of Responsibility (CoR) pattern and including the commands in the NetUI configuration. +
    • +
    +
    +
    + Bugs +
      +
    • [BEEHIVE-206] - control property constraint:AnnotationMemberTypes.Date accept one format
    • +
    • [BEEHIVE-919] - controls-spring sample throws exception when refreshing the browser page familyTree.jsp
    • +
    • [BEEHIVE-998] - Compilation error for generated client initializer due to generated eventAdaptor not implementing methods in super intf of EventSet intf
    • +
    • [BEEHIVE-1007] - Propagate exception causes while throwing ServletException
    • +
    • [BEEHIVE-1048] - generateScopeId not rendering required JavaScript in some cases
    • +
    • [BEEHIVE-1059] - ClassCastException when InternalUtils.addActionError() casts ActionMessages for the Global.ERROR_KEY attribute to a sub class, ActionErrors
    • +
    • [BEEHIVE-1060] - Control not being initialized when Inheriting from a parent page flow with a package protected control
    • +
    • [BEEHIVE-1065] - Petstore Sample -- No listener in source, but configured in web.xml
    • +
    • [BEEHIVE-1067] - Invalid value for @ControlReferences annotation causes assertion error in apt
    • +
    • [BEEHIVE-1068] - requests to a JPF in a webapp without a Global.app throws two CNF exceptions
    • +
    • [BEEHIVE-1069] - Exposed Properties on PageFlowController can be set by hidden fields in a form
    • +
    • [BEEHIVE-1070] - bindingUpdateErrors expression="${aValue}" always returns tag error
    • +
    • [BEEHIVE-1075] - NPE in ScopedRequestImpl.registerOuterAttribute() when running without asserts.
    • +
    • [BEEHIVE-1078] - Control interface properties aren't added as properties in the control's BeanInfo
    • +
    • [BEEHIVE-1079] - annotations on event set methods that interact with interceptors can result in compilation errors
    • +
    • [BEEHIVE-1082] - Controls ClientIntializer runtime error
    • +
    • [BEEHIVE-1083] - NetUI leaks PageFlowContext object attached to ThreadLocal
    • +
    • [BEEHIVE-1085] - netui:attribute not overriding disabled property on textArea and textBox
    • +
    • [BEEHIVE-1086] - controls which implement non-control interfaces may cause compilation errors on overridden methods
    • +
    • [BEEHIVE-1087] - Controls with simple name conflicts not resolved correctly
    • +
    • [BEEHIVE-1088] - NetUI page flow compiler's WebappPathType.checkRelativePath() needs to handle path to a JPF that begins with './'
    • +
    • [BEEHIVE-1089] - NetUI page flow compiler's WebappPathType.checkRelativePath() needs to handle paths to JPF that begin with "./"
    • +
    • [BEEHIVE-1090] - NetUI page flow compiler's WebappPathType.checkRelativePath() needs to handle paths to JPF that begin with "./"
    • +
    • [BEEHIVE-1091] - checkBoxGroup, radioButtonGroup, select box don't work in the data grid or repeater
    • +
    • [BEEHIVE-1092] - The ControlBean generated for a control extensions with a base control that defines an event set are not generated correctly
    • +
    • [BEEHIVE-1096] - Inherited NetUI shared flow reference not initialized correctly.
    • +
    • [BEEHIVE-1097] - NetUI FlowController execute() should handle exception from begin/end context on page flow ControlContainerContext
    • +
    • [BEEHIVE-1099] - NetUI DeferredSessionStorageHandler should persist session attributes atomically
    • +
    • [BEEHIVE-1107] - JdbcControl does not handle lower case column names correctly when returning a Map
    • +
    • [BEEHIVE-1108] - the netui:form tag doesn't work when the body is in a <jsp:include>
    • +
    • [BEEHIVE-1109] - legacy javascript routine getNetuiTagName fails in IE6 inside of a table
    • +
    • [BEEHIVE-1111] - A space in the context path causes PageFlowUtils.getActionURI() to throw a URISyntaxException
    • +
    • [BEEHIVE-1112] - Make NameSevice implement Serializable
    • +
    • [BEEHIVE-1113] - Control compilation fails for eventset with no methods
    • +
    • [BEEHIVE-1114] - Modify PageFlowUtils.strutsLookup() method to work in a lazy servlet reinitialization
    • +
    • [BEEHIVE-1115] - problem with Jpf.NavigateTo.currentPage
    • +
    • [BEEHIVE-1116] - CLONE -the netui:form tag doesn't work when the body is in a <jsp:include>
    • +
    • [BEEHIVE-1117] - JDBC System control not parsing 'sql:' substitutions correctly when they contain unexpected whitespace
    • +
    • [BEEHIVE-1118] - form bean validations are not following the order
    • +
    • [BEEHIVE-1119] - Message Bundles in the Base class are not inherited to the derived class
    • +
    • [BEEHIVE-1120] - Data Grid loosing sort state when we click any application URL's on the page
    • +
    • [BEEHIVE-1125] - behavior of derived actions
    • +
    • [BEEHIVE-1126] - value of 0 not allowed for arrayMaxLength on JDBCControl statement
    • +
    • [BEEHIVE-1127] - No check() phase during the Controller annotation processing for an external form bean class and ValidatableProperty
    • +
    • [BEEHIVE-1132] - tag docs for anchor and anchorCell tags should be more specific about href URL and use of parameter tag
    • +
    • [BEEHIVE-1133] - Event handlers marked as private are not flagged as errors during annotation processing
    • +
    • [BEEHIVE-1135] - NetUI deadlock condition for concurrent requests to an action and a JSP with a JSP include
    • +
    • [BEEHIVE-1138] - fix problems in step 8 and 9 of NetUI tutorial
    • +
    • [BEEHIVE-1140] - EJBJarDescriptorHandler does modify the deployment descriptor for EJBControls pointing to Entity beans
    • +
    • [BEEHIVE-1141] - Form bean implementing Serializable can not populate its property attributes from HTTP GET request parameters
    • +
    • [BEEHIVE-1142] - PageFlowViewHandler.renderView() needs to check request type before casting to HttpServletRequest
    • +
    • [BEEHIVE-1143] - Control APT compilation errors when using the Eclipse IDE
    • +
    • [BEEHIVE-1144] - No validation of form beans in an action with the useFormBean attribute
    • +
    • [BEEHIVE-1145] - Doc issue: Controls Overview says PropertySet.externalConfig controls ControlBean setters instead of PropertySet.hasSetters
    • +
    • [BEEHIVE-1148] - PageFlowActionListener needs to check request type before casting to ServletRequest
    • +
    • [BEEHIVE-1149] - NetUI deadlock with NameService
    • +
    • [BEEHIVE-1150] - Compiler warning that Jpf.ValidatorVersion is deprecated though the enum has not been deprecated
    • +
    +
    +
    + Improvements +
      +
    • [BEEHIVE-790] - Add commons logging to ejb control
    • +
    • [BEEHIVE-892] - AnnotationMemberTypes.Decimal.places() should have new default value
    • +
    • [BEEHIVE-1073] - Modify the popup window ActionForward handling to forward to a framework JSP (or Servlet) instead of writing directly to the response in the DefaultActionForwardHandler
    • +
    • [BEEHIVE-1074] - Include generated src in the src dist - like for the system controls
    • +
    • [BEEHIVE-1080] - Enforce correct attribute validation on the NetUI form's method attribute in HTML
    • +
    • [BEEHIVE-1093] - Add URLTemplateFactory and TemplatedURLFormatter to the request to reduce synchronized bottleneck in ServletContext.
    • +
    • [BEEHIVE-1105] - Perf bottleneck with the number of calls from PageFlowPageFilter to get ActionServlet from ServletContext
    • +
    • [BEEHIVE-1128] - Update to Apache Struts version 1.2.9 in NetUI
    • +
    • [BEEHIVE-1136] - Using stax-api from woodstox, missing dependencies in pom.xml
    • +
    • [BEEHIVE-1146] - Provide annotation processor warning for conditional forwards with duplicate expressions
    • +
    +
    + +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/samples/index.xml b/docs/forrest/release/src/documentation/content/xdocs/samples/index.xml new file mode 100644 index 0000000..8587757 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/samples/index.xml @@ -0,0 +1,38 @@ + + + +
    + Beehive Samples Overview +
    + +

    Beehive ships with various samples and project templates. Follow the links + for instructions on using the samples and templates.

    +

    + Samples +

    + +

    + Project Templates +

    + + +
    + Java, J2EE, and JCP are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.
    + © 2004, Apache Software Foundation +
    +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/samples/petstore.xml b/docs/forrest/release/src/documentation/content/xdocs/samples/petstore.xml new file mode 100644 index 0000000..44469d8 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/samples/petstore.xml @@ -0,0 +1,318 @@ + + + +
    + Beehive Sample: Petstore +
    + +
    + Introduction +

    The Petstore sample demonstrates how to integrate all three + Beehive technologies (NetUI, Controls and Web Services) in + one application.

    +

    NetUI provides customers with web access to the + Petstore. There are separate page flows for different customer + activities: the 'shop' page flow (located at: + petstoreWeb/web/shop/) lets users browse the catalog + of pets, the 'checkout' page flow (petstoreWeb/web/checkout) lets + users purchase selected items from a shopping cart, etc.

    +

    A web service (located at petstoreWeb/ws/PestoreInventoryManager.java) + provides store managers access to the inventory.

    +

    Most of the page flows have associated Control files (located + at: + petstoreWeb/src/org/apache/beehive/samples/petstore/controls/). + The Controls handle the backend data traffic and encapsulate + the operations of the web application, such as retrieving data + from a database and handling user orders.

    +

    Petstore runs against a Derby database implementation. See the instructions below + for downloading Derby.

    +
    + Petstore Directory Structure +

    The table below describes the functions of the most important + files in the Petstore web application.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    DirectoryDescription
    petstoreWeb +
    +     srcThis directory contains the back-end data and controls used by the web app. +
    +         org +
    +             .../controller/AccountController.javaClass controls some of the internationalization settings for the site.
    +             .../controlsBeehive Controls encapsulating different + functionalities, including handling user account data, + catalogue data, and order processing.
    +             .../formsForm Beans: each form bean is a server-side + representation of an HTML form appearing in the user + interface.
    +             .../modelJava object classes (java beans) used to represent the basic + types in the app: + addresses, orders, products, etc.
    +             .../resourcesVarious .properties files
    +         sqlA SQL file to initialize the database.
        test-srcJava types used by the application's internal tests.
        webContains the NetUI web application modules.
            accountNetUI user interface for managing user accounts
            authNetUI user interface for managing login
            checkoutNetUI user interface for managing the shopping + cart
            searchNetUI user interface for searching the + Petstore
            shopNetUI user interface for browsing the catalogue of + pets
            siteContains the Petstore "skin", including the CSS file, + HTML frameset, and template file
            webappRoot + +
            WEB-INFContains configuration files for deployment, + validation, security (web.xml), and generated Struts config files.
                tagsContains .tag files.
                libJAR resources -- this directory is created and populated when you call the ant target deploy-beehive.
            wsContains the web service interface for the web app.
    +
    +
    Build Targets +

    The build file (located at petstoreWeb/build.xml) contains the following + build targets.

    + + + + + + + +
    TargetDescription
    deploy-beehiveCopies the Beehive runtime JARs into the webapp's + WEB-INF/lib directory.
    buildCompiles the webapp components: + XMLBean schemas, controls, page flows, and web services.
    scrubDeletes the build directories and the test-related + directories.
    cleanDeletes the build directories from the web app.
    warBuilds a WAR file from the web app files.
    +
    +
    +
    + Running the PetStore Sample on Tomcat 5 +

    The following explains how to run the Petstore sample on Tomcat 5. The Petstore sample + will run on other web containers, but we have chosen Tomcat 5 for convenience.

    +
    + To Set up the Environment +

    Before proceeding, complete all of the necessary and optional steps in the + following topic: + Beehive Installation and Setup

    +

    Open a command shell and confirm that you have set following variables:

    +
      +
    • ANT_HOME
    • +
    • JAVA_HOME
    • +
    • CATALINA_HOME
    • +
    +

    Also ensure that the following elements are on your PATH:

    +
      +
    • ANT_HOME/bin
    • +
    • JAVA_HOME/bin
    • +
    +
    +
    + Download Derby Implementation +

    The Petstore app runs against an imbedded Derby database. You must + download a Derby implementation before building and running the Petstore.

    +

    Download a Derby distribution at: http://db.apache.org/derby/derby_downloads.html

    + +
    +
    (Optional) Dowload HTTPUnit Implementation +

    If you want to run the HTTPUnit tests associated with Petstore, + you must download a HTTPUnit implementation from: + http://httpunit.sourceforge.net/

    +
    + To Copy the Petstore Application to a Project + Folder (Optional Step) +

    To keep your Beehive distribution directory + pristine, you should copy the folder + <BeehiveRoot>/samples/petstoreWeb to another location before + proceeding.

    + + <BeehiveRoot> refers to the top-level directory of your Beehive installation. + A typical value for <BeehiveRoot> would be /apache/apache-beehive-1.0. +

    The following instructions assume that you have + copied the folder petstoreWeb into the + directory /beehive_projects, + resulting in the following directory structure.

    + / + beehive_projects + petstoreWeb + Strictly speaking, you do not need to copy the petstoreWeb + directory to another location. If you wish to leave the petstoreWeb directory + in place, in the instructions below you must + replace occurrences of the path element /beehive_projects + with this path element: <BeehiveRoot>/samples. +

    + For example, to build the sample, run the following Ant command: +

    +    ant -f <BeehiveRoot>/samples/petstoreWeb/build.xml clean build war +

    + To delete the sample's build directory, run the clean target: +

    +    ant -f <BeehiveRoot>/samples/petstoreWeb/build.xml clean
    +
    +
    Edit the <code>build.properties</code> File +

    Edit the build.properties file--the file + that sets the build-related properties for your web application.

    +

    Open the file /beehive_projects/petstoreWeb/build.properties + in a text editor.

    +

    At a minimum, you will need to edit the following two properties:

    +
    • beehive.home
    • derby.jar
    +

    If you want to run the httpunit tests, you must set the following additional + property

    +
    • httpunit.dir
    +

    The following example shows typical values for these three properties. + Note that the property derby.jar points to a JAR file, not + to a directory.

    +beehive.home=/apache/apache-beehive-1.0 + +context.path=petstoreWeb + +servlet-api.jar=${os.CATALINA_HOME}/common/lib/servlet-api.jar +jsp-api.jar=${os.CATALINA_HOME}/common/lib/jsp-api.jar + +derby.jar=/apache/derby/derby.jar + +# Set this path in order to run HTTPUnit tests against the webapp +httpunit.dir=/httpunit-1.6 +Windows users must use forwardslashes (/) not backslashes (\) in the + build.properties file. + +
    +
    + To Compile the Petstore Application +

    To compile the Petstore app, enter the following Ant command:

    +ant -f /beehive_projects/petstoreWeb/build.xml clean build war + +

    A WAR file named petstoreWeb.war will be created at /beehive_projects/petstoreWeb/petstoreWeb.war.

    +
    +
    + To Start Tomcat +

    To start Tomcat, run the following command:

    + %CATALINA_HOME%\bin\startup.bat +

    On non-Windows systems:

    + $CATALINA_HOME/bin/startup.sh +
    +
    + To Deploy to Tomcat +

    To deploy the web application, copy the WAR file to Tomcat's webapps directory.

    +

    On Windows:

    + copy C:\beehive_projects\petstoreWeb\petstoreWeb.war %CATALINA_HOME%\webapps /Y + + On Windows, there are file-locking issues that Tomcat versions 5.5.x and above are sensitive to. + In particular, any web application that uses Struts will fail to redeploy if you + copy in a new .war file as described here. The Commons Digester team is adding a workaround for the + issue (see + this bug), but in the meantime, + you can work around it with the antiResourceLocking option in Tomcat. Just add a file + called context.xml in a directory called META-INF inside the + web directory before building (so it will end up as META-INF/context.xml + in your controls_tutorial.war): +
    +
    +     <?xml version="1.0" encoding="UTF-8"?>
    +     <Context antiResourceLocking="true">
    +     </Context> +
    +

    Everywhere else:

    + cp /beehive_projects/petstoreWeb/petstoreWeb.war $CATALINA_HOME/webapps + +
    +
    + Running Petstore +

    Visit the following URL:

    +

    http://localhost:8080/petstoreWeb

    +
    +
    +
    + Running the Petstore Tests +

    The Petstore app ships with associated junit tests. + Before running the tests, ensure that the web app is up and running, i.e, + accessible at http://localhost:8080/petstoreWeb.

    +

    To run the tests, enter the following Ant command:

    + ant -f /beehive_projects/petstoreWeb/build.xml test.run +
    + +
    + Java, J2EE, and JCP are trademarks or registered trademarks of + Sun Microsystems, Inc. in the United States and other + countries.
    © 2004, Apache Software Foundation
    +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/site.xml b/docs/forrest/release/src/documentation/content/xdocs/site.xml new file mode 100644 index 0000000..61e2064 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/site.xml @@ -0,0 +1,205 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/forrest/release/src/documentation/content/xdocs/system-controls/ejb/annotations.xml b/docs/forrest/release/src/documentation/content/xdocs/system-controls/ejb/annotations.xml new file mode 100644 index 0000000..25d8339 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/system-controls/ejb/annotations.xml @@ -0,0 +1,16 @@ + + + +
    + Ejb Control Annotations +
    + +

    @EJBControl.EJBHome

    +

    @EJBControl.JNDIContextEnv

    + +
    + Java, J2EE, and JCP are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.
    + © 2005, Apache Software Foundation +
    +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/system-controls/ejb/guide.xml b/docs/forrest/release/src/documentation/content/xdocs/system-controls/ejb/guide.xml new file mode 100644 index 0000000..9878164 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/system-controls/ejb/guide.xml @@ -0,0 +1,516 @@ + + + +
    + EJB Control Developer's Guide +
    + +
    + Overview + +

    To access the capabilities of an Enterprise JavaBean (EJB) without an EJB control, several preparatory + operations must be performed. You must look up the EJB in the JNDI registry, obtain the EJB's home + interface, obtain an EJB instance, and then finally invoke methods on the EJB's remote interface to + perform tasks.

    + +

    The EJB control eliminates all of this preparatory work. Once you have created the EJB control, + a web service or page flow can use the control to access the EJB's business methods directly. The EJB + control manages communication with the EJB, including all JNDI lookup, interface discovery and + EJB instance creation and management.

    + +

    In short, EJB controls provide an alternative approach that makes it easy to use an existing, + deployed EJB from within an application. EJB controls supports interaction with two of the three types + of EJBs, that is, session beans and entity beans. The EJB control does not support direct communication + with message-driven EJBs.

    + +

    Note: Requests for messages can be sent indirectly to message-driven EJBs using the + JMS control instead. However, unlike the EJB control, the JMS control is not used to locate and + reference an existing message-driven EJB. For more information, see JMS Control.

    + + +

    To create an EJB control to represent an EJB, you must know the names of the home and business + interfaces. The name for the home interface is typically of the form com.mycompany.MyBeanNameHome + or com.mycompany.MyBeanNameLocalHome, and the business interface is typically of the form + com.mycompany.MyBeanName or com.mycompany.MyBeanNameLocal. The EJB control uses either + the EJB's local interfaces or the remote interfaces.

    + + + + +
    +
    + EJB Control Annotations +
    + The EJBHome Annotation +

    EJBHome is a required class-level annotation used to specify the target EJB's home + interface for the EJB control. Either the jndiName or ejbLink attribute + must be specified. +

    + + + + + + + + + + + + + + +
    Member NameValue TypeValue RequiredDescription
    jndiNameStringNoSpecifies the JNDI name of the target EJB's home interface + (e.g. EJBNameHome). This value may also be an URL using the "JNDI:" + protocol (e.g. jndi://username:password@host:port/EJBNameHome). +
    ejbLinkStringNo + Specifies the name of the target EJB using the application relative path to the EJB JAR. + This syntax causes the runtime to use an application scoped name when locating the + referenced EJB. The naming syntax is BeanName#EJBJAR (e.g. CreditCard#CustomerData.jar). +
    +
    +
    + The JNDIContextEnv Annotation +

    JNDIContextEnv specifies the environment properties for the JNDI context that will + be used to lookup the target EJB. It is an optional class-level annotation for the EJB + Control.

    +

    If using a URL with the "JNDI:" protocol or to use a JNDI context with the + default envirnoment properties, this annotation is not necessary.

    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Member NameValue TypeValue RequiredDescription
    contextFactoryStringNoThe fully qualified class name of a JNDI context factory. If not set the default + InitialContext will be used and none of the other attribute values of this annotation + will be used. +
    providerURLStringNoThe provider URL. Used only if contextFactory attribute has been set.
    principalStringNoSpecifies the identity of the principal for authenticating the caller to the service. + Used only if the contextFactory attribute has been set. +
    credentialsStringNoSpecifies the credentials of the principal for authenticating the caller to the service. + Used only if the contextFactory attribute has been set. +
    +
    +
    + +
    + EJB Control Methods +

    The following methods are supported by the EJB Control:

    + + + + + + + + + + + + + + + + + + +
    MethodDescription
    getEJBHomeInstance() + Returns an instance of the home interface associated with the target bean component. +
    hasEJBHomeInstance() + Returns true if the EJB control currently has a target bean instance upon which bean + business interface methods may be invoked. This will be true after a successful + create() or single select finder method execution, or in cases where + implicit creation or find has occurred by the control on the control users behalf. + This provides a simple way to procedurally check the status of explicit or implicit + bean instance creation or find operations. +
    getEJBBeanInstance() + Returns the current target instance of the bean business interface used for business + interface method invocations. This API is provided for advanced use cases were + direct access to the local/remote interfaces outside of the control is required. It will + return null if no target instance is currently selected. +
    getEJBException() + Returns the last EJB exception serviced by the EJB control on the developers behalf. This can + be used to discover or log additional information, for example when a create or find method + is unable to locate a target bean instance. +
    +
    + +
    + Accessing EJBs on a Different Server +

    You can access EJBs on a different server with an EJB control, provided the server hosting the EJB + control and the server to which the target EJB is deployed are in the same domain. You access EJBs + on a different server by using special JNDI syntax in the EJBHome annotation's jndiName + attribute.

    + +

    For example:

    + + @EJBHome(jndiName="jndi://username:password@host:7001/my.resource.jndi.object") + + +

    You can also use environment properties to specify configuration information, such as:

    + + + @EJBHome(jndiName="jndi://host:7001/MyEJBHome?SECURITY_PRINCIPAL=me&SECURITY_CREDENTIALS=passwd") + +
    + +
    + Creating an EJB Control +

    The EJB Control is an extensible control, and you do not use it directly. + To create an EJB control for an EJB, you would create a control extending the EJB Control. + An extended EJB control can only represent one EJB, so you must create one for each EJB.

    + +

    The following steps should be observed:

    +
      +
    1. Create a Java interface extending the appropriate EJB Control interface. If the EJB is a + session bean, extend org.apache.beehive.controls.system.ejb.SessionEJBControl, + if it is an entity bean, extend org.apache.beehive.controls.system.ejb.EntityEJBControl. +
    2. +
    3. Annotate the Java interface with @ControlExtension (org.apache.beehive.controls.api.bean.ControlExtension), + so the Control Annotation Processor will know that the Java interface is a control extension. +
    4. +
    5. Have the Java interface also extend the EJB's home and business interfaces. The business interface + may either by the EJB's local interface or the remote interface. +
    6. +
    7. Specifiy how the EJB control should lookup the EJB. To lookup the EJB by its JNDI name, set the + EJB control's @EJBHome.jndiName annotation to the EJB's JNDI name. To lookup the EJB using an EJB + link, set the EJB control's @EJBHome.ejbLink annotation to the name of the EJB link. +
    8. +
    9. If the EJB control uses JNDI to look up an EJB, optionally specify the JNDI context + environment properties using the @JNDIContextEnv annotation. +
    10. +
    +
    +
    + Using an EJB Control +

    After you have created an EJB Control, you can invoke an target EJB method via the EJB control. + Specifically, the EJB control exposes all and only the EJB methods defined in the EJB interfaces + that the control extends. You can invoke these methods simply by invoking the method with the + same signature on your EJB control.

    + +

    The EJB control automatically manages locating and referencing the EJB instance, and directs + method invocations to the correct instance of the target EJB. Whether or not you must first + create an instance of the target EJB using the EJB's create method depends on whether the EJB + control references a session or an entity bean.

    + +

    Here is an example of the code required to invoke a single method on an exposed EJB using standard J2EE APIs:

    + +Trader trader = null; +try { + InitialContext ic = new InitialContext(); + TraderHome home = (TraderHome)ic.lookup("MyTraderBean"); + trader = home.create(); + TradeResult tradeResult = trader.buy(stock, shares); + return tradeResult; +} +catch (NamingException e) { + ... +} +catch (CreateException e) { + ... +} +catch (RemoteException e) { + ... +} +finally { + if (trader != null) + trader.remove(); +} + +

    The code can be reduced to the following using the EJB Control:

    + +@Control +TraderControlBean traderControl; + +try { + TradeResult tradeResult = traderControl.buy(stock, shares); + return tradeResult; +} +catch (RemoteException re) { + ... +} +finally { + if (traderControl != null) + traderControl.remove(); +} + +
    +
    + Selecting Instances for Session EJBs + +

    A session EJB is used to execute business tasks for a client on the application server. The + session EJB might execute only a single method for a client, in the case of stateless session + beans, or it might execute several methods for that same client, in the case of stateful session + beans. A session bean never serves multiple clients at the same time. The lifetime of a stateful + session bean is tied to the duration of the conversation with the client. In contrast, a small + number of pooled stateless session bean instances is used to serve large number of client requests.

    + +
    + Creating a Session EJB +

    If the target EJB is a stateless session bean, you do not need to invoke the create method of + the EJB via the EJB control. Instead, the EJB control automatically creates a reference to + an appropriate instance of the EJB whenever one of the EJB's business methods is invoked, as + is shown in this code fragment:

    + +@Control() +private EJBControls.MusicBeanControl library; +... +// create method is not invoked first +allBands = library.getBands(); + +

    If the target EJB is a stateful session bean you must first invoke (one of) its create method(s) + to obtain a reference.

    +
    +
    + Caching a Session EJB Reference +

    After a reference is obtained, it is cached in the EJB control and is used for any + subsequent calls to the EJB within the method invocation in which the initial call was made. + If for a stateless session bean you explicitly call the create method, or if for a stateful session + bean you again call a create method, the EJB control replaces a previously cached reference with the + newly created reference.

    + +

    The lifetime of the cached EJB reference within the EJB control depends on the invoking application + and the type of session bean. If a stateful session EJB is invoked by a conversational web service + (that is, a web service method that takes part in a conversation), the EJB reference's lifetime is the + lifetime of the conversation. If a stateful or stateless session EJB is invoked by a non-conversational + web service, the lifetime of the EJB reference in the EJB control is the lifetime of the web service + method invocation. For page flows and both stateful and stateless session EJBs, if the session EJB is + defined in the controller class, the lifetime of the reference is the lifetime of the page flow.

    +
    +
    + Removing a Session EJB +

    When you call the remove method on an EJB control that represents a session EJB, the currently + cached instance of the bean is released. The server might destroy the bean at that time, but the + actual behavior is up to the server. Either way, the bean no longer communicates with the EJB control.

    +
    +
    +
    + Selecting Instances for Entity Beans + +

    Instances of entity EJBs are associated with a particular collection of data. Typically this + collection of data is a row in a database table.

    + +
    + Creating an Entity EJB + +

    When you invoke the EJB's create method through the EJB control, you create a new persistent + entity, that is, a new record in the underlying database table. In other words, creating a + new entity bean with the create method amounts to inserting a new record in a table.

    +
    +
    + Referencing an Entity EJB +

    You can reference an entity EJB instance by calling the findByPrimaryKey method, or another + findXxx method provided by the EJB's designer that returns a reference to one entity bean. + In other words, the entity bean instance represents an existing record in a database table.

    +
    +
    + Caching an Entity EJB Reference +

    The EJB control caches a reference to the EJB instance being used, that is, the instance + returned by the most recent call to the create, findByPrimaryKey or findXxx method, which + returns one data record. When you invoke subsequent methods on the EJB control, it invokes + that method on the EJB instance to which the cached reference refers. If there is no EJB + reference currently cached, the EJB control attempts to invoke the findByPrimaryKey method + with the last successful key used in a create or findByPrimaryKey call. If there is no + previous key, the EJB control throws an exception.

    + +

    The lifetime of the cached entity EJB reference within the EJB control depends on the invoking + application. If the entity EJB is invoked by a conversational web service (that is, a web + service method that takes part in a conversation), the EJB reference's lifetime is the lifetime + of the conversation. For non-conversational web services, the lifetime of the EJB reference in + the EJB control is the lifetime of the web service method invocation. For page flows, if the + entity EJB is defined in the controller class, the lifetime of the reference is the lifetime + of the page flow.

    +
    +
    + Removing an Entity EJB +

    When you call the remove method on an EJB control that represents an entity EJB, the record + represented by the cached EJB reference is removed from the underlying persistent storage. That is, + the row is deleted from the database table.

    +
    +
    + Returning Multiple Records +

    A findXxx method may return a Collection object, holding a set of references to entity beans. The + EJB control does not cache this object. If you wish to cache the return value of a findXxx method, + you should store the object in a member variable of the application invoking the EJB control.

    +
    +
    +
    + Handling EJB Exceptions + +

    The EJB control makes it easy to use an existing, deployed EJB from within an application. This + topic describes how to handle exceptions that might be thrown by the target EJB or the EJB control + itself.

    +
    + Checked Exceptions +

    If the target EJB method invoked via an EJB control throws a checked exception (that is, an + exception that does not extend a RuntimeException), a try-catch block must catch the exception. + It is generally considered a best practice to catch exceptions that occur within the EJB method + (thrown by other methods the EJB method uses), and either overcome the exception or, when this + is impossible, rethrow these exceptions either as an application exception or an EJBException, + depending on whether the failure is due to a system-level or business logic error, and whether + the transaction should be automatically rolled back.

    + +

    An application exception is a checked exception that is either defined by the bean developer + and does not extend a RemoteException, or is predefined in the javax.ejb package (that is, + CreateException, DuplicateKeyException, FinderException, ObjectNotFoundException, or RemoveException). + The EJB's method explicitly defines any application exception in the throws statement, and a + try-catch block must catch the exception.

    + +

    If the EJB control uses the EJB control's remote interfaces, a RunTimeException or an + EJBException thrown by the EJB method is nested by the EJB container inside a RemoteException, + and the RemoteException is propagated to the client. Because a RemoteException is a checked + exception, the client must catch the exception. For more information on RemoteException, see + your favorite J2EE reference documentation or the J2SE API documentation at http://java.sun.com. + An example of catching a RemoteException is given below.

    +
    +
    + Runtime Exceptions + +

    A java.lang.RuntimeException and its subtypes, including EJBException, can be thrown by an EJB + method via its corresponding EJB control. Although these exceptions do not have to be explicitly + caught in your code, it is generally a good idea to catch these exceptions in the client + application invoking an EJB control, which uses the EJB's local interfaces. (Remember that for + remote interfaces, the EJBException is rethrown by the EJB container as a RemoteException.)

    + +

    As mentioned above, a checked exceptions caught in a bean method is often rethrown as an + EJBException. You can checked for such a nested exception by invoking the getCause() or + getCausedByException() methods on the caught EJBException. + An example of nesting and catching an exception through EJBException is given below.

    + +

    The EJB control will throw a org.apache.beehive.controls.api.ControlException when it has + a problem locating/referencing the EJB. Although this is a subtype of RuntimeException and therefore + does not have to be caught explicitly, it again might be a good idea to catch it in the client + application.

    +
    + +
    + A Nested Exception Example + +

    The following example demonstrates the rethrowing of a checked exception inside an EJBException + by an EJB method, and the catching of this exception on the client side. Rethrowing the exception + inside an EJBException in the example is done solely to illustrate the mechanics of exception + handling, and should not be considered recommended design. As mentioned above, checked exceptions + should be rethrown either as an application exception or an EJBException, depending on whether the + failure is due to a system-level or business logic error, and whether the transaction should + be automatically rolled back.

    + +

    The first code snippet shows the definition of the MusicBean method addRecording. Notice that + FinderException, which can be thrown by findByPrimaryKey, is rethrown inside an EJBException, + and that CreateException, which can be thrown by the BandBean's business method addThisRecording, + is rethown inside an EJBException:

    + + public void addRecording(String band, String recording) + { + + try { + Band bandBean = bandHome.findByPrimaryKey(new BandPK(band)); + if(bandBean != null) { + bandBean.addThisRecording(recording); + } + } + catch(CreateException ce) { + throw (EJBException) new EJBException(ce).initCause(ce); + } + catch(FinderException fe) { + throw (EJBException) new EJBException(fe).initCause(fe); + } + } + + +

    On the client side, the MusicBean's method is invoked via an EJB control, and an EJBException + is caught and checked. If the client uses an EJB control that locates the EJB via its local + interfaces, you can catch the EJBException directly and retrieve the nested exception. The + following code snippet shows how this is done in a page flow's action method, using an EJB + control that locates the EJB via its local interfaces:

    + + @Control() + private EJBControls.MusicBeanControl library; + + ... + + @Jpf.Action( + forwards = { + @Jpf.Forward(name="success", path="addRecording.jsp") + } + } + protected Forward addARecording(AddARecordingForm form) + { + String recording = (form.getRecordingName()).trim(); + String bandChoice = form.getSelectedBand(); + if(recording.length() != 0) { + try { + library.addRecording(bandChoice, recording); + allRecordings = library.getRecordings(bandChoice); + } + catch(EJBException ee) { + Exception ne = (Exception) ee.getCause(); + if(ne.getClass().getName().equals("FinderException")) + ... + else if(...) + ... + } + } + ... + return new Forward("success"); + } + + +

    If the client uses an EJB control that references the EJB via its remote interfaces, you must + catch the RemoteException instead and retrieve its nested exception. The following code snippet + shows how this is done:

    + + @Control() + private EJBControls.RemoteMusicBeanControl remoteLibrary; + + ... + + @Jpf.Action( + forwards = { + @Jpf.Forward(name="success", path="addRecording.jsp") + } + } + protected Forward addARecording(AddARecordingForm form) + { + String recording = (form.getRecordingName()).trim(); + String bandChoice = form.getSelectedBand(); + if(recording.length() != 0) { + try { + remoteLibrary.addRecording(bandChoice, recording); + allRecordings = library.getRecordings(bandChoice); + } + catch(RemoteException re) { + EJBException ee = (EJBException) re.getCause(); + Exception ne = (Exception) ee.getCause(); + ... + } + } + ... + return new Forward("success"); + } + +
    +
    + +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/system-controls/ejb/tutorial.xml b/docs/forrest/release/src/documentation/content/xdocs/system-controls/ejb/tutorial.xml new file mode 100644 index 0000000..39035c5 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/system-controls/ejb/tutorial.xml @@ -0,0 +1,92 @@ + + + +
    + EJB Control Tutorial +
    + +
    + Overview +

    The EJB Control is an extensible control, and you do not use it directly. To create an EJB control + for an EJB, you would create a control extending the EJB Control. An extended EJB control can + only represent one EJB, so you must create one for each EJB. +

    +
    +
    + Extending the EJB Control +
      +
    1. Create a Java interface extending the appropriate EJB Control interface. If the EJB is a + session bean, you must extend org.apache.beehive.controls.system.ejb.SessionEJBControl, or if it is an + entity bean, extend org.apache.beehive.controls.system.ejb.EntityEJBControl.
    2. + +
    3. Annotate the Java interface with @ControlExtension + (org.apache.beehive.controls.api.bean.ControlExtension), so the Control Annotation + Processor will know that the Java interface is a control extension.
    4. + +
    5. Have the Java interface also extend the EJB's home and business interfaces. The + business interface may either by the EJB's local interface or the remote interface.
    6. + +
    7. Specifiy how the EJB control should lookup the EJB. To lookup the EJB by its JNDI name, + set the EJB control's @EJBHome.jndiName annotation to the EJB's JNDI name. To lookup + the EJB using an EJB link, set the EJB control's @EJBHome.ejbLink annotation to the name + of the EJB link.
    8. + +
    9. If the EJB control uses JNDI to look up an EJB, you may optionally specify the JNDI context + environment properties using the @JNDIContextEnv annotation.
    10. +
    +
    +
    + EJB Control Extension Examples +
    + Session Bean EJB Control Example +

    This code is part of the EJB Control samples that is available in the samples directory of the + Beehive source tree. This sample demonstrates an EJB control for a session bean.

    + + +package org.apache.beehive.controls.system.ejb.sample.control; + +import org.apache.beehive.controls.api.bean.ControlExtension; +import org.apache.beehive.controls.system.ejb.SessionEJBControl; +import org.apache.beehive.controls.system.ejb.EJBControl.EJBHome; +import org.apache.beehive.controls.system.ejb.EJBControl.JNDIContextEnv; +import org.apache.beehive.controls.system.ejb.sample.bean.HelloHome; +import org.apache.beehive.controls.system.ejb.sample.bean.HelloRemote; + +@ControlExtension +@EJBHome(jndiName="org.apache.beehive.controls.system.ejb.sample.HelloHome") +@JNDIContextEnv( + contextFactory="weblogic.jndi.WLInitialContextFactory", + providerURL="t3://localhost:7001", + principal="manager", + credentials="manager") +public interface HelloEJBControl + extends SessionEJBControl, HelloHome, HelloRemote { +} + + +
    + +
    + Entity Bean EJB Control Example +

    This sample demonstrates an EJB control for a entity bean.

    + + +package org.apache.beehive.controls.system.ejb.sample.control; + +import org.apache.beehive.controls.api.bean.ControlExtension; +import org.apache.beehive.controls.system.ejb.EntityEJBControl; +import org.apache.beehive.controls.system.ejb.EJBControl.EJBHome; +import com.mycompany.MyEntityBeanHome; +import com.mycompany.MyEntityBeanRemote; + +@ControlExtension +@EJBHome(jndiName="com.mycompany.MyEntityBeanHome") +public interface MyEJBControl + extends EntityEJBControl, MyEntityBeanHome, MyEntityBeanRemote { +} + + +
    +
    + +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/system-controls/jdbc/annotations.xml b/docs/forrest/release/src/documentation/content/xdocs/system-controls/jdbc/annotations.xml new file mode 100644 index 0000000..95c3d49 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/system-controls/jdbc/annotations.xml @@ -0,0 +1,19 @@ + + + +
    + JDBC Control Annotations +
    + +

    @JdbcControl.ConnectionDataSource

    +

    @JdbcControl.ConnectionDriver

    +

    @JdbcControl.ConnectionOptions

    +

    @JdbcControl.SQL

    +

    @JdbcControl.TypeMapper

    + +
    + Java, J2EE, and JCP are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.
    + © 2005, Apache Software Foundation +
    +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/system-controls/jdbc/guide.xml b/docs/forrest/release/src/documentation/content/xdocs/system-controls/jdbc/guide.xml new file mode 100644 index 0000000..3f905bb --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/system-controls/jdbc/guide.xml @@ -0,0 +1,1397 @@ + + + +
    + Jdbc Control Developer's Guide +
    + +
    + Jdbc Control Annotation's Reference + +

    The Jdbc Control uses Java 1.5 annotations extensively. All annotations are defined in the + org.apache.beehive.controls.system.jdbc.JdbcControl interface. Whenever possible annotations are checked for validity during compile + time using an apt processor. The compile time checks include parsing the _statement_ member of the SQL annotation + to make sure it conforms to the parameter substitution syntax expected by the Jdbc Control. +

    + +
    + The ConnectionDataSource Annotation +

    The ConnectionDataSource annotation is a class-level annotation used to lookup a DataSource using the JNDI service.

    + + + + +
    Member NameValue TypeValue RequiredDescription
    jndiNameStringYesA data source name which can be used for a JNDI lookup
    jndiContextFactoryClass <? extends JndiContextFactory>NoA JNDI context factory
    +
    +
    + The ConnectionDriver Annotation +

    The ConnectionDriver annotation is a class-level annotation used to connect directly to a database + instance using a connection URL.

    + + + + + + + + +
    Member NameValue TypeValue RequiredDescription
    databaseDriverClassjava.lang.ClassYesThe database driver class
    databaseURLStringYesThe database connection URL
    userNameStringNoThe username to connect to the database with
    passwordStringNoThe password associated with userName
    propertiesStringNoA semicolon seperated list of properties for the connection, property values are ignored if either the userName or password element of this annotation is set.
    +
    +
    + The ConnectionOptions Annotation +

    The ConnectionOptions annotation is a class-level annotation used to set options on a JDBC connection. + It is used in conjunction with the ConnectionDataSource and ConnectionDriver annotations but is not required. +

    + + + + + + +
    Member NameValue TypeValue RequiredDescription
    readOnly|booleanNoIf set to true tells the database to optimize the connection for read-only access (still can do updates, etc), defaults to false
    resultSetHoldabilityHoldabilityTypeNoSpecifies ResultSet cursor holdability, defaults to close cursors after commit
    typeMappersTypeMapper[]NoType mappers implement the java.sql.SQLData interface and handle mappings between SQL UDTs and Java classes
    +
    +
    + The SQL Annotation +

    The SQL annotation is method annotation which specifies the SQL to send to the database as + well as any other options for the query.

    + + + + + + + + + + + + + + + + + +
    Member NameValue TypeValue RequiredDescription
    statementStringYesThe SQL statement to send to the database
    arrayMaxLengthintNoIf the method return type is an array type, limit the size of the array to this value
    batchUpdatebooleanNoDefaults to false, JDBC 3.0 batch update
    fetchSizeintNoPerformance hint for fetching ResultSet rows, defaults to zero, indicating db should determine fetch size.
    fetchDirectionFetchDirectionNoPerformance hint for fetching ResultSet rows, defaults to forward.
    getGeneratedKeysbooleanNoDefaults to false, JDBC 3.0 generated keys
    generatedKeyColumnNamesString arrayNoDefines column names of columns with generated keys to be returned
    generatedKeyColumnIndexesint arrayNoDefines column indexes of columns with generated keys to be returned
    iteratorElementTypeClassNoDefines type of class to iterate over when method return type is Iterator
    maxRowsintNoLimit the maximum number of rows returned by the database.
    resultSetHoldabilityOverrideHoldabilityTypeNoOverrides value set by ConnectionOptions holdability element for the duration of the method call.
    resultSetMapperClassNoDefines a custom ResultSetMapper for use with this method
    scrollableResultSetScrollType enumerationNoEnables the return of scrollable ResultSet's, default is non-scrollable. See JdbcControl.java for ScrollType values.
    typeMappersOverrideTypeMapper[]NoOverrides typemapper's set in the ConnectionOptions annotation.
    +
    +
    +
    + Parameter Substitution in the SQL Annotation's Statement Member + +

    You can use parameter substitution in the SQL annotation's _statement_ member to form a query dynamically. + The client calls the method on the Jdbc control, passing in values for the method's parameters, and + those parameter values are substituted into the SQL statement.

    + +

    This topic describes substitution techniques and rules, including how to treat curly braces, how to + substitute whole SQL statements, SQL phrases, simple parameters, and indirect parameters.

    +
    + Substitution Criteria + +

    Substitution is subject to the following criteria:

    +
      +
    • Substitution matching is case sensitive. For example, the method parameter CustCity will not match the substitution pattern {custCity}.
    • + +
    • The type of the method parameter must be compatible with the type of the associated database field in the statement. If you attempt to substitute a Java String where the database expects a NUMBER, the statement will fail. For information on mapping between database types and Java types, see Mapping Database Field Types to Java Types in the Database Control.
    • + +
    • Substitution will not occur if the substitution pattern contains spaces. The Java Database Connectivity (JDBC) API allows access to built-in database functions via escapes of the form {fn user()}. If spaces occur in an item enclosed in curly braces ({}), the Database control treats the item as a JDBC escape and passes it on without substitution. For example, the custCity method parameter will not be substituted if the substitution is specified as {custCity } or { custCity}. For more information on JDBC escapes, please consult the documentation for your JDBC driver.
    • + +
    • When substituting date or time values, use the classes in the java.sql package. For example, attempting to substitute java.util.Date in a SQL Date field will not work. Use java.sql.Date instead.
    • +
    +
    + +
    + Substituting Simple Parameters + +

    If you are substituting individual values into a WHERE, LIKE, or AND clause, you may substitute them directly + in the @SQL annotation's statement parameter without escaping the values with the {sql:} substitution syntax.

    + +

    The following example illustrates simple parameter substitution:

    + + +@SQL(statement="SELECT name FROM customer WHERE city={custCity} AND state={custState}") +public String [] getCustomersInCity( String custCity, String custState ); + + +

    The value of the custCity method parameter is substituted in the query in place of the {custCity} item, and the value of the custState method parameter is substituted in the query in place of the {custState} item.

    +
    + +
    + Treatment of Curly Braces Within Literals + +

    Curly braces (\{\}) within literals (strings within quotes) are ignored. This means statements like the + following will not work as you might expect. In the following example the curly braces have lost their + substitution functionality, because they appear within single quotes.

    + + + @SQL( statement="SELECT name FROM employees WHERE name LIKE '%{partialName}%'") +public String[] partialNameSearch(String partialName); + + +

    Since the curly braces are ignored inside the literal string, the expected substitution of the + partialName Java String into the SELECT statement does not occur. To avoid this problem, + pre-format the match string before invoking the Jdbc control method, as shown below. Note + that single quotes are not included in the pre-formatted string because single quotes are + implicitly added to the substitution value when it is passed to the SQL query.

    + + +String partialNameToMatch = "%" + matchString + "%" +String [] names = myJdbcControl.partialNameSeach(partialNameToMatch); + + +

    Then pass the pre-formatted string to the Jdbc control:

    + + +@SQL ( statement="SELECT name FROM employees WHERE name LIKE {partialNameToMatch}") + public String[] partialNameSearch(String partialNameToMatch); + +
    + +
    + Substituting Indirect Parameters + +

    Assume the following class is declared and is accessible to the Database control:

    + + +public static class Customer +{ + public String firstName; + public String lastName; + public String streetAddress; + public String city; + private String state; + public String zipCode; + public String getState() {return state}; +} + + +

    You can then refer to the members of the Customer class in the SQL statement, as shown in the following example:

    + + +@SQL( statement="SELECT name FROM customer WHERE city={cust.city} AND state={cust.state}") +public String [] getCustomersInCity( Customer cust ); + + +

    Note: Class member variables and accessor (getXxx) methods must be public in order for the Database control to substitute them.

    + +

    The dot notation is used to access the members of the parameter object.

    + +

    The following list describes the precedence for resolving dot notations in substitutions given the substitution pattern {myClass.myMember}:

    + +
      +
    • If class myClass exposes public getMyMember() and setMyMember() methods, getMyMember() is called and the return value is substituted. For Boolean variables, substitute isMyMember() for getMyMemnber().
    • +
    • Else if class myClass exposes a public field named myMember, myClass.myMember is substituted.
    • +
    • Lastly, if class myClass implements java.util.Map, myClass.get("myMember") is called and the return value is substituted.
    • +
    • Any combination of these may exist, as in {A.B.C} where B is a public member of A and B has a public getC() method.
    • +
    + +

    If none of these conditions exist, the Jdbc control method will throw a com.bea.control.ControlException.

    +
    +
    + Generic Substitution + +

    To pass a whole SQL statement to the database, use the substitution syntax shown in bold.

    + + +@SQL(statement="{sql: sqlStatement}") +public myRecordType myQuery( String sqlStatement ); + + +

    The SQL statement placed within the bracket syntax {sql: } is escaped and passed directly to the database.

    + +

    You can use same substitution syntax to pass in any part of a SQL statement, such as a WHERE or LIKE clause, or a column name. In the following example, filtering phrases can be substituted into the base SQL statement.

    + + +@SQL(statement="SELECT * FROM CUSTOMER {sql: whereClause}") +public myRecordType myQuery( String whereClause ); + + +

    In the following example, a column name is dynamically written to the SQL statement by means of the {sql: } bracket syntax.

    + + +@SQL(statement="SELECT SUM( {sql: colName} ) FROM MYTABLE") +public int sumColumn(String colName); + +
    + +
    + Referring to Functions in Substitution Statements + +

    If your database supports internal functions, you can refer to the internal function within + the substitution syntax {sql: }. The following method refers to the function in(), by placing + the function call within the brackets {sql: }.

    + + + @SQL( statement="SELECT * FROM customer WHERE {sql:fn in(custid,{customerIDs})}") + Customer[] callInternalFunction(Integer[] customerIDs); + + +

    Not all databases and database drivers support internal functions within substitution brackets; for example, Oracle drivers do not support this scenario.

    +
    + +
    + SQL Escapes Support +

    The SQL annotations statement member supports the use of the SQL Escape syntax within the SQL statement. + SQL Escapes follow the standard escape syntax and may contain parameter substitutions. The set of + supported escape keywords is:

    +
      +
    • escape
    • +
    • fn
    • +
    • d
    • +
    • t
    • +
    • ts
    • +
    • call
    • +
    • ?=
    • +
    • oj
    • +
    + +

    The following examples illustrate some of the possible usages.

    + + +@SQL(statement="INSERT INTO USERS (creationDate, userName) VALUES({d {creationDateFormat}},{userName}) +public int addUser(String creationDateFormat, String userName) throws SQLException; + + + +@SQL(statement="INSERT INTO USERS (userId, userName) VALUES({?= sp_userId()},{userName})") +public int addUser(String userName) throws SQLException; + +
    +
    + +
    + Invoking Stored Procedures with the Jdbc Control + +

    The following topics explain how to call and create stored procedures with the Jdbc Control.

    +
    + Calling Stored Procedures with IN Parameters +

    If the stored procedure contains only IN parameters, you can call the procedure by + passing method parameters to the procedure.

    +

    Assume the following procedure sp_updateData has been created on the database.

    + + + CREATE OR REPLACE PROCEDURE sp_updateData + (pkID IN SMALLINT, + intVal IN INT) + AS + BEGIN + UPDATE CUSTOMER + SET NAME = intVal + WHERE CUSTID = pkID; + END sp_updateData; + + +

    The following database control method calls the procedure sp_updateData and + passes two method parameters to the procedure.

    + + + @SQL(statement="call sp_updateData({keyVal}, {intVal})" + void call_sp_updateCust(short keyVal, int intVal); + + +

    The method parameters are substituted into the procedure call using the curly brace substitution syntax.

    + +

    If you are calling this stored procedure against a Sybase database, you must include curly braces around the stored procedure call. For Sybase, the annotation value should look like this:

    + + +@SQL(statement="{call sp_updateData({keyVal}, {intVal})}") + +
    +
    + Calling Stored Procedures with OUT Parameters + +

    To call a procedure that contains OUT parameters:

    +
      +
    1. Use a SQLParameter Array as the parameter of the Java method that calls the procedure.
    2. +
    3. Use question marks as placeholders for the parameters within the procedure call.
    4. +
    + +

    The SQLParameter class is an public inner class of JdbcControl.java, source follows:

    + + + public static class SQLParameter { + public static final int IN = 1; + public static final int OUT = 2; + public static final int INOUT = IN | OUT; + + public Object value = null; + public int type = Types.NULL; + public int dir = IN; + + public SQLParameter(Object value) { + this.value = value; + } + + public SQLParameter(Object value, int type) { + this.value = value; + this.type = type; + } + + public SQLParameter(Object value, int type, int dir) { + this.value = value; + this.type = type; + this.dir = dir; + } + + public Object clone() { + return new SQLParameter(value, type, dir); + } + } + + +

    For example, assume that the following procedure sp_squareInt exists on the database.

    + + + CREATE OR REPLACE PROCEDURE sp_squareInt + (field1 IN INTEGER, field2 OUT INTEGER) IS + BEGIN + field2 := field1 * field1; + END sp_squareInt; + + +

    The following Java method will call the procedure sp_squareInt.

    + + + @SQL(statement="{call sp_squareInt(?, ?)})" + void call_sp_squareInt(SQLParameter[] params) throws SQLException; + + +

    Note that the method parameter params is not explicitly substituted into the procedure + call {call sp_squareInt(?, ?)}. The substitution syntax {call ...} has special + meaning within the @SQL statement annotation. When the substitution syntax + {call myStoredProc(?,?,?...)} is encountered, it automatically distributes the + elements of params into the procedure call.

    + +

    The following shows how to construct an SQLParameter[] to call the procedure sp_squareInt.

    + + + // Construct a SQLParameter[] + // to hold two SQLParameter objects + SQLParameter[] params = new SQLParameter[2]; + + // Construct two objects corresponding to the initial values of the + // stored procedure's two parameters. + Object obj0 = new Integer\(x); + Object obj1 = new Integer(0); + + // The stored procedure sp_squareInt has two parameters: + // an IN parameter of data type INTEGER + // and an OUT parameter of data type INTEGER. + // params[0] is build to correspond to the IN parameter, + // params[1] is build to correspond to the OUT parameter. + params[0] = new SQLParameter(obj0, Types.INTEGER, SQLParameter.IN); + params[1] = new SQLParameter(obj1, Types.INTEGER, SQLParameter.OUT); + + // Call the stored procedure. + // Note that the procedure does not return any value. + // Instead the result of the procedure is loaded directly into the OUT parameter, + // and, in turn, into params[1]. + myJDBCControlFile.call_sp_squareInt(params); + + // Get the result loaded directly into params[1]. + return Integer.parseInt(params[1].value.toString()); + + +

    Note that Jdbc control method call_sp_squareInt does not return the result of the procedure call. + Instead the result of the procedure is loaded directly into the procedure's OUT parameter, + and this in turn is loaded directly into the corresponding SQLParameter object. To get the + result of the procedure, examine the .value property of the SQLParameter object.

    + + + params[1].value + +
    +
    + Wrapping Procedures in Functions + +

    An alternative to calling stored procedures directly is to wrap them in stored functions, + then call the wrapping function from your database control file.

    + +

    For example the following Jdbc control method will create a function that wraps the + procedure sp_squareInt.

    + + + /** + * Wraps a procedure in a function. + * / + @SQL(statement="CREATE OR REPLACE FUNCTION wrapProc (p1 INTEGER) RETURN INTEGER IS p2 INTEGER; BEGIN sp_squareInt(p1, p2); RETURN p2; END;") + public void create_wrapProc(); + + +

    Once the procedure has been wrapped, you can call the function, instead of calling the procedure directly.

    + + + @SQL(statement="SELECT wrapProc({x}) FROM DUAL") + public int callWrapProc(int x, int y); + +
    +
    + Creating Strored Procedures + +

    You can also send any DDL statement to the database through a database control method.

    + + + /** + * A stored procedure that takes an integer, squares it, and loads + * the result into an OUT parameter. + * / + @SQL(statement="CREATE OR REPLACE PROCEDURE sp_squareInt (field1 IN INTEGER, field2 OUT INTEGER) IS BEGIN field2 := field1 * field1; END sp_squareInt; ") + void create_sp_squareInt() throws SQLException; + + +

    Some XA database drivers contain restrictions on code that rollsback or commits a + transaction independently of the driver's transaction management. Since DDL + statements are implicitly transactional (COMMIT is called whether or not + it explicitly appears in the DDL statement), you may have to suspend the + transaction with these XA drivers. For example if you send a DDL statement + using the Oracle XA thin client without suspending the transaction, the driver + throws the following exception:

    + +

    ORA-02089: COMMIT is not allowed in a subordinate session

    + +

    The following code suspends the transaction, executes the DDL statement, and then resumes the transaction.

    + + + import javax.transaction.Transaction; + import javax.transaction.TransactionManager; + import javax.transaction.TxHelper; + + TransactionManager tm = TxHelper.getTransactionManager(); + Transaction saveTx = null; + try + { + + // Suspend the transaction + saveTx = tm.forceSuspend(); + + + // Execute the DDL statement + myDBControlFile.create_sp_squareInt(); + } + finally + { + + // Resume the transaction + tm.forceResume(saveTx); + } + +
    +
    +
    + Stored Functions + +

    This topic explains how to call and create stored functions using Jdbc control.

    +
    + Calling Stored Functions + +

    To call a stored function, place the function call in an @SQL statement annotation. When the + Java method callMyFunction is called, the SQL statement in the @SQLl statement annotation + is passed to the database. Any data returned by the SQL statement is passed back to, and + returned by, the Java method.

    + + + @SQL(statement="SELECT my_function FROM DUAL") + int callMyFunction() throws SQLException; + + +

    In most cases, the Jdbc control automatically converts between the appropriate database data types + and Java data types. For example, if the database function my_function returns the database + type INTEGER, the Java method callMyFunction() will automatically convert it into the Java type int.

    + +

    You can substitute values dynamically into the database function call using curly braces. + The following method passes the parameter int x to the function call.

    +
    +
    + Creating Stored Functions + +

    You can also send any DDL statement to the database through a Jdbc control method.

    + + + /** + * A stored function that takes an integer, squares it, and returns the + * result through the database control method. + * / + @SQL(statement="CREATE OR REPLACE FUNCTION fn_squareInt (field1 IN INTEGER) RETURN INTEGER IS field2 INTEGER; BEGIN field2 := field1 * field1; RETURN field2; END fn_squareInt;") + void create_fn_squareInt() throws SQLException; + + +

    Some XA database drivers contain restrictions on code that rollsback or commits a + transaction independently of the driver's transaction management. Since DDL + statements are implicitly transactional (COMMIT is called whether or not + it explicitly appears in the DDL statement), you may have to suspend the + transaction with these XA drivers. For example if you send a DDL statement + using the Oracle XA thin client without suspending the transaction, the driver + throws the following exception:

    + +

    ORA-02089: COMMIT is not allowed in a subordinate session

    + +

    The following code suspends the transaction, executes the DDL statement, and then resumes the transaction.

    + + + import javax.transaction.Transaction; + import javax.transaction.TransactionManager; + import javax.transaction.TxHelper; + + TransactionManager tm = TxHelper.getTransactionManager(); + Transaction saveTx = null; + try + { + + // Suspend the transaction + saveTx = tm.forceSuspend(); + + + // Execute the DDL statement + myDBControlFile.create_fn_squareInt(); + } + finally + { + + // Resume the transaction + tm.forceResume(saveTx); + } + +
    +
    + +
    + Jdbc Control Return Type Mapping +

    When returning a value from a database, the Jdbc Control maps the JDBC ResultSet generated by the SQL to the calling + method's return type. These mappings can be characterized as follows:

    + +
    + Mapping a Single Value + +

    This topic describes how to write methods that return a single value from the database. The example + provided represents a SELECT statement that requests only a single field of a single row. The + return value of the method should be an object or primitive of the appropriate type for that + field's data.

    + +
    + Returning a Single Column + +

    The following example assumes a Customers table in which the field custid, representing + the customer ID, is the primary key. Given the customer ID, the method looks up a + single customer name.

    + + +@SQL(statement="SELECT name FROM customer WHERE custid={customerID}") +public String getCustomerName(int customerID); + + +

    In this example, the name field is of type VARCHAR, so the return value is declared as String. + The method's customerID parameter is of type int. When the SQL statement executes, this + parameter is mapped to an appropriate numeric type accepted by the database.

    +
    +
    + Returning an Update Count + +

    Suppose that with the same database table a row is inserted; the following code could be + used to get the update count from the insert statement:

    + + +@SQL(statement="INSERT INTO customer VALUES ({customerName},{customerID})") +public int insertCustomer(String customerName, int customerID); + +
    +
    +
    + Mapping a Single Row + +

    This topic describes how to write methods on a Jdbc control that return a single row from the database. + When you return a single row with multiple fields, your method must have a return type that can + contain multiple values--either an object that is an instance of a class that you have built for + that purpose, or a java.util.HashMap object.

    + +

    If you know the names of the fields returned by the query, you will probably want to return a + custom object. If the number of columns or the particular field names returned by the query are + unknown or may change, you may choose to return a HashMap.

    + +
    + Returning an Object + +

    You can specify that the return type of a Jdbc control method is a custom object, an instance + of a class whose members correspond to fields in the database table. In most cases, a + class whose members hold corresponding database field values is declared as an inner + class (a class declared inside another class) in the Jdbc control's JCX file. However, + it may be any Java class that meets the following criteria:

    + +
      +
    • The class must contain members with names that match the names of the columns that + will be returned by the query. Because database column names are case-insensitive, + the matching names are case-insensitive. The class may also contain other members, + but members with matching names are required.
    • +
    • The members must be of an appropriate type to hold a value from the corresponding + column in the database.
    • +
    • The class must be declared as public static if the class is an inner class.
    • +
    + +

    The following example declares a Customer class with members corresponding to fields in the + Customers table. The findCustomer method returns an object of type Customer:

    + + +public static class Customer +{ + public int custid; + public String name; + public Customer() {}; +} + +@SQL(statement="SELECT custid,name FROM customer WHERE custid={customerID})" +Customer findCustomer(int customerID) + + +

    Note: The Customer class above is simplified for the sake of clarity. For data modeling + classes, it is generally good design practice to have private fields, with public + setter and getter methods.

    + + + public static class Customer + { + private int custid; + private String name; + + public Customer() {}; + + public int getCustid() + { + return this.custid; + } + + public void setCustid(int custid) + { + this.custid = custid; + } + + public String getName() + { + return this.name; + } + + public void setName(String name) + { + this.name = name; + } + } + +
    +
    + Handling Empty Values When Returning Objects + +

    If a database field being queried contains no value for a given row, the class member is set to + null if it is an object and to 0 or false if it is a primitive. This may affect your + decisions regarding the types you use in your class. If the database field contained no data, + an Integer member would receive the value null, but an int member would receive the value 0. + Zero may be a valid value, so using int instead of Integer makes it impossible for subsequent + code to determine whether a value was present in the database.

    + +

    If there is no column in the database corresponding to a member of the class, that member is also + set to null or 0, depending on whether the member is an primitive or an object.

    + +

    If the query returns columns that cannot be matched to the members of the class, an exception is + thrown. If you don't know the columns that will be returned or if they may change, you should + consider returning a HashMap instead of a specific class. For more information, see the + Returning a HashMap section, below.

    + +

    If no rows are returned by the query, the returned value of the Jdbc control method is null.

    + +

    In the example given above, the method is declared as returning a single object of type Customer. + So even if the database operation returns multiple rows, only the first row is returned to + the method's caller. To learn how to return multiple rows to the caller, + see Mapping Multiple Rows.

    +
    +
    + Returning a HashMap or Map + +

    If the number of columns or the particular column names returned by the query are unknown + or may change, you may choose to return a HashMap. To return a HashMap, declare the + return value of the method as java.util.HashMap, as shown here:

    + + +@SQL(statement="SELECT * FROM customer WHERE custid={custID})" +public java.util.HashMap findCustomerHash(int custID); + + +

    The HashMap returned contains an entry for each column in the result. The key for each + entry is the corresponding column name. The capitalization of the key names returned + by HashMap.keySet() depends on the database driver in use, but all keys are case-insensitive + when accessed via the HashMap's methods. The value is an object of the Java Database + Connectivity (JDBC) default type for the database column.

    + +

    In the example above, the method is declared as returning a single object of type + java.util.HashMap. So even if the database operation returns multiple rows, + only the first row is returned to the method's caller.

    + +

    To learn how return multiple rows to the caller, see Mapping Multiple Rows.

    + +

    The following code allows you to access the name field of the returned record:

    + + +@Control +private CustomerDBControl custDB; + +public String getCustomerName(int custID) +{ + java.util.HashMap hash; + String name; + hash = custDB.findCustomerHash(custID); + if( hash != null ) + { + name = (String)hash.get("NAME"); + } + else + { + name = new String("Customer not found"); + } + return name; +} + + +

    If the query returns no rows, the returned value of the Jdbc control method is null.

    +
    +
    + +
    + Returning Multiple Rows from a Jdbc Control Method + +

    This topic describes how to write a method on a Jdbc control that returns multiple rows from the + database. It describes the ways in which you can perform this operation, including returning + an array, returning an Iterator object, and returning a resultset.

    +
    + Deciding How to Return Multiple Rows + +

    A SELECT query may return one or more fields from multiple rows. A method on a Jdbc control + that returns multiple rows should have a return type that can store these values. The + Jdbc control method can return an array of objects, an Iterator, or a resultset.

    + +

    Returning an array of objects is the easiest way to return multiple rows, so it is a good choice + if you think your users will prefer simplicity when using your control. However, when an + array is returned only one database operation is performed, and the entire resultset must + be stored in memory. For large resultsets, this is problematic. You can limit the size + of the returned array, but then you cannot provide a way for your user to get the remainder + of the resultset. To learn how to return an array of objects, see the Returning an Array of Objects + section, below.

    + +

    While Iterators require more sophistication on the part of users of your control, they are more + efficient at handling large resultsets. An Iterator is accessed one element (row) at a time + via the Iterator's next() method, and it transparently makes repeated requests from the database + until all records have been processed. An Iterator does not present the risk of running out of + memory that an array presents. However, note that an Iterator returned from a database control + cannot be used within a Page Flow controller class, because an Iterator wraps a ResultSet object, + which is always closed by the time it is passed to the web-tier (where Page Flow files reside). + For this reason, your Jdbc control should return an array of objects (see above) when it is called + from a page flow controller. Also, an Iterator cannot be returned to a stateful process, because + stateful processes cannot maintain an open database connection (which Iterators require). To + learn about returning a java.util.Iterator, see the Returning an Iterator section, below.

    + +

    Finally, you can choose to return a java.sql.ResultSet from a Jdbc control method. This grants + complete access to the results of the database operation to clients of your control, but it + requires knowledge of the java.sql package. Also, note that a ResultSet returned from a + Jdbc control cannot be used within a Page Flow controller, because a ResultSet object is + always closed by the time it is passed to the web-tier (where Page Flow files reside). For + this reason, your Jdbc control should provide an array of objects when it is called from a + Page Flow controller. To learn about returning a java.sql.ResultSet, see the Returning a Resultset + section, below.

    +
    + +
    + Returning an Array of Objects + +

    To return an array of objects, declare the method's return type to be an array of the object you + want to return. That type may be either a type you define, or it may be java.util.Hashmap.

    + +

    Examples of both of these techniques are provided in the following sections.

    +
    + +
    + Returning an Array of User-Defined Objects + +

    The following example demonstrates how to return an array of objects whose type you have declared. + In this case, an array of Customer objects is returned:

    + + +public static class Customer +{ + public int custid; + public String name; +} + +@SQL(statement="SELECT custid,name FROM customer WHERE custage<19", arrayMaxLength=100) +Customer [] findAllMinorCustomers() + + +

    This example returns all rows in which the custage field contains a value less than 19.

    + +

    When returning an array of objects, the class declared as the return type of the method + must meet the criteria described in the Returning an Object section of the Returning + a Single Row from a Jdbc Control topic. If no rows are returned by the query, the returned + value of the Database control method is a zero-length array.

    + +

    If you are returning an array from Jdbc control method, you can limit the size of the array + returned by setting the arrayMaxLength attribute of the @SQL annotation. This attribute + can protect you from very large resultsets that may be returned by very general queries. + If arrayMaxLength is present, no more than that many rows are returned by the method.

    + +

    The default value of arrayMaxLength is 1024. For very large ResultSets you can avoid excessive + memory usage by returning an Iterator object as described below in the Returning an Iterator + section, below.

    + +
    +
    + Returning an Array of HashMaps + +

    Returning an array of HashMaps is analogous to returning an array of user-defined objects, + which is described in the preceding section.

    + +

    The following example demonstrates returning an array of HashMaps:

    + + +public static class Customer +{ + public int custid; + public String name; + public Customer() {}; +} + +@SQL(statement="SELECT custid,name FROM customer WHERE custage<19", arrayMaxLength=100) +java.util.HashMap [] findAllMinorCustomersHash() + + +

    The array of HashMaps returned contains an element for each row returned, and each element of the + array contains an entry for each column in the result. The key for each entry is the corresponding + column name. The capitalization of the key names returned by HashMap.keySet() depends on the + database driver in use, but keys are case-insensitive when accessed via the HashMap's methods. + The value returned is an object of the Java Database Connectivity (JDBC) default type for the + database column.

    + +

    If no rows are returned by the query, the returned value of the Jdbc control method is a zero-length array.

    + +

    The following code shows how to access the name field of the returned records:

    + + +@Control +private CustomerDBControl custDB; + +java.util.HashMap [] hashArr; +String name; + +hashArr = custDB.findAllMinorCustomersHash(); +for(i=0; i<hashArr.length; i++) +{ + name = (String)hashArr[i].get("NAME"); + // say hello to the all of the minors + + System.out.println("Hello, " + name + "!"); +} + +
    + +
    + Returning an Iterator + +

    When you want to return an Iterator object, you declare the method's return type to be java.util.Iterator. + You then add the iteratorElementType attribute to the @SQL annotation to indicate the underlying + type that the Iterator will contain. The specified type may be either a type you define, or it may + be java.util.Hashmap. Examples of these techniques are given in the following sections. If your + method returns an Iterator, a compile time error will be generated if the iteratorElementType + annotation member has not been set.

    + +

    The Iterator that is returned is only guaranteed to be valid for the life of the method call to which it is + returned. You should not store an Iterator returned from a Jdbc control method as a static member of + your web service's class, nor should you attempt to reuse the Iterator in subsequent method calls if + it is persisted by other means.

    +
    +
    + Returning an Iterator with a User-Defined Object + +

    To return an Iterator that encapsulates a user-defined type, provide the class name as the + value of the iteratorElementType attribute of the @SQL annotation, as shown here:

    + + +public static class Customer +{ + public int custid; + public String name; + public Customer() {}; +} + +@SQL(statement="SELECT custid,name FROM customer" iteratorElementType=Customer.class) +java.util.Iterator getAllCustomersIterator() + + +

    The class specified in the iterator-element-type attribute must meet the criteria described + in Returning an Object.

    + +

    The following example shows how to access the returned records:

    + + +CustomerJDBCControl.Customer cust; +java.util.Iterator iter = null; +iter = custDB.getAllCustomersIterator(); +while (iter.hasNext()) +{ + cust = (CustomerJDBCControl.Customer)iter.next(); + // say hello to every customer + System.out.println("hello, " + cust.name + "!"); +} + + +
    +
    + Returning an Iterator with HashMap +

    To return an Iterator that encapsulates a HashMap, provide java.util.HashMap as the value of + the iterator-element-type attribute of the @SQL annotation, as shown here:

    + + +public static class Customer +{ + public int custid; + public String name; + public Customer() {}; +} + +@SQL(statement="SELECT custid,name FROM customer", iteratorElementType=java.util.HashMap.class) +java.util.Iterator getAllCustomersIterator() + + +

    The following code shows how to access the returned records:

    + + +java.util.HashMap custHash; +java.util.Iterator iter = null; +int customerID; +String customerName; +iter = custDB.getAllCustomersIterator(); +while (iter.hasNext()) +{ + custHash = (java.util.HashMap)iter.next(); + customerID = (int)custHash.get("CUSTID"); + customerName = (String)custHash.get("NAME"); +} + + +

    The HashMap contains an entry for each database column that is returned by the query. The key for + each entry is the corresponding column name, in all uppercase. The value is an object of + the JDBC default type for the database column.

    +
    +
    + Returning a ResultSet + +

    The Jdbc control is designed to allow you to obtain data from a database in a variety of ways without + having to understand the classes in the java.sql package. If you and your users do understand + these classes, however, you can gain complete access to the java.sql.ResultSet object returned by a query.

    + +

    If you want to return a resultset, you declare the method's return type to be java.sql.ResultSet. A client + of your control then accesses the resultset directly to process the results of the database operation.

    + +

    The following example demonstrates returning a resultset:

    + + +@SQL(statement="SELECT * FROM customer") +public java.sql.ResultSet findAllCustomersResultSet(); + + +

    The following code shows how to access the returned resultset:

    + + +java.sql.ResultSet resultSet; +String thisCustomerName; +resultSet = custDB.findAllCustomersResultSet(); +while (resultSet.next()) +{ + thisCustomerName = new String(resultSet.getString("name")); +} + + +

    This example assumes the rows returned from the database operation include a column called name.

    +
    +
    + +
    + Returning Apache XMLBeans from a Jdbc Control + +

    This topic assumes a strong understanding of Apache XML Beans. For additional information about XML Bean see the Apache XML Beans Site http://xmlbeans.apache.org/.

    + +

    The following topic explains how to return XMLBean types from custom Jdbc controls.

    + +

    An XMLBean is essentially an XML document with a Java API attached to it. The API is used for parsing and manipulating + the data in the XML document. A typical XMLBean might represent database data in the following form.

    + + +<DOCTYPE XCustomer> +<XCustomer xmlns="java:///database/customer_db" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <XCustomerRow> + <CUSTID>1<CUSTID> + <NAME>Fred Williams<NAME> + <ADDRESS>123 Slugger Circle<ADDRESS> + <XCustomerRow> + <XCustomerRow> + <CUSTID>2<CUSTID> + <NAME>Marnie Smithers<NAME> + <ADDRESS>5 Hitchcock Lane<ADDRESS> + <XCustomerRow> + <XCustomerRow> + <CUSTID>3<CUSTID> + <NAME>Bill Walton<NAME> + <ADDRESS>655 Tall Timbers Road<ADDRESS> + <XCustomerRow> +<XCustomer> + + +

    The data can be accessed and manipulated using the XMLBean's API. For example, assume that custBean represents + the XML document above. The following Java code extracts the Fred Williams from the document.

    + + +String name = custBean.getXCustomer().getXCustomerRowArray(1).getNAME(); + + +

    Retrofitting database controls to return XMLBeans rather than RowSets, ResultSets, or Iterators, is a powerful + technique because there are few restrictions on where XMLBeans can be imported. This is not the case with + ResultSets and Iterators, which cannot be passed directly to web-tier classes (web services and page flows). + Also, data in XMLBean form is very easy to manipulate because there is a rich API attached to the XMLBean.

    +
    + Creating a Schema + +

    The first step in using XMLBean classes is creating a schema from which the XMLBean classes can be generated. + The schema you create for a database control must be capable of modeling the sorts of data returned + from the database.

    + +

    If you write your own schema, at a minimum, the schema's elements should have the same names as the fields + in the database, which allows data returned from the database to be automatically mapped into the XMLBean.

    + +

    When the XSD file is compiled, XMLBean types are generated that can be returned by the methods in the database control.

    +
    +
    + Editing Schemas to Create New "Document" Types + +

    Note that only one of the generated types is a "Document" XMLBean type: XCustomerDocument. The other types, + XCustomerDocument.XCustomer and XCustomerDocument.XCustomer.XCustomerRow, can only be used with reference + to the "Document" type. This distinction is especially important because only "Document" types are eligible + for direct participation in a business process, or to be passed to a web service. For this reason you may + want to edit your schema to include "Document" types corresponding to other types in the Schema, especially + if you have a very large schema with many nested types defined in terms of a single "Document" type.

    + +

    To generate a new Document type for some element, move that element so that it becomes a top-level element in + the schema. In the following example, the XCustomerRow element has been moved to the top-level of the + schema: its original position has been replaced with a reference element: <xsd:element ref="XCustomerRow"/>.

    + + +<xml version="1.0" encoding="UTF-8"?> +<xsd:schema targetNamespace="java:///database/customer_db" + xmlns="java:///database/customer_db" xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:wld="http://www.bea.com/2002/10/weblogicdata" + elementFormDefault="qualified" + attributeFormDefault="unqualified"> + + <xsd:element name="XCustomer" wld:DefaultNamespace="java:///database/customer_db" wld:RowSet="true"> + <xsd:complexType> + <xsd:choice maxOccurs="unbounded"> + <xsd:element ref="XCustomerRow"/> + <xsd:choice> + <xsd:complexType> + <xsd:element> + <xsd:element name="XCustomerRow"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="CUSTID" type="xsd:int" wld:JDBCType="INTEGER" minOccurs="0" wld:TableName="MYSCHEMA.CUSTOMER" nillable="true"><xsd:element> + <xsd:element name="NAME" type="xsd:string" wld:JDBCType="VARCHAR" minOccurs="0" wld:TableName="MYSCHEMA.CUSTOMER" nillable="true"><xsd:element> + <xsd:element name="ADDRESS" type="xsd:string" wld:JDBCType="VARCHAR" minOccurs="0" wld:TableName="MYSCHEMA.CUSTOMER" nillable="true"><xsd:element> + <xsd:element name="CITY" type="xsd:string" wld:JDBCType="VARCHAR" minOccurs="0" wld:TableName="MYSCHEMA.CUSTOMER" nillable="true"><xsd:element> + <xsd:element name="STATE" type="xsd:string" wld:JDBCType="CHAR" minOccurs="0" wld:TableName="MYSCHEMA.CUSTOMER" nillable="true"><xsd:element> + <xsd:element name="ZIP" type="xsd:string" wld:JDBCType="VARCHAR" minOccurs="0" wld:TableName="MYSCHEMA.CUSTOMER" nillable="true"><xsd:element> + <xsd:element name="AREA_CODE" type="xsd:string" wld:JDBCType="CHAR" minOccurs="0" wld:TableName="MYSCHEMA.CUSTOMER" nillable="true"><xsd:element> + <xsd:element name="PHONE" type="xsd:string" wld:JDBCType="CHAR" minOccurs="0" wld:TableName="MYSCHEMA.CUSTOMER" nillable="true"><xsd:element> + <xsd:sequence> + <xsd:anyAttribute namespace="http://www.bea.com/2002/10/weblogicdata" processContents="skip">lt;xsd:anyAttribute> + <xsd:complexType> + <xsd:element> +<xsd:schema> + + +

    There are now two top-level elements, XCustomer and XCustomerRow, which compile into two + corresponding "Document" types: XCustomerDocument and XCustomerRowDocument.

    +
    + +
    + Returning a XMLBean Types from Control Methods + +

    Once you have generated XMLBean types that model the database data, you can import these types into + your Jdbc control.

    + + +import databaseCustomerDb.XCustomerDocument; +import databaseCustomerDb.XCustomerDocument.XCustomer; +import databaseCustomerDb.XCustomerDocument.Factory; + + +

    XMLBean types can be returned from the control's methods.

    + + +@SQL(statement="SELECT custid, name, address FROM customer") +public XCustomerDocument findAllCustomersDoc(); + + +

    The data returned from the query is automatically mapped into the XMLBean because the names of the + database fields match the fields of the XMLBean.

    +
    + +
    + +
    + Mapping to a RowSet + +

    This topic describes how to write methods on a Jdbc control that return a RowSet from the database. + Since the RowSet implementations provided by the JDK are part of the javax.sql, package the + JdbcControl does not support any of them by default. A sample ResultSetMapper for RowSet's is + included as part of the Jdbc Control's distribution but must be explicitly set in the @SQL + annotation in order to be invoked.

    + +

    The DefaultRowSetResultSetMapper will create a javax.sql.CachedRowSetImpl. The following example + sets the resultSetMapper for the method getAllUsers() to the DefaultRowSetResultSetMapper + which enables the Jdbc control to map the ResultSet to a RowSet.

    + + +@SQL(statement="SELECT * FROM USERS", resultSetMapper=org.apache.beehive.controls.system.jdbc.DefaultRowSetResultSetMapper.class) +public RowSet getAllUsers() throws SQLException; + + +

    ResultSetMapper's can be created for other types of RowSets and almost any other type of mapping + from a result set to any object. See the [Jdbc Control Custom ResultSetMappers] topic for more information. +

    +
    + +
    + Creating Customer Result Set Mappers + +
    + Overview +

    When the Jdbc Control maps a ResultSet to a return type, it first checks to see if a resultSetMapper + has been set in the method's @SQL annotation. If a mapper has been set, it is always the one used + for mapping the ResultSet to the method's return type. If resultSetMapper has not been + set, the Jdbc control looks for a _resultSetMapper_ based on the method's return type.

    + + + + + + + +
    Mapper Class NameMethod Return Type
    DefaultIteratorResultSetMapperIterator
    DefaultResultSetMapperResultSet
    DefaultXmlObjectResultSetMapperClasses derived from XmlObject
    DefaultObjectresultMapperDefault to this mapper
    + +
    +
    + Creating a custom ResultSet Mapper +

    To create your own ResultSet mapper, create a new class which extends the abstract class + org.apache.beehive.controls.system.jdbc.ResultSetMapper. The mapToResultType() method does all the work + of mapping the ResultSet to the method's return type -- it will be invoked by the + JdbcControl when the control is ready to perform the mapping. Below is the code for + the ResultSetMapper class.

    + + +/** + * Extend this class to create new ResultSet mappers. The extended class will be invoked by the JdbcController + * when it is time to map a ResultSet to a method's return type. + * + * ResultSet mappers must be specified on a per method basis using the SQL annotation's resultSetMapper field + */ +public abstract class ResultSetMapper { + + /** + * Map a ResultSet to an object type + * + * @param context A ControlBeanContext instance, see Beehive controls javadoc for additional information + * @param m Method assoicated with this call. + * @param resultSet Result set to map. + * @param cal A Calendar instance for time/date value resolution. + * @return The Object resulting from the ResultSet + * @throws Exception On error. + */ + public abstract Object mapToResultType(ControlBeanContext context, Method m, ResultSet resultSet, Calendar cal) + throws Exception; + + /** + * Can the ResultSet which this mapper uses be closed by the Jdbc control? + * @return true if the ResultSet can be closed by the JdbcControl + */ + public boolean canCloseResultSet() { return true; } +} + +
    +
    + An Example + +

    Suppose you have a return type class which needs to do some special processing of a ResultSet.

    + + +public final class CustomerX +{ + private String _customerName; + private String _customerPhoneNumber; + + public void setCustomerName(String firstName, String lastName) { + _customerName = firstName + " " + lastName; + } + + public String getCustomerName() { return _customerName; } + + public void setCustomerPhoneNumber(int areaCode, String phoneNumber) { + _customerPhoneNumber = "(" + areaCode + ")" + phoneNumber; + } + + public String getCustomerPhoneNumber() { return _customerPhoneNumber; } +} + + +

    Let's assume the ResultSet contains the following columns:

    + + + + + + +
    Column NameType
    FIRST_NAMEVarchar
    LAST_NAMEVarchar
    AREA_CODEINT
    PHONE_NUMBERVarchar
    + +

    Here's what the ResultSetMapper implementation might look like:

    + +public final class CustomerXResultSetMapper extends ResultSetMapper { + + public Object mapToResultType(ControlBeanContext context, Method m, ResultSet resultSet, Calendar cal) + throws Exception + { + resultSet.next(); + CustomerX c = new CustomerX(); + final String fName = resultSet.getString("FIRST_NAME"); + final String lName = resultSet.getString("LAST_NAME"); + + c.setCustomerName(fName, lName); + + final int aCode = resultSet.getInt("AREA_CODE"); + final int phone = resultSet.get("PHONE_NUMBER"); + + c.setCustomerPhoneNumber(aCode, phone); + + return c; + } +} + + +

    and finally the method and SQL annotation to invoke:

    + + +@SQL(statement="SELECT FIRST_NAME,LAST_NAME,AREA_CODE,PHONE_NUMBER FROM customers WHERE userId={userId}", + resultSetMapper=CustomerXResultSetMapper.class) +public CustomerX getCustomer(String userId); + +
    +
    + Additional Examples +

    See the Jdbc Control Rowset Mapping topic for an example of using a ResultSet mapper to support + the RowSet return type.

    +
    +
    +
    + Database -> Java Type Mapping Tables +
    + PointBase 4.4 Type Mappings + +

    The following table lists the relationships between database types and Java types for the + PointBase Version 4.4 database.

    + + + + + + + + + + + + + + + + + + + + + + + + +
    Java Data TypesJDBC Data TypesPointBase SQL Data Types (Version 4.4)
    booleanBITboolean
    byteTINYINTsmallint
    shortSMALLINTsmallint
    intINTEGERinteger
    longBIGINTnumeric/decimal
    doubleFLOATreal
    doubleDOUBLEdouble
    floatFLOATfloat
    java.math.BigDecimalNUMERICnumeric
    java.math.BigDecimalDECIMALdecimal
    StringCHARchar
    StringVARCHARvarchar
    StringLONGVARCHARclob
    java.sql.DateDATEdate
    java.sql.TimeTIMEtime
    java.sql.TimestampTIMESTAMPtimestamp
    byte[]BINARYblob
    byte[]VARBINARYblob
    byte[]LONGVARBINARYblob
    java.sql.BlobBLOBblob
    java.sql.ClobCLOBclob
    +
    +
    + Oracle Type Mappings + +

    Type Mappings for Oracle 8i

    + +

    The following table lists the relationships between database types and Java types for the Oracle 8i database.

    + + + + + + + + + + + + + + + + + + + + + + + + +
    Java Data TypesJDBC Data TypesOracle SQL Data Types (Version 8i)
    booleanBITNUMBER
    byteTINYINTNUMBER
    shortSMALLINTNUMBER
    intINTEGERNUMBER
    longBIGINTNUMBER
    doubleFLOATNUMBER
    floatREALNUMBER
    doubleDOUBLENUMBER
    java.math.BigDecimalNUMERICNUMBER
    java.math.BigDecimalDECIMALNUMBER
    StringCHARCHAR
    StringVARCHARVARCHAR2
    StringLONGVARCHARLONG
    java.sql.DateDATEDATE
    java.sql.TimeTIMEDATE
    java.sql.TimestampTIMESTAMPDATE
    byte[]BINARYNUMBER
    byte[]VARBINARYRAW
    byte[]LONGVARBINARYLONGRAW
    java.sql.BlobBLOBBLOB
    java.sql.ClobCLOBCLOB
    +
    +
    + Derby Type Mappings + +

    Type Mappings for Derby 10

    + + + + + + + + + + + + + + + + +
    Java Data TypesJDBC Data TypesDerby SQL Data Types (Version 4.4)
    longBIGINTBIGINT
    java.sql.BlobBLOBBLOB
    StringCHARCHAR
    java.sql.ClobCLOBCLOB
    java.sql.DateDATEDATE
    java.math.BigDecimalDECIMALDECIMAL,NUMERIC
    doubleDOUBLEDOUBLE [PRECISION]
    floatFLOATfloat
    intINTEGERinteger
    StringLONGVARCHARLONG VARCHAR
    shortSMALLINTSMALLINT
    java.sql.TimeTIMEtime
    java.sql.TimestampTIMESTAMPtimestamp
    StringVARCHARVARCHAR
    +
    +
    +
    + New Features and Enhancements +

    JDBC 3.0 feature support as well as other new features are being added to the JdbcControl on a + regular basis. Here some of the latest features which have been added:

    + +
      +
    • Support for custom mapping of SQL UDTs
    • +
    • Support for ResultSet holdability (connection and statement level support)
    • +
    • Support for fetchSize and direction
    • +
    • Support for scrollable ResultSets
    • +
    • Retrieval of auto-generated keys
    • +
    • BOOLEAN and DATALINK data types
    • +
    • Blob and Clob type support
    • +
    • Batch Update support
    • +
    +
    +
    + + +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/system-controls/jdbc/tutorial.xml b/docs/forrest/release/src/documentation/content/xdocs/system-controls/jdbc/tutorial.xml new file mode 100644 index 0000000..6fa9fb0 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/system-controls/jdbc/tutorial.xml @@ -0,0 +1,167 @@ + + + +
    + JDBC Control Tutorial +
    + +
    + Overview +
    + The Problem with JDBC: Complexity +

    + The JDBC Control makes it easy to access a relational database from your Java code using SQL commands. + The JDBC Control handles the work of connecting to the database, so you don't have to understand JDBC to + work with a database.

    +

    + The methods that you add to a JDBC Control execute SQL commands against the database. You can send any + SQL command to the database via the JDBC Control, so that you can retrieve data, perform operations like + inserts and updates, and even make structural changes to the database.

    +

    + All JDBC controls are subclassed from the JdbcControl interface. The interface defines methods that JDBC + control instances can call from an application. See the Tutorial for more detailed information + about using the JdbcControl.

    +
    +
    +
    + Tutorial +
    + JDBC Control Tutorial +

    + The code fragements used in the mini-tutorial are from the jdbcControlSample - the full source + can be found in the samples directory of the JdbcControl's source tree.

    +
    + +
    + Extending the JDBC-Control Interface +

    + The JdbcControl is an extensible control. Before a JdbcControl can be used in an application, + a subinterface of the org.apache.beehive.controls.system.jdbc.JdbcControl interface must be created.

    + +/** + * JdbcControl implementation for the JdbcControl sample app. + */ +@org.apache.beehive.controls.api.bean.ControlExtension +@JdbcControl.ConnectionDataSource(jndiName="java:comp/env/jdbc/JdbcControlSampleDB") +public interface SimpleDBControl extends JdbcControl { + . + . + . +} + + +

    + In the sample above several Java 1.5 annotations are used. The @ControlExtension annotation is required and + tells the Beehive control framework that this control extends an extensible control (in this case the JdbcControl). +

    +
    + +
    + Connecting to a Database Instance +

    The next step is to tell the JdbcControl how to connect to a database instance. + This is done using class level Java annotations, there are two annotations which can be used:

    +
      +
    • JdbcControl.ConnectionDriver
    • +
    • JdbcControl.ConnectionDataSource
    • +
    + +

    (i) See the JDBC Control Annotation Reference for additional information about these annotations.

    +
    + +
    + Making JDBC Calls to a Database Instance + +

    Now that the control knows how to connect to the database instance, the next step is to create + methods in the control which access the database. Let's assume we want to access a table + in the database which looks like:

    + + +CREATE TABLE products (name VARCHAR(64), description VARCHAR(128), quantity INT) + + +

    Here's what the control might look like:

    + + +/** + * JdbcControl implementation for the JdbcControl sample app. + */ +@org.apache.beehive.controls.api.bean.ControlExtension +@JdbcControl.ConnectionDataSource(jndiName="java:comp/env/jdbc/JdbcControlSampleDB") +public interface SimpleDBControl + extends JdbcControl { + + static final long serialVersionUID = 1L; + + public static class Product { + + private String _name; + private String _description; + private int _quantity; + + public int getQuantity() { return _quantity; } + public void setQuantity(int i) { _quantity = i; } + + public String getName() { return _name; } + public void setName(String n) { _name = n; } + + public String getDescription() { return _description; } + public void setDescription(String n) { _description = n; } + } + + /** + * Get the name column from the products table. + * @return An array of strings. + */ + @JdbcControl.SQL(statement="SELECT name FROM products") + public String[] getProductNames() throws SQLException; + + /** + * Get the rest of the columns associated with a product name. + * @param productName Name of product to lookup. + * @return An instance of Product. + */ + @JdbcControl.SQL(statement="SELECT * FROM products WHERE name={productName}") + public Product getProductDetails(String productName) throws SQLException; +} + +

    The SimpleJdbcControl can be accessed from an application as follows:

    + +public class Foo { + + // the @Control annotation causes the control to be intialized when this class is loaded. + @Control + public SimpleDBControl jdbcCtrl; + + public void doFoo() { + String[] productNames = jdbcCtrl.getProductNames(); + Product productInfo = jdbcCtrl.getProductDetails(productNames[3]); + } +} + +

    Note the use of the @SQL method annotation in SimpleDBControl.java, see the JdbcControl Annotation Reference for + additional information about the SQL annotation.

    +
    +
    + SQL Parameter Substitution + +

    It is also possible to substitute method parameter values into the statement member of the @SQL annotation:

    + +// +// simple query with param substitution +// +@SQL(statement="SELECT * FROM USERS WHERE userid={someUserId}") +public ResultSet getSomeUser(int someUserId) throws SQLException; + +// +// query with sql substitution +// +@SQL(statement="SELECT * FROM USERS WHERE {sql: where}") +public ResultSet getJustOneUser(String where) throws SQLException; + +

    For the first method, the value of the parameter 'someUserId' gets substituted into the SQL statement at + runtime when the getSomeUser() method is invoked. For the second method, the substitution gets added to the + SQL statement as the literal value of the 'where' parameter.

    +
    +
    + +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/system-controls/jms/annotations.xml b/docs/forrest/release/src/documentation/content/xdocs/system-controls/jms/annotations.xml new file mode 100644 index 0000000..1b1ed4e --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/system-controls/jms/annotations.xml @@ -0,0 +1,24 @@ + + + +
    + JMS Control Annotations +
    + +

    @JMSControl.CorrelationId

    +

    @JMSControl.Delivery

    +

    @JMSControl.Destination

    +

    @JMSControl.Expiration

    +

    @JMSControl.Message

    +

    @JMSControl.Priority

    +

    @JMSControl.Properties

    +

    @JMSControl.Property

    +

    @JMSControl.PropertyValue

    +

    @JMSControl.Type

    + +
    + Java, J2EE, and JCP are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.
    + © 2005, Apache Software Foundation +
    +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/system-controls/jms/guide.xml b/docs/forrest/release/src/documentation/content/xdocs/system-controls/jms/guide.xml new file mode 100644 index 0000000..b3cae1e --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/system-controls/jms/guide.xml @@ -0,0 +1,568 @@ + + + +
    + The JMS Control Developer's Guide +
    + +
    + Overview: Messaging Systems and JMS +

    A JMS control makes it easy for your application to communicate with messaging systems. To better + understand how to use a JMS control, it helps to understand messaging systems and how JMS control + interact with them.

    + +
    + Understanding Messaging Systems + +

    Messaging systems provide communication between software components. A client of a messaging + system can send messages to, and receive messages from, any other client. Each client connects + to a messaging server that provides facilities for sending and receiving messages. + Codehaus's ActiveMQ which is a component of the Apache Geronimo project, is an example of a + messaging server.

    + +

    Messaging systems provide distributed communication that is asynchronous. This means that a + component sends a message to a destination and a message recipient can retrieve messages from a + destination, but the sender and receiver do not communicate directly. The sender only knows that a + destination exists to which it can send messages, and the receiver also knows there is a destination + from which it can receive messages. As long as they agree what message format and what destination + to use, the messaging system manages the actual message delivery.

    + +

    Messaging systems also provide reliability for message delivery. The specific level of reliability + is typically configurable on a per-destination or per-client basis, but messaging systems are + capable of guaranteeing that a message will be delivered, and that it will be delivered to each + intended recipient exactly once.

    + +

    JMS supports two basic styles of message-based communications: point-to-point and + publish-and-subscribe. Each is described in greater detail below.

    +
    + +
    + Using JMS Queues for Point-to-Point Messaging + +

    Point-to-point messaging is accomplished with JMS queues, which are specific named resources + configured in a JMS server. A JMS client, of which the JMS control is an example, sends + messages to a queue or receives messages from a queue.

    + +

    Point-to-point messages have a single consumer. Multiple receivers can listen for messages + on the same queue, but once any receiver retrieves a particular message from the queue that + message is consumed and is no longer available to other potential consumers.

    + +

    The messaging system continues to resend a particular message until a predetermined number of + retries have been attempted. Once the message is received, a message consumer acknowledges receipt.

    +
    + +
    + Using JMS Topics for Publish-and-Subscribe Messaging + +

    Publish-and-subscribe messaging is accomplished with JMS topics. A topic is a specific named + resource configured in a JMS server.

    + +

    A JMS client, of which the JMS control is an example, publishes messages to a topic, or subscribes + to a topic. Published messages have multiple potential subscribers. All current subscribers to a + topic receive all messages published to that topic after the subscription becomes active.

    +
    +
    + Connection Factories and Transactions + +

    Before a JMS client can send or receive messages to a queue or topic, it must obtain a connection + to the messaging system, via a connection factory. A connection factory is a resource that is + configured by the message server administrator. The names of connection factories are stored in + a JNDI directory, where clients wishing to make a connection can look them up.

    + +

    Unless otherwise specified the default initial context is used. This may be overridden by settng + the jndiContextFactory and jndiProviderUrl properties, either programically + using the setJndiContextFactory() and setJndiProviderUrl() setters or via the + corresponding @Destination attributes.

    + +
    +
    + +
    + JMS Control Annotations +
    + JMS Control Class-level Annotations + +

    The JMSControl.Destination annotation defines the destination + of the message, the message type and connection related attributes. + The attributes defined for this annotation are:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AttributeValueRequiredDescription
    sendJndiNameStringYesJNDI name of the queue or topic.
    sendCorrelationPropertyStringNoThe correlation property to be used for message sent. Default is empty, + which signifies that the JMS correlation header is to be used.
    connectionFactoryJndiNameStringYesJNDI name of the connection factory. Required
    transactedbooleanNoTrue if en-queuing is under transactional semantics of the enclosing container. + Default is true.
    acknowledgeModeenum AcknowledgeModeNoThe acknowledgement strategy, one of Auto, Client, DupsOk. Default is Auto.
    sendTypeJMSControl.DestinationTypeNoValues are Auto, Queue and Topic. If Auto, then the type is determined + by the destination named by the sendJndiName attribute. Default is Auto.
    jndiContextFactoryStringNoThe class name of the jndi-context-factory. Default is none.
    jndiProviderURLStringNoThe provider URL for JNDI. Default is none.
    +
    + +
    + JMS Control Method Annotations + +

    Methods added to a JMS control that send messages may be annotated with the following + annotations:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AnnotationValueDescription
    JMSControl.MessageJMSControl.MessageType (enum)Enum values are: Auto, Text, Bytes, Object, Map and JMSMessage
    JMSControl.PriorityintA JMS priority (0-9). Defaults to provider's default priority.
    JMSControl.ExpirationlongA JMS expiration in milliseconds. Default's to provider's default expiration.
    JMSControl.DeliveryJMSControl.DeliveryMode (enum) This attribute determines the delivery mode of the message. + Defaults to the JMS provider's default delivery mode. Enum values are: + NonPersistent, Persistent and Auto
    JMSControl.TypeStringSpecifies the JMS type.
    JMSControl.CorrelationIdStringSpecifies the JMS correlation id.
    JMSControl.PropertiesJMSControl.PropertyValue[]One or more string/int/long valued properties to be added to the message. + PropertyValue has the string valued attributes 'name', 'value' + and class valued 'type'. The allowed values for 'type' are String.class, + Integer.class and Long.class. If type is not specified, then String + is assumed.
    + + +

    Notes for the JWSControl.MessageType enumerated value:

    + +
      +
    • If not specified or no message-type string, then the default is Auto.
    • +
    • If Auto, then the type of JMS message is determined by the type of the body passed in; rules for determining these types are: +
        +
      • If the body is a String or XmlObject, a TextMessage is sent.
      • +
      • If the body is a byte[], a StreamMessage is sent.
      • +
      • If the body is a Map, a MapMessage is sent
      • +
      • If the body is a JMSMessage, a JMSMessage is sent
      • +
      • Otherwise if the body is Serializable, an ObjectMessage is sent.
      • +
      • Any other type results in a control exception.
      • +
      +
    • +
    +
    + + +
    + JMS Control Method Parameter Annotations + +

    These annotations denote which parameter is to be the body of the message and zero or more + properties to be set in the message respectively. The following annotations my be + used on method parameters:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AnnotationValueDescription
    JMSControl.PropertyStringThe parameter contains the value of the property.
    JMSControl.PriorityintA JMS priority (0-9). If not specifed the method-level annotation is used; + if method-level annotation has not been specified the default for the + JMS provider is used.
    JMSControl.ExpirationlongJMS expiration in milliseconds. If not specified the method-level annotation is used; + if method-level annotation has not been specified the default for the provider + is used.
    JMSControl.DeliveryJMSControl.DeliveryMode The DeliveryMode valued parameter determines the delivery mode of the message. + If not specified, then the method-level annotation is used; else the default for + the provider is used.
    JMSControl.TypeStringThe JMS type.
    JMSControl.CorrelationIdStringThe JMS correlation id.
    +
    +
    + + +
    + JMS Control Methods + +

    A JMS control always includes the following methods:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    MethodDescription
    getSession()Get the queue/topic session.
    getDestination()Get the queue/topic destination.
    getConnection()Get the queue/topic connection.
    setHeaders(Map) Sets the JMS headers to be assigned to the next JMS message sent. Note that + these headers are set only on the next message, subsequent messages will + not get these headers. Also note that if the body is a message itself, + then any header set through this map will override headers set in the message. + + + The keys should be of type HeaderType or equivalent strings. + See table below for valid values.
    setHeader(HeaderType,Object)Sets a JMS header to be assigned to the next JMS message sent. Note that + this header is set only on the next message, subsequent messages will + not get this header. Also note that if the body is a message itself, + then the header set here will override the header set in the message.
    setProperties(Map)Sets the JMS properties to be assigned to the next JMS message sent. Note that + these properties are set only on the next message, subsequent messages will + not get these properties. Also note that if the next message is sent through + a publish method, then any property set through this map will override + properties set in the message itself. +
    setProperty(String,Object)Set the given JMS property to be assigned to the next JMS message sent. Note that + this property is set only on the next message, subsequent messages will not get this + property. Also note that if the body is a message itself, then the property set here + will override the property set in the message. +
    + +

    The methods of the extension control-classes correspond to sending a message to a topic/queue, e.g.

    + send<message-type>(...) +
    + +
    + Header Types + +

    The table below defines the valid values for header types passed into setHeader() or setHeaders():

    + + + + + + + + + + + + + + + + + + + + + + +
    JMS Message MethodHeaderType/StringAllowed Value Types
    setJMSType()JMSTypeString
    setJMSCorrelationID()JMSCorrelationIDString or byte[]
    setJMSExpiration()JMSExpirationString valued long or Long
    setJMSPriority()PriorityString valued int or Integer
    +
    + +
    + Creating a JMS Control + +

    The JMS control is an extensible control. Before a JMS Control can be used in an application, + a sub-interface of the org.apache.beehive.controls.system.jms.JmsControl interface + must be created and annotated with @ControlExtension.

    + + +@ControlExtension +public interface SampleQueue + extends JMSControl { +... +} + + + +

    A JMS control needs to know the destination of the messages it will send. This is accomplished + using a JNDI context. Unless otherwise specified the default initial context is used. This may + be overridden by settng the @Destination annotation's jndiContextFactory + and the jndiProviderUrl attributes.

    + +

    The queue/topic destination is then obtained using the value of the sendJndiName attribute of + the @Destination annotation. A queue/topic connection is obtained using by + the jndiConnectionFactory attribute. In most cases the same connection factory is + used for both queues and topics.

    + +

    The @Destination.sendType attribute may be used to + constrain the use of the control to either a topic or a queue. By default its value is + Auto which allows for run-time determination of whether the sendJndiName + names a queue or a topic. By setting it to Queue or Topic a run-time check is made to see if + the connection factory and destination is of the correct type.

    + +

    The extension interface can include one or more methods that send messages. These + methods must have at least one parameter that corresponds to the body of + the message. Other annotated parameters can defined to provide property values and + other information at run-time to the message. The method itself can be annotated as well.

    + +

    In the example below, the OrderQueue control class has one submitOrder() method that takes an + Order object as the body and a string that sets the 'DeliverBy' property in the + javax.jms.ObjectMessage to be sent to the queue.orders JMS queue.

    + + +@ControlExtension +@JMSControl.Destination(sendJndiName="queue.orders",jndiConnectionFactory="weblogic.jws.jms.QueueConnectionFactory") +public interface OrderQueue extends JMSControl + { + public class Order implements java.io.Serializable + { + public Order() + { + + } + public Order(int buyer,String[] list) + { + buyerId = buyer; + itemList = list; + + } + private int buyerId; + private String[] itemList; + } + + public void submitOrder(Order order,@Property(name="DeliverBy") String deliverBy); +} + +
    +
    + Specifying the Message Body + +

    This section describes some of the ways in which you can specify the body of a message + sent via the JMS control.

    + +
    + Selecting the Message Type + +

    A JMS control can send text messages (including XML messages), byte array messages, + object messages, and javax.jms.Message (JMS Message) objects. These are the types defined by + the JMS messaging service specification.

    + +

    When you create a JMS control, you can specify which type of message it sends and receives + with the JMSControl.Message.messageType() annotation.

    + +

    You have complete control over the send methods, as long as you are sending a message of a + supported type; you can modify method signatures as you need to, including + adding additional parameters to handle message headers and properties. However, you can + only specify one parameter in the method for the message body.

    + +
    +
    + Sending and Receiving a Simple Text Message + +

    The simplest message body is a text message. The following example shows a simple text + message sent to the messaging service via a JMS control:

    + +public void sendString(String msg) throws Exception + { + myJMSControl.sendTextMessage(msg); + } + + + +
    +
    + Sending and Receiving an XML Message using XMLBeans + +

    If you need to send a set of values in the message body, you can construct the message + body using an XMLBeans object type. Apache XMLBeans technology generates a set of Java + classes from an XML schema (.xsd) file. You can then use these classes to work with + XML documents in your code.

    + +

    If you don't already have a schema file, you can construct one by hand, or you can generate + one from an XML document or fragment using a third-party authoring tool. Once you've + generated the XMLBeans classes from the schema file, you can import those classes into + your JMS control class. You can then modify the send method or receiving callback on + the JMS control to send or receive a message of the appropriate type.

    + +

    Note that XMLBeans messages are transmitted as JMS text messages. When you create a JMS + control that will use an XMLBeans type for the message body, specify the type as + with the JMSControl.Message.messageType() annotation as 'Text'.

    + +

    The following is a simple JWS Control which sends an XML message:

    + +import java.util.Date; + +import org.apache.beehive.controls.api.bean.ControlExtension; +import org.apache.beehive.controls.system.jms.JMSControl; +import org.apache.xmlbeans.XmlObject; + +@ControlExtension +@JMSControl.Destination(sendJndiName="jms.SampleQueue",jndiConnectionFactory="weblogic.jws.jms.QueueConnectionFactory") +public interface SampleQueue extends JMSControl +{ + /** + * Submit an xml object (org.apache.xmlbeans) as a text message. + * @param document the document. + * @param type the message JMS type. + */ + public void submitXml(XmlObject document,@Type String type); + + /** + * Submit an xml object (org.apache.xmlbeans) with JMS type "xmlObject". + * @param document the document. + */ + @Message(MessageType.Text) + @Type("xmlObject") + public void submitXml(XmlObject document); + + /** + * Submit an already constructed message + * @param message the jms-message. + */ + public void submitMessage(Message message); +} + +
    +
    + + +
    + Specifying Message Headers and Properties + +

    The JMS control includes properties for setting and retrieving headers and properties + on a JMS message.

    + +
    + Accessing Message Headers + +

    A JMS message includes a number of header fields that contain information used to + identify and route messages. You can set the message headers for an outgoing + message using the JMS control by using the JMSControl.setHeaders(Map) method + or the JMSControl.setHeader(HeaderType, Object) method. + The supported headers for an outgoing message are:

    +
      +
    • JMSCorrelationID
    • +
    • JMSExpriation
    • +
    • Priority
    • +
    • JMSType
    • +
    + +

    For more information on these headers, see the Sun JMS specification.

    + +
    + +
    + Accessing Message Properties + +

    A JMS message can also include properties that you or the message sender can add to + send additional information about the message. You can think of them as optional, + custom headers. Properties can be of type boolean, byte, short, int, long, float, + double, or string. They can be set when a message is sent. You can add as many properties + to the message as you need to.

    + +

    You can set the properties of messages sent using the JMS control by using the + JMSControl.setProperties(Map) or the + JMSControl.setProperty(String, Object) methods.

    + +

    When the JMS control is sending a message, the JMS control adds the properties + specified to the outgoing message. You can optionally specify that a parameter + passed to the method that sends the message should be substituted as a property + value on the message.

    +
    + +
    + +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/system-controls/jms/tutorial.xml b/docs/forrest/release/src/documentation/content/xdocs/system-controls/jms/tutorial.xml new file mode 100644 index 0000000..7bf7321 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/system-controls/jms/tutorial.xml @@ -0,0 +1,103 @@ + + + +
    + JMS Control Tutorial +
    + +

    The Jmscontrol is an extensible control. Before a JmsControl can be used in an application, + a sub-interface of the org.apache.beehive.controls.system.jms.JmsControl interface must be created and + annotated with @ControlExtension.

    + + +@ControlExtension +public interface SampleQueue + extends JMSControl { +... +} + + +

    In order for the control to work, it needs to know the destination of the messages. This is + accomplished using a JNDI context. Unless otherwise specified the default initial + context is used. This may be overridden by settng the jndiContextFactory and + jndiProviderUrl properties, either programically using the setJndiContextFactory() and + setJndiProviderUrl() setters or via the corresponding @Destination attributes.

    + +

    The queue/topic destination is then obtained using the value of the sendJndiName property + and a queue/topic connection is obtained using by the jndiConnectionFactory property. + In most cases the same connection factory is used for both queues and topics. The + @Destination sendType attribute may be used to constrain the use of the control to + either a topic or a queue. By default it's value is Auto which allowes for run-time + determination of whether the sendJndiName names a queue or a topic. By setting it to + Queue or Topic a run-time check is made to see if the connection factory and destination + is of the correct type.

    + +

    If the JNDI context to be used (i.e. the control is running in an ejb-container (or + servlet-container with a JNDI context) is known (or is the default context) and the + connection-factory (e.g. weblogic.jms.ConnectionFactory) and queue JNDI name + (e.g. jms.SampleQueue) is also known at development time then the extension class can + be annotated with the @Destination annotation as shown in the example:

    + + +@ControlExtension +@JMSControl.Destination(sendType=JMSControl.DestinationType.Queue,sendJndiName="jms.SampleQueue",jndiConnectionFactory="weblogic.jms.ConnectionFactory") +public interface SampleQueue + extends JMSControl { +... +} + +

    Likewise, for a topic (e.g. jms.SampleTopic) the following file might be appropriate:

    + +@ControlExtension +@JMSControl.Destination(sendType=JMSControl.DestinationType.Topic,sendJndiName="jms.SampleTopic",jndiConnectionFactory="weblogic.jms.ConnectionFactory") +public interface SampleTopic + extends JMSControl { +... +} + +

    The sendType attribute could be left out of these examples and the control extensions would still work.

    +

    See Extension Class Annotation for other annotations defined at the class or type level.

    +

    The extension interface can include one or more methods that send messages. These methods must have + at least one unannotated parameter that corresponds to the body of the message. Other annotated + parameters can defined to provide property values and other information at run-time to the + message (see Extension Class Annotation for allowed annotation). The method itself can be + annotated (see Extension Class Annotation for allowed annotation).

    +

    Some examples appropriate to topics and queues include:

    + +/** + * Submit an xml object (org.apache.xmlbeans) as a text message. + * @param document the document. + * @param type the message JMS type. +*/ +public void submitXml(XmlObject document, @Type String type); + +/** + * Submit an xml object (org.apache.xmlbeans) with JMS type "xmlObject". + * @param document the document. + */ +@Message(MessageType.Text) +@Type("xmlObject") +public void submitXml(XmlObject document); + +/** + * Submit an already constructed message + * @param message the jms-message. +*/ +public void submitMessage(Message message); + +/** + * Submit a BytesMessage with the given byte array body and property hello. + * @param body the byte array. + * @param hello the value of the hello property. +*/ +public void submitMessage(byte[] body, @Property(name=hello) hello); + +/** + * Submit a MapMessage with the given map and property hello set to world. + * @param body the byte array. +*/ +@Properties({PropertyValue(name="hello", value="world")}) +public void submitMessage(Map body); + + +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/system-controls/wsc/annotations.xml b/docs/forrest/release/src/documentation/content/xdocs/system-controls/wsc/annotations.xml new file mode 100644 index 0000000..79757c1 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/system-controls/wsc/annotations.xml @@ -0,0 +1,17 @@ + + + +
    + Web Service Control Annotations +
    + +

    @ServiceControl.OperationName

    +

    @ServiceControl.ServiceFactoryProvider

    +

    @ServiceControl.WSDL

    + +
    + Java, J2EE, and JCP are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.
    + © 2006, Apache Software Foundation +
    +
    +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/system-controls/wsc/guide.xml b/docs/forrest/release/src/documentation/content/xdocs/system-controls/wsc/guide.xml new file mode 100644 index 0000000..7016a3f --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/system-controls/wsc/guide.xml @@ -0,0 +1,426 @@ + + + +
    + Web Service Control Developer's Guide +
    + +
    + Overview +

    If you have ever created a JAX-RPC client without the aid of development tools you will + really appreciate the web service control. A web service control (WSC) is generated + from a WSDL file using the WebServiceControlGeneratorTask Apache Ant task. The WSC + contains public methods for each operation defined by the WSDL. Just invoke a WSC + method to invoke the web service operation.

    +
    +
    + Supported Web Services +

    Just about any web service should work with the WSC including (but not limited to):

    +
      +
    • Apache Axis
    • +
    • .NET
    • +
    • NuSOAP
    • +
    • Visual Dataflex
    • +
    • Cold Fusion
    • +
    • Delphi
    • +
    • SOAPLite
    • +
    +
    +
    + External Dependencies +

    The underlying JAX-RPC client of a WSC is currently Axis 1.2.x, an Apache Axis distribution needs + to be available to generate and run a WSC.

    +
    +
    + Runtime Dependencies +

    The current version of the WSC requires that the WSDL file that was used to generate it be accessible at + runtime + (in the runtime classpath). This requirement will be reviewed for future releases.

    +
    +
    + Adding a WSC to Your Project +

    The basic steps necessary to add a WSC to your project are:

    +
      +
    1. Modify your build script to generate Java classes from the WSDL's types (XMLBeans, POJOs, Axis, + etc.).
    2. +
    3. Use the + generate-wsc + Ant macro to generate and build the WSC. +
    4. +
    +

    The generate-wsc documentation can be found + here + . Refer to the + WSC Tutorial + for additional information about adding a WSC to your project. +

    +
    +
    + WSDL type -> Java Class Generation +

    WSDL type generation must occur before a WSC can be generated from the WSDL file. + The included + AxisTypeGenerator + Ant task can be used to generate Java types from the WSDL. + Any other tool may be used for type generation including Apache XMLBeans. The only requirement + is that the generated class files are in the classpath when the WSC is generated and run. +

    +
    +
    + WSC Generation +

    A web service control is generated from a WSDL. There are several ways to generate a WSC from an Ant + build file including the + generate-wsc + Ant macro and also the + WebServiceControlGeneratorTask + Ant task. For any given WSDL + a WSC is generated based on a service and port defined in that WSDL. If a WSDL defines multiple services + or ports the first + one found during generation will be used -- in this case it is usually a good idea to specify the + particular service name and port + name to the generator. +

    +

    When generating a WSC there are several options for specifing where the WSDL is. The WSDL can be + specified by a URL, it can + be a local file, or a directory of WSDL's may be specfied. For the latter a WSC is generated for each + WSDL in the specified + directory. +

    + +

    A WSC must be able to locate the WSDL file used to generate it at runtime. The + wsdlRuntimePath + attribute may be optionally + used to specify that location. If not set the WSC generator will compute this value. +

    + +
    +
    + WSC API +

    In addition to the generated public interface all web service controls share a common API, + the API methods include:

    +
      +
    • + public URL getEndpoint() + - returns the current service endpoint. +
    • +
    • + public void setEndpoint() + - sets the service endpoint. +
    • +
    • + public String getPassword() + - get the last password for the service set by the setPassword() API. +
    • +
    • + public void setPassword(String) + - set the password for the service. +
    • +
    • + public String getUsername() + - get the last username for the service set by the setUsername() API. +
    • +
    • + public void setUsername(String) + - set the username for the service. +
    • +
    • + public void setHandlers(List<HandlerInfo>) + - set JAX-RPC handlers. +
    • +
    +

    For additional information about these APIs see the JavaDoc for the + org.apache.beehive.controls.system.webservice.ServiceControl + interface. +

    +
    +
    + Modifing a WSC +

    Once a WSC has been generated, if necessary it can be modified, however; none of the generated methods + which correspond to WSDL operations should be modified or unexpected behavior might ensue.

    +
    +
    + JAX-RPC Handler Support +

    For a more detailed discussion of what JAX-RPC handlers are and how they are used please + see the JAX-RPC specification.

    +

    To add a handler to a WSC, create the JAX-RPC handler, configure a + javax.xml.rpc.HandlerInfo + instance for the handler and register it with the WSC via the WSC public API + setHandlers(List<HandlerInfo>) + . +

    +

    The remove or reconfigure existing handlers use the setHandlers api with an empty List + to remove all handlers, or a modified list to modify handlers already registered with the WSC.

    +
    +
    + Extending the WSC to Use Other JAX-RPC Clients +

    The current WSC implementation is based on the Apache Axis JAX-RPC client. + With a bit of work it can be extended to use any other JAX-RPC client. There are + several classes which need to be implemented, with a degree of complexity that will + depend almost entirely on the JAX-RPC client implementation.

    + +

    All Axis specific classes can be found in:

    +

    <beehive_src_home>/system-controls/src/webservice/jaxrpc-clients/axis

    + +

    These include a AxisCall implemenation of the Beehive JAX-RPC Call abstraction and an + AxisTypeRegistrar implementation of JAX-RPC type support. Both of these classes + will need to be re-implemented for a new JAX-RPC client.

    + +

    In addition the ServiceControl interface's ServiceFactoryProviderType enum should + be updated to include a new enum type for the new client.

    +
    +
    + WSC Ant Tasks +
    + WebServiceControlGeneratorTask +

    + Description +

    +

    This Ant task generates a web service control (WSC) from a WSDL. WSDL types are + translated/transformed into concrete Java types, which are expected to be in this + task's classpath. This task can process all WSDL files in a specified directory or + single WSDL (either file or URL).

    +

    The class name of the generated WSC will be the name of the service defined by the + WSDL used for WSC generation (the service name is Javatized as necessary to + be a legal Java class name).

    + + +

    + Parameters +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AttributeDescriptionRequired
    destDirLocation to write the generated WSC.Yes
    wsdlSrcFile, directory or URL containing the WSDL file(s) to generate WSC(s) from.Yes
    copyWsdlIf set to true WSDL file is copied to the same location as the generated WSC. Default value + is false.No
    destPackageNameThe Java(tm) package name of the generated control. Defaults to no package.No
    serviceNameThe name of the service in the WSDL which should be used to generate the WSC. + If not specified and multiple services are present the first service found in the WSDL + will be used for WSC generation.No
    serviceNamespaceThe namespace of the serviceName attribute.No
    servicePortThe port name of the service to be used for WSC generation. If + not specified and multiple ports are present, the first port found will be + used for WSC generation.No
    wsdlRuntimePathThe runtime location of the WSDL file. If not specified will be generated + automagically.No
    + +

    + Parameters specified as nested elements +

    +

    None.

    + +

    + Examples +

    + + <taskdef name="wsc-gen" + classname="org.apache.beehive.controls.system.webservice.generate.WebServiceControlGenerationTask" + classpathref="wscgen.dependency.path"/> + <wsc-gen + wsdlSrc="http://myservice.net/service?wsdl" + destDir="src" + copyWsdl="true" + servicePort="RPCClient" + destPackageName="wscpkg"/> + +

    Will generate a WSC from the WSDL file at http://myservice.net/service?wsdl with a package + name of 'wscpkg' and will copy the WSDL file into the same directory as the generated WSC.

    +
    +
    + AxisTypeGeneratorTask +

    This Ant task processes a WSDL and generates Java types from the WSDL's complex types. + As currently implemented this task is an extension to the + org.apache.axis.wsdl.toJava.JavaGeneratorFactory + which only generates the + Java types (does not generate Axis skeletons/stubs/etc). +

    +

    + Parameters +

    + + + + + + + + + + + + + + + + +
    AttributeDescriptionRequired
    outputDirLocation to write the generated Java types source files.Yes
    wsdlDirDirectory containing WSDLs to generate Java types from.Yes
    +

    + Parameters specified as nested elements +

    +

    None.

    +

    + Examples +

    + + <taskdef name="axis-type-gen" + classname="org.apache.beehive.controls.system.jaxrpc.AxisTypeGeneratorTask" + classpathref="client.classpath"/> + + <axis-type-gen wsdldir="/tmp/wsdls" outputdir="/tmp/wsdl-types-src"/> + + +

    Will generate Java types from the WSDL file(s) in '/tmp/wsdls' into the specified output + directory.

    +
    +
    +
    + WSC Ant Macros +
    + generate-wsc +

    This Ant macro generates and optionally compiles a WSC. It uses the WebServiceControlGeneratorTask + and the necessary build + commands to compile the generated control. The compilation step is disabled by setting the + nocompile + attribute + to true. +

    +

    + Parameters +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AttributeDescriptionRequired
    wsdlsrcLocation of the WSDL. May be either a file, directory or URL.Yes
    wscgendirLocation to generate the WSC. If a package name has been specified the package directories + will be placed directly under + this directory.Yes
    tempdirThe temporary directory for generated Java source files.Yes
    destdirThe directory for Java class files.Yes
    copywsdlCopy WSDL file used to generate WSC to WSC generation location.No, defaults to false.
    packagenameName of Java package for generated WSC.No
    nocompileFlag to decide whether to skip compilation.No, defaults to false.
    servicenameIf WSDL contains multiple services, use to specify service name for WSC generation.No
    servicenamespaceIf WSDL contains multiple services, use to specify namespace of service.No
    serviceportIf service contains multiple ports, use to specify port name.No
    serviceportIf service contains multiple ports, use to specify port name.No
    wsdlruntimepathLocation of WSDL at runtime.No, auto generated if not specified.
    classpathrefThe classpath reference for building the controls.Yes
    + +

    + Parameters specified as nested elements +

    +

    None.

    + +

    + Examples +

    + + <generate-wsc wsdlsrc="http://localhost:8080/myservice?wsdl" wscgendir="build/src" + tempdir="build/gensrc" destdir="build/classes" + packagename="wsc.axis.sample" copywsdl="true" + classpathref="build.classpath"/> + + +

    Generates a service control from the WSDL at http://localhost:8080/myservice?wsdl. A Copy of WSDL + file + is stored in the same location as the compiled WSC. The + WSC Tutorial + contains + a detailed example of the use of this macro. +

    +
    +
    + +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/system-controls/wsc/tutorial.xml b/docs/forrest/release/src/documentation/content/xdocs/system-controls/wsc/tutorial.xml new file mode 100644 index 0000000..bbe9cfa --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/system-controls/wsc/tutorial.xml @@ -0,0 +1,336 @@ + + + +
    + Web Service System Control Tutorial +
    + +
    + Overview +

    The Web Service Control tutorial demonstrates how to generate, build and test a web service control. Key + topics covered include:

    +
      +
    • Adding a WSC to a project.
    • +
    • Generating Java classes from WSDL types.
    • +
    • Generating and building a WSC.
    • +
    • Using JUnit to test a WSC.
    • +
    +

    This tutorial starts with the 'controls-blank' project template which can be found in the samples + directory of + the Beehive distribution. The code fragements used in the mini-tutorial are from the interop-client + sample. The + full source can be found in the system control samples directory. +

    +

    For additional information about the web service control see the + Web Service Control Developer's Guide + . +

    +
    +
    + Tutorial +
    + Step 1: Install Tutorial Dependencies +
    + Install Beehive +

    + Complete all of the required and optional steps to install and setup Beehive + here + . +

    +
    +
    + Install Apache Axis +

    + Apache Axis 1.3 or later is required at build and runtime by the WSC. + Apache Axis can be downloaded + here + . Once downloaded + install the Axis distribution to a local directory. +

    +
    +
    + Install JUnit +

    + In this tutorial, JUnit is the test framework used. In order to use JUnit, download a JUnit + release + here + and unzip it into a local + directory. +

    +
    +
    + Create a Control Project +

    + Copy the directory + <BeehiveRoot>/samples/controls-blank + to a location of your choice. For example, you might copy + to the following location: + /beehive-projects/controls-blank + . +

    +

    + Rename + controls-blank + to + wsc_tutorial + . +

    +

    + Edit the file + wsc_tutorial/build.properties + so that the property + beehive.home + points + to the top level folder of your Beehive distribution. +

    +

    + Add the property + junit.home + to the file and ensure that it points to your JUnit installation. +

    +

    + Add the property + axis.home + to the file and ensure that it points to your Axis installation. +

    +

    + For example, if Beehive distribution is located in + /apache/apache-beehive-1.0.2 + and JUnit is located in + /test-tools/junit + , then your + build.properties + file + would appear as follows: +

    + + beehive.home= + /apache/apache-beehive-1.0.2 + + junit.home= + /test-tools/junit + + axis.home= + /apps/axis + + + Properties files should use the '/' character to separate drive, directory, and file names. + +
    +
    + +
    + Step 2: Web Service Used in This Tutorial +

    This tutorial uses a web service designed to test SOAP Interoperability, it is a .NET service. The + web service's WSDL can be found at: + + http://mssoapinterop.org/asmx/xsd/round4XSD.wsdl + . Notice that there are + several complex types defined by the WSDL. In order to generate a WSC from this WSDL it will be + necessary to + first generate Java classes from those types. +

    +

    + For this particular WSDL type generation is not required. If the types are not present during + generation the WSC's interface will declare method parameters and return types which correspond + to these + complex types as + java.lang.Object + . + +

    +
    + +
    + Step 3: WSDL Type Generation +

    Java classes can be generated from WSDL types using any of the following methods:

    +
      +
    • POJOs
    • +
    • Apache XMLBeans
    • +
    • Axis type generation
    • +
    • Any other method which can generate Java classes from WSDL complex types
    • +
    + +

    In this tutorial the + AxisTypeGeneratorTask + Ant task will be used to generate the Java classes from the WSDL types. This Ant task is included + as part of the WSC distribution jar. +

    + +

    Modify the build classpath as follows:

    + + <path id="build.classpath"> + <pathelement path="${build.classes}"/> + <path refid="controls.dependency.path"/> + <path refid="wsc.dependency.path"/>> + </path> + + +

    Insert the following block of code:

    + + <property name="source.dir" location="${build.dir}/src"/> + <property name="junit.source.dir" location="${basedir}/junit"/> + <property name="build.typesrc" location="${build.dir}/typesrc"/> + + <fileset id="axis.jars" dir="${axis.home}"> + <include name="**/*.jar"/> + </fileset> + <fileset id="commons.jars" dir="${beehive.home}/lib/common"> + <include name="**/*.jar"/> + </fileset> + + <target name="gen.wsdl.types" description="Generate and compile java classes from WSDL types."> + + <path id="_typegen.classpath"> + <path refid="build.classpath"/> + <fileset refid="axis.jars"/> + <fileset refid="commons.jars"/> + </path> + + <taskdef name="axisbeanbuild" + classname="org.apache.beehive.controls.system.jaxrpc.AxisTypeGeneratorTask" + classpathref="_typegen.classpath"/> + + <axisbeanbuild wsdlsrc="http://mssoapinterop.org/asmx/xsd/round4XSD.wsdl" + outputdir="${build.beansrc}"/> + <javac srcdir="${build.typesrc}" destdir="${build.classes}" classpathref="_typegen.classpath" + debug="true"/> + </target> + + <target name="init.dirs"> + <mkdir dir="${source.dir}"/> + <mkdir dir="${build.classes}"/> + <mkdir dir="${build.beansrc}"/> + <mkdir dir="${build.typesrc}"/> + <mkdir dir="${build.dir}/junit-logs"/> + </target> + + +

    To test your changes, run 'ant clean init.dirs gen.wsdl.types' from the command line. A number of + Java class files + should be generated and placed in the build/classes directory. These classes will be used during the + generation of the + WSC and also at runtime. +

    +
    +
    + Step 4: WSC Generation +

    Now the WSC can be generated, use the + generate-wsc + Ant macro. Add the following to the build target in the build.xml file: +

    + + <target name="build" + >depends="init.dirs, gen.wsdl.types"> + description="Build control sources"> + + > + <generate-wsc wsdlsrc="http://mssoapinterop.org/asmx/xsd/round4XSD.wsdl" + wscgendir="${source.dir}" + tempdir="${build.beansrc}" destdir="${build.classes}" + packagename="mssoapinterop" copywsdl="true" + serviceport="Round4XSDTestSoap" classpathref="build.classpath"/> + > + <build-controls srcdir=" + {junit.source.dir}> + " + destdir="${build.classes}" + tempdir="${build.beansrc}" + classpathref="build.classpath"/> + + <control-jar destfile="${build.dir}/${build.jar}" basedir="${build.classes}" /> + </target> + +

    For this particular WSDL the + generate-wsc + macro needs to set the serviceport value since the WSDL defines multiple service ports. Also note + that since + the copywsdl attribute has been set to true that a copy of the WSDL file is placed in the same + location as the generated web service control. To try out your changes + run 'ant clean build' from the command line. A WSC will be generated and compiled. The source of the + generated WSC can be found in the build/src directory. The WSC + will contain a method for each operation defined by the WSDL. +

    +
    +
    + Step 5: Testing the WSC with JUnit +

    First create the JUnit test file in + wsc_tutorial/junit/tests +

    + + package tests; + + import mssoapinterop.Round4XSDTest; + import org.apache.beehive.controls.test.junit.ControlTestCase; + import org.apache.beehive.controls.api.bean.Control; + + /** + * Junit test case for the interop-client web service system control sample. + */ + public class InteropTest extends ControlTestCase { + + @Control + private Round4XSDTest _interopCtrl; + + /** + * Test echoing a string. + */ + public void testEchoString() throws Exception { + assertNotNull(_interopCtrl); + assertEquals("HelloWorld", _interopCtrl.echoString("HelloWorld")); + } + + /** + * Test echoing an Integer. + */ + public void testEchoInteger() throws Exception { + assertNotNull(_interopCtrl); + assertEquals(6, _interopCtrl.echoInteger(6)); + } + } + +

    Note that the InteropTest extends the + org.apache.beehive.controls.test.junit.ControlTestCase + class. This class + provides a standalone control test container for JUnit testing and is included as part of the + standard Beehive distribution. + When using the class control's can be tested in JUnit without having to deploy them to an + application server. +

    + +

    Now add the following target to the build.xml file:

    + + + <target name="junit.test" depends="build" description="Run the JUnit tests for this project."> + + <path id="_test.classpath"> + <path refid="build.classpath"/> + <pathelement location="${junit.home}/junit.jar"/> + <fileset refid="axis.jars"/> + <fileset refid="commons.jars"/> + </path> + + <junit printsummary="yes" showOutput="true" failureproperty="controls.junit.failure" + errorproperty="controls.junit.error"> + <classpath refid="_test.classpath"/> + <formatter type="plain"/> + <batchtest fork="yes" todir="${build.dir}/junit-logs"> + <fileset dir="${build.classes}"> + <include name="**/*Test.class"/> + <exclude name="**/Round4XSDTest.class"/> + </fileset> + </batchtest> + </junit> + + <fail if="controls.junit.failure" message="Controls JUnit tests had a failure"/> + <fail if="controls.junit.error" message="Controls JUnit tests had an error"/> + </target> + + +

    To run the JUnit test run 'ant clean junit.test' from the command line. The complete source for this + tutorial can be found in the interop-client sample in the system-controls/samples/webservice + directory.

    +
    +
    + +
    diff --git a/docs/forrest/release/src/documentation/content/xdocs/tabs.xml b/docs/forrest/release/src/documentation/content/xdocs/tabs.xml new file mode 100644 index 0000000..c946264 --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/tabs.xml @@ -0,0 +1,22 @@ + + + + + + + + + + diff --git a/docs/forrest/release/src/documentation/content/xdocs/tutorial/setup.xml b/docs/forrest/release/src/documentation/content/xdocs/tutorial/setup.xml new file mode 100644 index 0000000..d0cc66c --- /dev/null +++ b/docs/forrest/release/src/documentation/content/xdocs/tutorial/setup.xml @@ -0,0 +1,46 @@ + + + +
    + Beehive Tutorial + Tomcat Setup +
    + +

    + The Beehive tutorials can be run on many different J2EE / Servlet application containers. Often, the tutorials use Tomcat as an + example application container during discussions of deployment and URLs. The following steps are useful for configuring + Tomcat to run the Beehive tutorials. Feel free to switch containers; just be sure to follow your application + container's deployment and URL address instructions +

    +

    + Because the Beehive NetUI requires JSP 2.0 and Servlet 2.4 features, the 5.0 version of Tomcat is the minimum container for running + Beehive-enabled applications. +

    +

    + (1) Install the latest Tomcat 5.x version -- download + http://jakarta.apache.org/site/binindex.cgi#tomcat +

    +

    + (2) Set the CATALINA_HOME environmental variable in your shell +

    +

    + (3) Optional. To easily deploy applications on Tomcat at build time, it is often useful to enable the manager username and role + in the $CATALINA_HOME/conf/tomcat-users.xml file. This allows the manager role to be used in conjunction with Tomcat's + Ant tasks for deploying, undeploying, and redeploying web applications. Note, for security reasons, the manager role should often + be enabled before deploying applications into production on Tomcat. An example tomcat-users-xml file is below; new XML elements + are shown below in bold type. +

    + +<?xml version='1.0' encoding='utf-8'?> +<tomcat-users> + <role rolename="tomcat"/> + <role rolename="role1"/> + <role rolename="manager"/> + <user username="tomcat" password="tomcat" roles="tomcat"/> + <user username="role1" password="tomcat" roles="role1"/> + <user username="both" password="tomcat" roles="tomcat,role1"/> + <user username="manager" password="manager" roles="manager"/> +</tomcat-users> + + +
    diff --git a/docs/forrest/release/src/documentation/resources/images/Logo_25wht.gif b/docs/forrest/release/src/documentation/resources/images/Logo_25wht.gif new file mode 100644 index 0000000..3daffe1 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/Logo_25wht.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/_Logo_25wht.gif b/docs/forrest/release/src/documentation/resources/images/_Logo_25wht.gif new file mode 100644 index 0000000..151f527 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/_Logo_25wht.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/_apache-incubator-logo.png b/docs/forrest/release/src/documentation/resources/images/_apache-incubator-logo.png new file mode 100644 index 0000000..81fb31e Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/_apache-incubator-logo.png differ diff --git a/docs/forrest/release/src/documentation/resources/images/_beehive_logo_wide.gif b/docs/forrest/release/src/documentation/resources/images/_beehive_logo_wide.gif new file mode 100644 index 0000000..3157b83 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/_beehive_logo_wide.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/_incubator-logo.gif b/docs/forrest/release/src/documentation/resources/images/_incubator-logo.gif new file mode 100644 index 0000000..310b426 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/_incubator-logo.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/_maven-button-1.png b/docs/forrest/release/src/documentation/resources/images/_maven-button-1.png new file mode 100644 index 0000000..bccee1a Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/_maven-button-1.png differ diff --git a/docs/forrest/release/src/documentation/resources/images/apache-asf-compressed.png b/docs/forrest/release/src/documentation/resources/images/apache-asf-compressed.png new file mode 100644 index 0000000..5e03ea3 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/apache-asf-compressed.png differ diff --git a/docs/forrest/release/src/documentation/resources/images/apache-incubator-logo.png b/docs/forrest/release/src/documentation/resources/images/apache-incubator-logo.png new file mode 100644 index 0000000..7915dec Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/apache-incubator-logo.png differ diff --git a/docs/forrest/release/src/documentation/resources/images/beehive_logo_wide.gif b/docs/forrest/release/src/documentation/resources/images/beehive_logo_wide.gif new file mode 100644 index 0000000..3bedba9 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/beehive_logo_wide.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/categoryGrid1.gif b/docs/forrest/release/src/documentation/resources/images/categoryGrid1.gif new file mode 100644 index 0000000..0fe19d1 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/categoryGrid1.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/categoryGrid2.gif b/docs/forrest/release/src/documentation/resources/images/categoryGrid2.gif new file mode 100644 index 0000000..1145aaf Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/categoryGrid2.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/categoryGrid3.gif b/docs/forrest/release/src/documentation/resources/images/categoryGrid3.gif new file mode 100644 index 0000000..2d90641 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/categoryGrid3.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/categoryGrid4.gif b/docs/forrest/release/src/documentation/resources/images/categoryGrid4.gif new file mode 100644 index 0000000..4047316 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/categoryGrid4.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/categoryGrid5.gif b/docs/forrest/release/src/documentation/resources/images/categoryGrid5.gif new file mode 100644 index 0000000..ccc442c Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/categoryGrid5.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/conOver1.gif b/docs/forrest/release/src/documentation/resources/images/conOver1.gif new file mode 100644 index 0000000..f898494 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/conOver1.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/conOver2.gif b/docs/forrest/release/src/documentation/resources/images/conOver2.gif new file mode 100644 index 0000000..97cc18e Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/conOver2.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/conOver3.gif b/docs/forrest/release/src/documentation/resources/images/conOver3.gif new file mode 100644 index 0000000..67706e9 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/conOver3.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/conOver4.gif b/docs/forrest/release/src/documentation/resources/images/conOver4.gif new file mode 100644 index 0000000..4218f00 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/conOver4.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/conProg1.gif b/docs/forrest/release/src/documentation/resources/images/conProg1.gif new file mode 100644 index 0000000..6c448d7 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/conProg1.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/conProg2.gif b/docs/forrest/release/src/documentation/resources/images/conProg2.gif new file mode 100644 index 0000000..c526701 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/conProg2.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/conProg3.gif b/docs/forrest/release/src/documentation/resources/images/conProg3.gif new file mode 100644 index 0000000..260a979 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/conProg3.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/folder.gif b/docs/forrest/release/src/documentation/resources/images/folder.gif new file mode 100644 index 0000000..b1defa4 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/folder.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/impl-flow-1-conditional-forward.dia b/docs/forrest/release/src/documentation/resources/images/impl-flow-1-conditional-forward.dia new file mode 100644 index 0000000..6db0ac1 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/impl-flow-1-conditional-forward.dia differ diff --git a/docs/forrest/release/src/documentation/resources/images/impl-flow-1-conditional-forward.png b/docs/forrest/release/src/documentation/resources/images/impl-flow-1-conditional-forward.png new file mode 100644 index 0000000..e59b943 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/impl-flow-1-conditional-forward.png differ diff --git a/docs/forrest/release/src/documentation/resources/images/impl-flow-1-exception-handling.dia b/docs/forrest/release/src/documentation/resources/images/impl-flow-1-exception-handling.dia new file mode 100644 index 0000000..329aaa4 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/impl-flow-1-exception-handling.dia differ diff --git a/docs/forrest/release/src/documentation/resources/images/impl-flow-1-exception-handling.png b/docs/forrest/release/src/documentation/resources/images/impl-flow-1-exception-handling.png new file mode 100644 index 0000000..3c252c1 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/impl-flow-1-exception-handling.png differ diff --git a/docs/forrest/release/src/documentation/resources/images/impl-flow-1-login-form.dia b/docs/forrest/release/src/documentation/resources/images/impl-flow-1-login-form.dia new file mode 100644 index 0000000..7b70b46 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/impl-flow-1-login-form.dia differ diff --git a/docs/forrest/release/src/documentation/resources/images/impl-flow-1-login-form.png b/docs/forrest/release/src/documentation/resources/images/impl-flow-1-login-form.png new file mode 100644 index 0000000..be3e9dd Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/impl-flow-1-login-form.png differ diff --git a/docs/forrest/release/src/documentation/resources/images/impl-flow-1.dia b/docs/forrest/release/src/documentation/resources/images/impl-flow-1.dia new file mode 100644 index 0000000..069aec1 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/impl-flow-1.dia differ diff --git a/docs/forrest/release/src/documentation/resources/images/impl-flow-1.png b/docs/forrest/release/src/documentation/resources/images/impl-flow-1.png new file mode 100644 index 0000000..585011f Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/impl-flow-1.png differ diff --git a/docs/forrest/release/src/documentation/resources/images/impl-flow-2.dia b/docs/forrest/release/src/documentation/resources/images/impl-flow-2.dia new file mode 100644 index 0000000..46172a2 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/impl-flow-2.dia differ diff --git a/docs/forrest/release/src/documentation/resources/images/impl-flow-2.png b/docs/forrest/release/src/documentation/resources/images/impl-flow-2.png new file mode 100644 index 0000000..d8544ca Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/impl-flow-2.png differ diff --git a/docs/forrest/release/src/documentation/resources/images/incubator-logo.gif b/docs/forrest/release/src/documentation/resources/images/incubator-logo.gif new file mode 100644 index 0000000..80b75e3 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/incubator-logo.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/jbContain.gif b/docs/forrest/release/src/documentation/resources/images/jbContain.gif new file mode 100755 index 0000000..825f1df Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/jbContain.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/lastLineJoin.gif b/docs/forrest/release/src/documentation/resources/images/lastLineJoin.gif new file mode 100644 index 0000000..e0ff2f0 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/lastLineJoin.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/lastNodeCollapsed.gif b/docs/forrest/release/src/documentation/resources/images/lastNodeCollapsed.gif new file mode 100644 index 0000000..e9d0a92 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/lastNodeCollapsed.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/lastNodeExpanded.gif b/docs/forrest/release/src/documentation/resources/images/lastNodeExpanded.gif new file mode 100644 index 0000000..caca87c Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/lastNodeExpanded.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/lineJoin.gif b/docs/forrest/release/src/documentation/resources/images/lineJoin.gif new file mode 100644 index 0000000..009f29b Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/lineJoin.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/logical-flow-1.dia b/docs/forrest/release/src/documentation/resources/images/logical-flow-1.dia new file mode 100644 index 0000000..d1d8d4c Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/logical-flow-1.dia differ diff --git a/docs/forrest/release/src/documentation/resources/images/logical-flow-1.png b/docs/forrest/release/src/documentation/resources/images/logical-flow-1.png new file mode 100644 index 0000000..2a55f16 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/logical-flow-1.png differ diff --git a/docs/forrest/release/src/documentation/resources/images/logical-flow-2.dia b/docs/forrest/release/src/documentation/resources/images/logical-flow-2.dia new file mode 100644 index 0000000..12784dd Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/logical-flow-2.dia differ diff --git a/docs/forrest/release/src/documentation/resources/images/logical-flow-2.png b/docs/forrest/release/src/documentation/resources/images/logical-flow-2.png new file mode 100644 index 0000000..7f32305 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/logical-flow-2.png differ diff --git a/docs/forrest/release/src/documentation/resources/images/maven-button-1.png b/docs/forrest/release/src/documentation/resources/images/maven-button-1.png new file mode 100644 index 0000000..dd87b12 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/maven-button-1.png differ diff --git a/docs/forrest/release/src/documentation/resources/images/nested_1.dia b/docs/forrest/release/src/documentation/resources/images/nested_1.dia new file mode 100644 index 0000000..1e5da3a Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/nested_1.dia differ diff --git a/docs/forrest/release/src/documentation/resources/images/nested_1.png b/docs/forrest/release/src/documentation/resources/images/nested_1.png new file mode 100644 index 0000000..defc444 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/nested_1.png differ diff --git a/docs/forrest/release/src/documentation/resources/images/nested_2.dia b/docs/forrest/release/src/documentation/resources/images/nested_2.dia new file mode 100644 index 0000000..735f3d0 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/nested_2.dia differ diff --git a/docs/forrest/release/src/documentation/resources/images/nested_2.png b/docs/forrest/release/src/documentation/resources/images/nested_2.png new file mode 100644 index 0000000..2745b99 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/nested_2.png differ diff --git a/docs/forrest/release/src/documentation/resources/images/netui/datagrid/datagridSimple.png b/docs/forrest/release/src/documentation/resources/images/netui/datagrid/datagridSimple.png new file mode 100644 index 0000000..ce76f32 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/netui/datagrid/datagridSimple.png differ diff --git a/docs/forrest/release/src/documentation/resources/images/netui/datagrid/datagridSimpleWithAnchor.png b/docs/forrest/release/src/documentation/resources/images/netui/datagrid/datagridSimpleWithAnchor.png new file mode 100644 index 0000000..6e2ba17 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/netui/datagrid/datagridSimpleWithAnchor.png differ diff --git a/docs/forrest/release/src/documentation/resources/images/netui/datagrid/datagridSimpleWithCSS.png b/docs/forrest/release/src/documentation/resources/images/netui/datagrid/datagridSimpleWithCSS.png new file mode 100644 index 0000000..aec93ad Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/netui/datagrid/datagridSimpleWithCSS.png differ diff --git a/docs/forrest/release/src/documentation/resources/images/netui/datagrid/datagridSimpleWithDefaultPager.png b/docs/forrest/release/src/documentation/resources/images/netui/datagrid/datagridSimpleWithDefaultPager.png new file mode 100644 index 0000000..a6d5b92 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/netui/datagrid/datagridSimpleWithDefaultPager.png differ diff --git a/docs/forrest/release/src/documentation/resources/images/netui/datagrid/datagridSimpleWithFPNLPager.png b/docs/forrest/release/src/documentation/resources/images/netui/datagrid/datagridSimpleWithFPNLPager.png new file mode 100644 index 0000000..46bc027 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/netui/datagrid/datagridSimpleWithFPNLPager.png differ diff --git a/docs/forrest/release/src/documentation/resources/images/netui/datagrid/datagridSimpleWithFormatter.png b/docs/forrest/release/src/documentation/resources/images/netui/datagrid/datagridSimpleWithFormatter.png new file mode 100644 index 0000000..5ad7202 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/netui/datagrid/datagridSimpleWithFormatter.png differ diff --git a/docs/forrest/release/src/documentation/resources/images/netui/datagrid/datagridSimpleWithHeader.png b/docs/forrest/release/src/documentation/resources/images/netui/datagrid/datagridSimpleWithHeader.png new file mode 100644 index 0000000..8185fb4 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/netui/datagrid/datagridSimpleWithHeader.png differ diff --git a/docs/forrest/release/src/documentation/resources/images/netui/datagrid/datagridSimpleWithImplicitObjectPager.png b/docs/forrest/release/src/documentation/resources/images/netui/datagrid/datagridSimpleWithImplicitObjectPager.png new file mode 100644 index 0000000..9e88869 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/netui/datagrid/datagridSimpleWithImplicitObjectPager.png differ diff --git a/docs/forrest/release/src/documentation/resources/images/netui/datagrid/datagridSimpleWithStyle.png b/docs/forrest/release/src/documentation/resources/images/netui/datagrid/datagridSimpleWithStyle.png new file mode 100644 index 0000000..a94a28b Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/netui/datagrid/datagridSimpleWithStyle.png differ diff --git a/docs/forrest/release/src/documentation/resources/images/netui/nestedPageFlow/basicNestingMain.gif b/docs/forrest/release/src/documentation/resources/images/netui/nestedPageFlow/basicNestingMain.gif new file mode 100644 index 0000000..1c2e3e6 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/netui/nestedPageFlow/basicNestingMain.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/netui/nestedPageFlow/basicNestingNested.gif b/docs/forrest/release/src/documentation/resources/images/netui/nestedPageFlow/basicNestingNested.gif new file mode 100644 index 0000000..b289c2b Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/netui/nestedPageFlow/basicNestingNested.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/netui/nestedPageFlow/nestingChooseAirport.gif b/docs/forrest/release/src/documentation/resources/images/netui/nestedPageFlow/nestingChooseAirport.gif new file mode 100644 index 0000000..2589c0f Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/netui/nestedPageFlow/nestingChooseAirport.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/netui/nestedPageFlow/nestingChooseAirportCancelled.gif b/docs/forrest/release/src/documentation/resources/images/netui/nestedPageFlow/nestingChooseAirportCancelled.gif new file mode 100644 index 0000000..484cc1f Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/netui/nestedPageFlow/nestingChooseAirportCancelled.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/netui/nestedPageFlow/nestingMain.gif b/docs/forrest/release/src/documentation/resources/images/netui/nestedPageFlow/nestingMain.gif new file mode 100644 index 0000000..eb575f6 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/netui/nestedPageFlow/nestingMain.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/nodeCollapsed.gif b/docs/forrest/release/src/documentation/resources/images/nodeCollapsed.gif new file mode 100644 index 0000000..02eff2b Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/nodeCollapsed.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/nodeExpanded.gif b/docs/forrest/release/src/documentation/resources/images/nodeExpanded.gif new file mode 100644 index 0000000..51afff8 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/nodeExpanded.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/pageflow_database_app_1.dia b/docs/forrest/release/src/documentation/resources/images/pageflow_database_app_1.dia new file mode 100644 index 0000000..57d1b56 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/pageflow_database_app_1.dia differ diff --git a/docs/forrest/release/src/documentation/resources/images/pageflow_database_app_1.png b/docs/forrest/release/src/documentation/resources/images/pageflow_database_app_1.png new file mode 100644 index 0000000..7a63fd1 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/pageflow_database_app_1.png differ diff --git a/docs/forrest/release/src/documentation/resources/images/repeatCheckBox.png b/docs/forrest/release/src/documentation/resources/images/repeatCheckBox.png new file mode 100644 index 0000000..9436776 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/repeatCheckBox.png differ diff --git a/docs/forrest/release/src/documentation/resources/images/repeatRadioButton.png b/docs/forrest/release/src/documentation/resources/images/repeatRadioButton.png new file mode 100644 index 0000000..b0eaf12 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/repeatRadioButton.png differ diff --git a/docs/forrest/release/src/documentation/resources/images/rootCollapsed.gif b/docs/forrest/release/src/documentation/resources/images/rootCollapsed.gif new file mode 100644 index 0000000..a5f6362 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/rootCollapsed.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/rootExpanded.gif b/docs/forrest/release/src/documentation/resources/images/rootExpanded.gif new file mode 100644 index 0000000..546e0bf Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/rootExpanded.gif differ diff --git a/docs/forrest/release/src/documentation/resources/images/runAtClientFlow.png b/docs/forrest/release/src/documentation/resources/images/runAtClientFlow.png new file mode 100644 index 0000000..01fa33d Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/runAtClientFlow.png differ diff --git a/docs/forrest/release/src/documentation/resources/images/runAtClientFlow.vsd b/docs/forrest/release/src/documentation/resources/images/runAtClientFlow.vsd new file mode 100644 index 0000000..e4abc08 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/runAtClientFlow.vsd differ diff --git a/docs/forrest/release/src/documentation/resources/images/simpleTreeFlow.png b/docs/forrest/release/src/documentation/resources/images/simpleTreeFlow.png new file mode 100644 index 0000000..d710121 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/simpleTreeFlow.png differ diff --git a/docs/forrest/release/src/documentation/resources/images/simpleTreeFlow.vsd b/docs/forrest/release/src/documentation/resources/images/simpleTreeFlow.vsd new file mode 100644 index 0000000..df9d939 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/simpleTreeFlow.vsd differ diff --git a/docs/forrest/release/src/documentation/resources/images/simpleTreePage.png b/docs/forrest/release/src/documentation/resources/images/simpleTreePage.png new file mode 100644 index 0000000..b30a9d5 Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/simpleTreePage.png differ diff --git a/docs/forrest/release/src/documentation/resources/images/tagErrors.png b/docs/forrest/release/src/documentation/resources/images/tagErrors.png new file mode 100644 index 0000000..2367f8d Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/tagErrors.png differ diff --git a/docs/forrest/release/src/documentation/resources/images/tagsJavaScriptScreen.png b/docs/forrest/release/src/documentation/resources/images/tagsJavaScriptScreen.png new file mode 100644 index 0000000..51c21ea Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/tagsJavaScriptScreen.png differ diff --git a/docs/forrest/release/src/documentation/resources/images/verticalLine.gif b/docs/forrest/release/src/documentation/resources/images/verticalLine.gif new file mode 100644 index 0000000..fdec15b Binary files /dev/null and b/docs/forrest/release/src/documentation/resources/images/verticalLine.gif differ diff --git a/docs/forrest/release/src/documentation/sitemap.xmap b/docs/forrest/release/src/documentation/sitemap.xmap new file mode 100644 index 0000000..5f94ef3 --- /dev/null +++ b/docs/forrest/release/src/documentation/sitemap.xmap @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/forrest/release/src/documentation/skinconf.xml b/docs/forrest/release/src/documentation/skinconf.xml new file mode 100644 index 0000000..8f1429d --- /dev/null +++ b/docs/forrest/release/src/documentation/skinconf.xml @@ -0,0 +1,334 @@ + + + + + + + + + true + + false + + true + + true + + + true + + false + + false + + false + .at. + + true + + + Apache Beehive + The Beehive project at the Apache Software Foundation + http://beehive.apache.org/ + images/_beehive_logo_wide.gif + + + + Apache Software Foundation + The Apache Software Foundation + http://www.apache.org/ + images/apache-asf-compressed.png + + + + + + + + + + 2004-2006 + The Apache Software Foundation. + + http://www.apache.org/licenses/ + + + + + + + + + + + + + + Send feedback about the website to: + + + + + p.quote { + margin-left: 2em; + padding: .5em; + background-color: #f0f0f0; + font-family: monospace; + } + pre.code { + margin-left: 2em; + padding: .5em; + background-color: #f0f0f0; + font-family: monospace; + font-size: 11px; + } + h3 { + font-size: 99%; + } + h4 { + font-weight: bold; + font-size: 99%; + } + p.filename { + margin-left: 2em; + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1in + 1in + 1.25in + 1in + + + false + + false + + + + + + + + diff --git a/docs/forrest/release/src/documentation/translations/langcode.xml b/docs/forrest/release/src/documentation/translations/langcode.xml new file mode 100644 index 0000000..63041b5 --- /dev/null +++ b/docs/forrest/release/src/documentation/translations/langcode.xml @@ -0,0 +1,26 @@ + + + + + English + Espanol + Italiano + diff --git a/docs/forrest/release/src/documentation/translations/languages_en.xml b/docs/forrest/release/src/documentation/translations/languages_en.xml new file mode 100644 index 0000000..c8b239a --- /dev/null +++ b/docs/forrest/release/src/documentation/translations/languages_en.xml @@ -0,0 +1,22 @@ + + + + English + Spanish + Dutch + diff --git a/docs/forrest/release/src/documentation/translations/languages_es.xml b/docs/forrest/release/src/documentation/translations/languages_es.xml new file mode 100644 index 0000000..e784e2c --- /dev/null +++ b/docs/forrest/release/src/documentation/translations/languages_es.xml @@ -0,0 +1,22 @@ + + + + Inglés + Español + Holandés + diff --git a/docs/forrest/release/src/documentation/translations/menu.xml b/docs/forrest/release/src/documentation/translations/menu.xml new file mode 100644 index 0000000..7d5e504 --- /dev/null +++ b/docs/forrest/release/src/documentation/translations/menu.xml @@ -0,0 +1,33 @@ + + + + About + Index + Changes + Todo + Samples + Apache document + Static content + Linking + Wiki page + Ihtml page + Ehtml page + FAQ + Simplifed Docbook + XSP page + diff --git a/docs/forrest/release/src/documentation/translations/menu_af.xml b/docs/forrest/release/src/documentation/translations/menu_af.xml new file mode 100644 index 0000000..5444ee6 --- /dev/null +++ b/docs/forrest/release/src/documentation/translations/menu_af.xml @@ -0,0 +1,33 @@ + + + + Aangaande + Inhoud + Veranderinge + Om te doen + Voorbeelde + Apache dokument + Statise Inhoud + Linking + Wiki bladsy + Ihtml bladsy + Ehtml bladsy + FAQ + Vereenvoudigde Docbook + XSP bladsy + diff --git a/docs/forrest/release/src/documentation/translations/menu_de.xml b/docs/forrest/release/src/documentation/translations/menu_de.xml new file mode 100644 index 0000000..237c1f6 --- /dev/null +++ b/docs/forrest/release/src/documentation/translations/menu_de.xml @@ -0,0 +1,33 @@ + + + + Über + Index + Änderungen + Todo + Beispiele + Apache Dokumentationsseite + Statischer Inhalt + Linking + Wiki Seite + ihtml Seite + ehtml Seite + FAQ + Vereinfachte Docbook + XSP Seite + diff --git a/docs/forrest/release/src/documentation/translations/menu_es.xml b/docs/forrest/release/src/documentation/translations/menu_es.xml new file mode 100644 index 0000000..e704b9b --- /dev/null +++ b/docs/forrest/release/src/documentation/translations/menu_es.xml @@ -0,0 +1,33 @@ + + + + Acerca de + Indice + Cambios + Tareas pendientes + Ejemplos + Documento Apache + Contenido Estático + Linking + Página Wiki + Página ihtml + Página ehtml + Preguntas Frecuentes + Página Simplifed Docbook + Página XSP + diff --git a/docs/forrest/release/src/documentation/translations/menu_it.xml b/docs/forrest/release/src/documentation/translations/menu_it.xml new file mode 100644 index 0000000..d2233aa --- /dev/null +++ b/docs/forrest/release/src/documentation/translations/menu_it.xml @@ -0,0 +1,33 @@ + + + + Riguardo a + Indice + Cambiamenti + Cose da fare + Esempi + Apache document + Contenuto Statico + Linking + Pagina Wiki + Pagina ihtml + Pagina ehtml + Domande frequenti + Simplifed Docbook + Pagina XSP + diff --git a/docs/forrest/release/src/documentation/translations/menu_no.xml b/docs/forrest/release/src/documentation/translations/menu_no.xml new file mode 100644 index 0000000..f9be343 --- /dev/null +++ b/docs/forrest/release/src/documentation/translations/menu_no.xml @@ -0,0 +1,33 @@ + + + + Om + Indeks + Endringer + Oppgave liste + Eksempler + Apache Dokument + Statisk innhold + Linking + Wiki side + ihtml side + ehtml side + FAQ + Simplifed Docbook + XSP side + diff --git a/docs/forrest/release/src/documentation/translations/menu_ru.xml b/docs/forrest/release/src/documentation/translations/menu_ru.xml new file mode 100644 index 0000000..0e35206 --- /dev/null +++ b/docs/forrest/release/src/documentation/translations/menu_ru.xml @@ -0,0 +1,33 @@ + + + + О проекте + Содержание + Изменения + План + Примеры + Страница документа Apache + Статическое содержание + Linking + Страница Wiki + Страница ihtml + Страница ehtml + Вопросы/Ответы + Docbook страница + XSP страница + diff --git a/docs/forrest/release/src/documentation/translations/menu_sk.xml b/docs/forrest/release/src/documentation/translations/menu_sk.xml new file mode 100644 index 0000000..2fc3fe9 --- /dev/null +++ b/docs/forrest/release/src/documentation/translations/menu_sk.xml @@ -0,0 +1,33 @@ + + + + O programe + Zoznám + Zmeny + Úlohy + Príklady + Apache Document + Statický Obsah + Linking + Wiki stránka + ihtml stránka + ehtml stránka + Casté Otázky + Simplifed Docbook stránka + XSP stránka + diff --git a/docs/forrest/release/src/documentation/translations/tabs.xml b/docs/forrest/release/src/documentation/translations/tabs.xml new file mode 100644 index 0000000..a5e1003 --- /dev/null +++ b/docs/forrest/release/src/documentation/translations/tabs.xml @@ -0,0 +1,22 @@ + + + + Home + Samples + Apache XML Projects + diff --git a/docs/forrest/release/src/documentation/translations/tabs_es.xml b/docs/forrest/release/src/documentation/translations/tabs_es.xml new file mode 100644 index 0000000..d273249 --- /dev/null +++ b/docs/forrest/release/src/documentation/translations/tabs_es.xml @@ -0,0 +1,22 @@ + + + + Inicio + Ejemplos + Projectos XML Apache + diff --git a/docs/forrest/template.xml b/docs/forrest/template.xml new file mode 100644 index 0000000..f092685 --- /dev/null +++ b/docs/forrest/template.xml @@ -0,0 +1,56 @@ + + + + + +
    + Your Title Here +
    + +
    + Overview +

    + TODO: overview +

    +
    +
    + Content +

    + TODO: content +

    +
    + Nested Content +

    + TODO: nested content +

    +
    +
    + Nested Content + + ]]> +
    +
    + Nested Content + +public class Foo + extends Bar { + + private String baz; + + public String doBlee() { + return baz; + } +} + +
    +
    + +
    diff --git a/docs/how_to_contribute_docs.txt b/docs/how_to_contribute_docs.txt new file mode 100644 index 0000000..3d91949 --- /dev/null +++ b/docs/how_to_contribute_docs.txt @@ -0,0 +1,139 @@ + +Contributing Documentation to Beehive +===================================== + +Introduction +------------ + +Beehive documentation is created using Apache Forrest--a tool for +building web sites from XML source docs. + +To contribute documentation you must first install Forrest on +your local machine. For installation details see: + + beehive/trunk/BUILDING.txt + +Forrest documentation is in the form of XML files, so it is a good idea +to use a tool that is able to validate XML during authoring. The XML +source files must be valid for the Beehive documentation to build +successfully. + +Note, the paths below are referenced relative to the SVN root: + + beehive/trunk + +In addition, instructions for updating the Beehive website are included +below. + +Authoring Documentation +------------------------ + +Beehive stores its Forrest XML files in one of two directories: + + docs/forrest/release/src/documentation/content/xdocs + +contains the documentation for a specific Beehive release and is +made available at the URL: + + http://beehive.apache.org/release/ + +The directory: + + docs/forrest/site/src/documentation/content/xdocs + +contains the documentation for the Beehive website and maps to the +URL: + + http://beehive.apache.org/ + +The command-line examples below assumes that you are authoring documentation +for a Beehive release. + +The XML source files are transformed by the Forrest tool into +an HTML web site. Forrest XML contains many idiomatic shorthand +expressions for referencing common HTML elements, esp. HTML links. +For details on this shorthand see + + http://forrest.apache.org/docs/linking.html + +The basic development cycle for Beehive documentation runs as follows: + +(1) Turn on the Jetty Server + +The Jetty server is a web server / Servlet container provided by Forrest +used to view/test the Forrest docs while they are development. + +To turn on the Jetty Server, run the following Ant command: + + docs/forrest/release> ant run + +Once the Jetty Server has been turned on, it is automatically aware of the +Forrest XML files in: + + /docs/forrest/src/documentation/content/xdocs + +Any changes you make to these XML files, will automatically be reflected +in the HTML served up the Jetty server. + +(2) Edit the Forrest XML source + +Make the desired changes to the Forrest XML source files. Your changes should +result in valid XML documents according to the appropriate Forrest DTDs, specifically +that available at: + + http://forrest.apache.org/dtd/document-v20.dtd + +While editing Forrest XML files, it is helpful to use an authoring environment +that can validate XML files. Invalid XML files will break the Beehive build. + +(3) View the changes to the documentation + +During authoring, changes can be viewed dynamically via a web browser by visiting: + + http://localhost:8888/index.html + +Repeat steps (2) and (3) to make iterative edits to the Forrest XML files. + +(4) Committing changes to documentation + +Changes to the Forrest XML files should be committed after ensuring that the +release / site documentation builds succeed successfully. To ensure that the +release build succeeds, run: + + docs/forrest> ant build.release + +To ensure that the website build succeeds, run: + + docs/forrest> ant build.site + +Additional instructions for editing the website are included below. + +Updating the Website +-------------------- + +The website is decoupled from the Beehive release documentation, though at the time +of this writing, they are both checked into trunk/. + +To update the website, make any modifications in docs/forrest/site/. Then, build the +documentation with: + + cd docs/forrest + ant build.site + +The build should complete without any errors. Once this is complete, the website +can be staged using: + + ant stage.site + +This will copy the website atop the docs/forrest/www directory. Run 'svn status' and +ensure that the Forrest files you changed are reflected in the HTML / PDF files that +Forrest generated. + +Once this is done, run 'svn commit' to submit the changes to docs/forrest/www to +source control. The website can be updated by checking it out of Subversion onto the +Apache web server. To do this, run: + + svn commit + ssh minotaur.apache.org + cd /www/beehive.apache.org + svn update http://svn.apache.org/repos/asf/beehive/docs/forrest/www diff --git a/docs/maven-support.txt b/docs/maven-support.txt new file mode 100644 index 0000000..6da8a9a --- /dev/null +++ b/docs/maven-support.txt @@ -0,0 +1,125 @@ +Overview +======== + +Producing Maven from the Build +============================== +In order to support Maven, the Beehive build neesd to support copying the Maven artifacts into directories that can be uploaded into M1.x and M2 repositories. Unfortunately, the Maven 1 and 2 repository layouts are different and two different uploadable directories need to be created. + +Note: +- All resources in the Maven repository must be *both* signed and checksum-ed. +- All resources must have the version number embedded. + +Maven 1.x +========= +beehive/ + distributions/ + + jars/ + beehive-controls-.jar + beehive-netui-core-.jar + beehive-netui-compiler-.jar + beehive-netui-tags-.jar + beehive-ejb-control-.jar + beehive-jms-control-.jar + beehive-jdbc-control-.jar + licenses/ + LICENSE + poms/ + beehive-controls-.pom + beehive-netui-.pom + +- How do we distribute the NetUI webapp resources in Maven 1.x? + +Maven 2.x +========= +org/apache/beehive/ + beehive-controls/ + maven-metadata.xml + / + maven-metadata.xml + beehive-controls-.pom + beehive-controls-.jar + beehive-ejb-control/ + maven-metadata.xml + / + maven-metadata.xml + beehive-ejb-control-.pom + beehive-ejb-control-.jar + beehive-ejb-control/ + maven-metadata.xml + / + maven-metadata.xml + beehive-jms-control-.pom + beehive-jms-control-.jar + beehive-ejb-control/ + maven-metadata.xml + / + maven-metadata.xml + beehive-jdbc-control-.pom + beehive-jdbc-control-.jar + beehive-netui/ + maven-metadata.xml + / + maven-metadata.xml + beehive-netui-core-.pom + beehive-netui-core-.jar + beehive-ejb-control/ + maven-metadata.xml + / + maven-metadata.xml + beehive-netui-compiler-.pom + beehive-netui-compiler-.jar + beehive-ejb-control/ + maven-metadata.xml + / + maven-metadata.xml + beehive-netui-tags-.pom + beehive-netui-tags-.jar + +This partitioning represents a separation of the NetUI and Controls sub-projects. This setup requires artifact IDs as "beehive-(netui|controls)" in order to qualify the JAR names correctly. + +- The NetUI resources are made available from the NetUI webapp archetype. +- Where do the M2 archetypes go? +- Can the same POM versions be used with Maven1 and Maven2? Yes. Looks like the Struts 1.2.8 ones are common between Maven1 and Maven2. + +Repository List +=============== +M1 SNAPSHOT: + http://cvs.apache.org/repository/ + +M1 Production: + http://www.apache.org/dist/java-repository/ + +M2 SNAPSHOT: + http://cvs.apache.org/maven-snapshot-repository/ + +M2 Production: + +Using Maven with Beehive +======================== +TODO + +Attachments +=========== +top-level maven-metadata.xml +::: + + org.apache.beehive + beehive + 1.0.1 + + + 1.0.1 + + + +::: + +release maven-metadata.xml +::: + + org.apache.beehive + beehive + 1.0.1 + +::: \ No newline at end of file diff --git a/docs/source-header/README.txt b/docs/source-header/README.txt new file mode 100644 index 0000000..97bb770 --- /dev/null +++ b/docs/source-header/README.txt @@ -0,0 +1,6 @@ +This directory contains source headers for a variety of file types. + +For more information, see: + + http://apache.org/legal/src-headers.html + diff --git a/docs/source-header/java.txt b/docs/source-header/java.txt new file mode 100644 index 0000000..56e3e37 --- /dev/null +++ b/docs/source-header/java.txt @@ -0,0 +1,18 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Header:$ + */ diff --git a/docs/source-header/jsp.txt b/docs/source-header/jsp.txt new file mode 100644 index 0000000..b3158dd --- /dev/null +++ b/docs/source-header/jsp.txt @@ -0,0 +1,18 @@ +<%-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + $Header:$ +--%> diff --git a/docs/source-header/properties.txt b/docs/source-header/properties.txt new file mode 100644 index 0000000..dd011f8 --- /dev/null +++ b/docs/source-header/properties.txt @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# $Header:$ +# diff --git a/docs/source-header/xml.txt b/docs/source-header/xml.txt new file mode 100644 index 0000000..81e0e3f --- /dev/null +++ b/docs/source-header/xml.txt @@ -0,0 +1,18 @@ + diff --git a/docs/tools/xslt/anno_ref.xslt b/docs/tools/xslt/anno_ref.xslt new file mode 100644 index 0000000..2492d84 --- /dev/null +++ b/docs/tools/xslt/anno_ref.xslt @@ -0,0 +1,52 @@ + + + ]> + + + + + + + +
    + Reference Documentation: <xsl:value-of select="chapter@xreflabel"/> +
    + + + +
    + +

    +
    +
    + +
    + Elements + +
    + <<xsl:value-of select="."/>> +

     

    +
    +
    +
    + + + +
    + Example +

    +
    +
    +
    + +
    + + +
    + + +
    diff --git a/docs/tools/xslt/config_ref.xslt b/docs/tools/xslt/config_ref.xslt new file mode 100644 index 0000000..be0dc19 --- /dev/null +++ b/docs/tools/xslt/config_ref.xslt @@ -0,0 +1,55 @@ + + + ]> + + + + + + + +
    + Reference Documentation: <xsl:value-of select="ref:schema/ref:element/@name"/>.xml File +
    + + + + +
    + Description +

    +
    +
    +
    + +
    + Elements + + +
    + <<xsl:value-of select="@name"/>> +

     

    +
    +
    +
    + + + +
    + Example +

    +
    +
    +
    + +
    + + +
    + + +
    diff --git a/external/axis-1.3/axis-ant.jar b/external/axis-1.3/axis-ant.jar new file mode 100644 index 0000000..a72ce1d Binary files /dev/null and b/external/axis-1.3/axis-ant.jar differ diff --git a/external/axis-1.3/axis-schema.jar b/external/axis-1.3/axis-schema.jar new file mode 100644 index 0000000..82e6a85 Binary files /dev/null and b/external/axis-1.3/axis-schema.jar differ diff --git a/external/axis-1.3/axis.jar b/external/axis-1.3/axis.jar new file mode 100644 index 0000000..2b8aba5 Binary files /dev/null and b/external/axis-1.3/axis.jar differ diff --git a/external/axis-1.3/jaxrpc.jar b/external/axis-1.3/jaxrpc.jar new file mode 100644 index 0000000..180d4ec Binary files /dev/null and b/external/axis-1.3/jaxrpc.jar differ diff --git a/external/axis-1.3/saaj.jar b/external/axis-1.3/saaj.jar new file mode 100644 index 0000000..ae32ad9 Binary files /dev/null and b/external/axis-1.3/saaj.jar differ diff --git a/external/axis-1.3/wsdl4j-1.5.1.jar b/external/axis-1.3/wsdl4j-1.5.1.jar new file mode 100644 index 0000000..c6254ee Binary files /dev/null and b/external/axis-1.3/wsdl4j-1.5.1.jar differ diff --git a/external/beehive-antext/README.txt b/external/beehive-antext/README.txt new file mode 100644 index 0000000..66a9d39 --- /dev/null +++ b/external/beehive-antext/README.txt @@ -0,0 +1,2 @@ +These are local tasks used for Beehive which may be useful to others. +If you wish to add a Task make sure to add the src and update the jar. diff --git a/external/beehive-antext/beehive-antext.jar b/external/beehive-antext/beehive-antext.jar new file mode 100644 index 0000000..d71e9d0 Binary files /dev/null and b/external/beehive-antext/beehive-antext.jar differ diff --git a/external/beehive-antext/build.xml b/external/beehive-antext/build.xml new file mode 100644 index 0000000..30d4e00 --- /dev/null +++ b/external/beehive-antext/build.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/beehive-antext/src/org/apache/beehive/test/tools/antext/GetHostName.java b/external/beehive-antext/src/org/apache/beehive/test/tools/antext/GetHostName.java new file mode 100644 index 0000000..8b80d64 --- /dev/null +++ b/external/beehive-antext/src/org/apache/beehive/test/tools/antext/GetHostName.java @@ -0,0 +1,27 @@ +package org.apache.beehive.test.tools.antext; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.Target; + +import java.net.InetAddress; + +public class GetHostName extends Task +{ + public void execute() throws BuildException + { + try + { + Target t = this.getOwningTarget(); + InetAddress inetAddr = InetAddress.getLocalHost(); + t.getProject().setProperty( "hostname", inetAddr.getHostName() ); + t.getProject().setProperty( "hostname.domain", inetAddr.getCanonicalHostName() ); + } + catch ( Exception e ) + { + throw new BuildException( "Error: " + e, e ); + } + + } // execute() + +} // GetHostName diff --git a/external/commons/commons-codec-1.3.jar b/external/commons/commons-codec-1.3.jar new file mode 100644 index 0000000..957b675 Binary files /dev/null and b/external/commons/commons-codec-1.3.jar differ diff --git a/external/commons/commons-discovery-0.2.jar b/external/commons/commons-discovery-0.2.jar new file mode 100644 index 0000000..b885548 Binary files /dev/null and b/external/commons/commons-discovery-0.2.jar differ diff --git a/external/commons/commons-logging-1.0.4.jar b/external/commons/commons-logging-1.0.4.jar new file mode 100644 index 0000000..b73a80f Binary files /dev/null and b/external/commons/commons-logging-1.0.4.jar differ diff --git a/external/crimson/crimson-1.1.jar b/external/crimson/crimson-1.1.jar new file mode 100644 index 0000000..a734d42 Binary files /dev/null and b/external/crimson/crimson-1.1.jar differ diff --git a/external/derby/derby_46005.jar b/external/derby/derby_46005.jar new file mode 100644 index 0000000..7c8948a Binary files /dev/null and b/external/derby/derby_46005.jar differ diff --git a/external/httpunit/httpunit.jar b/external/httpunit/httpunit.jar new file mode 100644 index 0000000..dd2404f Binary files /dev/null and b/external/httpunit/httpunit.jar differ diff --git a/external/httpunit/nekohtml.jar b/external/httpunit/nekohtml.jar new file mode 100644 index 0000000..58616ec Binary files /dev/null and b/external/httpunit/nekohtml.jar differ diff --git a/external/httpunit/xercesImpl.jar b/external/httpunit/xercesImpl.jar new file mode 100644 index 0000000..3197095 Binary files /dev/null and b/external/httpunit/xercesImpl.jar differ diff --git a/external/jakarta/jakarta-regexp-1.2.jar b/external/jakarta/jakarta-regexp-1.2.jar new file mode 100644 index 0000000..713441c Binary files /dev/null and b/external/jakarta/jakarta-regexp-1.2.jar differ diff --git a/external/jaxp/jaxp.jar b/external/jaxp/jaxp.jar new file mode 100644 index 0000000..d79e6b5 Binary files /dev/null and b/external/jaxp/jaxp.jar differ diff --git a/external/junit/cpl-v10.html b/external/junit/cpl-v10.html new file mode 100644 index 0000000..36aa208 --- /dev/null +++ b/external/junit/cpl-v10.html @@ -0,0 +1,125 @@ + + + +Common Public License - v 1.0 + + + + + + +

    Common Public License - v 1.0 +

    +

    THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. +

    +

    1. DEFINITIONS +

    "Contribution" means: + +

      a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and
      +b) in the case of each subsequent Contributor:
    + + +
      i) changes to the Program, and
    + + +
      ii) additions to the Program;
    + + +
      where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program.
    + +

    +

    "Contributor" means any person or entity that distributes the Program. +

    +

    "Licensed Patents " mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. +

    +

    "Program" means the Contributions distributed in accordance with this Agreement. +

    +

    "Recipient" means anyone who receives the Program under this Agreement, including all Contributors. +

    +

    2. GRANT OF RIGHTS + +

      a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form.
    + + +
    + + +
      b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
    + + +
    + + +
      c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
    + + +
    + + +
      d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
    + + +
    + +

    3. REQUIREMENTS +

    A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: + +

      a) it complies with the terms and conditions of this Agreement; and
    + + +
      b) its license agreement:
    + + +
      i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    + + +
      ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    + + +
      iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and
    + + +
      iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange.
    + + +
    + +

    When the Program is made available in source code form: + +

      a) it must be made available under this Agreement; and
    + + +
      b) a copy of this Agreement must be included with each copy of the Program.
    + +

    +

    Contributors may not remove or alter any copyright notices contained within the Program. +

    +

    Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. +

    +

    4. COMMERCIAL DISTRIBUTION +

    Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. +

    +

    For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. +

    +

    5. NO WARRANTY +

    EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. +

    +

    6. DISCLAIMER OF LIABILITY +

    EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +

    +

    7. GENERAL +

    If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. +

    +

    If Recipient institutes patent litigation against a Contributor with respect to a patent applicable to software (including a cross-claim or counterclaim in a lawsuit), then any patent licenses granted by that Contributor to such Recipient under this Agreement shall terminate as of the date such litigation is filed. In addition, if Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. +

    +

    All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. +

    +

    Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. IBM is the initial Agreement Steward. IBM may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. +

    +

    This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. +

    +

    + + + + \ No newline at end of file diff --git a/external/junit/junit.jar b/external/junit/junit.jar new file mode 100644 index 0000000..674d71e Binary files /dev/null and b/external/junit/junit.jar differ diff --git a/external/log4j/log4j-1.2.8.jar b/external/log4j/log4j-1.2.8.jar new file mode 100644 index 0000000..493a3cc Binary files /dev/null and b/external/log4j/log4j-1.2.8.jar differ diff --git a/external/servlet/jsp-api-2.0.jar b/external/servlet/jsp-api-2.0.jar new file mode 100644 index 0000000..95832ba Binary files /dev/null and b/external/servlet/jsp-api-2.0.jar differ diff --git a/external/servlet/servlet-api-2.4.jar b/external/servlet/servlet-api-2.4.jar new file mode 100644 index 0000000..bc0dea0 Binary files /dev/null and b/external/servlet/servlet-api-2.4.jar differ diff --git a/external/velocity/velocity-dep-1.4.jar b/external/velocity/velocity-dep-1.4.jar new file mode 100644 index 0000000..375712b Binary files /dev/null and b/external/velocity/velocity-dep-1.4.jar differ diff --git a/external/xmlbeans/apache-xbean.jar b/external/xmlbeans/apache-xbean.jar new file mode 100644 index 0000000..08c72cd Binary files /dev/null and b/external/xmlbeans/apache-xbean.jar differ diff --git a/maven/build.xml b/maven/build.xml new file mode 100644 index 0000000..3935c1b --- /dev/null +++ b/maven/build.xml @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + +Note, don't forget to sign the Maven upload!zip + +for i in *.*; do gpg --output $i.asc --detach-sig --armor $i; done + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/netui/ant/javadoc.xml b/netui/ant/javadoc.xml new file mode 100644 index 0000000..fabdd8c --- /dev/null +++ b/netui/ant/javadoc.xml @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/netui/ant/netui.properties b/netui/ant/netui.properties new file mode 100644 index 0000000..008a4b5 --- /dev/null +++ b/netui/ant/netui.properties @@ -0,0 +1,99 @@ +# +# common.properties -- an Ant properties file that +# contains properties that are read-only in +# a user's development environment. +# +netui.home=${beehive.home}/netui +netui.ant.dir=${netui.home}/ant +test.dir=${netui.home}/test +docs.dir=${netui.home}/docs +external.dir=${netui.home}/external +app.dir=${test.dir}/webapps + +classes.dir=${build.dir}/classes + +javadoc.dir=${build.dir}/javadoc +javadoc.module.dir=${javadoc.dir}/modules + +default.tomcat-users.xml=${conf.dir}/tomcat-users.xml + +testRecorder.dir=${netui.home}/build/tools/testRecorder + +#build.lib.dir=${build.dir}/lib +#build.dir=${netui.home}/build +#src.dir=${netui.home}/src + +# --------------------------------------------------------------------------------- +# +# External JAR and resource paths +# +# --------------------------------------------------------------------------------- + +struts.dir=${netui.home}/external/struts +struts11.dir=${struts.dir}/legacy/jakarta-struts-1.1-lib +struts12.dir=${struts.dir} +tomcat.lib.dir=${netui.home}/external/tomcat +myfaces.jar=${myfaces.dir}/myfaces.jar +jsf-api.jar=${myfaces.dir}/myfaces-jsf-api.jar + +# +# Tomcat properties. These JARs are used to compile the Tomcat ServletContainerAdapter(s). +# +catalina.5.0.x.jar=${tomcat.lib.dir}/5.0.x/catalina.jar +coyote.5.0.x.jar=${tomcat.lib.dir}/5.0.x/tomcat-coyote.jar +catalina.5.5.x.jar=${tomcat.lib.dir}/5.5.x/catalina.jar +coyote.5.5.x.jar=${tomcat.lib.dir}/5.5.x/tomcat-coyote.jar + +# +# XDoclet properties. These JARs are used by the Page Flow XDoclet compiler (compiler-xdoclet module) +# +xdoclet.jar=${external.dir}/xdoclet/xdoclet-1.2b4.jar +xjavadoc.jar=${external.dir}/xdoclet/xjavadoc-1.1.jar + +# --------------------------------------------------------------------------------- +# +# NetUI build artifact JAR and resource names +# +# --------------------------------------------------------------------------------- + +# NetUI JAR file names +#bootstrap.jar.name=bootstrap.jar +compiler.jar.name=beehive-netui-compiler.jar +compiler-xdoclet.jar.name=beehive-netui-compiler-xdoclet.jar + +netui-tomcat-common.5.0.x.jar.name=beehive-netui-tomcat-common-5.0.x.jar +netui-tomcat-server.5.0.x.jar.name=beehive-netui-tomcat-server-5.0.x.jar +netui-tomcat-webapp.5.0.x.jar.name=beehive-netui-tomcat-webapp-5.0.x.jar +netui-tomcat-common.5.5.x.jar.name=beehive-netui-tomcat-common-5.5.x.jar +netui-tomcat-server.5.5.x.jar.name=beehive-netui-tomcat-server-5.5.x.jar +netui-tomcat-webapp.5.5.x.jar.name=beehive-netui-tomcat-webapp-5.5.x.jar + +# NetUI TLD Names +netui-tags-simple.tld.name=beehive-netui-tags-simple.tld +netui-tags-html.tld.name=beehive-netui-tags-html.tld +netui-tags-template.tld.name=beehive-netui-tags-template.tld +netui-tags-databinding.tld.name=beehive-netui-tags-databinding.tld + +# NetUI config file name +netuiconfig.xml.name=beehive-netui-config.xml + +# NetUI config file references +netuiconfig.xml=${src.dir}/webapp-template/default/web/WEB-INF/beehive-netui-config.xml + +# Default web.xml file reference +default.web.xml=${src.dir}/webapp-template/default/web/WEB-INF/web.xml + +# Validator rules file references +beehive-netui-validator-rules.xml=${src.dir}/webapp-template/default/web/WEB-INF/beehive-netui-validator-rules.xml +validator-rules.xml=${src.dir}/webapp-template/default/web/WEB-INF/validator-rules.xml + +#compile options +compile.debug=true +compile.deprecation=off +compile.optimize=off +compile.source=1.4 +compile.target=1.4 + +# runtime and compiler versions +pageflow.version.runtime=3 +pageflow.version.compiler=3 diff --git a/netui/ant/webappTemplate.xml b/netui/ant/webappTemplate.xml new file mode 100644 index 0000000..bc2ffe3 --- /dev/null +++ b/netui/ant/webappTemplate.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Create NetUI Webapp in: ${webapp.dir} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Deploy the NetUI runtime to webapp rooted at: ${webapp.dir} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Deploy Struts 1.2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/netui/build.xml b/netui/build.xml new file mode 100644 index 0000000..10999ed --- /dev/null +++ b/netui/build.xml @@ -0,0 +1,284 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Deploy NetUI to webapp rooted at: ${webapp.dir} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/netui/docs/external/xalan.jar b/netui/docs/external/xalan.jar new file mode 100644 index 0000000..46f3383 Binary files /dev/null and b/netui/docs/external/xalan.jar differ diff --git a/netui/docs/testresults.html b/netui/docs/testresults.html new file mode 100644 index 0000000..25f63a1 --- /dev/null +++ b/netui/docs/testresults.html @@ -0,0 +1,38 @@ + + + NetUI Test Results + + + +NetUI Test Results +

    +DRTs +

    +Note, the JUnit test results above will only be created when running DRTs. The output files for the BVTs are linked below. +

    +

    +
    +BVTs
    +

    +

    + + diff --git a/netui/docs/tools/README.txt b/netui/docs/tools/README.txt new file mode 100644 index 0000000..a727ae9 --- /dev/null +++ b/netui/docs/tools/README.txt @@ -0,0 +1,86 @@ +Custom Doclet: JSP Tag Library Reference +---------------------------------------- + +This document describes how the JSP Tag Library Reference is generated using a custom doclet. + +Introduction +------------ + +The custom doclet was created especially for JSP tag library documentation. +From a JSP tag-user perspective, standard Javadoc can be difficult to read: standard javadoc +output contains too many implementation details and the information that the tag-user is +looking for often gets lost in the thicket of information. + +To solve this problem, the custom doclet generates HTML topics oriented specifically for the tag-user: +They include (1) a syntax section that describes the JSP tag's syntax, (2) an attributes section which describes +how each JSP tag attribute works, and (3) an example section that shows the JSP tag in action on a JSP page. + +Custom Doclet Files +------------------- + +The custom doclet files are contained in the JAR file BEEHIVE_HOME/netui/docs/tools/lib/jsptagrefdoclet.jar. +This JAR file contains the following resources: + +(1) Doclet classes that extend the Javadoc API. (The source code for these classes will be posted in the Apache Commons project at a later date.) + +(2) Static HTML and CSS files. + +(3) XML stylesheets (XSTL files) that convert XML files into HTML files. + +How the Custom Doclet Works +--------------------------- + +The doclet generates HTML documentation in two stages. + + ----- ----- ----- + | | | | | | + | | ---(1)---> | | ---(2)---> | | + | | | | | | + ----- ----- ----- + + JAVA tag XML files HTML topics + handler classes + + (1) First XML documents are constructed from the javadoc content in the Java source files (= the tag handler classes). + (2) HTML topics are constructed from the XML documents. + +In the XML-generating step, the doclet makes one XML document for each Java tag handler class. +The doclet reads content from the @jsptagref.xxx javadoc annotations in the Java source files, +and creates an XML document from the content. + +For example, here is a snippet from the tag handler class Anchor.java, which handles the JSP tag. + + * @jsptagref.tagdescription + *

    + * Generates an anchor that can link... + +The doclet reads this content, and constructs the following XML snippet. + + + + <p>Generates an anchor that can link... + +In the HTML-generating step, XML stylesheets (XSLT files) are used to construct HTML topics based on +the XML files. The stylesheets map the content in the XML files into HTML files. +The following diagram shows how the stylesheets divide up the real estate in the HTML pages. + + -------------------------- + | | | + | | | + taglib-overview-frame.xslt --> | | | + | | | + -------- | + | | | + | | | + | | | <--- taglib-overview-summary.xslt + | | | <--- taglib-summary.xslt + all-tablibs-frame.xslt ---> | | | <--- tag_topics.xslt + taglib-frame.xslt ---> | | | + | | | + | | | + | | | + | | | + | | | + -------------------------- + + diff --git a/netui/docs/tools/lib/jsptagrefdoclet_single.jar b/netui/docs/tools/lib/jsptagrefdoclet_single.jar new file mode 100644 index 0000000..17c896a Binary files /dev/null and b/netui/docs/tools/lib/jsptagrefdoclet_single.jar differ diff --git a/netui/external/commons-collections/commons-collections.jar b/netui/external/commons-collections/commons-collections.jar new file mode 100644 index 0000000..3272f2b Binary files /dev/null and b/netui/external/commons-collections/commons-collections.jar differ diff --git a/netui/external/commons-el/commons-el.jar b/netui/external/commons-el/commons-el.jar new file mode 100644 index 0000000..608ed79 Binary files /dev/null and b/netui/external/commons-el/commons-el.jar differ diff --git a/netui/external/jsf/myfaces-1.0.9/lib/myfaces-extensions.jar b/netui/external/jsf/myfaces-1.0.9/lib/myfaces-extensions.jar new file mode 100644 index 0000000..22745c7 Binary files /dev/null and b/netui/external/jsf/myfaces-1.0.9/lib/myfaces-extensions.jar differ diff --git a/netui/external/jsf/myfaces-1.0.9/lib/myfaces-impl.jar b/netui/external/jsf/myfaces-1.0.9/lib/myfaces-impl.jar new file mode 100644 index 0000000..16f528a Binary files /dev/null and b/netui/external/jsf/myfaces-1.0.9/lib/myfaces-impl.jar differ diff --git a/netui/external/jsf/myfaces-1.0.9/lib/myfaces-jsf-api.jar b/netui/external/jsf/myfaces-1.0.9/lib/myfaces-jsf-api.jar new file mode 100644 index 0000000..44c8d03 Binary files /dev/null and b/netui/external/jsf/myfaces-1.0.9/lib/myfaces-jsf-api.jar differ diff --git a/netui/external/jsf/myfaces-1.0.9/lib/myfaces.jar b/netui/external/jsf/myfaces-1.0.9/lib/myfaces.jar new file mode 100644 index 0000000..85dc1d4 Binary files /dev/null and b/netui/external/jsf/myfaces-1.0.9/lib/myfaces.jar differ diff --git a/netui/external/jstl/jstl.jar b/netui/external/jstl/jstl.jar new file mode 100644 index 0000000..6b41358 Binary files /dev/null and b/netui/external/jstl/jstl.jar differ diff --git a/netui/external/jstl/standard.jar b/netui/external/jstl/standard.jar new file mode 100644 index 0000000..258daae Binary files /dev/null and b/netui/external/jstl/standard.jar differ diff --git a/netui/external/struts/LICENSE b/netui/external/struts/LICENSE new file mode 100644 index 0000000..dd5b3a5 --- /dev/null +++ b/netui/external/struts/LICENSE @@ -0,0 +1,174 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. diff --git a/netui/external/struts/NOTICE b/netui/external/struts/NOTICE new file mode 100644 index 0000000..2dcd61c --- /dev/null +++ b/netui/external/struts/NOTICE @@ -0,0 +1,7 @@ +This product includes software developed by +The Apache Software Foundation (http://www.apache.org/). + +This product includes the ANTLR parsing library, +developed by JGuru.com (http://www.antlr.org and +http://www.jguru.com). + diff --git a/netui/external/struts/antlr.jar b/netui/external/struts/antlr.jar new file mode 100644 index 0000000..8850fc6 Binary files /dev/null and b/netui/external/struts/antlr.jar differ diff --git a/netui/external/struts/commons-beanutils.jar b/netui/external/struts/commons-beanutils.jar new file mode 100644 index 0000000..b1b89c9 Binary files /dev/null and b/netui/external/struts/commons-beanutils.jar differ diff --git a/netui/external/struts/commons-digester.jar b/netui/external/struts/commons-digester.jar new file mode 100644 index 0000000..9765493 Binary files /dev/null and b/netui/external/struts/commons-digester.jar differ diff --git a/netui/external/struts/commons-fileupload.jar b/netui/external/struts/commons-fileupload.jar new file mode 100644 index 0000000..1ca4a9c Binary files /dev/null and b/netui/external/struts/commons-fileupload.jar differ diff --git a/netui/external/struts/commons-logging.jar b/netui/external/struts/commons-logging.jar new file mode 100644 index 0000000..b73a80f Binary files /dev/null and b/netui/external/struts/commons-logging.jar differ diff --git a/netui/external/struts/commons-validator.jar b/netui/external/struts/commons-validator.jar new file mode 100644 index 0000000..bf76e86 Binary files /dev/null and b/netui/external/struts/commons-validator.jar differ diff --git a/netui/external/struts/jakarta-oro.jar b/netui/external/struts/jakarta-oro.jar new file mode 100644 index 0000000..ed6c60a Binary files /dev/null and b/netui/external/struts/jakarta-oro.jar differ diff --git a/netui/external/struts/legacy/jakarta-struts-1.1-lib/LICENSE b/netui/external/struts/legacy/jakarta-struts-1.1-lib/LICENSE new file mode 100644 index 0000000..e64cba8 --- /dev/null +++ b/netui/external/struts/legacy/jakarta-struts-1.1-lib/LICENSE @@ -0,0 +1,65 @@ +/* + * $Header: /home/cvs/jakarta-struts/LICENSE,v 1.2 2001/02/02 00:38:31 craigmcc Exp $ + * $Revision: 1.2 $ + * $Date: 2001/02/02 00:38:31 $ + * + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999-2001 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Struts", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + + + + + diff --git a/netui/external/struts/legacy/jakarta-struts-1.1-lib/commons-beanutils.jar b/netui/external/struts/legacy/jakarta-struts-1.1-lib/commons-beanutils.jar new file mode 100644 index 0000000..795655a Binary files /dev/null and b/netui/external/struts/legacy/jakarta-struts-1.1-lib/commons-beanutils.jar differ diff --git a/netui/external/struts/legacy/jakarta-struts-1.1-lib/commons-collections.jar b/netui/external/struts/legacy/jakarta-struts-1.1-lib/commons-collections.jar new file mode 100644 index 0000000..f66c6d2 Binary files /dev/null and b/netui/external/struts/legacy/jakarta-struts-1.1-lib/commons-collections.jar differ diff --git a/netui/external/struts/legacy/jakarta-struts-1.1-lib/commons-digester.jar b/netui/external/struts/legacy/jakarta-struts-1.1-lib/commons-digester.jar new file mode 100644 index 0000000..c2a7d9d Binary files /dev/null and b/netui/external/struts/legacy/jakarta-struts-1.1-lib/commons-digester.jar differ diff --git a/netui/external/struts/legacy/jakarta-struts-1.1-lib/commons-fileupload.jar b/netui/external/struts/legacy/jakarta-struts-1.1-lib/commons-fileupload.jar new file mode 100644 index 0000000..1ca4a9c Binary files /dev/null and b/netui/external/struts/legacy/jakarta-struts-1.1-lib/commons-fileupload.jar differ diff --git a/netui/external/struts/legacy/jakarta-struts-1.1-lib/commons-lang.jar b/netui/external/struts/legacy/jakarta-struts-1.1-lib/commons-lang.jar new file mode 100644 index 0000000..37ddb9b Binary files /dev/null and b/netui/external/struts/legacy/jakarta-struts-1.1-lib/commons-lang.jar differ diff --git a/netui/external/struts/legacy/jakarta-struts-1.1-lib/commons-logging.jar b/netui/external/struts/legacy/jakarta-struts-1.1-lib/commons-logging.jar new file mode 100644 index 0000000..b99c937 Binary files /dev/null and b/netui/external/struts/legacy/jakarta-struts-1.1-lib/commons-logging.jar differ diff --git a/netui/external/struts/legacy/jakarta-struts-1.1-lib/commons-validator.jar b/netui/external/struts/legacy/jakarta-struts-1.1-lib/commons-validator.jar new file mode 100644 index 0000000..096a7f4 Binary files /dev/null and b/netui/external/struts/legacy/jakarta-struts-1.1-lib/commons-validator.jar differ diff --git a/netui/external/struts/legacy/jakarta-struts-1.1-lib/jakarta-oro.jar b/netui/external/struts/legacy/jakarta-struts-1.1-lib/jakarta-oro.jar new file mode 100644 index 0000000..346504c Binary files /dev/null and b/netui/external/struts/legacy/jakarta-struts-1.1-lib/jakarta-oro.jar differ diff --git a/netui/external/struts/legacy/jakarta-struts-1.1-lib/struts-bean.tld b/netui/external/struts/legacy/jakarta-struts-1.1-lib/struts-bean.tld new file mode 100644 index 0000000..7dfc6bd --- /dev/null +++ b/netui/external/struts/legacy/jakarta-struts-1.1-lib/struts-bean.tld @@ -0,0 +1,382 @@ + + + + + + + + + + +1.0 +1.1 +bean +http://jakarta.apache.org/struts/tags-bean + +cookie +org.apache.struts.taglib.bean.CookieTag +org.apache.struts.taglib.bean.CookieTei +empty + +id +true +false + + +multiple +false +true + + +name +true +true + + +value +false +true + + + +define +org.apache.struts.taglib.bean.DefineTag +org.apache.struts.taglib.bean.DefineTei +JSP + +id +true +false + + +name +false +true + + +property +false +true + + +scope +false +true + + +toScope +false +true + + +type +false +true + + +value +false +true + + + +header +org.apache.struts.taglib.bean.HeaderTag +org.apache.struts.taglib.bean.HeaderTei +empty + +id +true +false + + +multiple +false +true + + +name +true +true + + +value +false +true + + + +include +org.apache.struts.taglib.bean.IncludeTag +org.apache.struts.taglib.bean.IncludeTei +empty + +anchor +false +true + + +forward +false +true + + +href +false +true + + +id +true +false + + +name +false +true + + +page +false +true + + +transaction +false +true + + + +message +org.apache.struts.taglib.bean.MessageTag +empty + +arg0 +false +true + + +arg1 +false +true + + +arg2 +false +true + + +arg3 +false +true + + +arg4 +false +true + + +bundle +false +true + + +key +false +true + + +locale +false +true + + +name +false +true + + +property +false +true + + +scope +false +true + + + +page +org.apache.struts.taglib.bean.PageTag +org.apache.struts.taglib.bean.PageTei +empty + +id +true +false + + +property +true +true + + + +parameter +org.apache.struts.taglib.bean.ParameterTag +org.apache.struts.taglib.bean.ParameterTei +empty + +id +true +false + + +multiple +false +true + + +name +true +true + + +value +false +true + + + +resource +org.apache.struts.taglib.bean.ResourceTag +org.apache.struts.taglib.bean.ResourceTei +empty + +id +true +false + + +input +false +true + + +name +true +true + + + +size +org.apache.struts.taglib.bean.SizeTag +org.apache.struts.taglib.bean.SizeTei +empty + +collection +false +true + + +id +true +false + + +name +false +true + + +property +false +true + + +scope +false +true + + + +struts +org.apache.struts.taglib.bean.StrutsTag +org.apache.struts.taglib.bean.StrutsTei +empty + +id +true +false + + +formBean +false +true + + +forward +false +true + + +mapping +false +true + + + +write +org.apache.struts.taglib.bean.WriteTag +empty + +bundle +false +true + + +filter +false +true + + +format +false +true + + +formatKey +false +true + + +ignore +false +true + + +locale +false +true + + +name +true +true + + +property +false +true + + +scope +false +true + + + + + + diff --git a/netui/external/struts/legacy/jakarta-struts-1.1-lib/struts-config_1_0.dtd b/netui/external/struts/legacy/jakarta-struts-1.1-lib/struts-config_1_0.dtd new file mode 100644 index 0000000..d6a28f6 --- /dev/null +++ b/netui/external/struts/legacy/jakarta-struts-1.1-lib/struts-config_1_0.dtd @@ -0,0 +1,408 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/netui/external/struts/legacy/jakarta-struts-1.1-lib/struts-config_1_1.dtd b/netui/external/struts/legacy/jakarta-struts-1.1-lib/struts-config_1_1.dtd new file mode 100644 index 0000000..2fbd9f7 --- /dev/null +++ b/netui/external/struts/legacy/jakarta-struts-1.1-lib/struts-config_1_1.dtd @@ -0,0 +1,697 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/netui/external/struts/legacy/jakarta-struts-1.1-lib/struts-html.tld b/netui/external/struts/legacy/jakarta-struts-1.1-lib/struts-html.tld new file mode 100644 index 0000000..9087060 --- /dev/null +++ b/netui/external/struts/legacy/jakarta-struts-1.1-lib/struts-html.tld @@ -0,0 +1,2972 @@ + + + + + + + + + + +1.0 +1.1 +html +http://jakarta.apache.org/struts/tags-html + +base +org.apache.struts.taglib.html.BaseTag +empty + +target +false +true + + +server +false +true + + + +button +org.apache.struts.taglib.html.ButtonTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +disabled +false +true + + +indexed +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +cancel +org.apache.struts.taglib.html.CancelTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +disabled +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +checkbox +org.apache.struts.taglib.html.CheckboxTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +disabled +false +true + + +indexed +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +errors +org.apache.struts.taglib.html.ErrorsTag +empty + +bundle +false +true + + +locale +false +true + + +name +false +true + + +property +false +true + + + +file +org.apache.struts.taglib.html.FileTag + +accesskey +false +true + + +accept +false +true + + +alt +false +true + + +altKey +false +true + + +disabled +false +true + + +indexed +false +true + + +maxlength +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +size +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +form +org.apache.struts.taglib.html.FormTag +JSP + +action +true +true + + +enctype +false +true + + +focus +false +true + + +focusIndex +false +true + + +method +false +true + + +name +false +true + + +onreset +false +true + + +onsubmit +false +true + + +scope +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +target +false +true + + +type +false +true + + + +frame +org.apache.struts.taglib.html.FrameTag + +action +false +true + + +anchor +false +true + + +forward +false +true + + +frameborder +false +true + + +frameName +false +true + + +href +false +true + + +longdesc +false +true + + +marginheight +false +true + + +marginwidth +false +true + + +name +false +true + + +noresize +false +true + + +page +false +true + + +paramId +false +true + + +paramName +false +true + + +paramProperty +false +true + + +paramScope +false +true + + +property +false +true + + +scope +false +true + + +scrolling +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +title +false +true + + +titleKey +false +true + + +transaction +false +true + + + +hidden +org.apache.struts.taglib.html.HiddenTag +empty + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +indexed +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + +write +false +true + + + +html +org.apache.struts.taglib.html.HtmlTag +JSP + +locale +false +true + + +xhtml +false +true + + + +image +org.apache.struts.taglib.html.ImageTag + +accesskey +false +true + + +align +false +true + + +alt +false +true + + +altKey +false +true + + +border +false +true + + +bundle +false +true + + +disabled +false +true + + +indexed +false +true + + +locale +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +page +false +true + + +pageKey +false +true + + +property +false +true + + +src +false +true + + +srcKey +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +img +org.apache.struts.taglib.html.ImgTag +empty + +align +false +true + + +alt +false +true + + +altKey +false +true + + +border +false +true + + +bundle +false +true + + +height +false +true + + +hspace +false +true + + +imageName +false +true + + +ismap +false +true + + +locale +false +true + + +lowsrc +false +true + + +name +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +paramId +false +true + + +page +false +true + + +pageKey +false +true + + +paramName +false +true + + +paramProperty +false +true + + +paramScope +false +true + + +property +false +true + + +scope +false +true + + +src +false +true + + +srcKey +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +title +false +true + + +titleKey +false +true + + +usemap +false +true + + +vspace +false +true + + +width +false +true + + + +javascript +org.apache.struts.taglib.html.JavascriptValidatorTag +empty + +cdata +false +true + + +dynamicJavascript +false +false + + +formName +false +true + + +method +false +true + + +page +false +true + + +src +false +true + + +staticJavascript +false +false + + +htmlComment +false +true + + + +link +org.apache.struts.taglib.html.LinkTag + +accesskey +false +true + + +action +false +true + + +anchor +false +true + + +forward +false +true + + +href +false +true + + +indexed +false +true + + +indexId +false +true + + +linkName +false +true + + +name +false +true + + +onblur +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +page +false +true + + +paramId +false +true + + +paramName +false +true + + +paramProperty +false +true + + +paramScope +false +true + + +property +false +true + + +scope +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +target +false +true + + +title +false +true + + +titleKey +false +true + + +transaction +false +true + + + +messages +org.apache.struts.taglib.html.MessagesTag +org.apache.struts.taglib.html.MessagesTei +JSP + +id +true +false + + +bundle +false +true + + +locale +false +true + + +name +false +true + + +property +false +true + + +header +false +true + + +footer +false +true + + +message +false +true + + + +multibox +org.apache.struts.taglib.html.MultiboxTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +disabled +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +option +org.apache.struts.taglib.html.OptionTag + +bundle +false +true + + +disabled +false +true + + +key +false +true + + +locale +false +true + + +style +false +true + + +styleId +false +true + + +styleClass +false +true + + +value +true +true + + + +options +org.apache.struts.taglib.html.OptionsTag +empty + +collection +false +true + + +filter +false +true + + +labelName +false +true + + +labelProperty +false +true + + +name +false +true + + +property +false +true + + +style +false +true + + +styleClass +false +true + + + +optionsCollection +org.apache.struts.taglib.html.OptionsCollectionTag +empty + +filter +false +true + + +label +false +true + + +name +false +true + + +property +false +true + + +style +false +true + + +styleClass +false +true + + +value +false +true + + + +password +org.apache.struts.taglib.html.PasswordTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +disabled +false +true + + +indexed +false +true + + +maxlength +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +readonly +false +true + + +redisplay +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +size +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +radio +org.apache.struts.taglib.html.RadioTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +disabled +false +true + + +indexed +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +property +true +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +true +true + + +idName +false +true + + + +reset +org.apache.struts.taglib.html.ResetTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +disabled +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +rewrite +org.apache.struts.taglib.html.RewriteTag +empty + +anchor +false +true + + +forward +false +true + + +href +false +true + + +name +false +true + + +page +false +true + + +paramId +false +true + + +paramName +false +true + + +paramProperty +false +true + + +paramScope +false +true + + +property +false +true + + +scope +false +true + + +transaction +false +true + + + +select +org.apache.struts.taglib.html.SelectTag +JSP + +alt +false +true + + +altKey +false +true + + +disabled +false +true + + +indexed +false +true + + +multiple +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +size +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +submit +org.apache.struts.taglib.html.SubmitTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +disabled +false +true + + +indexed +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +text +org.apache.struts.taglib.html.TextTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +disabled +false +true + + +indexed +false +true + + +maxlength +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +readonly +false +true + + +size +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +textarea +org.apache.struts.taglib.html.TextareaTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +cols +false +true + + +disabled +false +true + + +indexed +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +readonly +false +true + + +rows +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +xhtml +org.apache.struts.taglib.html.XhtmlTag +empty + + + diff --git a/netui/external/struts/legacy/jakarta-struts-1.1-lib/struts-legacy.jar b/netui/external/struts/legacy/jakarta-struts-1.1-lib/struts-legacy.jar new file mode 100644 index 0000000..a642acb Binary files /dev/null and b/netui/external/struts/legacy/jakarta-struts-1.1-lib/struts-legacy.jar differ diff --git a/netui/external/struts/legacy/jakarta-struts-1.1-lib/struts-logic.tld b/netui/external/struts/legacy/jakarta-struts-1.1-lib/struts-logic.tld new file mode 100644 index 0000000..1975973 --- /dev/null +++ b/netui/external/struts/legacy/jakarta-struts-1.1-lib/struts-logic.tld @@ -0,0 +1,642 @@ + + + + + + + + + +1.0 +1.1 +logic +http://jakarta.apache.org/struts/tags-logic + +empty +org.apache.struts.taglib.logic.EmptyTag +JSP + +name +false +true + + +property +false +true + + +scope +false +true + + + +equal +org.apache.struts.taglib.logic.EqualTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +forward +org.apache.struts.taglib.logic.ForwardTag +empty + +name +true +true + + + +greaterEqual +org.apache.struts.taglib.logic.GreaterEqualTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +greaterThan +org.apache.struts.taglib.logic.GreaterThanTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +iterate +org.apache.struts.taglib.logic.IterateTag +org.apache.struts.taglib.logic.IterateTei +JSP + +collection +false +true + + +id +true +false + + +indexId +false +false + + +length +false +true + + +name +false +true + + +offset +false +true + + +property +false +true + + +scope +false +true + + +type +false +true + + + +lessEqual +org.apache.struts.taglib.logic.LessEqualTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +lessThan +org.apache.struts.taglib.logic.LessThanTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +match +org.apache.struts.taglib.logic.MatchTag +JSP + +cookie +false +true + + +header +false +true + + +location +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +messagesNotPresent +org.apache.struts.taglib.logic.MessagesNotPresentTag +JSP + +name +false +true + + +property +false +true + + +message +false +true + + + +messagesPresent +org.apache.struts.taglib.logic.MessagesPresentTag +JSP + +name +false +true + + +property +false +true + + +message +false +true + + + +notEmpty +org.apache.struts.taglib.logic.NotEmptyTag +JSP + +name +false +true + + +property +false +true + + +scope +false +true + + + +notEqual +org.apache.struts.taglib.logic.NotEqualTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +notMatch +org.apache.struts.taglib.logic.NotMatchTag +JSP + +cookie +false +true + + +header +false +true + + +location +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +notPresent +org.apache.struts.taglib.logic.NotPresentTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +role +false +true + + +scope +false +true + + +user +false +true + + + +present +org.apache.struts.taglib.logic.PresentTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +role +false +true + + +scope +false +true + + +user +false +true + + + +redirect +org.apache.struts.taglib.logic.RedirectTag + +anchor +false +true + + +forward +false +true + + +href +false +true + + +name +false +true + + +page +false +true + + +paramId +false +true + + +paramName +false +true + + +paramProperty +false +true + + +paramScope +false +true + + +property +false +true + + +scope +false +true + + +transaction +false +true + + + + + + diff --git a/netui/external/struts/legacy/jakarta-struts-1.1-lib/struts-nested.tld b/netui/external/struts/legacy/jakarta-struts-1.1-lib/struts-nested.tld new file mode 100644 index 0000000..29bf792 --- /dev/null +++ b/netui/external/struts/legacy/jakarta-struts-1.1-lib/struts-nested.tld @@ -0,0 +1,2870 @@ + + + + + + + + + +1.0 +1.1 +nested +http://jakarta.apache.org/struts/tags-nested + +nest +org.apache.struts.taglib.nested.NestedPropertyTag +JSP + +property +false +true + + + +writeNesting +org.apache.struts.taglib.nested.NestedWriteNestingTag +JSP + +property +false +true + + +filter +false +true + + + +root +org.apache.struts.taglib.nested.NestedRootTag +JSP + +name +false +true + + + +define +org.apache.struts.taglib.nested.bean.NestedDefineTag +org.apache.struts.taglib.nested.bean.NestedDefineTei +empty + +id +true +true + + +name +false +true + + +property +false +true + + +scope +false +true + + +toScope +false +true + + +type +false +true + + +value +false +true + + + +message +org.apache.struts.taglib.nested.bean.NestedMessageTag +empty + +arg0 +false +true + + +arg1 +false +true + + +arg2 +false +true + + +arg3 +false +true + + +arg4 +false +true + + +bundle +false +true + + +key +false +true + + +locale +false +true + + +name +false +true + + +property +false +true + + +scope +false +true + + + +size +org.apache.struts.taglib.nested.bean.NestedSizeTag +org.apache.struts.taglib.bean.SizeTei +empty + +collection +false +true + + +id +true +true + + +name +false +true + + +property +false +true + + +scope +false +true + + + +write +org.apache.struts.taglib.nested.bean.NestedWriteTag +empty + +bundle +false +true + + +filter +false +true + + +format +false +true + + +formatKey +false +true + + +ignore +false +true + + +locale +false +true + + +name +false +true + + +property +false +true + + +scope +false +true + + + +checkbox +org.apache.struts.taglib.nested.html.NestedCheckboxTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +disabled +false +true + + +indexed +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +errors +org.apache.struts.taglib.nested.html.NestedErrorsTag +empty + +bundle +false +true + + +locale +false +true + + +name +false +true + + +property +false +true + + + +file +org.apache.struts.taglib.nested.html.NestedFileTag + +accesskey +false +true + + +accept +false +true + + +alt +false +true + + +altKey +false +true + + +disabled +false +true + + +indexed +false +true + + +maxlength +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +size +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +form +org.apache.struts.taglib.nested.html.NestedFormTag +JSP + +action +true +true + + +enctype +false +true + + +focus +false +true + + +method +false +true + + +name +false +true + + +onreset +false +true + + +onsubmit +false +true + + +scope +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +target +false +true + + +type +false +true + + + +hidden +org.apache.struts.taglib.nested.html.NestedHiddenTag + +alt +false +true + + +altKey +false +true + + +indexed +false +true + + +name +false +true + + +property +true +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +image +org.apache.struts.taglib.nested.html.NestedImageTag + +accesskey +false +true + + +align +false +true + + +alt +false +true + + +altKey +false +true + + +border +false +true + + +bundle +false +true + + +disabled +false +true + + +indexed +false +true + + +locale +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +page +false +true + + +pageKey +false +true + + +property +false +true + + +src +false +true + + +srcKey +false +true + + +style +false +true + + +styleClass +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +img +org.apache.struts.taglib.nested.html.NestedImgTag +empty + +accesskey +false +true + + +align +false +true + + +alt +false +true + + +altKey +false +true + + +border +false +true + + +bundle +false +true + + +height +false +true + + +hspace +false +true + + +imageName +false +true + + +ismap +false +true + + +locale +false +true + + +lowsrc +false +true + + +name +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +paramId +false +true + + +page +false +true + + +pageKey +false +true + + +paramName +false +true + + +paramProperty +false +true + + +paramScope +false +true + + +property +false +true + + +scope +false +true + + +src +false +true + + +srcKey +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +title +false +true + + +titleKey +false +true + + +usemap +false +true + + +vspace +false +true + + +width +false +true + + + +link +org.apache.struts.taglib.nested.html.NestedLinkTag + +accesskey +false +true + + +action +false +true + + +anchor +false +true + + +forward +false +true + + +href +false +true + + +indexed +false +true + + +indexId +false +true + + +linkName +false +true + + +name +false +true + + +onblur +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +page +false +true + + +paramId +false +true + + +paramName +false +true + + +paramProperty +false +true + + +paramScope +false +true + + +property +false +true + + +scope +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +target +false +true + + +title +false +true + + +titleKey +false +true + + +transaction +false +true + + + +messages +org.apache.struts.taglib.nested.html.NestedMessagesTag +org.apache.struts.taglib.html.MessagesTei +JSP + +id +true +true + + +bundle +false +true + + +locale +false +true + + +name +false +true + + +property +false +true + + +header +false +true + + +footer +false +true + + +message +false +true + + + +multibox +org.apache.struts.taglib.nested.html.NestedMultiboxTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +disabled +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +options +org.apache.struts.taglib.nested.html.NestedOptionsTag +empty + +collection +false +true + + +labelName +false +true + + +labelProperty +false +true + + +name +false +true + + +property +false +true + + +style +false +true + + +styleClass +false +true + + + +optionsCollection +org.apache.struts.taglib.nested.html.NestedOptionsCollectionTag +empty + +label +false +true + + +name +false +true + + +property +true +true + + +style +false +true + + +styleClass +false +true + + +value +false +true + + + +password +org.apache.struts.taglib.nested.html.NestedPasswordTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +disabled +false +true + + +indexed +false +true + + +maxlength +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +readonly +false +true + + +redisplay +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +size +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +radio +org.apache.struts.taglib.nested.html.NestedRadioTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +disabled +false +true + + +indexed +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +property +true +true + + +onmousedown +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +true +true + + + +select +org.apache.struts.taglib.nested.html.NestedSelectTag +JSP + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +disabled +false +true + + +indexed +false +true + + +multiple +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +size +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +submit +org.apache.struts.taglib.nested.html.NestedSubmitTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +disabled +false +true + + +indexed +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +text +org.apache.struts.taglib.nested.html.NestedTextTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +disabled +false +true + + +indexed +false +true + + +maxlength +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +readonly +false +true + + +size +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +textarea +org.apache.struts.taglib.nested.html.NestedTextareaTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +cols +false +true + + +disabled +false +true + + +indexed +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +readonly +false +true + + +rows +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +empty +org.apache.struts.taglib.nested.logic.NestedEmptyTag +JSP + +name +false +true + + +property +false +true + + +scope +false +true + + + +equal +org.apache.struts.taglib.nested.logic.NestedEqualTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +greaterEqual +org.apache.struts.taglib.nested.logic.NestedGreaterEqualTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +greaterThan +org.apache.struts.taglib.nested.logic.NestedGreaterThanTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +iterate +org.apache.struts.taglib.nested.logic.NestedIterateTag +org.apache.struts.taglib.nested.logic.NestedIterateTei +JSP + +collection +false +true + + +id +false +true + + +indexId +false +true + + +length +false +true + + +name +false +true + + +offset +false +true + + +property +false +true + + +scope +false +true + + +type +false +true + + + +lessEqual +org.apache.struts.taglib.nested.logic.NestedLessEqualTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +lessThan +org.apache.struts.taglib.nested.logic.NestedLessThanTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +match +org.apache.struts.taglib.nested.logic.NestedMatchTag +JSP + +cookie +false +true + + +header +false +true + + +location +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +messagesNotPresent +org.apache.struts.taglib.nested.logic.NestedMessagesNotPresentTag +JSP + +name +false +true + + +property +false +true + + +message +false +true + + + +messagesPresent +org.apache.struts.taglib.nested.logic.NestedMessagesPresentTag +JSP + +name +false +true + + +property +false +true + + +message +false +true + + + +notEmpty +org.apache.struts.taglib.nested.logic.NestedNotEmptyTag +JSP + +name +false +true + + +property +false +true + + +scope +false +true + + + +notEqual +org.apache.struts.taglib.nested.logic.NestedNotEqualTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +notMatch +org.apache.struts.taglib.nested.logic.NestedNotMatchTag +JSP + +cookie +false +true + + +header +false +true + + +location +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +notPresent +org.apache.struts.taglib.nested.logic.NestedNotPresentTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +role +false +true + + +scope +false +true + + +user +false +true + + + +present +org.apache.struts.taglib.nested.logic.NestedPresentTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +role +false +true + + +scope +false +true + + +user +false +true + + + + + + diff --git a/netui/external/struts/legacy/jakarta-struts-1.1-lib/struts-template.tld b/netui/external/struts/legacy/jakarta-struts-1.1-lib/struts-template.tld new file mode 100644 index 0000000..f8fbe99 --- /dev/null +++ b/netui/external/struts/legacy/jakarta-struts-1.1-lib/struts-template.tld @@ -0,0 +1,73 @@ + + + + + + + + + + +1.0 +1.1 +template +http://jakarta.apache.org/struts/tags-template + +insert +org.apache.struts.taglib.template.InsertTag +JSP + +template +true +true + + + +put +org.apache.struts.taglib.template.PutTag +JSP + +name +true +true + + +role +false +true + + +content +false +true + + +direct +false +true + + + +get +org.apache.struts.taglib.template.GetTag +empty + +flush +false +true + + +name +true +true + + +role +false +true + + + + + + diff --git a/netui/external/struts/legacy/jakarta-struts-1.1-lib/struts-tiles.tld b/netui/external/struts/legacy/jakarta-struts-1.1-lib/struts-tiles.tld new file mode 100644 index 0000000..e70d3ce --- /dev/null +++ b/netui/external/struts/legacy/jakarta-struts-1.1-lib/struts-tiles.tld @@ -0,0 +1,344 @@ + + + + + + + + + + +1.0 +1.1 +tiles +http://jakarta.apache.org/struts/tags-tiles + +insert +org.apache.struts.taglib.tiles.InsertTag +JSP + +template +false +true + + +component +false +true + + +page +false +true + + +definition +false +true + + +attribute +false +false + + +name +false +true + + +beanName +false +true + + +beanProperty +false +true + + +beanScope +false +false + + +flush +false +false + + +ignore +false +true + + +role +false +true + + +controllerUrl +false +true + + +controllerClass +false +true + + + +definition +org.apache.struts.taglib.tiles.DefinitionTag +JSP + +id +true +false + + +scope +false +false + + +template +false +true + + +page +false +true + + +role +false +true + + +extends +false +true + + + +put +org.apache.struts.taglib.tiles.PutTag +JSP + +name +false +false + + +value +false +true + + +content +false +true + + +direct +false +false + + +type +false +false + + +beanName +false +true + + +beanProperty +false +true + + +beanScope +false +false + + +role +false +true + + + +putList +org.apache.struts.taglib.tiles.PutListTag +JSP + +name +true +false + + + +add +org.apache.struts.taglib.tiles.AddTag +JSP + +value +false +false + + +content +false +true + + +direct +false +false + + +type +false +false + + +beanName +false +true + + +beanProperty +false +true + + +beanScope +false +false + + +role +false +true + + + +get +org.apache.struts.taglib.tiles.GetTag +empty + +name +true +true + + +ignore +false +true + + +flush +false +false + + +role +false +true + + + +getAsString +org.apache.struts.taglib.tiles.GetAttributeTag +empty + +name +true +true + + +ignore +false +true + + +role +false +true + + + +useAttribute +org.apache.struts.taglib.tiles.UseAttributeTag +org.apache.struts.taglib.tiles.UseAttributeTei +empty + +id +false +false + + +classname +false +false + + +scope +false +false + + +name +true +true + + +ignore +false +true + + + +importAttribute +org.apache.struts.taglib.tiles.ImportAttributeTag +empty + +name +false +true + + +scope +false +false + + +ignore +false +true + + + +initComponentDefinitions +org.apache.struts.taglib.tiles.InitDefinitionsTag +empty + +file +true +false + + +classname +false +false + + + + + + diff --git a/netui/external/struts/legacy/jakarta-struts-1.1-lib/struts.jar b/netui/external/struts/legacy/jakarta-struts-1.1-lib/struts.jar new file mode 100644 index 0000000..db32f9f Binary files /dev/null and b/netui/external/struts/legacy/jakarta-struts-1.1-lib/struts.jar differ diff --git a/netui/external/struts/legacy/jakarta-struts-1.1-lib/tiles-config.dtd b/netui/external/struts/legacy/jakarta-struts-1.1-lib/tiles-config.dtd new file mode 100644 index 0000000..9d53d53 --- /dev/null +++ b/netui/external/struts/legacy/jakarta-struts-1.1-lib/tiles-config.dtd @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/netui/external/struts/legacy/jakarta-struts-1.1-lib/tiles-config_1_1.dtd b/netui/external/struts/legacy/jakarta-struts-1.1-lib/tiles-config_1_1.dtd new file mode 100644 index 0000000..646759c --- /dev/null +++ b/netui/external/struts/legacy/jakarta-struts-1.1-lib/tiles-config_1_1.dtd @@ -0,0 +1,281 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/netui/external/struts/legacy/jakarta-struts-1.1-lib/validation_1_1.dtd b/netui/external/struts/legacy/jakarta-struts-1.1-lib/validation_1_1.dtd new file mode 100644 index 0000000..8c7a9d4 --- /dev/null +++ b/netui/external/struts/legacy/jakarta-struts-1.1-lib/validation_1_1.dtd @@ -0,0 +1,251 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/netui/external/struts/legacy/jakarta-struts-1.1-lib/validator-rules.xml b/netui/external/struts/legacy/jakarta-struts-1.1-lib/validator-rules.xml new file mode 100644 index 0000000..de8e3fa --- /dev/null +++ b/netui/external/struts/legacy/jakarta-struts-1.1-lib/validator-rules.xml @@ -0,0 +1,1044 @@ + + + + + + + + + + = 0) { + value = field.options[si].value; + } + } else { + value = field.value; + } + + if (trim(value).length == 0) { + + if (i == 0) { + focusField = field; + } + fields[i++] = oRequired[x][1]; + isValid = false; + } + } + } + if (fields.length > 0) { + focusField.focus(); + alert(fields.join('\n')); + } + return isValid; + } + + // Trim whitespace from left and right sides of s. + function trim(s) { + return s.replace( /^\s*/, "" ).replace( /\s*$/, "" ); + } + + ]]> + + + + + + + + + + 0) && (field.value.length < iMin)) { + if (i == 0) { + focusField = field; + } + fields[i++] = oMinLength[x][1]; + isValid = false; + } + } + } + if (fields.length > 0) { + focusField.focus(); + alert(fields.join('\n')); + } + return isValid; + }]]> + + + + + + + + iMax) { + if (i == 0) { + focusField = field; + } + fields[i++] = oMaxLength[x][1]; + isValid = false; + } + } + } + if (fields.length > 0) { + focusField.focus(); + alert(fields.join('\n')); + } + return isValid; + }]]> + + + + + + + + 0)) { + + if (!matchPattern(field.value, oMasked[x][2]("mask"))) { + if (i == 0) { + focusField = field; + } + fields[i++] = oMasked[x][1]; + isValid = false; + } + } + } + + if (fields.length > 0) { + focusField.focus(); + alert(fields.join('\n')); + } + return isValid; + } + + function matchPattern(value, mask) { + return mask.exec(value); + }]]> + + + + + + + + = 0) { + value = field.options[si].value; + } + } else { + value = field.value; + } + + if (value.length > 0) { + if (!isAllDigits(value)) { + bValid = false; + if (i == 0) { + focusField = field; + } + fields[i++] = oByte[x][1]; + + } else { + + var iValue = parseInt(value); + if (isNaN(iValue) || !(iValue >= -128 && iValue <= 127)) { + if (i == 0) { + focusField = field; + } + fields[i++] = oByte[x][1]; + bValid = false; + } + } + } + + } + } + if (fields.length > 0) { + focusField.focus(); + alert(fields.join('\n')); + } + return bValid; + }]]> + + + + + + + + = 0) { + value = field.options[si].value; + } + } else { + value = field.value; + } + + if (value.length > 0) { + if (!isAllDigits(value)) { + bValid = false; + if (i == 0) { + focusField = field; + } + fields[i++] = oShort[x][1]; + + } else { + + var iValue = parseInt(value); + if (isNaN(iValue) || !(iValue >= -32768 && iValue <= 32767)) { + if (i == 0) { + focusField = field; + } + fields[i++] = oShort[x][1]; + bValid = false; + } + } + } + } + } + if (fields.length > 0) { + focusField.focus(); + alert(fields.join('\n')); + } + return bValid; + }]]> + + + + + + + + = 0) { + value = field.options[si].value; + } + } else { + value = field.value; + } + + if (value.length > 0) { + + if (!isAllDigits(value)) { + bValid = false; + if (i == 0) { + focusField = field; + } + fields[i++] = oInteger[x][1]; + + } else { + var iValue = parseInt(value); + if (isNaN(iValue) || !(iValue >= -2147483648 && iValue <= 2147483647)) { + if (i == 0) { + focusField = field; + } + fields[i++] = oInteger[x][1]; + bValid = false; + } + } + } + } + } + if (fields.length > 0) { + focusField.focus(); + alert(fields.join('\n')); + } + return bValid; + } + + function isAllDigits(argvalue) { + argvalue = argvalue.toString(); + var validChars = "0123456789"; + var startFrom = 0; + if (argvalue.substring(0, 2) == "0x") { + validChars = "0123456789abcdefABCDEF"; + startFrom = 2; + } else if (argvalue.charAt(0) == "0") { + validChars = "01234567"; + startFrom = 1; + } else if (argvalue.charAt(0) == "-") { + startFrom = 1; + } + + for (var n = startFrom; n < argvalue.length; n++) { + if (validChars.indexOf(argvalue.substring(n, n+1)) == -1) return false; + } + return true; + }]]> + + + + + + + + + + + = 0) { + value = field.options[si].value; + } + } else { + value = field.value; + } + + if (value.length > 0) { + // remove '.' before checking digits + var tempArray = value.split('.'); + var joinedString= tempArray.join(''); + + if (!isAllDigits(joinedString)) { + bValid = false; + if (i == 0) { + focusField = field; + } + fields[i++] = oFloat[x][1]; + + } else { + var iValue = parseFloat(value); + if (isNaN(iValue)) { + if (i == 0) { + focusField = field; + } + fields[i++] = oFloat[x][1]; + bValid = false; + } + } + } + } + } + if (fields.length > 0) { + focusField.focus(); + alert(fields.join('\n')); + } + return bValid; + }]]> + + + + + + + + + + + 0) && + (datePattern.length > 0)) { + var MONTH = "MM"; + var DAY = "dd"; + var YEAR = "yyyy"; + var orderMonth = datePattern.indexOf(MONTH); + var orderDay = datePattern.indexOf(DAY); + var orderYear = datePattern.indexOf(YEAR); + if ((orderDay < orderYear && orderDay > orderMonth)) { + var iDelim1 = orderMonth + MONTH.length; + var iDelim2 = orderDay + DAY.length; + var delim1 = datePattern.substring(iDelim1, iDelim1 + 1); + var delim2 = datePattern.substring(iDelim2, iDelim2 + 1); + if (iDelim1 == orderDay && iDelim2 == orderYear) { + dateRegexp = new RegExp("^(\\d{2})(\\d{2})(\\d{4})$"); + } else if (iDelim1 == orderDay) { + dateRegexp = new RegExp("^(\\d{2})(\\d{2})[" + delim2 + "](\\d{4})$"); + } else if (iDelim2 == orderYear) { + dateRegexp = new RegExp("^(\\d{2})[" + delim1 + "](\\d{2})(\\d{4})$"); + } else { + dateRegexp = new RegExp("^(\\d{2})[" + delim1 + "](\\d{2})[" + delim2 + "](\\d{4})$"); + } + var matched = dateRegexp.exec(value); + if(matched != null) { + if (!isValidDate(matched[2], matched[1], matched[3])) { + if (i == 0) { + focusField = form[oDate[x][0]]; + } + fields[i++] = oDate[x][1]; + bValid = false; + } + } else { + if (i == 0) { + focusField = form[oDate[x][0]]; + } + fields[i++] = oDate[x][1]; + bValid = false; + } + } else if ((orderMonth < orderYear && orderMonth > orderDay)) { + var iDelim1 = orderDay + DAY.length; + var iDelim2 = orderMonth + MONTH.length; + var delim1 = datePattern.substring(iDelim1, iDelim1 + 1); + var delim2 = datePattern.substring(iDelim2, iDelim2 + 1); + if (iDelim1 == orderMonth && iDelim2 == orderYear) { + dateRegexp = new RegExp("^(\\d{2})(\\d{2})(\\d{4})$"); + } else if (iDelim1 == orderMonth) { + dateRegexp = new RegExp("^(\\d{2})(\\d{2})[" + delim2 + "](\\d{4})$"); + } else if (iDelim2 == orderYear) { + dateRegexp = new RegExp("^(\\d{2})[" + delim1 + "](\\d{2})(\\d{4})$"); + } else { + dateRegexp = new RegExp("^(\\d{2})[" + delim1 + "](\\d{2})[" + delim2 + "](\\d{4})$"); + } + var matched = dateRegexp.exec(value); + if(matched != null) { + if (!isValidDate(matched[1], matched[2], matched[3])) { + if (i == 0) { + focusField = form[oDate[x][0]]; + } + fields[i++] = oDate[x][1]; + bValid = false; + } + } else { + if (i == 0) { + focusField = form[oDate[x][0]]; + } + fields[i++] = oDate[x][1]; + bValid = false; + } + } else if ((orderMonth > orderYear && orderMonth < orderDay)) { + var iDelim1 = orderYear + YEAR.length; + var iDelim2 = orderMonth + MONTH.length; + var delim1 = datePattern.substring(iDelim1, iDelim1 + 1); + var delim2 = datePattern.substring(iDelim2, iDelim2 + 1); + if (iDelim1 == orderMonth && iDelim2 == orderDay) { + dateRegexp = new RegExp("^(\\d{4})(\\d{2})(\\d{2})$"); + } else if (iDelim1 == orderMonth) { + dateRegexp = new RegExp("^(\\d{4})(\\d{2})[" + delim2 + "](\\d{2})$"); + } else if (iDelim2 == orderDay) { + dateRegexp = new RegExp("^(\\d{4})[" + delim1 + "](\\d{2})(\\d{2})$"); + } else { + dateRegexp = new RegExp("^(\\d{4})[" + delim1 + "](\\d{2})[" + delim2 + "](\\d{2})$"); + } + var matched = dateRegexp.exec(value); + if(matched != null) { + if (!isValidDate(matched[3], matched[2], matched[1])) { + if (i == 0) { + focusField = form[oDate[x][0]]; + } + fields[i++] = oDate[x][1]; + bValid = false; + } + } else { + if (i == 0) { + focusField = form[oDate[x][0]]; + } + fields[i++] = oDate[x][1]; + bValid = false; + } + } else { + if (i == 0) { + focusField = form[oDate[x][0]]; + } + fields[i++] = oDate[x][1]; + bValid = false; + } + } + } + if (fields.length > 0) { + focusField.focus(); + alert(fields.join('\n')); + } + return bValid; + } + + function isValidDate(day, month, year) { + if (month < 1 || month > 12) { + return false; + } + if (day < 1 || day > 31) { + return false; + } + if ((month == 4 || month == 6 || month == 9 || month == 11) && + (day == 31)) { + return false; + } + if (month == 2) { + var leap = (year % 4 == 0 && + (year % 100 != 0 || year % 400 == 0)); + if (day>29 || (day == 29 && !leap)) { + return false; + } + } + return true; + }]]> + + + + + + + + + + + + + + + 0)) { + + var iMin = parseInt(oRange[x][2]("min")); + var iMax = parseInt(oRange[x][2]("max")); + var iValue = parseInt(field.value); + if (!(iValue >= iMin && iValue <= iMax)) { + if (i == 0) { + focusField = field; + } + fields[i++] = oRange[x][1]; + isValid = false; + } + } + } + if (fields.length > 0) { + focusField.focus(); + alert(fields.join('\n')); + } + return isValid; + }]]> + + + + + + + 0)) { + + var fMin = parseFloat(oRange[x][2]("min")); + var fMax = parseFloat(oRange[x][2]("max")); + var fValue = parseFloat(field.value); + if (!(fValue >= fMin && fValue <= fMax)) { + if (i == 0) { + focusField = field; + } + fields[i++] = oRange[x][1]; + isValid = false; + } + } + } + if (fields.length > 0) { + focusField.focus(); + alert(fields.join('\n')); + } + return isValid; + }]]> + + + + + + + 0)) { + if (!luhnCheck(form[oCreditCard[x][0]].value)) { + if (i == 0) { + focusField = form[oCreditCard[x][0]]; + } + fields[i++] = oCreditCard[x][1]; + bValid = false; + } + } + } + if (fields.length > 0) { + focusField.focus(); + alert(fields.join('\n')); + } + return bValid; + } + + /** + * Reference: http://www.ling.nwu.edu/~sburke/pub/luhn_lib.pl + */ + function luhnCheck(cardNumber) { + if (isLuhnNum(cardNumber)) { + var no_digit = cardNumber.length; + var oddoeven = no_digit & 1; + var sum = 0; + for (var count = 0; count < no_digit; count++) { + var digit = parseInt(cardNumber.charAt(count)); + if (!((count & 1) ^ oddoeven)) { + digit *= 2; + if (digit > 9) digit -= 9; + }; + sum += digit; + }; + if (sum == 0) return false; + if (sum % 10 == 0) return true; + }; + return false; + } + + function isLuhnNum(argvalue) { + argvalue = argvalue.toString(); + if (argvalue.length == 0) { + return false; + } + for (var n = 0; n < argvalue.length; n++) { + if ((argvalue.substring(n, n+1) < "0") || + (argvalue.substring(n,n+1) > "9")) { + return false; + } + } + return true; + }]]> + + + + + + + + 0)) { + if (!checkEmail(form[oEmail[x][0]].value)) { + if (i == 0) { + focusField = form[oEmail[x][0]]; + } + fields[i++] = oEmail[x][1]; + bValid = false; + } + } + } + if (fields.length > 0) { + focusField.focus(); + alert(fields.join('\n')); + } + return bValid; + } + + /** + * Reference: Sandeep V. Tamhankar (stamhankar@hotmail.com), + * http://javascript.internet.com + */ + function checkEmail(emailStr) { + if (emailStr.length == 0) { + return true; + } + var emailPat=/^(.+)@(.+)$/; + var specialChars="\\(\\)<>@,;:\\\\\\\"\\.\\[\\]"; + var validChars="\[^\\s" + specialChars + "\]"; + var quotedUser="(\"[^\"]*\")"; + var ipDomainPat=/^(\d{1,3})[.](\d{1,3})[.](\d{1,3})[.](\d{1,3})$/; + var atom=validChars + '+'; + var word="(" + atom + "|" + quotedUser + ")"; + var userPat=new RegExp("^" + word + "(\\." + word + ")*$"); + var domainPat=new RegExp("^" + atom + "(\\." + atom + ")*$"); + var matchArray=emailStr.match(emailPat); + if (matchArray == null) { + return false; + } + var user=matchArray[1]; + var domain=matchArray[2]; + if (user.match(userPat) == null) { + return false; + } + var IPArray = domain.match(ipDomainPat); + if (IPArray != null) { + for (var i = 1; i <= 4; i++) { + if (IPArray[i] > 255) { + return false; + } + } + return true; + } + var domainArray=domain.match(domainPat); + if (domainArray == null) { + return false; + } + var atomPat=new RegExp(atom,"g"); + var domArr=domain.match(atomPat); + var len=domArr.length; + if ((domArr[domArr.length-1].length < 2) || + (domArr[domArr.length-1].length > 3)) { + return false; + } + if (len < 2) { + return false; + } + return true; + }]]> + + + + + + + diff --git a/netui/external/struts/legacy/jakarta-struts-1.1-lib/validator-rules_1_1.dtd b/netui/external/struts/legacy/jakarta-struts-1.1-lib/validator-rules_1_1.dtd new file mode 100644 index 0000000..e8b1ac1 --- /dev/null +++ b/netui/external/struts/legacy/jakarta-struts-1.1-lib/validator-rules_1_1.dtd @@ -0,0 +1,282 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/netui/external/struts/legacy/jakarta-struts-1.1-lib/web-app_2_2.dtd b/netui/external/struts/legacy/jakarta-struts-1.1-lib/web-app_2_2.dtd new file mode 100644 index 0000000..be0c01e --- /dev/null +++ b/netui/external/struts/legacy/jakarta-struts-1.1-lib/web-app_2_2.dtd @@ -0,0 +1,565 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/netui/external/struts/legacy/jakarta-struts-1.1-lib/web-app_2_3.dtd b/netui/external/struts/legacy/jakarta-struts-1.1-lib/web-app_2_3.dtd new file mode 100644 index 0000000..b110d76 --- /dev/null +++ b/netui/external/struts/legacy/jakarta-struts-1.1-lib/web-app_2_3.dtd @@ -0,0 +1,1059 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/netui/external/struts/struts-bean.tld b/netui/external/struts/struts-bean.tld new file mode 100644 index 0000000..a4b8fd7 --- /dev/null +++ b/netui/external/struts/struts-bean.tld @@ -0,0 +1,382 @@ + + + + + + + + + + +1.2 +1.1 +bean +http://struts.apache.org/tags-bean + +cookie +org.apache.struts.taglib.bean.CookieTag +org.apache.struts.taglib.bean.CookieTei +empty + +id +true +false + + +multiple +false +true + + +name +true +true + + +value +false +true + + + +define +org.apache.struts.taglib.bean.DefineTag +org.apache.struts.taglib.bean.DefineTei +JSP + +id +true +false + + +name +false +true + + +property +false +true + + +scope +false +true + + +toScope +false +true + + +type +false +true + + +value +false +true + + + +header +org.apache.struts.taglib.bean.HeaderTag +org.apache.struts.taglib.bean.HeaderTei +empty + +id +true +false + + +multiple +false +true + + +name +true +true + + +value +false +true + + + +include +org.apache.struts.taglib.bean.IncludeTag +org.apache.struts.taglib.bean.IncludeTei +empty + +anchor +false +true + + +forward +false +true + + +href +false +true + + +id +true +false + + +name +false +true + + +page +false +true + + +transaction +false +true + + + +message +org.apache.struts.taglib.bean.MessageTag +empty + +arg0 +false +true + + +arg1 +false +true + + +arg2 +false +true + + +arg3 +false +true + + +arg4 +false +true + + +bundle +false +true + + +key +false +true + + +locale +false +true + + +name +false +true + + +property +false +true + + +scope +false +true + + + +page +org.apache.struts.taglib.bean.PageTag +org.apache.struts.taglib.bean.PageTei +empty + +id +true +false + + +property +true +true + + + +parameter +org.apache.struts.taglib.bean.ParameterTag +org.apache.struts.taglib.bean.ParameterTei +empty + +id +true +false + + +multiple +false +true + + +name +true +true + + +value +false +true + + + +resource +org.apache.struts.taglib.bean.ResourceTag +org.apache.struts.taglib.bean.ResourceTei +empty + +id +true +false + + +input +false +true + + +name +true +true + + + +size +org.apache.struts.taglib.bean.SizeTag +org.apache.struts.taglib.bean.SizeTei +empty + +collection +false +true + + +id +true +false + + +name +false +true + + +property +false +true + + +scope +false +true + + + +struts +org.apache.struts.taglib.bean.StrutsTag +org.apache.struts.taglib.bean.StrutsTei +empty + +id +true +false + + +formBean +false +true + + +forward +false +true + + +mapping +false +true + + + +write +org.apache.struts.taglib.bean.WriteTag +empty + +bundle +false +true + + +filter +false +true + + +format +false +true + + +formatKey +false +true + + +ignore +false +true + + +locale +false +true + + +name +true +true + + +property +false +true + + +scope +false +true + + + + + + diff --git a/netui/external/struts/struts-config_1_0.dtd b/netui/external/struts/struts-config_1_0.dtd new file mode 100644 index 0000000..3e8ab49 --- /dev/null +++ b/netui/external/struts/struts-config_1_0.dtd @@ -0,0 +1,408 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/netui/external/struts/struts-config_1_1.dtd b/netui/external/struts/struts-config_1_1.dtd new file mode 100644 index 0000000..3c9b3cf --- /dev/null +++ b/netui/external/struts/struts-config_1_1.dtd @@ -0,0 +1,695 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/netui/external/struts/struts-config_1_2.dtd b/netui/external/struts/struts-config_1_2.dtd new file mode 100644 index 0000000..9f5e89f --- /dev/null +++ b/netui/external/struts/struts-config_1_2.dtd @@ -0,0 +1,686 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/netui/external/struts/struts-html.tld b/netui/external/struts/struts-html.tld new file mode 100644 index 0000000..257c26f --- /dev/null +++ b/netui/external/struts/struts-html.tld @@ -0,0 +1,3302 @@ + + + + + + + + + + +1.2 +1.1 +html +http://struts.apache.org/tags-html + +base +org.apache.struts.taglib.html.BaseTag +empty + +target +false +true + + +server +false +true + + + +button +org.apache.struts.taglib.html.ButtonTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +bundle +false +true + + +disabled +false +true + + +indexed +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +cancel +org.apache.struts.taglib.html.CancelTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +bundle +false +true + + +disabled +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +checkbox +org.apache.struts.taglib.html.CheckboxTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +bundle +false +true + + +disabled +false +true + + +errorKey +false +true + + +errorStyle +false +true + + +errorStyleClass +false +true + + +errorStyleId +false +true + + +indexed +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +errors +org.apache.struts.taglib.html.ErrorsTag +empty + +bundle +false +true + + +footer +false +true + + +header +false +true + + +locale +false +true + + +name +false +true + + +prefix +false +true + + +property +false +true + + +suffix +false +true + + + +file +org.apache.struts.taglib.html.FileTag + +accesskey +false +true + + +accept +false +true + + +alt +false +true + + +altKey +false +true + + +bundle +false +true + + +disabled +false +true + + +errorKey +false +true + + +errorStyle +false +true + + +errorStyleClass +false +true + + +errorStyleId +false +true + + +indexed +false +true + + +maxlength +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +size +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +form +org.apache.struts.taglib.html.FormTag +JSP + +action +true +true + + +acceptCharset +false +true + + +disabled +false +true + + +enctype +false +true + + +focus +false +true + + +focusIndex +false +true + + +method +false +true + + +onreset +false +true + + +onsubmit +false +true + + +readonly +false +true + + +scriptLanguage +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +target +false +true + + + +frame +org.apache.struts.taglib.html.FrameTag + +bundle +false +true + + +action +false +true + + +module +false +true + + +anchor +false +true + + +forward +false +true + + +frameborder +false +true + + +frameName +false +true + + +href +false +true + + +longdesc +false +true + + +marginheight +false +true + + +marginwidth +false +true + + +name +false +true + + +noresize +false +true + + +page +false +true + + +paramId +false +true + + +paramName +false +true + + +paramProperty +false +true + + +paramScope +false +true + + +property +false +true + + +scope +false +true + + +scrolling +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +title +false +true + + +titleKey +false +true + + +transaction +false +true + + + +hidden +org.apache.struts.taglib.html.HiddenTag +empty + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +bundle +false +true + + +disabled +false +true + + +indexed +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + +write +false +true + + + +html +org.apache.struts.taglib.html.HtmlTag +JSP + +lang +false +true + + +locale +false +true + + +xhtml +false +true + + + +image +org.apache.struts.taglib.html.ImageTag + +accesskey +false +true + + +align +false +true + + +alt +false +true + + +altKey +false +true + + +border +false +true + + +bundle +false +true + + +disabled +false +true + + +indexed +false +true + + +locale +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +page +false +true + + +pageKey +false +true + + +property +false +true + + +src +false +true + + +srcKey +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +img +org.apache.struts.taglib.html.ImgTag +empty + +align +false +true + + +alt +false +true + + +altKey +false +true + + +border +false +true + + +bundle +false +true + + +contextRelative +false +true + + +height +false +true + + +hspace +false +true + + +imageName +false +true + + +ismap +false +true + + +locale +false +true + + +lowsrc +false +true + + +name +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +paramId +false +true + + +page +false +true + + +pageKey +false +true + + +action +false +true + + +module +false +true + + +paramName +false +true + + +paramProperty +false +true + + +paramScope +false +true + + +property +false +true + + +scope +false +true + + +src +false +true + + +srcKey +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +title +false +true + + +titleKey +false +true + + +useLocalEncoding +false +true + + +usemap +false +true + + +vspace +false +true + + +width +false +true + + + +javascript +org.apache.struts.taglib.html.JavascriptValidatorTag +empty + +cdata +false +true + + +dynamicJavascript +false +false + + +formName +false +true + + +method +false +true + + +page +false +true + + +scriptLanguage +false +true + + +src +false +true + + +staticJavascript +false +false + + +htmlComment +false +true + + +bundle +false +true + + + +link +org.apache.struts.taglib.html.LinkTag + +accesskey +false +true + + +action +false +true + + +module +false +true + + +anchor +false +true + + +forward +false +true + + +href +false +true + + +indexed +false +true + + +indexId +false +true + + +bundle +false +true + + +linkName +false +true + + +name +false +true + + +onblur +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +page +false +true + + +paramId +false +true + + +paramName +false +true + + +paramProperty +false +true + + +paramScope +false +true + + +property +false +true + + +scope +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +target +false +true + + +title +false +true + + +titleKey +false +true + + +transaction +false +true + + +useLocalEncoding +false +true + + + +messages +org.apache.struts.taglib.html.MessagesTag +org.apache.struts.taglib.html.MessagesTei +JSP + +id +true +false + + +bundle +false +true + + +locale +false +true + + +name +false +true + + +property +false +true + + +header +false +true + + +footer +false +true + + +message +false +true + + + +multibox +org.apache.struts.taglib.html.MultiboxTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +bundle +false +true + + +disabled +false +true + + +errorKey +false +true + + +errorStyle +false +true + + +errorStyleClass +false +true + + +errorStyleId +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +option +org.apache.struts.taglib.html.OptionTag + +bundle +false +true + + +disabled +false +true + + +key +false +true + + +locale +false +true + + +style +false +true + + +styleId +false +true + + +styleClass +false +true + + +value +true +true + + + +options +org.apache.struts.taglib.html.OptionsTag +empty + +collection +false +true + + +filter +false +true + + +labelName +false +true + + +labelProperty +false +true + + +name +false +true + + +property +false +true + + +style +false +true + + +styleClass +false +true + + + +optionsCollection +org.apache.struts.taglib.html.OptionsCollectionTag +empty + +filter +false +true + + +label +false +true + + +name +false +true + + +property +false +true + + +style +false +true + + +styleClass +false +true + + +value +false +true + + + +password +org.apache.struts.taglib.html.PasswordTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +bundle +false +true + + +disabled +false +true + + +errorKey +false +true + + +errorStyle +false +true + + +errorStyleClass +false +true + + +errorStyleId +false +true + + +indexed +false +true + + +maxlength +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +readonly +false +true + + +redisplay +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +size +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +radio +org.apache.struts.taglib.html.RadioTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +bundle +false +true + + +disabled +false +true + + +errorKey +false +true + + +errorStyle +false +true + + +errorStyleClass +false +true + + +errorStyleId +false +true + + +indexed +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +property +true +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +true +true + + +idName +false +true + + + +reset +org.apache.struts.taglib.html.ResetTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +bundle +false +true + + +disabled +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +rewrite +org.apache.struts.taglib.html.RewriteTag +empty + +action +false +true + + +module +false +true + + +anchor +false +true + + +forward +false +true + + +href +false +true + + +name +false +true + + +page +false +true + + +paramId +false +true + + +paramName +false +true + + +paramProperty +false +true + + +paramScope +false +true + + +property +false +true + + +scope +false +true + + +transaction +false +true + + +useLocalEncoding +false +true + + + +select +org.apache.struts.taglib.html.SelectTag +JSP + +alt +false +true + + +altKey +false +true + + +bundle +false +true + + +disabled +false +true + + +errorKey +false +true + + +errorStyle +false +true + + +errorStyleClass +false +true + + +errorStyleId +false +true + + +indexed +false +true + + +multiple +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +size +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +submit +org.apache.struts.taglib.html.SubmitTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +bundle +false +true + + +disabled +false +true + + +indexed +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +text +org.apache.struts.taglib.html.TextTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +bundle +false +true + + +disabled +false +true + + +errorKey +false +true + + +errorStyle +false +true + + +errorStyleClass +false +true + + +errorStyleId +false +true + + +indexed +false +true + + +maxlength +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +readonly +false +true + + +size +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +textarea +org.apache.struts.taglib.html.TextareaTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +bundle +false +true + + +cols +false +true + + +disabled +false +true + + +errorKey +false +true + + +errorStyle +false +true + + +errorStyleClass +false +true + + +errorStyleId +false +true + + +indexed +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +readonly +false +true + + +rows +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +xhtml +org.apache.struts.taglib.html.XhtmlTag +empty + + + diff --git a/netui/external/struts/struts-logic.tld b/netui/external/struts/struts-logic.tld new file mode 100644 index 0000000..f267fcc --- /dev/null +++ b/netui/external/struts/struts-logic.tld @@ -0,0 +1,652 @@ + + + + + + + + + +1.2 +1.1 +logic +http://struts.apache.org/tags-logic + +empty +org.apache.struts.taglib.logic.EmptyTag +JSP + +name +false +true + + +property +false +true + + +scope +false +true + + + +equal +org.apache.struts.taglib.logic.EqualTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +forward +org.apache.struts.taglib.logic.ForwardTag +empty + +name +true +true + + + +greaterEqual +org.apache.struts.taglib.logic.GreaterEqualTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +greaterThan +org.apache.struts.taglib.logic.GreaterThanTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +iterate +org.apache.struts.taglib.logic.IterateTag +org.apache.struts.taglib.logic.IterateTei +JSP + +collection +false +true + + +id +true +false + + +indexId +false +false + + +length +false +true + + +name +false +true + + +offset +false +true + + +property +false +true + + +scope +false +true + + +type +false +true + + + +lessEqual +org.apache.struts.taglib.logic.LessEqualTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +lessThan +org.apache.struts.taglib.logic.LessThanTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +match +org.apache.struts.taglib.logic.MatchTag +JSP + +cookie +false +true + + +header +false +true + + +location +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +messagesNotPresent +org.apache.struts.taglib.logic.MessagesNotPresentTag +JSP + +name +false +true + + +property +false +true + + +message +false +true + + + +messagesPresent +org.apache.struts.taglib.logic.MessagesPresentTag +JSP + +name +false +true + + +property +false +true + + +message +false +true + + + +notEmpty +org.apache.struts.taglib.logic.NotEmptyTag +JSP + +name +false +true + + +property +false +true + + +scope +false +true + + + +notEqual +org.apache.struts.taglib.logic.NotEqualTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +notMatch +org.apache.struts.taglib.logic.NotMatchTag +JSP + +cookie +false +true + + +header +false +true + + +location +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +notPresent +org.apache.struts.taglib.logic.NotPresentTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +role +false +true + + +scope +false +true + + +user +false +true + + + +present +org.apache.struts.taglib.logic.PresentTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +role +false +true + + +scope +false +true + + +user +false +true + + + +redirect +org.apache.struts.taglib.logic.RedirectTag + +action +false +true + + +anchor +false +true + + +forward +false +true + + +href +false +true + + +name +false +true + + +page +false +true + + +paramId +false +true + + +paramName +false +true + + +paramProperty +false +true + + +paramScope +false +true + + +property +false +true + + +scope +false +true + + +transaction +false +true + + +useLocalEncoding +false +true + + + + + + diff --git a/netui/external/struts/struts-nested.tld b/netui/external/struts/struts-nested.tld new file mode 100644 index 0000000..f296c41 --- /dev/null +++ b/netui/external/struts/struts-nested.tld @@ -0,0 +1,3171 @@ + + + + + + + + + +1.2 +1.1 +nested +http://struts.apache.org/tags-nested + +nest +org.apache.struts.taglib.nested.NestedPropertyTag +JSP + +property +false +true + + + +writeNesting +org.apache.struts.taglib.nested.NestedWriteNestingTag +org.apache.struts.taglib.nested.NestedWriteNestingTei +JSP + +property +false +true + + +id +false +true + + +filter +false +true + + + +root +org.apache.struts.taglib.nested.NestedRootTag +JSP + +name +false +true + + + +define +org.apache.struts.taglib.nested.bean.NestedDefineTag +org.apache.struts.taglib.nested.bean.NestedDefineTei +empty + +id +true +true + + +name +false +true + + +property +false +true + + +scope +false +true + + +toScope +false +true + + +type +false +true + + +value +false +true + + + +message +org.apache.struts.taglib.nested.bean.NestedMessageTag +empty + +arg0 +false +true + + +arg1 +false +true + + +arg2 +false +true + + +arg3 +false +true + + +arg4 +false +true + + +bundle +false +true + + +key +false +true + + +locale +false +true + + +name +false +true + + +property +false +true + + +scope +false +true + + + +size +org.apache.struts.taglib.nested.bean.NestedSizeTag +org.apache.struts.taglib.bean.SizeTei +empty + +collection +false +true + + +id +true +true + + +name +false +true + + +property +false +true + + +scope +false +true + + + +write +org.apache.struts.taglib.nested.bean.NestedWriteTag +empty + +bundle +false +true + + +filter +false +true + + +format +false +true + + +formatKey +false +true + + +ignore +false +true + + +locale +false +true + + +name +false +true + + +property +false +true + + +scope +false +true + + + +checkbox +org.apache.struts.taglib.nested.html.NestedCheckboxTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +bundle +false +true + + +disabled +false +true + + +errorKey +false +true + + +errorStyle +false +true + + +errorStyleClass +false +true + + +errorStyleId +false +true + + +indexed +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +errors +org.apache.struts.taglib.nested.html.NestedErrorsTag +empty + +bundle +false +true + + +footer +false +true + + +header +false +true + + +locale +false +true + + +name +false +true + + +prefix +false +true + + +property +false +true + + +suffix +false +true + + + +file +org.apache.struts.taglib.nested.html.NestedFileTag + +accesskey +false +true + + +accept +false +true + + +alt +false +true + + +altKey +false +true + + +bundle +false +true + + +disabled +false +true + + +errorKey +false +true + + +errorStyle +false +true + + +errorStyleClass +false +true + + +errorStyleId +false +true + + +indexed +false +true + + +maxlength +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +size +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +form +org.apache.struts.taglib.nested.html.NestedFormTag +JSP + +action +true +true + + +acceptCharset +false +true + + +disabled +false +true + + +enctype +false +true + + +focus +false +true + + +focusIndex +false +true + + +method +false +true + + +onreset +false +true + + +onsubmit +false +true + + +readonly +false +true + + +scriptLanguage +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +target +false +true + + + +hidden +org.apache.struts.taglib.nested.html.NestedHiddenTag + +alt +false +true + + +altKey +false +true + + +indexed +false +true + + +name +false +true + + +property +true +true + + +title +false +true + + +titleKey +false +true + + +styleClass +false +true + + +styleId +false +true + + +value +false +true + + +write +false +true + + + +image +org.apache.struts.taglib.nested.html.NestedImageTag + +accesskey +false +true + + +align +false +true + + +alt +false +true + + +altKey +false +true + + +border +false +true + + +bundle +false +true + + +disabled +false +true + + +indexed +false +true + + +locale +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +page +false +true + + +pageKey +false +true + + +property +false +true + + +src +false +true + + +srcKey +false +true + + +style +false +true + + +styleClass +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +img +org.apache.struts.taglib.nested.html.NestedImgTag +empty + +accesskey +false +true + + +align +false +true + + +alt +false +true + + +altKey +false +true + + +border +false +true + + +bundle +false +true + + +height +false +true + + +hspace +false +true + + +imageName +false +true + + +ismap +false +true + + +locale +false +true + + +lowsrc +false +true + + +name +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +paramId +false +true + + +page +false +true + + +pageKey +false +true + + +action +false +true + + +module +false +true + + +paramName +false +true + + +paramProperty +false +true + + +paramScope +false +true + + +property +false +true + + +scope +false +true + + +src +false +true + + +srcKey +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +title +false +true + + +titleKey +false +true + + +useLocalEncoding +false +true + + +usemap +false +true + + +vspace +false +true + + +width +false +true + + + +link +org.apache.struts.taglib.nested.html.NestedLinkTag + +accesskey +false +true + + +action +false +true + + +module +false +true + + +anchor +false +true + + +forward +false +true + + +href +false +true + + +indexed +false +true + + +indexId +false +true + + +bundle +false +true + + +linkName +false +true + + +name +false +true + + +onblur +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +page +false +true + + +paramId +false +true + + +paramName +false +true + + +paramProperty +false +true + + +paramScope +false +true + + +property +false +true + + +scope +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +target +false +true + + +title +false +true + + +titleKey +false +true + + +transaction +false +true + + +useLocalEncoding +false +true + + + +messages +org.apache.struts.taglib.nested.html.NestedMessagesTag +org.apache.struts.taglib.html.MessagesTei +JSP + +id +true +true + + +bundle +false +true + + +locale +false +true + + +name +false +true + + +property +false +true + + +header +false +true + + +footer +false +true + + +message +false +true + + + +multibox +org.apache.struts.taglib.nested.html.NestedMultiboxTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +bundle +false +true + + +disabled +false +true + + +errorKey +false +true + + +errorStyle +false +true + + +errorStyleClass +false +true + + +errorStyleId +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +options +org.apache.struts.taglib.nested.html.NestedOptionsTag +empty + +collection +false +true + + +filter +false +true + + +labelName +false +true + + +labelProperty +false +true + + +name +false +true + + +property +false +true + + +style +false +true + + +styleClass +false +true + + + +optionsCollection +org.apache.struts.taglib.nested.html.NestedOptionsCollectionTag +empty + +filter +false +true + + +label +false +true + + +name +false +true + + +property +true +true + + +style +false +true + + +styleClass +false +true + + +value +false +true + + + +password +org.apache.struts.taglib.nested.html.NestedPasswordTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +bundle +false +true + + +disabled +false +true + + +errorKey +false +true + + +errorStyle +false +true + + +errorStyleClass +false +true + + +errorStyleId +false +true + + +indexed +false +true + + +maxlength +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +readonly +false +true + + +redisplay +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +size +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +radio +org.apache.struts.taglib.nested.html.NestedRadioTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +bundle +false +true + + +disabled +false +true + + +errorKey +false +true + + +errorStyle +false +true + + +errorStyleClass +false +true + + +errorStyleId +false +true + + +indexed +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +property +true +true + + +onmousedown +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +true +true + + +idName +false +true + + + +select +org.apache.struts.taglib.nested.html.NestedSelectTag +JSP + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +bundle +false +true + + +disabled +false +true + + +errorKey +false +true + + +errorStyle +false +true + + +errorStyleClass +false +true + + +errorStyleId +false +true + + +indexed +false +true + + +multiple +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +size +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +submit +org.apache.struts.taglib.nested.html.NestedSubmitTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +bundle +false +true + + +disabled +false +true + + +indexed +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +text +org.apache.struts.taglib.nested.html.NestedTextTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +bundle +false +true + + +disabled +false +true + + +errorKey +false +true + + +errorStyle +false +true + + +errorStyleClass +false +true + + +errorStyleId +false +true + + +indexed +false +true + + +maxlength +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +readonly +false +true + + +size +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +textarea +org.apache.struts.taglib.nested.html.NestedTextareaTag + +accesskey +false +true + + +alt +false +true + + +altKey +false +true + + +bundle +false +true + + +cols +false +true + + +disabled +false +true + + +errorKey +false +true + + +errorStyle +false +true + + +errorStyleClass +false +true + + +errorStyleId +false +true + + +indexed +false +true + + +name +false +true + + +onblur +false +true + + +onchange +false +true + + +onclick +false +true + + +ondblclick +false +true + + +onfocus +false +true + + +onkeydown +false +true + + +onkeypress +false +true + + +onkeyup +false +true + + +onmousedown +false +true + + +onmousemove +false +true + + +onmouseout +false +true + + +onmouseover +false +true + + +onmouseup +false +true + + +property +true +true + + +readonly +false +true + + +rows +false +true + + +style +false +true + + +styleClass +false +true + + +styleId +false +true + + +tabindex +false +true + + +title +false +true + + +titleKey +false +true + + +value +false +true + + + +empty +org.apache.struts.taglib.nested.logic.NestedEmptyTag +JSP + +name +false +true + + +property +false +true + + +scope +false +true + + + +equal +org.apache.struts.taglib.nested.logic.NestedEqualTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +greaterEqual +org.apache.struts.taglib.nested.logic.NestedGreaterEqualTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +greaterThan +org.apache.struts.taglib.nested.logic.NestedGreaterThanTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +iterate +org.apache.struts.taglib.nested.logic.NestedIterateTag +org.apache.struts.taglib.nested.logic.NestedIterateTei +JSP + +collection +false +true + + +id +false +true + + +indexId +false +true + + +length +false +true + + +name +false +true + + +offset +false +true + + +property +false +true + + +scope +false +true + + +type +false +true + + + +lessEqual +org.apache.struts.taglib.nested.logic.NestedLessEqualTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +lessThan +org.apache.struts.taglib.nested.logic.NestedLessThanTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +match +org.apache.struts.taglib.nested.logic.NestedMatchTag +JSP + +cookie +false +true + + +header +false +true + + +location +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +messagesNotPresent +org.apache.struts.taglib.nested.logic.NestedMessagesNotPresentTag +JSP + +name +false +true + + +property +false +true + + +message +false +true + + + +messagesPresent +org.apache.struts.taglib.nested.logic.NestedMessagesPresentTag +JSP + +name +false +true + + +property +false +true + + +message +false +true + + + +notEmpty +org.apache.struts.taglib.nested.logic.NestedNotEmptyTag +JSP + +name +false +true + + +property +false +true + + +scope +false +true + + + +notEqual +org.apache.struts.taglib.nested.logic.NestedNotEqualTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +notMatch +org.apache.struts.taglib.nested.logic.NestedNotMatchTag +JSP + +cookie +false +true + + +header +false +true + + +location +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +scope +false +true + + +value +true +true + + + +notPresent +org.apache.struts.taglib.nested.logic.NestedNotPresentTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +role +false +true + + +scope +false +true + + +user +false +true + + + +present +org.apache.struts.taglib.nested.logic.NestedPresentTag +JSP + +cookie +false +true + + +header +false +true + + +name +false +true + + +parameter +false +true + + +property +false +true + + +role +false +true + + +scope +false +true + + +user +false +true + + + + + + diff --git a/netui/external/struts/struts-tiles.tld b/netui/external/struts/struts-tiles.tld new file mode 100644 index 0000000..7ae564b --- /dev/null +++ b/netui/external/struts/struts-tiles.tld @@ -0,0 +1,344 @@ + + + + + + + + + + +1.2 +1.1 +tiles +http://struts.apache.org/tags-tiles + +insert +org.apache.struts.taglib.tiles.InsertTag +JSP + +template +false +true + + +component +false +true + + +page +false +true + + +definition +false +true + + +attribute +false +false + + +name +false +true + + +beanName +false +true + + +beanProperty +false +true + + +beanScope +false +false + + +flush +false +false + + +ignore +false +true + + +role +false +true + + +controllerUrl +false +true + + +controllerClass +false +true + + + +definition +org.apache.struts.taglib.tiles.DefinitionTag +JSP + +id +true +false + + +scope +false +false + + +template +false +true + + +page +false +true + + +role +false +true + + +extends +false +true + + + +put +org.apache.struts.taglib.tiles.PutTag +JSP + +name +false +false + + +value +false +true + + +content +false +true + + +direct +false +false + + +type +false +false + + +beanName +false +true + + +beanProperty +false +true + + +beanScope +false +false + + +role +false +true + + + +putList +org.apache.struts.taglib.tiles.PutListTag +JSP + +name +true +false + + + +add +org.apache.struts.taglib.tiles.AddTag +JSP + +value +false +false + + +content +false +true + + +direct +false +false + + +type +false +false + + +beanName +false +true + + +beanProperty +false +true + + +beanScope +false +false + + +role +false +true + + + +get +org.apache.struts.taglib.tiles.GetTag +empty + +name +true +true + + +ignore +false +true + + +flush +false +false + + +role +false +true + + + +getAsString +org.apache.struts.taglib.tiles.GetAttributeTag +empty + +name +true +true + + +ignore +false +true + + +role +false +true + + + +useAttribute +org.apache.struts.taglib.tiles.UseAttributeTag +org.apache.struts.taglib.tiles.UseAttributeTei +empty + +id +false +false + + +classname +false +false + + +scope +false +false + + +name +true +true + + +ignore +false +true + + + +importAttribute +org.apache.struts.taglib.tiles.ImportAttributeTag +empty + +name +false +true + + +scope +false +false + + +ignore +false +true + + + +initComponentDefinitions +org.apache.struts.taglib.tiles.InitDefinitionsTag +empty + +file +true +false + + +classname +false +false + + + + + + diff --git a/netui/external/struts/struts.jar b/netui/external/struts/struts.jar new file mode 100644 index 0000000..7815901 Binary files /dev/null and b/netui/external/struts/struts.jar differ diff --git a/netui/external/struts/tiles-config_1_1.dtd b/netui/external/struts/tiles-config_1_1.dtd new file mode 100644 index 0000000..a3b2f70 --- /dev/null +++ b/netui/external/struts/tiles-config_1_1.dtd @@ -0,0 +1,281 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/netui/external/struts/validator-rules.xml b/netui/external/struts/validator-rules.xml new file mode 100644 index 0000000..0baaa7b --- /dev/null +++ b/netui/external/struts/validator-rules.xml @@ -0,0 +1,313 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/netui/external/struts/version.txt b/netui/external/struts/version.txt new file mode 100644 index 0000000..c6cebb5 --- /dev/null +++ b/netui/external/struts/version.txt @@ -0,0 +1,3 @@ +Struts 1.2.9 + +Downloaded: 2006-09-28 diff --git a/netui/external/struts/web-app_2_2.dtd b/netui/external/struts/web-app_2_2.dtd new file mode 100644 index 0000000..be0c01e --- /dev/null +++ b/netui/external/struts/web-app_2_2.dtd @@ -0,0 +1,565 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/netui/external/struts/web-app_2_3.dtd b/netui/external/struts/web-app_2_3.dtd new file mode 100644 index 0000000..b110d76 --- /dev/null +++ b/netui/external/struts/web-app_2_3.dtd @@ -0,0 +1,1059 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/netui/external/testRecorder/commons-httpclient-2.0.jar b/netui/external/testRecorder/commons-httpclient-2.0.jar new file mode 100644 index 0000000..f58ec95 Binary files /dev/null and b/netui/external/testRecorder/commons-httpclient-2.0.jar differ diff --git a/netui/external/tomcat/5.0.x/catalina.jar b/netui/external/tomcat/5.0.x/catalina.jar new file mode 100644 index 0000000..5de0b50 Binary files /dev/null and b/netui/external/tomcat/5.0.x/catalina.jar differ diff --git a/netui/external/tomcat/5.0.x/tomcat-coyote.jar b/netui/external/tomcat/5.0.x/tomcat-coyote.jar new file mode 100644 index 0000000..c9a2924 Binary files /dev/null and b/netui/external/tomcat/5.0.x/tomcat-coyote.jar differ diff --git a/netui/external/tomcat/5.5.x/catalina.jar b/netui/external/tomcat/5.5.x/catalina.jar new file mode 100644 index 0000000..a3b30d8 Binary files /dev/null and b/netui/external/tomcat/5.5.x/catalina.jar differ diff --git a/netui/external/tomcat/5.5.x/tomcat-coyote.jar b/netui/external/tomcat/5.5.x/tomcat-coyote.jar new file mode 100644 index 0000000..e870d5e Binary files /dev/null and b/netui/external/tomcat/5.5.x/tomcat-coyote.jar differ diff --git a/netui/external/xdoclet/xdoclet-1.2b4.jar b/netui/external/xdoclet/xdoclet-1.2b4.jar new file mode 100644 index 0000000..c465cfd Binary files /dev/null and b/netui/external/xdoclet/xdoclet-1.2b4.jar differ diff --git a/netui/external/xdoclet/xdoclet-web-module-1.2b4.jar b/netui/external/xdoclet/xdoclet-web-module-1.2b4.jar new file mode 100644 index 0000000..5f344bf Binary files /dev/null and b/netui/external/xdoclet/xdoclet-web-module-1.2b4.jar differ diff --git a/netui/external/xdoclet/xjavadoc-1.1.jar b/netui/external/xdoclet/xjavadoc-1.1.jar new file mode 100644 index 0000000..037cce6 Binary files /dev/null and b/netui/external/xdoclet/xjavadoc-1.1.jar differ diff --git a/netui/netui-imports.xml b/netui/netui-imports.xml new file mode 100644 index 0000000..ed846e7 --- /dev/null +++ b/netui/netui-imports.xml @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/netui/src/bootstrap/build.xml b/netui/src/bootstrap/build.xml new file mode 100644 index 0000000..e809731 --- /dev/null +++ b/netui/src/bootstrap/build.xml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + compile module: ${module.name} + + module classpath: ${classpath} + debug: ${compile.debug} + src.dir: ${src.dir} + + + + + + + + + + + + + + + + + + + + + + + +