felix-framework-4.0.1.orig/0000755000175000017500000000000011644651244015460 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/pom.xml0000644000175000017500000001002411644651234016771 0ustar drazzibdrazzib org.apache.felix felix-parent 2.1 ../pom/pom.xml 4.0.0 bundle Apache Felix Framework org.apache.felix.framework 4.0.1 $ scm:svn:http://svn.apache.org/repos/asf/felix/releases/org.apache.felix.framework-4.0.1 scm:svn:https://svn.apache.org/repos/asf/felix/releases/org.apache.felix.framework-4.0.1 scm:svn:https://svn.apache.org/repos/asf/felix/releases/org.apache.felix.framework-4.0.1 org.apache.maven.plugins maven-compiler-plugin jsr14 1.5 org.apache.felix maven-bundle-plugin 2.3.5 true org.apache.felix.framework Apache Felix Framework OSGi R4 framework implementation. The Apache Software Foundation org.osgi.framework.*;-split-package:=merge-first,org.osgi.service.packageadmin,org.osgi.service.url,org.osgi.service.startlevel,org.osgi.util.tracker org.apache.felix.framework.* !* org.apache.rat apache-rat-plugin verify check src/** src/main/appended-resources/** src/**/packageinfo src/main/resources/META-INF/services/org.osgi.framework.launch.FrameworkFactory src/main/resources/org/apache/felix/framework/Felix.properties src/main/resources true felix-framework-4.0.1.orig/LICENSE0000644000175000017500000005427411644651244016501 0ustar drazzibdrazzib 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. 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. felix-framework-4.0.1.orig/NOTICE0000644000175000017500000000053211644651244016364 0ustar drazzibdrazzib Apache Felix Framework Copyright 2006-2011 The Apache Software Foundation This product includes software developed at The Apache Software Foundation (http://www.apache.org/). This product includes software developed at The OSGi Alliance (http://www.osgi.org/). Copyright (c) OSGi Alliance (2000, 2009). Licensed under the Apache License 2.0. felix-framework-4.0.1.orig/DEPENDENCIES0000644000175000017500000000164311644651244017235 0ustar drazzibdrazzib// ------------------------------------------------------------------ // Transitive dependencies of this project determined from the // maven pom organized by organization. // ------------------------------------------------------------------ Apache Felix Framework Copyright 2011 The Apache Software Foundation This software was developed at the Apache Software Foundation (http://www.apache.org) and may have dependencies on other Apache software licensed under Apache License 2.0. I. Included Third-Party Software This product includes software developed at The OSGi Alliance (http://www.osgi.org/). Copyright (c) OSGi Alliance (2000, 2009). Licensed under the Apache License 2.0. II. Used Third-Party Software This product uses software developed at The OSGi Alliance (http://www.osgi.org/). Copyright (c) OSGi Alliance (2000, 2009). Licensed under the Apache License 2.0. III. License Summary - Apache License 2.0 felix-framework-4.0.1.orig/src/0000755000175000017500000000000011644651227016250 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/src/main/0000755000175000017500000000000011644651234017172 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/src/main/appended-resources/0000755000175000017500000000000011644651234022762 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/src/main/appended-resources/META-INF/0000755000175000017500000000000011655235117024122 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/src/main/appended-resources/META-INF/LICENSE0000644000175000017500000002613611644651234025137 0ustar drazzibdrazzib 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. felix-framework-4.0.1.orig/src/main/appended-resources/META-INF/NOTICE0000644000175000017500000000024711644651234025031 0ustar drazzibdrazzibThis product includes software developed at The OSGi Alliance (http://www.osgi.org/). Copyright (c) OSGi Alliance (2000, 2009). Licensed under the Apache License 2.0. felix-framework-4.0.1.orig/src/main/appended-resources/META-INF/DEPENDENCIES0000644000175000017500000000122311644651234025671 0ustar drazzibdrazzibCopyright 2011 The Apache Software Foundation This software was developed at the Apache Software Foundation (http://www.apache.org) and may have dependencies on other Apache software licensed under Apache License 2.0. I. Included Third-Party Software This product includes software developed at The OSGi Alliance (http://www.osgi.org/). Copyright (c) OSGi Alliance (2000, 2009). Licensed under the Apache License 2.0. II. Used Third-Party Software This product uses software developed at The OSGi Alliance (http://www.osgi.org/). Copyright (c) OSGi Alliance (2000, 2009). Licensed under the Apache License 2.0. III. License Summary - Apache License 2.0 felix-framework-4.0.1.orig/src/main/resources/0000755000175000017500000000000011655235117021204 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/src/main/resources/META-INF/0000755000175000017500000000000011644651234022344 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/src/main/resources/META-INF/services/0000755000175000017500000000000011655235117024167 5ustar drazzibdrazzib././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootrootfelix-framework-4.0.1.orig/src/main/resources/META-INF/services/org.osgi.framework.launch.FrameworkFactoryfelix-framework-4.0.1.orig/src/main/resources/META-INF/services/org.osgi.framework.launch.FrameworkF0000644000175000017500000000005411644651234033147 0ustar drazzibdrazziborg.apache.felix.framework.FrameworkFactory felix-framework-4.0.1.orig/src/main/resources/default.properties0000644000175000017500000017613311644651234024761 0ustar drazzibdrazzib# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # Framework config properties. # # New-style generic execution environment capabilities. org.osgi.framework.system.capabilities= \ ${dollar}{eecap-${dollar}{java.specification.version}} eecap-1.7= osgi.ee; osgi.ee="OSGi/Minimum"; version:List="1.0,1.1,1.2", \ osgi.ee; osgi.ee="JavaSE"; version:List="1.0,1.1,1.2,1.3,1.4,1.5,1.6,1.7" eecap-1.6= osgi.ee; osgi.ee="OSGi/Minimum"; version:List="1.0,1.1,1.2", \ osgi.ee; osgi.ee="JavaSE"; version:List="1.0,1.1,1.2,1.3,1.4,1.5,1.6" eecap-1.5= osgi.ee; osgi.ee="OSGi/Minimum"; version:List="1.0,1.1,1.2", \ osgi.ee; osgi.ee="JavaSE"; version:List="1.0,1.1,1.2,1.3,1.4,1.5" eecap-1.4= osgi.ee; osgi.ee="OSGi/Minimum"; version:List="1.0,1.1,1.2", \ osgi.ee; osgi.ee="JavaSE"; version:List="1.0,1.1,1.2,1.3,1.4" eecap-1.3= osgi.ee; osgi.ee="OSGi/Minimum"; version:List="1.0,1.1", \ osgi.ee; osgi.ee="JavaSE"; version:List="1.0,1.1,1.2,1.3" eecap-1.2= osgi.ee; osgi.ee="OSGi/Minimum"; version:List="1.0,1.1", \ osgi.ee; osgi.ee="JavaSE"; version:List="1.0,1.1,1.2" # Deprecated old-style execution environment properties. org.osgi.framework.executionenvironment= \ ${dollar}{ee-${dollar}{java.specification.version}} ee-1.7=JavaSE-1.7,JavaSE-1.6,J2SE-1.5,J2SE-1.4,J2SE-1.3, \ J2SE-1.2,JRE-1.1,JRE-1.0,OSGi/Minimum-1.2,OSGi/Minimum-1.1, \ OSGi/Minimum-1.0 ee-1.6=JavaSE-1.6,J2SE-1.5,J2SE-1.4,J2SE-1.3,J2SE-1.2, \ JRE-1.1,JRE-1.0,OSGi/Minimum-1.2,OSGi/Minimum-1.1,OSGi/Minimum-1.0 ee-1.5=J2SE-1.5,J2SE-1.4,J2SE-1.3,J2SE-1.2,JRE-1.1,JRE-1.0, \ OSGi/Minimum-1.2,OSGi/Minimum-1.1,OSGi/Minimum-1.0 ee-1.4=J2SE-1.4,J2SE-1.3,J2SE-1.2,JRE-1.1,JRE-1.0,OSGi/Minimum-1.2, \ OSGi/Minimum-1.1,OSGi/Minimum-1.0 ee-1.3=J2SE-1.3,J2SE-1.2,JRE-1.1,JRE-1.0,OSGi/Minimum-1.1,OSGi/Minimum-1.0 ee-1.2=J2SE-1.2,JRE-1.1,JRE-1.0,OSGi/Minimum-1.1,OSGi/Minimum-1.0 # Default packages exported by system bundle. org.osgi.framework.system.packages=org.osgi.framework; version=1.6.0, \ org.osgi.framework.launch; version=1.0.0, \ org.osgi.framework.wiring; version=1.0.0, \ org.osgi.framework.startlevel; version=1.0.0, \ org.osgi.framework.hooks.bundle; version=1.0.0, \ org.osgi.framework.hooks.resolver; version=1.0.0, \ org.osgi.framework.hooks.service; version=1.1.0, \ org.osgi.framework.hooks.weaving; version=1.0.0, \ org.osgi.service.packageadmin; version=1.2.0, \ org.osgi.service.startlevel; version=1.1.0, \ org.osgi.service.url; version=1.0.0, \ org.osgi.util.tracker; version=1.5.0 \ ${dollar}{jre-${dollar}{java.specification.version}} # # Java platform package export properties. # jre-1.3=, \ javax.accessibility;uses:="javax.swing.text";version="0.0.0.1_003_J2SE", \ javax.naming.directory;uses:="javax.naming";version="0.0.0.1_003_J2SE", \ javax.naming.event;uses:="javax.naming,javax.naming.directory";version="0.0.0.1_003_J2SE", \ javax.naming.ldap;uses:="javax.naming,javax.naming.directory,javax.naming.event";version="0.0.0.1_003_J2SE", \ javax.naming.spi;uses:="javax.naming,javax.naming.directory";version="0.0.0.1_003_J2SE", \ javax.naming;uses:="javax.naming.spi";version="0.0.0.1_003_J2SE", \ javax.rmi.CORBA;uses:="org.omg.CORBA,org.omg.CORBA_2_3.portable,org.omg.CORBA.portable,org.omg.SendingContext";version="0.0.0.1_003_J2SE", \ javax.rmi;uses:="org.omg.CORBA,javax.rmi.CORBA";version="0.0.0.1_003_J2SE", \ javax.sound.midi.spi;uses:="javax.sound.midi";version="0.0.0.1_003_J2SE", \ javax.sound.midi;uses:="javax.sound.midi.spi";version="0.0.0.1_003_J2SE", \ javax.sound.sampled.spi;uses:="javax.sound.sampled";version="0.0.0.1_003_J2SE", \ javax.sound.sampled;uses:="javax.sound.sampled.spi";version="0.0.0.1_003_J2SE", \ javax.swing.border;uses:="javax.swing";version="0.0.0.1_003_J2SE", \ javax.swing.colorchooser;uses:="javax.swing.event,javax.swing,javax.swing.text,javax.swing.border,javax.accessibility";version="0.0.0.1_003_J2SE", \ javax.swing.event;uses:="javax.swing,javax.swing.text,javax.swing.table,javax.swing.tree,javax.swing.undo";version="0.0.0.1_003_J2SE", \ javax.swing.filechooser;uses:="javax.swing";version="0.0.0.1_003_J2SE", \ javax.swing.plaf.basic;uses:="javax.swing,javax.swing.border,javax.swing.plaf,javax.swing.text,javax.swing.event,javax.swing.colorchooser,javax.accessibility,javax.swing.filechooser,javax.swing.text.html,javax.swing.table,javax.swing.tree";version="0.0.0.1_003_J2SE", \ javax.swing.plaf.metal;uses:="javax.swing.plaf,javax.swing.border,javax.swing,javax.swing.text,javax.swing.plaf.basic,javax.swing.event,javax.swing.filechooser,javax.accessibility,javax.swing.tree";version="0.0.0.1_003_J2SE", \ javax.swing.plaf.multi;uses:="javax.accessibility,javax.swing,javax.swing.plaf,javax.swing.filechooser,javax.swing.text,javax.swing.tree";version="0.0.0.1_003_J2SE", \ javax.swing.plaf;uses:="javax.swing,javax.swing.border,javax.accessibility,javax.swing.filechooser,javax.swing.text,javax.swing.tree";version="0.0.0.1_003_J2SE", \ javax.swing.table;uses:="javax.swing.event,javax.swing.plaf,javax.swing.border,javax.swing,javax.accessibility";version="0.0.0.1_003_J2SE", \ javax.swing.text.html.parser;uses:="javax.swing.text.html,javax.swing.text";version="0.0.0.1_003_J2SE", \ javax.swing.text.html;uses:="javax.swing.text,javax.swing,javax.swing.event,javax.swing.border,javax.swing.undo,javax.swing.plaf,javax.swing.text.html.parser";version="0.0.0.1_003_J2SE", \ javax.swing.text.rtf;uses:="javax.swing.text";version="0.0.0.1_003_J2SE", \ javax.swing.text;uses:="javax.swing.event,javax.swing.tree,javax.swing.undo,javax.swing,javax.swing.plaf,javax.swing.plaf.basic,javax.accessibility,javax.swing.text.html";version="0.0.0.1_003_J2SE", \ javax.swing.tree;uses:="javax.swing.event,javax.swing,javax.swing.border,javax.swing.plaf";version="0.0.0.1_003_J2SE", \ javax.swing.undo;uses:="javax.swing,javax.swing.event";version="0.0.0.1_003_J2SE", \ javax.swing;uses:="javax.swing.event,javax.swing.text,javax.accessibility,javax.swing.plaf,javax.swing.border,javax.swing.tree,javax.swing.table,javax.swing.colorchooser,javax.swing.plaf.basic,javax.swing.text.html,javax.swing.filechooser";version="0.0.0.1_003_J2SE", \ javax.transaction;version="0.0.0.1_003_J2SE", \ org.omg.CORBA.DynAnyPackage;uses:="org.omg.CORBA";version="0.0.0.1_003_J2SE", \ org.omg.CORBA.ORBPackage;uses:="org.omg.CORBA";version="0.0.0.1_003_J2SE", \ org.omg.CORBA.TypeCodePackage;uses:="org.omg.CORBA";version="0.0.0.1_003_J2SE", \ org.omg.CORBA.portable;uses:="org.omg.CORBA,org.omg.CORBA_2_3.portable";version="0.0.0.1_003_J2SE", \ org.omg.CORBA;uses:="org.omg.CORBA.portable,org.omg.CORBA.DynAnyPackage,org.omg.CORBA.ORBPackage,org.omg.CORBA_2_3.portable,org.omg.CORBA.TypeCodePackage";version="0.0.0.1_003_J2SE", \ org.omg.CORBA_2_3.portable;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_003_J2SE", \ org.omg.CORBA_2_3;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_003_J2SE", \ org.omg.CosNaming.NamingContextPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable,org.omg.CosNaming";version="0.0.0.1_003_J2SE", \ org.omg.CosNaming;uses:="org.omg.CORBA.portable,org.omg.CORBA,org.omg.CosNaming.NamingContextPackage";version="0.0.0.1_003_J2SE", \ org.omg.SendingContext;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_003_J2SE", \ org.omg.stub.java.rmi;uses:="javax.rmi.CORBA";version="0.0.0.1_003_J2SE" jre-1.4=, \ javax.accessibility;uses:="javax.swing.text";version="0.0.0.1_004_J2SE", \ javax.crypto.interfaces;uses:="javax.crypto.spec,javax.crypto";version="0.0.0.1_004_J2SE", \ javax.crypto.spec;uses:="javax.crypto";version="0.0.0.1_004_J2SE", \ javax.crypto;uses:="javax.crypto.spec";version="0.0.0.1_004_J2SE", \ javax.imageio.event;uses:="javax.imageio";version="0.0.0.1_004_J2SE", \ javax.imageio.metadata;uses:="org.w3c.dom,javax.imageio,org.apache.crimson.util";version="0.0.0.1_004_J2SE", \ javax.imageio.plugins.jpeg;uses:="javax.imageio";version="0.0.0.1_004_J2SE", \ javax.imageio.spi;uses:="javax.imageio.stream,javax.imageio,javax.imageio.metadata";version="0.0.0.1_004_J2SE", \ javax.imageio.stream;uses:="javax.imageio";version="0.0.0.1_004_J2SE", \ javax.imageio;uses:="javax.imageio.metadata,javax.imageio.stream,javax.imageio.spi,javax.imageio.event";version="0.0.0.1_004_J2SE", \ javax.naming.directory;uses:="javax.naming";version="0.0.0.1_004_J2SE", \ javax.naming.event;uses:="javax.naming,javax.naming.directory";version="0.0.0.1_004_J2SE", \ javax.naming.ldap;uses:="javax.naming,javax.naming.directory,javax.net.ssl,javax.naming.event";version="0.0.0.1_004_J2SE", \ javax.naming.spi;uses:="javax.naming,javax.naming.directory";version="0.0.0.1_004_J2SE", \ javax.naming;uses:="javax.naming.spi";version="0.0.0.1_004_J2SE", \ javax.net.ssl;uses:="javax.security.cert,javax.net";version="0.0.0.1_004_J2SE", \ javax.net;version="0.0.0.1_004_J2SE", \ javax.print.attribute.standard;uses:="javax.print.attribute";version="0.0.0.1_004_J2SE", \ javax.print.attribute;version="0.0.0.1_004_J2SE", \ javax.print.event;uses:="javax.print,javax.print.attribute";version="0.0.0.1_004_J2SE", \ javax.print;uses:="javax.print.attribute,javax.print.event,javax.print.attribute.standard";version="0.0.0.1_004_J2SE", \ javax.rmi.CORBA;uses:="org.omg.CORBA,org.omg.CORBA_2_3.portable,org.omg.CORBA.portable,org.omg.SendingContext";version="0.0.0.1_004_J2SE", \ javax.rmi;uses:="org.omg.CORBA,javax.rmi.CORBA";version="0.0.0.1_004_J2SE", \ javax.security.auth.callback;version="0.0.0.1_004_J2SE", \ javax.security.auth.kerberos;uses:="javax.security.auth,javax.crypto";version="0.0.0.1_004_J2SE", \ javax.security.auth.login;uses:="javax.security.auth,javax.security.auth.callback";version="0.0.0.1_004_J2SE", \ javax.security.auth.spi;uses:="javax.security.auth.callback,javax.security.auth.login,javax.security.auth";version="0.0.0.1_004_J2SE", \ javax.security.auth.x500;uses:="javax.security.auth";version="0.0.0.1_004_J2SE", \ javax.security.auth;version="0.0.0.1_004_J2SE", \ javax.security.cert;version="0.0.0.1_004_J2SE", \ javax.sound.midi.spi;uses:="javax.sound.midi";version="0.0.0.1_004_J2SE", \ javax.sound.midi;uses:="javax.sound.midi.spi";version="0.0.0.1_004_J2SE", \ javax.sound.sampled.spi;uses:="javax.sound.sampled";version="0.0.0.1_004_J2SE", \ javax.sound.sampled;uses:="javax.sound.sampled.spi";version="0.0.0.1_004_J2SE", \ javax.sql;uses:="javax.transaction.xa";version="0.0.0.1_004_J2SE", \ javax.swing.border;uses:="javax.swing";version="0.0.0.1_004_J2SE", \ javax.swing.colorchooser;uses:="javax.swing.event,javax.swing,javax.swing.border,javax.accessibility";version="0.0.0.1_004_J2SE", \ javax.swing.event;uses:="javax.swing,javax.swing.text,javax.swing.table,javax.swing.tree,javax.swing.undo";version="0.0.0.1_004_J2SE", \ javax.swing.filechooser;uses:="javax.swing";version="0.0.0.1_004_J2SE", \ javax.swing.plaf.basic;uses:="javax.swing.border,javax.swing,javax.swing.plaf,javax.swing.text,javax.swing.event,javax.swing.colorchooser,javax.accessibility,javax.swing.filechooser,javax.swing.text.html,javax.sound.sampled,javax.swing.table,javax.swing.tree";version="0.0.0.1_004_J2SE", \ javax.swing.plaf.metal;uses:="javax.swing.plaf,javax.swing,javax.swing.border,javax.swing.text,javax.swing.plaf.basic,javax.swing.filechooser,javax.swing.event,javax.swing.table,javax.accessibility,javax.swing.tree";version="0.0.0.1_004_J2SE", \ javax.swing.plaf.multi;uses:="javax.accessibility,javax.swing,javax.swing.plaf,javax.swing.filechooser,javax.swing.text,javax.swing.tree";version="0.0.0.1_004_J2SE", \ javax.swing.plaf;uses:="javax.swing,javax.swing.border,javax.accessibility,javax.swing.filechooser,javax.swing.text,javax.swing.tree";version="0.0.0.1_004_J2SE", \ javax.swing.table;uses:="javax.swing.event,javax.swing.plaf,javax.swing.border,javax.swing,javax.accessibility";version="0.0.0.1_004_J2SE", \ javax.swing.text.html.parser;uses:="javax.swing.text,javax.swing.text.html";version="0.0.0.1_004_J2SE", \ javax.swing.text.html;uses:="javax.swing.event,javax.swing.text,javax.accessibility,javax.swing,javax.swing.plaf,javax.swing.border,javax.swing.undo,javax.swing.text.html.parser";version="0.0.0.1_004_J2SE", \ javax.swing.text.rtf;uses:="javax.swing.text";version="0.0.0.1_004_J2SE", \ javax.swing.text;uses:="javax.swing.event,javax.swing.tree,javax.swing.undo,javax.swing,javax.swing.plaf,javax.swing.plaf.basic,javax.accessibility,javax.swing.text.html";version="0.0.0.1_004_J2SE", \ javax.swing.tree;uses:="javax.swing.event,javax.swing,javax.swing.border,javax.swing.plaf";version="0.0.0.1_004_J2SE", \ javax.swing.undo;uses:="javax.swing,javax.swing.event";version="0.0.0.1_004_J2SE", \ javax.swing;uses:="javax.swing.event,javax.accessibility,javax.swing.text,javax.swing.plaf,javax.swing.border,javax.swing.tree,javax.swing.table,javax.swing.colorchooser,javax.swing.plaf.basic,javax.swing.text.html,javax.swing.filechooser";version="0.0.0.1_004_J2SE", \ javax.transaction.xa;version="0.0.0.1_004_J2SE", \ javax.transaction;version="0.0.0.1_004_J2SE", \ javax.xml.parsers;uses:="org.w3c.dom,org.xml.sax,org.xml.sax.helpers";version="0.0.0.1_004_J2SE", \ javax.xml.transform.dom;uses:="javax.xml.transform,org.w3c.dom";version="0.0.0.1_004_J2SE", \ javax.xml.transform.sax;uses:="org.xml.sax.ext,javax.xml.transform,org.xml.sax,javax.xml.transform.stream";version="0.0.0.1_004_J2SE", \ javax.xml.transform.stream;uses:="javax.xml.transform";version="0.0.0.1_004_J2SE", \ javax.xml.transform;version="0.0.0.1_004_J2SE", \ org.ietf.jgss;version="0.0.0.1_004_J2SE", \ org.omg.CORBA.DynAnyPackage;uses:="org.omg.CORBA";version="0.0.0.1_004_J2SE", \ org.omg.CORBA.ORBPackage;uses:="org.omg.CORBA";version="0.0.0.1_004_J2SE", \ org.omg.CORBA.TypeCodePackage;uses:="org.omg.CORBA";version="0.0.0.1_004_J2SE", \ org.omg.CORBA.portable;uses:="org.omg.CORBA,org.omg.CORBA_2_3.portable";version="0.0.0.1_004_J2SE", \ org.omg.CORBA;uses:="org.omg.CORBA.portable,org.omg.CORBA.DynAnyPackage,org.omg.CORBA.ORBPackage,org.omg.CORBA_2_3.portable,org.omg.CORBA.TypeCodePackage";version="0.0.0.1_004_J2SE", \ org.omg.CORBA_2_3.portable;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_004_J2SE", \ org.omg.CORBA_2_3;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_004_J2SE", \ org.omg.CosNaming.NamingContextExtPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_004_J2SE", \ org.omg.CosNaming.NamingContextPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable,org.omg.CosNaming";version="0.0.0.1_004_J2SE", \ org.omg.CosNaming;uses:="org.omg.CORBA.portable,org.omg.CORBA,org.omg.PortableServer,org.omg.CosNaming.NamingContextPackage,org.omg.CosNaming.NamingContextExtPackage";version="0.0.0.1_004_J2SE", \ org.omg.Dynamic;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_004_J2SE", \ org.omg.DynamicAny.DynAnyFactoryPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_004_J2SE", \ org.omg.DynamicAny.DynAnyPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_004_J2SE", \ org.omg.DynamicAny;uses:="org.omg.CORBA,org.omg.CORBA.portable,org.omg.DynamicAny.DynAnyFactoryPackage,org.omg.DynamicAny.DynAnyPackage";version="0.0.0.1_004_J2SE", \ org.omg.IOP.CodecFactoryPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_004_J2SE", \ org.omg.IOP.CodecPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_004_J2SE", \ org.omg.IOP;uses:="org.omg.CORBA,org.omg.CORBA.portable,org.omg.IOP.CodecFactoryPackage,org.omg.IOP.CodecPackage";version="0.0.0.1_004_J2SE", \ org.omg.Messaging;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_004_J2SE", \ org.omg.PortableInterceptor.ORBInitInfoPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_004_J2SE", \ org.omg.PortableInterceptor;uses:="org.omg.CORBA.portable,org.omg.CORBA,org.omg.IOP,org.omg.PortableInterceptor.ORBInitInfoPackage,org.omg.Dynamic";version="0.0.0.1_004_J2SE", \ org.omg.PortableServer.CurrentPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_004_J2SE", \ org.omg.PortableServer.POAManagerPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_004_J2SE", \ org.omg.PortableServer.POAPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_004_J2SE", \ org.omg.PortableServer.ServantLocatorPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_004_J2SE", \ org.omg.PortableServer.portable;uses:="org.omg.CORBA,org.omg.PortableServer";version="0.0.0.1_004_J2SE", \ org.omg.PortableServer;uses:="org.omg.CORBA,org.omg.CORBA.portable,org.omg.PortableServer.CurrentPackage,org.omg.PortableServer.POAManagerPackage,org.omg.PortableServer.POAPackage,org.omg.PortableServer.portable,org.omg.CORBA_2_3,org.omg.PortableServer.ServantLocatorPackage";version="0.0.0.1_004_J2SE", \ org.omg.SendingContext;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_004_J2SE", \ org.omg.stub.java.rmi;uses:="javax.rmi.CORBA";version="0.0.0.1_004_J2SE", \ org.w3c.dom;version="0.0.0.1_004_J2SE", \ org.xml.sax.ext;uses:="org.xml.sax";version="0.0.0.1_004_J2SE", \ org.xml.sax.helpers;uses:="org.xml.sax";version="0.0.0.1_004_J2SE", \ org.xml.sax;version="0.0.0.1_004_J2SE" jre-1.5=, \ javax.accessibility;uses:="javax.swing.text";version="0.0.0.1_005_J2SE", \ javax.activity;version="0.0.0.1_005_J2SE", \ javax.crypto.interfaces;uses:="javax.crypto.spec,javax.crypto";version="0.0.0.1_005_J2SE", \ javax.crypto.spec;uses:="javax.crypto";version="0.0.0.1_005_J2SE", \ javax.crypto;uses:="javax.crypto.spec";version="0.0.0.1_005_J2SE", \ javax.imageio.event;uses:="javax.imageio";version="0.0.0.1_005_J2SE", \ javax.imageio.metadata;uses:="org.w3c.dom,javax.imageio";version="0.0.0.1_005_J2SE", \ javax.imageio.plugins.bmp;uses:="javax.imageio";version="0.0.0.1_005_J2SE", \ javax.imageio.plugins.jpeg;uses:="javax.imageio";version="0.0.0.1_005_J2SE", \ javax.imageio.spi;uses:="javax.imageio.stream,javax.imageio,javax.imageio.metadata";version="0.0.0.1_005_J2SE", \ javax.imageio.stream;uses:="javax.imageio";version="0.0.0.1_005_J2SE", \ javax.imageio;uses:="javax.imageio.metadata,javax.imageio.stream,javax.imageio.spi,javax.imageio.event";version="0.0.0.1_005_J2SE", \ javax.management.loading;uses:="javax.management";version="0.0.0.1_005_J2SE", \ javax.management.modelmbean;uses:="javax.management,javax.management.loading";version="0.0.0.1_005_J2SE", \ javax.management.monitor;uses:="javax.management";version="0.0.0.1_005_J2SE", \ javax.management.openmbean;uses:="javax.management";version="0.0.0.1_005_J2SE", \ javax.management.relation;uses:="javax.management";version="0.0.0.1_005_J2SE", \ javax.management.remote.rmi;uses:="javax.management.remote,javax.security.auth,javax.management,javax.naming,org.omg.CORBA,org.omg.CORBA.portable,javax.rmi,javax.rmi.CORBA";version="0.0.0.1_005_J2SE", \ javax.management.remote;uses:="javax.security.auth,javax.management";version="0.0.0.1_005_J2SE", \ javax.management.timer;uses:="javax.management";version="0.0.0.1_005_J2SE", \ javax.management;uses:="javax.management.loading";version="0.0.0.1_005_J2SE", \ javax.naming.directory;uses:="javax.naming";version="0.0.0.1_005_J2SE", \ javax.naming.event;uses:="javax.naming,javax.naming.directory";version="0.0.0.1_005_J2SE", \ javax.naming.ldap;uses:="javax.naming,javax.naming.directory,javax.net.ssl,javax.naming.event";version="0.0.0.1_005_J2SE", \ javax.naming.spi;uses:="javax.naming,javax.naming.directory";version="0.0.0.1_005_J2SE", \ javax.naming;uses:="javax.naming.spi";version="0.0.0.1_005_J2SE", \ javax.net.ssl;uses:="javax.security.cert,javax.security.auth.x500,javax.net";version="0.0.0.1_005_J2SE", \ javax.net;version="0.0.0.1_005_J2SE", \ javax.print.attribute.standard;uses:="javax.print.attribute";version="0.0.0.1_005_J2SE", \ javax.print.attribute;version="0.0.0.1_005_J2SE", \ javax.print.event;uses:="javax.print,javax.print.attribute";version="0.0.0.1_005_J2SE", \ javax.print;uses:="javax.print.attribute,javax.print.event,javax.print.attribute.standard";version="0.0.0.1_005_J2SE", \ javax.rmi.CORBA;uses:="org.omg.CORBA,org.omg.CORBA_2_3.portable,org.omg.CORBA.portable,org.omg.SendingContext";version="0.0.0.1_005_J2SE", \ javax.rmi.ssl;uses:="javax.net,javax.net.ssl";version="0.0.0.1_005_J2SE", \ javax.rmi;uses:="org.omg.CORBA,javax.rmi.CORBA";version="0.0.0.1_005_J2SE", \ javax.security.auth.callback;version="0.0.0.1_005_J2SE", \ javax.security.auth.kerberos;uses:="javax.security.auth,javax.crypto";version="0.0.0.1_005_J2SE", \ javax.security.auth.login;uses:="javax.security.auth,javax.security.auth.callback";version="0.0.0.1_005_J2SE", \ javax.security.auth.spi;uses:="javax.security.auth.callback,javax.security.auth.login,javax.security.auth";version="0.0.0.1_005_J2SE", \ javax.security.auth.x500;uses:="javax.security.auth";version="0.0.0.1_005_J2SE", \ javax.security.auth;version="0.0.0.1_005_J2SE", \ javax.security.cert;version="0.0.0.1_005_J2SE", \ javax.security.sasl;uses:="javax.security.auth.callback";version="0.0.0.1_005_J2SE", \ javax.sound.midi.spi;uses:="javax.sound.midi";version="0.0.0.1_005_J2SE", \ javax.sound.midi;uses:="javax.sound.midi.spi";version="0.0.0.1_005_J2SE", \ javax.sound.sampled.spi;uses:="javax.sound.sampled";version="0.0.0.1_005_J2SE", \ javax.sound.sampled;uses:="javax.sound.sampled.spi";version="0.0.0.1_005_J2SE", \ javax.sql.rowset.serial;uses:="javax.sql.rowset";version="0.0.0.1_005_J2SE", \ javax.sql.rowset.spi;uses:="javax.sql,javax.naming,javax.sql.rowset";version="0.0.0.1_005_J2SE", \ javax.sql.rowset;uses:="javax.sql,javax.sql.rowset.serial,javax.sql.rowset.spi";version="0.0.0.1_005_J2SE", \ javax.sql;uses:="javax.transaction.xa";version="0.0.0.1_005_J2SE", \ javax.swing.border;uses:="javax.swing";version="0.0.0.1_005_J2SE", \ javax.swing.colorchooser;uses:="javax.swing.event,javax.swing,javax.swing.border";version="0.0.0.1_005_J2SE", \ javax.swing.event;uses:="javax.swing,javax.swing.text,javax.swing.table,javax.swing.tree,javax.swing.undo";version="0.0.0.1_005_J2SE", \ javax.swing.filechooser;uses:="javax.swing";version="0.0.0.1_005_J2SE", \ javax.swing.plaf.basic;uses:="javax.swing.border,javax.swing,javax.swing.plaf,javax.swing.text,javax.swing.event,javax.swing.colorchooser,javax.accessibility,javax.swing.filechooser,javax.swing.text.html,javax.sound.sampled,javax.swing.table,javax.swing.tree";version="0.0.0.1_005_J2SE", \ javax.swing.plaf.metal;uses:="javax.swing.plaf,javax.swing,javax.swing.border,javax.swing.text,javax.swing.plaf.basic,javax.swing.filechooser,javax.swing.event,javax.accessibility,javax.swing.tree";version="0.0.0.1_005_J2SE", \ javax.swing.plaf.multi;uses:="javax.accessibility,javax.swing,javax.swing.plaf,javax.swing.filechooser,javax.swing.text,javax.swing.tree";version="0.0.0.1_005_J2SE", \ javax.swing.plaf.synth;uses:="javax.swing,javax.swing.plaf,javax.swing.border,javax.swing.plaf.basic,javax.swing.colorchooser,javax.swing.text,javax.xml.parsers,org.xml.sax,javax.swing.table,javax.swing.tree";version="0.0.0.1_005_J2SE", \ javax.swing.plaf;uses:="javax.swing,javax.swing.border,javax.accessibility,javax.swing.filechooser,javax.swing.text,javax.swing.tree";version="0.0.0.1_005_J2SE", \ javax.swing.table;uses:="javax.swing.event,javax.swing.plaf,javax.swing.border,javax.swing,javax.accessibility";version="0.0.0.1_005_J2SE", \ javax.swing.text.html.parser;uses:="javax.swing.text.html,javax.swing.text";version="0.0.0.1_005_J2SE", \ javax.swing.text.html;uses:="javax.swing.event,javax.swing.text,javax.accessibility,javax.swing,javax.swing.plaf,javax.swing.border,javax.swing.undo";version="0.0.0.1_005_J2SE", \ javax.swing.text.rtf;uses:="javax.swing.text";version="0.0.0.1_005_J2SE", \ javax.swing.text;uses:="javax.swing.event,javax.swing.tree,javax.swing.undo,javax.swing,javax.swing.plaf,javax.swing.plaf.basic,javax.accessibility,javax.swing.text.html";version="0.0.0.1_005_J2SE", \ javax.swing.tree;uses:="javax.swing.event,javax.swing,javax.swing.border,javax.swing.plaf,javax.swing.plaf.basic";version="0.0.0.1_005_J2SE", \ javax.swing.undo;uses:="javax.swing,javax.swing.event";version="0.0.0.1_005_J2SE", \ javax.swing;uses:="javax.swing.event,javax.accessibility,javax.swing.text,javax.swing.plaf,javax.swing.border,javax.swing.tree,javax.swing.table,javax.swing.colorchooser,javax.swing.plaf.basic,javax.swing.text.html,javax.swing.filechooser,javax.print.attribute,javax.swing.plaf.metal";version="0.0.0.1_005_J2SE", \ javax.transaction.xa;version="0.0.0.1_005_J2SE", \ javax.transaction;version="0.0.0.1_005_J2SE", \ javax.xml.datatype;uses:="javax.xml.namespace";version="0.0.0.1_005_J2SE", \ javax.xml.namespace;version="0.0.0.1_005_J2SE", \ javax.xml.parsers;uses:="javax.xml.validation,org.w3c.dom,org.xml.sax,org.xml.sax.helpers";version="0.0.0.1_005_J2SE", \ javax.xml.transform.dom;uses:="javax.xml.transform,org.w3c.dom";version="0.0.0.1_005_J2SE", \ javax.xml.transform.sax;uses:="org.xml.sax.ext,javax.xml.transform,org.xml.sax,javax.xml.transform.stream";version="0.0.0.1_005_J2SE", \ javax.xml.transform.stream;uses:="javax.xml.transform";version="0.0.0.1_005_J2SE", \ javax.xml.transform;version="0.0.0.1_005_J2SE", \ javax.xml.validation;uses:="org.w3c.dom.ls,javax.xml.transform,javax.xml.transform.stream,org.xml.sax,org.w3c.dom";version="0.0.0.1_005_J2SE", \ javax.xml.xpath;uses:="org.xml.sax,javax.xml.namespace";version="0.0.0.1_005_J2SE", \ javax.xml;version="0.0.0.1_005_J2SE", \ org.ietf.jgss;version="0.0.0.1_005_J2SE", \ org.omg.CORBA.DynAnyPackage;uses:="org.omg.CORBA";version="0.0.0.1_005_J2SE", \ org.omg.CORBA.ORBPackage;uses:="org.omg.CORBA";version="0.0.0.1_005_J2SE", \ org.omg.CORBA.TypeCodePackage;uses:="org.omg.CORBA";version="0.0.0.1_005_J2SE", \ org.omg.CORBA.portable;uses:="org.omg.CORBA,org.omg.CORBA_2_3.portable";version="0.0.0.1_005_J2SE", \ org.omg.CORBA;uses:="org.omg.CORBA.portable,org.omg.CORBA.DynAnyPackage,org.omg.CORBA.ORBPackage,org.omg.CORBA_2_3.portable,org.omg.CORBA.TypeCodePackage";version="0.0.0.1_005_J2SE", \ org.omg.CORBA_2_3.portable;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_005_J2SE", \ org.omg.CORBA_2_3;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_005_J2SE", \ org.omg.CosNaming.NamingContextExtPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_005_J2SE", \ org.omg.CosNaming.NamingContextPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable,org.omg.CosNaming";version="0.0.0.1_005_J2SE", \ org.omg.CosNaming;uses:="org.omg.CORBA.portable,org.omg.CORBA,org.omg.PortableServer,org.omg.CosNaming.NamingContextPackage,org.omg.CosNaming.NamingContextExtPackage";version="0.0.0.1_005_J2SE", \ org.omg.Dynamic;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_005_J2SE", \ org.omg.DynamicAny.DynAnyFactoryPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_005_J2SE", \ org.omg.DynamicAny.DynAnyPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_005_J2SE", \ org.omg.DynamicAny;uses:="org.omg.CORBA,org.omg.CORBA.portable,org.omg.DynamicAny.DynAnyFactoryPackage,org.omg.DynamicAny.DynAnyPackage";version="0.0.0.1_005_J2SE", \ org.omg.IOP.CodecFactoryPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_005_J2SE", \ org.omg.IOP.CodecPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_005_J2SE", \ org.omg.IOP;uses:="org.omg.CORBA,org.omg.CORBA.portable,org.omg.IOP.CodecFactoryPackage,org.omg.IOP.CodecPackage";version="0.0.0.1_005_J2SE", \ org.omg.Messaging;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_005_J2SE", \ org.omg.PortableInterceptor.ORBInitInfoPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_005_J2SE", \ org.omg.PortableInterceptor;uses:="org.omg.CORBA,org.omg.CORBA.portable,org.omg.IOP,org.omg.PortableInterceptor.ORBInitInfoPackage,org.omg.CORBA_2_3.portable,org.omg.Dynamic";version="0.0.0.1_005_J2SE", \ org.omg.PortableServer.CurrentPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_005_J2SE", \ org.omg.PortableServer.POAManagerPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_005_J2SE", \ org.omg.PortableServer.POAPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_005_J2SE", \ org.omg.PortableServer.ServantLocatorPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_005_J2SE", \ org.omg.PortableServer.portable;uses:="org.omg.CORBA,org.omg.PortableServer";version="0.0.0.1_005_J2SE", \ org.omg.PortableServer;uses:="org.omg.CORBA,org.omg.CORBA.portable,org.omg.PortableServer.CurrentPackage,org.omg.PortableServer.POAManagerPackage,org.omg.PortableServer.POAPackage,org.omg.PortableServer.portable,org.omg.CORBA_2_3,org.omg.PortableServer.ServantLocatorPackage";version="0.0.0.1_005_J2SE", \ org.omg.SendingContext;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_005_J2SE", \ org.omg.stub.java.rmi;uses:="javax.rmi.CORBA";version="0.0.0.1_005_J2SE", \ org.w3c.dom.bootstrap;uses:="org.w3c.dom";version="0.0.0.1_005_J2SE", \ org.w3c.dom.events;uses:="org.w3c.dom,org.w3c.dom.views";version="0.0.0.1_005_J2SE", \ org.w3c.dom.ls;uses:="org.w3c.dom,org.w3c.dom.events,org.w3c.dom.traversal";version="0.0.0.1_005_J2SE", \ org.w3c.dom;version="0.0.0.1_005_J2SE", \ org.xml.sax.ext;uses:="org.xml.sax,org.xml.sax.helpers";version="0.0.0.1_005_J2SE", \ org.xml.sax.helpers;uses:="org.xml.sax";version="0.0.0.1_005_J2SE", \ org.xml.sax;version="0.0.0.1_005_J2SE" jre-1.6=, \ javax.accessibility;uses:="javax.swing.text";version="0.0.0.1_006_JavaSE", \ javax.activation;version="0.0.0.1_006_JavaSE", \ javax.activity;version="0.0.0.1_006_JavaSE", \ javax.annotation.processing;uses:="javax.tools,javax.lang.model,javax.lang.model.element,javax.lang.model.util";version="0.0.0.1_006_JavaSE", \ javax.annotation;version="0.0.0.1_006_JavaSE", \ javax.crypto.interfaces;uses:="javax.crypto.spec,javax.crypto";version="0.0.0.1_006_JavaSE", \ javax.crypto.spec;uses:="javax.crypto";version="0.0.0.1_006_JavaSE", \ javax.crypto;uses:="javax.crypto.spec";version="0.0.0.1_006_JavaSE", \ javax.imageio.event;uses:="javax.imageio";version="0.0.0.1_006_JavaSE", \ javax.imageio.metadata;uses:="org.w3c.dom,javax.imageio";version="0.0.0.1_006_JavaSE", \ javax.imageio.plugins.bmp;uses:="javax.imageio";version="0.0.0.1_006_JavaSE", \ javax.imageio.plugins.jpeg;uses:="javax.imageio";version="0.0.0.1_006_JavaSE", \ javax.imageio.spi;uses:="javax.imageio.stream,javax.imageio,javax.imageio.metadata";version="0.0.0.1_006_JavaSE", \ javax.imageio.stream;uses:="javax.imageio";version="0.0.0.1_006_JavaSE", \ javax.imageio;uses:="javax.imageio.metadata,javax.imageio.stream,javax.imageio.spi,javax.imageio.event";version="0.0.0.1_006_JavaSE", \ javax.jws.soap;version="0.0.0.1_006_JavaSE", \ javax.jws;version="0.0.0.1_006_JavaSE", \ javax.lang.model.element;uses:="javax.lang.model.type";version="0.0.0.1_006_JavaSE", \ javax.lang.model.type;uses:="javax.lang.model.element";version="0.0.0.1_006_JavaSE", \ javax.lang.model.util;uses:="javax.lang.model,javax.lang.model.element,javax.annotation.processing,javax.lang.model.type";version="0.0.0.1_006_JavaSE", \ javax.lang.model;version="0.0.0.1_006_JavaSE", \ javax.management.loading;uses:="javax.management";version="0.0.0.1_006_JavaSE", \ javax.management.modelmbean;uses:="javax.management,javax.management.loading";version="0.0.0.1_006_JavaSE", \ javax.management.monitor;uses:="javax.management,javax.management.openmbean";version="0.0.0.1_006_JavaSE", \ javax.management.openmbean;uses:="javax.management";version="0.0.0.1_006_JavaSE", \ javax.management.relation;uses:="javax.management";version="0.0.0.1_006_JavaSE", \ javax.management.remote.rmi;uses:="javax.management.remote,javax.security.auth,javax.management,javax.management.loading,javax.naming,org.omg.CORBA,javax.rmi.ssl,org.omg.CORBA.portable,javax.rmi,javax.rmi.CORBA,org.omg.CORBA_2_3.portable";version="0.0.0.1_006_JavaSE", \ javax.management.remote;uses:="javax.security.auth,javax.management";version="0.0.0.1_006_JavaSE", \ javax.management.timer;uses:="javax.management";version="0.0.0.1_006_JavaSE", \ javax.management;uses:="javax.management.loading,javax.management.openmbean";version="0.0.0.1_006_JavaSE", \ javax.naming.directory;uses:="javax.naming";version="0.0.0.1_006_JavaSE", \ javax.naming.event;uses:="javax.naming,javax.naming.directory";version="0.0.0.1_006_JavaSE", \ javax.naming.ldap;uses:="javax.naming,javax.naming.directory,javax.net.ssl,javax.naming.event";version="0.0.0.1_006_JavaSE", \ javax.naming.spi;uses:="javax.naming,javax.naming.directory";version="0.0.0.1_006_JavaSE", \ javax.naming;uses:="javax.naming.spi";version="0.0.0.1_006_JavaSE", \ javax.net.ssl;uses:="javax.security.cert,javax.security.auth.x500,javax.net";version="0.0.0.1_006_JavaSE", \ javax.net;version="0.0.0.1_006_JavaSE", \ javax.print.attribute.standard;uses:="javax.print.attribute";version="0.0.0.1_006_JavaSE", \ javax.print.attribute;version="0.0.0.1_006_JavaSE", \ javax.print.event;uses:="javax.print,javax.print.attribute";version="0.0.0.1_006_JavaSE", \ javax.print;uses:="javax.print.attribute,javax.print.event,javax.print.attribute.standard";version="0.0.0.1_006_JavaSE", \ javax.rmi.CORBA;uses:="org.omg.CORBA,org.omg.CORBA_2_3.portable,org.omg.CORBA.portable,org.omg.SendingContext";version="0.0.0.1_006_JavaSE", \ javax.rmi.ssl;uses:="javax.net,javax.net.ssl";version="0.0.0.1_006_JavaSE", \ javax.rmi;uses:="org.omg.CORBA,javax.rmi.CORBA";version="0.0.0.1_006_JavaSE", \ javax.script;version="0.0.0.1_006_JavaSE", \ javax.security.auth.callback;version="0.0.0.1_006_JavaSE", \ javax.security.auth.kerberos;uses:="javax.security.auth,javax.crypto";version="0.0.0.1_006_JavaSE", \ javax.security.auth.login;uses:="javax.security.auth,javax.security.auth.callback";version="0.0.0.1_006_JavaSE", \ javax.security.auth.spi;uses:="javax.security.auth.callback,javax.security.auth.login,javax.security.auth";version="0.0.0.1_006_JavaSE", \ javax.security.auth.x500;uses:="javax.security.auth";version="0.0.0.1_006_JavaSE", \ javax.security.auth;version="0.0.0.1_006_JavaSE", \ javax.security.cert;version="0.0.0.1_006_JavaSE", \ javax.security.sasl;uses:="javax.security.auth.callback";version="0.0.0.1_006_JavaSE", \ javax.sound.midi.spi;uses:="javax.sound.midi";version="0.0.0.1_006_JavaSE", \ javax.sound.midi;uses:="javax.sound.midi.spi";version="0.0.0.1_006_JavaSE", \ javax.sound.sampled.spi;uses:="javax.sound.sampled";version="0.0.0.1_006_JavaSE", \ javax.sound.sampled;uses:="javax.sound.sampled.spi";version="0.0.0.1_006_JavaSE", \ javax.sql.rowset.serial;uses:="javax.sql.rowset";version="0.0.0.1_006_JavaSE", \ javax.sql.rowset.spi;uses:="javax.sql,javax.naming,javax.sql.rowset";version="0.0.0.1_006_JavaSE", \ javax.sql.rowset;uses:="javax.sql,javax.sql.rowset.serial,javax.sql.rowset.spi";version="0.0.0.1_006_JavaSE", \ javax.sql;uses:="javax.transaction.xa";version="0.0.0.1_006_JavaSE", \ javax.swing.border;uses:="javax.swing";version="0.0.0.1_006_JavaSE", \ javax.swing.colorchooser;uses:="javax.swing.event,javax.swing,javax.swing.border";version="0.0.0.1_006_JavaSE", \ javax.swing.event;uses:="javax.swing,javax.swing.text,javax.swing.table,javax.swing.tree,javax.swing.undo";version="0.0.0.1_006_JavaSE", \ javax.swing.filechooser;uses:="javax.swing";version="0.0.0.1_006_JavaSE", \ javax.swing.plaf.basic;uses:="javax.swing.border,javax.swing,javax.swing.plaf,javax.swing.text,javax.swing.event,javax.swing.colorchooser,javax.accessibility,javax.swing.filechooser,javax.swing.text.html,javax.sound.sampled,javax.swing.table,javax.swing.tree";version="0.0.0.1_006_JavaSE", \ javax.swing.plaf.metal;uses:="javax.swing.plaf,javax.swing,javax.swing.border,javax.swing.text,javax.swing.plaf.basic,javax.swing.filechooser,javax.swing.event,javax.swing.tree";version="0.0.0.1_006_JavaSE", \ javax.swing.plaf.multi;uses:="javax.accessibility,javax.swing,javax.swing.plaf,javax.swing.filechooser,javax.swing.text,javax.swing.tree";version="0.0.0.1_006_JavaSE", \ javax.swing.plaf.synth;uses:="javax.swing,javax.swing.plaf,javax.swing.text,javax.swing.border,javax.swing.plaf.basic,javax.swing.colorchooser,javax.swing.event,javax.xml.parsers,org.xml.sax,javax.swing.table,javax.swing.tree";version="0.0.0.1_006_JavaSE", \ javax.swing.plaf;uses:="javax.swing,javax.swing.border,javax.accessibility,javax.swing.filechooser,javax.swing.text,javax.swing.tree";version="0.0.0.1_006_JavaSE", \ javax.swing.table;uses:="javax.swing.event,javax.swing.plaf,javax.swing.border,javax.swing,javax.accessibility";version="0.0.0.1_006_JavaSE", \ javax.swing.text.html.parser;uses:="javax.swing.text.html,javax.swing.text";version="0.0.0.1_006_JavaSE", \ javax.swing.text.html;uses:="javax.swing.event,javax.swing.text,javax.accessibility,javax.swing,javax.swing.plaf,javax.swing.border,javax.swing.undo";version="0.0.0.1_006_JavaSE", \ javax.swing.text.rtf;uses:="javax.swing.text";version="0.0.0.1_006_JavaSE", \ javax.swing.text;uses:="javax.swing.event,javax.swing.tree,javax.swing.undo,javax.swing,javax.swing.plaf,javax.swing.plaf.basic,javax.print,javax.print.attribute,javax.accessibility,javax.swing.text.html";version="0.0.0.1_006_JavaSE", \ javax.swing.tree;uses:="javax.swing.event,javax.swing,javax.swing.border,javax.swing.plaf,javax.swing.plaf.basic";version="0.0.0.1_006_JavaSE", \ javax.swing.undo;uses:="javax.swing,javax.swing.event";version="0.0.0.1_006_JavaSE", \ javax.swing;uses:="javax.swing.event,javax.accessibility,javax.swing.text,javax.swing.plaf,javax.swing.border,javax.swing.tree,javax.swing.table,javax.swing.colorchooser,javax.swing.plaf.basic,javax.swing.text.html,javax.swing.filechooser,javax.print,javax.print.attribute,javax.swing.plaf.metal";version="0.0.0.1_006_JavaSE", \ javax.tools;uses:="javax.lang.model.element,javax.annotation.processing,javax.lang.model";version="0.0.0.1_006_JavaSE", \ javax.transaction.xa;version="0.0.0.1_006_JavaSE", \ javax.transaction;version="0.0.0.1_006_JavaSE", \ javax.xml.bind.annotation.adapters;uses:="javax.xml.bind";version="0.0.0.1_006_JavaSE", \ javax.xml.bind.annotation;uses:="javax.xml.transform,javax.xml.bind,javax.xml.parsers,javax.xml.transform.dom,org.w3c.dom";version="0.0.0.1_006_JavaSE", \ javax.xml.bind.attachment;uses:="javax.activation";version="0.0.0.1_006_JavaSE", \ javax.xml.bind.helpers;uses:="javax.xml.bind.annotation.adapters,javax.xml.transform.dom,org.w3c.dom,org.xml.sax,javax.xml.bind.attachment,javax.xml.stream,javax.xml.transform,javax.xml.transform.stream,javax.xml.validation,javax.xml.transform.sax,javax.xml.bind,javax.xml.parsers";version="0.0.0.1_006_JavaSE", \ javax.xml.bind.util;uses:="javax.xml.transform.sax,javax.xml.bind,org.xml.sax,org.xml.sax.ext,org.xml.sax.helpers";version="0.0.0.1_006_JavaSE", \ javax.xml.bind;uses:="javax.xml.validation,javax.xml.namespace,javax.xml.datatype,javax.xml.transform,javax.xml.bind.annotation,javax.xml.transform.stream,org.w3c.dom,javax.xml.bind.attachment,javax.xml.stream,javax.xml.bind.annotation.adapters,org.xml.sax";version="0.0.0.1_006_JavaSE", \ javax.xml.crypto.dom;uses:="javax.xml.crypto,org.w3c.dom";version="0.0.0.1_006_JavaSE", \ javax.xml.crypto.dsig.dom;uses:="javax.xml.crypto.dsig,javax.xml.crypto,org.w3c.dom,javax.xml.crypto.dom";version="0.0.0.1_006_JavaSE", \ javax.xml.crypto.dsig.keyinfo;uses:="javax.xml.crypto";version="0.0.0.1_006_JavaSE", \ javax.xml.crypto.dsig.spec;uses:="javax.xml.crypto";version="0.0.0.1_006_JavaSE", \ javax.xml.crypto.dsig;uses:="javax.xml.crypto,javax.xml.crypto.dsig.spec,javax.xml.crypto.dsig.keyinfo";version="0.0.0.1_006_JavaSE", \ javax.xml.crypto;uses:="javax.xml.crypto.dsig.keyinfo";version="0.0.0.1_006_JavaSE", \ javax.xml.datatype;uses:="javax.xml.namespace";version="0.0.0.1_006_JavaSE", \ javax.xml.namespace;version="0.0.0.1_006_JavaSE", \ javax.xml.parsers;uses:="javax.xml.validation,org.w3c.dom,org.xml.sax,org.xml.sax.helpers";version="0.0.0.1_006_JavaSE", \ javax.xml.soap;uses:="javax.activation,javax.xml.namespace,org.w3c.dom,javax.xml.transform.dom,javax.xml.transform";version="0.0.0.1_006_JavaSE", \ javax.xml.stream.events;uses:="javax.xml.namespace,javax.xml.stream";version="0.0.0.1_006_JavaSE", \ javax.xml.stream.util;uses:="javax.xml.stream,javax.xml.stream.events,javax.xml.namespace";version="0.0.0.1_006_JavaSE", \ javax.xml.stream;uses:="javax.xml.stream.events,javax.xml.namespace,javax.xml.stream.util,javax.xml.transform";version="0.0.0.1_006_JavaSE", \ javax.xml.transform.dom;uses:="javax.xml.transform,org.w3c.dom";version="0.0.0.1_006_JavaSE", \ javax.xml.transform.sax;uses:="org.xml.sax.ext,javax.xml.transform,org.xml.sax,javax.xml.transform.stream";version="0.0.0.1_006_JavaSE", \ javax.xml.transform.stax;uses:="javax.xml.stream,javax.xml.transform,javax.xml.stream.events";version="0.0.0.1_006_JavaSE", \ javax.xml.transform.stream;uses:="javax.xml.transform";version="0.0.0.1_006_JavaSE", \ javax.xml.transform;version="0.0.0.1_006_JavaSE", \ javax.xml.validation;uses:="org.w3c.dom.ls,javax.xml.transform,javax.xml.transform.stream,org.xml.sax,org.w3c.dom";version="0.0.0.1_006_JavaSE", \ javax.xml.ws.handler.soap;uses:="javax.xml.ws.handler,javax.xml.namespace,javax.xml.soap,javax.xml.bind";version="0.0.0.1_006_JavaSE", \ javax.xml.ws.handler;uses:="javax.xml.ws,javax.xml.namespace";version="0.0.0.1_006_JavaSE", \ javax.xml.ws.http;uses:="javax.xml.ws";version="0.0.0.1_006_JavaSE", \ javax.xml.ws.soap;uses:="javax.xml.ws.spi,javax.xml.ws,javax.xml.soap";version="0.0.0.1_006_JavaSE", \ javax.xml.ws.spi;uses:="javax.xml.ws,javax.xml.ws.wsaddressing,javax.xml.transform,org.w3c.dom,javax.xml.namespace,javax.xml.ws.handler,javax.xml.bind";version="0.0.0.1_006_JavaSE", \ javax.xml.ws.wsaddressing;uses:="javax.xml.bind.annotation,javax.xml.namespace,org.w3c.dom,javax.xml.transform,javax.xml.bind,javax.xml.ws,javax.xml.ws.spi";version="0.0.0.1_006_JavaSE", \ javax.xml.ws;uses:="javax.xml.ws.handler,javax.xml.ws.spi,javax.xml.transform,org.w3c.dom,javax.xml.bind.annotation,javax.xml.transform.stream,javax.xml.bind,javax.xml.namespace";version="0.0.0.1_006_JavaSE", \ javax.xml.xpath;uses:="org.xml.sax,javax.xml.namespace";version="0.0.0.1_006_JavaSE", \ javax.xml;version="0.0.0.1_006_JavaSE", \ org.ietf.jgss;version="0.0.0.1_006_JavaSE", \ org.omg.CORBA.DynAnyPackage;uses:="org.omg.CORBA";version="0.0.0.1_006_JavaSE", \ org.omg.CORBA.ORBPackage;uses:="org.omg.CORBA";version="0.0.0.1_006_JavaSE", \ org.omg.CORBA.TypeCodePackage;uses:="org.omg.CORBA";version="0.0.0.1_006_JavaSE", \ org.omg.CORBA.portable;uses:="org.omg.CORBA,org.omg.CORBA_2_3.portable";version="0.0.0.1_006_JavaSE", \ org.omg.CORBA;uses:="org.omg.CORBA.portable,org.omg.CORBA.DynAnyPackage,org.omg.CORBA.ORBPackage,org.omg.CORBA_2_3.portable,org.omg.CORBA.TypeCodePackage";version="0.0.0.1_006_JavaSE", \ org.omg.CORBA_2_3.portable;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_006_JavaSE", \ org.omg.CORBA_2_3;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_006_JavaSE", \ org.omg.CosNaming.NamingContextExtPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_006_JavaSE", \ org.omg.CosNaming.NamingContextPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable,org.omg.CosNaming";version="0.0.0.1_006_JavaSE", \ org.omg.CosNaming;uses:="org.omg.CORBA.portable,org.omg.CORBA,org.omg.PortableServer,org.omg.CosNaming.NamingContextPackage,org.omg.CosNaming.NamingContextExtPackage";version="0.0.0.1_006_JavaSE", \ org.omg.Dynamic;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_006_JavaSE", \ org.omg.DynamicAny.DynAnyFactoryPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_006_JavaSE", \ org.omg.DynamicAny.DynAnyPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_006_JavaSE", \ org.omg.DynamicAny;uses:="org.omg.CORBA,org.omg.CORBA.portable,org.omg.DynamicAny.DynAnyFactoryPackage,org.omg.DynamicAny.DynAnyPackage";version="0.0.0.1_006_JavaSE", \ org.omg.IOP.CodecFactoryPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_006_JavaSE", \ org.omg.IOP.CodecPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_006_JavaSE", \ org.omg.IOP;uses:="org.omg.CORBA,org.omg.CORBA.portable,org.omg.IOP.CodecFactoryPackage,org.omg.IOP.CodecPackage";version="0.0.0.1_006_JavaSE", \ org.omg.Messaging;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_006_JavaSE", \ org.omg.PortableInterceptor.ORBInitInfoPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_006_JavaSE", \ org.omg.PortableInterceptor;uses:="org.omg.CORBA,org.omg.CORBA.portable,org.omg.IOP,org.omg.PortableInterceptor.ORBInitInfoPackage,org.omg.CORBA_2_3.portable,org.omg.Dynamic";version="0.0.0.1_006_JavaSE", \ org.omg.PortableServer.CurrentPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_006_JavaSE", \ org.omg.PortableServer.POAManagerPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_006_JavaSE", \ org.omg.PortableServer.POAPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_006_JavaSE", \ org.omg.PortableServer.ServantLocatorPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_006_JavaSE", \ org.omg.PortableServer.portable;uses:="org.omg.CORBA,org.omg.PortableServer";version="0.0.0.1_006_JavaSE", \ org.omg.PortableServer;uses:="org.omg.CORBA,org.omg.CORBA.portable,org.omg.PortableServer.CurrentPackage,org.omg.PortableServer.POAManagerPackage,org.omg.PortableServer.POAPackage,org.omg.PortableServer.portable,org.omg.CORBA_2_3,org.omg.PortableServer.ServantLocatorPackage";version="0.0.0.1_006_JavaSE", \ org.omg.SendingContext;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_006_JavaSE", \ org.omg.stub.java.rmi;uses:="javax.rmi.CORBA";version="0.0.0.1_006_JavaSE", \ org.w3c.dom.bootstrap;uses:="org.w3c.dom";version="0.0.0.1_006_JavaSE", \ org.w3c.dom.events;uses:="org.w3c.dom,org.w3c.dom.views";version="0.0.0.1_006_JavaSE", \ org.w3c.dom.ls;uses:="org.w3c.dom,org.w3c.dom.events,org.w3c.dom.traversal";version="0.0.0.1_006_JavaSE", \ org.w3c.dom;version="0.0.0.1_006_JavaSE", \ org.xml.sax.ext;uses:="org.xml.sax,org.xml.sax.helpers";version="0.0.0.1_006_JavaSE", \ org.xml.sax.helpers;uses:="org.xml.sax";version="0.0.0.1_006_JavaSE", \ org.xml.sax;version="0.0.0.1_006_JavaSE" jre-1.7=, \ javax.accessibility;uses:="javax.swing.text";version="0.0.0.1_007_JavaSE", \ javax.activation;version="0.0.0.1_007_JavaSE", \ javax.activity;version="0.0.0.1_007_JavaSE", \ javax.annotation.processing;uses:="javax.tools,javax.lang.model,javax.lang.model.element,javax.lang.model.util";version="0.0.0.1_007_JavaSE", \ javax.annotation;version="0.0.0.1_007_JavaSE", \ javax.crypto.interfaces;uses:="javax.crypto.spec,javax.crypto";version="0.0.0.1_007_JavaSE", \ javax.crypto.spec;uses:="javax.crypto";version="0.0.0.1_007_JavaSE", \ javax.crypto;uses:="javax.crypto.spec";version="0.0.0.1_007_JavaSE", \ javax.imageio.event;uses:="javax.imageio";version="0.0.0.1_007_JavaSE", \ javax.imageio.metadata;uses:="org.w3c.dom,javax.imageio";version="0.0.0.1_007_JavaSE", \ javax.imageio.plugins.bmp;uses:="javax.imageio";version="0.0.0.1_007_JavaSE", \ javax.imageio.plugins.jpeg;uses:="javax.imageio";version="0.0.0.1_007_JavaSE", \ javax.imageio.spi;uses:="javax.imageio.stream,javax.imageio,javax.imageio.metadata";version="0.0.0.1_007_JavaSE", \ javax.imageio.stream;uses:="javax.imageio";version="0.0.0.1_007_JavaSE", \ javax.imageio;uses:="javax.imageio.metadata,javax.imageio.stream,javax.imageio.spi,javax.imageio.event";version="0.0.0.1_007_JavaSE", \ javax.jws.soap;version="0.0.0.1_007_JavaSE", \ javax.jws;version="0.0.0.1_007_JavaSE", \ javax.lang.model.element;uses:="javax.lang.model.type,javax.lang.model";version="0.0.0.1_007_JavaSE", \ javax.lang.model.type;uses:="javax.lang.model.element,javax.lang.model";version="0.0.0.1_007_JavaSE", \ javax.lang.model.util;uses:="javax.lang.model,javax.lang.model.element,javax.annotation.processing,javax.lang.model.type";version="0.0.0.1_007_JavaSE", \ javax.lang.model;version="0.0.0.1_007_JavaSE", \ javax.management.loading;uses:="javax.management";version="0.0.0.1_007_JavaSE", \ javax.management.modelmbean;uses:="javax.management,javax.management.loading";version="0.0.0.1_007_JavaSE", \ javax.management.monitor;uses:="javax.management";version="0.0.0.1_007_JavaSE", \ javax.management.openmbean;uses:="javax.management";version="0.0.0.1_007_JavaSE", \ javax.management.relation;uses:="javax.management";version="0.0.0.1_007_JavaSE", \ javax.management.remote.rmi;uses:="javax.management.remote,javax.security.auth,javax.management,javax.management.loading,javax.naming,javax.rmi.ssl,org.omg.CORBA,org.omg.CORBA_2_3.portable,org.omg.CORBA.portable,javax.rmi.CORBA,javax.rmi";version="0.0.0.1_007_JavaSE", \ javax.management.remote;uses:="javax.security.auth,javax.management";version="0.0.0.1_007_JavaSE", \ javax.management.timer;uses:="javax.management";version="0.0.0.1_007_JavaSE", \ javax.management;uses:="javax.management.loading,javax.management.openmbean";version="0.0.0.1_007_JavaSE", \ javax.naming.directory;uses:="javax.naming";version="0.0.0.1_007_JavaSE", \ javax.naming.event;uses:="javax.naming,javax.naming.directory";version="0.0.0.1_007_JavaSE", \ javax.naming.ldap;uses:="javax.naming,javax.naming.directory,javax.net.ssl,javax.naming.event";version="0.0.0.1_007_JavaSE", \ javax.naming.spi;uses:="javax.naming,javax.naming.directory";version="0.0.0.1_007_JavaSE", \ javax.naming;uses:="javax.naming.spi";version="0.0.0.1_007_JavaSE", \ javax.net.ssl;uses:="javax.security.cert,javax.security.auth.x500,javax.net";version="0.0.0.1_007_JavaSE", \ javax.net;version="0.0.0.1_007_JavaSE", \ javax.print.attribute.standard;uses:="javax.print.attribute";version="0.0.0.1_007_JavaSE", \ javax.print.attribute;version="0.0.0.1_007_JavaSE", \ javax.print.event;uses:="javax.print,javax.print.attribute";version="0.0.0.1_007_JavaSE", \ javax.print;uses:="javax.print.attribute,javax.print.event,javax.print.attribute.standard";version="0.0.0.1_007_JavaSE", \ javax.rmi.CORBA;uses:="org.omg.CORBA,org.omg.CORBA_2_3.portable,org.omg.CORBA.portable,org.omg.SendingContext";version="0.0.0.1_007_JavaSE", \ javax.rmi.ssl;uses:="javax.net,javax.net.ssl";version="0.0.0.1_007_JavaSE", \ javax.rmi;uses:="org.omg.CORBA,javax.rmi.CORBA";version="0.0.0.1_007_JavaSE", \ javax.script;version="0.0.0.1_007_JavaSE", \ javax.security.auth.callback;version="0.0.0.1_007_JavaSE", \ javax.security.auth.kerberos;uses:="javax.security.auth,javax.crypto";version="0.0.0.1_007_JavaSE", \ javax.security.auth.login;uses:="javax.security.auth,javax.security.auth.callback";version="0.0.0.1_007_JavaSE", \ javax.security.auth.spi;uses:="javax.security.auth.callback,javax.security.auth.login,javax.security.auth";version="0.0.0.1_007_JavaSE", \ javax.security.auth.x500;uses:="javax.security.auth";version="0.0.0.1_007_JavaSE", \ javax.security.auth;version="0.0.0.1_007_JavaSE", \ javax.security.cert;version="0.0.0.1_007_JavaSE", \ javax.security.sasl;uses:="javax.security.auth.callback";version="0.0.0.1_007_JavaSE", \ javax.sound.midi.spi;uses:="javax.sound.midi";version="0.0.0.1_007_JavaSE", \ javax.sound.midi;uses:="javax.sound.midi.spi";version="0.0.0.1_007_JavaSE", \ javax.sound.sampled.spi;uses:="javax.sound.sampled";version="0.0.0.1_007_JavaSE", \ javax.sound.sampled;uses:="javax.sound.sampled.spi";version="0.0.0.1_007_JavaSE", \ javax.sql.rowset.serial;uses:="javax.sql.rowset";version="0.0.0.1_007_JavaSE", \ javax.sql.rowset.spi;uses:="javax.sql,javax.naming,javax.sql.rowset";version="0.0.0.1_007_JavaSE", \ javax.sql.rowset;uses:="javax.sql,javax.sql.rowset.serial,javax.sql.rowset.spi";version="0.0.0.1_007_JavaSE", \ javax.sql;uses:="javax.transaction.xa";version="0.0.0.1_007_JavaSE", \ javax.swing.border;uses:="javax.swing";version="0.0.0.1_007_JavaSE", \ javax.swing.colorchooser;uses:="javax.swing,javax.swing.border,javax.swing.event,javax.swing.text";version="0.0.0.1_007_JavaSE", \ javax.swing.event;uses:="javax.swing,javax.swing.text,javax.swing.table,javax.swing.tree,javax.swing.undo";version="0.0.0.1_007_JavaSE", \ javax.swing.filechooser;uses:="javax.swing";version="0.0.0.1_007_JavaSE", \ javax.swing.plaf.basic;uses:="javax.swing.border,javax.swing,javax.swing.plaf,javax.swing.text,javax.swing.event,javax.swing.colorchooser,javax.accessibility,javax.swing.filechooser,javax.swing.text.html,javax.sound.sampled,javax.swing.table,javax.swing.plaf.synth,javax.swing.tree";version="0.0.0.1_007_JavaSE", \ javax.swing.plaf.metal;uses:="javax.swing.plaf,javax.swing,javax.swing.border,javax.swing.text,javax.swing.plaf.basic,javax.swing.filechooser,javax.swing.event,javax.swing.tree";version="0.0.0.1_007_JavaSE", \ javax.swing.plaf.multi;uses:="javax.accessibility,javax.swing,javax.swing.plaf,javax.swing.filechooser,javax.swing.text,javax.swing.tree";version="0.0.0.1_007_JavaSE", \ javax.swing.plaf.nimbus;uses:="javax.swing,javax.swing.plaf,javax.swing.border,javax.swing.plaf.synth";version="0.0.0.1_007_JavaSE", \ javax.swing.plaf.synth;uses:="javax.swing,javax.swing.plaf,javax.swing.text,javax.swing.border,javax.swing.plaf.basic,javax.swing.colorchooser,javax.swing.event,javax.xml.parsers,org.xml.sax,org.xml.sax.helpers,javax.swing.table,javax.swing.tree";version="0.0.0.1_007_JavaSE", \ javax.swing.plaf;uses:="javax.swing,javax.swing.border,javax.accessibility,javax.swing.filechooser,javax.swing.text,javax.swing.tree";version="0.0.0.1_007_JavaSE", \ javax.swing.table;uses:="javax.swing.event,javax.swing.plaf,javax.swing.border,javax.swing,javax.accessibility";version="0.0.0.1_007_JavaSE", \ javax.swing.text.html.parser;uses:="javax.swing.text,javax.swing.text.html";version="0.0.0.1_007_JavaSE", \ javax.swing.text.html;uses:="javax.swing.event,javax.swing.text,javax.accessibility,javax.swing,javax.swing.plaf,javax.swing.border,javax.swing.undo";version="0.0.0.1_007_JavaSE", \ javax.swing.text.rtf;uses:="javax.swing.text";version="0.0.0.1_007_JavaSE", \ javax.swing.text;uses:="javax.swing.event,javax.swing.tree,javax.swing.undo,javax.swing,javax.swing.plaf,javax.swing.plaf.basic,javax.print,javax.print.attribute,javax.accessibility,javax.swing.text.html";version="0.0.0.1_007_JavaSE", \ javax.swing.tree;uses:="javax.swing.event,javax.swing,javax.swing.border,javax.swing.plaf,javax.swing.plaf.basic";version="0.0.0.1_007_JavaSE", \ javax.swing.undo;uses:="javax.swing,javax.swing.event";version="0.0.0.1_007_JavaSE", \ javax.swing;uses:="javax.swing.event,javax.accessibility,javax.swing.text,javax.swing.plaf,javax.swing.border,javax.swing.tree,javax.swing.table,javax.swing.colorchooser,javax.swing.plaf.basic,javax.swing.text.html,javax.swing.filechooser,javax.print,javax.print.attribute,javax.swing.plaf.metal";version="0.0.0.1_007_JavaSE", \ javax.tools;uses:="javax.lang.model.element,javax.annotation.processing,javax.lang.model";version="0.0.0.1_007_JavaSE", \ javax.transaction.xa;version="0.0.0.1_007_JavaSE", \ javax.transaction;version="0.0.0.1_007_JavaSE", \ javax.xml.bind.annotation.adapters;uses:="javax.xml.bind";version="0.0.0.1_007_JavaSE", \ javax.xml.bind.annotation;uses:="javax.xml.transform,javax.xml.bind,javax.xml.parsers,javax.xml.transform.dom,org.w3c.dom";version="0.0.0.1_007_JavaSE", \ javax.xml.bind.attachment;uses:="javax.activation";version="0.0.0.1_007_JavaSE", \ javax.xml.bind.helpers;uses:="javax.xml.bind.annotation.adapters,javax.xml.transform.dom,org.w3c.dom,org.xml.sax,javax.xml.bind.attachment,javax.xml.stream,javax.xml.transform,javax.xml.transform.stream,javax.xml.validation,javax.xml.transform.sax,javax.xml.bind,javax.xml.parsers";version="0.0.0.1_007_JavaSE", \ javax.xml.bind.util;uses:="javax.xml.transform.sax,javax.xml.bind,org.xml.sax,org.xml.sax.ext,org.xml.sax.helpers";version="0.0.0.1_007_JavaSE", \ javax.xml.bind;uses:="javax.xml.validation,javax.xml.namespace,javax.xml.datatype,javax.xml.transform,javax.xml.bind.annotation,javax.xml.transform.stream,org.w3c.dom,javax.xml.bind.attachment,javax.xml.stream,javax.xml.bind.annotation.adapters,org.xml.sax";version="0.0.0.1_007_JavaSE", \ javax.xml.crypto.dom;uses:="javax.xml.crypto,org.w3c.dom";version="0.0.0.1_007_JavaSE", \ javax.xml.crypto.dsig.dom;uses:="javax.xml.crypto.dsig,javax.xml.crypto,org.w3c.dom,javax.xml.crypto.dom";version="0.0.0.1_007_JavaSE", \ javax.xml.crypto.dsig.keyinfo;uses:="javax.xml.crypto";version="0.0.0.1_007_JavaSE", \ javax.xml.crypto.dsig.spec;uses:="javax.xml.crypto";version="0.0.0.1_007_JavaSE", \ javax.xml.crypto.dsig;uses:="javax.xml.crypto,javax.xml.crypto.dsig.spec,javax.xml.crypto.dsig.keyinfo";version="0.0.0.1_007_JavaSE", \ javax.xml.crypto;uses:="javax.xml.crypto.dsig.keyinfo";version="0.0.0.1_007_JavaSE", \ javax.xml.datatype;uses:="javax.xml.namespace";version="0.0.0.1_007_JavaSE", \ javax.xml.namespace;version="0.0.0.1_007_JavaSE", \ javax.xml.parsers;uses:="javax.xml.validation,org.w3c.dom,org.xml.sax,org.xml.sax.helpers";version="0.0.0.1_007_JavaSE", \ javax.xml.soap;uses:="javax.activation,javax.xml.namespace,org.w3c.dom,javax.xml.transform.dom,javax.xml.transform";version="0.0.0.1_007_JavaSE", \ javax.xml.stream.events;uses:="javax.xml.namespace,javax.xml.stream";version="0.0.0.1_007_JavaSE", \ javax.xml.stream.util;uses:="javax.xml.stream,javax.xml.stream.events,javax.xml.namespace";version="0.0.0.1_007_JavaSE", \ javax.xml.stream;uses:="javax.xml.stream.events,javax.xml.namespace,javax.xml.stream.util,javax.xml.transform";version="0.0.0.1_007_JavaSE", \ javax.xml.transform.dom;uses:="javax.xml.transform,org.w3c.dom";version="0.0.0.1_007_JavaSE", \ javax.xml.transform.sax;uses:="org.xml.sax.ext,javax.xml.transform,org.xml.sax,javax.xml.transform.stream";version="0.0.0.1_007_JavaSE", \ javax.xml.transform.stax;uses:="javax.xml.stream,javax.xml.transform,javax.xml.stream.events";version="0.0.0.1_007_JavaSE", \ javax.xml.transform.stream;uses:="javax.xml.transform";version="0.0.0.1_007_JavaSE", \ javax.xml.transform;version="0.0.0.1_007_JavaSE", \ javax.xml.validation;uses:="org.w3c.dom.ls,javax.xml.transform,javax.xml.transform.stream,org.xml.sax,org.w3c.dom";version="0.0.0.1_007_JavaSE", \ javax.xml.ws.handler.soap;uses:="javax.xml.ws.handler,javax.xml.namespace,javax.xml.soap,javax.xml.bind";version="0.0.0.1_007_JavaSE", \ javax.xml.ws.handler;uses:="javax.xml.ws,javax.xml.namespace";version="0.0.0.1_007_JavaSE", \ javax.xml.ws.http;uses:="javax.xml.ws";version="0.0.0.1_007_JavaSE", \ javax.xml.ws.soap;uses:="javax.xml.ws.spi,javax.xml.ws,javax.xml.soap";version="0.0.0.1_007_JavaSE", \ javax.xml.ws.spi.http;version="0.0.0.1_007_JavaSE", \ javax.xml.ws.spi;uses:="javax.xml.ws,javax.xml.ws.wsaddressing,javax.xml.transform,org.w3c.dom,javax.xml.namespace,javax.xml.ws.handler,javax.xml.bind";version="0.0.0.1_007_JavaSE", \ javax.xml.ws.wsaddressing;uses:="javax.xml.bind.annotation,javax.xml.namespace,org.w3c.dom,javax.xml.transform,javax.xml.bind,javax.xml.ws,javax.xml.ws.spi";version="0.0.0.1_007_JavaSE", \ javax.xml.ws;uses:="javax.xml.ws.handler,javax.xml.ws.spi,javax.xml.ws.spi.http,javax.xml.transform,org.w3c.dom,javax.xml.bind.annotation,javax.xml.transform.stream,javax.xml.bind,javax.xml.namespace";version="0.0.0.1_007_JavaSE", \ javax.xml.xpath;uses:="org.xml.sax,javax.xml.namespace";version="0.0.0.1_007_JavaSE", \ javax.xml;version="0.0.0.1_007_JavaSE", \ org.ietf.jgss;version="0.0.0.1_007_JavaSE", \ org.omg.CORBA.DynAnyPackage;uses:="org.omg.CORBA";version="0.0.0.1_007_JavaSE", \ org.omg.CORBA.ORBPackage;uses:="org.omg.CORBA";version="0.0.0.1_007_JavaSE", \ org.omg.CORBA.TypeCodePackage;uses:="org.omg.CORBA";version="0.0.0.1_007_JavaSE", \ org.omg.CORBA.portable;uses:="org.omg.CORBA,org.omg.CORBA_2_3.portable";version="0.0.0.1_007_JavaSE", \ org.omg.CORBA;uses:="org.omg.CORBA.portable,org.omg.CORBA.DynAnyPackage,org.omg.CORBA.ORBPackage,org.omg.CORBA_2_3.portable,org.omg.CORBA.TypeCodePackage";version="0.0.0.1_007_JavaSE", \ org.omg.CORBA_2_3.portable;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", \ org.omg.CORBA_2_3;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", \ org.omg.CosNaming.NamingContextExtPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", \ org.omg.CosNaming.NamingContextPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable,org.omg.CosNaming";version="0.0.0.1_007_JavaSE", \ org.omg.CosNaming;uses:="org.omg.CORBA.portable,org.omg.CORBA,org.omg.PortableServer,org.omg.CosNaming.NamingContextPackage,org.omg.CosNaming.NamingContextExtPackage";version="0.0.0.1_007_JavaSE", \ org.omg.Dynamic;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", \ org.omg.DynamicAny.DynAnyFactoryPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", \ org.omg.DynamicAny.DynAnyPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", \ org.omg.DynamicAny;uses:="org.omg.CORBA,org.omg.CORBA.portable,org.omg.DynamicAny.DynAnyFactoryPackage,org.omg.DynamicAny.DynAnyPackage";version="0.0.0.1_007_JavaSE", \ org.omg.IOP.CodecFactoryPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", \ org.omg.IOP.CodecPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", \ org.omg.IOP;uses:="org.omg.CORBA,org.omg.CORBA.portable,org.omg.IOP.CodecFactoryPackage,org.omg.IOP.CodecPackage";version="0.0.0.1_007_JavaSE", \ org.omg.Messaging;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", \ org.omg.PortableInterceptor.ORBInitInfoPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", \ org.omg.PortableInterceptor;uses:="org.omg.CORBA,org.omg.CORBA.portable,org.omg.IOP,org.omg.PortableInterceptor.ORBInitInfoPackage,org.omg.CORBA_2_3.portable,org.omg.Dynamic";version="0.0.0.1_007_JavaSE", \ org.omg.PortableServer.CurrentPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", \ org.omg.PortableServer.POAManagerPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", \ org.omg.PortableServer.POAPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", \ org.omg.PortableServer.ServantLocatorPackage;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", \ org.omg.PortableServer.portable;uses:="org.omg.CORBA,org.omg.PortableServer";version="0.0.0.1_007_JavaSE", \ org.omg.PortableServer;uses:="org.omg.CORBA,org.omg.CORBA.portable,org.omg.PortableServer.CurrentPackage,org.omg.PortableServer.POAManagerPackage,org.omg.PortableServer.POAPackage,org.omg.PortableServer.portable,org.omg.CORBA_2_3,org.omg.PortableServer.ServantLocatorPackage";version="0.0.0.1_007_JavaSE", \ org.omg.SendingContext;uses:="org.omg.CORBA,org.omg.CORBA.portable";version="0.0.0.1_007_JavaSE", \ org.omg.stub.java.rmi;uses:="javax.rmi.CORBA";version="0.0.0.1_007_JavaSE", \ org.w3c.dom.bootstrap;uses:="org.w3c.dom";version="0.0.0.1_007_JavaSE", \ org.w3c.dom.events;uses:="org.w3c.dom,org.w3c.dom.views";version="0.0.0.1_007_JavaSE", \ org.w3c.dom.ls;uses:="org.w3c.dom,org.w3c.dom.events,org.w3c.dom.traversal";version="0.0.0.1_007_JavaSE", \ org.w3c.dom;version="0.0.0.1_007_JavaSE", \ org.xml.sax.ext;uses:="org.xml.sax,org.xml.sax.helpers";version="0.0.0.1_007_JavaSE", \ org.xml.sax.helpers;uses:="org.xml.sax";version="0.0.0.1_007_JavaSE", \ org.xml.sax;version="0.0.0.1_007_JavaSE" felix-framework-4.0.1.orig/src/main/resources/org/0000755000175000017500000000000011644651234021773 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/src/main/resources/org/apache/0000755000175000017500000000000011644651234023214 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/src/main/resources/org/apache/felix/0000755000175000017500000000000011644651234024323 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/src/main/resources/org/apache/felix/framework/0000755000175000017500000000000011655235117026320 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/src/main/resources/org/apache/felix/framework/Felix.properties0000644000175000017500000000003511644651234031503 0ustar drazzibdrazzibfelix.version=${pom.version} felix-framework-4.0.1.orig/src/main/resources/org/osgi/0000755000175000017500000000000011644651234022734 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/src/main/resources/org/osgi/service/0000755000175000017500000000000011644651234024374 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/src/main/resources/org/osgi/service/startlevel/0000755000175000017500000000000011655235117026561 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/src/main/resources/org/osgi/service/startlevel/packageinfo0000644000175000017500000000001411644651234030746 0ustar drazzibdrazzibversion 1.1 felix-framework-4.0.1.orig/src/main/resources/org/osgi/service/packageadmin/0000755000175000017500000000000011655235117027000 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/src/main/resources/org/osgi/service/packageadmin/packageinfo0000644000175000017500000000001411644651234031165 0ustar drazzibdrazzibversion 1.2 felix-framework-4.0.1.orig/src/main/resources/org/osgi/service/url/0000755000175000017500000000000011655235117025176 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/src/main/resources/org/osgi/service/url/packageinfo0000644000175000017500000000001411644651234027363 0ustar drazzibdrazzibversion 1.0 felix-framework-4.0.1.orig/src/main/resources/org/osgi/framework/0000755000175000017500000000000011655235117024731 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/src/main/resources/org/osgi/framework/startlevel/0000755000175000017500000000000011655235117027116 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/src/main/resources/org/osgi/framework/startlevel/packageinfo0000644000175000017500000000001411644651234031303 0ustar drazzibdrazzibversion 1.0 felix-framework-4.0.1.orig/src/main/resources/org/osgi/framework/launch/0000755000175000017500000000000011655235117026203 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/src/main/resources/org/osgi/framework/launch/packageinfo0000644000175000017500000000001411644651234030370 0ustar drazzibdrazzibversion 1.0 felix-framework-4.0.1.orig/src/main/resources/org/osgi/framework/packageinfo0000644000175000017500000000001411644651234027116 0ustar drazzibdrazzibversion 1.6 felix-framework-4.0.1.orig/src/main/resources/org/osgi/framework/wiring/0000755000175000017500000000000011655235117026230 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/src/main/resources/org/osgi/framework/wiring/packageinfo0000644000175000017500000000001411644651234030415 0ustar drazzibdrazzibversion 1.0 felix-framework-4.0.1.orig/src/main/resources/org/osgi/framework/hooks/0000755000175000017500000000000011644651234026054 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/src/main/resources/org/osgi/framework/hooks/resolver/0000755000175000017500000000000011655235117027715 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/src/main/resources/org/osgi/framework/hooks/resolver/packageinfo0000644000175000017500000000001411644651234032102 0ustar drazzibdrazzibversion 1.0 felix-framework-4.0.1.orig/src/main/resources/org/osgi/framework/hooks/service/0000755000175000017500000000000011655235117027514 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/src/main/resources/org/osgi/framework/hooks/service/packageinfo0000644000175000017500000000001411644651234031701 0ustar drazzibdrazzibversion 1.1 felix-framework-4.0.1.orig/src/main/resources/org/osgi/framework/hooks/bundle/0000755000175000017500000000000011655235117027325 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/src/main/resources/org/osgi/framework/hooks/bundle/packageinfo0000644000175000017500000000001411644651234031512 0ustar drazzibdrazzibversion 1.0 felix-framework-4.0.1.orig/src/main/resources/org/osgi/framework/hooks/weaving/0000755000175000017500000000000011655235117027514 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/src/main/resources/org/osgi/framework/hooks/weaving/packageinfo0000644000175000017500000000001411644651234031701 0ustar drazzibdrazzibversion 1.0 felix-framework-4.0.1.orig/src/main/resources/org/osgi/util/0000755000175000017500000000000011644651234023711 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/src/main/resources/org/osgi/util/tracker/0000755000175000017500000000000011655235117025344 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/src/main/resources/org/osgi/util/tracker/packageinfo0000644000175000017500000000001411644651234027531 0ustar drazzibdrazzibversion 1.5 felix-framework-4.0.1.orig/src/main/java/0000755000175000017500000000000011644651227020115 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/src/main/java/org/0000755000175000017500000000000011644651232020700 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/src/main/java/org/apache/0000755000175000017500000000000011644651227022125 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/src/main/java/org/apache/felix/0000755000175000017500000000000011644651227023234 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/0000755000175000017500000000000011655235117025227 5ustar drazzibdrazzibfelix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/ExtensionManager.java0000644000175000017500000007453211644651232031352 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework; import java.io.IOException; import java.net.InetAddress; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; import java.net.URLStreamHandler; import java.security.AccessControlException; import java.security.AllPermission; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.NoSuchElementException; import java.util.Set; import org.apache.felix.framework.util.FelixConstants; import org.apache.felix.framework.util.StringMap; import org.apache.felix.framework.util.Util; import org.apache.felix.framework.util.manifestparser.ManifestParser; import org.apache.felix.framework.cache.Content; import org.apache.felix.framework.util.manifestparser.R4Library; import org.apache.felix.framework.wiring.BundleCapabilityImpl; import org.apache.felix.framework.wiring.BundleWireImpl; import org.osgi.framework.AdminPermission; import org.osgi.framework.Bundle; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; import org.osgi.framework.Constants; import org.osgi.framework.Version; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRequirement; import org.osgi.framework.wiring.BundleRevision; import org.osgi.framework.wiring.BundleWire; import org.osgi.framework.wiring.BundleWiring; /** * The ExtensionManager class is used in several ways. *

* First, a private instance is added (as URL with the instance as * URLStreamHandler) to the classloader that loaded the class. * It is assumed that this is an instance of URLClassloader (if not extension * bundles will not work). Subsequently, extension bundles can be managed by * instances of this class (their will be one instance per framework instance). *

*

* Second, it is used as module definition of the systembundle. Added extension * bundles with exported packages will contribute their exports to the * systembundle export. *

*

* Third, it is used as content loader of the systembundle. Added extension * bundles exports will be available via this loader. *

*/ // The general approach is to have one private static instance that we register // with the parent classloader and one instance per framework instance that // keeps track of extension bundles and systembundle exports for that framework // instance. class ExtensionManager extends URLStreamHandler implements Content { // The private instance that is added to Felix.class.getClassLoader() - // will be null if extension bundles are not supported (i.e., we are not // loaded by an instance of URLClassLoader) static final ExtensionManager m_extensionManager; static { // pre-init the url sub-system as otherwise we don't work on gnu/classpath ExtensionManager extensionManager = new ExtensionManager(); try { (new URL("http://felix.extensions:9/")).openConnection(); } catch (Throwable t) { // This doesn't matter much - we only need the above to init the url subsystem } // We use the secure action of Felix to add a new instance to the parent // classloader. try { Felix.m_secureAction.addURLToURLClassLoader(Felix.m_secureAction.createURL( Felix.m_secureAction.createURL(null, "http:", extensionManager), "http://felix.extensions:9/", extensionManager), Felix.class.getClassLoader()); } catch (Throwable ex) { // extension bundles will not be supported. extensionManager = null; } m_extensionManager = extensionManager; } private final Logger m_logger; private final Map m_configMap; private final Map m_headerMap = new StringMap(false); private final BundleRevision m_systemBundleRevision; private volatile List m_capabilities = Collections.EMPTY_LIST; private volatile Set m_exportNames = Collections.EMPTY_SET; private volatile Object m_securityContext = null; private final List m_extensions; private volatile Bundle[] m_extensionsCache; private final Set m_names; private final Map m_sourceToExtensions; // This constructor is only used for the private instance added to the parent // classloader. private ExtensionManager() { m_logger = null; m_configMap = null; m_systemBundleRevision = null; m_extensions = new ArrayList(); m_extensionsCache = new Bundle[0]; m_names = new HashSet(); m_sourceToExtensions = new HashMap(); } /** * This constructor is used to create one instance per framework instance. * The general approach is to have one private static instance that we register * with the parent classloader and one instance per framework instance that * keeps track of extension bundles and systembundle exports for that framework * instance. * * @param logger the logger to use. * @param config the configuration to read properties from. * @param systemBundleInfo the info to change if we need to add exports. */ ExtensionManager(Logger logger, Map configMap, Felix felix) { m_logger = logger; m_configMap = configMap; m_systemBundleRevision = new ExtensionManagerRevision(felix); m_extensions = null; m_extensionsCache = null; m_names = null; m_sourceToExtensions = null; // TODO: FRAMEWORK - Not all of this stuff really belongs here, probably only exports. // Populate system bundle header map. m_headerMap.put(FelixConstants.BUNDLE_VERSION, m_configMap.get(FelixConstants.FELIX_VERSION_PROPERTY)); m_headerMap.put(FelixConstants.BUNDLE_SYMBOLICNAME, FelixConstants.SYSTEM_BUNDLE_SYMBOLICNAME); m_headerMap.put(FelixConstants.BUNDLE_NAME, "System Bundle"); m_headerMap.put(FelixConstants.BUNDLE_DESCRIPTION, "This bundle is system specific; it implements various system services."); m_headerMap.put(FelixConstants.EXPORT_SERVICE, "org.osgi.service.packageadmin.PackageAdmin," + "org.osgi.service.startlevel.StartLevel," + "org.osgi.service.url.URLHandlers"); // The system bundle exports framework packages as well as // arbitrary user-defined packages from the system class path. // We must construct the system bundle's export metadata. // Get configuration property that specifies which class path // packages should be exported by the system bundle. String syspkgs = (String) m_configMap.get(FelixConstants.FRAMEWORK_SYSTEMPACKAGES); // If no system packages were specified, load our default value. syspkgs = (syspkgs == null) ? Util.getDefaultProperty(logger, Constants.FRAMEWORK_SYSTEMPACKAGES) : syspkgs; syspkgs = (syspkgs == null) ? "" : syspkgs; // If any extra packages are specified, then append them. String pkgextra = (String) m_configMap.get(FelixConstants.FRAMEWORK_SYSTEMPACKAGES_EXTRA); syspkgs = (pkgextra == null) ? syspkgs : syspkgs + "," + pkgextra; m_headerMap.put(FelixConstants.BUNDLE_MANIFESTVERSION, "2"); m_headerMap.put(FelixConstants.EXPORT_PACKAGE, syspkgs); // The system bundle alsp provides framework generic capabilities // as well as arbitrary user-defined generic capabilities. We must // construct the system bundle's capabilitie metadata. Get the // configuration property that specifies which capabilities should // be provided by the system bundle. String syscaps = (String) m_configMap.get(FelixConstants.FRAMEWORK_SYSTEMCAPABILITIES); // If no system capabilities were specified, load our default value. syscaps = (syscaps == null) ? Util.getDefaultProperty(logger, Constants.FRAMEWORK_SYSTEMCAPABILITIES) : syscaps; syscaps = (syscaps == null) ? "" : syscaps; // If any extra capabilities are specified, then append them. String capextra = (String) m_configMap.get(FelixConstants.FRAMEWORK_SYSTEMCAPABILITIES_EXTRA); syscaps = (capextra == null) ? syscaps : syscaps + "," + capextra; m_headerMap.put(FelixConstants.PROVIDE_CAPABILITY, syscaps); try { ManifestParser mp = new ManifestParser( m_logger, m_configMap, m_systemBundleRevision, m_headerMap); List caps = aliasSymbolicName(mp.getCapabilities()); appendCapabilities(caps); } catch (Exception ex) { m_capabilities = Collections.EMPTY_LIST; m_logger.log( Logger.LOG_ERROR, "Error parsing system bundle export statement: " + syspkgs, ex); } } private static List aliasSymbolicName(List caps) { if (caps == null) { return new ArrayList(0); } List aliasCaps = new ArrayList(caps); for (int capIdx = 0; capIdx < aliasCaps.size(); capIdx++) { // Get the attributes and search for bundle symbolic name. for (Entry entry : aliasCaps.get(capIdx).getAttributes().entrySet()) { // If there is a bundle symbolic name attribute, add the // standard alias as a value. if (entry.getKey().equalsIgnoreCase(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE)) { // Make a copy of the attribute array. Map aliasAttrs = new HashMap(aliasCaps.get(capIdx).getAttributes()); // Add the aliased value. aliasAttrs.put( Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE, new String[] { (String) entry.getValue(), Constants.SYSTEM_BUNDLE_SYMBOLICNAME}); // Create the aliased capability to replace the old capability. aliasCaps.set(capIdx, new BundleCapabilityImpl( caps.get(capIdx).getRevision(), caps.get(capIdx).getNamespace(), caps.get(capIdx).getDirectives(), aliasAttrs)); // Continue with the next capability. break; } } } return aliasCaps; } public BundleRevision getRevision() { return m_systemBundleRevision; } public Object getSecurityContext() { return m_securityContext; } public synchronized void setSecurityContext(Object securityContext) { m_securityContext = securityContext; } /** * Add an extension bundle. The bundle will be added to the parent classloader * and it's exported packages will be added to the module definition * exports of this instance. Subsequently, they are available form the * instance in it's role as content loader. * * @param felix the framework instance the given extension bundle comes from. * @param bundle the extension bundle to add. * @throws BundleException if extension bundles are not supported or this is * not a framework extension. * @throws SecurityException if the caller does not have the needed * AdminPermission.EXTENSIONLIFECYCLE and security is enabled. * @throws Exception in case something goes wrong. */ synchronized void addExtensionBundle(Felix felix, BundleImpl bundle) throws SecurityException, BundleException, Exception { Object sm = System.getSecurityManager(); if (sm != null) { ((SecurityManager) sm).checkPermission( new AdminPermission(bundle, AdminPermission.EXTENSIONLIFECYCLE)); } if (!((BundleProtectionDomain) bundle.getProtectionDomain()).impliesDirect(new AllPermission())) { throw new SecurityException("Extension Bundles must have AllPermission"); } String directive = ManifestParser.parseExtensionBundleHeader((String) ((BundleRevisionImpl) bundle.adapt(BundleRevision.class)) .getHeaders().get(Constants.FRAGMENT_HOST)); // We only support classpath extensions (not bootclasspath). if (!Constants.EXTENSION_FRAMEWORK.equals(directive)) { throw new BundleException("Unsupported Extension Bundle type: " + directive, new UnsupportedOperationException( "Unsupported Extension Bundle type!")); } try { // Merge the exported packages with the exported packages of the systembundle. List exports = null; try { exports = ManifestParser.parseExportHeader( m_logger, m_systemBundleRevision, (String) ((BundleRevisionImpl) bundle.adapt(BundleRevision.class)) .getHeaders().get(Constants.EXPORT_PACKAGE), m_systemBundleRevision.getSymbolicName(), m_systemBundleRevision.getVersion()); exports = aliasSymbolicName(exports); } catch (Exception ex) { m_logger.log( bundle, Logger.LOG_ERROR, "Error parsing extension bundle export statement: " + ((BundleRevisionImpl) bundle.adapt(BundleRevision.class)) .getHeaders().get(Constants.EXPORT_PACKAGE), ex); return; } // Add the bundle as extension if we support extensions if (m_extensionManager != null) { // This needs to be the private instance. m_extensionManager.addExtension(felix, bundle); } else { // We don't support extensions (i.e., the parent is not an URLClassLoader). m_logger.log(bundle, Logger.LOG_WARNING, "Unable to add extension bundle to FrameworkClassLoader - Maybe not an URLClassLoader?"); throw new UnsupportedOperationException( "Unable to add extension bundle to FrameworkClassLoader - Maybe not an URLClassLoader?"); } appendCapabilities(exports); } catch (Exception ex) { throw ex; } BundleRevisionImpl bri = (BundleRevisionImpl) bundle.adapt(BundleRevision.class); List reqs = bri.getDeclaredRequirements(BundleRevision.HOST_NAMESPACE); List caps = getCapabilities(BundleRevision.HOST_NAMESPACE); BundleWire bw = new BundleWireImpl(bri, reqs.get(0), m_systemBundleRevision, caps.get(0)); bri.resolve( new BundleWiringImpl( m_logger, m_configMap, null, bri, null, Collections.singletonList(bw), Collections.EMPTY_MAP, Collections.EMPTY_MAP)); felix.getDependencies().addDependent(bw); felix.setBundleStateAndNotify(bundle, Bundle.RESOLVED); } /** * This is a Felix specific extension mechanism that allows extension bundles * to have activators and be started via this method. * * @param felix the framework instance the extension bundle is installed in. * @param bundle the extension bundle to start if it has a Felix specific activator. */ void startExtensionBundle(Felix felix, BundleImpl bundle) { String activatorClass = (String) ((BundleRevisionImpl) bundle.adapt(BundleRevision.class)) .getHeaders().get(FelixConstants.FELIX_EXTENSION_ACTIVATOR); if (activatorClass != null) { try { // TODO: SECURITY - Should this consider security? BundleActivator activator = (BundleActivator) felix.getClass().getClassLoader().loadClass( activatorClass.trim()).newInstance(); // TODO: EXTENSIONMANAGER - This is kind of hacky, can we improve it? felix.m_activatorList.add(activator); BundleContext context = felix._getBundleContext(); bundle.setBundleContext(context); if ((felix.getState() == Bundle.ACTIVE) || (felix.getState() == Bundle.STARTING)) { Felix.m_secureAction.startActivator(activator, context); } } catch (Throwable ex) { m_logger.log(bundle, Logger.LOG_WARNING, "Unable to start Felix Extension Activator", ex); } } } /** * Remove all extension registered by the given framework instance. Note, it * is not possible to unregister allready loaded classes form those extensions. * That is why the spec requires a JVM restart. * * @param felix the framework instance whose extensions need to be unregistered. */ void removeExtensions(Felix felix) { if (m_extensionManager != null) { m_extensionManager._removeExtensions(felix); } } private List getCapabilities(String namespace) { List caps = m_capabilities; List result = caps; if (namespace != null) { result = new ArrayList(); for (BundleCapability cap : caps) { if (cap.getNamespace().equals(namespace)) { result.add(cap); } } } return result; } private synchronized void appendCapabilities(List caps) { List newCaps = new ArrayList(m_capabilities.size() + caps.size()); newCaps.addAll(m_capabilities); newCaps.addAll(caps); m_capabilities = Collections.unmodifiableList(newCaps); m_headerMap.put(Constants.EXPORT_PACKAGE, convertCapabilitiesToHeaders(m_headerMap)); } private String convertCapabilitiesToHeaders(Map headers) { StringBuffer exportSB = new StringBuffer(""); Set exportNames = new HashSet(); List caps = m_capabilities; for (BundleCapability cap : caps) { if (cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)) { // Add a comma separate if there is an existing package. if (exportSB.length() > 0) { exportSB.append(", "); } // Append exported package information. exportSB.append(cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE)); for (Entry entry : cap.getDirectives().entrySet()) { exportSB.append("; "); exportSB.append(entry.getKey()); exportSB.append(":=\""); exportSB.append(entry.getValue()); exportSB.append("\""); } for (Entry entry : cap.getAttributes().entrySet()) { if (!entry.getKey().equals(BundleRevision.PACKAGE_NAMESPACE) && !entry.getKey().equals(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE) && !entry.getKey().equals(Constants.BUNDLE_VERSION_ATTRIBUTE)) { exportSB.append("; "); exportSB.append(entry.getKey()); exportSB.append("=\""); exportSB.append(entry.getValue()); exportSB.append("\""); } } // Remember exported packages. exportNames.add( (String) cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE)); } } m_exportNames = exportNames; return exportSB.toString(); } // // Classpath Extension // /* * See whether any registered extension provides the class requested. If not * throw an IOException. */ public URLConnection openConnection(URL url) throws IOException { String path = url.getPath(); if (path.trim().equals("/")) { return new URLHandlersBundleURLConnection(url); } Bundle[] extensions = m_extensionsCache; URL result = null; for (Bundle extBundle : extensions) { try { BundleRevisionImpl bri = (BundleRevisionImpl) extBundle.adapt(BundleRevision.class); if (bri != null) { result = bri.getResourceLocal(path); } } catch (Exception ex) { // Maybe the bundle went away, so ignore this exception. } if (result != null) { return result.openConnection(); } } return new URLConnection(url) { public void connect() throws IOException { throw new IOException("Resource not provided by any extension!"); } }; } protected InetAddress getHostAddress(URL u) { // the extension URLs do not address real hosts return null; } private synchronized void addExtension(Object source, Bundle extension) { List sourceExtensions = (List) m_sourceToExtensions.get(source); if (sourceExtensions == null) { sourceExtensions = new ArrayList(); m_sourceToExtensions.put(source, sourceExtensions); } sourceExtensions.add(extension); _add(extension.getSymbolicName(), extension); m_extensionsCache = (Bundle[]) m_extensions.toArray(new Bundle[m_extensions.size()]); } private synchronized void _removeExtensions(Object source) { if (m_sourceToExtensions.remove(source) == null) { return; } m_extensions.clear(); m_names.clear(); for (Iterator iter = m_sourceToExtensions.values().iterator(); iter.hasNext();) { List extensions = (List) iter.next(); for (Iterator extIter = extensions.iterator(); extIter.hasNext();) { Bundle bundle = (Bundle) extIter.next(); _add(bundle.getSymbolicName(), bundle); } m_extensionsCache = (Bundle[]) m_extensions.toArray(new Bundle[m_extensions.size()]); } } private void _add(String name, Bundle extension) { if (!m_names.contains(name)) { m_names.add(name); m_extensions.add(extension); } } public void close() { // Do nothing on close, since we have nothing open. } public Enumeration getEntries() { return new Enumeration() { public boolean hasMoreElements() { return false; } public Object nextElement() throws NoSuchElementException { throw new NoSuchElementException(); } }; } public boolean hasEntry(String name) { return false; } public byte[] getEntryAsBytes(String name) { return null; } public InputStream getEntryAsStream(String name) throws IOException { return null; } public Content getEntryAsContent(String name) { return null; } public String getEntryAsNativeLibrary(String name) { return null; } public URL getEntryAsURL(String name) { return null; } // // Utility methods. // class ExtensionManagerRevision extends BundleRevisionImpl { private final Version m_version; private volatile BundleWiring m_wiring; ExtensionManagerRevision(Felix felix) { super(felix, "0"); m_version = new Version((String) m_configMap.get(FelixConstants.FELIX_VERSION_PROPERTY)); } @Override public Map getHeaders() { synchronized (ExtensionManager.this) { return m_headerMap; } } @Override public List getDeclaredCapabilities(String namespace) { return ExtensionManager.this.getCapabilities(namespace); } @Override public String getSymbolicName() { return FelixConstants.SYSTEM_BUNDLE_SYMBOLICNAME; } @Override public Version getVersion() { return m_version; } @Override public void close() { // Nothing needed here. } @Override public Content getContent() { return ExtensionManager.this; } @Override public URL getEntry(String name) { // There is no content for the system bundle, so return null. return null; } @Override public boolean hasInputStream(int index, String urlPath) { return (getClass().getClassLoader().getResource(urlPath) != null); } @Override public InputStream getInputStream(int index, String urlPath) { return getClass().getClassLoader().getResourceAsStream(urlPath); } @Override public URL getLocalURL(int index, String urlPath) { return getClass().getClassLoader().getResource(urlPath); } @Override public void resolve(BundleWiringImpl wire) { try { m_wiring = new ExtensionManagerWiring( m_logger, m_configMap, this); } catch (Exception ex) { // This should never happen. } } @Override public BundleWiring getWiring() { return m_wiring; } } class ExtensionManagerWiring extends BundleWiringImpl { ExtensionManagerWiring( Logger logger, Map configMap, BundleRevisionImpl revision) throws Exception { super(logger, configMap, null, revision, null, Collections.EMPTY_LIST, null, null); } @Override public ClassLoader getClassLoader() { return getClass().getClassLoader(); } @Override public List getCapabilities(String namespace) { return ExtensionManager.this.getCapabilities(namespace); } @Override public List getNativeLibraries() { return Collections.EMPTY_LIST; } @Override public Class getClassByDelegation(String name) throws ClassNotFoundException { Class clazz = null; String pkgName = Util.getClassPackage(name); if (shouldBootDelegate(pkgName)) { try { // Get the appropriate class loader for delegation. ClassLoader bdcl = getBootDelegationClassLoader(); clazz = bdcl.loadClass(name); // If this is a java.* package, then always terminate the // search; otherwise, continue to look locally if not found. if (pkgName.startsWith("java.") || (clazz != null)) { return clazz; } } catch (ClassNotFoundException ex) { // If this is a java.* package, then always terminate the // search; otherwise, continue to look locally if not found. if (pkgName.startsWith("java.")) { throw ex; } } } if (clazz == null) { if (!m_exportNames.contains(Util.getClassPackage(name))) { throw new ClassNotFoundException(name); } clazz = getClass().getClassLoader().loadClass(name); } return clazz; } @Override public URL getResourceByDelegation(String name) { return getClass().getClassLoader().getResource(name); } @Override public Enumeration getResourcesByDelegation(String name) { try { return getClass().getClassLoader().getResources(name); } catch (IOException ex) { return null; } } @Override public void dispose() { // Nothing needed here. } } } felix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/EntryFilterEnumeration.java0000644000175000017500000002540611644651232032555 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework; import java.net.MalformedURLException; import java.net.URL; import java.util.*; import org.apache.felix.framework.capabilityset.SimpleFilter; import org.apache.felix.framework.util.Util; import org.osgi.framework.wiring.BundleRevision; class EntryFilterEnumeration implements Enumeration { private final BundleRevision m_revision; private final List m_enumerations; private final List m_revisions; private int m_revisionIndex = 0; private final String m_path; private final List m_filePattern; private final boolean m_recurse; private final boolean m_isURLValues; private final Set m_dirEntries = new HashSet(); private final List m_nextEntries = new ArrayList(2); public EntryFilterEnumeration( BundleRevision revision, boolean includeFragments, String path, String filePattern, boolean recurse, boolean isURLValues) { m_revision = revision; List fragments = Util.getFragments(revision.getWiring()); if (includeFragments && !fragments.isEmpty()) { m_revisions = fragments; } else { m_revisions = new ArrayList(1); } m_revisions.add(0, m_revision); m_enumerations = new ArrayList(m_revisions.size()); for (int i = 0; i < m_revisions.size(); i++) { m_enumerations.add(((BundleRevisionImpl) m_revisions.get(i)).getContent() != null ? ((BundleRevisionImpl) m_revisions.get(i)).getContent().getEntries() : null); } m_recurse = recurse; m_isURLValues = isURLValues; // Sanity check the parameters. if (path == null) { throw new IllegalArgumentException("The path for findEntries() cannot be null."); } // Strip leading '/' if present. if ((path.length() > 0) && (path.charAt(0) == '/')) { path = path.substring(1); } // Add a '/' to the end if not present. if ((path.length() > 0) && (path.charAt(path.length() - 1) != '/')) { path = path + "/"; } m_path = path; // File pattern defaults to "*" if not specified. filePattern = (filePattern == null) ? "*" : filePattern; m_filePattern = SimpleFilter.parseSubstring(filePattern); findNext(); } public synchronized boolean hasMoreElements() { return !m_nextEntries.isEmpty(); } public synchronized Object nextElement() { if (m_nextEntries.isEmpty()) { throw new NoSuchElementException("No more entries."); } Object last = m_nextEntries.remove(0); findNext(); return last; } private void findNext() { // This method filters the content entry enumeration, such that // it only displays the contents of the directory specified by // the path argument either recursively or not; much like using // "ls -R" or "ls" to list the contents of a directory, respectively. if (m_enumerations == null) { return; } while ((m_revisionIndex < m_enumerations.size()) && m_nextEntries.isEmpty()) { while (m_enumerations.get(m_revisionIndex) != null && m_enumerations.get(m_revisionIndex).hasMoreElements() && m_nextEntries.isEmpty()) { // Get the current entry to determine if it should be filtered or not. String entryName = (String) m_enumerations.get(m_revisionIndex).nextElement(); // Check to see if the current entry is a descendent of the specified path. if (!entryName.equals(m_path) && entryName.startsWith(m_path)) { // Cached entry URL. If we are returning URLs, we use this // cached URL to avoid doing multiple URL lookups from a revision // when synthesizing directory URLs. URL entryURL = null; // If the current entry is in a subdirectory of the specified path, // get the index of the slash character. int dirSlashIdx = entryName.indexOf('/', m_path.length()); // JAR files are supposed to contain entries for directories, // but not all do. So determine the directory for this entry // and see if we've already seen an entry for for it. If not, // synthesize an entry for it. If we are doing a recursive // match, we need to synthesize each matching subdirectory // of the entry. if (dirSlashIdx >= 0) { // Start synthesizing directories for the current entry // at the subdirectory after the initial path. int subDirSlashIdx = dirSlashIdx; String dir; do { // Calculate the subdirectory name. dir = entryName.substring(0, subDirSlashIdx + 1); // If we have not seen this directory before, then record // it and add it to the list of available next entries. If // the original entry is actually a directory, then it will // be added to next entries like normal if it matches, but if // it is not a directory, its parent directory entries may be // synthesized depending on the matching filter and recursion. if (!m_dirEntries.contains(dir)) { // Record the directory entry. m_dirEntries.add(dir); // Add the directory to the list of if (SimpleFilter.compareSubstring( m_filePattern, getLastPathElement(dir))) { // Add synthesized directory entry to the next // entries list in the correct form. if (m_isURLValues) { entryURL = (entryURL == null) ? ((BundleRevisionImpl) m_revisions. get(m_revisionIndex)).getEntry(entryName) : entryURL; try { m_nextEntries.add(new URL(entryURL, "/" + dir)); } catch (MalformedURLException ex) { } } else { m_nextEntries.add(dir); } } } // Now prepare to synthesize the next subdirectory // if we are matching recursively. subDirSlashIdx = entryName.indexOf('/', dir.length()); } while (m_recurse && (subDirSlashIdx >= 0)); } // Now we actually need to check if the current entry itself should // be filtered or not. If we are recursive or the current entry // is a child (not a grandchild) of the initial path, then we need // to check if it matches the file pattern. If we've already added // or synthesized the directory entry, then we can ignore it. if (!m_dirEntries.contains(entryName) && (m_recurse || (dirSlashIdx < 0) || (dirSlashIdx == entryName.length() - 1))) { // See if the file pattern matches the last element of the path. if (SimpleFilter.compareSubstring( m_filePattern, getLastPathElement(entryName))) { if (m_isURLValues) { entryURL = (entryURL == null) ? ((BundleRevisionImpl) m_revisions.get(m_revisionIndex)).getEntry(entryName) : entryURL; m_nextEntries.add(entryURL); } else { m_nextEntries.add(entryName); } } } } } if (m_nextEntries.isEmpty()) { m_revisionIndex++; // Reset directory entries, since fragments may // have overlapping directory entries that need // to be returned. m_dirEntries.clear(); } } } private static String getLastPathElement(String entryName) { int endIdx = (entryName.charAt(entryName.length() - 1) == '/') ? entryName.length() - 1 : entryName.length(); int startIdx = (entryName.charAt(entryName.length() - 1) == '/') ? entryName.lastIndexOf('/', endIdx - 1) + 1 : entryName.lastIndexOf('/', endIdx) + 1; return entryName.substring(startIdx, endIdx); } } felix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/Felix.java0000644000175000017500000055001511644651232027145 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework; import org.osgi.framework.launch.Framework; import java.io.*; import java.net.*; import java.security.*; import java.util.*; import org.apache.felix.framework.BundleWiringImpl.BundleClassLoader; import org.apache.felix.framework.ServiceRegistry.ServiceRegistryCallbacks; import org.apache.felix.framework.cache.BundleArchive; import org.apache.felix.framework.cache.BundleCache; import org.apache.felix.framework.capabilityset.CapabilitySet; import org.apache.felix.framework.capabilityset.SimpleFilter; import org.apache.felix.framework.ext.SecurityProvider; import org.apache.felix.framework.resolver.ResolveException; import org.apache.felix.framework.util.EventDispatcher; import org.apache.felix.framework.util.FelixConstants; import org.apache.felix.framework.util.ListenerInfo; import org.apache.felix.framework.util.MapToDictionary; import org.apache.felix.framework.util.SecureAction; import org.apache.felix.framework.util.ShrinkableCollection; import org.apache.felix.framework.util.StringMap; import org.apache.felix.framework.util.ThreadGate; import org.apache.felix.framework.util.Util; import org.apache.felix.framework.util.manifestparser.R4LibraryClause; import org.apache.felix.framework.wiring.BundleRequirementImpl; import org.osgi.framework.AdminPermission; import org.osgi.framework.Bundle; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleEvent; import org.osgi.framework.BundleException; import org.osgi.framework.BundleListener; import org.osgi.framework.BundleReference; import org.osgi.framework.Constants; import org.osgi.framework.Filter; import org.osgi.framework.FrameworkEvent; import org.osgi.framework.FrameworkListener; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceEvent; import org.osgi.framework.ServiceException; import org.osgi.framework.ServiceFactory; import org.osgi.framework.ServiceListener; import org.osgi.framework.ServicePermission; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; import org.osgi.framework.startlevel.FrameworkStartLevel; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRevision; import org.osgi.framework.wiring.BundleRevisions; import org.osgi.framework.wiring.BundleWiring; import org.osgi.framework.wiring.FrameworkWiring; import org.osgi.service.packageadmin.ExportedPackage; public class Felix extends BundleImpl implements Framework { // The secure action used to do privileged calls static final SecureAction m_secureAction = new SecureAction(); // The extension manager to handle extension bundles private final ExtensionManager m_extensionManager; // Framework wiring object. private final FrameworkWiringImpl m_fwkWiring; private final FrameworkStartLevelImpl m_fwkStartLevel; // Logging related member variables. private final Logger m_logger; // Immutable config properties. private final Map m_configMap; // Mutable configuration properties passed into constructor. private final Map m_configMutableMap; // Resolver and resolver state. private final StatefulResolver m_resolver; // Lock object used to determine if an individual bundle // lock or the global lock can be acquired. private final Object[] m_bundleLock = new Object[0]; // Keeps track of threads wanting to acquire the global lock. private final List m_globalLockWaitersList = new ArrayList(); // The thread currently holding the global lock. private Thread m_globalLockThread = null; // How many times the global lock was acquired by the thread holding // the global lock; if this value is zero, then it means the global // lock is free. private int m_globalLockCount = 0; // Maps a bundle location to a bundle location; // used to reserve a location when installing a bundle. private final Map m_installRequestMap = new HashMap(); // This lock must be acquired to modify m_installRequestMap; // to help avoid deadlock this lock as priority 1 and should // be acquired before locks with lower priority. private final Object[] m_installRequestLock_Priority1 = new Object[0]; // Contains two maps, one mapping a String bundle location to a bundle // and the other mapping a Long bundle identifier to a bundle. // CONCURRENCY: Access guarded by the global lock for writes, // but no lock for reads since it is copy on write. private volatile Map[] m_installedBundles; private static final int LOCATION_MAP_IDX = 0; private static final int IDENTIFIER_MAP_IDX = 1; // An array of uninstalled bundles before a refresh occurs. // CONCURRENCY: Access guarded by the global lock for writes, // but no lock for reads since it is copy on write. private volatile List m_uninstalledBundles; // Object to keep track of dependencies among bundle revisions. private final BundleRevisionDependencies m_dependencies = new BundleRevisionDependencies(); // Framework's active start level. private volatile int m_activeStartLevel = FelixConstants.FRAMEWORK_INACTIVE_STARTLEVEL; // Framework's target start level. // Normally the target start will equal the active start level, except // whem the start level is changing, in which case the target start level // will report the new start level while the active start level will report // the old start level. Once the start level change is complete, the two // will become equal again. private volatile int m_targetStartLevel = FelixConstants.FRAMEWORK_INACTIVE_STARTLEVEL; // Keep track of bundles currently being processed by start level thread. private final SortedSet m_startLevelBundles = new TreeSet(); // Local bundle cache. private BundleCache m_cache = null; // System bundle activator list. List m_activatorList = null; // Next available bundle identifier. private long m_nextId = 1L; private final Object m_nextIdLock = new Object[0]; // Service registry. private final ServiceRegistry m_registry; // List of event listeners. private final EventDispatcher m_dispatcher; // Reusable bundle URL stream handler. private final URLStreamHandler m_bundleStreamHandler; // Boot package delegation. private final String[] m_bootPkgs; private final boolean[] m_bootPkgWildcards; // Shutdown gate. private volatile ThreadGate m_shutdownGate = null; // Security Manager created by the framework private SecurityManager m_securityManager = null; /** *

* This constructor creates a framework instance with a specified Map * of configuration properties. Configuration properties are used internally * by the framework to alter its default behavior. The configuration properties * should have a String key and an Object value. The passed * in Map is copied by the framework and all keys are converted to * Strings. *

*

* Configuration properties are generally the sole means to configure the * framework's default behavior; the framework does not typically refer to * any system properties for configuration information. If a Map is * supplied to this method for configuration properties, then the framework * will consult the Map instance for any and all configuration * properties. It is possible to specify a null for the configuration * property map, in which case the framework will use its default behavior * in all cases. *

*

* The following configuration properties can be specified (properties starting * with "felix" are specific to Felix, while those starting with * "org.osgi" are standard OSGi properties): *

*
    *
  • org.osgi.framework.storage - Sets the directory to use as * the bundle cache; by default bundle cache directory is * felix-cache in the current working directory. The value * should be a valid directory name. The directory name can be either absolute * or relative. Relative directory names are relative to the current working * directory. The specified directory will be created if it does * not exist. *
  • *
  • org.osgi.framework.storage.clean - Determines whether the * bundle cache is flushed. The value can either be "none" * or "onFirstInit", where "none" does not flush * the bundle cache and "onFirstInit" flushes the bundle * cache when the framework instance is first initialized. The default * value is "none". *
  • *
  • felix.cache.rootdir - Sets the root directory to use to * calculate the bundle cache directory for relative directory names. If * org.osgi.framework.storage is set to a relative name, by * default it is relative to the current working directory. If this * property is set, then it will be calculated as being relative to * the specified root directory. *
  • *
  • felix.cache.filelimit - The integer value of this string * sets an upper limit on how many files the cache will open. The default * value is zero, which means there is no limit. *
  • *
  • felix.cache.locking - Enables or disables bundle cache locking, * which is used to prevent concurrent access to the bundle cache. This is * enabled by default, but on older/smaller JVMs file channel locking is * not available; set this property to false to disable it. *
  • *
  • felix.cache.bufsize - Sets the buffer size to be used by * the cache; the default value is 4096. The integer value of this * string provides control over the size of the internal buffer of the * disk cache for performance reasons. *
  • *
  • org.osgi.framework.system.packages - Specifies a * comma-delimited list of packages that should be exported via the * System Bundle from the parent class loader. The framework will set * this to a reasonable default. If the value is specified, it * replaces any default value. *
  • *
  • org.osgi.framework.system.packages.extra - Specifies a * comma-delimited list of packages that should be exported via the * System Bundle from the parent class loader in addition to the * packages in org.osgi.framework.system.packages. The default * value is empty. If a value is specified, it is appended to the list * of default or specified packages in * org.osgi.framework.system.packages. *
  • *
  • org.osgi.framework.bootdelegation - Specifies a * comma-delimited list of packages that should be made implicitly * available to all bundles from the parent class loader. It is * recommended not to use this property since it breaks modularity. * The default value is empty. *
  • *
  • felix.systembundle.activators - A List of * BundleActivator instances that are started/stopped when * the System Bundle is started/stopped. The specified instances will * receive the System Bundle's BundleContext when invoked. *
  • *
  • felix.log.logger - An instance of Logger that the * framework uses as its default logger. *
  • *
  • felix.log.level - An integer value indicating the degree * of logging reported by the framework; the higher the value the more * logging is reported. If zero ('0') is specified, then logging is * turned off completely. The log levels match those specified in the * OSGi Log Service (i.e., 1 = error, 2 = warning, 3 = information, * and 4 = debug). The default value is 1. *
  • *
  • org.osgi.framework.startlevel.beginning - The initial * start level of the framework once it starts execution; the default * value is 1. *
  • *
  • felix.startlevel.bundle - The default start level for * newly installed bundles; the default value is 1. *
  • *
  • felix.service.urlhandlers - Flag to indicate whether * to activate the URL Handlers service for the framework instance; * the default value is "true". Activating the URL Handlers * service will result in the URL.setURLStreamHandlerFactory() * and URLConnection.setContentHandlerFactory() being called. *
  • *
  • felix.fragment.validation - Determines if installing * unsupported fragment bundles throws an exception or logs a warning. * Possible values are "exception" or "warning". The * default value is "exception". *
*

* The Main class implements some * functionality for default property file handling, which makes it * possible to specify configuration properties and framework properties * in files that are automatically loaded when starting the framework. If you * plan to create your own framework instance, you may be * able to take advantage of the features it provides; refer to its * class documentation for more information. *

*

* The framework is not actually started until the start() method * is called. *

* * @param configMap A map for obtaining configuration properties, * may be null. **/ public Felix(Map configMap) { super(); // Copy the configuration properties; convert keys to strings. m_configMutableMap = new StringMap(false); if (configMap != null) { for (Iterator i = configMap.entrySet().iterator(); i.hasNext(); ) { Map.Entry entry = (Map.Entry) i.next(); m_configMutableMap.put(entry.getKey().toString(), entry.getValue()); } } m_configMap = createUnmodifiableMap(m_configMutableMap); // Create logger with appropriate log level. Even though the // logger needs the system bundle's context for tracking log // services, it is created now because it is needed before // the system bundle is activated. The system bundle's context // will be set in the init() method after the system bundle // is activated. if (m_configMutableMap.get(FelixConstants.LOG_LOGGER_PROP) != null) { m_logger = (Logger) m_configMutableMap.get(FelixConstants.LOG_LOGGER_PROP); } else { m_logger = new Logger(); } try { m_logger.setLogLevel( Integer.parseInt( (String) m_configMutableMap.get(FelixConstants.LOG_LEVEL_PROP))); } catch (NumberFormatException ex) { // Ignore and just use the default logging level. } // Initialize framework properties. initializeFrameworkProperties(); // Read the boot delegation property and parse it. String s = (m_configMap == null) ? null : (String) m_configMap.get(Constants.FRAMEWORK_BOOTDELEGATION); s = (s == null) ? "java.*" : s + ",java.*"; StringTokenizer st = new StringTokenizer(s, " ,"); m_bootPkgs = new String[st.countTokens()]; m_bootPkgWildcards = new boolean[m_bootPkgs.length]; for (int i = 0; i < m_bootPkgs.length; i++) { s = st.nextToken(); if (s.equals("*") || s.endsWith(".*")) { m_bootPkgWildcards[i] = true; s = s.substring(0, s.length() - 1); } m_bootPkgs[i] = s; } // Create default bundle stream handler. m_bundleStreamHandler = new URLHandlersBundleStreamHandler(this); // Create a resolver and its state. m_resolver = new StatefulResolver(this); // Create the extension manager, which we will use as the // revision for the system bundle. m_extensionManager = new ExtensionManager(m_logger, m_configMap, this); try { addRevision(m_extensionManager.getRevision()); } catch (Exception ex) { // This should not throw an exception, but if so, lets convert it to // a runtime exception. throw new RuntimeException(ex.getMessage()); } // Create service registry. m_registry = new ServiceRegistry(m_logger, new ServiceRegistryCallbacks() { public void serviceChanged(ServiceEvent event, Dictionary oldProps) { fireServiceEvent(event, oldProps); } }); // Create event dispatcher. m_dispatcher = new EventDispatcher(m_logger, m_registry); // Create framework wiring object. m_fwkWiring = new FrameworkWiringImpl(this, m_registry); // Create framework start level object. m_fwkStartLevel = new FrameworkStartLevelImpl(this, m_registry); } Logger getLogger() { return m_logger; } Map getConfig() { return m_configMap; } StatefulResolver getResolver() { return m_resolver; } BundleRevisionDependencies getDependencies() { return m_dependencies; } URLStreamHandler getBundleStreamHandler() { return m_bundleStreamHandler; } String[] getBootPackages() { return m_bootPkgs; } boolean[] getBootPackageWildcards() { return m_bootPkgWildcards; } private Map createUnmodifiableMap(Map mutableMap) { Map result = Collections.unmodifiableMap(mutableMap); // Work around a bug in certain version of J9 where a call to // Collections.unmodifiableMap().keySet().iterator() throws // a NoClassDefFoundError. We try to detect this and return // the given mutableMap instead. try { result.keySet().iterator(); } catch (NoClassDefFoundError ex) { return mutableMap; } return result; } // This overrides BundleImpl.close() which avoids removing the // system bundle module from the resolver state. @Override void close() { } // This overrides the default behavior of BundleImpl.getFramework() // to return "this", since the system bundle is the framework. Felix getFramework() { return this; } @Override public A adapt(Class type) { checkAdapt(type); if ((type == FrameworkWiring.class) || (type == FrameworkWiringImpl.class)) { return (A) m_fwkWiring; } else if ((type == FrameworkStartLevel.class) || (type == FrameworkStartLevelImpl.class)) { return (A) m_fwkStartLevel; } return super.adapt(type); } public long getBundleId() { return 0; } public long getLastModified() { return 0; } void setLastModified(long l) { // Ignore. } String _getLocation() { return Constants.SYSTEM_BUNDLE_LOCATION; } public int getPersistentState() { return Bundle.ACTIVE; } public void setPersistentStateInactive() { // Ignore. } public void setPersistentStateActive() { // Ignore. } public void setPersistentStateUninstalled() { // Ignore. } /** * Overrides standard BundleImpl.getStartLevel() behavior to * always return zero for the system bundle. * @param defaultLevel This parameter is ignored by the system bundle. * @return Always returns zero. **/ int getStartLevel(int defaultLevel) { return 0; } /** * Overrides standard BundleImpl.setStartLevel() behavior to * always throw an exception since the system bundle's start level cannot * be changed. * @param level This parameter is ignored by the system bundle. * @throws IllegalArgumentException Always throws exception since system * bundle's start level cannot be changed. **/ void setStartLevel(int level) { throw new IllegalArgumentException("Cannot set the system bundle's start level."); } public boolean hasPermission(Object obj) { return true; } /** * This method initializes the framework, which is comprised of resolving * the system bundle, reloading any cached bundles, and activating the system * bundle. The framework is left in the Bundle.STARTING state and * reloaded bundles are in the Bundle.INSTALLED state. After * successfully invoking this method, getBundleContext() will * return a valid BundleContext for the system bundle. To finish * starting the framework, invoke the start() method. * * @throws org.osgi.framework.BundleException if any error occurs. **/ public void init() throws BundleException { // The system bundle can only be initialized if it currently isn't started. acquireBundleLock(this, Bundle.INSTALLED | Bundle.RESOLVED | Bundle.STARTING | Bundle.ACTIVE); try { if ((getState() == Bundle.INSTALLED) || (getState() == Bundle.RESOLVED)) { String security = (String) m_configMap.get(Constants.FRAMEWORK_SECURITY); if (security != null) { if (System.getSecurityManager() != null) { throw new SecurityException("SecurityManager already installed"); } security = security.trim(); if (Constants.FRAMEWORK_SECURITY_OSGI.equalsIgnoreCase(security) || (security.length() == 0)) { System.setSecurityManager(m_securityManager = new SecurityManager()); } else { try { System.setSecurityManager(m_securityManager = (SecurityManager) Class.forName(security).newInstance()); } catch (Throwable t) { SecurityException se = new SecurityException( "Unable to install custom SecurityManager: " + security); se.initCause(t); throw se; } } } // Generate a framework UUID. // Spec says we get a new UUID for each invocation of init(). m_configMutableMap.put( FelixConstants.FRAMEWORK_UUID, Util.randomUUID()); // Get any system bundle activators. m_activatorList = (List) m_configMutableMap.get(FelixConstants.SYSTEMBUNDLE_ACTIVATORS_PROP); m_activatorList = (m_activatorList == null) ? new ArrayList() : new ArrayList(m_activatorList); // Initialize event dispatcher. m_dispatcher.startDispatching(); // Create the bundle cache, if necessary, so that we can reload any // installed bundles. m_cache = (BundleCache) m_configMutableMap.get(FelixConstants.FRAMEWORK_BUNDLECACHE_IMPL); if (m_cache == null) { try { m_cache = new BundleCache(m_logger, m_configMap); } catch (Exception ex) { m_logger.log(Logger.LOG_ERROR, "Error creating bundle cache.", ex); throw new BundleException("Error creating bundle cache.", ex); } } // If this is the first time init is called, check to see if // we need to flush the bundle cache. if (getState() == Bundle.INSTALLED) { String clean = (String) m_configMap.get(Constants.FRAMEWORK_STORAGE_CLEAN); if ((clean != null) && clean.equalsIgnoreCase(Constants.FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT)) { try { m_cache.delete(); } catch (Exception ex) { throw new BundleException("Unable to flush bundle cache.", ex); } } } // Initialize installed bundle data structures. Map[] maps = new Map[] { new HashMap(1), new TreeMap() }; m_uninstalledBundles = new ArrayList(0); // Add the system bundle to the set of installed bundles. maps[LOCATION_MAP_IDX].put(_getLocation(), this); maps[IDENTIFIER_MAP_IDX].put(new Long(0), this); m_installedBundles = maps; // Manually resolve the system bundle, which will cause its // state to be set to RESOLVED. try { m_resolver.resolve( Collections.singleton(adapt(BundleRevision.class)), Collections.EMPTY_SET); } catch (ResolveException ex) { // This should never happen. throw new BundleException( "Unresolved constraint in System Bundle:" + ex.getRequirement()); } // Reload the cached bundles before creating and starting the // system bundle, since we want all cached bundles to be reloaded // when we activate the system bundle and any subsequent system // bundle activators passed into the framework constructor. BundleArchive[] archives = null; // First get cached bundle identifiers. try { archives = m_cache.getArchives(); } catch (Exception ex) { m_logger.log(Logger.LOG_ERROR, "Unable to list saved bundles.", ex); archives = null; } // Now load all cached bundles. for (int i = 0; (archives != null) && (i < archives.length); i++) { try { // Keep track of the max bundle ID currently in use since we // will need to use this as our next bundle ID value if the // persisted value cannot be read. m_nextId = Math.max(m_nextId, archives[i].getId() + 1); // It is possible that a bundle in the cache was previously // uninstalled, but not completely deleted (perhaps because // of a crash or a locked file), so if we see an archive // with an UNINSTALLED persistent state, then try to remove // it now. if (archives[i].getPersistentState() == Bundle.UNINSTALLED) { archives[i].closeAndDelete(); } // Otherwise re-install the cached bundle. else { // Install the cached bundle. reloadBundle(archives[i]); } } catch (Exception ex) { fireFrameworkEvent(FrameworkEvent.ERROR, this, ex); try { m_logger.log( Logger.LOG_ERROR, "Unable to re-install " + archives[i].getLocation(), ex); } catch (Exception ex2) { m_logger.log( Logger.LOG_ERROR, "Unable to re-install cached bundle.", ex); } // TODO: FRAMEWORK - Perhaps we should remove the cached bundle? } } // Now that we have loaded all cached bundles and have determined the // max bundle ID of cached bundles, we need to try to load the next // bundle ID from persistent storage. In case of failure, we should // keep the max value. m_nextId = Math.max(m_nextId, loadNextId()); // The framework is now in its startup sequence. setBundleStateAndNotify(this, Bundle.STARTING); // Now it is possible for threads to wait for the framework to stop, // so create a gate for that purpose. m_shutdownGate = new ThreadGate(); // Create system bundle activator and bundle context so we can activate it. setActivator(new SystemBundleActivator()); setBundleContext(new BundleContextImpl(m_logger, this, this)); try { Felix.m_secureAction.startActivator( getActivator(), _getBundleContext()); } catch (Throwable ex) { m_dispatcher.stopDispatching(); m_logger.log(Logger.LOG_ERROR, "Unable to start system bundle.", ex); throw new RuntimeException("Unable to start system bundle."); } // Now that the system bundle is successfully created we can give // its bundle context to the logger so that it can track log services. m_logger.setSystemBundleContext(_getBundleContext()); // Clear the cache of classes coming from the system bundle. // This is only used for Felix.getBundle(Class clazz) to speed // up class lookup for the system bundle. synchronized (m_systemBundleClassCache) { m_systemBundleClassCache.clear(); } } } finally { releaseBundleLock(this); } } /** * This method starts the framework instance, which will transition the * framework from start level 0 to its active start level as specified in * its configuration properties (1 by default). If the init() was * not explicitly invoked before calling this method, then it will be * implicitly invoked before starting the framework. * * @throws org.osgi.framework.BundleException if any error occurs. **/ public void start() throws BundleException { int startLevel = FelixConstants.FRAMEWORK_DEFAULT_STARTLEVEL; acquireBundleLock(this, Bundle.INSTALLED | Bundle.RESOLVED | Bundle.STARTING | Bundle.ACTIVE); try { // Initialize if necessary. if ((getState() == Bundle.INSTALLED) || (getState() == Bundle.RESOLVED)) { init(); } // If the current state is STARTING, then the system bundle can be started. if (getState() == Bundle.STARTING) { // Get the framework's default start level. String s = (String) m_configMap.get(Constants.FRAMEWORK_BEGINNING_STARTLEVEL); if (s != null) { try { startLevel = Integer.parseInt(s); } catch (NumberFormatException ex) { startLevel = FelixConstants.FRAMEWORK_DEFAULT_STARTLEVEL; } } m_fwkStartLevel.setStartLevelAndWait(startLevel); // The framework is now running. setBundleStateAndNotify(this, Bundle.ACTIVE); } } finally { releaseBundleLock(this); } // Fire started event for system bundle. fireBundleEvent(BundleEvent.STARTED, this); // Send a framework event to indicate the framework has started. fireFrameworkEvent(FrameworkEvent.STARTED, this, null); } public void start(int options) throws BundleException { start(); } /** * This method asynchronously shuts down the framework, it must be called at the * end of a session in order to shutdown all active bundles. **/ public void stop() throws BundleException { Object sm = System.getSecurityManager(); if (sm != null) { ((SecurityManager) sm).checkPermission(new AdminPermission(this, AdminPermission.EXECUTE)); } if ((getState() & (Bundle.INSTALLED | Bundle.RESOLVED)) == 0) { // Spec says stop() on SystemBundle should return immediately and // shutdown framework on another thread. new Thread(new Runnable() { public void run() { try { stopBundle(Felix.this, true); } catch (BundleException ex) { m_logger.log( Logger.LOG_ERROR, "Exception trying to stop framework.", ex); } } }, "FelixShutdown").start(); } } public void stop(int options) throws BundleException { stop(); } /** * This method will cause the calling thread to block until the framework * shuts down. * @param timeout A timeout value. * @throws java.lang.InterruptedException If the thread was interrupted. **/ public FrameworkEvent waitForStop(long timeout) throws InterruptedException { // Throw exception if timeout is negative. if (timeout < 0) { throw new IllegalArgumentException("Timeout cannot be negative."); } // If there is a gate, wait on it; otherwise, return immediately. // Grab a copy of the gate, since it is volatile. ThreadGate gate = m_shutdownGate; boolean open = false; if (gate != null) { open = gate.await(timeout); } FrameworkEvent event; if (open && (gate.getMessage() != null)) { event = (FrameworkEvent) gate.getMessage(); } else if (!open && (gate != null)) { event = new FrameworkEvent(FrameworkEvent.WAIT_TIMEDOUT, this, null); } else { event = new FrameworkEvent(FrameworkEvent.STOPPED, this, null); } return event; } public void uninstall() throws BundleException { throw new BundleException("Cannot uninstall the system bundle."); } public void update() throws BundleException { update(null); } public void update(InputStream is) throws BundleException { Object sm = System.getSecurityManager(); if (sm != null) { ((SecurityManager) sm).checkPermission(new AdminPermission(this, AdminPermission.EXECUTE)); } // Spec says to close input stream first. try { if (is != null) is.close(); } catch (IOException ex) { m_logger.log(Logger.LOG_WARNING, "Exception closing input stream.", ex); } // Then to stop and restart the framework on a separate thread. new Thread(new Runnable() { public void run() { try { // First acquire the system bundle lock to verify the state. acquireBundleLock(Felix.this, Bundle.STARTING | Bundle.ACTIVE); // Set the reason for the shutdown. m_shutdownGate.setMessage( new FrameworkEvent(FrameworkEvent.STOPPED_UPDATE, Felix.this, null)); // Record the state and stop the system bundle. int oldState = Felix.this.getState(); try { stop(); } catch (BundleException ex) { m_logger.log(Logger.LOG_WARNING, "Exception stopping framework.", ex); } finally { releaseBundleLock(Felix.this); } // Make sure the framework is stopped. try { waitForStop(0); } catch (InterruptedException ex) { m_logger.log(Logger.LOG_WARNING, "Did not wait for framework to stop.", ex); } // Depending on the old state, restart the framework. try { switch (oldState) { case Bundle.STARTING: init(); break; case Bundle.ACTIVE: start(); break; } } catch (BundleException ex) { m_logger.log(Logger.LOG_WARNING, "Exception restarting framework.", ex); } } catch (Exception ex) { m_logger.log(Logger.LOG_WARNING, "Cannot update an inactive framework."); } } }).start(); } public String toString() { return getSymbolicName() + " [" + getBundleId() +"]"; } /** * Returns the active start level of the framework; this method * implements functionality for the Start Level service. * @return The active start level of the framework. **/ int getActiveStartLevel() { return m_activeStartLevel; } /** * Implements the functionality of the setStartLevel() * method for the StartLevel service, but does not do the security or * parameter check. The security and parameter check are done in the * StartLevel service implementation because this method is called on * a separate thread and the caller's thread would already be gone if * we did the checks in this method. This method should not be called * directly. * @param requestedLevel The new start level of the framework. **/ void setActiveStartLevel(int requestedLevel, FrameworkListener[] listeners) { Bundle[] bundles = null; // Record the target start level immediately and use this for // comparisons for starting/stopping bundles to avoid race // conditions to restart stopped bundles. m_targetStartLevel = requestedLevel; // Do nothing if the requested start level is the same as the // active start level. if (m_targetStartLevel != m_activeStartLevel) { // Synchronization for changing the start level is rather loose. // The framework's active start level is volatile, so no lock is // needed to access it. No locks are held while processing the // currently installed bundles for starting/stopping based on the new // active start level. The only locking that occurs is for individual // bundles when startBundle()/stopBundle() is called, but this locking // is done in the respective method. // // This approach does mean that it is possible for a for individual // bundle states to change during this operation. If a bundle's start // level changes, then it is possible for it to be processed out of // order. Uninstalled bundles are just logged andignored. // // Calls to this method are only made by the start level thread, which // serializes framework start level changes. Thus, it is not possible // for two requests to change the framework's start level to interfere // with each other. // Determine if we are lowering or raising the // active start level. boolean lowering = (m_targetStartLevel < m_activeStartLevel); // Acquire global lock. boolean locked = acquireGlobalLock(); if (!locked) { // If the calling thread holds bundle locks, then we might not // be able to get the global lock. throw new IllegalStateException( "Unable to acquire global lock to create bundle snapshot."); } boolean bundlesRemaining; try { synchronized (m_startLevelBundles) { // Get a sorted snapshot of all installed bundles // to be processed during the start level change. // We also snapshot the start level here, since it // may change and we don't want to consider any // changes since they will be queued for the start // level thread. bundles = getBundles(); for (Bundle b : bundles) { m_startLevelBundles.add( new StartLevelTuple( (BundleImpl) b, ((BundleImpl) b).getStartLevel( getInitialBundleStartLevel()))); } bundlesRemaining = !m_startLevelBundles.isEmpty(); } } finally { releaseGlobalLock(); } // Process bundles and stop or start them accordingly. while (bundlesRemaining) { StartLevelTuple tuple; synchronized (m_startLevelBundles) { if (lowering) { tuple = m_startLevelBundles.last(); } else { tuple = m_startLevelBundles.first(); } } // Ignore the system bundle, since its start() and // stop() methods get called explicitly in Felix.start() // and Felix.stop(), respectively. if (tuple.m_bundle.getBundleId() != 0) { // Lock the current bundle. try { acquireBundleLock(tuple.m_bundle, Bundle.INSTALLED | Bundle.RESOLVED | Bundle.ACTIVE | Bundle.STARTING | Bundle.STOPPING); } catch (IllegalStateException ex) { // Ignore if the bundle has been uninstalled. if (tuple.m_bundle.getState() != Bundle.UNINSTALLED) { fireFrameworkEvent(FrameworkEvent.ERROR, tuple.m_bundle, ex); m_logger.log(tuple.m_bundle, Logger.LOG_ERROR, "Error locking " + tuple.m_bundle._getLocation(), ex); } continue; } try { // Start the bundle if necessary. if (((tuple.m_bundle.getPersistentState() == Bundle.ACTIVE) || (tuple.m_bundle.getPersistentState() == Bundle.STARTING)) && (tuple.m_level <= m_targetStartLevel)) { // Count up the active start level. if (m_activeStartLevel != tuple.m_level) { m_activeStartLevel = tuple.m_level; } try { // TODO: LAZY - Not sure if this is the best way... int options = Bundle.START_TRANSIENT; options = (tuple.m_bundle.getPersistentState() == Bundle.STARTING) ? options | Bundle.START_ACTIVATION_POLICY : options; startBundle(tuple.m_bundle, options); } catch (Throwable th) { fireFrameworkEvent(FrameworkEvent.ERROR, tuple.m_bundle, th); m_logger.log(tuple.m_bundle, Logger.LOG_ERROR, "Error starting " + tuple.m_bundle._getLocation(), th); } } // Stop the bundle if necessary. else if (((tuple.m_bundle.getState() == Bundle.ACTIVE) || (tuple.m_bundle.getState() == Bundle.STARTING)) && (tuple.m_level > m_targetStartLevel)) { // Count down the active start level. if (m_activeStartLevel != tuple.m_level) { m_activeStartLevel = tuple.m_level; } try { stopBundle(tuple.m_bundle, false); } catch (Throwable th) { fireFrameworkEvent(FrameworkEvent.ERROR, tuple.m_bundle, th); m_logger.log(tuple.m_bundle, Logger.LOG_ERROR, "Error stopping " + tuple.m_bundle._getLocation(), th); } } } finally { // Always release bundle lock. releaseBundleLock(tuple.m_bundle); } } synchronized (m_startLevelBundles) { m_startLevelBundles.remove(tuple); bundlesRemaining = !m_startLevelBundles.isEmpty(); } } m_activeStartLevel = m_targetStartLevel; } if (getState() == Bundle.ACTIVE) { fireFrameworkEvent(FrameworkEvent.STARTLEVEL_CHANGED, this, null); if (listeners != null) { FrameworkEvent event = new FrameworkEvent( FrameworkEvent.STARTLEVEL_CHANGED, this, null); for (FrameworkListener l : listeners) { try { l.frameworkEvent(event); } catch (Throwable th) { m_logger.log(Logger.LOG_ERROR, "Framework listener delivery error.", th); } } } } } /** * Returns the start level into which newly installed bundles will * be placed by default; this method implements functionality for * the Start Level service. * @return The default start level for newly installed bundles. **/ int getInitialBundleStartLevel() { String s = (String) m_configMap.get(FelixConstants.BUNDLE_STARTLEVEL_PROP); if (s != null) { try { int i = Integer.parseInt(s); return (i > 0) ? i : FelixConstants.BUNDLE_DEFAULT_STARTLEVEL; } catch (NumberFormatException ex) { // Ignore and return the default value. } } return FelixConstants.BUNDLE_DEFAULT_STARTLEVEL; } /** * Sets the default start level into which newly installed bundles * will be placed; this method implements functionality for the Start * Level service. * @param startLevel The new default start level for newly installed * bundles. * @throws java.lang.IllegalArgumentException If the specified start * level is not greater than zero. * @throws java.security.SecurityException If the caller does not * have AdminPermission. **/ void setInitialBundleStartLevel(int startLevel) { if (startLevel <= 0) { throw new IllegalArgumentException( "Initial start level must be greater than zero."); } m_configMutableMap.put( FelixConstants.BUNDLE_STARTLEVEL_PROP, Integer.toString(startLevel)); } /** * Returns the start level for the specified bundle; this method * implements functionality for the Start Level service. * @param bundle The bundle to examine. * @return The start level of the specified bundle. * @throws java.lang.IllegalArgumentException If the specified * bundle has been uninstalled. **/ int getBundleStartLevel(Bundle bundle) { if (bundle.getState() == Bundle.UNINSTALLED) { throw new IllegalArgumentException("Bundle is uninstalled."); } return ((BundleImpl) bundle).getStartLevel(getInitialBundleStartLevel()); } /** * Sets the start level of the specified bundle; this method * implements functionality for the Start Level service. * @param bundle The bundle whose start level is to be modified. * @param startLevel The new start level of the specified bundle. * @throws java.lang.IllegalArgumentException If the specified * bundle is the system bundle or if the bundle has been * uninstalled. * @throws java.security.SecurityException If the caller does not * have AdminPermission. **/ void setBundleStartLevel(Bundle bundle, int startLevel) { // Acquire bundle lock. BundleImpl impl = (BundleImpl) bundle; try { acquireBundleLock(impl, Bundle.INSTALLED | Bundle.RESOLVED | Bundle.ACTIVE | Bundle.STARTING | Bundle.STOPPING); } catch (IllegalStateException ex) { fireFrameworkEvent(FrameworkEvent.ERROR, impl, ex); m_logger.log(impl, Logger.LOG_ERROR, "Error locking " + impl._getLocation(), ex); return; } Throwable rethrow = null; try { if (startLevel >= 1) { // NOTE: The start level was persistently recorded inside // the start level impl because the spec requires it to be // done synchronously. try { // Start the bundle if necessary. // We don't need to be concerned about the target // start level here, since this method is only executed // by the start level thread, so no start level change // can be occurring concurrently. if (((impl.getPersistentState() == Bundle.ACTIVE) || (impl.getPersistentState() == Bundle.STARTING)) && (startLevel <= m_activeStartLevel)) { // TODO: LAZY - Not sure if this is the best way... int options = Bundle.START_TRANSIENT; options = (impl.getPersistentState() == Bundle.STARTING) ? options | Bundle.START_ACTIVATION_POLICY : options; startBundle(impl, options); } // Stop the bundle if necessary. // We don't need to be concerned about the target // start level here, since this method is only executed // by the start level thread, so no start level change // can be occurring concurrently. else if (((impl.getState() == Bundle.ACTIVE) || (impl.getState() == Bundle.STARTING)) && (startLevel > m_activeStartLevel)) { stopBundle(impl, false); } } catch (Throwable th) { rethrow = th; m_logger.log( impl, Logger.LOG_ERROR, "Error starting/stopping bundle.", th); } } else { m_logger.log( impl, Logger.LOG_WARNING, "Bundle start level must be greater than zero."); } } finally { // Always release bundle lock. releaseBundleLock(impl); } if (rethrow != null) { fireFrameworkEvent(FrameworkEvent.ERROR, bundle, rethrow); } } /** * Returns whether a bundle is persistently started; this is an * method implementation for the Start Level service. * @param bundle The bundle to examine. * @return true if the bundle is marked as persistently * started, false otherwise. * @throws java.lang.IllegalArgumentException If the specified * bundle has been uninstalled. **/ boolean isBundlePersistentlyStarted(Bundle bundle) { if (bundle.getState() == Bundle.UNINSTALLED) { throw new IllegalArgumentException("Bundle is uninstalled."); } return (((BundleImpl) bundle).getPersistentState() == Bundle.ACTIVE) || (((BundleImpl) bundle).getPersistentState() == Bundle.STARTING); } /** * Returns whether the bundle is using its declared activation policy; * this is an method implementation for the Start Level service. * @param bundle The bundle to examine. * @return true if the bundle is using its declared activation * policy, false otherwise. * @throws java.lang.IllegalArgumentException If the specified * bundle has been uninstalled. **/ boolean isBundleActivationPolicyUsed(Bundle bundle) { if (bundle.getState() == Bundle.UNINSTALLED) { throw new IllegalArgumentException("Bundle is uninstalled."); } return ((BundleImpl) bundle).isDeclaredActivationPolicyUsed(); } // // Implementation of Bundle interface methods. // /** * Get bundle headers and resolve any localized strings from resource bundles. * @param bundle * @param locale * @return localized bundle headers dictionary. **/ Dictionary getBundleHeaders(BundleImpl bundle, String locale) { return new MapToDictionary(bundle.getCurrentLocalizedHeader(locale)); } /** * Implementation for Bundle.getResource(). **/ URL getBundleResource(BundleImpl bundle, String name) { if (bundle.getState() == Bundle.UNINSTALLED) { throw new IllegalStateException("The bundle is uninstalled."); } else if (Util.isFragment(bundle.adapt(BundleRevision.class))) { return null; } try { resolveBundleRevision(bundle.adapt(BundleRevision.class)); } catch (Exception ex) { // Ignore. } // If the bundle revision isn't resolved, then just search // locally, otherwise delegate. if (bundle.adapt(BundleRevision.class).getWiring() == null) { return ((BundleRevisionImpl) bundle.adapt(BundleRevision.class)) .getResourceLocal(name); } else { return ((BundleWiringImpl) bundle.adapt(BundleRevision.class).getWiring()) .getResourceByDelegation(name); } } /** * Implementation for Bundle.getResources(). **/ Enumeration getBundleResources(BundleImpl bundle, String name) { if (bundle.getState() == Bundle.UNINSTALLED) { throw new IllegalStateException("The bundle is uninstalled."); } else if (Util.isFragment(bundle.adapt(BundleRevision.class))) { return null; } try { resolveBundleRevision(bundle.adapt(BundleRevision.class)); } catch (Exception ex) { // Ignore. } if (bundle.adapt(BundleRevision.class).getWiring() == null) { return ((BundleRevisionImpl) bundle.adapt(BundleRevision.class)) .getResourcesLocal(name); } else { return ((BundleWiringImpl) bundle.adapt(BundleRevision.class).getWiring()) .getResourcesByDelegation(name); } } /** * Implementation for Bundle.getEntry(). **/ URL getBundleEntry(BundleImpl bundle, String name) { if (bundle.getState() == Bundle.UNINSTALLED) { throw new IllegalStateException("The bundle is uninstalled."); } URL url = ((BundleRevisionImpl) bundle.adapt(BundleRevision.class)).getEntry(name); // Some JAR files do not contain directory entries, so if // the entry wasn't found and is a directory, scan the entries // to see if we should synthesize an entry for it. if ((url == null) && name.endsWith("/") && !name.equals("/")) { // Use the entry filter enumeration to search the bundle content // recursively for matching entries and return URLs to them. Enumeration enumeration = new EntryFilterEnumeration( bundle.adapt(BundleRevision.class), false, name, "*", true, true); // If the enumeration has elements, then that means we need // to synthesize the directory entry. if (enumeration.hasMoreElements()) { URL entryURL = (URL) enumeration.nextElement(); try { url = new URL(entryURL, ((name.charAt(0) == '/') ? name : "/" + name)); } catch (MalformedURLException ex) { url = null; } } } return url; } /** * Implementation for Bundle.getEntryPaths(). **/ Enumeration getBundleEntryPaths(BundleImpl bundle, String path) { if (bundle.getState() == Bundle.UNINSTALLED) { throw new IllegalStateException("The bundle is uninstalled."); } // Get the entry enumeration from the revision content and // create a wrapper enumeration to filter it. Enumeration enumeration = new EntryFilterEnumeration( bundle.adapt(BundleRevision.class), false, path, "*", false, false); // Return the enumeration if it has elements. return (!enumeration.hasMoreElements()) ? null : enumeration; } /** * Implementation for Bundle.findEntries(). **/ Enumeration findBundleEntries( BundleRevision revision, String path, String filePattern, boolean recurse) { // Try to resolve the bundle per the spec. List list = new ArrayList(1); list.add(revision.getBundle()); resolveBundles(list); // Get the entry enumeration from the revision content and // create a wrapper enumeration to filter it. Enumeration enumeration = new EntryFilterEnumeration(revision, true, path, filePattern, recurse, true); // Return the enumeration if it has elements. return (!enumeration.hasMoreElements()) ? null : enumeration; } ServiceReference[] getBundleRegisteredServices(BundleImpl bundle) { if (bundle.getState() == Bundle.UNINSTALLED) { throw new IllegalStateException("The bundle is uninstalled."); } // Filter list of registered service references. ServiceReference[] refs = m_registry.getRegisteredServices(bundle); return refs; } ServiceReference[] getBundleServicesInUse(Bundle bundle) { // Filter list of "in use" service references. ServiceReference[] refs = m_registry.getServicesInUse(bundle); return refs; } boolean bundleHasPermission(BundleImpl bundle, Object obj) { if (bundle.getState() == Bundle.UNINSTALLED) { throw new IllegalStateException("The bundle is uninstalled."); } if (System.getSecurityManager() != null) { try { return (obj instanceof java.security.Permission) ? impliesBundlePermission( (BundleProtectionDomain) bundle.getProtectionDomain(), (java.security.Permission) obj, true) : false; } catch (Exception ex) { m_logger.log( bundle, Logger.LOG_WARNING, "Exception while evaluating the permission.", ex); return false; } } return true; } /** * Implementation for Bundle.loadClass(). **/ Class loadBundleClass(BundleImpl bundle, String name) throws ClassNotFoundException { if (bundle.getState() == Bundle.UNINSTALLED) { throw new IllegalStateException("Bundle is uninstalled"); } else if (Util.isFragment(bundle.adapt(BundleRevision.class))) { throw new ClassNotFoundException("Fragments cannot load classes."); } else if (bundle.getState() == Bundle.INSTALLED) { try { resolveBundleRevision(bundle.adapt(BundleRevision.class)); } catch (BundleException ex) { // The spec says we must fire a framework error. fireFrameworkEvent(FrameworkEvent.ERROR, bundle, ex); // Then throw a class not found exception. throw new ClassNotFoundException(name, ex); } } // We do not call getClassLoader().loadClass() for arrays because // it does not correctly handle array types, which is necessary in // cases like deserialization using a wrapper class loader. if ((name != null) && (name.length() > 0) && (name.charAt(0) == '[')) { return Class.forName(name, false, ((BundleWiringImpl) bundle.adapt(BundleWiring.class)).getClassLoader()); } return ((BundleWiringImpl) bundle.adapt(BundleWiring.class)).getClassLoader().loadClass(name); } /** * Implementation for Bundle.start(). **/ void startBundle(BundleImpl bundle, int options) throws BundleException { // CONCURRENCY NOTE: // We will first acquire the bundle lock for the specific bundle // as long as the bundle is INSTALLED, RESOLVED, or ACTIVE. If this // bundle is not yet resolved, then it will be resolved too. In // that case, the global lock will be acquired to make sure no // bundles can be installed or uninstalled during the resolve. int eventType; // Acquire bundle lock. try { acquireBundleLock(bundle, Bundle.INSTALLED | Bundle.RESOLVED | Bundle.STARTING | Bundle.ACTIVE | Bundle.STOPPING); } catch (IllegalStateException ex) { if (bundle.getState() == Bundle.UNINSTALLED) { throw new IllegalStateException("Cannot start an uninstalled bundle."); } else { throw new BundleException( "Bundle " + bundle + " cannot be started, since it is either starting or stopping."); } } // Record whether the bundle is using its declared activation policy. boolean wasDeferred = bundle.isDeclaredActivationPolicyUsed() && (((BundleRevisionImpl) bundle.adapt(BundleRevision.class)) .getDeclaredActivationPolicy() == BundleRevisionImpl.LAZY_ACTIVATION); bundle.setDeclaredActivationPolicyUsed( (options & Bundle.START_ACTIVATION_POLICY) != 0); BundleException rethrow = null; try { // The spec doesn't say whether it is possible to start an extension // We just do nothing if (bundle.isExtension()) { return; } // As per the OSGi spec, fragment bundles can not be started and must // throw a BundleException when there is an attempt to start one. if (Util.isFragment(bundle.adapt(BundleRevision.class))) { throw new BundleException("Fragment bundles can not be started."); } // Set and save the bundle's persistent state to active // if we are supposed to record state change. if ((options & Bundle.START_TRANSIENT) == 0) { if ((options & Bundle.START_ACTIVATION_POLICY) != 0) { bundle.setPersistentStateStarting(); } else { bundle.setPersistentStateActive(); } } // Check to see if the bundle's start level is greater than the // the framework's active start level. int bundleLevel = bundle.getStartLevel(getInitialBundleStartLevel()); if (bundleLevel > m_targetStartLevel) { // Throw an exception for transient starts. if ((options & Bundle.START_TRANSIENT) != 0) { throw new BundleException( "Cannot start bundle " + bundle + " because its start level is " + bundleLevel + ", which is greater than the framework's start level of " + m_targetStartLevel + "."); } // Ignore persistent starts. return; } // Check to see if there is a start level change in progress and if so // add this bundle to the bundles being processed by the start level // thread and return. if (!Thread.currentThread().getName().equals(FrameworkStartLevelImpl.THREAD_NAME)) { synchronized (m_startLevelBundles) { if (!m_startLevelBundles.isEmpty()) { // Only add the bundle to the start level bundles // being process if it is not already there. boolean found = false; for (StartLevelTuple tuple : m_startLevelBundles) { if (tuple.m_bundle == bundle) { found = true; } } if (!found) { // TODO: STARTLEVEL - Technically, if a bundle is installed and started during a // start level operation, then it will end up being queued for the start level // thread even if its start level is met, when it potentially could have been // started immediately. m_startLevelBundles.add(new StartLevelTuple(bundle, bundleLevel)); } return; } } } switch (bundle.getState()) { case Bundle.UNINSTALLED: throw new IllegalStateException("Cannot start an uninstalled bundle."); case Bundle.STARTING: if (!wasDeferred) { throw new BundleException( "Bundle " + bundle + " cannot be started, since it is starting."); } break; case Bundle.STOPPING: throw new BundleException( "Bundle " + bundle + " cannot be started, since it is stopping."); case Bundle.ACTIVE: return; case Bundle.INSTALLED: resolveBundleRevision(bundle.adapt(BundleRevision.class)); // No break. case Bundle.RESOLVED: // Set the bundle's context. bundle.setBundleContext(new BundleContextImpl(m_logger, this, bundle)); // At this point, no matter if the bundle's activation policy is // eager or deferred, we need to set the bundle's state to STARTING. // We don't fire a BundleEvent here for this state change, since // STARTING events are only fired if we are invoking the activator, // which we may not do if activation is deferred. setBundleStateAndNotify(bundle, Bundle.STARTING); break; } // If the bundle's activation policy is eager or activation has already // been triggered, then activate the bundle immediately. if (!bundle.isDeclaredActivationPolicyUsed() || (((BundleRevisionImpl) bundle.adapt(BundleRevision.class)) .getDeclaredActivationPolicy() != BundleRevisionImpl.LAZY_ACTIVATION) || ((BundleClassLoader) bundle.adapt(BundleWiring.class).getClassLoader()) .isActivationTriggered()) { // Record the event type for the final event and activate. eventType = BundleEvent.STARTED; // Note that the STARTING event is thrown in the activateBundle() method. try { activateBundle(bundle, false); } catch (BundleException ex) { rethrow = ex; } } // Otherwise, defer bundle activation. else { // Record the event type for the final event. eventType = BundleEvent.LAZY_ACTIVATION; } // We still need to fire the STARTED event, but we will do // it later so we can release the bundle lock. } finally { // Release bundle lock. releaseBundleLock(bundle); } // If there was no exception, then we should fire the STARTED // or LAZY_ACTIVATION event here without holding the lock. Otherwise, // fire STOPPED and rethrow exception. if (rethrow == null) { fireBundleEvent(eventType, bundle); } else { fireBundleEvent(BundleEvent.STOPPED, bundle); throw rethrow; } } void activateBundle(BundleImpl bundle, boolean fireEvent) throws BundleException { // CONCURRENCY NOTE: // We will first acquire the bundle lock for the specific bundle // as long as the bundle is STARTING or ACTIVE, shich is necessary // because we may change the bundle state. // Acquire bundle lock. try { acquireBundleLock(bundle, Bundle.STARTING | Bundle.ACTIVE); } catch (IllegalStateException ex) { throw new IllegalStateException( "Activation only occurs for bundles in STARTING state."); } try { // If the bundle is already active or its start level is not met, // simply return. Generally, the bundle start level should always // be less than or equal to the active start level since the bundle // must be in the STARTING state to activate it. One potential corner // case is if the bundle is being lazily activated at the same time // there is a start level change going on to lower the start level. // In that case, we test here and avoid activating the bundle since // it will be stopped by the start level thread. if ((bundle.getState() == Bundle.ACTIVE) || (bundle.getStartLevel(getInitialBundleStartLevel()) > m_targetStartLevel)) { return; } // Fire STARTING event to signify call to bundle activator. fireBundleEvent(BundleEvent.STARTING, bundle); try { // Set the bundle's activator. bundle.setActivator(createBundleActivator(bundle)); // Activate the bundle if it has an activator. if (bundle.getActivator() != null) { m_secureAction.startActivator( bundle.getActivator(), bundle._getBundleContext()); } setBundleStateAndNotify(bundle, Bundle.ACTIVE); // We still need to fire the STARTED event, but we will do // it later so we can release the bundle lock. } catch (Throwable th) { // Spec says we must fire STOPPING event. fireBundleEvent(BundleEvent.STOPPING, bundle); // If there was an error starting the bundle, // then reset its state to RESOLVED. setBundleStateAndNotify(bundle, Bundle.RESOLVED); // Clean up the bundle activator bundle.setActivator(null); // Clean up the bundle context. // We invalidate this first to make sure it cannot be used // after stopping the activator. BundleContextImpl bci = (BundleContextImpl) bundle._getBundleContext(); bci.invalidate(); bundle.setBundleContext(null); // Unregister any services offered by this bundle. m_registry.unregisterServices(bundle); // Release any services being used by this bundle. m_registry.ungetServices(bundle); // Remove any listeners registered by this bundle. m_dispatcher.removeListeners(bci); // The spec says to expect BundleException or // SecurityException, so rethrow these exceptions. if (th instanceof BundleException) { throw (BundleException) th; } else if ((System.getSecurityManager() != null) && (th instanceof java.security.PrivilegedActionException)) { th = ((java.security.PrivilegedActionException) th).getException(); } // Rethrow all other exceptions as a BundleException. throw new BundleException( "Activator start error in bundle " + bundle + ".", BundleException.ACTIVATOR_ERROR, th); } } finally { // Release bundle lock. releaseBundleLock(bundle); } // If there was no exception, then we should fire the STARTED // event here without holding the lock if specified. // TODO: LAZY - It would be nice to figure out how to do this without // duplicating code; this method is called from two different // places -- one fires the event itself the other one needs it. if (fireEvent) { fireBundleEvent(BundleEvent.STARTED, bundle); } } void updateBundle(BundleImpl bundle, InputStream is) throws BundleException { // Acquire bundle lock. try { acquireBundleLock(bundle, Bundle.INSTALLED | Bundle.RESOLVED | Bundle.ACTIVE); } catch (IllegalStateException ex) { if (bundle.getState() == Bundle.UNINSTALLED) { throw new IllegalStateException("Cannot update an uninstalled bundle."); } else { throw new BundleException( "Bundle " + bundle + " cannot be update, since it is either starting or stopping."); } } // We must release the lock and close the input stream, so do both // in a finally block. try { // Variable to indicate whether bundle is active or not. Throwable rethrow = null; final int oldState = bundle.getState(); // First get the update-URL from our header. String updateLocation = (String) ((BundleRevisionImpl) bundle.adapt(BundleRevision.class)) .getHeaders().get(Constants.BUNDLE_UPDATELOCATION); // If no update location specified, use original location. if (updateLocation == null) { updateLocation = bundle._getLocation(); } // Stop the bundle if it is active, but do not change its // persistent state. if (oldState == Bundle.ACTIVE) { stopBundle(bundle, false); } try { // Revising the bundle creates a new revision, which modifies // the global state, so we need to acquire the global lock // before revising. boolean locked = acquireGlobalLock(); if (!locked) { throw new BundleException( "Cannot acquire global lock to update the bundle."); } try { // Try to revise. boolean wasExtension = bundle.isExtension(); bundle.revise(updateLocation, is); // Verify bundle revision. try { Object sm = System.getSecurityManager(); if (sm != null) { ((SecurityManager) sm).checkPermission( new AdminPermission(bundle, AdminPermission.LIFECYCLE)); } // If this is an update from a normal to an extension bundle // then attach the extension if (!wasExtension && bundle.isExtension()) { m_extensionManager.addExtensionBundle(this, bundle); // TODO: REFACTOR - Perhaps we could move this into extension manager. m_resolver.addRevision(m_extensionManager.getRevision()); // TODO: REFACTOR - Not clear why this is here. We should look at all of these steps more closely. setBundleStateAndNotify(bundle, Bundle.RESOLVED); } else if (wasExtension) { setBundleStateAndNotify(bundle, Bundle.INSTALLED); } } catch (Throwable ex) { try { bundle.rollbackRevise(); } catch (Exception busted) { m_logger.log( bundle, Logger.LOG_ERROR, "Unable to rollback.", busted); } throw ex; } } finally { // Always release the global lock. releaseGlobalLock(); } } catch (Throwable ex) { m_logger.log( bundle, Logger.LOG_ERROR, "Unable to update the bundle.", ex); rethrow = ex; } // Set new state, mark as needing a refresh, and fire updated event // if successful. if (rethrow == null) { bundle.setLastModified(System.currentTimeMillis()); if (!bundle.isExtension()) { setBundleStateAndNotify(bundle, Bundle.INSTALLED); } else { m_extensionManager.startExtensionBundle(this, bundle); } fireBundleEvent(BundleEvent.UNRESOLVED, bundle); fireBundleEvent(BundleEvent.UPDATED, bundle); // Acquire global lock to check if we should auto-refresh. boolean locked = acquireGlobalLock(); // If we did not get the global lock, then do not try to // auto-refresh. if (locked) { try { if (!m_dependencies.hasDependents(bundle) && !bundle.isExtension()) { try { List list = new ArrayList(1); list.add(bundle); refreshPackages(list, null); } catch (Exception ex) { m_logger.log(bundle, Logger.LOG_ERROR, "Unable to immediately purge the bundle revisions.", ex); } } } finally { // Always release the global lock. releaseGlobalLock(); } } } // If the old state was active, but the new revision is a fragment, // then mark the persistent state to inactive. if ((oldState == Bundle.ACTIVE) && Util.isFragment(bundle.adapt(BundleRevision.class))) { bundle.setPersistentStateInactive(); m_logger.log(bundle, Logger.LOG_WARNING, "Previously active bundle was updated to a fragment, resetting state to inactive: " + bundle); } // Otherwise, restart the bundle if it was previously active, // but do not change its persistent state. else if (oldState == Bundle.ACTIVE) { startBundle(bundle, Bundle.START_TRANSIENT); } // If update failed, rethrow exception. if (rethrow != null) { if (rethrow instanceof AccessControlException) { throw (AccessControlException) rethrow; } else if (rethrow instanceof BundleException) { throw (BundleException) rethrow; } else { throw new BundleException( "Update of bundle " + bundle + " failed.", rethrow); } } } finally { // Close the input stream. try { if (is != null) is.close(); } catch (Exception ex) { m_logger.log(bundle, Logger.LOG_ERROR, "Unable to close input stream.", ex); } // Release bundle lock. releaseBundleLock(bundle); } } void stopBundle(BundleImpl bundle, boolean record) throws BundleException { // Acquire bundle lock. try { acquireBundleLock(bundle, Bundle.INSTALLED | Bundle.RESOLVED | Bundle.STARTING | Bundle.ACTIVE | Bundle.STOPPING); } catch (IllegalStateException ex) { if (bundle.getState() == Bundle.UNINSTALLED) { throw new IllegalStateException("Cannot stop an uninstalled bundle."); } else { throw new BundleException( "Bundle " + bundle + " cannot be stopped since it is already stopping."); } } try { Throwable rethrow = null; // Set the bundle's persistent state to inactive if necessary. if (record) { bundle.setPersistentStateInactive(); } // If the bundle is not persistently started, then we // need to reset the activation policy flag, since it // does not persist across persistent stops or transient // stops. if (!isBundlePersistentlyStarted(bundle)) { bundle.setDeclaredActivationPolicyUsed(false); } // As per the OSGi spec, fragment bundles can not be stopped and must // throw a BundleException when there is an attempt to stop one. if (Util.isFragment(bundle.adapt(BundleRevision.class))) { throw new BundleException("Fragment bundles can not be stopped: " + bundle); } boolean wasActive = false; switch (bundle.getState()) { case Bundle.UNINSTALLED: throw new IllegalStateException("Cannot stop an uninstalled bundle."); case Bundle.STARTING: if (bundle.isDeclaredActivationPolicyUsed() && ((BundleRevisionImpl) bundle.adapt(BundleRevision.class)) .getDeclaredActivationPolicy() != BundleRevisionImpl.LAZY_ACTIVATION) { throw new BundleException( "Stopping a starting or stopping bundle is currently not supported."); } break; case Bundle.STOPPING: throw new BundleException( "Stopping a starting or stopping bundle is currently not supported."); case Bundle.INSTALLED: case Bundle.RESOLVED: return; case Bundle.ACTIVE: wasActive = true; break; } // At this point, no matter if the bundle's activation policy is // eager or deferred, we need to set the bundle's state to STOPPING // and fire the STOPPING event. setBundleStateAndNotify(bundle, Bundle.STOPPING); fireBundleEvent(BundleEvent.STOPPING, bundle); // If the bundle was active, then invoke the activator stop() method // or if we are stopping the system bundle. if ((wasActive) || (bundle.getBundleId() == 0)) { try { if (bundle.getActivator() != null) { m_secureAction.stopActivator(bundle.getActivator(), bundle._getBundleContext()); } } catch (Throwable th) { m_logger.log(bundle, Logger.LOG_ERROR, "Error stopping bundle.", th); rethrow = th; } } // Do not clean up after the system bundle since it will // clean up after itself. if (bundle.getBundleId() != 0) { // Clean up the bundle activator. bundle.setActivator(null); // Clean up the bundle context. // We invalidate this first to make sure it cannot be used // after stopping the activator. BundleContextImpl bci = (BundleContextImpl) bundle._getBundleContext(); bci.invalidate(); bundle.setBundleContext(null); // Unregister any services offered by this bundle. m_registry.unregisterServices(bundle); // Release any services being used by this bundle. m_registry.ungetServices(bundle); // The spec says that we must remove all event // listeners for a bundle when it is stopped. m_dispatcher.removeListeners(bci); setBundleStateAndNotify(bundle, Bundle.RESOLVED); // We still need to fire the STOPPED event, but we will do // it later so we can release the bundle lock. } // Throw activator error if there was one. if (rethrow != null) { // The spec says to expect BundleException or // SecurityException, so rethrow these exceptions. if (rethrow instanceof BundleException) { throw (BundleException) rethrow; } else if ((System.getSecurityManager() != null) && (rethrow instanceof java.security.PrivilegedActionException)) { rethrow = ((java.security.PrivilegedActionException) rethrow).getException(); } // Rethrow all other exceptions as a BundleException. throw new BundleException( "Activator stop error in bundle " + bundle + ".", rethrow); } } finally { // Always release bundle lock. releaseBundleLock(bundle); } // If there was no exception, then we should fire the STOPPED event // here without holding the lock. fireBundleEvent(BundleEvent.STOPPED, bundle); } void uninstallBundle(BundleImpl bundle) throws BundleException { // Acquire bundle lock. try { acquireBundleLock(bundle, Bundle.INSTALLED | Bundle.RESOLVED | Bundle.STARTING | Bundle.ACTIVE | Bundle.STOPPING); } catch (IllegalStateException ex) { if (bundle.getState() == Bundle.UNINSTALLED) { throw new IllegalStateException("Cannot uninstall an uninstalled bundle."); } else { throw new BundleException( "Bundle " + bundle + " cannot be uninstalled since it is stopping."); } } try { // The spec says that uninstall should always succeed, so // catch an exception here if stop() doesn't succeed and // rethrow it at the end. if (!bundle.isExtension() && (bundle.getState() == Bundle.ACTIVE)) { try { stopBundle(bundle, true); } catch (BundleException ex) { fireFrameworkEvent(FrameworkEvent.ERROR, bundle, ex); } } // Remove the bundle from the installed map. BundleImpl target = null; // Acquire global lock. boolean locked = acquireGlobalLock(); if (!locked) { // If the calling thread holds bundle locks, then we might not // be able to get the global lock. throw new IllegalStateException( "Unable to acquire global lock to remove bundle."); } try { // Use a copy-on-write approach to remove the bundle // from the installed maps. Map[] maps = new Map[] { new HashMap(m_installedBundles[LOCATION_MAP_IDX]), new TreeMap(m_installedBundles[IDENTIFIER_MAP_IDX]) }; target = (BundleImpl) maps[LOCATION_MAP_IDX].remove(bundle._getLocation()); maps[IDENTIFIER_MAP_IDX].remove(new Long(target.getBundleId())); m_installedBundles = maps; // Put the uninstalled bundle into the uninstalled // list for subsequent refreshing. if (target != null) { // Set the bundle's persistent state to uninstalled. bundle.setPersistentStateUninstalled(); // Put bundle in uninstalled bundle array. rememberUninstalledBundle(bundle); } } finally { releaseGlobalLock(); } if (target == null) { m_logger.log(bundle, Logger.LOG_ERROR, "Unable to remove bundle from installed map!"); } setBundleStateAndNotify(bundle, Bundle.INSTALLED); // Unfortunately, fire UNRESOLVED event while holding the lock, // since we still need to change the bundle state. fireBundleEvent(BundleEvent.UNRESOLVED, bundle); // Set state to uninstalled. setBundleStateAndNotify(bundle, Bundle.UNINSTALLED); bundle.setLastModified(System.currentTimeMillis()); } finally { // Always release bundle lock. releaseBundleLock(bundle); } // Fire UNINSTALLED event without holding the lock. fireBundleEvent(BundleEvent.UNINSTALLED, bundle); // Acquire global lock to check if we should auto-refresh. boolean locked = acquireGlobalLock(); if (locked) { try { // If the bundle is not used by anyone, then garbage // collect it now. if (!m_dependencies.hasDependents(bundle)) { try { List list = Collections.singletonList((Bundle) bundle); refreshPackages(list, null); } catch (Exception ex) { m_logger.log(bundle, Logger.LOG_ERROR, "Unable to immediately garbage collect the bundle.", ex); } } } finally { // Always release the global lock. releaseGlobalLock(); } } } // // Implementation of BundleContext interface methods. // /** * Implementation for BundleContext.getProperty(). Returns * environment property associated with the framework. * * @param key The name of the property to retrieve. * @return The value of the specified property or null. **/ String getProperty(String key) { // First, check the config properties. String val = (String) m_configMap.get(key); // If not found, then try the system properties. return (val == null) ? System.getProperty(key) : val; } private Bundle reloadBundle(BundleArchive ba) throws BundleException { BundleImpl bundle = null; // Try to purge old revisions before installing; // this is done just in case a "refresh" didn't // occur last session...this would only be due to // an error or system crash. try { if (ba.isRemovalPending()) { ba.purge(); } } catch (Exception ex) { m_logger.log( Logger.LOG_ERROR, "Could not purge bundle.", ex); } try { // Acquire the global lock to create the bundle, // since this impacts the global state. boolean locked = acquireGlobalLock(); if (!locked) { throw new BundleException( "Unable to acquire the global lock to install the bundle."); } try { bundle = new BundleImpl(this, ba); // Extensions are handled as a special case. if (bundle.isExtension()) { m_extensionManager.addExtensionBundle(this, bundle); m_resolver.addRevision(m_extensionManager.getRevision()); } // Use a copy-on-write approach to add the bundle // to the installed maps. Map[] maps = new Map[] { new HashMap(m_installedBundles[LOCATION_MAP_IDX]), new TreeMap(m_installedBundles[IDENTIFIER_MAP_IDX]) }; maps[LOCATION_MAP_IDX].put(bundle._getLocation(), bundle); maps[IDENTIFIER_MAP_IDX].put(new Long(bundle.getBundleId()), bundle); m_installedBundles = maps; } finally { // Always release the global lock. releaseGlobalLock(); } } catch (Throwable ex) { if (ex instanceof BundleException) { throw (BundleException) ex; } else if (ex instanceof AccessControlException) { throw (AccessControlException) ex; } else { throw new BundleException("Could not create bundle object.", ex); } } if (bundle.isExtension()) { m_extensionManager.startExtensionBundle(this, bundle); } return bundle; } Bundle installBundle( Bundle origin, String location, InputStream is) throws BundleException { BundleArchive ba = null; BundleImpl existing, bundle = null; // Acquire an install lock. acquireInstallLock(location); try { // Check to see if the framework is still running; if ((getState() == Bundle.STOPPING) || (getState() == Bundle.UNINSTALLED)) { throw new BundleException("The framework has been shutdown."); } // If bundle location is already installed, then // return it as required by the OSGi specification. existing = (BundleImpl) getBundle(location); if (existing == null) { // First generate an identifier for it. long id = getNextId(); try { // Add the bundle to the cache. ba = m_cache.create(id, getInitialBundleStartLevel(), location, is); } catch (Exception ex) { throw new BundleException( "Unable to cache bundle: " + location, ex); } finally { try { if (is != null) is.close(); } catch (IOException ex) { m_logger.log( Logger.LOG_ERROR, "Unable to close input stream.", ex); } } try { // Acquire the global lock to create the bundle, // since this impacts the global state. boolean locked = acquireGlobalLock(); if (!locked) { throw new BundleException( "Unable to acquire the global lock to install the bundle."); } try { bundle = new BundleImpl(this, ba); } finally { // Always release the global lock. releaseGlobalLock(); } if (!bundle.isExtension()) { Object sm = System.getSecurityManager(); if (sm != null) { ((SecurityManager) sm).checkPermission( new AdminPermission(bundle, AdminPermission.LIFECYCLE)); } } else { m_extensionManager.addExtensionBundle(this, bundle); m_resolver.addRevision(m_extensionManager.getRevision()); } } catch (Throwable ex) { // Remove bundle from the cache. try { if (bundle != null) { bundle.closeAndDelete(); } else if (ba != null) { ba.closeAndDelete(); } } catch (Exception ex1) { m_logger.log(bundle, Logger.LOG_ERROR, "Could not remove from cache.", ex1); } if (ex instanceof BundleException) { throw (BundleException) ex; } else if (ex instanceof AccessControlException) { throw (AccessControlException) ex; } else { throw new BundleException("Could not create bundle object.", ex); } } // Acquire global lock. boolean locked = acquireGlobalLock(); if (!locked) { // If the calling thread holds bundle locks, then we might not // be able to get the global lock. throw new IllegalStateException( "Unable to acquire global lock to add bundle."); } try { // Use a copy-on-write approach to add the bundle // to the installed maps. Map[] maps = new Map[] { new HashMap(m_installedBundles[LOCATION_MAP_IDX]), new TreeMap(m_installedBundles[IDENTIFIER_MAP_IDX]) }; maps[LOCATION_MAP_IDX].put(location, bundle); maps[IDENTIFIER_MAP_IDX].put(new Long(bundle.getBundleId()), bundle); m_installedBundles = maps; } finally { releaseGlobalLock(); } if (bundle.isExtension()) { m_extensionManager.startExtensionBundle(this, bundle); } } } finally { // Always release install lock. releaseInstallLock(location); // Always try to close the input stream. try { if (is != null) is.close(); } catch (IOException ex) { m_logger.log(bundle, Logger.LOG_ERROR, "Unable to close input stream.", ex); // Not much else we can do. } } if (existing != null) { Set> hooks = getHooks(org.osgi.framework.hooks.bundle.FindHook.class); if (!hooks.isEmpty()) { Collection bundles = new ArrayList(1); bundles.add(existing); bundles = new ShrinkableCollection(bundles); for (ServiceReference hook : hooks) { org.osgi.framework.hooks.bundle.FindHook fh = getService(this, hook); if (fh != null) { try { m_secureAction.invokeBundleFindHook( fh, origin.getBundleContext(), bundles); } catch (Throwable th) { m_logger.doLog( hook.getBundle(), hook, Logger.LOG_WARNING, "Problem invoking bundle hook.", th); } } } if (bundles.isEmpty()) { throw new BundleException( "Bundle installation rejected by hook.", BundleException.REJECTED_BY_HOOK); } } } else { // Fire bundle event. fireBundleEvent(BundleEvent.INSTALLED, bundle, origin); } // Return new bundle. return (existing != null) ? existing : bundle; } /** * Retrieves a bundle from its location. * * @param location The location of the bundle to retrieve. * @return The bundle associated with the location or null if there * is no bundle associated with the location. **/ Bundle getBundle(String location) { return (Bundle) m_installedBundles[LOCATION_MAP_IDX].get(location); } /** * Implementation for BundleContext.getBundle(). Retrieves a * bundle from its identifier. * * @param id The identifier of the bundle to retrieve. * @return The bundle associated with the identifier or null if there * is no bundle associated with the identifier. **/ Bundle getBundle(BundleContext bc, long id) { BundleImpl bundle = (BundleImpl) m_installedBundles[IDENTIFIER_MAP_IDX].get(new Long(id)); if (bundle != null) { List uninstalledBundles = m_uninstalledBundles; for (int i = 0; (bundle == null) && (uninstalledBundles != null) && (i < uninstalledBundles.size()); i++) { if (uninstalledBundles.get(i).getBundleId() == id) { bundle = uninstalledBundles.get(i); } } } Set> hooks = getHooks(org.osgi.framework.hooks.bundle.FindHook.class); if (!hooks.isEmpty() && (bundle != null)) { Collection bundles = new ArrayList(1); bundles.add(bundle); bundles = new ShrinkableCollection(bundles); for (ServiceReference hook : hooks) { org.osgi.framework.hooks.bundle.FindHook fh = getService(this, hook); if (fh != null) { try { m_secureAction.invokeBundleFindHook(fh, bc, bundles); } catch (Throwable th) { m_logger.doLog( hook.getBundle(), hook, Logger.LOG_WARNING, "Problem invoking bundle hook.", th); } } } bundle = (bundles.isEmpty()) ? null : bundle; } return bundle; } /** * Retrieves a bundle by its identifier and avoids bundles hooks. * * @return The bundle associated with the identifier or null. **/ Bundle getBundle(long id) { BundleImpl bundle = (BundleImpl) m_installedBundles[IDENTIFIER_MAP_IDX].get(new Long(id)); if (bundle != null) { return bundle; } List uninstalledBundles = m_uninstalledBundles; for (int i = 0; (uninstalledBundles != null) && (i < uninstalledBundles.size()); i++) { if (uninstalledBundles.get(i).getBundleId() == id) { return uninstalledBundles.get(i); } } return null; } /** * Implementation for BundleContext.getBundles(). Retrieves * all installed bundles. * * @return An array containing all installed bundles or null if * there are no installed bundles. **/ Bundle[] getBundles(BundleContext bc) { Collection bundles = m_installedBundles[IDENTIFIER_MAP_IDX].values(); Set> hooks = getHooks(org.osgi.framework.hooks.bundle.FindHook.class); if (!hooks.isEmpty()) { bundles = new ShrinkableCollection(new ArrayList(bundles)); for (ServiceReference hook : hooks) { org.osgi.framework.hooks.bundle.FindHook fh = getService(this, hook); if (fh != null) { try { m_secureAction.invokeBundleFindHook(fh, bc, bundles); } catch (Throwable th) { m_logger.doLog( hook.getBundle(), hook, Logger.LOG_WARNING, "Problem invoking bundle hook.", th); } } } } return (Bundle[]) bundles.toArray(new Bundle[bundles.size()]); } /** * Retrieves all installed bundles and avoids bundles hooks. * * @return An array containing all installed bundles or null if * there are no installed bundles. **/ Bundle[] getBundles() { Collection bundles = m_installedBundles[IDENTIFIER_MAP_IDX].values(); return (Bundle[]) bundles.toArray(new Bundle[bundles.size()]); } void addBundleListener(BundleImpl bundle, BundleListener l) { m_dispatcher.addListener( bundle._getBundleContext(), BundleListener.class, l, null); } void removeBundleListener(BundleImpl bundle, BundleListener l) { m_dispatcher.removeListener( bundle._getBundleContext(), BundleListener.class, l); } /** * Implementation for BundleContext.addServiceListener(). * Adds service listener to the listener list so that is * can listen for ServiceEvents. * * @param bundle The bundle that registered the listener. * @param l The service listener to add to the listener list. * @param f The filter for the listener; may be null. **/ void addServiceListener(BundleImpl bundle, ServiceListener l, String f) throws InvalidSyntaxException { Filter oldFilter; Filter newFilter = (f == null) ? null : FrameworkUtil.createFilter(f); oldFilter = m_dispatcher.addListener( bundle._getBundleContext(), ServiceListener.class, l, newFilter); // Invoke ListenerHook.removed() if filter updated. Set> listenerHooks = m_registry.getHooks(org.osgi.framework.hooks.service.ListenerHook.class); if (oldFilter != null) { final Collection removed = Collections.singleton( new ListenerInfo(bundle, bundle._getBundleContext(), ServiceListener.class, l, oldFilter, null, true)); for (ServiceReference sr : listenerHooks) { org.osgi.framework.hooks.service.ListenerHook lh = getService(this, sr); if (lh != null) { try { m_secureAction.invokeServiceListenerHookRemoved(lh, removed); } catch (Throwable th) { m_logger.log(sr, Logger.LOG_WARNING, "Problem invoking service registry hook", th); } finally { m_registry.ungetService(this, sr); } } } } // Invoke the ListenerHook.added() on all hooks. final Collection added = Collections.singleton( new ListenerInfo(bundle, bundle._getBundleContext(), ServiceListener.class, l, newFilter, null, false)); for (ServiceReference sr : listenerHooks) { org.osgi.framework.hooks.service.ListenerHook lh = getService(this, sr); if (lh != null) { try { m_secureAction.invokeServiceListenerHookAdded(lh, added); } catch (Throwable th) { m_logger.log(sr, Logger.LOG_WARNING, "Problem invoking service registry hook", th); } finally { m_registry.ungetService(this, sr); } } } } /** * Implementation for BundleContext.removeServiceListener(). * Removes service listeners from the listener list. * * @param bundle The context bundle of the listener * @param l The service listener to remove from the listener list. **/ void removeServiceListener(BundleImpl bundle, ServiceListener l) { org.osgi.framework.hooks.service.ListenerHook.ListenerInfo listener = m_dispatcher.removeListener( bundle._getBundleContext(), ServiceListener.class, l); if (listener != null) { // Invoke the ListenerHook.removed() on all hooks. Set> listenerHooks = m_registry.getHooks(org.osgi.framework.hooks.service.ListenerHook.class); Collection removed = Collections.singleton(listener); for (ServiceReference sr : listenerHooks) { org.osgi.framework.hooks.service.ListenerHook lh = getService(this, sr); if (lh != null) { try { m_secureAction.invokeServiceListenerHookRemoved(lh, removed); } catch (Throwable th) { m_logger.log(sr, Logger.LOG_WARNING, "Problem invoking service registry hook", th); } finally { m_registry.ungetService(this, sr); } } } } } void addFrameworkListener(BundleImpl bundle, FrameworkListener l) { m_dispatcher.addListener( bundle._getBundleContext(), FrameworkListener.class, l, null); } void removeFrameworkListener(BundleImpl bundle, FrameworkListener l) { m_dispatcher.removeListener( bundle._getBundleContext(), FrameworkListener.class, l); } /** * Implementation for BundleContext.registerService(). Registers * a service for the specified bundle bundle. * * @param classNames A string array containing the names of the classes * under which the new service is available. * @param svcObj The service object or ServiceFactory. * @param dict A dictionary of properties that further describe the * service or null. * @return A ServiceRegistration object or null. **/ ServiceRegistration registerService( BundleImpl bundle, String[] classNames, Object svcObj, Dictionary dict) { if (classNames == null) { throw new NullPointerException("Service class names cannot be null."); } else if (svcObj == null) { throw new IllegalArgumentException("Service object cannot be null."); } // Acquire bundle lock. try { acquireBundleLock(bundle, Bundle.STARTING | Bundle.ACTIVE | Bundle.STOPPING); } catch (IllegalStateException ex) { throw new IllegalStateException( "Can only register services while bundle is active or activating."); } ServiceRegistration reg = null; try { // Check to make sure that the service object is // an instance of all service classes; ignore if // service object is a service factory. if (!(svcObj instanceof ServiceFactory)) { for (int i = 0; i < classNames.length; i++) { Class clazz = Util.loadClassUsingClass(svcObj.getClass(), classNames[i], m_secureAction); if (clazz == null) { throw new IllegalArgumentException( "Cannot cast service: " + classNames[i]); } else if (!clazz.isAssignableFrom(svcObj.getClass())) { throw new IllegalArgumentException( "Service object is not an instance of \"" + classNames[i] + "\"."); } } } reg = m_registry.registerService(bundle, classNames, svcObj, dict); } finally { // Always release bundle lock. releaseBundleLock(bundle); } // Check to see if this a listener hook; if so, then we need // to invoke the callback with all existing service listeners. if (ServiceRegistry.isHook( classNames, org.osgi.framework.hooks.service.ListenerHook.class, svcObj)) { org.osgi.framework.hooks.service.ListenerHook lh = (org.osgi.framework.hooks.service.ListenerHook) getService(this, reg.getReference()); if (lh != null) { try { m_secureAction.invokeServiceListenerHookAdded( lh, m_dispatcher.getAllServiceListeners()); } catch (Throwable th) { m_logger.log(reg.getReference(), Logger.LOG_WARNING, "Problem invoking service registry hook", th); } finally { m_registry.ungetService(this, reg.getReference()); } } } // Fire service event. fireServiceEvent(new ServiceEvent(ServiceEvent.REGISTERED, reg.getReference()), null); return reg; } /** * Retrieves an array of {@link ServiceReference} objects based on calling bundle, * service class name, and filter expression. Optionally checks for isAssignable to * make sure that the service can be cast to the * @param bundle Calling Bundle * @param className Service Classname or null for all * @param expr Filter Criteria or null * @return Array of ServiceReference objects that meet the criteria * @throws InvalidSyntaxException */ ServiceReference[] getServiceReferences( final BundleImpl bundle, final String className, final String expr, final boolean checkAssignable) throws InvalidSyntaxException { // Define filter if expression is not null. SimpleFilter filter = null; if (expr != null) { try { filter = SimpleFilter.parse(expr); } catch (Exception ex) { throw new InvalidSyntaxException(ex.getMessage(), expr); } } // Ask the service registry for all matching service references. final List refList = m_registry.getServiceReferences(className, filter); // Filter on assignable references if (checkAssignable) { for (int refIdx = 0; (refList != null) && (refIdx < refList.size()); refIdx++) { // Get the current service reference. ServiceReference ref = (ServiceReference) refList.get(refIdx); // Now check for castability. if (!Util.isServiceAssignable(bundle, ref)) { refList.remove(refIdx); refIdx--; } } } // activate findhooks Set> findHooks = m_registry.getHooks(org.osgi.framework.hooks.service.FindHook.class); for (ServiceReference sr : findHooks) { org.osgi.framework.hooks.service.FindHook fh = getService(this, sr); if (fh != null) { try { m_secureAction.invokeServiceFindHook( fh, bundle._getBundleContext(), className, expr, !checkAssignable, new ShrinkableCollection(refList)); } catch (Throwable th) { m_logger.log(sr, Logger.LOG_WARNING, "Problem invoking service registry hook", th); } finally { m_registry.ungetService(this, sr); } } } if (refList.size() > 0) { return (ServiceReference[]) refList.toArray(new ServiceReference[refList.size()]); } return null; } /** * Retrieves Array of {@link ServiceReference} objects based on calling bundle, service class name, * optional filter expression, and optionally filters further on the version. * If running under a {@link SecurityManager}, checks that the calling bundle has permissions to * see the service references and removes references that aren't. * @param bundle Calling Bundle * @param className Service Classname or null for all * @param expr Filter Criteria or null * @param checkAssignable true to check for isAssignable, false to return all versions * @return Array of ServiceReference objects that meet the criteria * @throws InvalidSyntaxException */ ServiceReference[] getAllowedServiceReferences( BundleImpl bundle, String className, String expr, boolean checkAssignable) throws InvalidSyntaxException { ServiceReference[] refs = getServiceReferences(bundle, className, expr, checkAssignable); Object sm = System.getSecurityManager(); if ((sm == null) || (refs == null)) { return refs; } List result = new ArrayList(); for (int i = 0; i < refs.length; i++) { try { ((SecurityManager) sm).checkPermission(new ServicePermission(refs[i], ServicePermission.GET)); result.add(refs[i]); } catch (Exception ex) { // Ignore, since we are just testing permission. } } if (result.isEmpty()) { return null; } return (ServiceReference[]) result.toArray(new ServiceReference[result.size()]); } S getService(Bundle bundle, ServiceReference ref) { try { return (S) m_registry.getService(bundle, ref); } catch (ServiceException ex) { fireFrameworkEvent(FrameworkEvent.ERROR, ref.getBundle(), ex); } return null; } boolean ungetService(Bundle bundle, ServiceReference ref) { return m_registry.ungetService(bundle, ref); } File getDataFile(BundleImpl bundle, String s) { try { if (bundle == this) { return m_cache.getSystemBundleDataFile(s); } return bundle.getArchive().getDataFile(s); } catch (Exception ex) { m_logger.log(bundle, Logger.LOG_ERROR, ex.getMessage()); return null; } } // // Hook service management methods. // boolean isHookBlackListed(ServiceReference sr) { return m_registry.isHookBlackListed(sr); } void blackListHook(ServiceReference sr) { m_registry.blackListHook(sr); } public Set> getHooks(Class hookClass) { return m_registry.getHooks(hookClass); } // // PackageAdmin related methods. // private final Map m_systemBundleClassCache = new WeakHashMap(); /** * This method returns the bundle associated with the specified class if * the class was loaded from a bundle from this framework instance. If the * class was not loaded from a bundle or was loaded by a bundle in another * framework instance, then null is returned. * * @param clazz the class for which to find its associated bundle. * @return the bundle associated with the specified class or null * if the class was not loaded by a bundle or its associated * bundle belongs to a different framework instance. **/ Bundle getBundle(Class clazz) { // If the class comes from bundle class loader, then return // associated bundle if it is from this framework instance. if (clazz.getClassLoader() instanceof BundleReference) { // Only return the bundle if it is from this framework. BundleReference br = (BundleReference) clazz.getClassLoader(); return ((br.getBundle() instanceof BundleImpl) && (((BundleImpl) br.getBundle()).getFramework() == this)) ? br.getBundle() : null; } // Otherwise check if the class conceptually comes from the // system bundle. Ignore implicit boot delegation. if (!clazz.getName().startsWith("java.")) { Boolean fromSystemBundle; synchronized (m_systemBundleClassCache) { fromSystemBundle = m_systemBundleClassCache.get(clazz); } if (fromSystemBundle == null) { Class sbClass = null; try { sbClass = ((BundleWiringImpl) m_extensionManager .getRevision().getWiring()).getClassByDelegation(clazz.getName()); } catch (ClassNotFoundException ex) { // Ignore, treat as false. } synchronized (m_systemBundleClassCache) { if (sbClass == clazz) { fromSystemBundle = Boolean.TRUE; } else { fromSystemBundle = Boolean.FALSE; } m_systemBundleClassCache.put(clazz, fromSystemBundle); } } return fromSystemBundle.booleanValue() ? this : null; } return null; } /** * Returns the exported packages associated with the specified * package name. This is used by the PackageAdmin service * implementation. * * @param pkgName The name of the exported package to find. * @return The exported package or null if no matching package was found. **/ ExportedPackage[] getExportedPackages(String pkgName) { // First, get all exporters of the package. Map attrs = Collections.singletonMap( BundleRevision.PACKAGE_NAMESPACE, (Object) pkgName); BundleRequirementImpl req = new BundleRequirementImpl( null, BundleRevision.PACKAGE_NAMESPACE, Collections.EMPTY_MAP, attrs); Set exports = m_resolver.getCandidates(req, false); // We only want resolved capabilities. for (Iterator it = exports.iterator(); it.hasNext(); ) { if (it.next().getRevision().getWiring() == null) { it.remove(); } } if (exports != null) { List pkgs = new ArrayList(); for (Iterator it = exports.iterator(); it.hasNext(); ) { // Get the bundle associated with the current exporting revision. Bundle bundle = it.next().getRevision().getBundle(); // We need to find the version of the exported package, but this // is tricky since there may be multiple versions of the package // offered by a given bundle, since multiple revisions of the // bundle JAR file may exist if the bundle was updated without // refreshing the framework. In this case, each revision of the // bundle JAR file is represented as a revision ordered from // newest to oldest. We assume that the first revision found to // be exporting the package is the provider of the package, // which makes sense since it must have been resolved first. List revisions = bundle.adapt(BundleRevisions.class).getRevisions(); for (int i = revisions.size() - 1; i >= 0; i--) { BundleRevision br = revisions.get(i); List caps = (br.getWiring() == null) ? br.getDeclaredCapabilities(null) : br.getWiring().getCapabilities(null); for (BundleCapability cap : caps) { if (cap.getNamespace().equals(req.getNamespace()) && CapabilitySet.matches(cap, req.getFilter())) { pkgs.add( new ExportedPackageImpl( this, (BundleImpl) bundle, br, cap)); } } } } return (pkgs.isEmpty()) ? null : (ExportedPackage[]) pkgs.toArray(new ExportedPackage[pkgs.size()]); } return null; } /** * Returns an array of all actively exported packages from the specified * bundle or if the specified bundle is null an array * containing all actively exported packages by all bundles. * * @param b The bundle whose exported packages are to be retrieved * or null if the exported packages of all bundles are * to be retrieved. * @return An array of exported packages. **/ ExportedPackage[] getExportedPackages(Bundle b) { List list = new ArrayList(); // If a bundle is specified, then return its // exported packages. if (b != null) { BundleImpl bundle = (BundleImpl) b; getExportedPackages(bundle, list); } // Otherwise return all exported packages. else { // To create a list of all exported packages, we must look // in the installed and uninstalled sets of bundles. boolean locked = acquireGlobalLock(); if (!locked) { // If the calling thread holds bundle locks, then we might not // be able to get the global lock. throw new IllegalStateException( "Unable to acquire global lock to retrieve exported packages."); } try { // First get exported packages from uninstalled bundles. for (int bundleIdx = 0; (m_uninstalledBundles != null) && (bundleIdx < m_uninstalledBundles.size()); bundleIdx++) { BundleImpl bundle = m_uninstalledBundles.get(bundleIdx); getExportedPackages(bundle, list); } // Now get exported packages from installed bundles. Bundle[] bundles = getBundles(); for (int bundleIdx = 0; bundleIdx < bundles.length; bundleIdx++) { BundleImpl bundle = (BundleImpl) bundles[bundleIdx]; getExportedPackages(bundle, list); } } finally { releaseGlobalLock(); } } return (list.isEmpty()) ? null : (ExportedPackage[]) list.toArray(new ExportedPackage[list.size()]); } /** * Adds any current active exported packages from the specified bundle * to the passed in list. * @param bundle The bundle from which to retrieve exported packages. * @param list The list to which the exported packages are added **/ private void getExportedPackages(Bundle bundle, List list) { // Since a bundle may have many revisions associated with it, // one for each revision in the cache, search each revision // to get all exports. for (BundleRevision br : bundle.adapt(BundleRevisions.class).getRevisions()) { List caps = (br.getWiring() == null) ? br.getDeclaredCapabilities(null) : br.getWiring().getCapabilities(null); if ((caps != null) && (caps.size() > 0)) { for (BundleCapability cap : caps) { if (cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)) { String pkgName = (String) cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE); list.add(new ExportedPackageImpl( this, (BundleImpl) bundle, br, cap)); } } } } } // Needed by ExportedPackageImpl. Set getImportingBundles(BundleImpl exporter, BundleCapability cap) { return m_dependencies.getImportingBundles(exporter, cap); } // Needed by RequiredBundleImpl. Set getRequiringBundles(BundleImpl bundle) { return m_dependencies.getRequiringBundles(bundle); } boolean resolveBundles(Collection targets) { // Acquire global lock. boolean locked = acquireGlobalLock(); if (!locked) { m_logger.log( Logger.LOG_WARNING, "Unable to acquire global lock to perform resolve.", null); return false; } try { // Remember original targets. Collection originalTargets = targets; // Determine set of bundles to be resolved, which is either the // specified bundles or all bundles if null. if (targets == null) { // Add all bundles to the list. targets = m_installedBundles[LOCATION_MAP_IDX].values(); } // Now resolve each target bundle. boolean result = true; // If there are targets, then resolve each one. if (!targets.isEmpty()) { // Get bundle revisions for bundles in INSTALLED state. Set revisions = new HashSet(targets.size()); for (Bundle b : targets) { if (b.getState() != Bundle.UNINSTALLED) { revisions.add(b.adapt(BundleRevision.class)); } } // If we had to filter any of the original targets, then // the return result will be false regardless. if ((originalTargets != null) && (originalTargets.size() != revisions.size())) { result = false; } try { m_resolver.resolve(Collections.EMPTY_SET, revisions); if (result) { for (BundleRevision br : revisions) { if (br.getWiring() == null) { result = false; break; } } } } catch (ResolveException ex) { result = false; } catch (BundleException ex) { result = false; } } return result; } finally { // Always release the global lock. releaseGlobalLock(); } } private void resolveBundleRevision(BundleRevision revision) throws BundleException { try { m_resolver.resolve(Collections.singleton(revision), Collections.EMPTY_SET); } catch (ResolveException ex) { if (ex.getRevision() != null) { Bundle b = ex.getRevision().getBundle(); throw new BundleException( "Unresolved constraint in bundle " + b + ": " + ex.getMessage(), BundleException.RESOLVE_ERROR); } else { throw new BundleException(ex.getMessage(), BundleException.RESOLVE_ERROR); } } } void refreshPackages(Collection targets, FrameworkListener[] listeners) { // Acquire global lock. boolean locked = acquireGlobalLock(); if (!locked) { // If the thread calling holds bundle locks, then we might not // be able to get the global lock. However, in practice this // should not happen since the calls to this method have either // already acquired the global lock or it is PackageAdmin which // doesn't hold bundle locks. throw new IllegalStateException( "Unable to acquire global lock for refresh."); } // Determine set of bundles to refresh, which is all transitive // dependencies of specified set or all transitive dependencies // of all bundles if null is specified. Collection newTargets = targets; if (newTargets == null) { List list = new ArrayList(); // First add all uninstalled bundles. for (int i = 0; (m_uninstalledBundles != null) && (i < m_uninstalledBundles.size()); i++) { list.add(m_uninstalledBundles.get(i)); } // Then add all updated bundles. Iterator iter = m_installedBundles[LOCATION_MAP_IDX].values().iterator(); while (iter.hasNext()) { BundleImpl bundle = (BundleImpl) iter.next(); if (bundle.isRemovalPending()) { list.add(bundle); } } if (!list.isEmpty()) { newTargets = list; } } // If there are targets, then find all dependencies for each one. Set bundles = null; if (newTargets != null) { // Create map of bundles that import the packages // from the target bundles. bundles = new HashSet(); for (Bundle target : newTargets) { // Add the current target bundle to the map of // bundles to be refreshed. bundles.add(target); // Add all importing bundles to map. populateDependentGraph((BundleImpl) target, bundles); } } // Now refresh each bundle. try { boolean restart = false; Bundle systemBundle = this; // We need to restart the framework if either an extension bundle is // refreshed or the system bundle is refreshed and any extension bundle // has been updated or uninstalled. if (bundles != null) { for (Bundle b : bundles) { if ((systemBundle == b) || ((BundleImpl) b).isExtension()) { restart = true; break; } } // If we need to restart the framework, then no reason to // do a refresh. if (!restart) { // Now we actually need to refresh the affected bundles. // At this point the collection contains every bundle that has // been updated and/or removed as well as all bundles that import // packages from these bundles. // Create refresh helpers for each bundle. List helpers = new ArrayList(bundles.size()); for (Bundle b : bundles) { // Remove any targeted bundles from the uninstalled bundles // array, since they will be removed from the system after // the refresh. // TODO: FRAMEWORK - Is this correct? forgetUninstalledBundle((BundleImpl) b); // Create refresh helper for bundle. helpers.add(new RefreshHelper(b)); } // Stop all refreshing bundles. for (RefreshHelper helper : helpers) { if (helper != null) { helper.stop(); } } // Refresh or remove all refreshing bundles first. for (RefreshHelper helper : helpers) { if (helper != null) { helper.refreshOrRemove(); } } // Restart all refreshed bundles that were previously running. for (RefreshHelper helper : helpers) { if (helper != null) { helper.restart(); } } } else { try { update(); } catch (BundleException ex) { m_logger.log(Logger.LOG_ERROR, "Framework restart error.", ex); } } } } finally { // Always release the global lock. releaseGlobalLock(); } fireFrameworkEvent(FrameworkEvent.PACKAGES_REFRESHED, this, null); if (listeners != null) { FrameworkEvent event = new FrameworkEvent( FrameworkEvent.PACKAGES_REFRESHED, this, null); for (FrameworkListener l : listeners) { try { l.frameworkEvent(event); } catch (Throwable th) { m_logger.log(Logger.LOG_ERROR, "Framework listener delivery error.", th); } } } } Collection getDependencyClosure(Collection targets) { // Acquire global lock. boolean locked = acquireGlobalLock(); if (!locked) { // If the thread calling holds bundle locks, then we might not // be able to get the global lock. However, in practice this // should not happen since the calls to this method have either // already acquired the global lock or it is PackageAdmin which // doesn't hold bundle locks. throw new IllegalStateException( "Unable to acquire global lock for refresh."); } try { // If there are targets, then find all dependencies for each one. Set bundles = Collections.EMPTY_SET; if (targets != null) { // Create map of bundles that import the packages // from the target bundles. bundles = new HashSet(); for (Bundle target : targets) { // Add the current target bundle to the map of // bundles to be refreshed. bundles.add(target); // Add all importing bundles to map. populateDependentGraph((BundleImpl) target, bundles); } } return bundles; } finally { // Always release the global lock. releaseGlobalLock(); } } // Calls to this method must have the global lock. private void populateDependentGraph(BundleImpl exporter, Set set) { // Get all dependent bundles of this bundle. Set dependents = m_dependencies.getDependentBundles(exporter); if (dependents != null) { for (Bundle b : dependents) { // Avoid cycles if the bundle is already in set. if (!set.contains(b)) { // Add each dependent bundle to set. set.add(b); // Now recurse into each bundle to get its dependents. populateDependentGraph((BundleImpl) b, set); } } } } Collection getRemovalPendingBundles() { // Acquire global lock. boolean locked = acquireGlobalLock(); if (!locked) { // If the thread calling holds bundle locks, then we might not // be able to get the global lock. However, in practice this // should not happen since the calls to this method have either // already acquired the global lock or it is PackageAdmin which // doesn't hold bundle locks. throw new IllegalStateException( "Unable to acquire global lock for refresh."); } try { List bundles = new ArrayList(); if (m_uninstalledBundles != null) { for (Bundle b : m_uninstalledBundles) { bundles.add(b); } } for (Bundle b : getBundles()) { if (((BundleImpl) b).isRemovalPending()) { bundles.add(b); } } return bundles; } finally { // Always release the global lock. releaseGlobalLock(); } } // // Miscellaneous private methods. // private volatile SecurityProvider m_securityProvider; SecurityProvider getSecurityProvider() { return m_securityProvider; } void setSecurityProvider(SecurityProvider securityProvider) { m_securityProvider = securityProvider; } Object getSignerMatcher(BundleImpl bundle, int signersType) { if ((bundle != this) && (m_securityProvider != null)) { return m_securityProvider.getSignerMatcher(bundle, signersType); } return new HashMap(); } boolean impliesBundlePermission(BundleProtectionDomain bundleProtectionDomain, Permission permission, boolean direct) { if (m_securityProvider != null) { return m_securityProvider.hasBundlePermission(bundleProtectionDomain, permission, direct); } return true; } private BundleActivator createBundleActivator(Bundle impl) throws Exception { // CONCURRENCY NOTE: // This method is called indirectly from startBundle() (via _startBundle()), // which has the bundle lock, so there is no need to do any locking here. // Get the activator class from the header map. BundleActivator activator = null; Map headerMap = ((BundleRevisionImpl) impl.adapt(BundleRevision.class)).getHeaders(); String className = (String) headerMap.get(Constants.BUNDLE_ACTIVATOR); // Try to instantiate activator class if present. if (className != null) { className = className.trim(); Class clazz; try { clazz = ((BundleWiringImpl) impl.adapt(BundleRevision.class).getWiring()).getClassByDelegation(className); } catch (ClassNotFoundException ex) { throw new BundleException("Not found: " + className, ex); } activator = (BundleActivator) clazz.newInstance(); } return activator; } private void refreshBundle(BundleImpl bundle) throws Exception { // Acquire bundle lock. try { acquireBundleLock(bundle, Bundle.INSTALLED | Bundle.RESOLVED); } catch (IllegalStateException ex) { throw new BundleException( "Bundle state has changed unexpectedly during refresh."); } try { // See if we need to fire UNRESOLVED event. boolean fire = (bundle.getState() != Bundle.INSTALLED); // Remove dependencies. m_dependencies.removeDependencies(bundle); // Reset the bundle object. ((BundleImpl) bundle).refresh(); // Fire UNRESOLVED event if necessary // and notify state change.. if (fire) { setBundleStateAndNotify(bundle, Bundle.INSTALLED); fireBundleEvent(BundleEvent.UNRESOLVED, bundle); } } catch (Exception ex) { fireFrameworkEvent(FrameworkEvent.ERROR, bundle, ex); } finally { // Always release the bundle lock. releaseBundleLock(bundle); } } // // Event-related methods. // /** * Fires bundle events. **/ void fireFrameworkEvent( int type, Bundle bundle, Throwable throwable) { m_dispatcher.fireFrameworkEvent(new FrameworkEvent(type, bundle, throwable)); } /** * Fires bundle events. * * @param type The type of bundle event to fire. * @param bundle The bundle associated with the event. **/ void fireBundleEvent(int type, Bundle bundle) { m_dispatcher.fireBundleEvent(new BundleEvent(type, bundle), this); } void fireBundleEvent(int type, Bundle bundle, Bundle origin) { m_dispatcher.fireBundleEvent(new BundleEvent(type, bundle, origin), this); } /** * Fires service events. * * @param event The service event to fire. * @param reg The service registration associated with the service object. **/ private void fireServiceEvent(ServiceEvent event, Dictionary oldProps) { m_dispatcher.fireServiceEvent(event, oldProps, this); } // // Property related methods. // private void initializeFrameworkProperties() { // Standard OSGi properties. m_configMutableMap.put( FelixConstants.FRAMEWORK_VERSION, FelixConstants.FRAMEWORK_VERSION_VALUE); m_configMutableMap.put( FelixConstants.FRAMEWORK_VENDOR, FelixConstants.FRAMEWORK_VENDOR_VALUE); m_configMutableMap.put( FelixConstants.FRAMEWORK_LANGUAGE, System.getProperty("user.language")); m_configMutableMap.put( FelixConstants.FRAMEWORK_OS_VERSION, System.getProperty("os.version")); m_configMutableMap.put( FelixConstants.SUPPORTS_FRAMEWORK_EXTENSION, "true"); m_configMutableMap.put( FelixConstants.SUPPORTS_FRAMEWORK_FRAGMENT, "true"); m_configMutableMap.put( FelixConstants.SUPPORTS_FRAMEWORK_REQUIREBUNDLE, "true"); m_configMutableMap.put( FelixConstants.SUPPORTS_BOOTCLASSPATH_EXTENSION, "false"); String s = null; s = R4LibraryClause.normalizeOSName(System.getProperty("os.name")); m_configMutableMap.put(FelixConstants.FRAMEWORK_OS_NAME, s); s = R4LibraryClause.normalizeProcessor(System.getProperty("os.arch")); m_configMutableMap.put(FelixConstants.FRAMEWORK_PROCESSOR, s); m_configMutableMap.put( FelixConstants.FELIX_VERSION_PROPERTY, getFrameworkVersion()); // Set supported execution environments to default value, // if not explicitly configured. if (!getConfig().containsKey(Constants.FRAMEWORK_EXECUTIONENVIRONMENT)) { s = Util.getDefaultProperty( m_logger, Constants.FRAMEWORK_EXECUTIONENVIRONMENT); if (s != null) { m_configMutableMap.put( Constants.FRAMEWORK_EXECUTIONENVIRONMENT, s); } } } /** * Read the framework version from the property file. * @return the framework version as a string. **/ private static String getFrameworkVersion() { // The framework version property. Properties props = new Properties(); InputStream in = Felix.class.getResourceAsStream("Felix.properties"); if (in != null) { try { props.load(in); } catch (IOException ex) { ex.printStackTrace(); } } // Maven uses a '-' to separate the version qualifier, // while OSGi uses a '.', so we need to convert to a '.' StringBuffer sb = new StringBuffer( props.getProperty( FelixConstants.FELIX_VERSION_PROPERTY, "0.0.0")); if (sb.toString().indexOf("-") >= 0) { sb.setCharAt(sb.toString().indexOf("-"), '.'); } String toRet = sb.toString(); if (toRet.indexOf("${pom") >= 0) { return "0.0.0"; } else { return toRet; } } // // Private utility methods. // /** * Generated the next valid bundle identifier. **/ private long loadNextId() { synchronized (m_nextIdLock) { // Read persisted next bundle identifier. InputStream is = null; BufferedReader br = null; try { File file = m_cache.getSystemBundleDataFile("bundle.id"); is = m_secureAction.getFileInputStream(file); br = new BufferedReader(new InputStreamReader(is)); return Long.parseLong(br.readLine()); } catch (FileNotFoundException ex) { // Ignore this case because we assume that this is the // initial startup of the framework and therefore the // file does not exist yet. } catch (Exception ex) { m_logger.log( Logger.LOG_WARNING, "Unable to initialize next bundle identifier from persistent storage.", ex); } finally { try { if (br != null) br.close(); if (is != null) is.close(); } catch (Exception ex) { m_logger.log( Logger.LOG_WARNING, "Unable to close next bundle identifier file.", ex); } } } return -1; } private long getNextId() { synchronized (m_nextIdLock) { // Save the current id. long id = m_nextId; // Increment the next id. m_nextId++; // Write the bundle state. OutputStream os = null; BufferedWriter bw = null; try { File file = m_cache.getSystemBundleDataFile("bundle.id"); os = m_secureAction.getFileOutputStream(file); bw = new BufferedWriter(new OutputStreamWriter(os)); String s = Long.toString(m_nextId); bw.write(s, 0, s.length()); } catch (Exception ex) { m_logger.log( Logger.LOG_WARNING, "Unable to save next bundle identifier to persistent storage.", ex); } finally { try { if (bw != null) bw.close(); if (os != null) os.close(); } catch (Exception ex) { m_logger.log( Logger.LOG_WARNING, "Unable to close next bundle identifier file.", ex); } } return id; } } // // Miscellaneous inner classes. // class SystemBundleActivator implements BundleActivator { public void start(BundleContext context) throws Exception { // Add the bundle activator for the url handler service. m_activatorList.add(0, new URLHandlersActivator(m_configMap, Felix.this)); // Start all activators. for (int i = 0; i < m_activatorList.size(); i++) { Felix.m_secureAction.startActivator( (BundleActivator) m_activatorList.get(i), context); } } public void stop(BundleContext context) { // The state of the framework should be STOPPING, so // acquire the bundle lock to verify it. acquireBundleLock(Felix.this, Bundle.STOPPING); releaseBundleLock(Felix.this); // Use the start level service to set the start level to zero // in order to stop all bundles in the framework. Since framework // shutdown happens on its own thread, we can wait for the start // level service to finish before proceeding by calling the // non-spec setStartLevelAndWait() method. m_fwkStartLevel.setStartLevelAndWait(0); // Stop framework wiring thread. m_fwkWiring.stop(); // Stop framework start level thread. m_fwkStartLevel.stop(); // Shutdown event dispatching queue. m_dispatcher.stopDispatching(); // Since there may be updated and uninstalled bundles that // have not been refreshed, we will take care of refreshing // them during shutdown. // Refresh all updated bundles. Bundle[] bundles = getBundles(); for (int i = 0; i < bundles.length; i++) { BundleImpl bundle = (BundleImpl) bundles[i]; if (bundle.isRemovalPending()) { try { refreshBundle(bundle); } catch (Exception ex) { fireFrameworkEvent(FrameworkEvent.ERROR, bundle, ex); m_logger.log(bundle, Logger.LOG_ERROR, "Unable to purge bundle " + bundle._getLocation(), ex); } } } // Delete uninstalled bundles. for (int i = 0; (m_uninstalledBundles != null) && (i < m_uninstalledBundles.size()); i++) { try { m_uninstalledBundles.get(i).closeAndDelete(); } catch (Exception ex) { m_logger.log(m_uninstalledBundles.get(i), Logger.LOG_ERROR, "Unable to remove " + m_uninstalledBundles.get(i)._getLocation(), ex); } } // Dispose of the bundles to close their associated contents. bundles = getBundles(); for (int i = 0; i < bundles.length; i++) { ((BundleImpl) bundles[i]).close(); } // Stop all system bundle activators. for (int i = 0; i < m_activatorList.size(); i++) { try { Felix.m_secureAction.stopActivator((BundleActivator) m_activatorList.get(i), _getBundleContext()); } catch (Throwable throwable) { m_logger.log( Logger.LOG_WARNING, "Exception stopping a system bundle activator.", throwable); } } if (m_securityManager != null) { System.setSecurityManager(null); m_securityManager = null; } m_dependencies.removeDependents(adapt(BundleRevision.class)); if (m_extensionManager != null) { m_extensionManager.removeExtensions(Felix.this); } // Dispose of the bundle cache. m_cache.release(); m_cache = null; // Set the framework state to resolved. acquireBundleLock(Felix.this, Bundle.STOPPING); try { // Clean up the bundle context. ((BundleContextImpl) _getBundleContext()).invalidate(); setBundleContext(null); // Set the framework state to resolved and open // the shutdown gate. setBundleStateAndNotify(Felix.this, Bundle.RESOLVED); m_shutdownGate.open(); m_shutdownGate = null; } finally { releaseBundleLock(Felix.this); } } } /** * Simple class that is used in refreshPackages() to embody * the refresh logic in order to keep the code clean. This class is * not static because it needs access to framework event firing methods. **/ private class RefreshHelper { private BundleImpl m_bundle = null; private int m_oldState = Bundle.INSTALLED; public RefreshHelper(Bundle bundle) { m_bundle = (BundleImpl) bundle; } public void stop() { // TODO: LOCKING - This is not really correct. if (m_bundle.getState() == Bundle.ACTIVE) { m_oldState = Bundle.ACTIVE; try { stopBundle(m_bundle, false); } catch (Throwable ex) { fireFrameworkEvent(FrameworkEvent.ERROR, m_bundle, ex); } } } public void refreshOrRemove() { try { // Delete or refresh the bundle depending on its // current state. if (m_bundle.getState() == Bundle.UNINSTALLED) { // Remove dependencies. m_dependencies.removeDependencies(m_bundle); m_bundle.closeAndDelete(); m_bundle = null; } else { // This removes all old bundle revisions from memory and // from disk. It only maintains the newest revision in the // bundle cache. refreshBundle(m_bundle); } } catch (Throwable ex) { fireFrameworkEvent(FrameworkEvent.ERROR, m_bundle, ex); } } public void restart() { if ((m_bundle != null) && (m_oldState == Bundle.ACTIVE)) { try { // TODO: LAZY - Not sure if this is the best way... int options = Bundle.START_TRANSIENT; options = (m_bundle.getPersistentState() == Bundle.STARTING) ? options | Bundle.START_ACTIVATION_POLICY : options; startBundle(m_bundle, options); } catch (Throwable ex) { fireFrameworkEvent(FrameworkEvent.ERROR, m_bundle, ex); } } } } // Compares bundles by start level. Within a start level, // bundles are sorted by bundle ID. private static class StartLevelTuple implements Comparable { private final BundleImpl m_bundle; private int m_level; StartLevelTuple(BundleImpl bundle, int level) { m_bundle = bundle; m_level = level; } public int compareTo(StartLevelTuple t) { int result = 1; if (m_level < t.m_level) { result = -1; } else if (m_level > t.m_level) { result = 1; } else if (m_bundle.getBundleId() < t.m_bundle.getBundleId()) { result = -1; } else if (m_bundle.getBundleId() == t.m_bundle.getBundleId()) { result = 0; } return result; } } // // Locking related methods. // private void rememberUninstalledBundle(BundleImpl bundle) { boolean locked = acquireGlobalLock(); if (!locked) { // If the calling thread holds bundle locks, then we might not // be able to get the global lock. throw new IllegalStateException( "Unable to acquire global lock to record uninstalled bundle."); } try { // Verify that the bundle is not already in the array. for (int i = 0; (m_uninstalledBundles != null) && (i < m_uninstalledBundles.size()); i++) { if (m_uninstalledBundles.get(i) == bundle) { return; } } // Use a copy-on-write approach to add the bundle // to the uninstalled list. List uninstalledBundles = new ArrayList(m_uninstalledBundles); uninstalledBundles.add(bundle); m_uninstalledBundles = uninstalledBundles; } finally { releaseGlobalLock(); } } private void forgetUninstalledBundle(BundleImpl bundle) { boolean locked = acquireGlobalLock(); if (!locked) { // If the calling thread holds bundle locks, then we might not // be able to get the global lock. throw new IllegalStateException( "Unable to acquire global lock to release uninstalled bundle."); } try { if (m_uninstalledBundles == null) { return; } // Use a copy-on-write approach to remove the bundle // from the uninstalled list. List uninstalledBundles = new ArrayList(m_uninstalledBundles); uninstalledBundles.remove(bundle); m_uninstalledBundles = uninstalledBundles; } finally { releaseGlobalLock(); } } void acquireInstallLock(String location) throws BundleException { synchronized (m_installRequestLock_Priority1) { while (m_installRequestMap.get(location) != null) { try { m_installRequestLock_Priority1.wait(); } catch (InterruptedException ex) { throw new BundleException("Unable to install, thread interrupted."); } } m_installRequestMap.put(location, location); } } void releaseInstallLock(String location) { synchronized (m_installRequestLock_Priority1) { m_installRequestMap.remove(location); m_installRequestLock_Priority1.notifyAll(); } } void setBundleStateAndNotify(BundleImpl bundle, int state) { synchronized (m_bundleLock) { bundle.__setState(state); m_bundleLock.notifyAll(); } } /** * This method acquires the lock for the specified bundle as long as the * bundle is in one of the specified states. If it is not, an exception * is thrown. Bundle state changes will be monitored to avoid deadlocks. * @param bundle The bundle to lock. * @param desiredStates Logically OR'ed desired bundle states. * @throws java.lang.IllegalStateException If the bundle is not in one of the * specified desired states. **/ void acquireBundleLock(BundleImpl bundle, int desiredStates) throws IllegalStateException { synchronized (m_bundleLock) { // Wait if the desired bundle is already locked by someone else // or if any thread has the global lock, unless the current thread // holds the global lock or the bundle lock already. while (!bundle.isLockable() || ((m_globalLockThread != null) && (m_globalLockThread != Thread.currentThread()))) { // Check to make sure the bundle is in a desired state. // If so, keep waiting. If not, throw an exception. if ((desiredStates & bundle.getState()) == 0) { throw new IllegalStateException("Bundle in unexpected state."); } // If the calling thread already owns the global lock, then make // sure no other thread is trying to promote a bundle lock to a // global lock. If so, interrupt the other thread to avoid deadlock. else if (m_globalLockThread == Thread.currentThread() && (bundle.getLockingThread() != null) && m_globalLockWaitersList.contains(bundle.getLockingThread())) { bundle.getLockingThread().interrupt(); } try { m_bundleLock.wait(); } catch (InterruptedException ex) { throw new IllegalStateException("Unable to acquire bundle lock, thread interrupted."); } } // Now that we can acquire the bundle lock, let's check to make sure // it is in a desired state; if not, throw an exception and do not // lock it. if ((desiredStates & bundle.getState()) == 0) { throw new IllegalStateException("Bundle in unexpected state."); } // Acquire the bundle lock. bundle.lock(); } } /** * Releases the bundle's lock. * @param bundle The bundle whose lock is to be released. * @throws java.lang.IllegalStateException If the calling thread does not * own the bundle lock. **/ void releaseBundleLock(BundleImpl bundle) { synchronized (m_bundleLock) { // Unlock the bundle. bundle.unlock(); // If the thread no longer holds the bundle lock, // then remove it from the held lock map. if (bundle.getLockingThread() == null) { m_bundleLock.notifyAll(); } } } /** * Attempts to acquire the global lock. Will also promote a bundle lock * to the global lock, if the calling thread already holds a bundle lock. * Since it is possible to deadlock when trying to acquire the global lock * while holding a bundle lock, this method may fail if a potential deadlock * is detected. If the calling thread does not hold a bundle lock, then it * will wait indefinitely to acquire the global. * @return true if the global lock was successfully acquired, * false otherwise. **/ boolean acquireGlobalLock() { synchronized (m_bundleLock) { // Wait as long as some other thread holds the global lock // and the current thread is not interrupted. boolean interrupted = false; while (!interrupted && (m_globalLockThread != null) && (m_globalLockThread != Thread.currentThread())) { // Add calling thread to global lock waiters list. m_globalLockWaitersList.add(Thread.currentThread()); // We need to wake up all waiting threads so we can // recheck for potential deadlock in acquireBundleLock() // if this thread was holding a bundle lock and is now // trying to promote it to a global lock. m_bundleLock.notifyAll(); // Now wait for the global lock. try { m_bundleLock.wait(); } catch (InterruptedException ex) { interrupted = true; } // At this point we are either interrupted or will get the // global lock, so remove the thread from the waiters list. m_globalLockWaitersList.remove(Thread.currentThread()); } // Check to see if we were interrupted, which means someone // with the global lock wants our bundle lock, so we should // fail gracefully. if (!interrupted) { // Increment the current thread's global lock count. m_globalLockCount++; m_globalLockThread = Thread.currentThread(); } // Note: If the thread was interrupted, there is no reason to notify // anyone, since the thread was likely interrupted to force it to give // up a bundle lock it is holding. When it does give up the bundle // lock, it will do a notifyAll() in there. return !interrupted; } } /** * Releases the global lock. * @throws java.lang.IllegalStateException If the calling thread does not * own the global lock. **/ void releaseGlobalLock() { synchronized (m_bundleLock) { // Decrement the current thread's global lock count; if (m_globalLockThread == Thread.currentThread()) { m_globalLockCount--; if (m_globalLockCount == 0) { m_globalLockThread = null; m_bundleLock.notifyAll(); } } else { throw new IllegalStateException( "The current thread doesn't own the global lock."); } } } private volatile URLHandlersActivator m_urlHandlersActivator; void setURLHandlersActivator(URLHandlersActivator urlHandlersActivator) { m_urlHandlersActivator = urlHandlersActivator; } Object getStreamHandlerService(String protocol) { return m_urlHandlersActivator.getStreamHandlerService(protocol); } Object getContentHandlerService(String mimeType) { return m_urlHandlersActivator.getContentHandlerService(mimeType); } } felix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/resolver/0000755000175000017500000000000011655235117027070 5ustar drazzibdrazzib././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootfelix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/resolver/CandidateComparator.javafelix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/resolver/CandidateComparator.jav0000644000175000017500000001026111644651232033474 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework.resolver; import java.util.Comparator; import org.apache.felix.framework.wiring.BundleCapabilityImpl; import org.osgi.framework.Constants; import org.osgi.framework.Version; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRevision; public class CandidateComparator implements Comparator { public int compare(BundleCapability cap1, BundleCapability cap2) { // First check resolved state, since resolved capabilities have priority // over unresolved ones. Compare in reverse order since we want to sort // in descending order. int c = 0; if ((cap1.getRevision().getWiring() != null) && (cap2.getRevision().getWiring() == null)) { c = -1; } else if ((cap1.getRevision().getWiring() == null) && (cap2.getRevision().getWiring() != null)) { c = 1; } // Compare revision capabilities. if ((c == 0) && cap1.getNamespace().equals(BundleRevision.BUNDLE_NAMESPACE)) { c = ((Comparable) cap1.getAttributes().get(BundleRevision.BUNDLE_NAMESPACE)) .compareTo(cap2.getAttributes().get(BundleRevision.BUNDLE_NAMESPACE)); if (c == 0) { Version v1 = (!cap1.getAttributes().containsKey(Constants.BUNDLE_VERSION_ATTRIBUTE)) ? Version.emptyVersion : (Version) cap1.getAttributes().get(Constants.BUNDLE_VERSION_ATTRIBUTE); Version v2 = (!cap2.getAttributes().containsKey(Constants.BUNDLE_VERSION_ATTRIBUTE)) ? Version.emptyVersion : (Version) cap2.getAttributes().get(Constants.BUNDLE_VERSION_ATTRIBUTE); // Compare these in reverse order, since we want // highest version to have priority. c = v2.compareTo(v1); } } // Compare package capabilities. else if ((c == 0) && cap1.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)) { c = ((Comparable) cap1.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE)) .compareTo(cap2.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE)); if (c == 0) { Version v1 = (!cap1.getAttributes().containsKey(BundleCapabilityImpl.VERSION_ATTR)) ? Version.emptyVersion : (Version) cap1.getAttributes().get(BundleCapabilityImpl.VERSION_ATTR); Version v2 = (!cap2.getAttributes().containsKey(BundleCapabilityImpl.VERSION_ATTR)) ? Version.emptyVersion : (Version) cap2.getAttributes().get(BundleCapabilityImpl.VERSION_ATTR); // Compare these in reverse order, since we want // highest version to have priority. c = v2.compareTo(v1); } } // Finally, compare bundle identity. if (c == 0) { if (cap1.getRevision().getBundle().getBundleId() < cap2.getRevision().getBundle().getBundleId()) { c = -1; } else if (cap1.getRevision().getBundle().getBundleId() > cap2.getRevision().getBundle().getBundleId()) { c = 1; } } return c; } }felix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/resolver/Resolver.java0000644000175000017500000000357511644651232031544 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework.resolver; import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedSet; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRequirement; import org.osgi.framework.wiring.BundleRevision; public interface Resolver { Map> resolve( ResolverState state, Set mandatoryRevisions, Set optionalRevisions, Set ondemandFragments); Map> resolve( ResolverState state, BundleRevision revision, String pkgName, Set ondemandFragments); public static interface ResolverState { boolean isEffective(BundleRequirement req); SortedSet getCandidates( BundleRequirement req, boolean obeyMandatory); void checkExecutionEnvironment(BundleRevision revision) throws ResolveException; void checkNativeLibraries(BundleRevision revision) throws ResolveException; } }felix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/resolver/Candidates.java0000644000175000017500000012320511644651232031773 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework.resolver; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; import org.apache.felix.framework.BundleRevisionImpl; import org.apache.felix.framework.resolver.Resolver.ResolverState; import org.apache.felix.framework.util.FelixConstants; import org.apache.felix.framework.util.Util; import org.apache.felix.framework.wiring.BundleCapabilityImpl; import org.apache.felix.framework.wiring.BundleRequirementImpl; import org.osgi.framework.Constants; import org.osgi.framework.Version; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRequirement; import org.osgi.framework.wiring.BundleRevision; import org.osgi.framework.wiring.BundleWire; import org.osgi.framework.wiring.BundleWiring; class Candidates { public static final int MANDATORY = 0; public static final int OPTIONAL = 1; public static final int ON_DEMAND = 2; // Set of all mandatory bundle revisions. private final Set m_mandatoryRevisions; // Maps a capability to requirements that match it. private final Map> m_dependentMap; // Maps a requirement to the capability it matches. private final Map> m_candidateMap; // Maps a bundle revision to its associated wrapped revision; this only happens // when a revision being resolved has fragments to attach to it. private final Map m_allWrappedHosts; // Map used when populating candidates to hold intermediate and final results. private final Map m_populateResultCache; // Flag to signal if fragments are present in the candidate map. private boolean m_fragmentsPresent = false; /** * Private copy constructor used by the copy() method. * @param dependentMap the capability dependency map. * @param candidateMap the requirement candidate map. * @param hostFragments the fragment map. * @param wrappedHosts the wrapped hosts map. **/ private Candidates( Set mandatoryRevisions, Map> dependentMap, Map> candidateMap, Map wrappedHosts, Map populateResultCache, boolean fragmentsPresent) { m_mandatoryRevisions = mandatoryRevisions; m_dependentMap = dependentMap; m_candidateMap = candidateMap; m_allWrappedHosts = wrappedHosts; m_populateResultCache = populateResultCache; m_fragmentsPresent = fragmentsPresent; } /** * Constructs an empty Candidates object. **/ public Candidates() { m_mandatoryRevisions = new HashSet(); m_dependentMap = new HashMap>(); m_candidateMap = new HashMap>(); m_allWrappedHosts = new HashMap(); m_populateResultCache = new HashMap(); } /** * Populates candidates for the specified revision. How a revision is * resolved depends on its resolution type as follows: *
    *
  • MANDATORY - must resolve and failure to do so throws * an exception.
  • *
  • OPTIONAL - attempt to resolve, but no exception is thrown * if the resolve fails.
  • *
  • ON_DEMAND - only resolve on demand; this only applies to * fragments and will only resolve a fragment if its host is already * selected as a candidate.
  • *
* @param state the resolver state used for populating the candidates. * @param revision the revision whose candidates should be populated. * @param resolution indicates the resolution type. */ public final void populate( ResolverState state, BundleRevision revision, int resolution) { // Get the current result cache value, to make sure the revision // hasn't already been populated. Object cacheValue = m_populateResultCache.get(revision); // Has been unsuccessfully populated. if (cacheValue instanceof ResolveException) { return; } // Has been successfully populated. else if (cacheValue instanceof Boolean) { return; } // We will always attempt to populate fragments, since this is necessary // for ondemand attaching of fragment. However, we'll only attempt to // populate optional non-fragment revisions if they aren't already // resolved. boolean isFragment = Util.isFragment(revision); if (!isFragment && (revision.getWiring() != null)) { return; } // Always attempt to populate mandatory or optional revisions. // However, for on-demand fragments only populate if their host // is already populated. if ((resolution != ON_DEMAND) || (isFragment && populateFragmentOndemand(state, revision))) { if (resolution == MANDATORY) { m_mandatoryRevisions.add(revision); } try { // Try to populate candidates for the optional revision. populateRevision(state, revision); } catch (ResolveException ex) { // Only throw an exception if resolution is mandatory. if (resolution == MANDATORY) { throw ex; } } } } /** * Populates candidates for the specified revision. * @param state the resolver state used for populating the candidates. * @param revision the revision whose candidates should be populated. */ // TODO: FELIX3 - Modify to not be recursive. private void populateRevision(ResolverState state, BundleRevision revision) { // Determine if we've already calculated this revision's candidates. // The result cache will have one of three values: // 1. A resolve exception if we've already attempted to populate the // revision's candidates but were unsuccessful. // 2. Boolean.TRUE indicating we've already attempted to populate the // revision's candidates and were successful. // 3. An array containing the cycle count, current map of candidates // for already processed requirements, and a list of remaining // requirements whose candidates still need to be calculated. // For case 1, rethrow the exception. For case 2, simply return immediately. // For case 3, this means we have a cycle so we should continue to populate // the candidates where we left off and not record any results globally // until we've popped completely out of the cycle. // Keeps track of the number of times we've reentered this method // for the current revision. Integer cycleCount = null; // Keeps track of the candidates we've already calculated for the // current revision's requirements. Map> localCandidateMap = null; // Keeps track of the current revision's requirements for which we // haven't yet found candidates. List remainingReqs = null; // Get the cache value for the current revision. Object cacheValue = m_populateResultCache.get(revision); // This is case 1. if (cacheValue instanceof ResolveException) { throw (ResolveException) cacheValue; } // This is case 2. else if (cacheValue instanceof Boolean) { return; } // This is case 3. else if (cacheValue != null) { // Increment and get the cycle count. cycleCount = (Integer) (((Object[]) cacheValue)[0] = new Integer(((Integer) ((Object[]) cacheValue)[0]).intValue() + 1)); // Get the already populated candidates. localCandidateMap = (Map) ((Object[]) cacheValue)[1]; // Get the remaining requirements. remainingReqs = (List) ((Object[]) cacheValue)[2]; } // If there is no cache value for the current revision, then this is // the first time we are attempting to populate its candidates, so // do some one-time checks and initialization. if ((remainingReqs == null) && (localCandidateMap == null)) { // Verify that any required execution environment is satisfied. state.checkExecutionEnvironment(revision); // Verify that any native libraries match the current platform. state.checkNativeLibraries(revision); // Record cycle count. cycleCount = new Integer(0); // Create a local map for populating candidates first, just in case // the revision is not resolvable. localCandidateMap = new HashMap(); // Create a modifiable list of the revision's requirements. remainingReqs = new ArrayList(revision.getDeclaredRequirements(null)); // Add these value to the result cache so we know we are // in the middle of populating candidates for the current // revision. m_populateResultCache.put(revision, cacheValue = new Object[] { cycleCount, localCandidateMap, remainingReqs }); } // If we have requirements remaining, then find candidates for them. while (remainingReqs.size() > 0) { BundleRequirement req = remainingReqs.remove(0); // Ignore non-effective and dynamic requirements. String resolution = req.getDirectives().get(Constants.RESOLUTION_DIRECTIVE); if (!state.isEffective(req) || ((resolution != null) && resolution.equals(FelixConstants.RESOLUTION_DYNAMIC))) { continue; } // Process the candidates, removing any candidates that // cannot resolve. SortedSet candidates = state.getCandidates((BundleRequirementImpl) req, true); ResolveException rethrow = processCandidates(state, revision, candidates); // If there are no candidates for the current requirement // and it is not optional, then create, cache, and throw // a resolve exception. if (candidates.isEmpty() && !((BundleRequirementImpl) req).isOptional()) { String msg = "Unable to resolve " + revision + ": missing requirement " + req; if (rethrow != null) { msg = msg + " [caused by: " + rethrow.getMessage() + "]"; } rethrow = new ResolveException(msg, revision, req); m_populateResultCache.put(revision, rethrow); throw rethrow; } // If we actually have candidates for the requirement, then // add them to the local candidate map. else if (candidates.size() > 0) { localCandidateMap.put(req, candidates); } } // If we are exiting from a cycle then decrement // cycle counter, otherwise record the result. if (cycleCount.intValue() > 0) { ((Object[]) cacheValue)[0] = new Integer(cycleCount.intValue() - 1); } else if (cycleCount.intValue() == 0) { // Record that the revision was successfully populated. m_populateResultCache.put(revision, Boolean.TRUE); // Merge local candidate map into global candidate map. if (localCandidateMap.size() > 0) { add(localCandidateMap); } } } private boolean populateFragmentOndemand(ResolverState state, BundleRevision revision) throws ResolveException { // Create a modifiable list of the revision's requirements. List remainingReqs = new ArrayList(revision.getDeclaredRequirements(null)); // Find the host requirement. BundleRequirement hostReq = null; for (Iterator it = remainingReqs.iterator(); it.hasNext(); ) { BundleRequirement r = it.next(); if (r.getNamespace().equals(BundleRevision.HOST_NAMESPACE)) { hostReq = r; it.remove(); break; } } // Get candidates hosts and keep any that have been populated. SortedSet hosts = state.getCandidates((BundleRequirementImpl) hostReq, false); for (Iterator it = hosts.iterator(); it.hasNext(); ) { BundleCapability host = it.next(); if (!isPopulated(host.getRevision())) { it.remove(); } } // If there aren't any populated hosts, then we can just // return since this fragment isn't needed. if (hosts.isEmpty()) { return false; } // If there are populates host candidates, then finish up // some other checks and prepopulate the result cache with // the work we've done so far. // Verify that any required execution environment is satisfied. state.checkExecutionEnvironment(revision); // Verify that any native libraries match the current platform. state.checkNativeLibraries(revision); // Record cycle count, but start at -1 since it will // be incremented again in populate(). Integer cycleCount = new Integer(-1); // Create a local map for populating candidates first, just in case // the revision is not resolvable. Map> localCandidateMap = new HashMap>(); // Add the discovered host candidates to the local candidate map. localCandidateMap.put(hostReq, hosts); // Add these value to the result cache so we know we are // in the middle of populating candidates for the current // revision. m_populateResultCache.put(revision, new Object[] { cycleCount, localCandidateMap, remainingReqs }); return true; } public void populateDynamic( ResolverState state, BundleRevision revision, BundleRequirement req, SortedSet candidates) { // Record the revision associated with the dynamic require // as a mandatory revision. m_mandatoryRevisions.add(revision); // Add the dynamic imports candidates. add(req, candidates); // Process the candidates, removing any candidates that // cannot resolve. ResolveException rethrow = processCandidates(state, revision, candidates); if (candidates.isEmpty()) { if (rethrow == null) { rethrow = new ResolveException("Dynamic import failed.", revision, req); } throw rethrow; } m_populateResultCache.put(revision, Boolean.TRUE); } /** * This method performs common processing on the given set of candidates. * Specifically, it removes any candidates which cannot resolve and it * synthesizes candidates for any candidates coming from any attached * fragments, since fragment capabilities only appear once, but technically * each host represents a unique capability. * @param state the resolver state. * @param revision the revision being resolved. * @param candidates the candidates to process. * @return a resolve exception to be re-thrown, if any, or null. */ private ResolveException processCandidates( ResolverState state, BundleRevision revision, SortedSet candidates) { // Get satisfying candidates and populate their candidates if necessary. ResolveException rethrow = null; Set fragmentCands = null; for (Iterator itCandCap = candidates.iterator(); itCandCap.hasNext(); ) { BundleCapability candCap = itCandCap.next(); boolean isFragment = Util.isFragment(candCap.getRevision()); // If the capability is from a fragment, then record it // because we have to insert associated host capabilities // if the fragment is already attached to any hosts. if (isFragment) { if (fragmentCands == null) { fragmentCands = new HashSet(); } fragmentCands.add(candCap); } // If the candidate revision is a fragment, then always attempt // to populate candidates for its dependency, since it must be // attached to a host to be used. Otherwise, if the candidate // revision is not already resolved and is not the current version // we are trying to populate, then populate the candidates for // its dependencies as well. // NOTE: Technically, we don't have to check to see if the // candidate revision is equal to the current revision, but this // saves us from recursing and also simplifies exceptions messages // since we effectively chain exception messages for each level // of recursion; thus, any avoided recursion results in fewer // exceptions to chain when an error does occur. if (isFragment || ((candCap.getRevision().getWiring() == null) && !candCap.getRevision().equals(revision))) { try { populateRevision(state, candCap.getRevision()); } catch (ResolveException ex) { if (rethrow == null) { rethrow = ex; } // Remove the candidate since we weren't able to // populate its candidates. itCandCap.remove(); } } } // If any of the candidates for the requirement were from a fragment, // then also insert synthesized hosted capabilities for any other host // to which the fragment is attached since they are all effectively // unique capabilities. if (fragmentCands != null) { for (BundleCapability fragCand : fragmentCands) { // Only necessary for resolved fragments. BundleWiring wiring = fragCand.getRevision().getWiring(); if (wiring != null) { // Fragments only have host wire, so each wire represents // an attached host. for (BundleWire wire : wiring.getRequiredWires(null)) { // If the capability is a package, then make sure the // host actually provides it in its resolved capabilities, // since it may be a substitutable export. if (!fragCand.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE) || wire.getProviderWiring().getCapabilities(null).contains(fragCand)) { // Note that we can just add this as a candidate // directly, since we know it is already resolved. candidates.add( new HostedCapability( wire.getCapability().getRevision(), (BundleCapabilityImpl) fragCand)); } } } } } return rethrow; } public boolean isPopulated(BundleRevision revision) { Object value = m_populateResultCache.get(revision); return ((value != null) && (value instanceof Boolean)); } public ResolveException getResolveException(BundleRevision revision) { Object value = m_populateResultCache.get(revision); return ((value != null) && (value instanceof ResolveException)) ? (ResolveException) value : null; } /** * Adds a requirement and its matching candidates to the internal data * structure. This method assumes it owns the data being passed in and * does not make a copy. It takes the data and processes, such as calculating * which requirements depend on which capabilities and recording any fragments * it finds for future merging. * @param req the requirement to add. * @param candidates the candidates matching the requirement. **/ private void add(BundleRequirement req, SortedSet candidates) { if (req.getNamespace().equals(BundleRevision.HOST_NAMESPACE)) { m_fragmentsPresent = true; } // Record the candidates. m_candidateMap.put(req, candidates); } /** * Adds requirements and candidates in bulk. The outer map is not retained * by this method, but the inner data structures are, so they should not * be further modified by the caller. * @param candidates the bulk requirements and candidates to add. **/ private void add(Map> candidates) { for (Entry> entry : candidates.entrySet()) { add(entry.getKey(), entry.getValue()); } } /** * Returns the wrapped module associated with the given module. If the module * was not wrapped, then the module itself is returned. This is really only * needed to determine if the root modules of the resolve have been wrapped. * @param m the module whose wrapper is desired. * @return the wrapper module or the module itself if it was not wrapped. **/ public BundleRevision getWrappedHost(BundleRevision m) { BundleRevision wrapped = m_allWrappedHosts.get(m); return (wrapped == null) ? m : wrapped; } /** * Gets the candidates associated with a given requirement. * @param req the requirement whose candidates are desired. * @return the matching candidates or null. **/ public SortedSet getCandidates(BundleRequirement req) { return m_candidateMap.get(req); } /** * Merges fragments into their hosts. It does this by wrapping all host * modules and attaching their selected fragments, removing all unselected * fragment modules, and replacing all occurrences of the original fragments * in the internal data structures with the wrapped host modules instead. * Thus, fragment capabilities and requirements are merged into the appropriate * host and the candidates for the fragment now become candidates for the host. * Likewise, any module depending on a fragment now depend on the host. Note * that this process is sort of like multiplication, since one fragment that * can attach to two hosts effectively gets multiplied across the two hosts. * So, any modules being satisfied by the fragment will end up having the * two hosts as potential candidates, rather than the single fragment. * @param existingSingletons existing resolved singletons. * @throws ResolveException if the removal of any unselected fragments result * in the root module being unable to resolve. **/ public void prepare() { // Maps a host capability to a map containing its potential fragments; // the fragment map maps a fragment symbolic name to a map that maps // a version to a list of fragments requirements matching that symbolic // name and version. Map>>> hostFragments = Collections.EMPTY_MAP; if (m_fragmentsPresent) { hostFragments = populateDependents(); } // This method performs the following steps: // 1. Select the fragments to attach to a given host. // 2. Wrap hosts and attach fragments. // 3. Remove any unselected fragments. This is necessary because // other revisions may depend on the capabilities of unselected // fragments, so we need to remove the unselected fragments and // any revisions that depends on them, which could ultimately cause // the entire resolve to fail. // 4. Replace all fragments with any host it was merged into // (effectively multiplying it). // * This includes setting candidates for attached fragment // requirements as well as replacing fragment capabilities // with host's attached fragment capabilities. // Steps 1 and 2 List hostRevisions = new ArrayList(); List unselectedFragments = new ArrayList(); for (Entry>>> hostEntry : hostFragments.entrySet()) { // Step 1 BundleCapability hostCap = hostEntry.getKey(); Map>> fragments = hostEntry.getValue(); List selectedFragments = new ArrayList(); for (Entry>> fragEntry : fragments.entrySet()) { boolean isFirst = true; for (Entry> versionEntry : fragEntry.getValue().entrySet()) { for (BundleRequirement hostReq : versionEntry.getValue()) { // Selecting the first fragment in each entry, which // is equivalent to selecting the highest version of // each fragment with a given symbolic name. if (isFirst) { selectedFragments.add(hostReq.getRevision()); isFirst = false; } // For any fragment that wasn't selected, remove the // current host as a potential host for it and remove it // as a dependent on the host. If there are no more // potential hosts for the fragment, then mark it as // unselected for later removal. else { m_dependentMap.get(hostCap).remove(hostReq); SortedSet hosts = m_candidateMap.get(hostReq); hosts.remove(hostCap); if (hosts.isEmpty()) { unselectedFragments.add(hostReq.getRevision()); } } } } } // Step 2 HostBundleRevision wrappedHost = new HostBundleRevision(hostCap.getRevision(), selectedFragments); hostRevisions.add(wrappedHost); m_allWrappedHosts.put(hostCap.getRevision(), wrappedHost); } // Step 3 for (BundleRevision br : unselectedFragments) { removeRevision(br, new ResolveException( "Fragment was not selected for attachment.", br, null)); } // Step 4 for (HostBundleRevision hostRevision : hostRevisions) { // Replaces capabilities from fragments with the capabilities // from the merged host. for (BundleCapability c : hostRevision.getDeclaredCapabilities(null)) { // Don't replace the host capability, since the fragment will // really be attached to the original host, not the wrapper. if (!c.getNamespace().equals(BundleRevision.HOST_NAMESPACE)) { BundleCapability origCap = ((HostedCapability) c).getOriginalCapability(); // Note that you might think we could remove the original cap // from the dependent map, but you can't since it may come from // a fragment that is attached to multiple hosts, so each host // will need to make their own copy. Set dependents = m_dependentMap.get(origCap); if (dependents != null) { dependents = new HashSet(dependents); m_dependentMap.put(c, dependents); for (BundleRequirement r : dependents) { Set cands = m_candidateMap.get(r); cands.remove(origCap); cands.add(c); } } } } // Copy candidates for fragment requirements to the host. for (BundleRequirement r : hostRevision.getDeclaredRequirements(null)) { BundleRequirement origReq = ((HostedRequirement) r).getOriginalRequirement(); SortedSet cands = m_candidateMap.get(origReq); if (cands != null) { m_candidateMap.put(r, new TreeSet(cands)); for (BundleCapability cand : cands) { Set dependents = m_dependentMap.get(cand); dependents.remove(origReq); dependents.add(r); } } } } // Lastly, verify that all mandatory revisions are still // populated, since some might have become unresolved after // selecting fragments/singletons. for (BundleRevision br : m_mandatoryRevisions) { if (!isPopulated(br)) { throw getResolveException(br); } } } // Maps a host capability to a map containing its potential fragments; // the fragment map maps a fragment symbolic name to a map that maps // a version to a list of fragments requirements matching that symbolic // name and version. private Map>>> populateDependents() { Map>>> hostFragments = new HashMap>>>(); for (Entry> entry : m_candidateMap.entrySet()) { BundleRequirement req = entry.getKey(); SortedSet caps = entry.getValue(); for (BundleCapability cap : caps) { // Record the requirement as dependent on the capability. Set dependents = m_dependentMap.get(cap); if (dependents == null) { dependents = new HashSet(); m_dependentMap.put(cap, dependents); } dependents.add(req); // Keep track of hosts and associated fragments. if (req.getNamespace().equals(BundleRevision.HOST_NAMESPACE)) { Map>> fragments = hostFragments.get(cap); if (fragments == null) { fragments = new HashMap>>(); hostFragments.put(cap, fragments); } Map> fragmentVersions = fragments.get(req.getRevision().getSymbolicName()); if (fragmentVersions == null) { fragmentVersions = new TreeMap>(Collections.reverseOrder()); fragments.put(req.getRevision().getSymbolicName(), fragmentVersions); } List actual = fragmentVersions.get(req.getRevision().getVersion()); if (actual == null) { actual = new ArrayList(); fragmentVersions.put(req.getRevision().getVersion(), actual); } actual.add(req); } } } return hostFragments; } /** * Removes a module from the internal data structures if it wasn't selected * as a fragment or a singleton. This process may cause other modules to * become unresolved if they depended on the module's capabilities and there * is no other candidate. * @param revision the module to remove. * @throws ResolveException if removing the module caused the resolve to fail. **/ private void removeRevision(BundleRevision revision, ResolveException ex) { // Add removal reason to result cache. m_populateResultCache.put(revision, ex); // Remove from dependents. Set unresolvedRevisions = new HashSet(); remove(revision, unresolvedRevisions); // Remove dependents that failed as a result of removing revision. while (!unresolvedRevisions.isEmpty()) { Iterator it = unresolvedRevisions.iterator(); revision = it.next(); it.remove(); remove(revision, unresolvedRevisions); } } /** * Removes the specified module from the internal data structures, which * involves removing its requirements and its capabilities. This may cause * other modules to become unresolved as a result. * @param br the module to remove. * @param unresolvedRevisions a list to containing any additional modules that * that became unresolved as a result of removing this module and will * also need to be removed. * @throws ResolveException if removing the module caused the resolve to fail. **/ private void remove(BundleRevision br, Set unresolvedRevisions) throws ResolveException { for (BundleRequirement r : br.getDeclaredRequirements(null)) { remove(r); } for (BundleCapability c : br.getDeclaredCapabilities(null)) { remove(c, unresolvedRevisions); } } /** * Removes a requirement from the internal data structures. * @param req the requirement to remove. **/ private void remove(BundleRequirement req) { boolean isFragment = req.getNamespace().equals(BundleRevision.HOST_NAMESPACE); SortedSet candidates = m_candidateMap.remove(req); if (candidates != null) { for (BundleCapability cap : candidates) { Set dependents = m_dependentMap.get(cap); if (dependents != null) { dependents.remove(req); } } } } /** * Removes a capability from the internal data structures. This may cause * other modules to become unresolved as a result. * @param c the capability to remove. * @param unresolvedRevisions a list to containing any additional modules that * that became unresolved as a result of removing this module and will * also need to be removed. * @throws ResolveException if removing the module caused the resolve to fail. **/ private void remove(BundleCapability c, Set unresolvedRevisions) throws ResolveException { Set dependents = m_dependentMap.remove(c); if (dependents != null) { for (BundleRequirement r : dependents) { SortedSet candidates = m_candidateMap.get(r); candidates.remove(c); if (candidates.isEmpty()) { m_candidateMap.remove(r); if (!((BundleRequirementImpl) r).isOptional()) { String msg = "Unable to resolve " + r.getRevision() + ": missing requirement " + r; m_populateResultCache.put( r.getRevision(), new ResolveException(msg, r.getRevision(), r)); unresolvedRevisions.add(r.getRevision()); } } } } } /** * Creates a copy of the Candidates object. This is used for creating * permutations when package space conflicts are discovered. * @return copy of this Candidates object. **/ public Candidates copy() { Map> dependentMap = new HashMap>(); for (Entry> entry : m_dependentMap.entrySet()) { Set dependents = new HashSet(entry.getValue()); dependentMap.put(entry.getKey(), dependents); } Map> candidateMap = new HashMap>(); for (Entry> entry : m_candidateMap.entrySet()) { SortedSet candidates = new TreeSet(entry.getValue()); candidateMap.put(entry.getKey(), candidates); } return new Candidates( m_mandatoryRevisions, dependentMap, candidateMap, m_allWrappedHosts, m_populateResultCache, m_fragmentsPresent); } public void dump() { // Create set of all revisions from requirements. Set revisions = new HashSet(); for (Entry> entry : m_candidateMap.entrySet()) { revisions.add(entry.getKey().getRevision()); } // Now dump the revisions. System.out.println("=== BEGIN CANDIDATE MAP ==="); for (BundleRevision br : revisions) { System.out.println(" " + br + " (" + ((br.getWiring() != null) ? "RESOLVED)" : "UNRESOLVED)")); List reqs = (br.getWiring() != null) ? br.getWiring().getRequirements(null) : br.getDeclaredRequirements(null); for (BundleRequirement req : reqs) { Set candidates = m_candidateMap.get(req); if ((candidates != null) && (candidates.size() > 0)) { System.out.println(" " + req + ": " + candidates); } } reqs = (br.getWiring() != null) ? Util.getDynamicRequirements(br.getWiring().getRequirements(null)) : Util.getDynamicRequirements(br.getDeclaredRequirements(null)); for (BundleRequirement req : reqs) { Set candidates = m_candidateMap.get(req); if ((candidates != null) && (candidates.size() > 0)) { System.out.println(" " + req + ": " + candidates); } } } System.out.println("=== END CANDIDATE MAP ==="); } }felix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/resolver/ResolverWire.java0000644000175000017500000000335011644651232032362 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework.resolver; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRequirement; import org.osgi.framework.wiring.BundleRevision; public interface ResolverWire { /** * Returns the importing bundle revision. * @return The importing bundle revision. **/ public BundleRevision getRequirer(); /** * Returns the associated requirement from the importing bundle revision * that resulted in the creation of this wire. * @return **/ public BundleRequirement getRequirement(); /** * Returns the exporting bundle revision. * @return The exporting bundle revision. **/ public BundleRevision getProvider(); /** * Returns the associated capability from the exporting bundle revision * that satisfies the requirement of the importing bundle revision. * @return **/ public BundleCapability getCapability(); }felix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java0000644000175000017500000021653311644651232032366 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework.resolver; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.SortedSet; import org.apache.felix.framework.BundleWiringImpl; import org.apache.felix.framework.Logger; import org.apache.felix.framework.capabilityset.CapabilitySet; import org.apache.felix.framework.util.FelixConstants; import org.apache.felix.framework.util.Util; import org.apache.felix.framework.wiring.BundleCapabilityImpl; import org.apache.felix.framework.wiring.BundleRequirementImpl; import org.osgi.framework.Constants; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRequirement; import org.osgi.framework.wiring.BundleRevision; import org.osgi.framework.wiring.BundleWire; public class ResolverImpl implements Resolver { private final Logger m_logger; // Holds candidate permutations based on permutating "uses" chains. // These permutations are given higher priority. private final List m_usesPermutations = new ArrayList(); // Holds candidate permutations based on permutating requirement candidates. // These permutations represent backtracking on previous decisions. private final List m_importPermutations = new ArrayList(); public ResolverImpl(Logger logger) { m_logger = logger; } public Map> resolve( ResolverState state, Set mandatoryRevisions, Set optionalRevisions, Set ondemandFragments) { Map> wireMap = new HashMap>(); Map revisionPkgMap = new HashMap(); boolean retry; do { retry = false; try { // Create object to hold all candidates. Candidates allCandidates = new Candidates(); // Populate mandatory revisions; since these are mandatory // revisions, failure throws a resolve exception. for (Iterator it = mandatoryRevisions.iterator(); it.hasNext(); ) { BundleRevision br = it.next(); if (Util.isFragment(br) || (br.getWiring() == null)) { allCandidates.populate(state, br, Candidates.MANDATORY); } else { it.remove(); } } // Populate optional revisions; since these are optional // revisions, failure does not throw a resolve exception. for (BundleRevision br : optionalRevisions) { boolean isFragment = Util.isFragment(br); if (isFragment || (br.getWiring() == null)) { allCandidates.populate(state, br, Candidates.OPTIONAL); } } // Populate ondemand fragments; since these are optional // revisions, failure does not throw a resolve exception. for (BundleRevision br : ondemandFragments) { boolean isFragment = Util.isFragment(br); if (isFragment) { allCandidates.populate(state, br, Candidates.ON_DEMAND); } } // Merge any fragments into hosts. allCandidates.prepare(); // Create a combined list of populated revisions; for // optional revisions. We do not need to consider ondemand // fragments, since they will only be pulled in if their // host is already present. Set allRevisions = new HashSet(mandatoryRevisions); for (BundleRevision br : optionalRevisions) { if (allCandidates.isPopulated(br)) { allRevisions.add(br); } } // Record the initial candidate permutation. m_usesPermutations.add(allCandidates); ResolveException rethrow = null; // If a populated revision is a fragment, then its host // must ultimately be verified, so store its host requirement // to use for package space calculation. Map> hostReqs = new HashMap>(); for (BundleRevision br : allRevisions) { if (Util.isFragment(br)) { hostReqs.put( br, br.getDeclaredRequirements(BundleRevision.HOST_NAMESPACE)); } } do { rethrow = null; revisionPkgMap.clear(); m_packageSourcesCache.clear(); allCandidates = (m_usesPermutations.size() > 0) ? m_usesPermutations.remove(0) : m_importPermutations.remove(0); //allCandidates.dump(); for (BundleRevision br : allRevisions) { BundleRevision target = br; // If we are resolving a fragment, then get its // host candidate and verify it instead. List hostReq = hostReqs.get(br); if (hostReq != null) { target = allCandidates.getCandidates(hostReq.get(0)) .iterator().next().getRevision(); } calculatePackageSpaces( allCandidates.getWrappedHost(target), allCandidates, revisionPkgMap, new HashMap(), new HashSet()); //System.out.println("+++ PACKAGE SPACES START +++"); //dumpRevisionPkgMap(revisionPkgMap); //System.out.println("+++ PACKAGE SPACES END +++"); try { checkPackageSpaceConsistency( false, allCandidates.getWrappedHost(target), allCandidates, revisionPkgMap, new HashMap()); } catch (ResolveException ex) { rethrow = ex; } } } while ((rethrow != null) && ((m_usesPermutations.size() > 0) || (m_importPermutations.size() > 0))); // If there is a resolve exception, then determine if an // optionally resolved revision is to blame (typically a fragment). // If so, then remove the optionally resolved resolved and try // again; otherwise, rethrow the resolve exception. if (rethrow != null) { BundleRevision faultyRevision = getActualBundleRevision(rethrow.getRevision()); if (rethrow.getRequirement() instanceof HostedRequirement) { faultyRevision = ((HostedRequirement) rethrow.getRequirement()) .getOriginalRequirement().getRevision(); } if (optionalRevisions.remove(faultyRevision)) { retry = true; } else if (ondemandFragments.remove(faultyRevision)) { retry = true; } else { throw rethrow; } } // If there is no exception to rethrow, then this was a clean // resolve, so populate the wire map. else { for (BundleRevision br : allRevisions) { BundleRevision target = br; // If we are resolving a fragment, then we // actually want to populate its host's wires. List hostReq = hostReqs.get(br); if (hostReq != null) { target = allCandidates.getCandidates(hostReq.get(0)) .iterator().next().getRevision(); } if (allCandidates.isPopulated(target)) { wireMap = populateWireMap( allCandidates.getWrappedHost(target), revisionPkgMap, wireMap, allCandidates); } } } } finally { // Always clear the state. m_usesPermutations.clear(); m_importPermutations.clear(); } } while (retry); return wireMap; } public Map> resolve( ResolverState state, BundleRevision revision, String pkgName, Set ondemandFragments) { // We can only create a dynamic import if the following // conditions are met: // 1. The specified revision is resolved. // 2. The package in question is not already imported. // 3. The package in question is not accessible via require-bundle. // 4. The package in question is not exported by the revision. // 5. The package in question matches a dynamic import of the revision. // The following call checks all of these conditions and returns // the associated dynamic import and matching capabilities. Candidates allCandidates = getDynamicImportCandidates(state, revision, pkgName); if (allCandidates != null) { Map> wireMap = new HashMap>(); Map revisionPkgMap = new HashMap(); boolean retry; do { retry = false; try { // Try to populate optional fragments. for (BundleRevision br : ondemandFragments) { if (Util.isFragment(br)) { allCandidates.populate(state, br, Candidates.ON_DEMAND); } } // Merge any fragments into hosts. allCandidates.prepare(); // Record the initial candidate permutation. m_usesPermutations.add(allCandidates); ResolveException rethrow = null; do { rethrow = null; revisionPkgMap.clear(); m_packageSourcesCache.clear(); allCandidates = (m_usesPermutations.size() > 0) ? m_usesPermutations.remove(0) : m_importPermutations.remove(0); //allCandidates.dump(); // For a dynamic import, the instigating revision // will never be a fragment since fragments never // execute code, so we don't need to check for // this case like we do for a normal resolve. calculatePackageSpaces( allCandidates.getWrappedHost(revision), allCandidates, revisionPkgMap, new HashMap(), new HashSet()); //System.out.println("+++ PACKAGE SPACES START +++"); //dumpRevisionPkgMap(revisionPkgMap); //System.out.println("+++ PACKAGE SPACES END +++"); try { checkPackageSpaceConsistency( false, allCandidates.getWrappedHost(revision), allCandidates, revisionPkgMap, new HashMap()); } catch (ResolveException ex) { rethrow = ex; } } while ((rethrow != null) && ((m_usesPermutations.size() > 0) || (m_importPermutations.size() > 0))); // If there is a resolve exception, then determine if an // optionally resolved revision is to blame (typically a fragment). // If so, then remove the optionally resolved revision and try // again; otherwise, rethrow the resolve exception. if (rethrow != null) { BundleRevision faultyRevision = getActualBundleRevision(rethrow.getRevision()); if (rethrow.getRequirement() instanceof HostedRequirement) { faultyRevision = ((HostedRequirement) rethrow.getRequirement()) .getOriginalRequirement().getRevision(); } if (ondemandFragments.remove(faultyRevision)) { retry = true; } else { throw rethrow; } } // If there is no exception to rethrow, then this was a clean // resolve, so populate the wire map. else { wireMap = populateDynamicWireMap( revision, pkgName, revisionPkgMap, wireMap, allCandidates); return wireMap; } } finally { // Always clear the state. m_usesPermutations.clear(); m_importPermutations.clear(); } } while (retry); } return null; } private static Candidates getDynamicImportCandidates( ResolverState state, BundleRevision revision, String pkgName) { // Unresolved revisions cannot dynamically import, nor can the default // package be dynamically imported. if ((revision.getWiring() == null) || pkgName.length() == 0) { return null; } // If the revision doesn't have dynamic imports, then just return // immediately. List dynamics = Util.getDynamicRequirements(revision.getWiring().getRequirements(null)); if ((dynamics == null) || dynamics.isEmpty()) { return null; } // If the revision exports this package, then we cannot // attempt to dynamically import it. for (BundleCapability cap : revision.getWiring().getCapabilities(null)) { if (cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE) && cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE).equals(pkgName)) { return null; } } // If this revision already imports or requires this package, then // we cannot dynamically import it. if (((BundleWiringImpl) revision.getWiring()).hasPackageSource(pkgName)) { return null; } // Determine if any providers of the package exist. Map attrs = Collections.singletonMap( BundleRevision.PACKAGE_NAMESPACE, (Object) pkgName); BundleRequirementImpl req = new BundleRequirementImpl( revision, BundleRevision.PACKAGE_NAMESPACE, Collections.EMPTY_MAP, attrs); SortedSet candidates = state.getCandidates(req, false); // Try to find a dynamic requirement that matches the capabilities. BundleRequirementImpl dynReq = null; for (int dynIdx = 0; (candidates.size() > 0) && (dynReq == null) && (dynIdx < dynamics.size()); dynIdx++) { for (Iterator itCand = candidates.iterator(); (dynReq == null) && itCand.hasNext(); ) { BundleCapability cap = itCand.next(); if (CapabilitySet.matches( (BundleCapabilityImpl) cap, ((BundleRequirementImpl) dynamics.get(dynIdx)).getFilter())) { dynReq = (BundleRequirementImpl) dynamics.get(dynIdx); } } } // If we found a matching dynamic requirement, then filter out // any candidates that do not match it. if (dynReq != null) { for (Iterator itCand = candidates.iterator(); itCand.hasNext(); ) { BundleCapability cap = itCand.next(); if (!CapabilitySet.matches( (BundleCapabilityImpl) cap, dynReq.getFilter())) { itCand.remove(); } } } else { candidates.clear(); } Candidates allCandidates = null; if (candidates.size() > 0) { allCandidates = new Candidates(); allCandidates.populateDynamic(state, revision, dynReq, candidates); } return allCandidates; } private void calculatePackageSpaces( BundleRevision revision, Candidates allCandidates, Map revisionPkgMap, Map> usesCycleMap, Set cycle) { if (cycle.contains(revision)) { return; } cycle.add(revision); // Create parallel arrays for requirement and proposed candidate // capability or actual capability if revision is resolved or not. List reqs = new ArrayList(); List caps = new ArrayList(); boolean isDynamicImporting = false; if (revision.getWiring() != null) { // Use wires to get actual requirements and satisfying capabilities. for (BundleWire wire : revision.getWiring().getRequiredWires(null)) { // Wrap the requirement as a hosted requirement if it comes // from a fragment, since we will need to know the host. We // also need to wrap if the requirement is a dynamic import, // since that requirement will be shared with any other // matching dynamic imports. BundleRequirement r = wire.getRequirement(); if (!r.getRevision().equals(wire.getRequirerWiring().getRevision()) || ((r.getDirectives().get(Constants.RESOLUTION_DIRECTIVE) != null) && r.getDirectives().get(Constants.RESOLUTION_DIRECTIVE).equals("dynamic"))) { r = new HostedRequirement( wire.getRequirerWiring().getRevision(), (BundleRequirementImpl) r); } // Wrap the capability as a hosted capability if it comes // from a fragment, since we will need to know the host. BundleCapability c = wire.getCapability(); if (!c.getRevision().equals(wire.getProviderWiring().getRevision())) { c = new HostedCapability( wire.getProviderWiring().getRevision(), (BundleCapabilityImpl) c); } reqs.add(r); caps.add(c); } // Since the revision is resolved, it could be dynamically importing, // so check to see if there are candidates for any of its dynamic // imports. for (BundleRequirement req : Util.getDynamicRequirements(revision.getWiring().getRequirements(null))) { // Get the candidates for the current requirement. SortedSet candCaps = allCandidates.getCandidates((BundleRequirementImpl) req); // Optional requirements may not have any candidates. if (candCaps == null) { continue; } BundleCapability cap = candCaps.iterator().next(); reqs.add(req); caps.add(cap); isDynamicImporting = true; // Can only dynamically import one at a time, so break // out of the loop after the first. break; } } else { for (BundleRequirement req : revision.getDeclaredRequirements(null)) { String resolution = req.getDirectives().get(Constants.RESOLUTION_DIRECTIVE); if ((resolution == null) || !resolution.equals(FelixConstants.RESOLUTION_DYNAMIC)) { // Get the candidates for the current requirement. SortedSet candCaps = allCandidates.getCandidates((BundleRequirementImpl) req); // Optional requirements may not have any candidates. if (candCaps == null) { continue; } BundleCapability cap = candCaps.iterator().next(); reqs.add(req); caps.add(cap); } } } // First, add all exported packages to the target revision's package space. calculateExportedPackages(revision, allCandidates, revisionPkgMap); Packages revisionPkgs = revisionPkgMap.get(revision); // Second, add all imported packages to the target revision's package space. for (int i = 0; i < reqs.size(); i++) { BundleRequirement req = reqs.get(i); BundleCapability cap = caps.get(i); calculateExportedPackages(cap.getRevision(), allCandidates, revisionPkgMap); mergeCandidatePackages( revision, req, cap, revisionPkgMap, allCandidates, new HashMap>()); } // Third, have all candidates to calculate their package spaces. for (int i = 0; i < caps.size(); i++) { calculatePackageSpaces( caps.get(i).getRevision(), allCandidates, revisionPkgMap, usesCycleMap, cycle); } // Fourth, if the target revision is unresolved or is dynamically importing, // then add all the uses constraints implied by its imported and required // packages to its package space. // NOTE: We do not need to do this for resolved revisions because their // package space is consistent by definition and these uses constraints // are only needed to verify the consistency of a resolving revision. The // only exception is if a resolved revision is dynamically importing, then // we need to calculate its uses constraints again to make sure the new // import is consistent with the existing package space. if ((revision.getWiring() == null) || isDynamicImporting) { // Merge uses constraints from required capabilities. for (int i = 0; i < reqs.size(); i++) { BundleRequirement req = reqs.get(i); BundleCapability cap = caps.get(i); // Ignore bundle/package requirements, since they are // considered below. if (!req.getNamespace().equals(BundleRevision.BUNDLE_NAMESPACE) && !req.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)) { List blameReqs = new ArrayList(); blameReqs.add(req); mergeUses( revision, revisionPkgs, cap, blameReqs, revisionPkgMap, allCandidates, usesCycleMap); } } // Merge uses constraints from imported packages. for (Entry> entry : revisionPkgs.m_importedPkgs.entrySet()) { for (Blame blame : entry.getValue()) { // Ignore revisions that import from themselves. if (!blame.m_cap.getRevision().equals(revision)) { List blameReqs = new ArrayList(); blameReqs.add(blame.m_reqs.get(0)); mergeUses( revision, revisionPkgs, blame.m_cap, blameReqs, revisionPkgMap, allCandidates, usesCycleMap); } } } // Merge uses constraints from required bundles. for (Entry> entry : revisionPkgs.m_requiredPkgs.entrySet()) { for (Blame blame : entry.getValue()) { List blameReqs = new ArrayList(); blameReqs.add(blame.m_reqs.get(0)); mergeUses( revision, revisionPkgs, blame.m_cap, blameReqs, revisionPkgMap, allCandidates, usesCycleMap); } } } } private void mergeCandidatePackages( BundleRevision current, BundleRequirement currentReq, BundleCapability candCap, Map revisionPkgMap, Candidates allCandidates, Map> cycles) { List cycleCaps = cycles.get(current); if (cycleCaps == null) { cycleCaps = new ArrayList(); cycles.put(current, cycleCaps); } if (cycleCaps.contains(candCap)) { return; } cycleCaps.add(candCap); if (candCap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)) { mergeCandidatePackage( current, false, currentReq, candCap, revisionPkgMap); } else if (candCap.getNamespace().equals(BundleRevision.BUNDLE_NAMESPACE)) { // TODO: FELIX3 - THIS NEXT LINE IS A HACK. IMPROVE HOW/WHEN WE CALCULATE EXPORTS. calculateExportedPackages( candCap.getRevision(), allCandidates, revisionPkgMap); // Get the candidate's package space to determine which packages // will be visible to the current revision. Packages candPkgs = revisionPkgMap.get(candCap.getRevision()); // We have to merge all exported packages from the candidate, // since the current revision requires it. for (Entry entry : candPkgs.m_exportedPkgs.entrySet()) { mergeCandidatePackage( current, true, currentReq, entry.getValue().m_cap, revisionPkgMap); } // If the candidate requires any other bundles with reexport visibility, // then we also need to merge their packages too. if (candCap.getRevision().getWiring() != null) { for (BundleWire bw : candCap.getRevision().getWiring().getRequiredWires(null)) { if (bw.getRequirement().getNamespace() .equals(BundleRevision.BUNDLE_NAMESPACE)) { String value = bw.getRequirement() .getDirectives().get(Constants.VISIBILITY_DIRECTIVE); if ((value != null) && value.equals(Constants.VISIBILITY_REEXPORT)) { mergeCandidatePackages( current, currentReq, bw.getCapability(), revisionPkgMap, allCandidates, cycles); } } } } else { for (BundleRequirement req : candCap.getRevision().getDeclaredRequirements(null)) { if (req.getNamespace().equals(BundleRevision.BUNDLE_NAMESPACE)) { String value = req.getDirectives().get(Constants.VISIBILITY_DIRECTIVE); if ((value != null) && value.equals(Constants.VISIBILITY_REEXPORT) && (allCandidates.getCandidates(req) != null)) { mergeCandidatePackages( current, currentReq, allCandidates.getCandidates(req).iterator().next(), revisionPkgMap, allCandidates, cycles); } } } } } cycles.remove(current); } private void mergeCandidatePackage( BundleRevision current, boolean requires, BundleRequirement currentReq, BundleCapability candCap, Map revisionPkgMap) { if (candCap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)) { // Merge the candidate capability into the revision's package space // for imported or required packages, appropriately. String pkgName = (String) candCap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE); List blameReqs = new ArrayList(); blameReqs.add(currentReq); Packages currentPkgs = revisionPkgMap.get(current); Map> packages = (requires) ? currentPkgs.m_requiredPkgs : currentPkgs.m_importedPkgs; List blames = packages.get(pkgName); if (blames == null) { blames = new ArrayList(); packages.put(pkgName, blames); } blames.add(new Blame(candCap, blameReqs)); //dumpRevisionPkgs(current, currentPkgs); } } private void mergeUses( BundleRevision current, Packages currentPkgs, BundleCapability mergeCap, List blameReqs, Map revisionPkgMap, Candidates allCandidates, Map> cycleMap) { // If there are no uses, then just return. // If the candidate revision is the same as the current revision, // then we don't need to verify and merge the uses constraints // since this will happen as we build up the package space. if (current.equals(mergeCap.getRevision())) { return; } // Check for cycles. List list = cycleMap.get(mergeCap); if ((list != null) && list.contains(current)) { return; } list = (list == null) ? new ArrayList() : list; list.add(current); cycleMap.put(mergeCap, list); for (BundleCapability candSourceCap : getPackageSources(mergeCap, revisionPkgMap)) { for (String usedPkgName : ((BundleCapabilityImpl) candSourceCap).getUses()) { Packages candSourcePkgs = revisionPkgMap.get(candSourceCap.getRevision()); List candSourceBlames = null; // Check to see if the used package is exported. Blame candExportedBlame = candSourcePkgs.m_exportedPkgs.get(usedPkgName); if (candExportedBlame != null) { candSourceBlames = new ArrayList(1); candSourceBlames.add(candExportedBlame); } else { // If the used package is not exported, check to see if it // is required. candSourceBlames = candSourcePkgs.m_requiredPkgs.get(usedPkgName); // Lastly, if the used package is not required, check to see if it // is imported. candSourceBlames = (candSourceBlames != null) ? candSourceBlames : candSourcePkgs.m_importedPkgs.get(usedPkgName); } // If the used package cannot be found, then just ignore it // since it has no impact. if (candSourceBlames == null) { continue; } List usedCaps = currentPkgs.m_usedPkgs.get(usedPkgName); if (usedCaps == null) { usedCaps = new ArrayList(); currentPkgs.m_usedPkgs.put(usedPkgName, usedCaps); } for (Blame blame : candSourceBlames) { if (blame.m_reqs != null) { List blameReqs2 = new ArrayList(blameReqs); blameReqs2.add(blame.m_reqs.get(blame.m_reqs.size() - 1)); usedCaps.add(new Blame(blame.m_cap, blameReqs2)); mergeUses(current, currentPkgs, blame.m_cap, blameReqs2, revisionPkgMap, allCandidates, cycleMap); } else { usedCaps.add(new Blame(blame.m_cap, blameReqs)); mergeUses(current, currentPkgs, blame.m_cap, blameReqs, revisionPkgMap, allCandidates, cycleMap); } } } } } private void checkPackageSpaceConsistency( boolean isDynamicImporting, BundleRevision revision, Candidates allCandidates, Map revisionPkgMap, Map resultCache) { if ((revision.getWiring() != null) && !isDynamicImporting) { return; } else if(resultCache.containsKey(revision)) { return; } Packages pkgs = revisionPkgMap.get(revision); ResolveException rethrow = null; Candidates permutation = null; Set mutated = null; // Check for conflicting imports from fragments. for (Entry> entry : pkgs.m_importedPkgs.entrySet()) { if (entry.getValue().size() > 1) { Blame sourceBlame = null; for (Blame blame : entry.getValue()) { if (sourceBlame == null) { sourceBlame = blame; } else if (!sourceBlame.m_cap.getRevision().equals(blame.m_cap.getRevision())) { // Try to permutate the conflicting requirement. permutate(allCandidates, blame.m_reqs.get(0), m_importPermutations); // Try to permutate the source requirement. permutate(allCandidates, sourceBlame.m_reqs.get(0), m_importPermutations); // Report conflict. ResolveException ex = new ResolveException( "Uses constraint violation. Unable to resolve bundle revision " + revision.getSymbolicName() + " [" + revision + "] because it is exposed to package '" + entry.getKey() + "' from bundle revisions " + sourceBlame.m_cap.getRevision().getSymbolicName() + " [" + sourceBlame.m_cap.getRevision() + "] and " + blame.m_cap.getRevision().getSymbolicName() + " [" + blame.m_cap.getRevision() + "] via two dependency chains.\n\nChain 1:\n" + toStringBlame(sourceBlame) + "\n\nChain 2:\n" + toStringBlame(blame), revision, blame.m_reqs.get(0)); m_logger.log( Logger.LOG_DEBUG, "Candidate permutation failed due to a conflict with a " + "fragment import; will try another if possible.", ex); throw ex; } } } } for (Entry entry : pkgs.m_exportedPkgs.entrySet()) { String pkgName = entry.getKey(); Blame exportBlame = entry.getValue(); if (!pkgs.m_usedPkgs.containsKey(pkgName)) { continue; } for (Blame usedBlame : pkgs.m_usedPkgs.get(pkgName)) { if (!isCompatible(exportBlame.m_cap, usedBlame.m_cap, revisionPkgMap)) { // Create a candidate permutation that eliminates all candidates // that conflict with existing selected candidates. permutation = (permutation != null) ? permutation : allCandidates.copy(); rethrow = (rethrow != null) ? rethrow : new ResolveException( "Uses constraint violation. Unable to resolve bundle revision " + revision.getSymbolicName() + " [" + revision + "] because it exports package '" + pkgName + "' and is also exposed to it from bundle revision " + usedBlame.m_cap.getRevision().getSymbolicName() + " [" + usedBlame.m_cap.getRevision() + "] via the following dependency chain:\n\n" + toStringBlame(usedBlame), null, null); mutated = (mutated != null) ? mutated : new HashSet(); for (int reqIdx = usedBlame.m_reqs.size() - 1; reqIdx >= 0; reqIdx--) { BundleRequirement req = usedBlame.m_reqs.get(reqIdx); // If we've already permutated this requirement in another // uses constraint, don't permutate it again just continue // with the next uses constraint. if (mutated.contains(req)) { break; } // See if we can permutate the candidates for blamed // requirement; there may be no candidates if the revision // associated with the requirement is already resolved. SortedSet candidates = permutation.getCandidates(req); if ((candidates != null) && (candidates.size() > 1)) { mutated.add(req); Iterator it = candidates.iterator(); it.next(); it.remove(); // Continue with the next uses constraint. break; } } } } if (rethrow != null) { if (mutated.size() > 0) { m_usesPermutations.add(permutation); } m_logger.log( Logger.LOG_DEBUG, "Candidate permutation failed due to a conflict between " + "an export and import; will try another if possible.", rethrow); throw rethrow; } } // Check if there are any uses conflicts with imported packages. for (Entry> entry : pkgs.m_importedPkgs.entrySet()) { for (Blame importBlame : entry.getValue()) { String pkgName = entry.getKey(); if (!pkgs.m_usedPkgs.containsKey(pkgName)) { continue; } for (Blame usedBlame : pkgs.m_usedPkgs.get(pkgName)) { if (!isCompatible(importBlame.m_cap, usedBlame.m_cap, revisionPkgMap)) { // Create a candidate permutation that eliminates any candidates // that conflict with existing selected candidates. permutation = (permutation != null) ? permutation : allCandidates.copy(); rethrow = (rethrow != null) ? rethrow : new ResolveException( "Uses constraint violation. Unable to resolve bundle revision " + revision.getSymbolicName() + " [" + revision + "] because it is exposed to package '" + pkgName + "' from bundle revisions " + importBlame.m_cap.getRevision().getSymbolicName() + " [" + importBlame.m_cap.getRevision() + "] and " + usedBlame.m_cap.getRevision().getSymbolicName() + " [" + usedBlame.m_cap.getRevision() + "] via two dependency chains.\n\nChain 1:\n" + toStringBlame(importBlame) + "\n\nChain 2:\n" + toStringBlame(usedBlame), null, null); mutated = (mutated != null) ? mutated : new HashSet(); for (int reqIdx = usedBlame.m_reqs.size() - 1; reqIdx >= 0; reqIdx--) { BundleRequirement req = usedBlame.m_reqs.get(reqIdx); // If we've already permutated this requirement in another // uses constraint, don't permutate it again just continue // with the next uses constraint. if (mutated.contains(req)) { break; } // See if we can permutate the candidates for blamed // requirement; there may be no candidates if the revision // associated with the requirement is already resolved. SortedSet candidates = permutation.getCandidates(req); if ((candidates != null) && (candidates.size() > 1)) { mutated.add(req); Iterator it = candidates.iterator(); it.next(); it.remove(); // Continue with the next uses constraint. break; } } } } // If there was a uses conflict, then we should add a uses // permutation if we were able to permutate any candidates. // Additionally, we should try to push an import permutation // for the original import to force a backtracking on the // original candidate decision if no viable candidate is found // for the conflicting uses constraint. if (rethrow != null) { // Add uses permutation if we mutated any candidates. if (mutated.size() > 0) { m_usesPermutations.add(permutation); } // Try to permutate the candidate for the original // import requirement; only permutate it if we haven't // done so already. BundleRequirement req = importBlame.m_reqs.get(0); if (!mutated.contains(req)) { // Since there may be lots of uses constraint violations // with existing import decisions, we may end up trying // to permutate the same import a lot of times, so we should // try to check if that the case and only permutate it once. permutateIfNeeded(allCandidates, req, m_importPermutations); } m_logger.log( Logger.LOG_DEBUG, "Candidate permutation failed due to a conflict between " + "imports; will try another if possible.", rethrow); throw rethrow; } } } resultCache.put(revision, Boolean.TRUE); // Now check the consistency of all revisions on which the // current revision depends. Keep track of the current number // of permutations so we know if the lower level check was // able to create a permutation or not in the case of failure. int permCount = m_usesPermutations.size() + m_importPermutations.size(); for (Entry> entry : pkgs.m_importedPkgs.entrySet()) { for (Blame importBlame : entry.getValue()) { if (!revision.equals(importBlame.m_cap.getRevision())) { try { checkPackageSpaceConsistency( false, importBlame.m_cap.getRevision(), allCandidates, revisionPkgMap, resultCache); } catch (ResolveException ex) { // If the lower level check didn't create any permutations, // then we should create an import permutation for the // requirement with the dependency on the failing revision // to backtrack on our current candidate selection. if (permCount == (m_usesPermutations.size() + m_importPermutations.size())) { BundleRequirement req = importBlame.m_reqs.get(0); permutate(allCandidates, req, m_importPermutations); } throw ex; } } } } } private static void permutate( Candidates allCandidates, BundleRequirement req, List permutations) { SortedSet candidates = allCandidates.getCandidates(req); if (candidates.size() > 1) { Candidates perm = allCandidates.copy(); candidates = perm.getCandidates(req); Iterator it = candidates.iterator(); it.next(); it.remove(); permutations.add(perm); } } private static void permutateIfNeeded( Candidates allCandidates, BundleRequirement req, List permutations) { SortedSet candidates = allCandidates.getCandidates(req); if (candidates.size() > 1) { // Check existing permutations to make sure we haven't // already permutated this requirement. This check for // duplicate permutations is simplistic. It assumes if // there is any permutation that contains a different // initial candidate for the requirement in question, // then it has already been permutated. boolean permutated = false; for (Candidates existingPerm : permutations) { Set existingPermCands = existingPerm.getCandidates(req); if (!existingPermCands.iterator().next().equals(candidates.iterator().next())) { permutated = true; } } // If we haven't already permutated the existing // import, do so now. if (!permutated) { permutate(allCandidates, req, permutations); } } } private static void calculateExportedPackages( BundleRevision revision, Candidates allCandidates, Map revisionPkgMap) { Packages packages = revisionPkgMap.get(revision); if (packages != null) { return; } packages = new Packages(revision); // Get all exported packages. List caps = (revision.getWiring() != null) ? revision.getWiring().getCapabilities(null) : revision.getDeclaredCapabilities(null); Map exports = new HashMap(caps.size()); for (BundleCapability cap : caps) { if (cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)) { if (!cap.getRevision().equals(revision)) { cap = new HostedCapability(revision, (BundleCapabilityImpl) cap); } exports.put( (String) cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE), cap); } } // Remove substitutable exports that were imported. // For resolved revisions BundleWiring.getCapabilities() // already excludes imported substitutable exports, but // for resolving revisions we must look in the candidate // map to determine which exports are substitutable. if (!exports.isEmpty()) { if (revision.getWiring() == null) { for (BundleRequirement req : revision.getDeclaredRequirements(null)) { if (req.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)) { Set cands = allCandidates.getCandidates((BundleRequirementImpl) req); if ((cands != null) && !cands.isEmpty()) { String pkgName = (String) cands.iterator().next() .getAttributes().get(BundleRevision.PACKAGE_NAMESPACE); exports.remove(pkgName); } } } } // Add all non-substituted exports to the revisions's package space. for (Entry entry : exports.entrySet()) { packages.m_exportedPkgs.put( entry.getKey(), new Blame(entry.getValue(), null)); } } revisionPkgMap.put(revision, packages); } private boolean isCompatible( BundleCapability currentCap, BundleCapability candCap, Map revisionPkgMap) { if ((currentCap != null) && (candCap != null)) { if (currentCap.equals(candCap)) { return true; } List currentSources = getPackageSources( currentCap, revisionPkgMap); List candSources = getPackageSources( candCap, revisionPkgMap); return currentSources.containsAll(candSources) || candSources.containsAll(currentSources); } return true; } private Map> m_packageSourcesCache = new HashMap(); private List getPackageSources( BundleCapability cap, Map revisionPkgMap) { if (cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)) { List sources = m_packageSourcesCache.get(cap); if (sources == null) { sources = getPackageSourcesInternal( cap, revisionPkgMap, new ArrayList(), new HashSet()); m_packageSourcesCache.put(cap, sources); } return sources; } if (!((BundleCapabilityImpl) cap).getUses().isEmpty()) { List caps = new ArrayList(1); caps.add(cap); return caps; } return Collections.EMPTY_LIST; } private static List getPackageSourcesInternal( BundleCapability cap, Map revisionPkgMap, List sources, Set cycleMap) { if (cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)) { if (cycleMap.contains(cap)) { return sources; } cycleMap.add(cap); // Get the package name associated with the capability. String pkgName = cap.getAttributes() .get(BundleRevision.PACKAGE_NAMESPACE).toString(); // Since a revision can export the same package more than once, get // all package capabilities for the specified package name. List caps = (cap.getRevision().getWiring() != null) ? cap.getRevision().getWiring().getCapabilities(null) : cap.getRevision().getDeclaredCapabilities(null); for (int capIdx = 0; capIdx < caps.size(); capIdx++) { if (caps.get(capIdx).getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE) && caps.get(capIdx).getAttributes().get(BundleRevision.PACKAGE_NAMESPACE).equals(pkgName)) { sources.add(caps.get(capIdx)); } } // Then get any addition sources for the package from required bundles. Packages pkgs = revisionPkgMap.get(cap.getRevision()); List required = pkgs.m_requiredPkgs.get(pkgName); if (required != null) { for (Blame blame : required) { getPackageSourcesInternal(blame.m_cap, revisionPkgMap, sources, cycleMap); } } } return sources; } private static BundleRevision getActualBundleRevision(BundleRevision br) { if (br instanceof HostBundleRevision) { return ((HostBundleRevision) br).getHost(); } return br; } private static BundleCapability getActualCapability(BundleCapability c) { if (c instanceof HostedCapability) { return ((HostedCapability) c).getOriginalCapability(); } return c; } private static BundleRequirement getActualRequirement(BundleRequirement r) { if (r instanceof HostedRequirement) { return ((HostedRequirement) r).getOriginalRequirement(); } return r; } private static Map> populateWireMap( BundleRevision revision, Map revisionPkgMap, Map> wireMap, Candidates allCandidates) { BundleRevision unwrappedRevision = getActualBundleRevision(revision); if ((unwrappedRevision.getWiring() == null) && !wireMap.containsKey(unwrappedRevision)) { wireMap.put(unwrappedRevision, (List) Collections.EMPTY_LIST); List packageWires = new ArrayList(); List bundleWires = new ArrayList(); List capabilityWires = new ArrayList(); for (BundleRequirement req : revision.getDeclaredRequirements(null)) { SortedSet cands = allCandidates.getCandidates(req); if ((cands != null) && (cands.size() > 0)) { BundleCapability cand = cands.iterator().next(); // Ignore revisions that import themselves. if (!revision.equals(cand.getRevision())) { if (cand.getRevision().getWiring() == null) { populateWireMap(cand.getRevision(), revisionPkgMap, wireMap, allCandidates); } Packages candPkgs = revisionPkgMap.get(cand.getRevision()); ResolverWire wire = new ResolverWireImpl( unwrappedRevision, getActualRequirement(req), getActualBundleRevision(cand.getRevision()), getActualCapability(cand)); if (req.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)) { packageWires.add(wire); } else if (req.getNamespace().equals(BundleRevision.BUNDLE_NAMESPACE)) { bundleWires.add(wire); } else { capabilityWires.add(wire); } } } } // Combine package wires with require wires last. packageWires.addAll(bundleWires); packageWires.addAll(capabilityWires); wireMap.put(unwrappedRevision, packageWires); // Add host wire for any fragments. if (revision instanceof HostBundleRevision) { List fragments = ((HostBundleRevision) revision).getFragments(); for (BundleRevision fragment : fragments) { List hostWires = wireMap.get(fragment); if (hostWires == null) { hostWires = new ArrayList(); wireMap.put(fragment, hostWires); } hostWires.add( new ResolverWireImpl( getActualBundleRevision(fragment), fragment.getDeclaredRequirements( BundleRevision.HOST_NAMESPACE).get(0), unwrappedRevision, unwrappedRevision.getDeclaredCapabilities( BundleRevision.HOST_NAMESPACE).get(0))); } } } return wireMap; } private static Map> populateDynamicWireMap( BundleRevision revision, String pkgName, Map revisionPkgMap, Map> wireMap, Candidates allCandidates) { wireMap.put(revision, (List) Collections.EMPTY_LIST); List packageWires = new ArrayList(); BundleRequirement dynReq = null; BundleCapability dynCand = null; for (BundleRequirement req : Util.getDynamicRequirements(revision.getWiring().getRequirements(null))) { // Get the candidates for the current dynamic requirement. SortedSet candCaps = allCandidates.getCandidates((BundleRequirementImpl) req); // Optional requirements may not have any candidates. if ((candCaps == null) || candCaps.isEmpty()) { continue; } // Record the dynamic requirement. dynReq = req; dynCand = candCaps.first(); // Can only dynamically import one at a time, so break // out of the loop after the first. break; } if (dynReq != null) { if (dynCand.getRevision().getWiring() == null) { populateWireMap(dynCand.getRevision(), revisionPkgMap, wireMap, allCandidates); } Map attrs = new HashMap(1); attrs.put(BundleRevision.PACKAGE_NAMESPACE, pkgName); packageWires.add( new ResolverWireImpl( revision, dynReq, getActualBundleRevision(dynCand.getRevision()), getActualCapability(dynCand))); } wireMap.put(revision, packageWires); return wireMap; } private static void dumpRevisionPkgMap(Map revisionPkgMap) { System.out.println("+++BUNDLE REVISION PKG MAP+++"); for (Entry entry : revisionPkgMap.entrySet()) { dumpRevisionPkgs(entry.getKey(), entry.getValue()); } } private static void dumpRevisionPkgs(BundleRevision revision, Packages packages) { System.out.println(revision + " (" + ((revision.getWiring() != null) ? "RESOLVED)" : "UNRESOLVED)")); System.out.println(" EXPORTED"); for (Entry entry : packages.m_exportedPkgs.entrySet()) { System.out.println(" " + entry.getKey() + " - " + entry.getValue()); } System.out.println(" IMPORTED"); for (Entry> entry : packages.m_importedPkgs.entrySet()) { System.out.println(" " + entry.getKey() + " - " + entry.getValue()); } System.out.println(" REQUIRED"); for (Entry> entry : packages.m_requiredPkgs.entrySet()) { System.out.println(" " + entry.getKey() + " - " + entry.getValue()); } System.out.println(" USED"); for (Entry> entry : packages.m_usedPkgs.entrySet()) { System.out.println(" " + entry.getKey() + " - " + entry.getValue()); } } private static String toStringBlame(Blame blame) { StringBuffer sb = new StringBuffer(); if ((blame.m_reqs != null) && !blame.m_reqs.isEmpty()) { for (int i = 0; i < blame.m_reqs.size(); i++) { BundleRequirement req = blame.m_reqs.get(i); sb.append(" "); sb.append(req.getRevision().getSymbolicName()); sb.append(" ["); sb.append(req.getRevision().toString()); sb.append("]\n"); if (req.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)) { sb.append(" import: "); } else { sb.append(" require: "); } sb.append(((BundleRequirementImpl) req).getFilter().toString()); sb.append("\n |"); if (req.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)) { sb.append("\n export: "); } else { sb.append("\n provide: "); } if ((i + 1) < blame.m_reqs.size()) { BundleCapability cap = Util.getSatisfyingCapability( blame.m_reqs.get(i + 1).getRevision(), (BundleRequirementImpl) blame.m_reqs.get(i)); if (cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)) { sb.append(BundleRevision.PACKAGE_NAMESPACE); sb.append("="); sb.append(cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE).toString()); BundleCapability usedCap; if ((i + 2) < blame.m_reqs.size()) { usedCap = Util.getSatisfyingCapability( blame.m_reqs.get(i + 2).getRevision(), (BundleRequirementImpl) blame.m_reqs.get(i + 1)); } else { usedCap = Util.getSatisfyingCapability( blame.m_cap.getRevision(), (BundleRequirementImpl) blame.m_reqs.get(i + 1)); } sb.append("; uses:="); sb.append(usedCap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE)); } else { sb.append(cap); } sb.append("\n"); } else { BundleCapability export = Util.getSatisfyingCapability( blame.m_cap.getRevision(), (BundleRequirementImpl) blame.m_reqs.get(i)); sb.append(export.getNamespace()); sb.append("="); sb.append(export.getAttributes().get(export.getNamespace()).toString()); if (export.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE) && !export.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE) .equals(blame.m_cap.getAttributes().get( BundleRevision.PACKAGE_NAMESPACE))) { sb.append("; uses:="); sb.append(blame.m_cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE)); sb.append("\n export: "); sb.append(BundleRevision.PACKAGE_NAMESPACE); sb.append("="); sb.append(blame.m_cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE).toString()); } sb.append("\n "); sb.append(blame.m_cap.getRevision().getSymbolicName()); sb.append(" ["); sb.append(blame.m_cap.getRevision().toString()); sb.append("]"); } } } else { sb.append(blame.m_cap.getRevision().toString()); } return sb.toString(); } private static class Packages { private final BundleRevision m_revision; public final Map m_exportedPkgs = new HashMap(); public final Map> m_importedPkgs = new HashMap(); public final Map> m_requiredPkgs = new HashMap(); public final Map> m_usedPkgs = new HashMap(); public Packages(BundleRevision revision) { m_revision = revision; } } private static class Blame { public final BundleCapability m_cap; public final List m_reqs; public Blame(BundleCapability cap, List reqs) { m_cap = cap; m_reqs = reqs; } @Override public String toString() { return m_cap.getRevision() + "." + m_cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE) + (((m_reqs == null) || m_reqs.isEmpty()) ? " NO BLAME" : " BLAMED ON " + m_reqs); } @Override public boolean equals(Object o) { return (o instanceof Blame) && m_reqs.equals(((Blame) o).m_reqs) && m_cap.equals(((Blame) o).m_cap); } } }felix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/resolver/HostBundleRevision.java0000644000175000017500000001111111644651232033512 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework.resolver; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.apache.felix.framework.wiring.BundleCapabilityImpl; import org.apache.felix.framework.wiring.BundleRequirementImpl; import org.osgi.framework.Bundle; import org.osgi.framework.Version; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRequirement; import org.osgi.framework.wiring.BundleRevision; import org.osgi.framework.wiring.BundleWiring; class HostBundleRevision implements BundleRevision { private final BundleRevision m_host; private final List m_fragments; private List m_cachedCapabilities = null; private List m_cachedRequirements = null; public HostBundleRevision(BundleRevision host, List fragments) { m_host = host; m_fragments = fragments; } public BundleRevision getHost() { return m_host; } public List getFragments() { return m_fragments; } public String getSymbolicName() { return m_host.getSymbolicName(); } public Version getVersion() { throw new UnsupportedOperationException("Not supported yet."); } public List getDeclaredCapabilities(String namespace) { if (m_cachedCapabilities == null) { List caps = new ArrayList(); // Wrap host capabilities. for (BundleCapability cap : m_host.getDeclaredCapabilities(null)) { caps.add(new HostedCapability(this, (BundleCapabilityImpl) cap)); } // Wrap fragment capabilities. if (m_fragments != null) { for (BundleRevision fragment : m_fragments) { for (BundleCapability cap : fragment.getDeclaredCapabilities(null)) { // TODO: OSGi R4.4 - OSGi R4.4 may introduce an identity capability, if so // that will need to be excluded from here. caps.add(new HostedCapability(this, (BundleCapabilityImpl) cap)); } } } m_cachedCapabilities = Collections.unmodifiableList(caps); } return m_cachedCapabilities; } public List getDeclaredRequirements(String namespace) { if (m_cachedRequirements == null) { List reqs = new ArrayList(); // Wrap host requirements. for (BundleRequirement req : m_host.getDeclaredRequirements(null)) { reqs.add(new HostedRequirement(this, (BundleRequirementImpl) req)); } // Wrap fragment requirements. if (m_fragments != null) { for (BundleRevision fragment : m_fragments) { for (BundleRequirement req : fragment.getDeclaredRequirements(null)) { if (!req.getNamespace().equals(BundleRevision.HOST_NAMESPACE)) { reqs.add(new HostedRequirement(this, (BundleRequirementImpl) req)); } } } } m_cachedRequirements = Collections.unmodifiableList(reqs); } return m_cachedRequirements; } public int getTypes() { return m_host.getTypes(); } public BundleWiring getWiring() { return null; } public Bundle getBundle() { return m_host.getBundle(); } public String toString() { return m_host.toString(); } }././@LongLink0000000000000000000000000000015400000000000011565 Lustar rootrootfelix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/resolver/ResourceNotFoundException.javafelix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/resolver/ResourceNotFoundExcepti0000644000175000017500000000210711644651232033577 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework.resolver; public class ResourceNotFoundException extends Exception { public ResourceNotFoundException(String msg) { super(msg); } public ResourceNotFoundException(String msg, Throwable th) { super(msg, th); } }felix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/resolver/ResolveException.java0000644000175000017500000000306411644651232033232 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework.resolver; import org.osgi.framework.wiring.BundleRequirement; import org.osgi.framework.wiring.BundleRevision; public class ResolveException extends RuntimeException { private final BundleRevision m_revision; private final BundleRequirement m_req; /** * Constructs an instance of ResolveException with the specified detail message. * @param msg the detail message. */ public ResolveException(String msg, BundleRevision revision, BundleRequirement req) { super(msg); m_revision = revision; m_req = req; } public BundleRevision getRevision() { return m_revision; } public BundleRequirement getRequirement() { return m_req; } }felix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/resolver/HostedCapability.java0000644000175000017500000000635711644651232033174 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework.resolver; import java.util.List; import java.util.Map; import org.apache.felix.framework.wiring.BundleCapabilityImpl; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRevision; public class HostedCapability extends BundleCapabilityImpl { private final BundleRevision m_host; private final BundleCapabilityImpl m_cap; public HostedCapability(BundleRevision host, BundleCapabilityImpl cap) { super(host, cap.getNamespace(), cap.getDirectives(), cap.getAttributes()); m_host = host; m_cap = cap; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final HostedCapability other = (HostedCapability) obj; if (m_host != other.m_host && (m_host == null || !m_host.equals(other.m_host))) { return false; } if (m_cap != other.m_cap && (m_cap == null || !m_cap.equals(other.m_cap))) { return false; } return true; } @Override public int hashCode() { int hash = 7; hash = 37 * hash + (m_host != null ? m_host.hashCode() : 0); hash = 37 * hash + (m_cap != null ? m_cap.hashCode() : 0); return hash; } public BundleCapabilityImpl getOriginalCapability() { return m_cap; } @Override public BundleRevision getRevision() { return m_host; } @Override public String getNamespace() { return m_cap.getNamespace(); } @Override public Map getDirectives() { return m_cap.getDirectives(); } @Override public Map getAttributes() { return m_cap.getAttributes(); } @Override public List getUses() { return m_cap.getUses(); } @Override public String toString() { if (m_host == null) { return getAttributes().toString(); } if (getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)) { return "[" + m_host + "] " + getNamespace() + "; " + getAttributes().get(BundleRevision.PACKAGE_NAMESPACE); } return "[" + m_host + "] " + getNamespace() + "; " + getAttributes(); } }felix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/resolver/HostedRequirement.java0000644000175000017500000000576611644651232033416 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework.resolver; import java.util.Map; import org.apache.felix.framework.capabilityset.SimpleFilter; import org.apache.felix.framework.wiring.BundleRequirementImpl; import org.osgi.framework.wiring.BundleRevision; public class HostedRequirement extends BundleRequirementImpl { private final BundleRevision m_host; private final BundleRequirementImpl m_req; public HostedRequirement(BundleRevision host, BundleRequirementImpl req) { super(host, req.getNamespace(), req.getDirectives(), req.getAttributes()); m_host = host; m_req = req; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final HostedRequirement other = (HostedRequirement) obj; if (m_host != other.m_host && (m_host == null || !m_host.equals(other.m_host))) { return false; } if (m_req != other.m_req && (m_req == null || !m_req.equals(other.m_req))) { return false; } return true; } @Override public int hashCode() { int hash = 7; hash = 37 * hash + (m_host != null ? m_host.hashCode() : 0); hash = 37 * hash + (m_req != null ? m_req.hashCode() : 0); return hash; } public BundleRequirementImpl getOriginalRequirement() { return m_req; } @Override public BundleRevision getRevision() { return m_host; } @Override public String getNamespace() { return m_req.getNamespace(); } @Override public SimpleFilter getFilter() { return m_req.getFilter(); } @Override public boolean isOptional() { return m_req.isOptional(); } @Override public Map getDirectives() { return m_req.getDirectives(); } @Override public Map getAttributes() { return m_req.getAttributes(); } @Override public String toString() { return "[" + m_host + "] " + getNamespace() + "; " + getFilter().toString(); } }felix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/resolver/ResolverWireImpl.java0000644000175000017500000000361311644651232033206 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework.resolver; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRequirement; import org.osgi.framework.wiring.BundleRevision; class ResolverWireImpl implements ResolverWire { private final BundleRevision m_requirer; private final BundleRequirement m_req; private final BundleRevision m_provider; private final BundleCapability m_cap; public ResolverWireImpl( BundleRevision requirer, BundleRequirement req, BundleRevision provider, BundleCapability cap) { m_requirer = requirer; m_req = req; m_provider = provider; m_cap = cap; } public BundleRevision getRequirer() { return m_requirer; } public BundleRequirement getRequirement() { return m_req; } public BundleRevision getProvider() { return m_provider; } public BundleCapability getCapability() { return m_cap; } public String toString() { return m_req + " -> " + "[" + m_provider + "]"; } }felix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/FilterImpl.java0000644000175000017500000001641311644651232030144 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework; import java.util.Collection; import java.util.Collections; import java.util.Dictionary; import java.util.Enumeration; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.apache.felix.framework.ServiceRegistrationImpl.ServiceReferenceImpl; import org.apache.felix.framework.capabilityset.CapabilitySet; import org.apache.felix.framework.capabilityset.SimpleFilter; import org.apache.felix.framework.util.StringMap; import org.apache.felix.framework.wiring.BundleCapabilityImpl; import org.osgi.framework.Filter; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; import org.osgi.framework.wiring.BundleRevision; public class FilterImpl implements Filter { private final SimpleFilter m_filter; public FilterImpl(String filterStr) throws InvalidSyntaxException { try { m_filter = SimpleFilter.parse(filterStr); } catch (Throwable th) { throw new InvalidSyntaxException(th.getMessage(), filterStr); } } public boolean match(ServiceReference sr) { if (sr instanceof ServiceReferenceImpl) { return CapabilitySet.matches((ServiceReferenceImpl) sr, m_filter); } else { return CapabilitySet.matches(new WrapperCapability(sr), m_filter); } } public boolean match(Dictionary dctnr) { return CapabilitySet.matches(new WrapperCapability(dctnr, false), m_filter); } public boolean matchCase(Dictionary dctnr) { return CapabilitySet.matches(new WrapperCapability(dctnr, true), m_filter); } public boolean matches(Map map) { return CapabilitySet.matches(new WrapperCapability(map), m_filter); } public boolean equals(Object o) { return toString().equals(o.toString()); } public int hashCode() { return toString().hashCode(); } public String toString() { return m_filter.toString(); } static class WrapperCapability extends BundleCapabilityImpl { private final Map m_map; public WrapperCapability(Map map) { super(null, null, Collections.EMPTY_MAP, Collections.EMPTY_MAP); m_map = (map == null) ? Collections.EMPTY_MAP : map; } public WrapperCapability(Dictionary dict, boolean caseSensitive) { super(null, null, Collections.EMPTY_MAP, Collections.EMPTY_MAP); m_map = new DictionaryToMap(dict, caseSensitive); } public WrapperCapability(ServiceReference sr) { super(null, null, Collections.EMPTY_MAP, Collections.EMPTY_MAP); m_map = new StringMap(false); for (String key : sr.getPropertyKeys()) { m_map.put(key, sr.getProperty(key)); } } @Override public BundleRevision getRevision() { throw new UnsupportedOperationException("Not supported yet."); } @Override public String getNamespace() { throw new UnsupportedOperationException("Not supported yet."); } @Override public Map getDirectives() { throw new UnsupportedOperationException("Not supported yet."); } @Override public Map getAttributes() { return m_map; } @Override public List getUses() { throw new UnsupportedOperationException("Not supported yet."); } } private static class DictionaryToMap implements Map { private final Map m_map; private final Dictionary m_dict; public DictionaryToMap(Dictionary dict, boolean caseSensitive) { if (!caseSensitive) { m_dict = null; m_map = new StringMap(false); if (dict != null) { Enumeration keys = dict.keys(); while (keys.hasMoreElements()) { Object key = keys.nextElement(); if (m_map.get(key) == null) { m_map.put(key, dict.get(key)); } else { throw new IllegalArgumentException( "Duplicate attribute: " + key.toString()); } } } } else { m_dict = dict; m_map = null; } } public int size() { throw new UnsupportedOperationException("Not supported yet."); } public boolean isEmpty() { throw new UnsupportedOperationException("Not supported yet."); } public boolean containsKey(Object o) { throw new UnsupportedOperationException("Not supported yet."); } public boolean containsValue(Object o) { throw new UnsupportedOperationException("Not supported yet."); } public Object get(Object o) { if (m_dict != null) { return m_dict.get(o); } else if (m_map != null) { return m_map.get(o); } return null; } public Object put(Object k, Object v) { throw new UnsupportedOperationException("Not supported yet."); } public Object remove(Object o) { throw new UnsupportedOperationException("Not supported yet."); } public void putAll(Map map) { throw new UnsupportedOperationException("Not supported yet."); } public void clear() { throw new UnsupportedOperationException("Not supported yet."); } public Set keySet() { throw new UnsupportedOperationException("Not supported yet."); } public Collection values() { throw new UnsupportedOperationException("Not supported yet."); } public Set> entrySet() { return Collections.EMPTY_SET; } } }././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootfelix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/URLHandlersBundleURLConnection.javafelix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/URLHandlersBundleURLConnection.j0000644000175000017500000001637711644651232033276 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; import java.security.Permission; import org.apache.felix.framework.util.Util; import org.osgi.framework.Bundle; import org.osgi.framework.wiring.BundleRevision; import org.osgi.framework.wiring.BundleRevisions; import org.osgi.framework.wiring.BundleWiring; class URLHandlersBundleURLConnection extends URLConnection { private Felix m_framework; private BundleRevision m_targetRevision; private int m_classPathIdx = -1; private int m_contentLength; private long m_contentTime; private String m_contentType; private InputStream m_is; public URLHandlersBundleURLConnection(URL url) { super(url); } public URLHandlersBundleURLConnection(URL url, Felix framework) throws IOException { super(url); // If this is an attempt to create a connection to the root of // the bundle, then throw an exception since this isn't possible. // We only allow "/" as a valid URL so it can be used as context // for creating other URLs. String path = url.getPath(); if ((path == null) || (path.length() == 0) || path.equals("/")) { throw new IOException("Resource does not exist: " + url); } m_framework = framework; // If we don't have a framework instance, try to find // one from the call context. if (m_framework == null) { Object tmp = URLHandlers.getFrameworkFromContext(); if (tmp instanceof Felix) { m_framework = (Felix) tmp; } } // If there is still no framework, then error. if (m_framework == null) { throw new IOException("Unable to find framework for URL: " + url); } // Verify that the resource pointed to by the URL exists. // The URL is constructed like this: // bundle://:/ // Where = . long bundleId = Util.getBundleIdFromRevisionId(url.getHost()); Bundle bundle = m_framework.getBundle(bundleId); if (bundle == null) { throw new IOException("No bundle associated with resource: " + url); } m_contentTime = bundle.getLastModified(); // Get the bundle's revisions to find the target revision. BundleRevisions revisions = bundle.adapt(BundleRevisions.class); if ((revisions == null) || revisions.getRevisions().isEmpty()) { throw new IOException("Resource does not exist: " + url); } // Search for matching revision name. for (BundleRevision br : revisions.getRevisions()) { if (((BundleRevisionImpl) br).getId().equals(url.getHost())) { m_targetRevision = br; break; } } // If not found, assume the current revision. if (m_targetRevision == null) { m_targetRevision = revisions.getRevisions().get(0); } // If the resource cannot be found at the current class path index, // then search them all in order to see if it can be found. This is // necessary since the user might create a resource URL from another // resource URL and not realize they have the wrong class path entry. // Of course, this approach won't work in cases where there are multiple // resources with the same path, since it will always find the first // one on the class path. m_classPathIdx = url.getPort(); if (m_classPathIdx < 0) { m_classPathIdx = 0; } if (!((BundleRevisionImpl) m_targetRevision) .hasInputStream(m_classPathIdx, url.getPath())) { BundleWiring wiring = m_targetRevision.getWiring(); ClassLoader cl = (wiring != null) ? wiring.getClassLoader() : null; URL newurl = (cl != null) ? cl.getResource(url.getPath()) : null; if (newurl == null) { throw new IOException("Resource does not exist: " + url); } m_classPathIdx = newurl.getPort(); } } public synchronized void connect() throws IOException { if (!connected) { if ((m_targetRevision == null) || (m_classPathIdx < 0)) { throw new IOException("Resource does not exist: " + url); } m_is = ((BundleRevisionImpl) m_targetRevision).getInputStream(m_classPathIdx, url.getPath()); m_contentLength = (m_is == null) ? 0 : m_is.available(); m_contentType = URLConnection.guessContentTypeFromName(url.getFile()); connected = true; } } public InputStream getInputStream() throws IOException { connect(); return m_is; } public int getContentLength() { try { connect(); } catch(IOException ex) { return -1; } return m_contentLength; } public long getLastModified() { try { connect(); } catch(IOException ex) { return 0; } if (m_contentTime != -1L) { return m_contentTime; } else { return 0L; } } public String getContentType() { try { connect(); } catch (IOException ex) { return null; } return m_contentType; } public Permission getPermission() { // TODO: SECURITY - This should probably return a FilePermission // to access the bundle JAR file, but we don't have the // necessary information here to construct the absolute // path of the JAR file...so it would take some // re-arranging to get this to work. return null; } /** * Retrieve the entry as a URL using standard protocols such as file: and jar: * * @return the local URL */ URL getLocalURL() { if ((m_targetRevision == null) || (m_classPathIdx < 0)) { return url; } return ((BundleRevisionImpl) m_targetRevision).getLocalURL(m_classPathIdx, url.getPath()); } }felix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/URLHandlersActivator.java0000644000175000017500000000763011644651232032076 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework; import java.net.ContentHandler; import java.util.Arrays; import java.util.Collections; import java.util.Map; import java.util.Set; import org.apache.felix.framework.util.FelixConstants; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.osgi.service.url.URLStreamHandlerService; import org.osgi.util.tracker.ServiceTracker; /** *

* Simple activator class used by the system bundle to enable the * URL Handlers service. The only purpose of this class is to call * URLHandlers.registerInstance() when the framework is * started and URLHandlers.unregisterInstance() when the * framework is stopped. *

**/ class URLHandlersActivator implements BundleActivator { private final Map m_configMap; private final Felix m_framework; public URLHandlersActivator(Map configMap, Felix framework) { m_configMap = configMap; m_framework = framework; } // // Bundle activator methods. // public void start(BundleContext context) { // Only register the framework with the URL Handlers service // if the service is enabled. boolean enable = (m_configMap.get( FelixConstants.SERVICE_URLHANDLERS_PROP) == null) ? true : !m_configMap.get(FelixConstants.SERVICE_URLHANDLERS_PROP).equals("false"); if (enable) { m_framework.setURLHandlersActivator(this); } URLHandlers.registerFrameworkInstance(m_framework, enable); } public void stop(BundleContext context) { URLHandlers.unregisterFrameworkInstance(m_framework); m_framework.setURLHandlersActivator(null); } protected Object getStreamHandlerService(String protocol) { return get( m_framework.getHooks(URLStreamHandlerService.class), "url.handler.protocol", protocol); } protected Object getContentHandlerService(String mimeType) { return get( m_framework.getHooks(ContentHandler.class), "url.content.mimetype", mimeType); } private S get(Set> hooks, String key, String value) { Object service = null; if (!hooks.isEmpty()) { for (ServiceReference ref : hooks) { Object values = ref.getProperty(key); if (values instanceof String[]) { for (int valueIdx = 0; (valueIdx < ((String[]) values).length) && (service == null); valueIdx++) { if (value.equals(((String[]) values)[valueIdx])) { return m_framework.getService(m_framework, ref); } } } else if (value.equals(values)) { return m_framework.getService(m_framework, ref); } } } return null; } }felix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/BundleContextImpl.java0000644000175000017500000003664111644651232031502 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework; import java.io.File; import java.io.InputStream; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Dictionary; import org.apache.felix.framework.ext.FelixBundleContext; import org.osgi.framework.AdminPermission; import org.osgi.framework.Bundle; import org.osgi.framework.BundleException; import org.osgi.framework.BundleListener; import org.osgi.framework.Constants; import org.osgi.framework.Filter; import org.osgi.framework.FrameworkListener; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceListener; import org.osgi.framework.ServicePermission; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; import org.osgi.framework.SynchronousBundleListener; class BundleContextImpl implements FelixBundleContext { private Logger m_logger = null; private Felix m_felix = null; private BundleImpl m_bundle = null; private boolean m_valid = true; protected BundleContextImpl(Logger logger, Felix felix, BundleImpl bundle) { m_logger = logger; m_felix = felix; m_bundle = bundle; } protected void invalidate() { m_valid = false; } public void addRequirement(String s) throws BundleException { throw new BundleException("Not implemented yet."); } public void removeRequirement() throws BundleException { throw new BundleException("Not implemented yet."); } public void addCapability() throws BundleException { throw new BundleException("Not implemented yet."); } public void removeCapability() throws BundleException { throw new BundleException("Not implemented yet."); } public String getProperty(String name) { checkValidity(); // CONCURRENCY NOTE: This is a check-then-act situation, // but we ignore it since the time window is small and // the result is the same as if the calling thread had // won the race condition. Object sm = System.getSecurityManager(); if (sm != null) { if (!(Constants.FRAMEWORK_VERSION.equals(name) || Constants.FRAMEWORK_VENDOR.equals(name) || Constants.FRAMEWORK_LANGUAGE.equals(name)|| Constants.FRAMEWORK_OS_NAME.equals(name) || Constants.FRAMEWORK_OS_VERSION.equals(name) || Constants.FRAMEWORK_PROCESSOR.equals(name))) { ((SecurityManager) sm).checkPermission( new java.util.PropertyPermission(name, "read")); } } return m_felix.getProperty(name); } public Bundle getBundle() { checkValidity(); // CONCURRENCY NOTE: This is a check-then-act situation, // but we ignore it since the time window is small and // the result is the same as if the calling thread had // won the race condition. return m_bundle; } public Filter createFilter(String expr) throws InvalidSyntaxException { checkValidity(); // CONCURRENCY NOTE: This is a check-then-act situation, // but we ignore it since the time window is small and // the result is the same as if the calling thread had // won the race condition. return new FilterImpl(expr); } public Bundle installBundle(String location) throws BundleException { return installBundle(location, null); } public Bundle installBundle(String location, InputStream is) throws BundleException { checkValidity(); // CONCURRENCY NOTE: This is a check-then-act situation, // but we ignore it since the time window is small and // the result is the same as if the calling thread had // won the race condition. Bundle result = null; Object sm = System.getSecurityManager(); if (sm != null) { result = m_felix.installBundle(m_bundle, location, is); // Do check the bundle again in case that is was installed // already. ((SecurityManager) sm).checkPermission( new AdminPermission(result, AdminPermission.LIFECYCLE)); } else { result = m_felix.installBundle(m_bundle, location, is); } return result; } public Bundle getBundle(long id) { checkValidity(); // CONCURRENCY NOTE: This is a check-then-act situation, // but we ignore it since the time window is small and // the result is the same as if the calling thread had // won the race condition. return m_felix.getBundle(this, id); } public Bundle getBundle(String location) { checkValidity(); // CONCURRENCY NOTE: This is a check-then-act situation, // but we ignore it since the time window is small and // the result is the same as if the calling thread had // won the race condition. return m_felix.getBundle(location); } public Bundle[] getBundles() { checkValidity(); // CONCURRENCY NOTE: This is a check-then-act situation, // but we ignore it since the time window is small and // the result is the same as if the calling thread had // won the race condition. return m_felix.getBundles(this); } public void addBundleListener(BundleListener l) { checkValidity(); // CONCURRENCY NOTE: This is a check-then-act situation, but // internally the event dispatcher double checks whether or not // the bundle context is valid before adding the service listener // while holding the event queue lock, so it will either succeed // or fail. Object sm = System.getSecurityManager(); if (sm != null) { if (l instanceof SynchronousBundleListener) { ((SecurityManager) sm).checkPermission(new AdminPermission(m_bundle, AdminPermission.LISTENER)); } } m_felix.addBundleListener(m_bundle, l); } public void removeBundleListener(BundleListener l) { checkValidity(); // CONCURRENCY NOTE: This is a check-then-act situation, // but we ignore it since the time window is small and // the result is the same as if the calling thread had // won the race condition. Object sm = System.getSecurityManager(); if (sm != null) { if (l instanceof SynchronousBundleListener) { ((SecurityManager) sm).checkPermission(new AdminPermission(m_bundle, AdminPermission.LISTENER)); } } m_felix.removeBundleListener(m_bundle, l); } public void addServiceListener(ServiceListener l) { try { addServiceListener(l, null); } catch (InvalidSyntaxException ex) { // This will not happen since the filter is null. } } public void addServiceListener(ServiceListener l, String s) throws InvalidSyntaxException { checkValidity(); // CONCURRENCY NOTE: This is a check-then-act situation, but // internally the event dispatcher double checks whether or not // the bundle context is valid before adding the service listener // while holding the event queue lock, so it will either succeed // or fail. m_felix.addServiceListener(m_bundle, l, s); } public void removeServiceListener(ServiceListener l) { checkValidity(); // CONCURRENCY NOTE: This is a check-then-act situation, // but we ignore it since the time window is small and // the result is the same as if the calling thread had // won the race condition. m_felix.removeServiceListener(m_bundle, l); } public void addFrameworkListener(FrameworkListener l) { checkValidity(); // CONCURRENCY NOTE: This is a check-then-act situation, but // internally the event dispatcher double checks whether or not // the bundle context is valid before adding the service listener // while holding the event queue lock, so it will either succeed // or fail. m_felix.addFrameworkListener(m_bundle, l); } public void removeFrameworkListener(FrameworkListener l) { checkValidity(); // CONCURRENCY NOTE: This is a check-then-act situation, // but we ignore it since the time window is small and // the result is the same as if the calling thread had // won the race condition. m_felix.removeFrameworkListener(m_bundle, l); } public ServiceRegistration registerService( String clazz, Object svcObj, Dictionary dict) { return registerService(new String[] { clazz }, svcObj, dict); } public ServiceRegistration registerService( String[] clazzes, Object svcObj, Dictionary dict) { checkValidity(); // CONCURRENCY NOTE: This is a NOT a check-then-act situation, // because internally the framework acquires the bundle state // lock to ensure state consistency. Object sm = System.getSecurityManager(); if (sm != null) { if (clazzes != null) { for (int i = 0;i < clazzes.length;i++) { ((SecurityManager) sm).checkPermission( new ServicePermission(clazzes[i], ServicePermission.REGISTER)); } } } return m_felix.registerService(m_bundle, clazzes, svcObj, dict); } public ServiceRegistration registerService( Class clazz, S svcObj, Dictionary dict) { return (ServiceRegistration) registerService(new String[] { clazz.getName() }, svcObj, dict); } public ServiceReference getServiceReference(String clazz) { checkValidity(); // CONCURRENCY NOTE: This is a check-then-act situation, // but we ignore it since the time window is small and // the result is the same as if the calling thread had // won the race condition. try { ServiceReference[] refs = getServiceReferences(clazz, null); return getBestServiceReference(refs); } catch (InvalidSyntaxException ex) { m_logger.log(m_bundle, Logger.LOG_ERROR, "BundleContextImpl: " + ex); } return null; } public ServiceReference getServiceReference(Class clazz) { return (ServiceReference) getServiceReference(clazz.getName()); } private ServiceReference getBestServiceReference(ServiceReference[] refs) { if (refs == null) { return null; } if (refs.length == 1) { return refs[0]; } // Loop through all service references and return // the "best" one according to its rank and ID. ServiceReference bestRef = refs[0]; for (int i = 1; i < refs.length; i++) { if (bestRef.compareTo(refs[i]) < 0) { bestRef = refs[i]; } } return bestRef; } public ServiceReference[] getAllServiceReferences(String clazz, String filter) throws InvalidSyntaxException { checkValidity(); // CONCURRENCY NOTE: This is a check-then-act situation, // but we ignore it since the time window is small and // the result is the same as if the calling thread had // won the race condition. return m_felix.getAllowedServiceReferences(m_bundle, clazz, filter, false); } public ServiceReference[] getServiceReferences(String clazz, String filter) throws InvalidSyntaxException { checkValidity(); // CONCURRENCY NOTE: This is a check-then-act situation, // but we ignore it since the time window is small and // the result is the same as if the calling thread had // won the race condition. return m_felix.getAllowedServiceReferences(m_bundle, clazz, filter, true); } public Collection> getServiceReferences( Class clazz, String filter) throws InvalidSyntaxException { ServiceReference[] refs = (ServiceReference[]) getServiceReferences(clazz.getName(), filter); return (refs == null) ? Collections.EMPTY_LIST : (Collection>) Arrays.asList(refs); } public S getService(ServiceReference ref) { checkValidity(); // CONCURRENCY NOTE: This is a check-then-act situation, // but we ignore it since the time window is small and // the result is the same as if the calling thread had // won the race condition. if (ref == null) { throw new NullPointerException("Specified service reference cannot be null."); } Object sm = System.getSecurityManager(); if (sm != null) { ((SecurityManager) sm).checkPermission(new ServicePermission(ref, ServicePermission.GET)); } return m_felix.getService(m_bundle, ref); } public boolean ungetService(ServiceReference ref) { checkValidity(); // CONCURRENCY NOTE: This is a check-then-act situation, // but we ignore it since the time window is small and // the result is the same as if the calling thread had // won the race condition. if (ref == null) { throw new NullPointerException("Specified service reference cannot be null."); } // Unget the specified service. return m_felix.ungetService(m_bundle, ref); } public File getDataFile(String s) { checkValidity(); // CONCURRENCY NOTE: This is a check-then-act situation, // but we ignore it since the time window is small and // the result is the same as if the calling thread had // won the race condition. return m_felix.getDataFile(m_bundle, s); } private void checkValidity() { if (m_valid) { switch (m_bundle.getState()) { case Bundle.ACTIVE: case Bundle.STARTING: case Bundle.STOPPING: return; } } throw new IllegalStateException("Invalid BundleContext."); } }felix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/BundleImpl.java0000644000175000017500000011522411644651232030130 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.security.ProtectionDomain; import java.util.*; import org.apache.felix.framework.cache.BundleArchive; import org.apache.felix.framework.ext.SecurityProvider; import org.apache.felix.framework.util.SecurityManagerEx; import org.apache.felix.framework.util.StringMap; import org.apache.felix.framework.util.Util; import org.osgi.framework.AdaptPermission; import org.osgi.framework.AdminPermission; import org.osgi.framework.Bundle; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; import org.osgi.framework.Constants; import org.osgi.framework.ServicePermission; import org.osgi.framework.ServiceReference; import org.osgi.framework.Version; import org.osgi.framework.startlevel.BundleStartLevel; import org.osgi.framework.wiring.BundleRevision; import org.osgi.framework.wiring.BundleRevisions; import org.osgi.framework.wiring.BundleWire; import org.osgi.framework.wiring.BundleWiring; class BundleImpl implements Bundle, BundleRevisions { // No one should use this field directly, use getFramework() instead. private final Felix __m_felix; private final BundleArchive m_archive; private final List m_revisions = new ArrayList(0); private volatile int m_state; private boolean m_useDeclaredActivationPolicy; private BundleActivator m_activator = null; private volatile BundleContext m_context = null; private final Map m_cachedHeaders = new HashMap(); private long m_cachedHeadersTimestamp; // Indicates whether the bundle is stale, meaning that it has // been refreshed and completely removed from the framework. private boolean m_stale = false; // Used for bundle locking. private int m_lockCount = 0; private Thread m_lockThread = null; /** * This constructor is used by the system bundle (i.e., the framework), * since it needs a constructor that does not throw an exception. **/ BundleImpl() { __m_felix = null; m_archive = null; m_state = Bundle.INSTALLED; m_useDeclaredActivationPolicy = false; m_stale = false; m_activator = null; m_context = null; } BundleImpl(Felix felix, BundleArchive archive) throws Exception { __m_felix = felix; m_archive = archive; m_state = Bundle.INSTALLED; m_useDeclaredActivationPolicy = false; m_stale = false; m_activator = null; m_context = null; BundleRevision revision = createRevision(); addRevision(revision); } // This method exists because the system bundle extends BundleImpl // and cannot pass itself into the BundleImpl constructor. All methods // in BundleImpl should use this method to get the framework and should // not access the field directly. Felix getFramework() { return __m_felix; } BundleArchive getArchive() { return m_archive; } // Only called when the framework is stopping. Don't need to clean up dependencies. synchronized void close() { closeRevisions(); try { m_archive.close(); } catch (Exception ex) { getFramework().getLogger().log( this, Logger.LOG_ERROR, "Unable to close archive revisions.", ex); } } // Called when install fails, when stopping framework with uninstalled bundles, // and when refreshing an uninstalled bundle. Only need to clear up dependencies // for last case. synchronized void closeAndDelete() throws Exception { // Mark the bundle as stale, since it is being deleted. m_stale = true; // Close all revisions. closeRevisions(); // Delete bundle archive, which will close revisions. m_archive.closeAndDelete(); } // Called from BundleImpl.close(), BundleImpl.closeAndDelete(), and BundleImpl.refresh() private void closeRevisions() { // Remove the bundle's associated revisions from the resolver state // and close them. for (BundleRevision br : m_revisions) { // Remove the revision from the resolver state. getFramework().getResolver().removeRevision(br); // Close the revision's content. ((BundleRevisionImpl) br).close(); } } // Called when refreshing a bundle. Must clean up dependencies beforehand. synchronized void refresh() throws Exception { if (isExtension() && (getFramework().getState() != Bundle.STOPPING)) { getFramework().getLogger().log(this, Logger.LOG_WARNING, "Framework restart on extension bundle refresh not implemented."); } else { // Get current revision, since we can reuse it. BundleRevisionImpl current = (BundleRevisionImpl) adapt(BundleRevisionImpl.class); // Close all existing revisions. closeRevisions(); // Clear all revisions. m_revisions.clear(); // Purge all old archive revisions, only keeping the newest one. m_archive.purge(); // Reset the content of the current bundle revision. current.resetContent(m_archive.getCurrentRevision().getContent()); // Re-add the revision to the bundle. addRevision(current); // Reset the bundle state. m_state = Bundle.INSTALLED; m_stale = false; m_cachedHeaders.clear(); m_cachedHeadersTimestamp = 0; } } synchronized boolean isDeclaredActivationPolicyUsed() { return m_useDeclaredActivationPolicy; } synchronized void setDeclaredActivationPolicyUsed(boolean b) { m_useDeclaredActivationPolicy = b; } synchronized BundleActivator getActivator() { return m_activator; } synchronized void setActivator(BundleActivator activator) { m_activator = activator; } public BundleContext getBundleContext() { Object sm = System.getSecurityManager(); if (sm != null) { ((SecurityManager) sm).checkPermission( new AdminPermission(this, AdminPermission.CONTEXT)); } return m_context; } void setBundleContext(BundleContext context) { m_context = context; } public long getBundleId() { try { return m_archive.getId(); } catch (Exception ex) { getFramework().getLogger().log( this, Logger.LOG_ERROR, "Error getting the identifier from bundle archive.", ex); return -1; } } public URL getEntry(String name) { Object sm = System.getSecurityManager(); if (sm != null) { try { ((SecurityManager) sm).checkPermission(new AdminPermission(this, AdminPermission.RESOURCE)); } catch (Exception e) { return null; // No permission } } return getFramework().getBundleEntry(this, name); } public Enumeration getEntryPaths(String path) { Object sm = System.getSecurityManager(); if (sm != null) { try { ((SecurityManager) sm).checkPermission(new AdminPermission(this, AdminPermission.RESOURCE)); } catch (Exception e) { return null; // No permission } } return getFramework().getBundleEntryPaths(this, path); } public Enumeration findEntries(String path, String filePattern, boolean recurse) { Object sm = System.getSecurityManager(); if (sm != null) { try { ((SecurityManager) sm).checkPermission(new AdminPermission(this, AdminPermission.RESOURCE)); } catch (Exception e) { return null; // No permission } } return getFramework().findBundleEntries( adapt(BundleRevisionImpl.class), path, filePattern, recurse); } public Dictionary getHeaders() { return getHeaders(Locale.getDefault().toString()); } public Dictionary getHeaders(String locale) { Object sm = System.getSecurityManager(); if (sm != null) { ((SecurityManager) sm).checkPermission(new AdminPermission(this, AdminPermission.METADATA)); } if (locale == null) { locale = Locale.getDefault().toString(); } return getFramework().getBundleHeaders(this, locale); } Map getCurrentLocalizedHeader(String locale) { Map result = null; // Spec says empty local returns raw headers. if (locale.length() == 0) { result = new StringMap(adapt(BundleRevisionImpl.class).getHeaders(), false); } // If we have no result, try to get it from the cached headers. if (result == null) { synchronized (m_cachedHeaders) { // If the bundle is uninstalled, then the cached headers should // only contain the localized headers for the default locale at // the time of uninstall, so just return that. if (getState() == Bundle.UNINSTALLED) { result = (Map) m_cachedHeaders.values().iterator().next(); } // If the bundle has been updated, clear the cached headers. else if (getLastModified() > m_cachedHeadersTimestamp) { m_cachedHeaders.clear(); } // Otherwise, returned the cached headers if they exist. else { // Check if headers for this locale have already been resolved if (m_cachedHeaders.containsKey(locale)) { result = (Map) m_cachedHeaders.get(locale); } } } } // If the requested locale is not cached, then try to create it. if (result == null) { // Get a modifiable copy of the raw headers. Map headers = new StringMap(adapt(BundleRevisionImpl.class).getHeaders(), false); // Assume for now that this will be the result. result = headers; // Check to see if we actually need to localize anything boolean localize = false; for (Iterator it = headers.values().iterator(); !localize && it.hasNext(); ) { if (((String) it.next()).startsWith("%")) { localize = true; } } if (!localize) { // If localization is not needed, just cache the headers and return // them as-is. Not sure if this is useful updateHeaderCache(locale, headers); } else { // Do localization here and return the localized headers String basename = (String) headers.get(Constants.BUNDLE_LOCALIZATION); if (basename == null) { basename = Constants.BUNDLE_LOCALIZATION_DEFAULT_BASENAME; } // Create ordered list of revisions to search for localization // property resources. List revisionList = createLocalizationRevisionList( adapt(BundleRevisionImpl.class)); // Create ordered list of files to load properties from List resourceList = createLocalizationResourceList(basename, locale); // Create a merged props file with all available props for this locale boolean found = false; Properties mergedProperties = new Properties(); for (BundleRevision br : revisionList) { for (String res : resourceList) { URL temp = ((BundleRevisionImpl) br).getEntry(res + ".properties"); if (temp != null) { found = true; try { mergedProperties.load( temp.openConnection().getInputStream()); } catch (IOException ex) { // File doesn't exist, just continue loop } } } } // If the specified locale was not found, then the spec says we should // return the default localization. if (!found && !locale.equals(Locale.getDefault().toString())) { result = getCurrentLocalizedHeader(Locale.getDefault().toString()); } // Otherwise, perform the localization based on the discovered // properties and cache the result. else { // Resolve all localized header entries for (Iterator it = headers.entrySet().iterator(); it.hasNext(); ) { Map.Entry entry = (Map.Entry) it.next(); String value = (String) entry.getValue(); if (value.startsWith("%")) { String newvalue; String key = value.substring(value.indexOf("%") + 1); newvalue = mergedProperties.getProperty(key); if (newvalue==null) { newvalue = key; } entry.setValue(newvalue); } } updateHeaderCache(locale, headers); } } } return result; } private void updateHeaderCache(String locale, Map localizedHeaders) { synchronized (m_cachedHeaders) { m_cachedHeaders.put(locale, localizedHeaders); m_cachedHeadersTimestamp = System.currentTimeMillis(); } } private static List createLocalizationRevisionList(BundleRevision br) { // If the revision is a fragment, then we actually need // to search its host and associated fragments for its // localization information. So, check to see if there // are any hosts and then use the one with the highest // version instead of the fragment itself. If there are // no hosts, but the revision is a fragment, then just // search the revision itself. if (Util.isFragment(br)) { if (br.getWiring() != null) { List hostWires = br.getWiring().getRequiredWires(null); if ((hostWires != null) && (hostWires.size() > 0)) { br = hostWires.get(0).getProviderWiring().getRevision(); for (int hostIdx = 1; hostIdx < hostWires.size(); hostIdx++) { if (br.getVersion().compareTo( hostWires.get(hostIdx).getProviderWiring().getRevision().getVersion()) < 0) { br = hostWires.get(hostIdx).getProviderWiring().getRevision(); } } } } } // Create a list of the revision and any attached fragment revisions. List result = new ArrayList(); result.add(br); BundleWiring wiring = br.getWiring(); if (wiring != null) { List fragments = Util.getFragments(wiring); if (fragments != null) { result.addAll(fragments); } } return result; } private static List createLocalizationResourceList(String basename, String locale) { List result = new ArrayList(4); StringTokenizer tokens; StringBuffer tempLocale = new StringBuffer(basename); result.add(tempLocale.toString()); if (locale.length() > 0) { tokens = new StringTokenizer(locale, "_"); while (tokens.hasMoreTokens()) { tempLocale.append("_").append(tokens.nextToken()); result.add(tempLocale.toString()); } } return result; } public long getLastModified() { try { return m_archive.getLastModified(); } catch (Exception ex) { getFramework().getLogger().log( this, Logger.LOG_ERROR, "Error reading last modification time from bundle archive.", ex); return 0; } } void setLastModified(long l) { try { m_archive.setLastModified(l); } catch (Exception ex) { getFramework().getLogger().log( this, Logger.LOG_ERROR, "Error writing last modification time to bundle archive.", ex); } } public String getLocation() { Object sm = System.getSecurityManager(); if (sm != null) { ((SecurityManager) sm).checkPermission(new AdminPermission(this, AdminPermission.METADATA)); } return _getLocation(); } String _getLocation() { try { return m_archive.getLocation(); } catch (Exception ex) { getFramework().getLogger().log( this, Logger.LOG_ERROR, "Error getting location from bundle archive.", ex); return null; } } /** * Returns a URL to a named resource in the bundle. * * @return a URL to named resource, or null if not found. **/ public URL getResource(String name) { Object sm = System.getSecurityManager(); if (sm != null) { try { ((SecurityManager) sm).checkPermission( new AdminPermission(this, AdminPermission.RESOURCE)); } catch (Exception e) { return null; // No permission } } return getFramework().getBundleResource(this, name); } public Enumeration getResources(String name) throws IOException { Object sm = System.getSecurityManager(); if (sm != null) { try { ((SecurityManager) sm).checkPermission( new AdminPermission(this, AdminPermission.RESOURCE)); } catch (Exception e) { return null; // No permission } } // Spec says we should return null when resources not found, // even though ClassLoader.getResources() returns empty enumeration. Enumeration e = getFramework().getBundleResources(this, name); return ((e == null) || !e.hasMoreElements()) ? null : e; } /** * Returns an array of service references corresponding to * the bundle's registered services. * * @return an array of service references or null. **/ public ServiceReference[] getRegisteredServices() { Object sm = System.getSecurityManager(); if (sm != null) { ServiceReference[] refs = getFramework().getBundleRegisteredServices(this); if (refs == null) { return refs; } List result = new ArrayList(); for (int i = 0; i < refs.length; i++) { try { ((SecurityManager) sm).checkPermission(new ServicePermission( refs[i], ServicePermission.GET)); result.add(refs[i]); } catch (Exception ex) { // Silently ignore. } } if (result.isEmpty()) { return null; } return (ServiceReference[]) result.toArray(new ServiceReference[result.size()]); } else { return getFramework().getBundleRegisteredServices(this); } } public ServiceReference[] getServicesInUse() { Object sm = System.getSecurityManager(); if (sm != null) { ServiceReference[] refs = getFramework().getBundleServicesInUse(this); if (refs == null) { return refs; } List result = new ArrayList(); for (int i = 0; i < refs.length; i++) { try { ((SecurityManager) sm).checkPermission( new ServicePermission(refs[i], ServicePermission.GET)); result.add(refs[i]); } catch (Exception ex) { // Silently ignore. } } if (result.isEmpty()) { return null; } return (ServiceReference[]) result.toArray(new ServiceReference[result.size()]); } return getFramework().getBundleServicesInUse(this); } public int getState() { return m_state; } // This method should not be called directly. void __setState(int i) { m_state = i; } int getPersistentState() { try { return m_archive.getPersistentState(); } catch (Exception ex) { getFramework().getLogger().log( this, Logger.LOG_ERROR, "Error reading persistent state from bundle archive.", ex); return Bundle.INSTALLED; } } void setPersistentStateInactive() { try { m_archive.setPersistentState(Bundle.INSTALLED); } catch (Exception ex) { getFramework().getLogger().log(this, Logger.LOG_ERROR, "Error writing persistent state to bundle archive.", ex); } } void setPersistentStateActive() { try { m_archive.setPersistentState(Bundle.ACTIVE); } catch (Exception ex) { getFramework().getLogger().log( this, Logger.LOG_ERROR, "Error writing persistent state to bundle archive.", ex); } } void setPersistentStateStarting() { try { m_archive.setPersistentState(Bundle.STARTING); } catch (Exception ex) { getFramework().getLogger().log( this, Logger.LOG_ERROR, "Error writing persistent state to bundle archive.", ex); } } void setPersistentStateUninstalled() { try { m_archive.setPersistentState(Bundle.UNINSTALLED); } catch (Exception ex) { getFramework().getLogger().log( this, Logger.LOG_ERROR, "Error writing persistent state to bundle archive.", ex); } } int getStartLevel(int defaultLevel) { try { return m_archive.getStartLevel(); } catch (Exception ex) { getFramework().getLogger().log( this, Logger.LOG_ERROR, "Error reading start level from bundle archive.", ex); return defaultLevel; } } void setStartLevel(int i) { try { m_archive.setStartLevel(i); } catch (Exception ex) { getFramework().getLogger().log( this, Logger.LOG_ERROR, "Error writing start level to bundle archive.", ex); } } synchronized boolean isStale() { return m_stale; } synchronized boolean isExtension() { for (BundleRevision revision : m_revisions) { if (((BundleRevisionImpl) revision).isExtension()) { return true; } } return false; } public String getSymbolicName() { return adapt(BundleRevisionImpl.class).getSymbolicName(); } public Version getVersion() { return adapt(BundleRevisionImpl.class).getVersion(); } public boolean hasPermission(Object obj) { return getFramework().bundleHasPermission(this, obj); } public Map getSignerCertificates(int signersType) { // TODO: SECURITY - This needs to be adapted to our security mechanisms. return (Map) getFramework().getSignerMatcher(this, signersType); } public Class loadClass(String name) throws ClassNotFoundException { if (isExtension()) { throw new ClassNotFoundException("Extension bundles cannot load classes."); } Object sm = System.getSecurityManager(); if (sm != null) { try { ((SecurityManager) sm).checkPermission(new AdminPermission(this, AdminPermission.CLASS)); } catch (Exception ex) { throw new ClassNotFoundException("No permission.", ex); } } return getFramework().loadBundleClass(this, name); } public void start() throws BundleException { start(0); } public void start(int options) throws BundleException { Object sm = System.getSecurityManager(); if (sm != null) { ((SecurityManager) sm).checkPermission(new AdminPermission(this, AdminPermission.EXECUTE)); } getFramework().startBundle(this, options); } public void update() throws BundleException { update(null); } public void update(InputStream is) throws BundleException { Object sm = System.getSecurityManager(); if (sm != null) { ((SecurityManager) sm).checkPermission(new AdminPermission(this, AdminPermission.LIFECYCLE)); } getFramework().updateBundle(this, is); } public void stop() throws BundleException { stop(0); } public void stop(int options) throws BundleException { Object sm = System.getSecurityManager(); if (sm != null) { ((SecurityManager) sm).checkPermission(new AdminPermission(this, AdminPermission.EXECUTE)); } getFramework().stopBundle(this, ((options & Bundle.STOP_TRANSIENT) == 0)); } public void uninstall() throws BundleException { Object sm = System.getSecurityManager(); if (sm != null) { ((SecurityManager) sm).checkPermission(new AdminPermission(this, AdminPermission.LIFECYCLE)); } // After a bundle is uninstalled, the spec says getHeaders() should // return the localized headers for the default locale at the time of // of uninstall. So, let's clear the existing header cache to throw // away any other locales and populate it with the headers for the // default locale. We only do this if there are multiple cached locales // and if the default locale is not cached. If this method is called // more than once, then subsequent calls will do nothing here since // only the default locale will be left in the header cache. synchronized (m_cachedHeaders) { if ((m_cachedHeaders.size() > 1) || !m_cachedHeaders.containsKey(Locale.getDefault().toString())) { m_cachedHeaders.clear(); Map map = getCurrentLocalizedHeader(Locale.getDefault().toString()); } } // Uninstall the bundle. getFramework().uninstallBundle(this); } private static final SecurityManagerEx m_smEx = new SecurityManagerEx(); private static final ClassLoader m_classloader = Felix.class.getClassLoader(); void checkAdapt(Class type) { Object sm = System.getSecurityManager(); if ((sm != null) && (getFramework().getSecurityProvider() != null)) { Class caller = m_smEx.getClassContext()[3]; if (((Felix.m_secureAction.getClassLoader(caller) != m_classloader) || !caller.getName().startsWith("org.apache.felix.framework."))) { ((SecurityManager) sm).checkPermission( new AdaptPermission(type.getName(), this, AdaptPermission.ADAPT)); } } } public synchronized A adapt(Class type) { checkAdapt(type); if (type == BundleStartLevel.class) { return (A) getFramework().adapt(FrameworkStartLevelImpl.class) .createBundleStartLevel(this); } else if (type == BundleRevision.class) { if (m_state == Bundle.UNINSTALLED) { return null; } return (A) m_revisions.get(0); } // We need some way to get the current revision even if // the associated bundle is uninstalled, so we use the // impl revision class for this purpose. else if (type == BundleRevisionImpl.class) { return (A) m_revisions.get(0); } else if (type == BundleRevisions.class) { return (A) this; } else if (type == BundleWiring.class) { if (m_state == Bundle.UNINSTALLED) { return null; } return (A) m_revisions.get(0).getWiring(); } return null; } public File getDataFile(String filename) { throw new UnsupportedOperationException("Not supported yet."); } public int compareTo(Bundle t) { throw new UnsupportedOperationException("Not supported yet."); } public String toString() { String sym = getSymbolicName(); if (sym != null) { return sym + " [" + getBundleId() +"]"; } return "[" + getBundleId() +"]"; } synchronized boolean isRemovalPending() { return (m_state == Bundle.UNINSTALLED) || (m_revisions.size() > 1) || m_stale; } // // Revision management. // public Bundle getBundle() { return this; } public synchronized List getRevisions() { return new ArrayList(m_revisions); } /** * Determines if the specified module is associated with this bundle. * @param revision the module to determine if it is associate with this bundle. * @return true if the specified module is in the array of modules * associated with this bundle, false otherwise. **/ synchronized boolean hasRevision(BundleRevision revision) { return m_revisions.contains(revision); } synchronized void revise(String location, InputStream is) throws Exception { // This operation will increase the revision count for the bundle. m_archive.revise(location, is); try { BundleRevision revision = createRevision(); addRevision(revision); } catch (Exception ex) { m_archive.rollbackRevise(); throw ex; } } synchronized boolean rollbackRevise() throws Exception { boolean isExtension = isExtension(); BundleRevision br = m_revisions.remove(0); if (!isExtension) { // Since revising a bundle adds a revision to the global // state, we must remove it from the global state on rollback. getFramework().getResolver().removeRevision(br); } return m_archive.rollbackRevise(); } // This method should be private, but is visible because the // system bundle needs to add its revision directly to the bundle, // since it doesn't have an archive from which it will be created, // which is the normal case. synchronized void addRevision(BundleRevision revision) throws Exception { m_revisions.add(0, revision); // Set protection domain after adding the revision to the bundle, // since this requires that the bundle has a revision. ((BundleRevisionImpl) revision).setProtectionDomain( new BundleProtectionDomain(getFramework(), this)); SecurityProvider sp = getFramework().getSecurityProvider(); if ((sp != null) && (System.getSecurityManager() != null)) { try { sp.checkBundle(this); } catch (Exception ex) { m_revisions.remove(0); throw ex; } } // TODO: REFACTOR - consider nulling capabilities for extension bundles // so we don't need this check anymore. if (!isExtension()) { // Now that the revision is added to the bundle, we can update // the resolver's state to be aware of any new capabilities. getFramework().getResolver().addRevision(revision); } } private BundleRevision createRevision() throws Exception { // Get and parse the manifest from the most recent revision and // create an associated revision object for it. Map headerMap = m_archive.getCurrentRevision().getManifestHeader(); // Create the bundle revision instance. BundleRevisionImpl revision = new BundleRevisionImpl( this, Long.toString(getBundleId()) + "." + m_archive.getCurrentRevisionNumber().toString(), headerMap, m_archive.getCurrentRevision().getContent()); // For R4 bundles, verify that the bundle symbolic name + version // is unique unless this check has been disabled. String allowMultiple = (String) getFramework().getConfig().get(Constants.FRAMEWORK_BSNVERSION); allowMultiple = (allowMultiple == null) ? Constants.FRAMEWORK_BSNVERSION_SINGLE : allowMultiple; if (revision.getManifestVersion().equals("2") && !allowMultiple.equals(Constants.FRAMEWORK_BSNVERSION_MULTIPLE)) { Version bundleVersion = revision.getVersion(); bundleVersion = (bundleVersion == null) ? Version.emptyVersion : bundleVersion; String symName = revision.getSymbolicName(); Bundle[] bundles = getFramework().getBundles(); for (int i = 0; (bundles != null) && (i < bundles.length); i++) { long id = ((BundleImpl) bundles[i]).getBundleId(); if (id != getBundleId()) { String sym = bundles[i].getSymbolicName(); Version ver = bundles[i].getVersion(); if ((symName != null) && (sym != null) && symName.equals(sym) && bundleVersion.equals(ver)) { throw new BundleException( "Bundle symbolic name and version are not unique: " + sym + ':' + ver, BundleException.DUPLICATE_BUNDLE_ERROR); } } } } return revision; } synchronized ProtectionDomain getProtectionDomain() { ProtectionDomain pd = null; for (int i = m_revisions.size() - 1; (i >= 0) && (pd == null); i--) { pd = (ProtectionDomain) ((BundleRevisionImpl) m_revisions.get(i)).getProtectionDomain(); } return pd; } // // Locking related methods. // synchronized boolean isLockable() { return (m_lockCount == 0) || (m_lockThread == Thread.currentThread()); } synchronized Thread getLockingThread() { return m_lockThread; } synchronized void lock() { if ((m_lockCount > 0) && (m_lockThread != Thread.currentThread())) { throw new IllegalStateException("Bundle is locked by another thread."); } m_lockCount++; m_lockThread = Thread.currentThread(); } synchronized void unlock() { if (m_lockCount == 0) { throw new IllegalStateException("Bundle is not locked."); } if ((m_lockCount > 0) && (m_lockThread != Thread.currentThread())) { throw new IllegalStateException("Bundle is locked by another thread."); } m_lockCount--; if (m_lockCount == 0) { m_lockThread = null; } } BundleContext _getBundleContext() { return m_context; } }felix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/BundleProtectionDomain.java0000644000175000017500000000631611644651232032506 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework; import java.lang.ref.WeakReference; import java.net.MalformedURLException; import java.security.CodeSource; import java.security.Permission; import java.security.ProtectionDomain; import java.security.cert.Certificate; import org.osgi.framework.wiring.BundleRevision; public class BundleProtectionDomain extends ProtectionDomain { private final WeakReference m_felix; private final WeakReference m_bundle; private final int m_hashCode; private final String m_toString; private final WeakReference m_revision; // TODO: SECURITY - This should probably take a revision, not a bundle. BundleProtectionDomain(Felix felix, BundleImpl bundle) throws MalformedURLException { super( new CodeSource( Felix.m_secureAction.createURL( Felix.m_secureAction.createURL(null, "location:", new FakeURLStreamHandler()), bundle._getLocation(), new FakeURLStreamHandler() ), (Certificate[]) null), null); m_felix = new WeakReference(felix); m_bundle = new WeakReference(bundle); m_revision = new WeakReference(bundle.adapt(BundleRevision.class)); m_hashCode = bundle.hashCode(); m_toString = "[" + bundle + "]"; } BundleRevision getRevision() { return (BundleRevision) m_revision.get(); } public boolean implies(Permission permission) { Felix felix = (Felix) m_felix.get(); return (felix != null) ? felix.impliesBundlePermission(this, permission, false) : false; } public boolean impliesDirect(Permission permission) { Felix felix = (Felix) m_felix.get(); return (felix != null) ? felix.impliesBundlePermission(this, permission, true) : false; } BundleImpl getBundle() { return (BundleImpl) m_bundle.get(); } public int hashCode() { return m_hashCode; } public boolean equals(Object other) { if ((other == null) || (other.getClass() != BundleProtectionDomain.class)) { return false; } if (m_hashCode != other.hashCode()) { return false; } return m_bundle.get() == ((BundleProtectionDomain) other).m_bundle.get(); } public String toString() { return m_toString; } }felix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/FakeURLStreamHandler.java0000644000175000017500000000331211644651232031772 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework; import java.io.IOException; import java.net.*; /** * This class implements a fake stream handler. This class is necessary in * some cases when assigning CodeSources to classes in * BundleClassLoader. In general, the bundle location is an URL * and this URL is used as the code source for the bundle's associated * classes. The OSGi specification does not require that the bundle * location be an URL, though, so in that case we try to generate a * fake URL for the code source of the bundle, which is just the location * string prepended with the "location:" protocol, by default. We need * this fake handler to avoid an unknown protocol exception. **/ class FakeURLStreamHandler extends URLStreamHandler { protected URLConnection openConnection(URL url) throws IOException { throw new IOException("FakeURLStreamHandler can not be used!"); } } ././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootfelix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/URLHandlersContentHandlerProxy.javafelix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/URLHandlersContentHandlerProxy.j0000644000175000017500000001560611644651232033426 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework; import java.io.IOException; import java.net.ContentHandler; import java.net.ContentHandlerFactory; import java.net.URLConnection; import java.util.HashMap; import java.util.Map; import java.util.StringTokenizer; import org.apache.felix.framework.util.SecureAction; /** *

* This class implements a content handler proxy. When the content handler * proxy instance is created, it is associated with a particular mime type * and will answer all future requests for content of that type. It does * not directly handle the content requests, but delegates the requests to * an underlying content handler service. *

*

* The proxy for a particular mime type is used for all framework instances * that may contain their own content handler services. When performing a * content handler operation, the proxy retrieves the handler service from * the framework instance associated with the current call stack and delegates * the call to the handler service. *

*

* The proxy will create simple content handler service trackers for each * framework instance. The trackers will listen to service events in its * respective framework instance to maintain a reference to the "best" * content handler service at any given time. *

**/ class URLHandlersContentHandlerProxy extends ContentHandler { private static final Class[] STRING_TYPES = new Class[]{String.class}; private static final String CONTENT_HANDLER_PACKAGE_PROP = "java.content.handler.pkgs"; private static final String DEFAULT_CONTENT_HANDLER_PACKAGE = "sun.net.www.content|com.ibm.oti.net.www.content|gnu.java.net.content|org.apache.harmony.luni.internal.net.www.content|COM.newmonics.www.content"; private static final Map m_builtIn = new HashMap(); private static final String m_pkgs; static { String pkgs = new SecureAction().getSystemProperty(CONTENT_HANDLER_PACKAGE_PROP, ""); m_pkgs = (pkgs.equals("")) ? DEFAULT_CONTENT_HANDLER_PACKAGE : pkgs + "|" + DEFAULT_CONTENT_HANDLER_PACKAGE; } private final ContentHandlerFactory m_factory; private final String m_mimeType; private final SecureAction m_action; public URLHandlersContentHandlerProxy(String mimeType, SecureAction action, ContentHandlerFactory factory) { m_mimeType = mimeType; m_action = action; m_factory = factory; } // // ContentHandler interface method. // public Object getContent(URLConnection urlc) throws IOException { ContentHandler svc = getContentHandlerService(); if (svc == null) { return urlc.getInputStream(); } return svc.getContent(urlc); } /** *

* Private method to retrieve the content handler service from the * framework instance associated with the current call stack. A * simple service tracker is created and cached for the associated * framework instance when this method is called. *

* @return the content handler service from the framework instance * associated with the current call stack or null * is no service is available. **/ private ContentHandler getContentHandlerService() { // Get the framework instance associated with call stack. Object framework = URLHandlers.getFrameworkFromContext(); if (framework == null) { return getBuiltIn(); } try { ContentHandler service; if (framework instanceof Felix) { service = (ContentHandler) ((Felix) framework).getContentHandlerService(m_mimeType); } else { service = (ContentHandler) m_action.invoke( m_action.getMethod(framework.getClass(), "getContentHandlerService", STRING_TYPES), framework, new Object[]{m_mimeType}); } return (service == null) ? getBuiltIn() : service; } catch (Exception ex) { // TODO: log this or something ex.printStackTrace(); return null; } } private ContentHandler getBuiltIn() { synchronized (m_builtIn) { if (m_builtIn.containsKey(m_mimeType)) { return (ContentHandler) m_builtIn.get(m_mimeType); } } if (m_factory != null) { ContentHandler result = m_factory.createContentHandler(m_mimeType); if (result != null) { return addToCache(m_mimeType, result); } } // Check for built-in handlers for the mime type. // Remove periods, slashes, and dashes from mime type. String fixedType = m_mimeType.replace('.', '_').replace('/', '.').replace('-', '_'); // Iterate over built-in packages. StringTokenizer pkgTok = new StringTokenizer(m_pkgs, "| "); while (pkgTok.hasMoreTokens()) { String pkg = pkgTok.nextToken().trim(); String className = pkg + "." + fixedType; try { // If a built-in handler is found then cache and return it Class handler = m_action.forName(className); if (handler != null) { return addToCache(m_mimeType, (ContentHandler) handler.newInstance()); } } catch (Exception ex) { // This could be a class not found exception or an // instantiation exception, not much we can do in either // case other than ignore it. } } return addToCache(m_mimeType, null); } private synchronized ContentHandler addToCache(String mimeType, ContentHandler handler) { if (!m_builtIn.containsKey(mimeType)) { m_builtIn.put(mimeType, handler); return handler; } return (ContentHandler) m_builtIn.get(mimeType); } }felix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/FrameworkWiringImpl.java0000644000175000017500000001344211644651232032033 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.osgi.framework.AdminPermission; import org.osgi.framework.Bundle; import org.osgi.framework.FrameworkListener; import org.osgi.framework.ServiceRegistration; import org.osgi.framework.wiring.FrameworkWiring; import org.osgi.service.packageadmin.PackageAdmin; class FrameworkWiringImpl implements FrameworkWiring, Runnable { private final Felix m_felix; private final List> m_requests = new ArrayList(); private final List m_requestListeners = new ArrayList(); private final ServiceRegistration m_paReg; private Thread m_thread = null; public FrameworkWiringImpl(Felix felix, ServiceRegistry registry) { m_felix = felix; m_paReg = registry.registerService(felix, new String[] { PackageAdmin.class.getName() }, new PackageAdminImpl(felix), null); } /** * Stops the FelixFrameworkWiring thread on system shutdown. Shutting down the * thread explicitly is required in the embedded case, where Felix may be * stopped without the Java VM being stopped. In this case the * FelixFrameworkWiring thread must be stopped explicitly. *

* This method is called by the * {@link PackageAdminActivator#stop(BundleContext)} method. */ void stop() { synchronized (m_requests) { if (m_thread != null) { // Null thread variable to signal to the thread that // we want it to exit. m_thread = null; // Wake up the thread, if it is currently in the wait() state // for more work. m_requests.notifyAll(); } } } public Bundle getBundle() { return m_felix; } public void refreshBundles(Collection bundles, FrameworkListener... listeners) { Object sm = System.getSecurityManager(); if (sm != null) { ((SecurityManager) sm).checkPermission( new AdminPermission(m_felix, AdminPermission.RESOLVE)); } synchronized (m_requests) { // Start a thread to perform asynchronous package refreshes. if (m_thread == null) { m_thread = new Thread(this, "FelixFrameworkWiring"); m_thread.setDaemon(true); m_thread.start(); } // Queue request and notify thread. m_requests.add(bundles); m_requestListeners.add(listeners); m_requests.notifyAll(); } } public boolean resolveBundles(Collection bundles) { Object sm = System.getSecurityManager(); if (sm != null) { ((SecurityManager) sm).checkPermission( new AdminPermission(m_felix, AdminPermission.RESOLVE)); } return m_felix.resolveBundles(bundles); } public Collection getRemovalPendingBundles() { return m_felix.getRemovalPendingBundles(); } public Collection getDependencyClosure(Collection targets) { return m_felix.getDependencyClosure(targets); } /** * The OSGi specification states that package refreshes happen * asynchronously; this is the run() method for the package * refreshing thread. **/ public void run() { // This thread loops forever, thus it should // be a daemon thread. while (true) { Collection bundles = null; FrameworkListener[] listeners = null; synchronized (m_requests) { // Wait for a refresh request. while (m_requests.isEmpty()) { // Terminate the thread if requested to do so (see stop()). if (m_thread == null) { return; } try { m_requests.wait(); } catch (InterruptedException ex) { } } // Get the bundles parameter for the current refresh request. bundles = m_requests.get(0); listeners = m_requestListeners.get(0); } // Perform refresh. // NOTE: We don't catch any exceptions here, because // the invoked method shields us from exceptions by // catching Throwables when its invokes callbacks. m_felix.refreshPackages(bundles, listeners); // Remove the first request since it is now completed. synchronized (m_requests) { m_requests.remove(0); m_requestListeners.remove(0); } } } }felix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/BundleWiringImpl.java0000644000175000017500000032646611644651232031324 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.security.SecureClassLoader; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import java.util.TreeSet; import org.apache.felix.framework.cache.Content; import org.apache.felix.framework.cache.JarContent; import org.apache.felix.framework.capabilityset.SimpleFilter; import org.apache.felix.framework.resolver.ResolveException; import org.apache.felix.framework.resolver.ResourceNotFoundException; import org.apache.felix.framework.util.CompoundEnumeration; import org.apache.felix.framework.util.FelixConstants; import org.apache.felix.framework.util.SecurityManagerEx; import org.apache.felix.framework.util.Util; import org.apache.felix.framework.util.manifestparser.ManifestParser; import org.apache.felix.framework.util.manifestparser.R4Library; import org.apache.felix.framework.wiring.BundleRequirementImpl; import org.osgi.framework.Bundle; import org.osgi.framework.BundleException; import org.osgi.framework.BundleReference; import org.osgi.framework.CapabilityPermission; import org.osgi.framework.Constants; import org.osgi.framework.FrameworkEvent; import org.osgi.framework.PackagePermission; import org.osgi.framework.ServiceReference; import org.osgi.framework.hooks.weaving.WeavingException; import org.osgi.framework.hooks.weaving.WeavingHook; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRequirement; import org.osgi.framework.wiring.BundleRevision; import org.osgi.framework.wiring.BundleWire; import org.osgi.framework.wiring.BundleWiring; public class BundleWiringImpl implements BundleWiring { public final static int LISTRESOURCES_DEBUG = 1048576; public final static int EAGER_ACTIVATION = 0; public final static int LAZY_ACTIVATION = 1; private final Logger m_logger; private final Map m_configMap; private final StatefulResolver m_resolver; private final BundleRevisionImpl m_revision; private final List m_fragments; // Wire list is copy-on-write since it may change due to // dynamic imports. private volatile List m_wires; // Imported package map is copy-on-write since it may change // due to dynamic imports. private volatile Map m_importedPkgs; private final Map> m_requiredPkgs; private final List m_resolvedCaps; private final Map>> m_includedPkgFilters; private final Map>> m_excludedPkgFilters; private final List m_resolvedReqs; private final List m_resolvedNativeLibs; private final List m_fragmentContents; private volatile List m_wovenReqs = null; private BundleClassLoader m_classLoader; // Bundle-specific class loader for boot delegation. private final ClassLoader m_bootClassLoader; // Default class loader for boot delegation. private final static ClassLoader m_defBootClassLoader; // Statically define the default class loader for boot delegation. static { ClassLoader cl = null; try { Constructor ctor = BundleRevisionImpl.getSecureAction().getDeclaredConstructor( SecureClassLoader.class, new Class[] { ClassLoader.class }); BundleRevisionImpl.getSecureAction().setAccesssible(ctor); cl = (ClassLoader) BundleRevisionImpl.getSecureAction().invoke( ctor, new Object[] { null }); } catch (Throwable ex) { // On Android we get an exception if we set the parent class loader // to null, so we will work around that case by setting the parent // class loader to the system class loader in getClassLoader() below. cl = null; System.err.println("Problem creating boot delegation class loader: " + ex); } m_defBootClassLoader = cl; } // Boolean flag to enable/disable implicit boot delegation. private final boolean m_implicitBootDelegation; // Boolean flag to enable/disable local URLs. private final boolean m_useLocalURLs; // Re-usable security manager for accessing class context. private static SecurityManagerEx m_sm = new SecurityManagerEx(); // Thread local to detect class loading cycles. private final ThreadLocal m_cycleCheck = new ThreadLocal(); // Thread local to keep track of deferred activation. private static final ThreadLocal m_deferredActivation = new ThreadLocal(); // Flag indicating whether we are on an old JVM or not. private volatile static boolean m_isPreJava5 = false; // Flag indicating whether this wiring has been disposed. private volatile boolean m_isDisposed = false; BundleWiringImpl( Logger logger, Map configMap, StatefulResolver resolver, BundleRevisionImpl revision, List fragments, List wires, Map importedPkgs, Map> requiredPkgs) throws Exception { m_logger = logger; m_configMap = configMap; m_resolver = resolver; m_revision = revision; m_importedPkgs = importedPkgs; m_requiredPkgs = requiredPkgs; m_wires = Collections.unmodifiableList(wires); // We need to sort the fragments and add ourself as a dependent of each one. // We also need to create an array of fragment contents to attach to our // content path. List fragmentContents = null; if (fragments != null) { // Sort fragments according to ID order, if necessary. // Note that this sort order isn't 100% correct since // it uses a string, but it is likely close enough and // avoids having to create more objects. if (fragments.size() > 1) { SortedMap sorted = new TreeMap(); for (BundleRevision f : fragments) { sorted.put(((BundleRevisionImpl) f).getId(), f); } fragments = new ArrayList(sorted.values()); } fragmentContents = new ArrayList(fragments.size()); for (int i = 0; (fragments != null) && (i < fragments.size()); i++) { fragmentContents.add( ((BundleRevisionImpl) fragments.get(i)).getContent() .getEntryAsContent(FelixConstants.CLASS_PATH_DOT)); } } m_fragments = fragments; m_fragmentContents = fragmentContents; // Calculate resolved list of requirements, which includes: // 1. All requirements for which we have a wire. // 2. All dynamic imports from the host and any fragments. // Also create set of imported packages so we can eliminate any // substituted exports from our resolved capabilities. Set imports = new HashSet(); List reqList = new ArrayList(); // First add resolved requirements from wires. for (BundleWire bw : wires) { // Fragments may have multiple wires for the same requirement, so we // need to check for and avoid duplicates in that case. if (!bw.getRequirement().getNamespace().equals(BundleRevision.HOST_NAMESPACE) || !reqList.contains(bw.getRequirement())) { reqList.add(bw.getRequirement()); if (bw.getRequirement().getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)) { imports.add((String) bw.getCapability().getAttributes().get(BundleRevision.PACKAGE_NAMESPACE)); } } } // Next add dynamic requirements from host. for (BundleRequirement req : m_revision.getDeclaredRequirements(null)) { if (req.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)) { String resolution = req.getDirectives().get(Constants.RESOLUTION_DIRECTIVE); if ((resolution != null) && (resolution.equals("dynamic"))) { reqList.add(req); } } } // Finally, add dynamic requirements from fragments. if (m_fragments != null) { for (BundleRevision fragment : m_fragments) { for (BundleRequirement req : fragment.getDeclaredRequirements(null)) { if (req.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)) { String resolution = req.getDirectives().get(Constants.RESOLUTION_DIRECTIVE); if ((resolution != null) && (resolution.equals("dynamic"))) { reqList.add(req); } } } } } m_resolvedReqs = Collections.unmodifiableList(reqList); // Calculate resolved list of capabilities, which includes: // 1. All capabilities from host and any fragments except for exported // packages that we have an import (i.e., the export was substituted). // And nothing else at this time. Fragments currently have no capabilities. boolean isFragment = Util.isFragment(revision); List capList = (isFragment) ? Collections.EMPTY_LIST : new ArrayList(); // Also keep track of whether any resolved package capabilities are filtered. Map>> includedPkgFilters = new HashMap>>(); Map>> excludedPkgFilters = new HashMap>>(); // TODO: OSGi R4.4 - Fragments currently have no capabilities, but they may // have an identity capability in the future. if (!isFragment) { for (BundleCapability cap : m_revision.getDeclaredCapabilities(null)) { if (!cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE) || (cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE) && !imports.contains(cap.getAttributes() .get(BundleRevision.PACKAGE_NAMESPACE).toString()))) { // TODO: OSGi R4.4 - We may need to make this more flexible since in the future it may // be possible to consider other effective values via OBR's Environment.isEffective(). String effective = cap.getDirectives().get(Constants.EFFECTIVE_DIRECTIVE); if ((effective == null) || (effective.equals(Constants.EFFECTIVE_RESOLVE))) { capList.add(cap); if (cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)) { List> filters = parsePkgFilters(cap, Constants.INCLUDE_DIRECTIVE); if (filters != null) { includedPkgFilters.put((String) cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE), filters); } filters = parsePkgFilters(cap, Constants.EXCLUDE_DIRECTIVE); if (filters != null) { excludedPkgFilters.put((String) cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE), filters); } } } } } if (m_fragments != null) { for (BundleRevision fragment : m_fragments) { for (BundleCapability cap : fragment.getDeclaredCapabilities(null)) { // TODO: OSGi R4.4 - OSGi R4.4 may introduce an identity capability, if so // that will need to be excluded from here. if (!cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE) || (cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE) && !imports.contains(cap.getAttributes() .get(BundleRevision.PACKAGE_NAMESPACE).toString()))) { // TODO: OSGi R4.4 - We may need to make this more flexible since in the future it may // be possible to consider other effective values via OBR's Environment.isEffective(). String effective = cap.getDirectives().get(Constants.EFFECTIVE_DIRECTIVE); if ((effective == null) || (effective.equals(Constants.EFFECTIVE_RESOLVE))) { capList.add(cap); if (cap.getNamespace().equals( BundleRevision.PACKAGE_NAMESPACE)) { List> filters = parsePkgFilters( cap, Constants.INCLUDE_DIRECTIVE); if (filters != null) { includedPkgFilters.put((String) cap.getAttributes() .get(BundleRevision.PACKAGE_NAMESPACE), filters); } filters = parsePkgFilters(cap, Constants.EXCLUDE_DIRECTIVE); if (filters != null) { excludedPkgFilters.put((String) cap.getAttributes() .get(BundleRevision.PACKAGE_NAMESPACE), filters); } } } } } } } } if (System.getSecurityManager() != null) { for (Iterator iter = capList.iterator();iter.hasNext();) { BundleCapability cap = iter.next(); if (cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)) { if (!((BundleProtectionDomain) ((BundleRevisionImpl) cap.getRevision()).getProtectionDomain()).impliesDirect( new PackagePermission((String) cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE), PackagePermission.EXPORTONLY))) { iter.remove(); } } else if (!cap.getNamespace().equals(BundleRevision.HOST_NAMESPACE) && !cap.getNamespace().equals(BundleRevision.BUNDLE_NAMESPACE) && !cap.getNamespace().equals("osgi.ee")) { if (!((BundleProtectionDomain) ((BundleRevisionImpl) cap.getRevision()).getProtectionDomain()).impliesDirect( new CapabilityPermission(cap.getNamespace(), CapabilityPermission.PROVIDE))) { iter.remove(); } } } } m_resolvedCaps = Collections.unmodifiableList(capList); m_includedPkgFilters = (includedPkgFilters.isEmpty()) ? Collections.EMPTY_MAP : includedPkgFilters; m_excludedPkgFilters = (excludedPkgFilters.isEmpty()) ? Collections.EMPTY_MAP : excludedPkgFilters; List libList = (m_revision.getDeclaredNativeLibraries() == null) ? new ArrayList() : new ArrayList(m_revision.getDeclaredNativeLibraries()); for (int fragIdx = 0; (m_fragments != null) && (fragIdx < m_fragments.size()); fragIdx++) { List libs = ((BundleRevisionImpl) m_fragments.get(fragIdx)) .getDeclaredNativeLibraries(); for (int reqIdx = 0; (libs != null) && (reqIdx < libs.size()); reqIdx++) { libList.add(libs.get(reqIdx)); } } // We need to return null here if we don't have any libraries, since a // zero-length array is used to indicate that matching native libraries // could not be found when resolving the bundle. m_resolvedNativeLibs = (libList.isEmpty()) ? null : Collections.unmodifiableList(libList); ClassLoader bootLoader = m_defBootClassLoader; if (revision.getBundle().getBundleId() != 0) { Object map = m_configMap.get(FelixConstants.BOOT_CLASSLOADERS_PROP); if (map instanceof Map) { Object l = ((Map) map).get(m_revision.getBundle()); if (l instanceof ClassLoader) { bootLoader = (ClassLoader) l; } } } m_bootClassLoader = bootLoader; m_implicitBootDelegation = (m_configMap.get(FelixConstants.IMPLICIT_BOOT_DELEGATION_PROP) == null) || Boolean.valueOf( (String) m_configMap.get( FelixConstants.IMPLICIT_BOOT_DELEGATION_PROP)).booleanValue(); m_useLocalURLs = (m_configMap.get(FelixConstants.USE_LOCALURLS_PROP) == null) ? false : true; } private static List> parsePkgFilters(BundleCapability cap, String filtername) { List> filters = null; String include = cap.getDirectives().get(filtername); if (include != null) { List filterStrings = ManifestParser.parseDelimitedString(include, ","); filters = new ArrayList>(filterStrings.size()); for (int filterIdx = 0; filterIdx < filterStrings.size(); filterIdx++) { List substrings = SimpleFilter.parseSubstring(filterStrings.get(filterIdx)); filters.add(substrings); } } return filters; } public synchronized void dispose() { if (m_fragmentContents != null) { for (Content content : m_fragmentContents) { content.close(); } } m_classLoader = null; m_isDisposed = true; } // TODO: OSGi R4.3 - This really shouldn't be public, but it is needed by the // resolver to determine if a bundle can dynamically import. public boolean hasPackageSource(String pkgName) { return (m_importedPkgs.containsKey(pkgName) || m_requiredPkgs.containsKey(pkgName)); } // TODO: OSGi R4.3 - This really shouldn't be public, but it is needed by the // to implement dynamic imports. public BundleRevision getImportedPackageSource(String pkgName) { return m_importedPkgs.get(pkgName); } List getFragmentContents() { return m_fragmentContents; } public boolean isCurrent() { BundleRevision current = getBundle().adapt(BundleRevision.class); return (current != null) && (current.getWiring() == this); } public synchronized boolean isInUse() { return !m_isDisposed; } public List getCapabilities(String namespace) { if (isInUse()) { List result = m_resolvedCaps; if (namespace != null) { result = new ArrayList(); for (BundleCapability cap : m_resolvedCaps) { if (cap.getNamespace().equals(namespace)) { result.add(cap); } } } return result; } return null; } public List getRequirements(String namespace) { if (isInUse()) { List searchReqs = m_resolvedReqs; List wovenReqs = m_wovenReqs; List result = m_resolvedReqs; if (wovenReqs != null) { searchReqs = new ArrayList(m_resolvedReqs); searchReqs.addAll(wovenReqs); result = searchReqs; } if (namespace != null) { result = new ArrayList(); for (BundleRequirement req : searchReqs) { if (req.getNamespace().equals(namespace)) { result.add(req); } } } return result; } return null; } public List getNativeLibraries() { return m_resolvedNativeLibs; } public List getProvidedWires(String namespace) { if (isInUse()) { return ((BundleImpl) m_revision.getBundle()) .getFramework().getDependencies().getProvidedWires(m_revision, namespace); } return null; } public List getRequiredWires(String namespace) { if (isInUse()) { List result = m_wires; if (namespace != null) { result = new ArrayList(); for (BundleWire bw : m_wires) { if (bw.getRequirement().getNamespace().equals(namespace)) { result.add(bw); } } } return result; } return null; } public synchronized void addDynamicWire(BundleWire wire) { // Make new wires list. List wires = new ArrayList(m_wires); wires.add(wire); // Make new imported package map. Map importedPkgs = new HashMap(m_importedPkgs); importedPkgs.put( (String) wire.getCapability().getAttributes().get(BundleRevision.PACKAGE_NAMESPACE), wire.getProviderWiring().getRevision()); // Update associated member values. // Technically, there is a window here where readers won't see // both values updates at the same time, but it seems unlikely // to cause any issues. m_wires = Collections.unmodifiableList(wires); m_importedPkgs = importedPkgs; } public BundleRevision getRevision() { return m_revision; } public synchronized ClassLoader getClassLoader() { if (m_isDisposed) { return null; } if (m_classLoader == null) { // Determine which class loader to use based on which // Java platform we are running on. Class clazz; if (m_isPreJava5) { clazz = BundleClassLoader.class; } else { try { clazz = BundleClassLoaderJava5.class; } catch (Throwable th) { // If we are on pre-Java5 then we will get a verify error // here since we try to override a getResources() which is // a final method in pre-Java5. m_isPreJava5 = true; clazz = BundleClassLoader.class; } } // Use SecureAction to create the class loader if security is // enabled; otherwise, create it directly. try { Constructor ctor = (Constructor) BundleRevisionImpl.getSecureAction() .getConstructor(clazz, new Class[] { BundleWiringImpl.class, ClassLoader.class }); m_classLoader = (BundleClassLoader) BundleRevisionImpl.getSecureAction().invoke(ctor, new Object[] { this, determineParentClassLoader() }); } catch (Exception ex) { throw new RuntimeException("Unable to create module class loader: " + ex.getMessage() + " [" + ex.getClass().getName() + "]"); } } return m_classLoader; } public List findEntries(String path, String filePattern, int options) { if (isInUse()) { if (!Util.isFragment(m_revision)) { Enumeration e = ((BundleImpl) m_revision.getBundle()).getFramework() .findBundleEntries(m_revision, path, filePattern, (options & BundleWiring.FINDENTRIES_RECURSE) > 0); List entries = new ArrayList(); while ((e != null) && e.hasMoreElements()) { entries.add(e.nextElement()); } return Collections.unmodifiableList(entries); } return Collections.EMPTY_LIST; } return null; } // Thread local to detect class loading cycles. private final ThreadLocal m_listResourcesCycleCheck = new ThreadLocal(); // TODO: OSGi R4.3 - Should this be synchronized or should we take a snapshot? public synchronized Collection listResources( String path, String filePattern, int options) { // Implementation note: If you enable the DEBUG option for // listResources() to print from where each resource comes, // it will not give 100% accurate answers in the face of // Require-Bundle cycles with overlapping content since // the actual source will depend on who does the class load // first. Further, normal class loaders cache class load // results so it is always the same subsequently, but we // don't do that here so it will always return a different // result depending upon who is asking. Moral to the story: // don't do cycles and certainly don't do them with // overlapping content. Collection resources = null; // Normalize path. if ((path.length() > 0) && (path.charAt(0) == '/')) { path = path.substring(1); } if ((path.length() > 0) && (path.charAt(path.length() - 1) != '/')) { path = path + '/'; } // Parse the file filter. filePattern = (filePattern == null) ? "*" : filePattern; List pattern = SimpleFilter.parseSubstring(filePattern); // We build an internal collection of ResourceSources, since this // allows us to print out additional debug information. Collection sources = listResourcesInternal(path, pattern, options); if (sources != null) { boolean debug = (options & LISTRESOURCES_DEBUG) > 0; resources = new TreeSet(); for (ResourceSource source : sources) { if (debug) { resources.add(source.toString()); } else { resources.add(source.m_resource); } } } return resources; } private Collection listResourcesInternal( String path, List pattern, int options) { if (isInUse()) { boolean recurse = (options & BundleWiring.LISTRESOURCES_RECURSE) > 0; boolean localOnly = (options & BundleWiring.LISTRESOURCES_LOCAL) > 0; // Check for cycles, which can happen with Require-Bundle. Set cycles = (Set) m_listResourcesCycleCheck.get(); if (cycles == null) { cycles = new HashSet(); m_listResourcesCycleCheck.set(cycles); } if (cycles.contains(path)) { return Collections.EMPTY_LIST; } cycles.add(path); try { // Calculate set of remote resources (i.e., those either // imported or required). Collection remoteResources = new TreeSet(); // Imported packages cannot have merged content, so we need to // keep track of these packages. Set noMerging = new HashSet(); // Loop through wires to compute remote resources. for (BundleWire bw : m_wires) { if (bw.getCapability().getNamespace() .equals(BundleRevision.PACKAGE_NAMESPACE)) { // For imported packages, we only need to calculate // the remote resources of the specific imported package. remoteResources.addAll( calculateRemotePackageResources( bw, bw.getCapability(), recurse, path, pattern, noMerging)); } else if (bw.getCapability().getNamespace() .equals(BundleRevision.BUNDLE_NAMESPACE)) { // For required bundles, all declared package capabilities // from the required bundle will be available to requirers, // so get the target required bundle's declared packages // and handle them in a similar fashion to a normal import // except that their content can be merged with local // packages. List exports = bw.getProviderWiring().getRevision() .getDeclaredCapabilities(BundleRevision.PACKAGE_NAMESPACE); for (BundleCapability export : exports) { remoteResources.addAll( calculateRemotePackageResources( bw, export, recurse, path, pattern, null)); } // Since required bundle may reexport bundles it requires, // check its wires for this case. List requiredBundles = bw.getProviderWiring().getRequiredWires( BundleRevision.BUNDLE_NAMESPACE); for (BundleWire rbWire : requiredBundles) { String visibility = rbWire.getRequirement().getDirectives() .get(Constants.VISIBILITY_DIRECTIVE); if ((visibility != null) && (visibility.equals(Constants.VISIBILITY_REEXPORT))) { // For each reexported required bundle, treat them // in a similar fashion as a normal required bundle // by including all of their declared package // capabilities in the requiring bundle's class // space. List reexports = rbWire.getProviderWiring().getRevision() .getDeclaredCapabilities(BundleRevision.PACKAGE_NAMESPACE); for (BundleCapability reexport : reexports) { remoteResources.addAll( calculateRemotePackageResources( bw, reexport, recurse, path, pattern, null)); } } } } } // Calculate set of local resources (i.e., those contained // in the revision or its fragments). Collection localResources = new TreeSet(); // Get the revision's content path, which includes contents // from fragments. List contentPath = m_revision.getContentPath(); for (Content content : contentPath) { Enumeration e = content.getEntries(); if (e != null) { while (e.hasMoreElements()) { String resource = e.nextElement(); String resourcePath = getTrailingPath(resource); if (!noMerging.contains(resourcePath)) { if ((!recurse && resourcePath.equals(path)) || (recurse && resourcePath.startsWith(path))) { if (matchesPattern(pattern, getPathHead(resource))) { localResources.add( new ResourceSource(resource, m_revision)); } } } } } } if (localOnly) { return localResources; } else { remoteResources.addAll(localResources); return remoteResources; } } finally { cycles.remove(path); if (cycles.isEmpty()) { m_listResourcesCycleCheck.set(null); } } } return null; } private Collection calculateRemotePackageResources( BundleWire bw, BundleCapability cap, boolean recurse, String path, List pattern, Set noMerging) { Collection resources = Collections.EMPTY_SET; // Convert package name to a path. String subpath = (String) cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE); subpath = subpath.replace('.', '/') + '/'; // If necessary, record that this package should not be merged // with local content. if (noMerging != null) { noMerging.add(subpath); } // If we are not recuring, check for path equality or if // we are recursing, check that the subpath starts with // the target path. if ((!recurse && subpath.equals(path)) || (recurse && subpath.startsWith(path))) { // Delegate to the original provider wiring to have it calculate // the list of resources in the package. In this case, we don't // want to recurse since we want the precise package. resources = ((BundleWiringImpl) bw.getProviderWiring()).listResourcesInternal( subpath, pattern, 0); // The delegatedResources result will include subpackages // which need to be filtered out, since imported packages // do not give access to subpackages. If a subpackage is // imported, it will be added by its own wire. for (Iterator it = resources.iterator(); it.hasNext(); ) { ResourceSource reqResource = it.next(); if (reqResource.m_resource.charAt( reqResource.m_resource.length() - 1) == '/') { it.remove(); } } } // If we are not recursing, but the required package // is a child of the desired path, then include its // immediate child package. We do this so that it is // possible to use listResources() to walk the resource // tree similar to doing a directory walk one level // at a time. else if (!recurse && subpath.startsWith(path)) { int idx = subpath.indexOf('/', path.length()); if (idx >= 0) { subpath = subpath.substring(0, idx + 1); } if (matchesPattern(pattern, getPathHead(subpath))) { resources = Collections.singleton( new ResourceSource(subpath, bw.getProviderWiring().getRevision())); } } return resources; } private static String getPathHead(String resource) { if (resource.length() == 0) { return resource; } int idx = (resource.charAt(resource.length() - 1) == '/') ? resource.lastIndexOf('/', resource.length() - 2) : resource.lastIndexOf('/'); if (idx < 0) { return resource; } return resource.substring(idx + 1); } private static String getTrailingPath(String resource) { if (resource.length() == 0) { return null; } int idx = (resource.charAt(resource.length() - 1) == '/') ? resource.lastIndexOf('/', resource.length() - 2) : resource.lastIndexOf('/'); if (idx < 0) { return ""; } return resource.substring(0, idx + 1); } private static boolean matchesPattern(List pattern, String resource) { if (resource.charAt(resource.length() - 1) == '/') { resource = resource.substring(0, resource.length() - 1); } return SimpleFilter.compareSubstring(pattern, resource); } public Bundle getBundle() { return m_revision.getBundle(); } // // Class loader implementation methods. // private URL createURL(int port, String path) { // Add a slash if there is one already, otherwise // the is no slash separating the host from the file // in the resulting URL. if (!path.startsWith("/")) { path = "/" + path; } try { return BundleRevisionImpl.getSecureAction().createURL(null, FelixConstants.BUNDLE_URL_PROTOCOL + "://" + m_revision.getId() + ":" + port + path, ((BundleImpl) getBundle()).getFramework().getBundleStreamHandler()); } catch (MalformedURLException ex) { m_logger.log(m_revision.getBundle(), Logger.LOG_ERROR, "Unable to create resource URL.", ex); } return null; } public Enumeration getResourcesByDelegation(String name) { Set requestSet = (Set) m_cycleCheck.get(); if (requestSet == null) { requestSet = new HashSet(); m_cycleCheck.set(requestSet); } if (!requestSet.contains(name)) { requestSet.add(name); try { return findResourcesByDelegation(name); } finally { requestSet.remove(name); } } return null; } private Enumeration findResourcesByDelegation(String name) { Enumeration urls = null; List completeUrlList = new ArrayList(); // Get the package of the target class/resource. String pkgName = Util.getResourcePackage(name); // Delegate any packages listed in the boot delegation // property to the parent class loader. if (shouldBootDelegate(pkgName)) { try { // Get the appropriate class loader for delegation. ClassLoader bdcl = getBootDelegationClassLoader(); urls = bdcl.getResources(name); } catch (IOException ex) { // This shouldn't happen and even if it does, there // is nothing we can do, so just ignore it. } // If this is a java.* package, then always terminate the // search; otherwise, continue to look locally. if (pkgName.startsWith("java.")) { return urls; } completeUrlList.add(urls); } // Look in the revisions's imported packages. If the package is // imported, then we stop searching no matter the result since // imported packages cannot be split. BundleRevision provider = m_importedPkgs.get(pkgName); if (provider != null) { // Delegate to the provider revision. urls = ((BundleWiringImpl) provider.getWiring()).getResourcesByDelegation(name); // If we find any resources, then add them. if ((urls != null) && (urls.hasMoreElements())) { completeUrlList.add(urls); } // Always return here since imported packages cannot be split // across required bundles or the revision's content. return new CompoundEnumeration((Enumeration[]) completeUrlList.toArray(new Enumeration[completeUrlList.size()])); } // See whether we can get the resource from the required bundles and // regardless of whether or not this is the case continue to the next // step potentially passing on the result of this search (if any). List providers = m_requiredPkgs.get(pkgName); if (providers != null) { for (BundleRevision p : providers) { // Delegate to the provider revision. urls = ((BundleWiringImpl) p.getWiring()).getResourcesByDelegation(name); // If we find any resources, then add them. if ((urls != null) && (urls.hasMoreElements())) { completeUrlList.add(urls); } // Do not return here, since required packages can be split // across the revision's content. } } // Try the module's own class path. If we can find the resource then // return it together with the results from the other searches else // try to look into the dynamic imports. urls = m_revision.getResourcesLocal(name); if ((urls != null) && (urls.hasMoreElements())) { completeUrlList.add(urls); } else { // If not found, then try the module's dynamic imports. // At this point, the module's imports were searched and so was the // the module's content. Now we make an attempt to load the // class/resource via a dynamic import, if possible. try { provider = m_resolver.resolve(m_revision, pkgName); } catch (ResolveException ex) { // Ignore this since it is likely normal. } catch (BundleException ex) { // Ignore this since it is likely the result of a resolver hook. } if (provider != null) { // Delegate to the provider revision. urls = ((BundleWiringImpl) provider.getWiring()).getResourcesByDelegation(name); // If we find any resources, then add them. if ((urls != null) && (urls.hasMoreElements())) { completeUrlList.add(urls); } } } return new CompoundEnumeration((Enumeration[]) completeUrlList.toArray(new Enumeration[completeUrlList.size()])); } private ClassLoader determineParentClassLoader() { // Determine the class loader's parent based on the // configuration property; use boot class loader by // default. String cfg = (String) m_configMap.get(Constants.FRAMEWORK_BUNDLE_PARENT); cfg = (cfg == null) ? Constants.FRAMEWORK_BUNDLE_PARENT_BOOT : cfg; final ClassLoader parent; if (cfg.equalsIgnoreCase(Constants.FRAMEWORK_BUNDLE_PARENT_APP)) { parent = BundleRevisionImpl.getSecureAction().getSystemClassLoader(); } else if (cfg.equalsIgnoreCase(Constants.FRAMEWORK_BUNDLE_PARENT_EXT)) { parent = BundleRevisionImpl.getSecureAction().getParentClassLoader( BundleRevisionImpl.getSecureAction().getSystemClassLoader()); } else if (cfg.equalsIgnoreCase(Constants.FRAMEWORK_BUNDLE_PARENT_FRAMEWORK)) { parent = BundleRevisionImpl.getSecureAction() .getClassLoader(BundleRevisionImpl.class); } // On Android we cannot set the parent class loader to be null, so // we special case that situation here and set it to the system // class loader by default instead, which is not really spec. else if (m_bootClassLoader == null) { parent = BundleRevisionImpl.getSecureAction().getSystemClassLoader(); } else { parent = null; } return parent; } boolean shouldBootDelegate(String pkgName) { // Always boot delegate if the bundle has a configured // boot class loader. if (m_bootClassLoader != m_defBootClassLoader) { return true; } boolean result = false; // Only consider delegation if we have a package name, since // we don't want to promote the default package. The spec does // not take a stand on this issue. if (pkgName.length() > 0) { for (int i = 0; !result && (i < ((BundleImpl) getBundle()) .getFramework().getBootPackages().length); i++) { // Check if the boot package is wildcarded. // A wildcarded boot package will be in the form "foo.", // so a matching subpackage will start with "foo.", e.g., // "foo.bar". if (((BundleImpl) getBundle()).getFramework().getBootPackageWildcards()[i] && pkgName.startsWith( ((BundleImpl) getBundle()).getFramework().getBootPackages()[i])) { return true; } // If not wildcarded, then check for an exact match. else if (((BundleImpl) getBundle()) .getFramework().getBootPackages()[i].equals(pkgName)) { return true; } } } return result; } synchronized ClassLoader getBootDelegationClassLoader() { // Get the appropriate class loader for delegation. ClassLoader parent = (m_classLoader == null) ? determineParentClassLoader() : m_classLoader.getParent(); return (parent == null) ? m_bootClassLoader : parent; } private static final Constructor m_dexFileClassConstructor; private static final Method m_dexFileClassLoadDex; private static final Method m_dexFileClassLoadClass; static { Constructor dexFileClassConstructor = null; Method dexFileClassLoadDex = null; Method dexFileClassLoadClass = null; try { Class dexFileClass; try { dexFileClass = Class.forName("dalvik.system.DexFile"); } catch (Exception ex) { dexFileClass = Class.forName("android.dalvik.DexFile"); } try { dexFileClassLoadDex = dexFileClass.getMethod("loadDex", new Class[]{String.class, String.class, Integer.TYPE}); } catch (Exception ex) { // Nothing we need to do } dexFileClassConstructor = dexFileClass.getConstructor( new Class[] { java.io.File.class }); dexFileClassLoadClass = dexFileClass.getMethod("loadClass", new Class[] { String.class, ClassLoader.class }); } catch (Throwable ex) { dexFileClassConstructor = null; dexFileClassLoadDex = null; dexFileClassLoadClass = null; } m_dexFileClassConstructor = dexFileClassConstructor; m_dexFileClassLoadDex = dexFileClassLoadDex; m_dexFileClassLoadClass = dexFileClassLoadClass; } public Class getClassByDelegation(String name) throws ClassNotFoundException { // We do not call getClassLoader().loadClass() for arrays because // it does not correctly handle array types, which is necessary in // cases like deserialization using a wrapper class loader. if ((name != null) && (name.length() > 0) && (name.charAt(0) == '[')) { return Class.forName(name, false, getClassLoader()); } // Check to see if the requested class is filtered. if (isFiltered(name)) { throw new ClassNotFoundException(name); } return getClassLoader().loadClass(name); } private boolean isFiltered(String name) { String pkgName = Util.getClassPackage(name); List> includeFilters = m_includedPkgFilters.get(pkgName); List> excludeFilters = m_excludedPkgFilters.get(pkgName); if ((includeFilters == null) && (excludeFilters == null)) { return false; } // Get the class name portion of the target class. String className = Util.getClassName(name); // If there are no include filters then all classes are included // by default, otherwise try to find one match. boolean included = (includeFilters == null); for (int i = 0; (!included) && (includeFilters != null) && (i < includeFilters.size()); i++) { included = SimpleFilter.compareSubstring(includeFilters.get(i), className); } // If there are no exclude filters then no classes are excluded // by default, otherwise try to find one match. boolean excluded = false; for (int i = 0; (!excluded) && (excludeFilters != null) && (i < excludeFilters.size()); i++) { excluded = SimpleFilter.compareSubstring(excludeFilters.get(i), className); } return !included || excluded; } public URL getResourceByDelegation(String name) { try { return (URL) findClassOrResourceByDelegation(name, false); } catch (ClassNotFoundException ex) { // This should never be thrown because we are loading resources. } catch (ResourceNotFoundException ex) { m_logger.log(m_revision.getBundle(), Logger.LOG_DEBUG, ex.getMessage()); } return null; } private Object findClassOrResourceByDelegation(String name, boolean isClass) throws ClassNotFoundException, ResourceNotFoundException { Object result = null; Set requestSet = (Set) m_cycleCheck.get(); if (requestSet == null) { requestSet = new HashSet(); m_cycleCheck.set(requestSet); } if (requestSet.add(name)) { try { // Get the package of the target class/resource. String pkgName = (isClass) ? Util.getClassPackage(name) : Util.getResourcePackage(name); // Delegate any packages listed in the boot delegation // property to the parent class loader. if (shouldBootDelegate(pkgName)) { try { // Get the appropriate class loader for delegation. ClassLoader bdcl = getBootDelegationClassLoader(); result = (isClass) ? (Object) bdcl.loadClass(name) : (Object) bdcl.getResource(name); // If this is a java.* package, then always terminate the // search; otherwise, continue to look locally if not found. if (pkgName.startsWith("java.") || (result != null)) { return result; } } catch (ClassNotFoundException ex) { // If this is a java.* package, then always terminate the // search; otherwise, continue to look locally if not found. if (pkgName.startsWith("java.")) { throw ex; } } } // Look in the revision's imports. Note that the search may // be aborted if this method throws an exception, otherwise // it continues if a null is returned. result = searchImports(pkgName, name, isClass); // If not found, try the revision's own class path. if (result == null) { result = (isClass) ? (Object) ((BundleClassLoader) getClassLoader()).findClass(name) : (Object) m_revision.getResourceLocal(name); // If still not found, then try the revision's dynamic imports. if (result == null) { result = searchDynamicImports(pkgName, name, isClass); } } } finally { requestSet.remove(name); } } else { // If a cycle is detected, we should return null to break the // cycle. This should only ever be return to internal class // loading code and not to the actual instigator of the class load. return null; } if (result == null) { if (isClass) { throw new ClassNotFoundException( name + " not found by " + this.getBundle()); } else { throw new ResourceNotFoundException( name + " not found by " + this.getBundle()); } } return result; } private Object searchImports(String pkgName, String name, boolean isClass) throws ClassNotFoundException, ResourceNotFoundException { // Check if the package is imported. BundleRevision provider = m_importedPkgs.get(pkgName); if (provider != null) { // If we find the class or resource, then return it. Object result = (isClass) ? (Object) ((BundleWiringImpl) provider.getWiring()).getClassByDelegation(name) : (Object) ((BundleWiringImpl) provider.getWiring()).getResourceByDelegation(name); if (result != null) { return result; } // If no class or resource was found, then we must throw an exception // since the provider of this package did not contain the // requested class and imported packages are atomic. if (isClass) { throw new ClassNotFoundException(name); } throw new ResourceNotFoundException(name); } // Check if the package is required. List providers = m_requiredPkgs.get(pkgName); if (providers != null) { for (BundleRevision p : providers) { // If we find the class or resource, then return it. try { Object result = (isClass) ? (Object) ((BundleWiringImpl) p.getWiring()).getClassByDelegation(name) : (Object) ((BundleWiringImpl) p.getWiring()).getResourceByDelegation(name); if (result != null) { return result; } } catch (ClassNotFoundException ex) { // Since required packages can be split, don't throw an // exception here if it is not found. Instead, we'll just // continue searching other required bundles and the // revision's local content. } } } return null; } private Object searchDynamicImports( final String pkgName, final String name, final boolean isClass) throws ClassNotFoundException, ResourceNotFoundException { // At this point, the module's imports were searched and so was the // the module's content. Now we make an attempt to load the // class/resource via a dynamic import, if possible. BundleRevision provider = null; try { provider = m_resolver.resolve(m_revision, pkgName); } catch (ResolveException ex) { // Ignore this since it is likely normal. } catch (BundleException ex) { // Ignore this since it is likely the result of a resolver hook. } // If the dynamic import was successful, then this initial // time we must directly return the result from dynamically // created package sources, but subsequent requests for // classes/resources in the associated package will be // processed as part of normal static imports. if (provider != null) { // Return the class or resource. return (isClass) ? (Object) ((BundleWiringImpl) provider.getWiring()).getClassByDelegation(name) : (Object) ((BundleWiringImpl) provider.getWiring()).getResourceByDelegation(name); } // If implicit boot delegation is enabled, then try to guess whether // we should boot delegate. if (m_implicitBootDelegation) { // At this point, the class/resource could not be found by the bundle's // static or dynamic imports, nor its own content. Before we throw // an exception, we will try to determine if the instigator of the // class/resource load was a class from a bundle or not. This is necessary // because the specification mandates that classes on the class path // should be hidden (except for java.*), but it does allow for these // classes/resources to be exposed by the system bundle as an export. // However, in some situations classes on the class path make the faulty // assumption that they can access everything on the class path from // every other class loader that they come in contact with. This is // not true if the class loader in question is from a bundle. Thus, // this code tries to detect that situation. If the class instigating // the load request was NOT from a bundle, then we will make the // assumption that the caller actually wanted to use the parent class // loader and we will delegate to it. If the class was // from a bundle, then we will enforce strict class loading rules // for the bundle and throw an exception. // Get the class context to see the classes on the stack. final Class[] classes = m_sm.getClassContext(); try { if (System.getSecurityManager() != null) { return AccessController .doPrivileged(new PrivilegedExceptionAction() { public Object run() throws Exception { return doImplicitBootDelegation(classes, name, isClass); } }); } else { return doImplicitBootDelegation(classes, name, isClass); } } catch (PrivilegedActionException ex) { Exception cause = ex.getException(); if (cause instanceof ClassNotFoundException) { throw (ClassNotFoundException) cause; } else { throw (ResourceNotFoundException) cause; } } } return null; } private Object doImplicitBootDelegation(Class[] classes, String name, boolean isClass) throws ClassNotFoundException, ResourceNotFoundException { // Start from 1 to skip security manager class. for (int i = 1; i < classes.length; i++) { // Find the first class on the call stack that is not from // the class loader that loaded the Felix classes or is not // a class loader or class itself, because we want to ignore // calls to ClassLoader.loadClass() and Class.forName() since // we are trying to find out who instigated the class load. // Also ignore inner classes of class loaders, since we can // assume they are a class loader too. // TODO: FRAMEWORK - This check is a hack and we should see if we can think // of another way to do it, since it won't necessarily work in all situations. // Since Felix uses threads for changing the start level // and refreshing packages, it is possible that there are no // bundle classes on the call stack; therefore, as soon as we // see Thread on the call stack we exit this loop. Other cases // where bundles actually use threads are not an issue because // the bundle classes will be on the call stack before the // Thread class. if (Thread.class.equals(classes[i])) { break; } // Break if the current class came from a bundle, since we should // not implicitly boot delegate in that case. else if (isClassLoadedFromBundleRevision(classes[i])) { break; } // Break if this goes through BundleImpl because it must be a call // to Bundle.loadClass() which should not implicitly boot delegate. else if (BundleImpl.class.equals(classes[i])) { break; } else if (isClassExternal(classes[i])) { try { // Return the class or resource from the parent class loader. return (isClass) ? (Object) BundleRevisionImpl.getSecureAction() .getClassLoader(this.getClass()).loadClass(name) : (Object) BundleRevisionImpl.getSecureAction() .getClassLoader(this.getClass()).getResource(name); } catch (NoClassDefFoundError ex) { // Ignore, will return null } break; } } return null; } private boolean isClassLoadedFromBundleRevision(Class clazz) { // The target class is loaded by a bundle class loader, // then return true. if (BundleClassLoader.class.isInstance( BundleRevisionImpl.getSecureAction().getClassLoader(clazz))) { return true; } // If the target class was loaded from a class loader that // came from a bundle, then return true. ClassLoader last = null; for (ClassLoader cl = BundleRevisionImpl.getSecureAction().getClassLoader(clazz); (cl != null) && (last != cl); cl = BundleRevisionImpl.getSecureAction().getClassLoader(cl.getClass())) { last = cl; if (BundleClassLoader.class.isInstance(cl)) { return true; } } return false; } /** * Tries to determine whether the given class is part of the framework or not. * Framework classes include everything in org.apache.felix.framework.* and * org.osgi.framework.*. We also consider ClassLoader and Class to be internal * classes, because they are inserted into the stack trace as a result of * method overloading. Typically, ClassLoader or Class will be mixed in * between framework classes or will be at the point where the class loading * request enters the framework class loading mechanism, which will then be * followed by either bundle or external code, which will then exit our * attempt to determine if we should boot delegate or not. Other standard * class loaders, like URLClassLoader, are considered external classes and * should trigger boot delegation. This means that bundles can create standard * class loaders to get access to boot packages, but this is the standard * behavior of class loaders. * @param clazz the class to determine if it is external or not. * @return true if the class is external, otherwise false. */ private boolean isClassExternal(Class clazz) { if (clazz.getName().startsWith("org.apache.felix.framework.")) { return false; } else if (clazz.getName().startsWith("org.osgi.framework.")) { return false; } else if (ClassLoader.class.equals(clazz)) { return false; } else if (Class.class.equals(clazz)) { return false; } return true; } static class ToLocalUrlEnumeration implements Enumeration { final Enumeration m_enumeration; ToLocalUrlEnumeration(Enumeration enumeration) { m_enumeration = enumeration; } public boolean hasMoreElements() { return m_enumeration.hasMoreElements(); } public Object nextElement() { return convertToLocalUrl((URL) m_enumeration.nextElement()); } } public class BundleClassLoaderJava5 extends BundleClassLoader { public BundleClassLoaderJava5(ClassLoader parent) { super(parent); } @Override public Enumeration getResources(String name) { Enumeration urls = BundleWiringImpl.this.getResourcesByDelegation(name); if (m_useLocalURLs) { urls = new ToLocalUrlEnumeration(urls); } return urls; } @Override protected Enumeration findResources(String name) { return m_revision.getResourcesLocal(name); } } public class BundleClassLoader extends SecureClassLoader implements BundleReference { // Flag used to determine if a class has been loaded from this class // loader or not. private volatile boolean m_isActivationTriggered = false; private final Map m_jarContentToDexFile; private Object[][] m_cachedLibs = new Object[0][]; private static final int LIBNAME_IDX = 0; private static final int LIBPATH_IDX = 1; public BundleClassLoader(ClassLoader parent) { super(parent); if (m_dexFileClassLoadClass != null) { m_jarContentToDexFile = new HashMap(); } else { m_jarContentToDexFile = null; } } public boolean isActivationTriggered() { return m_isActivationTriggered; } public Bundle getBundle() { return BundleWiringImpl.this.getBundle(); } @Override protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { Class clazz = null; // Make sure the class was not already loaded. synchronized (this) { clazz = findLoadedClass(name); } if (clazz == null) { try { clazz = (Class) findClassOrResourceByDelegation(name, true); } catch (ResourceNotFoundException ex) { // This should never happen since we are asking for a class, // so just ignore it. } catch (ClassNotFoundException cnfe) { ClassNotFoundException ex = cnfe; String msg = name; if (m_logger.getLogLevel() >= Logger.LOG_DEBUG) { msg = diagnoseClassLoadError(m_resolver, m_revision, name); ex = (msg != null) ? new ClassNotFoundException(msg, cnfe) : ex; } throw ex; } } // Resolve the class and return it. if (resolve) { resolveClass(clazz); } return clazz; } @Override protected Class findClass(String name) throws ClassNotFoundException { Class clazz = null; // Search for class in bundle revision. if (clazz == null) { String actual = name.replace('.', '/') + ".class"; byte[] bytes = null; // Check the bundle class path. List contentPath = m_revision.getContentPath(); Content content = null; for (int i = 0; (bytes == null) && (i < contentPath.size()); i++) { bytes = contentPath.get(i).getEntryAsBytes(actual); content = contentPath.get(i); } if (bytes != null) { // Get package name. String pkgName = Util.getClassPackage(name); // Get weaving hooks and invoke them to give them a // chance to weave the class' byte code before we // define it. // NOTE: We don't try to dynamically track hook addition // or removal, we just get a snapshot and leave any changes // as a race condition, doing any necessary clean up in // the error handling. Felix felix = ((BundleImpl) m_revision.getBundle()).getFramework(); Set> hooks = felix.getHooks(WeavingHook.class); WovenClassImpl wci = null; if (!hooks.isEmpty()) { // Create woven class to be used for hooks. wci = new WovenClassImpl(name, BundleWiringImpl.this, bytes); // Loop through hooks in service ranking order. for (ServiceReference sr : hooks) { // Only use the hook if it is not black listed. if (!felix.isHookBlackListed(sr)) { // Get the hook service object. // Note that we don't use the bundle context // to get the service object since that would // perform sercurity checks. WeavingHook wh = felix.getService(felix, sr); if (wh != null) { try { m_revision.getSecureAction() .invokeWeavingHook(wh, wci); } catch (Throwable th) { if (!(th instanceof WeavingException)) { felix.blackListHook(sr); } felix.fireFrameworkEvent( FrameworkEvent.ERROR, sr.getBundle(), th); // Mark the woven class as incomplete. wci.complete(null, null, null); // Throw class format exception per spec. Error error = new ClassFormatError("Weaving hook failed."); error.initCause(th); throw error; } finally { felix.ungetService(felix, sr); } } } } } // Before we actually attempt to define the class, grab // the lock for this class loader and make sure than no // other thread has defined this class in the meantime. synchronized (this) { byte[] wovenBytes = null; Class wovenClass = null; List wovenImports = null; try { clazz = findLoadedClass(name); if (clazz == null) { // If we have a woven class then get the class bytes from // it since they may have changed. // NOTE: We are taking a snapshot of these values and // are not preventing a malbehaving weaving hook from // modifying them after the fact. The price of preventing // this isn't worth it, since they can already wreck // havoc via weaving anyway. However, we do pass the // snapshot values into the woven class when we mark it // as complete so that it will refect the actual values // we used to define the class. if (wci != null) { bytes = wovenBytes = wci._getBytes(); wovenImports = wci.getDynamicImportsInternal(); // Try to add any woven dynamic imports, since they // could potentially be needed when defining the class. List allWovenReqs = new ArrayList(); for (String s : wovenImports) { try { List wovenReqs = ManifestParser.parseDynamicImportHeader( m_logger, m_revision, s); allWovenReqs.addAll(wovenReqs); } catch (BundleException ex) { // There should be no exception here // since we checked syntax before adding // dynamic import strings to list. } } // Add the dynamic requirements. if (!allWovenReqs.isEmpty()) { // Check for duplicate woven imports. // First grab existing woven imports, if any. Set filters = new HashSet(); if (m_wovenReqs != null) { for (BundleRequirement req : m_wovenReqs) { filters.add( ((BundleRequirementImpl) req) .getFilter().toString()); } } // Then check new woven imports for duplicates // against existing and self. int idx = allWovenReqs.size(); while (idx < allWovenReqs.size()) { BundleRequirement wovenReq = allWovenReqs.get(idx); String filter = ((BundleRequirementImpl) wovenReq).getFilter().toString(); if (!filters.contains(filter)) { filters.add(filter); idx++; } else { allWovenReqs.remove(idx); } } // Merge existing with new imports, if any. if (!allWovenReqs.isEmpty()) { if (m_wovenReqs != null) { allWovenReqs.addAll(0, m_wovenReqs); } m_wovenReqs = allWovenReqs; } } } int activationPolicy = ((BundleImpl) getBundle()).isDeclaredActivationPolicyUsed() ? ((BundleRevisionImpl) getBundle() .adapt(BundleRevision.class)).getDeclaredActivationPolicy() : EAGER_ACTIVATION; // If the revision is using deferred activation, then if // we load this class from this revision we need to activate // the bundle before returning the class. We will short // circuit the trigger matching if the trigger is already // tripped. boolean isTriggerClass = m_isActivationTriggered ? false : m_revision.isActivationTrigger(pkgName); if (!m_isActivationTriggered && isTriggerClass && (activationPolicy == BundleRevisionImpl.LAZY_ACTIVATION) && (getBundle().getState() == Bundle.STARTING)) { List deferredList = (List) m_deferredActivation.get(); if (deferredList == null) { deferredList = new ArrayList(); m_deferredActivation.set(deferredList); } deferredList.add(new Object[] { name, getBundle() }); } // We need to try to define a Package object for the class // before we call defineClass() if we haven't already // created it. if (pkgName.length() > 0) { if (getPackage(pkgName) == null) { Object[] params = definePackage(pkgName); if (params != null) { definePackage( pkgName, (String) params[0], (String) params[1], (String) params[2], (String) params[3], (String) params[4], (String) params[5], null); } else { definePackage(pkgName, null, null, null, null, null, null, null); } } } // If we can load the class from a dex file do so if (content instanceof JarContent) { try { clazz = getDexFileClass((JarContent) content, name, this); } catch (Exception ex) { // Looks like we can't } } if (clazz == null) { // If we have a security context, then use it to // define the class with it for security purposes, // otherwise define the class without a protection domain. if (m_revision.getProtectionDomain() != null) { clazz = defineClass(name, bytes, 0, bytes.length, m_revision.getProtectionDomain()); } else { clazz = defineClass(name, bytes, 0, bytes.length); } wovenClass = clazz; } // At this point if we have a trigger class, then the deferred // activation trigger has tripped. if (!m_isActivationTriggered && isTriggerClass && (clazz != null)) { m_isActivationTriggered = true; } } } finally { // If we have a woven class, mark it as complete. // Not exactly clear how we should deal with the // case where the weaving didn't happen because // someone else beat us in defining the class. if (wci != null) { wci.complete(wovenClass, wovenBytes, wovenImports); } } } // Perform deferred activation without holding the class loader lock, // if the class we are returning is the instigating class. List deferredList = (List) m_deferredActivation.get(); if ((deferredList != null) && (deferredList.size() > 0) && ((Object[]) deferredList.get(0))[0].equals(name)) { for (int i = deferredList.size() - 1; i >= 0; i--) { try { felix.getFramework().activateBundle( (BundleImpl) ((Object[]) deferredList.get(i))[1], true); } catch (BundleException ex) { ex.printStackTrace(); } } deferredList.clear(); } } } return clazz; } private Object[] definePackage(String pkgName) { String spectitle = (String) m_revision.getHeaders().get("Specification-Title"); String specversion = (String) m_revision.getHeaders().get("Specification-Version"); String specvendor = (String) m_revision.getHeaders().get("Specification-Vendor"); String impltitle = (String) m_revision.getHeaders().get("Implementation-Title"); String implversion = (String) m_revision.getHeaders().get("Implementation-Version"); String implvendor = (String) m_revision.getHeaders().get("Implementation-Vendor"); if ((spectitle != null) || (specversion != null) || (specvendor != null) || (impltitle != null) || (implversion != null) || (implvendor != null)) { return new Object[] { spectitle, specversion, specvendor, impltitle, implversion, implvendor }; } return null; } private Class getDexFileClass(JarContent content, String name, ClassLoader loader) throws Exception { if (m_jarContentToDexFile == null) { return null; } Object dexFile = null; if (!m_jarContentToDexFile.containsKey(content)) { try { if (m_dexFileClassLoadDex != null) { dexFile = m_dexFileClassLoadDex.invoke(null, new Object[]{content.getFile().getAbsolutePath(), content.getFile().getAbsolutePath() + ".dex", new Integer(0)}); } else { dexFile = m_dexFileClassConstructor.newInstance( new Object[] { content.getFile() }); } } finally { m_jarContentToDexFile.put(content, dexFile); } } else { dexFile = m_jarContentToDexFile.get(content); } if (dexFile != null) { return (Class) m_dexFileClassLoadClass.invoke(dexFile, new Object[] { name.replace('.','/'), loader }); } return null; } @Override public URL getResource(String name) { URL url = BundleWiringImpl.this.getResourceByDelegation(name); if (m_useLocalURLs) { url = convertToLocalUrl(url); } return url; } @Override protected URL findResource(String name) { return m_revision.getResourceLocal(name); } // The findResources() method should only look at the revision itself, but // instead it tries to delegate because in Java version prior to 1.5 the // getResources() method was final and could not be overridden. We should // override getResources() like getResource() to make it delegate, but we // can't. As a workaround, we make findResources() delegate instead. @Override protected Enumeration findResources(String name) { Enumeration urls = BundleWiringImpl.this.getResourcesByDelegation(name); if (m_useLocalURLs) { urls = new ToLocalUrlEnumeration(urls); } return urls; } @Override protected String findLibrary(String name) { // Remove leading slash, if present. if (name.startsWith("/")) { name = name.substring(1); } String result = null; // CONCURRENCY: In the long run, we might want to break this // sync block in two to avoid manipulating the cache while // holding the lock, but for now we will do it the simple way. synchronized (this) { // Check to make sure we haven't already found this library. for (int i = 0; (result == null) && (i < m_cachedLibs.length); i++) { if (m_cachedLibs[i][LIBNAME_IDX].equals(name)) { result = (String) m_cachedLibs[i][LIBPATH_IDX]; } } // If we don't have a cached result, see if we have a matching // native library. if (result == null) { List libs = getNativeLibraries(); for (int libIdx = 0; (libs != null) && (libIdx < libs.size()); libIdx++) { if (libs.get(libIdx).match(m_configMap, name)) { // Search bundle content first for native library. result = m_revision.getContent().getEntryAsNativeLibrary( libs.get(libIdx).getEntryName()); // If not found, then search fragments in order. for (int i = 0; (result == null) && (m_fragmentContents != null) && (i < m_fragmentContents.size()); i++) { result = m_fragmentContents.get(i).getEntryAsNativeLibrary( libs.get(libIdx).getEntryName()); } } } // Remember the result for future requests. if (result != null) { Object[][] tmp = new Object[m_cachedLibs.length + 1][]; System.arraycopy(m_cachedLibs, 0, tmp, 0, m_cachedLibs.length); tmp[m_cachedLibs.length] = new Object[] { name, result }; m_cachedLibs = tmp; } } } return result; } @Override public String toString() { return BundleWiringImpl.this.toString(); } } static URL convertToLocalUrl(URL url) { if (url.getProtocol().equals("bundle")) { try { url = ((URLHandlersBundleURLConnection) url.openConnection()).getLocalURL(); } catch (IOException ex) { // Ignore and add original url. } } return url; } private static class ResourceSource implements Comparable { public final String m_resource; public final BundleRevision m_revision; public ResourceSource(String resource, BundleRevision revision) { m_resource = resource; m_revision = revision; } @Override public boolean equals(Object o) { if (o instanceof ResourceSource) { return m_resource.equals(((ResourceSource) o).m_resource); } return false; } @Override public int hashCode() { return m_resource.hashCode(); } public int compareTo(ResourceSource t) { return m_resource.compareTo(t.m_resource); } @Override public String toString() { return m_resource + " -> " + m_revision.getSymbolicName() + " [" + m_revision + "]"; } } private static String diagnoseClassLoadError( StatefulResolver resolver, BundleRevision revision, String name) { // We will try to do some diagnostics here to help the developer // deal with this exception. // Get package name. String pkgName = Util.getClassPackage(name); if (pkgName.length() == 0) { return null; } // First, get the bundle string of the revision doing the class loader. String importer = revision.getBundle().toString(); // Next, check to see if the revision imports the package. List wires = (revision.getWiring() == null) ? null : revision.getWiring().getProvidedWires(null); for (int i = 0; (wires != null) && (i < wires.size()); i++) { if (wires.get(i).getCapability().getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE) && wires.get(i).getCapability().getAttributes().get(BundleRevision.PACKAGE_NAMESPACE).equals(pkgName)) { String exporter = wires.get(i).getProviderWiring().getBundle().toString(); StringBuffer sb = new StringBuffer("*** Package '"); sb.append(pkgName); sb.append("' is imported by bundle "); sb.append(importer); sb.append(" from bundle "); sb.append(exporter); sb.append(", but the exported package from bundle "); sb.append(exporter); sb.append(" does not contain the requested class '"); sb.append(name); sb.append("'. Please verify that the class name is correct in the importing bundle "); sb.append(importer); sb.append(" and/or that the exported package is correctly bundled in "); sb.append(exporter); sb.append(". ***"); return sb.toString(); } } // Next, check to see if the package was optionally imported and // whether or not there is an exporter available. List reqs = revision.getWiring().getRequirements(null); /* * TODO: RB - Fix diagnostic message for optional imports. for (int i = 0; (reqs != null) && (i < reqs.length); i++) { if (reqs[i].getName().equals(pkgName) && reqs[i].isOptional()) { // Try to see if there is an exporter available. IModule[] exporters = getResolvedExporters(reqs[i], true); exporters = (exporters.length == 0) ? getUnresolvedExporters(reqs[i], true) : exporters; // An exporter might be available, but it may have attributes // that do not match the importer's required attributes, so // check that case by simply looking for an exporter of the // desired package without any attributes. if (exporters.length == 0) { IRequirement pkgReq = new Requirement( ICapability.PACKAGE_NAMESPACE, "(package=" + pkgName + ")"); exporters = getResolvedExporters(pkgReq, true); exporters = (exporters.length == 0) ? getUnresolvedExporters(pkgReq, true) : exporters; } long expId = (exporters.length == 0) ? -1 : Util.getBundleIdFromModuleId(exporters[0].getId()); StringBuffer sb = new StringBuffer("*** Class '"); sb.append(name); sb.append("' was not found, but this is likely normal since package '"); sb.append(pkgName); sb.append("' is optionally imported by bundle "); sb.append(impId); sb.append("."); if (exporters.length > 0) { sb.append(" However, bundle "); sb.append(expId); if (reqs[i].isSatisfied( Util.getExportPackage(exporters[0], reqs[i].getName()))) { sb.append(" does export this package. Bundle "); sb.append(expId); sb.append(" must be installed before bundle "); sb.append(impId); sb.append(" is resolved or else the optional import will be ignored."); } else { sb.append(" does export this package with attributes that do not match."); } } sb.append(" ***"); return sb.toString(); } } */ // Next, check to see if the package is dynamically imported by the revision. if (resolver.isAllowedDynamicImport(revision, pkgName)) { // Try to see if there is an exporter available. Map dirs = Collections.EMPTY_MAP; Map attrs = Collections.singletonMap( BundleRevision.PACKAGE_NAMESPACE, (Object) pkgName); BundleRequirementImpl req = new BundleRequirementImpl( revision, BundleRevision.PACKAGE_NAMESPACE, dirs, attrs); Set exporters = resolver.getCandidates(req, false); BundleRevision provider = null; try { provider = resolver.resolve(revision, pkgName); } catch (Exception ex) { provider = null; } String exporter = (exporters.isEmpty()) ? null : exporters.iterator().next().getRevision().getBundle().toString(); StringBuffer sb = new StringBuffer("*** Class '"); sb.append(name); sb.append("' was not found, but this is likely normal since package '"); sb.append(pkgName); sb.append("' is dynamically imported by bundle "); sb.append(importer); sb.append("."); if ((exporters.size() > 0) && (provider == null)) { sb.append(" However, bundle "); sb.append(exporter); sb.append(" does export this package with attributes that do not match."); } sb.append(" ***"); return sb.toString(); } // Next, check to see if there are any exporters for the package at all. Map dirs = Collections.EMPTY_MAP; Map attrs = Collections.singletonMap( BundleRevision.PACKAGE_NAMESPACE, (Object) pkgName); BundleRequirementImpl req = new BundleRequirementImpl( revision, BundleRevision.PACKAGE_NAMESPACE, dirs, attrs); Set exports = resolver.getCandidates(req, false); if (exports.size() > 0) { boolean classpath = false; try { BundleRevisionImpl.getSecureAction() .getClassLoader(BundleClassLoader.class).loadClass(name); classpath = true; } catch (NoClassDefFoundError err) { // Ignore } catch (Exception ex) { // Ignore } String exporter = exports.iterator().next().getRevision().getBundle().toString(); StringBuffer sb = new StringBuffer("*** Class '"); sb.append(name); sb.append("' was not found because bundle "); sb.append(importer); sb.append(" does not import '"); sb.append(pkgName); sb.append("' even though bundle "); sb.append(exporter); sb.append(" does export it."); if (classpath) { sb.append(" Additionally, the class is also available from the system class loader. There are two fixes: 1) Add an import for '"); sb.append(pkgName); sb.append("' to bundle "); sb.append(importer); sb.append("; imports are necessary for each class directly touched by bundle code or indirectly touched, such as super classes if their methods are used. "); sb.append("2) Add package '"); sb.append(pkgName); sb.append("' to the '"); sb.append(Constants.FRAMEWORK_BOOTDELEGATION); sb.append("' property; a library or VM bug can cause classes to be loaded by the wrong class loader. The first approach is preferable for preserving modularity."); } else { sb.append(" To resolve this issue, add an import for '"); sb.append(pkgName); sb.append("' to bundle "); sb.append(importer); sb.append("."); } sb.append(" ***"); return sb.toString(); } // Next, try to see if the class is available from the system // class loader. try { BundleRevisionImpl.getSecureAction() .getClassLoader(BundleClassLoader.class).loadClass(name); StringBuffer sb = new StringBuffer("*** Package '"); sb.append(pkgName); sb.append("' is not imported by bundle "); sb.append(importer); sb.append(", nor is there any bundle that exports package '"); sb.append(pkgName); sb.append("'. However, the class '"); sb.append(name); sb.append("' is available from the system class loader. There are two fixes: 1) Add package '"); sb.append(pkgName); sb.append("' to the '"); sb.append(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA); sb.append("' property and modify bundle "); sb.append(importer); sb.append(" to import this package; this causes the system bundle to export class path packages. 2) Add package '"); sb.append(pkgName); sb.append("' to the '"); sb.append(Constants.FRAMEWORK_BOOTDELEGATION); sb.append("' property; a library or VM bug can cause classes to be loaded by the wrong class loader. The first approach is preferable for preserving modularity."); sb.append(" ***"); return sb.toString(); } catch (Exception ex2) { } // Finally, if there are no imports or exports for the package // and it is not available on the system class path, simply // log a message saying so. StringBuffer sb = new StringBuffer("*** Class '"); sb.append(name); sb.append("' was not found. Bundle "); sb.append(importer); sb.append(" does not import package '"); sb.append(pkgName); sb.append("', nor is the package exported by any other bundle or available from the system class loader."); sb.append(" ***"); return sb.toString(); } } felix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/cache/0000755000175000017500000000000011655235117026272 5ustar drazzibdrazzib././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootfelix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/cache/ContentDirectoryContent.javafelix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/cache/ContentDirectoryContent.ja0000644000175000017500000001120511644651230033433 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework.cache; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.Enumeration; import java.util.NoSuchElementException; public class ContentDirectoryContent implements Content { private final Content m_content; private final String m_rootPath; public ContentDirectoryContent(Content content, String path) { m_content = content; // Add a '/' to the end if not present. m_rootPath = (path.length() > 0) && (path.charAt(path.length() - 1) != '/') ? path + "/" : path; } public void close() { // We do not actually close the associated content // from which we are filtering our directory because // we assume that this will be close manually by // the owner of that content. } public boolean hasEntry(String name) throws IllegalStateException { if ((name.length() > 0) && (name.charAt(0) == '/')) { name = name.substring(1); } return m_content.hasEntry(m_rootPath + name); } public Enumeration getEntries() { return new EntriesEnumeration(m_content.getEntries(), m_rootPath); } public byte[] getEntryAsBytes(String name) throws IllegalStateException { if ((name.length() > 0) && (name.charAt(0) == '/')) { name = name.substring(1); } return m_content.getEntryAsBytes(m_rootPath + name); } public InputStream getEntryAsStream(String name) throws IllegalStateException, IOException { if ((name.length() > 0) && (name.charAt(0) == '/')) { name = name.substring(1); } return m_content.getEntryAsStream(m_rootPath + name); } public URL getEntryAsURL(String name) { return m_content.getEntryAsURL(m_rootPath + name); } public Content getEntryAsContent(String name) { if ((name.length() > 0) && (name.charAt(0) == '/')) { name = name.substring(1); } return m_content.getEntryAsContent(m_rootPath + name); } public String getEntryAsNativeLibrary(String name) { if ((name.length() > 0) && (name.charAt(0) == '/')) { name = name.substring(1); } return m_content.getEntryAsNativeLibrary(m_rootPath + name); } public String toString() { return "CONTENT DIR " + m_rootPath + " (" + m_content + ")"; } private static class EntriesEnumeration implements Enumeration { private final Enumeration m_enumeration; private final String m_rootPath; private String m_nextEntry = null; public EntriesEnumeration(Enumeration enumeration, String rootPath) { m_enumeration = enumeration; m_rootPath = rootPath; m_nextEntry = findNextEntry(); } public synchronized boolean hasMoreElements() { return (m_nextEntry != null); } public synchronized Object nextElement() { if (m_nextEntry == null) { throw new NoSuchElementException("No more elements."); } String currentEntry = m_nextEntry; m_nextEntry = findNextEntry(); return currentEntry; } private String findNextEntry() { // Find next entry that is inside the root directory. while (m_enumeration.hasMoreElements()) { String next = (String) m_enumeration.nextElement(); if (next.startsWith(m_rootPath) && !next.equals(m_rootPath)) { // Strip off the root directory. return next.substring(m_rootPath.length()); } } return null; } } }felix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/cache/JarRevision.java0000644000175000017500000002660511644651230031375 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework.cache; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.lang.ref.SoftReference; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import java.util.Map; import java.util.zip.ZipEntry; import org.apache.felix.framework.Logger; import org.apache.felix.framework.util.StringMap; import org.apache.felix.framework.util.Util; import org.apache.felix.framework.util.WeakZipFileFactory; import org.apache.felix.framework.util.WeakZipFileFactory.WeakZipFile; /** *

* This class implements a bundle archive revision for a standard bundle * JAR file. The specified location is the URL of the JAR file. By default, * the associated JAR file is copied into the revision's directory on the * file system, but it is possible to mark the JAR as 'by reference', which * will result in the bundle JAR be used 'in place' and not being copied. In * either case, some of the contents may be extracted into the revision * directory, such as embedded JAR files and native libraries. *

**/ class JarRevision extends BundleArchiveRevision { private static final transient String BUNDLE_JAR_FILE = "bundle.jar"; private final WeakZipFileFactory m_zipFactory; private final File m_bundleFile; private final WeakZipFile m_zipFile; public JarRevision( Logger logger, Map configMap, WeakZipFileFactory zipFactory, File revisionRootDir, String location, boolean byReference, InputStream is) throws Exception { super(logger, configMap, revisionRootDir, location); m_zipFactory = zipFactory; if (byReference) { m_bundleFile = new File(location.substring( location.indexOf(BundleArchive.FILE_PROTOCOL) + BundleArchive.FILE_PROTOCOL.length())); } else { m_bundleFile = new File(getRevisionRootDir(), BUNDLE_JAR_FILE); } // Save and process the bundle JAR. initialize(byReference, is); // Open shared copy of the JAR file. WeakZipFile zipFile = null; try { // Open bundle JAR file. zipFile = m_zipFactory.create(m_bundleFile); // Error if no jar file. if (zipFile == null) { throw new IOException("No JAR file found."); } m_zipFile = zipFile; } catch (Exception ex) { if (zipFile != null) zipFile.close(); throw ex; } } public Map getManifestHeader() throws Exception { // Create a case insensitive map of manifest attributes. Map headers = new StringMap(false); // Read and parse headers. getMainAttributes(headers, m_zipFile); return headers; } public synchronized Content getContent() throws Exception { return new JarContent(getLogger(), getConfig(), m_zipFactory, this, getRevisionRootDir(), m_bundleFile, m_zipFile); } protected void close() throws Exception { m_zipFile.close(); } // // Private methods. // private void initialize(boolean byReference, InputStream is) throws Exception { try { // If the revision directory does not exist, then create it. if (!BundleCache.getSecureAction().fileExists(getRevisionRootDir())) { if (!BundleCache.getSecureAction().mkdir(getRevisionRootDir())) { getLogger().log( Logger.LOG_ERROR, getClass().getName() + ": Unable to create revision directory."); throw new IOException("Unable to create archive directory."); } if (!byReference) { URLConnection conn = null; try { if (is == null) { // Do it the manual way to have a chance to // set request properties such as proxy auth. URL url = BundleCache.getSecureAction().createURL( null, getLocation(), null); conn = url.openConnection(); // Support for http proxy authentication. String auth = BundleCache.getSecureAction() .getSystemProperty("http.proxyAuth", null); if ((auth != null) && (auth.length() > 0)) { if ("http".equals(url.getProtocol()) || "https".equals(url.getProtocol())) { String base64 = Util.base64Encode(auth); conn.setRequestProperty( "Proxy-Authorization", "Basic " + base64); } } is = BundleCache.getSecureAction() .getURLConnectionInputStream(conn); } // Save the bundle jar file. BundleCache.copyStreamToFile(is, m_bundleFile); } finally { // This is a hack to fix an issue on Android, where // HttpURLConnections are not properly closed. (FELIX-2728) if ((conn != null) && (conn instanceof HttpURLConnection)) { ((HttpURLConnection) conn).disconnect(); } } } } } finally { if (is != null) is.close(); } } private static final ThreadLocal m_defaultBuffer = new ThreadLocal(); private static final int DEFAULT_BUFFER = 1024 * 64; // Parse the main attributes of the manifest of the given jarfile. // The idea is to not open the jar file as a java.util.jarfile but // read the mainfest from the zipfile directly and parse it manually // to use less memory and be faster. private static void getMainAttributes(Map result, WeakZipFile zipFile) throws Exception { ZipEntry entry = zipFile.getEntry("META-INF/MANIFEST.MF"); // Get a buffer for this thread if there is one already otherwise, // create one of size DEFAULT_BUFFER (64K) if the manifest is less // than 64k or of the size of the manifest. SoftReference ref = (SoftReference) m_defaultBuffer.get(); byte[] bytes = null; if (ref != null) { bytes = (byte[]) ref.get(); } int size = (int) entry.getSize(); if (bytes == null) { bytes = new byte[size > DEFAULT_BUFFER ? size : DEFAULT_BUFFER]; m_defaultBuffer.set(new SoftReference(bytes)); } else if (size > bytes.length) { bytes = new byte[size]; m_defaultBuffer.set(new SoftReference(bytes)); } // Now read in the manifest in one go into the bytes array. // The InputStream is already // buffered and can handle up to 64K buffers in one go. InputStream is = null; try { is = zipFile.getInputStream(entry); int i = is.read(bytes); while (i < size) { i += is.read(bytes, i, bytes.length - i); } } finally { is.close(); } // Now parse the main attributes. The idea is to do that // without creating new byte arrays. Therefore, we read through // the manifest bytes inside the bytes array and write them back into // the same array unless we don't need them (e.g., \r\n and \n are skipped). // That allows us to create the strings from the bytes array without the skipped // chars. We stopp as soon as we see a blankline as that denotes that the main //attributes part is finished. String key = null; int last = 0; int current = 0; for (int i = 0; i < size; i++) { // skip \r and \n if it is follows by another \n // (we catch the blank line case in the next iteration) if (bytes[i] == '\r') { if ((i + 1 < size) && (bytes[i + 1] == '\n')) { continue; } } if (bytes[i] == '\n') { if ((i + 1 < size) && (bytes[i + 1] == ' ')) { i++; continue; } } // If we don't have a key yet and see the first : we parse it as the key // and skip the : that follows it. if ((key == null) && (bytes[i] == ':')) { key = new String(bytes, last, (current - last), "UTF-8"); if ((i + 1 < size) && (bytes[i + 1] == ' ')) { last = current + 1; continue; } else { throw new Exception( "Manifest error: Missing space separator - " + key); } } // if we are at the end of a line if (bytes[i] == '\n') { // and it is a blank line stop parsing (main attributes are done) if ((last == current) && (key == null)) { break; } // Otherwise, parse the value and add it to the map (we throw an // exception if we don't have a key or the key already exist. String value = new String(bytes, last, (current - last), "UTF-8"); if (key == null) { throw new Exception("Manifst error: Missing attribute name - " + value); } else if (result.put(key, value) != null) { throw new Exception("Manifst error: Duplicate attribute name - " + key); } last = current; key = null; } else { // write back the byte if it needs to be included in the key or the value. bytes[current++] = bytes[i]; } } } }felix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/cache/BundleArchive.java0000644000175000017500000013652611644651230031661 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework.cache; import java.io.*; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import org.apache.felix.framework.Logger; import org.apache.felix.framework.util.WeakZipFileFactory; import org.osgi.framework.Bundle; import org.osgi.framework.Constants; /** *

* This class is a logical abstraction for a bundle archive. This class, * combined with BundleCache and concrete BundleRevision * subclasses, implement the bundle cache for Felix. The bundle archive * abstracts the actual bundle content into revisions and the revisions * provide access to the actual bundle content. When a bundle is * installed it has one revision associated with its content. Updating a * bundle adds another revision for the updated content. Any number of * revisions can be associated with a bundle archive. When the bundle * (or framework) is refreshed, then all old revisions are purged and only * the most recent revision is maintained. *

*

* The content associated with a revision can come in many forms, such as * a standard JAR file or an exploded bundle directory. The bundle archive * is responsible for creating all revision instances during invocations * of the revise() method call. Internally, it determines the * concrete type of revision type by examining the location string as an * URL. Currently, it supports standard JAR files, referenced JAR files, * and referenced directories. Examples of each type of URL are, respectively: *

*
    *
  • http://www.foo.com/bundle.jar
  • *
  • reference:file:/foo/bundle.jar
  • *
  • reference:file:/foo/bundle/
  • *
*

* The "reference:" notation signifies that the resource should be * used "in place", meaning that they will not be copied. For referenced JAR * files, some resources may still be copied, such as embedded JAR files or * native libraries, but for referenced exploded bundle directories, nothing * will be copied. Currently, reference URLs can only refer to "file:" targets. *

* @see org.apache.felix.framework.cache.BundleCache * @see org.apache.felix.framework.cache.BundleRevision **/ public class BundleArchive { public static final transient String FILE_PROTOCOL = "file:"; public static final transient String REFERENCE_PROTOCOL = "reference:"; public static final transient String INPUTSTREAM_PROTOCOL = "inputstream:"; private static final transient String BUNDLE_INFO_FILE = "bundle.info"; private static final transient String REVISION_LOCATION_FILE = "revision.location"; private static final transient String REVISION_DIRECTORY = "version"; private static final transient String DATA_DIRECTORY = "data"; private final Logger m_logger; private final Map m_configMap; private final WeakZipFileFactory m_zipFactory; private final File m_archiveRootDir; private final boolean m_isSingleBundleFile; private long m_id = -1; private String m_originalLocation = null; private int m_persistentState = -1; private int m_startLevel = -1; private long m_lastModified = -1; /** * The refresh count field is used when generating the bundle revision * directory name where native libraries are extracted. This is necessary * because Sun's JVM requires a one-to-one mapping between native libraries * and class loaders where the native library is uniquely identified by its * absolute path in the file system. This constraint creates a problem when * a bundle is refreshed, because it gets a new class loader. Using the * refresh counter to generate the name of the bundle revision directory * resolves this problem because each time bundle is refresh, the native * library will have a unique name. As a result of the unique name, the JVM * will then reload the native library without a problem. **/ private long m_refreshCount = -1; // Maps a Long revision number to a BundleRevision. private final SortedMap m_revisions = new TreeMap(); /** *

* This constructor is used for creating new archives when a bundle is * installed into the framework. Each archive receives a logger, a root * directory, its associated bundle identifier, the associated bundle * location string, and an input stream from which to read the bundle * content. The root directory is where any required state can be * stored. The input stream may be null, in which case the location is * used as an URL to the bundle content. *

* @param logger the logger to be used by the archive. * @param archiveRootDir the archive root directory for storing state. * @param id the bundle identifier associated with the archive. * @param location the bundle location string associated with the archive. * @param is input stream from which to read the bundle content. * @throws Exception if any error occurs. **/ public BundleArchive(Logger logger, Map configMap, WeakZipFileFactory zipFactory, File archiveRootDir, long id, int startLevel, String location, InputStream is) throws Exception { m_logger = logger; m_configMap = configMap; m_zipFactory = zipFactory; m_archiveRootDir = archiveRootDir; m_id = id; if (m_id <= 0) { throw new IllegalArgumentException( "Bundle ID cannot be less than or equal to zero."); } m_originalLocation = location; m_persistentState = Bundle.INSTALLED; m_startLevel = startLevel; m_lastModified = System.currentTimeMillis(); m_refreshCount = 0; String s = (String) m_configMap.get(BundleCache.CACHE_SINGLEBUNDLEFILE_PROP); m_isSingleBundleFile = ((s == null) || s.equalsIgnoreCase("true")) ? true : false; // Save state. initialize(); // Add a revision for the content. reviseInternal(false, new Long(0), m_originalLocation, is); } /** *

* This constructor is called when an archive for a bundle is being * reconstructed when the framework is restarted. Each archive receives * a logger, a root directory, and its associated bundle identifier. * The root directory is where any required state can be stored. *

* @param logger the logger to be used by the archive. * @param archiveRootDir the archive root directory for storing state. * @param configMap configMap for BundleArchive * @throws Exception if any error occurs. **/ public BundleArchive(Logger logger, Map configMap, WeakZipFileFactory zipFactory, File archiveRootDir) throws Exception { m_logger = logger; m_configMap = configMap; m_zipFactory = zipFactory; m_archiveRootDir = archiveRootDir; String s = (String) m_configMap.get(BundleCache.CACHE_SINGLEBUNDLEFILE_PROP); m_isSingleBundleFile = ((s == null) || s.equalsIgnoreCase("true")) ? true : false; if (m_isSingleBundleFile) { readBundleInfo(); } // Add a revision number for each revision that exists in the file // system. The file system might contain more than one revision if // the bundle was updated in a previous session, but the framework // was not refreshed; this might happen if the framework did not // exit cleanly. We must add the existing revisions so that // they can be properly purged. // Find the existing revision directories, which will be named like: // "${REVISION_DIRECTORY)${refresh-count}.${revision-number}" File[] children = m_archiveRootDir.listFiles(); for (File child : children) { if (child.getName().startsWith(REVISION_DIRECTORY) && child.isDirectory()) { // Determine the revision number and add it to the revision map. int idx = child.getName().lastIndexOf('.'); if (idx > 0) { Long revNum = Long.decode(child.getName().substring(idx + 1)); m_revisions.put(revNum, null); } } } if (m_revisions.isEmpty()) { throw new Exception( "No valid revisions in bundle archive directory: " + archiveRootDir); } // Remove the last revision number since the call to reviseInternal() // will properly add the most recent bundle revision. // NOTE: We do not actually need to add a real revision object for the // older revisions since they will be purged immediately on framework // startup. Long currentRevNum = m_revisions.lastKey(); m_revisions.remove(currentRevNum); // Add the revision object for the most recent revision. reviseInternal(true, currentRevNum, getRevisionLocation(currentRevNum), null); } /** *

* Returns the bundle identifier associated with this archive. *

* @return the bundle identifier associated with this archive. * @throws Exception if any error occurs. **/ public synchronized long getId() throws Exception { if (m_id <= 0) { m_id = readId(); } return m_id; } /** *

* Returns the location string associated with this archive. *

* @return the location string associated with this archive. * @throws Exception if any error occurs. **/ public synchronized String getLocation() throws Exception { if (m_originalLocation == null) { m_originalLocation = readLocation(); } return m_originalLocation; } /** *

* Returns the persistent state of this archive. The value returned is * one of the following: Bundle.INSTALLED, Bundle.ACTIVE, * or Bundle.UNINSTALLED. *

* @return the persistent state of this archive. * @throws Exception if any error occurs. **/ public synchronized int getPersistentState() throws Exception { if (m_persistentState < 0) { m_persistentState = readPersistentState(); } return m_persistentState; } /** *

* Sets the persistent state of this archive. The value is * one of the following: Bundle.INSTALLED, Bundle.ACTIVE, * or Bundle.UNINSTALLED. *

* @param state the persistent state value to set for this archive. * @throws Exception if any error occurs. **/ public synchronized void setPersistentState(int state) throws Exception { if (m_persistentState != state) { m_persistentState = state; if (m_isSingleBundleFile) { writeBundleInfo(); } else { writePersistentState(); } } } /** *

* Returns the start level of this archive. *

* @return the start level of this archive. * @throws Exception if any error occurs. **/ public synchronized int getStartLevel() throws Exception { if (m_startLevel < 0) { m_startLevel = readStartLevel(); } return m_startLevel; } /** *

* Sets the the start level of this archive this archive. *

* @param level the start level to set for this archive. * @throws Exception if any error occurs. **/ public synchronized void setStartLevel(int level) throws Exception { if (m_startLevel != level) { m_startLevel = level; if (m_isSingleBundleFile) { writeBundleInfo(); } else { writeStartLevel(); } } } /** *

* Returns the last modification time of this archive. *

* @return the last modification time of this archive. * @throws Exception if any error occurs. **/ public synchronized long getLastModified() throws Exception { if (m_lastModified < 0) { m_lastModified = readLastModified(); } return m_lastModified; } /** *

* Sets the the last modification time of this archive. *

* @param lastModified The time of the last modification to set for * this archive. According to the OSGi specification this time is * set each time a bundle is installed, updated or uninstalled. * * @throws Exception if any error occurs. **/ public synchronized void setLastModified(long lastModified) throws Exception { if (m_lastModified != lastModified) { m_lastModified = lastModified; if (m_isSingleBundleFile) { writeBundleInfo(); } else { writeLastModified(); } } } /** * This utility method is used to retrieve the current refresh * counter value for the bundle. This value is used when generating * the bundle revision directory name where native libraries are extracted. * This is necessary because Sun's JVM requires a one-to-one mapping * between native libraries and class loaders where the native library * is uniquely identified by its absolute path in the file system. This * constraint creates a problem when a bundle is refreshed, because it * gets a new class loader. Using the refresh counter to generate the name * of the bundle revision directory resolves this problem because each time * bundle is refresh, the native library will have a unique name. * As a result of the unique name, the JVM will then reload the * native library without a problem. **/ private long getRefreshCount() throws Exception { // If the refresh counter is not yet initialized, do so now. if (m_refreshCount < 0) { m_refreshCount = readRefreshCount(); } return m_refreshCount; } /** * This utility method is used to retrieve the current refresh * counter value for the bundle. This value is used when generating * the bundle revision directory name where native libraries are extracted. * This is necessary because Sun's JVM requires a one-to-one mapping * between native libraries and class loaders where the native library * is uniquely identified by its absolute path in the file system. This * constraint creates a problem when a bundle is refreshed, because it * gets a new class loader. Using the refresh counter to generate the name * of the bundle revision directory resolves this problem because each time * bundle is refresh, the native library will have a unique name. * As a result of the unique name, the JVM will then reload the * native library without a problem. **/ private void setRefreshCount(long count) throws Exception { if (m_refreshCount != count) { m_refreshCount = count; if (m_isSingleBundleFile) { writeBundleInfo(); } else { writeRefreshCount(); } } } /** *

* Returns a File object corresponding to the data file * of the relative path of the specified string. *

* @return a File object corresponding to the specified file name. * @throws Exception if any error occurs. **/ public synchronized File getDataFile(String fileName) throws Exception { // Do some sanity checking. if ((fileName.length() > 0) && (fileName.charAt(0) == File.separatorChar)) { throw new IllegalArgumentException( "The data file path must be relative, not absolute."); } else if (fileName.indexOf("..") >= 0) { throw new IllegalArgumentException( "The data file path cannot contain a reference to the \"..\" directory."); } // Get bundle data directory. File dataDir = new File(m_archiveRootDir, DATA_DIRECTORY); // Create the data directory if necessary. if (!BundleCache.getSecureAction().fileExists(dataDir)) { if (!BundleCache.getSecureAction().mkdir(dataDir)) { throw new IOException("Unable to create bundle data directory."); } } // Return the data file. return new File(dataDir, fileName); } /** *

* Returns the current revision object for the archive. *

* @return the current revision object for the archive. **/ public synchronized Long getCurrentRevisionNumber() { return (m_revisions.isEmpty()) ? null : m_revisions.lastKey(); } /** *

* Returns the current revision object for the archive. *

* @return the current revision object for the archive. **/ public synchronized BundleArchiveRevision getCurrentRevision() { return (m_revisions.isEmpty()) ? null : m_revisions.get(m_revisions.lastKey()); } public synchronized boolean isRemovalPending() { return (m_revisions.size() > 1); } /** *

* This method adds a revision to the archive using the associated * location and input stream. If the input stream is null, then the * location is used a URL to obtain an input stream. *

* @param location the location string associated with the revision. * @param is the input stream from which to read the revision. * @throws Exception if any error occurs. **/ public synchronized void revise(String location, InputStream is) throws Exception { Long revNum = (m_revisions.isEmpty()) ? new Long(0) : new Long(m_revisions.lastKey().longValue() + 1); reviseInternal(false, revNum, location, is); } /** * Actually adds a revision to the bundle archive. This method is also * used to reload cached bundles too. The revision is given the specified * revision number and is read from the input stream if supplied or from * the location URL if not. * @param isReload if the bundle is being reloaded or not. * @param revNum the revision number of the revision. * @param location the location associated with the revision. * @param is the input stream from which to read the revision. * @throws Exception if any error occurs. */ private void reviseInternal( boolean isReload, Long revNum, String location, InputStream is) throws Exception { // If we have an input stream, then we have to use it // no matter what the update location is, so just ignore // the update location and set the location to be input // stream. if (is != null) { location = "inputstream:"; } // Create a bundle revision for revision number. BundleArchiveRevision revision = createRevisionFromLocation(location, is, revNum); if (revision == null) { throw new Exception("Unable to revise archive."); } if (!isReload) { setRevisionLocation(location, revNum); } // Add new revision to revision map. m_revisions.put(revNum, revision); } /** *

* This method undoes the previous revision to the archive; this method will * remove the latest revision from the archive. This method is only called * when there are problems during an update after the revision has been * created, such as errors in the update bundle's manifest. This method * can only be called if there is more than one revision, otherwise there * is nothing to undo. *

* @return true if the undo was a success false if there is no previous revision * @throws Exception if any error occurs. */ public synchronized boolean rollbackRevise() throws Exception { // Can only undo the revision if there is more than one. if (m_revisions.size() <= 1) { return false; } Long revNum = m_revisions.lastKey(); BundleArchiveRevision revision = m_revisions.remove(revNum); try { revision.close(); } catch(Exception ex) { m_logger.log(Logger.LOG_ERROR, getClass().getName() + ": Unable to dispose latest revision", ex); } File revisionDir = new File(m_archiveRootDir, REVISION_DIRECTORY + getRefreshCount() + "." + revNum.toString()); if (BundleCache.getSecureAction().fileExists(revisionDir)) { BundleCache.deleteDirectoryTree(revisionDir); } return true; } private synchronized String getRevisionLocation(Long revNum) throws Exception { InputStream is = null; BufferedReader br = null; try { is = BundleCache.getSecureAction().getFileInputStream(new File( new File(m_archiveRootDir, REVISION_DIRECTORY + getRefreshCount() + "." + revNum.toString()), REVISION_LOCATION_FILE)); br = new BufferedReader(new InputStreamReader(is)); return br.readLine(); } finally { if (br != null) br.close(); if (is != null) is.close(); } } private synchronized void setRevisionLocation(String location, Long revNum) throws Exception { // Save current revision location. OutputStream os = null; BufferedWriter bw = null; try { os = BundleCache.getSecureAction() .getFileOutputStream(new File( new File(m_archiveRootDir, REVISION_DIRECTORY + getRefreshCount() + "." + revNum.toString()), REVISION_LOCATION_FILE)); bw = new BufferedWriter(new OutputStreamWriter(os)); bw.write(location, 0, location.length()); } finally { if (bw != null) bw.close(); if (os != null) os.close(); } } public synchronized void close() { // Get the current revision count. for (BundleArchiveRevision revision : m_revisions.values()) { // Dispose of the revision, but this might be null in certain // circumstances, such as if this bundle archive was created // for an existing bundle that was updated, but not refreshed // due to a system crash; see the constructor code for details. if (revision != null) { try { revision.close(); } catch (Exception ex) { m_logger.log( Logger.LOG_ERROR, "Unable to close revision - " + revision.getRevisionRootDir(), ex); } } } } /** *

* This method closes any revisions and deletes the bundle archive directory. *

* @throws Exception if any error occurs. **/ public synchronized void closeAndDelete() { // Close the revisions and delete the archive directory. close(); if (!BundleCache.deleteDirectoryTree(m_archiveRootDir)) { m_logger.log( Logger.LOG_ERROR, "Unable to delete archive directory - " + m_archiveRootDir); } } /** *

* This method removes all old revisions associated with the archive * and keeps only the current revision. *

* @throws Exception if any error occurs. **/ public synchronized void purge() throws Exception { // Remember current revision number. Long currentRevNum = getCurrentRevisionNumber(); // Record whether the current revision has native libraries, which // we'll use later to determine if we need to rename its directory. boolean hasNativeLibs = getCurrentRevision().getManifestHeader() .containsKey(Constants.BUNDLE_NATIVECODE); // Close all revisions and then delete all but the current revision. // We don't delete it the current revision, because we want to rename it // to the new refresh level. close(); // Delete all old revisions. long refreshCount = getRefreshCount(); for (Long revNum : m_revisions.keySet()) { if (!revNum.equals(currentRevNum)) { File revisionDir = new File( m_archiveRootDir, REVISION_DIRECTORY + refreshCount + "." + revNum.toString()); if (BundleCache.getSecureAction().fileExists(revisionDir)) { BundleCache.deleteDirectoryTree(revisionDir); } } } // If the revision has native libraries, then rename its directory // to avoid the issue of being unable to load the same native library // into two different class loaders. if (hasNativeLibs) { // Increment the refresh count. setRefreshCount(refreshCount + 1); // Rename the current revision directory to the new refresh level. File currentDir = new File(m_archiveRootDir, REVISION_DIRECTORY + (refreshCount + 1) + "." + currentRevNum.toString()); File revisionDir = new File(m_archiveRootDir, REVISION_DIRECTORY + refreshCount + "." + currentRevNum.toString()); BundleCache.getSecureAction().renameFile(revisionDir, currentDir); } // Clear the revision map since they are all invalid now. m_revisions.clear(); // Recreate the revision for the current location. BundleArchiveRevision revision = createRevisionFromLocation( getRevisionLocation(currentRevNum), null, currentRevNum); // Add new revision to the revision map. m_revisions.put(currentRevNum, revision); } /** *

* Initializes the bundle archive object by creating the archive * root directory and saving the initial state. *

* @throws Exception if any error occurs. **/ private void initialize() throws Exception { OutputStream os = null; BufferedWriter bw = null; try { // If the archive directory exists, then we don't // need to initialize since it has already been done. if (BundleCache.getSecureAction().fileExists(m_archiveRootDir)) { return; } // Create archive directory, if it does not exist. if (!BundleCache.getSecureAction().mkdir(m_archiveRootDir)) { m_logger.log( Logger.LOG_ERROR, getClass().getName() + ": Unable to create archive directory."); throw new IOException("Unable to create archive directory."); } if (m_isSingleBundleFile) { writeBundleInfo(); } else { writeId(); writeLocation(); writePersistentState(); writeStartLevel(); writeLastModified(); } } finally { if (bw != null) bw.close(); if (os != null) os.close(); } } /** *

* Creates a revision based on the location string and/or input stream. *

* @return the location string associated with this archive. **/ private BundleArchiveRevision createRevisionFromLocation( String location, InputStream is, Long revNum) throws Exception { // The revision directory is named using the refresh count and // the revision number. The revision number is an increasing // counter of the number of times the bundle was revised. // The refresh count is necessary due to how native libraries // are handled in Java; needless to say, every time a bundle is // refreshed we must change the name of its native libraries so // that we can reload them. Thus, we use the refresh counter as // a way to change the name of the revision directory to give // native libraries new absolute names. File revisionRootDir = new File(m_archiveRootDir, REVISION_DIRECTORY + getRefreshCount() + "." + revNum.toString()); BundleArchiveRevision result = null; try { // Check if the location string represents a reference URL. if ((location != null) && location.startsWith(REFERENCE_PROTOCOL)) { // Reference URLs only support the file protocol. location = location.substring(REFERENCE_PROTOCOL.length()); if (!location.startsWith(FILE_PROTOCOL)) { throw new IOException("Reference URLs can only be files: " + location); } // Decode any URL escaped sequences. location = decode(location); // Make sure the referenced file exists. File file = new File(location.substring(FILE_PROTOCOL.length())); if (!BundleCache.getSecureAction().fileExists(file)) { throw new IOException("Referenced file does not exist: " + file); } // If the referenced file is a directory, then create a directory // revision; otherwise, create a JAR revision with the reference // flag set to true. if (BundleCache.getSecureAction().isFileDirectory(file)) { result = new DirectoryRevision(m_logger, m_configMap, m_zipFactory, revisionRootDir, location); } else { result = new JarRevision(m_logger, m_configMap, m_zipFactory, revisionRootDir, location, true, null); } } else if (location.startsWith(INPUTSTREAM_PROTOCOL)) { // Assume all input streams point to JAR files. result = new JarRevision(m_logger, m_configMap, m_zipFactory, revisionRootDir, location, false, is); } else { // Anything else is assumed to be a URL to a JAR file. result = new JarRevision(m_logger, m_configMap, m_zipFactory, revisionRootDir, location, false, null); } } catch (Exception ex) { if (BundleCache.getSecureAction().fileExists(revisionRootDir)) { if (!BundleCache.deleteDirectoryTree(revisionRootDir)) { m_logger.log( Logger.LOG_ERROR, getClass().getName() + ": Unable to delete revision directory - " + revisionRootDir); } } throw ex; } return result; } // Method from Harmony java.net.URIEncoderDecoder (luni subproject) // used by URI to decode uri components. private static String decode(String s) throws UnsupportedEncodingException { StringBuffer result = new StringBuffer(); ByteArrayOutputStream out = new ByteArrayOutputStream(); for (int i = 0; i < s.length();) { char c = s.charAt(i); if (c == '%') { out.reset(); do { if ((i + 2) >= s.length()) { throw new IllegalArgumentException( "Incomplete % sequence at: " + i); } int d1 = Character.digit(s.charAt(i + 1), 16); int d2 = Character.digit(s.charAt(i + 2), 16); if ((d1 == -1) || (d2 == -1)) { throw new IllegalArgumentException("Invalid % sequence (" + s.substring(i, i + 3) + ") at: " + String.valueOf(i)); } out.write((byte) ((d1 << 4) + d2)); i += 3; } while ((i < s.length()) && (s.charAt(i) == '%')); result.append(out.toString("UTF-8")); continue; } result.append(c); i++; } return result.toString(); } private void readBundleInfo() throws Exception { File infoFile = new File(m_archiveRootDir, BUNDLE_INFO_FILE); // Read the bundle start level. InputStream is = null; BufferedReader br= null; try { is = BundleCache.getSecureAction() .getFileInputStream(infoFile); br = new BufferedReader(new InputStreamReader(is)); // Read id. m_id = Long.parseLong(br.readLine()); // Read location. m_originalLocation = br.readLine(); // Read state. m_persistentState = Integer.parseInt(br.readLine()); // Read start level. m_startLevel = Integer.parseInt(br.readLine()); // Read last modified. m_lastModified = Long.parseLong(br.readLine()); // Read refresh count. m_refreshCount = Long.parseLong(br.readLine()); } catch (FileNotFoundException ex) { // If there wasn't an info file, then maybe this is an old-style // bundle cache, so try to read the files individually. We can // delete this eventually. m_id = readId(); m_originalLocation = readLocation(); m_persistentState = readPersistentState(); m_startLevel = readStartLevel(); m_lastModified = readLastModified(); m_refreshCount = readRefreshCount(); } finally { if (br != null) br.close(); if (is != null) is.close(); } } private void writeBundleInfo() throws Exception { // Write the bundle start level. OutputStream os = null; BufferedWriter bw = null; try { os = BundleCache.getSecureAction() .getFileOutputStream(new File(m_archiveRootDir, BUNDLE_INFO_FILE)); bw = new BufferedWriter(new OutputStreamWriter(os)); // Write id. String s = Long.toString(m_id); bw.write(s, 0, s.length()); bw.newLine(); // Write location. s = (m_originalLocation == null) ? "" : m_originalLocation; bw.write(s, 0, s.length()); bw.newLine(); // Write state. s = Integer.toString(m_persistentState); bw.write(s, 0, s.length()); bw.newLine(); // Write start level. s = Integer.toString(m_startLevel); bw.write(s, 0, s.length()); bw.newLine(); // Write last modified. s = Long.toString(m_lastModified); bw.write(s, 0, s.length()); bw.newLine(); // Write refresh count. s = Long.toString(m_refreshCount); bw.write(s, 0, s.length()); bw.newLine(); } catch (IOException ex) { m_logger.log( Logger.LOG_ERROR, getClass().getName() + ": Unable to cache bundle info - " + ex); throw ex; } finally { if (bw != null) bw.close(); if (os != null) os.close(); } } // // Deprecated bundle cache format to be deleted eventually. // private static final transient String BUNDLE_ID_FILE = "bundle.id"; private static final transient String BUNDLE_LOCATION_FILE = "bundle.location"; private static final transient String BUNDLE_STATE_FILE = "bundle.state"; private static final transient String BUNDLE_START_LEVEL_FILE = "bundle.startlevel"; private static final transient String BUNDLE_LASTMODIFIED_FILE = "bundle.lastmodified"; private static final transient String REFRESH_COUNTER_FILE = "refresh.counter"; private void writeId() throws Exception { OutputStream os = BundleCache.getSecureAction() .getFileOutputStream(new File(m_archiveRootDir, BUNDLE_ID_FILE)); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os)); bw.write(Long.toString(m_id), 0, Long.toString(m_id).length()); bw.close(); os.close(); } private long readId() throws Exception { long id; InputStream is = null; BufferedReader br = null; try { is = BundleCache.getSecureAction() .getFileInputStream(new File(m_archiveRootDir, BUNDLE_ID_FILE)); br = new BufferedReader(new InputStreamReader(is)); id = Long.parseLong(br.readLine()); } catch (FileNotFoundException ex) { // HACK: Get the bundle identifier from the archive root directory // name, which is of the form "bundle" where is the bundle // identifier numbers. This is a hack to deal with old archives that // did not save their bundle identifier, but instead had it passed // into them. Eventually, this can be removed. id = Long.parseLong( m_archiveRootDir.getName().substring( BundleCache.BUNDLE_DIR_PREFIX.length())); } finally { if (br != null) br.close(); if (is != null) is.close(); } return id; } private void writeLocation() throws Exception { OutputStream os = BundleCache.getSecureAction() .getFileOutputStream(new File(m_archiveRootDir, BUNDLE_LOCATION_FILE)); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os)); bw.write(m_originalLocation, 0, m_originalLocation.length()); bw.close(); os.close(); } private String readLocation() throws Exception { InputStream is = null; BufferedReader br = null; try { is = BundleCache.getSecureAction() .getFileInputStream(new File(m_archiveRootDir, BUNDLE_LOCATION_FILE)); br = new BufferedReader(new InputStreamReader(is)); return br.readLine(); } finally { if (br != null) br.close(); if (is != null) is.close(); } } private static final transient String ACTIVE_STATE = "active"; private static final transient String STARTING_STATE = "starting"; private static final transient String INSTALLED_STATE = "installed"; private static final transient String UNINSTALLED_STATE = "uninstalled"; private void writePersistentState() throws Exception { OutputStream os = null; BufferedWriter bw = null; try { os = BundleCache.getSecureAction() .getFileOutputStream(new File(m_archiveRootDir, BUNDLE_STATE_FILE)); bw = new BufferedWriter(new OutputStreamWriter(os)); String s = null; switch (m_persistentState) { case Bundle.ACTIVE: s = ACTIVE_STATE; break; case Bundle.STARTING: s = STARTING_STATE; break; case Bundle.UNINSTALLED: s = UNINSTALLED_STATE; break; default: s = INSTALLED_STATE; break; } bw.write(s, 0, s.length()); } catch (IOException ex) { m_logger.log( Logger.LOG_ERROR, getClass().getName() + ": Unable to record state - " + ex); throw ex; } finally { if (bw != null) bw.close(); if (os != null) os.close(); } } private int readPersistentState() throws Exception { int state = Bundle.INSTALLED; // Get bundle state file. File stateFile = new File(m_archiveRootDir, BUNDLE_STATE_FILE); // If the state file doesn't exist, then // assume the bundle was installed. if (BundleCache.getSecureAction().fileExists(stateFile)) { // Read the bundle state. InputStream is = null; BufferedReader br = null; try { is = BundleCache.getSecureAction() .getFileInputStream(stateFile); br = new BufferedReader(new InputStreamReader(is)); String s = br.readLine(); if ((s != null) && s.equals(ACTIVE_STATE)) { state = Bundle.ACTIVE; } else if ((s != null) && s.equals(STARTING_STATE)) { state = Bundle.STARTING; } else if ((s != null) && s.equals(UNINSTALLED_STATE)) { state = Bundle.UNINSTALLED; } else { state = Bundle.INSTALLED; } } catch (Exception ex) { state = Bundle.INSTALLED; } finally { if (br != null) br.close(); if (is != null) is.close(); } } return state; } private void writeStartLevel() throws Exception { OutputStream os = null; BufferedWriter bw = null; try { os = BundleCache.getSecureAction() .getFileOutputStream(new File(m_archiveRootDir, BUNDLE_START_LEVEL_FILE)); bw = new BufferedWriter(new OutputStreamWriter(os)); String s = Integer.toString(m_startLevel); bw.write(s, 0, s.length()); } catch (IOException ex) { m_logger.log( Logger.LOG_ERROR, getClass().getName() + ": Unable to record start level - " + ex); throw ex; } finally { if (bw != null) bw.close(); if (os != null) os.close(); } } private int readStartLevel() throws Exception { int level = -1; // Get bundle start level file. File levelFile = new File(m_archiveRootDir, BUNDLE_START_LEVEL_FILE); // If the start level file doesn't exist, then // return an error. if (!BundleCache.getSecureAction().fileExists(levelFile)) { level = -1; } else { // Read the bundle start level. InputStream is = null; BufferedReader br= null; try { is = BundleCache.getSecureAction() .getFileInputStream(levelFile); br = new BufferedReader(new InputStreamReader(is)); level = Integer.parseInt(br.readLine()); } finally { if (br != null) br.close(); if (is != null) is.close(); } } return level; } private void writeLastModified() throws Exception { OutputStream os = null; BufferedWriter bw = null; try { os = BundleCache.getSecureAction() .getFileOutputStream(new File(m_archiveRootDir, BUNDLE_LASTMODIFIED_FILE)); bw = new BufferedWriter(new OutputStreamWriter(os)); String s = Long.toString(m_lastModified); bw.write(s, 0, s.length()); } catch (IOException ex) { m_logger.log( Logger.LOG_ERROR, getClass().getName() + ": Unable to record start level - " + ex); throw ex; } finally { if (bw != null) bw.close(); if (os != null) os.close(); } } private long readLastModified() throws Exception { long last = 0; InputStream is = null; BufferedReader br = null; try { is = BundleCache.getSecureAction() .getFileInputStream(new File(m_archiveRootDir, BUNDLE_LASTMODIFIED_FILE)); br = new BufferedReader(new InputStreamReader(is)); last = Long.parseLong(br.readLine()); } catch (Exception ex) { last = 0; } finally { if (br != null) br.close(); if (is != null) is.close(); } return last; } private void writeRefreshCount() throws Exception { OutputStream os = null; BufferedWriter bw = null; try { os = BundleCache.getSecureAction() .getFileOutputStream(new File(m_archiveRootDir, REFRESH_COUNTER_FILE)); bw = new BufferedWriter(new OutputStreamWriter(os)); String s = Long.toString(m_refreshCount); bw.write(s, 0, s.length()); } catch (IOException ex) { m_logger.log( Logger.LOG_ERROR, getClass().getName() + ": Unable to write refresh count: " + ex); throw ex; } finally { if (bw != null) bw.close(); if (os != null) os.close(); } } private long readRefreshCount() throws Exception { long count = 0; InputStream is = null; BufferedReader br = null; try { is = BundleCache.getSecureAction() .getFileInputStream(new File(m_archiveRootDir, REFRESH_COUNTER_FILE)); br = new BufferedReader(new InputStreamReader(is)); count = Long.parseLong(br.readLine()); } catch (Exception ex) { count = 0; } finally { if (br != null) br.close(); if (is != null) is.close(); } return count; } } felix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/cache/JarContent.java0000644000175000017500000004471611644651230031214 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework.cache; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.Properties; import java.util.zip.ZipEntry; import org.apache.felix.framework.Logger; import org.apache.felix.framework.util.FelixConstants; import org.apache.felix.framework.util.Util; import org.apache.felix.framework.util.WeakZipFileFactory; import org.apache.felix.framework.util.WeakZipFileFactory.WeakZipFile; import org.osgi.framework.Constants; public class JarContent implements Content { private static final int BUFSIZE = 4096; private static final transient String EMBEDDED_DIRECTORY = "-embedded"; private static final transient String LIBRARY_DIRECTORY = "-lib"; private final Logger m_logger; private final Map m_configMap; private final WeakZipFileFactory m_zipFactory; private final Object m_revisionLock; private final File m_rootDir; private final File m_file; private final WeakZipFile m_zipFile; private final boolean m_isZipFileOwner; private Map m_nativeLibMap; public JarContent(Logger logger, Map configMap, WeakZipFileFactory zipFactory, Object revisionLock, File rootDir, File file, WeakZipFile zipFile) { m_logger = logger; m_configMap = configMap; m_zipFactory = zipFactory; m_revisionLock = revisionLock; m_rootDir = rootDir; m_file = file; if (zipFile == null) { try { m_zipFile = m_zipFactory.create(m_file); } catch (IOException ex) { throw new RuntimeException( "Unable to open JAR file, probably deleted: " + ex.getMessage()); } } else { m_zipFile = zipFile; } m_isZipFileOwner = (zipFile == null); } protected void finalize() { close(); } public void close() { try { if (m_isZipFileOwner) { m_zipFile.close(); } } catch (Exception ex) { m_logger.log( Logger.LOG_ERROR, "JarContent: Unable to close JAR file.", ex); } } public boolean hasEntry(String name) throws IllegalStateException { try { ZipEntry ze = m_zipFile.getEntry(name); return ze != null; } catch (Exception ex) { return false; } finally { } } public Enumeration getEntries() { // Wrap entries enumeration to filter non-matching entries. Enumeration e = new EntriesEnumeration(m_zipFile.entries()); // Spec says to return null if there are no entries. return (e.hasMoreElements()) ? e : null; } public byte[] getEntryAsBytes(String name) throws IllegalStateException { // Get the embedded resource. InputStream is = null; ByteArrayOutputStream baos = null; try { ZipEntry ze = m_zipFile.getEntry(name); if (ze == null) { return null; } is = m_zipFile.getInputStream(ze); if (is == null) { return null; } baos = new ByteArrayOutputStream(BUFSIZE); byte[] buf = new byte[BUFSIZE]; int n = 0; while ((n = is.read(buf, 0, buf.length)) >= 0) { baos.write(buf, 0, n); } return baos.toByteArray(); } catch (Exception ex) { m_logger.log( Logger.LOG_ERROR, "JarContent: Unable to read bytes.", ex); return null; } finally { try { if (baos != null) baos.close(); } catch (Exception ex) { } try { if (is != null) is.close(); } catch (Exception ex) { } } } public InputStream getEntryAsStream(String name) throws IllegalStateException, IOException { // Get the embedded resource. InputStream is = null; try { ZipEntry ze = m_zipFile.getEntry(name); if (ze == null) { return null; } is = m_zipFile.getInputStream(ze); if (is == null) { return null; } } catch (Exception ex) { return null; } return is; } public URL getEntryAsURL(String name) { try { return new URL("jar:" + m_file.toURI().toURL().toExternalForm() + "!/" + name); } catch (MalformedURLException e) { return null; } } public Content getEntryAsContent(String entryName) { // If the entry name refers to the content itself, then // just return it immediately. if (entryName.equals(FelixConstants.CLASS_PATH_DOT)) { return new JarContent(m_logger, m_configMap, m_zipFactory, m_revisionLock, m_rootDir, m_file, m_zipFile); } // Remove any leading slash. entryName = (entryName.startsWith("/")) ? entryName.substring(1) : entryName; // Any embedded JAR files will be extracted to the embedded directory. // Since embedded JAR file names may clash when extracting from multiple // embedded JAR files, the embedded directory is per embedded JAR file. File embedDir = new File(m_rootDir, m_file.getName() + EMBEDDED_DIRECTORY); // Find the entry in the JAR file and create the // appropriate content type for it. // Determine if the entry is an emdedded JAR file or // directory in the bundle JAR file. Ignore any entries // that do not exist per the spec. ZipEntry ze = m_zipFile.getEntry(entryName); if ((ze != null) && ze.isDirectory()) { File extractDir = new File(embedDir, entryName); // Extracting an embedded directory file impacts all other existing // contents for this revision, so we have to grab the revision // lock first before trying to create a directory for an embedded // directory to avoid a race condition. synchronized (m_revisionLock) { if (!BundleCache.getSecureAction().fileExists(extractDir)) { if (!BundleCache.getSecureAction().mkdirs(extractDir)) { m_logger.log( Logger.LOG_ERROR, "Unable to extract embedded directory."); } } } return new ContentDirectoryContent(this, entryName); } else if ((ze != null) && ze.getName().endsWith(".jar")) { File extractJar = new File(embedDir, entryName); // Extracting the embedded JAR file impacts all other existing // contents for this revision, so we have to grab the revision // lock first before trying to extract the embedded JAR file // to avoid a race condition. synchronized (m_revisionLock) { try { extractEmbeddedJar(entryName); } catch (Exception ex) { m_logger.log( Logger.LOG_ERROR, "Unable to extract embedded JAR file.", ex); } } return new JarContent( m_logger, m_configMap, m_zipFactory, m_revisionLock, extractJar.getParentFile(), extractJar, null); } // The entry could not be found, so return null. return null; } // TODO: SECURITY - This will need to consider security. public String getEntryAsNativeLibrary(String entryName) { // Return result. String result = null; // Remove any leading slash. entryName = (entryName.startsWith("/")) ? entryName.substring(1) : entryName; // Any embedded native libraries will be extracted to the lib directory. // Since embedded library file names may clash when extracting from multiple // embedded JAR files, the embedded lib directory is per embedded JAR file. File libDir = new File(m_rootDir, m_file.getName() + LIBRARY_DIRECTORY); // The entry name must refer to a file type, since it is // a native library, not a directory. ZipEntry ze = m_zipFile.getEntry(entryName); if ((ze != null) && !ze.isDirectory()) { // Extracting the embedded native library file impacts all other // existing contents for this revision, so we have to grab the // revision lock first before trying to extract the embedded JAR // file to avoid a race condition. synchronized (m_revisionLock) { // Since native libraries cannot be shared, we must extract a // separate copy per request, so use the request library counter // as part of the extracted path. if (m_nativeLibMap == null) { m_nativeLibMap = new HashMap(); } Integer libCount = (Integer) m_nativeLibMap.get(entryName); // Either set or increment the library count. libCount = (libCount == null) ? new Integer(0) : new Integer(libCount.intValue() + 1); m_nativeLibMap.put(entryName, libCount); File libFile = new File( libDir, libCount.toString() + File.separatorChar + entryName); if (!BundleCache.getSecureAction().fileExists(libFile)) { if (!BundleCache.getSecureAction().fileExists(libFile.getParentFile()) && !BundleCache.getSecureAction().mkdirs(libFile.getParentFile())) { m_logger.log( Logger.LOG_ERROR, "Unable to create library directory."); } else { InputStream is = null; try { is = new BufferedInputStream( m_zipFile.getInputStream(ze), BundleCache.BUFSIZE); if (is == null) { throw new IOException("No input stream: " + entryName); } // Create the file. BundleCache.copyStreamToFile(is, libFile); // Perform exec permission command on extracted library // if one is configured. String command = (String) m_configMap.get( Constants.FRAMEWORK_EXECPERMISSION); if (command != null) { Properties props = new Properties(); props.setProperty("abspath", libFile.toString()); command = Util.substVars(command, "command", null, props); Process p = BundleCache.getSecureAction().exec(command); // We have to make sure we read stdout and stderr because // otherwise we will block on certain unbuffered os's // (like eg. windows) Thread stdOut = new Thread( new DevNullRunnable(p.getInputStream())); Thread stdErr = new Thread( new DevNullRunnable(p.getErrorStream())); stdOut.setDaemon(true); stdErr.setDaemon(true); stdOut.start(); stdErr.start(); p.waitFor(); stdOut.join(); stdErr.join(); } // Return the path to the extracted native library. result = BundleCache.getSecureAction().getAbsolutePath(libFile); } catch (Exception ex) { m_logger.log( Logger.LOG_ERROR, "Extracting native library.", ex); } finally { try { if (is != null) is.close(); } catch (IOException ex) { // Not much we can do. } } } } else { // Return the path to the extracted native library. result = BundleCache.getSecureAction().getAbsolutePath(libFile); } } } return result; } public String toString() { return "JAR " + m_file.getPath(); } public File getFile() { return m_file; } /** * This method extracts an embedded JAR file from the bundle's * JAR file. * @param id the identifier of the bundle that owns the embedded JAR file. * @param jarPath the path to the embedded JAR file inside the bundle JAR file. **/ private void extractEmbeddedJar(String jarPath) throws Exception { // Remove leading slash if present. jarPath = (jarPath.length() > 0) && (jarPath.charAt(0) == '/') ? jarPath.substring(1) : jarPath; // Any embedded JAR files will be extracted to the embedded directory. // Since embedded JAR file names may clash when extracting from multiple // embedded JAR files, the embedded directory is per embedded JAR file. File embedDir = new File(m_rootDir, m_file.getName() + EMBEDDED_DIRECTORY); File jarFile = new File(embedDir, jarPath); if (!BundleCache.getSecureAction().fileExists(jarFile)) { InputStream is = null; try { // Make sure class path entry is a JAR file. ZipEntry ze = m_zipFile.getEntry(jarPath); if (ze == null) { return; } // If the zip entry is a directory, then ignore it since // we don't need to extact it; otherwise, it points to an // embedded JAR file, so extract it. else if (!ze.isDirectory()) { // Make sure that the embedded JAR's parent directory exists; // it may be in a sub-directory. File jarDir = jarFile.getParentFile(); if (!BundleCache.getSecureAction().fileExists(jarDir)) { if (!BundleCache.getSecureAction().mkdirs(jarDir)) { throw new IOException("Unable to create embedded JAR directory."); } } // Extract embedded JAR into its directory. is = new BufferedInputStream(m_zipFile.getInputStream(ze), BundleCache.BUFSIZE); if (is == null) { throw new IOException("No input stream: " + jarPath); } // Copy the file. BundleCache.copyStreamToFile(is, jarFile); } } finally { if (is != null) is.close(); } } } private static class EntriesEnumeration implements Enumeration { private final Enumeration m_enumeration; public EntriesEnumeration(Enumeration enumeration) { m_enumeration = enumeration; } public boolean hasMoreElements() { return m_enumeration.hasMoreElements(); } public String nextElement() { return ((ZipEntry) m_enumeration.nextElement()).getName(); } } private static class DevNullRunnable implements Runnable { private final InputStream m_in; public DevNullRunnable(InputStream in) { m_in = in; } public void run() { try { try { while (m_in.read() != -1){} } finally { m_in.close(); } } catch (Exception ex) { // Not much we can do - maybe we should log it? } } } }felix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/cache/Content.java0000644000175000017500000001120011644651230030535 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework.cache; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.Enumeration; public interface Content { /** *

* This method must be called when the content is no longer needed so * that any resourses being used (e.g., open files) can be closed. Once * this method is called, the content is no longer usable. If the content * is already closed, then calls on this method should have no effect. *

**/ void close(); /** *

* This method determines if the specified named entry is contained in * the associated content. The entry name is a relative path with '/' * separators. *

* @param name The name of the entry to find. * @return true if a corresponding entry was found, false * otherwise. **/ boolean hasEntry(String name); /** *

* Returns an enumeration of entry names as String objects. * An entry name is a path constructed with '/' as path element * separators and is relative to the root of the content. Entry names * for entries that represent directories should end with the '/' * character. *

* @returns An enumeration of entry names or null. **/ Enumeration getEntries(); /** *

* This method returns the named entry as an array of bytes. *

* @param name The name of the entry to retrieve as a byte array. * @return An array of bytes if the corresponding entry was found, null * otherwise. **/ byte[] getEntryAsBytes(String name); /** *

* This method returns the named entry as an input stream. *

* @param name The name of the entry to retrieve as an input stream. * @return An input stream if the corresponding entry was found, null * otherwise. * @throws java.io.IOException if any error occurs. **/ InputStream getEntryAsStream(String name) throws IOException; /** *

* This method returns the named entry as an IContent Typically, * this method only makes sense for entries that correspond to some form * of aggregated resource (e.g., an embedded JAR file or directory), but * implementations are free to interpret this however makes sense. This method * should return a new IContent instance for every invocation and * the caller is responsible for opening and closing the returned content * object. *

* @param name The name of the entry to retrieve as an IContent. * @return An IContent instance if a corresponding entry was found, * null otherwise. **/ Content getEntryAsContent(String name); /** *

* This method returns the named entry as a file in the file system for * use as a native library. It may not be possible for all content * implementations (e.g., memory only) to implement this method, in which * case it is acceptable to return null. Since native libraries * can only be associated with a single class loader, this method should * return a unique file per request. *

* @param name The name of the entry to retrieve as a file. * @return A string corresponding to the absolute path of the file if a * corresponding entry was found, null otherwise. **/ String getEntryAsNativeLibrary(String name); /** *

* This method allows retrieving an entry as a local URL. *

* * @param name The name of the entry to retrieve as a URL * @return A URL using a local protocol such as file, jar * or null if not possible. */ URL getEntryAsURL(String name); }felix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/cache/DirectoryContent.java0000644000175000017500000003446611644651230032445 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework.cache; import java.io.*; import java.net.MalformedURLException; import java.net.URL; import java.util.*; import org.apache.felix.framework.Logger; import org.apache.felix.framework.util.FelixConstants; import org.apache.felix.framework.util.Util; import org.apache.felix.framework.util.WeakZipFileFactory; import org.osgi.framework.Constants; public class DirectoryContent implements Content { private static final int BUFSIZE = 4096; private static final transient String EMBEDDED_DIRECTORY = "-embedded"; private static final transient String LIBRARY_DIRECTORY = "-lib"; private final Logger m_logger; private final Map m_configMap; private final WeakZipFileFactory m_zipFactory; private final Object m_revisionLock; private final File m_rootDir; private final File m_dir; private Map m_nativeLibMap; public DirectoryContent(Logger logger, Map configMap, WeakZipFileFactory zipFactory, Object revisionLock, File rootDir, File dir) { m_logger = logger; m_configMap = configMap; m_zipFactory = zipFactory; m_revisionLock = revisionLock; m_rootDir = rootDir; m_dir = dir; } public void close() { // Nothing to clean up. } public boolean hasEntry(String name) throws IllegalStateException { if ((name.length() > 0) && (name.charAt(0) == '/')) { name = name.substring(1); } // Return true if the file associated with the entry exists, // unless the entry name ends with "/", in which case only // return true if the file is really a directory. File file = new File(m_dir, name); return BundleCache.getSecureAction().fileExists(file) && (name.endsWith("/") ? BundleCache.getSecureAction().isFileDirectory(file) : true); } public Enumeration getEntries() { // Wrap entries enumeration to filter non-matching entries. Enumeration e = new EntriesEnumeration(m_dir); // Spec says to return null if there are no entries. return (e.hasMoreElements()) ? e : null; } public byte[] getEntryAsBytes(String name) throws IllegalStateException { if ((name.length() > 0) && (name.charAt(0) == '/')) { name = name.substring(1); } // Get the embedded resource. InputStream is = null; ByteArrayOutputStream baos = null; try { is = new BufferedInputStream( BundleCache.getSecureAction().getFileInputStream(new File(m_dir, name))); baos = new ByteArrayOutputStream(BUFSIZE); byte[] buf = new byte[BUFSIZE]; int n = 0; while ((n = is.read(buf, 0, buf.length)) >= 0) { baos.write(buf, 0, n); } return baos.toByteArray(); } catch (Exception ex) { return null; } finally { try { if (baos != null) baos.close(); } catch (Exception ex) { } try { if (is != null) is.close(); } catch (Exception ex) { } } } public InputStream getEntryAsStream(String name) throws IllegalStateException, IOException { if ((name.length() > 0) && (name.charAt(0) == '/')) { name = name.substring(1); } return BundleCache.getSecureAction().getFileInputStream(new File(m_dir, name)); } public URL getEntryAsURL(String name) { if ((name.length() > 0) && (name.charAt(0) == '/')) { name = name.substring(1); } try { return BundleCache.getSecureAction().toURI(new File(m_dir, name)).toURL(); } catch (MalformedURLException e) { return null; } } public Content getEntryAsContent(String entryName) { // If the entry name refers to the content itself, then // just return it immediately. if (entryName.equals(FelixConstants.CLASS_PATH_DOT)) { return new DirectoryContent( m_logger, m_configMap, m_zipFactory, m_revisionLock, m_rootDir, m_dir); } // Remove any leading slash, since all bundle class path // entries are relative to the root of the bundle. entryName = (entryName.startsWith("/")) ? entryName.substring(1) : entryName; // Any embedded JAR files will be extracted to the embedded directory. File embedDir = new File(m_rootDir, m_dir.getName() + EMBEDDED_DIRECTORY); // Determine if the entry is an emdedded JAR file or // directory in the bundle JAR file. Ignore any entries // that do not exist per the spec. File file = new File(m_dir, entryName); if (BundleCache.getSecureAction().isFileDirectory(file)) { return new DirectoryContent( m_logger, m_configMap, m_zipFactory, m_revisionLock, m_rootDir, file); } else if (BundleCache.getSecureAction().fileExists(file) && entryName.endsWith(".jar")) { File extractDir = new File(embedDir, (entryName.lastIndexOf('/') >= 0) ? entryName.substring(0, entryName.lastIndexOf('/')) : entryName); synchronized (m_revisionLock) { if (!BundleCache.getSecureAction().fileExists(extractDir)) { if (!BundleCache.getSecureAction().mkdirs(extractDir)) { m_logger.log( Logger.LOG_ERROR, "Unable to extract embedded directory."); } } } return new JarContent( m_logger, m_configMap, m_zipFactory, m_revisionLock, extractDir, file, null); } // The entry could not be found, so return null. return null; } // TODO: SECURITY - This will need to consider security. public String getEntryAsNativeLibrary(String entryName) { // Return result. String result = null; // Remove any leading slash, since all bundle class path // entries are relative to the root of the bundle. entryName = (entryName.startsWith("/")) ? entryName.substring(1) : entryName; // Any embedded native library files will be extracted to the lib directory. File libDir = new File(m_rootDir, m_dir.getName() + LIBRARY_DIRECTORY); // The entry must exist and refer to a file, not a directory, // since we are expecting it to be a native library. File entryFile = new File(m_dir, entryName); if (BundleCache.getSecureAction().fileExists(entryFile) && !BundleCache.getSecureAction().isFileDirectory(entryFile)) { // Extracting the embedded native library file impacts all other // existing contents for this revision, so we have to grab the // revision lock first before trying to extract the embedded JAR // file to avoid a race condition. synchronized (m_revisionLock) { // Since native libraries cannot be shared, we must extract a // separate copy per request, so use the request library counter // as part of the extracted path. if (m_nativeLibMap == null) { m_nativeLibMap = new HashMap(); } Integer libCount = (Integer) m_nativeLibMap.get(entryName); // Either set or increment the library count. libCount = (libCount == null) ? new Integer(0) : new Integer(libCount.intValue() + 1); m_nativeLibMap.put(entryName, libCount); File libFile = new File( libDir, libCount.toString() + File.separatorChar + entryName); if (!BundleCache.getSecureAction().fileExists(libFile)) { if (!BundleCache.getSecureAction().fileExists(libFile.getParentFile()) && !BundleCache.getSecureAction().mkdirs(libFile.getParentFile())) { m_logger.log( Logger.LOG_ERROR, "Unable to create library directory."); } else { InputStream is = null; try { is = new BufferedInputStream( BundleCache.getSecureAction().getFileInputStream(entryFile), BundleCache.BUFSIZE); if (is == null) { throw new IOException("No input stream: " + entryName); } // Create the file. BundleCache.copyStreamToFile(is, libFile); // Perform exec permission command on extracted library // if one is configured. String command = (String) m_configMap.get( Constants.FRAMEWORK_EXECPERMISSION); if (command != null) { Properties props = new Properties(); props.setProperty("abspath", libFile.toString()); command = Util.substVars(command, "command", null, props); Process p = BundleCache.getSecureAction().exec(command); p.waitFor(); } // Return the path to the extracted native library. result = BundleCache.getSecureAction().getAbsolutePath(libFile); } catch (Exception ex) { m_logger.log( Logger.LOG_ERROR, "Extracting native library.", ex); } finally { try { if (is != null) is.close(); } catch (IOException ex) { // Not much we can do. } } } } else { // Return the path to the extracted native library. result = BundleCache.getSecureAction().getAbsolutePath(libFile); } } } return result; } public String toString() { return "DIRECTORY " + m_dir; } private static class EntriesEnumeration implements Enumeration { private final File m_dir; private final File[] m_children; private int m_counter = 0; public EntriesEnumeration(File dir) { m_dir = dir; m_children = listFilesRecursive(m_dir); } public synchronized boolean hasMoreElements() { return (m_children != null) && (m_counter < m_children.length); } public synchronized Object nextElement() { if ((m_children == null) || (m_counter >= m_children.length)) { throw new NoSuchElementException("No more entry paths."); } // Convert the file separator character to slashes. String abs = BundleCache.getSecureAction() .getAbsolutePath(m_children[m_counter]).replace(File.separatorChar, '/'); // Remove the leading path of the reference directory, since the // entry paths are supposed to be relative to the root. StringBuffer sb = new StringBuffer(abs); sb.delete(0, BundleCache.getSecureAction().getAbsolutePath(m_dir).length() + 1); // Add a '/' to the end of directory entries. if (BundleCache.getSecureAction().isFileDirectory(m_children[m_counter])) { sb.append('/'); } m_counter++; return sb.toString(); } private File[] listFilesRecursive(File dir) { File[] children = BundleCache.getSecureAction().listDirectory(dir); File[] combined = children; for (int i = 0; i < children.length; i++) { if (BundleCache.getSecureAction().isFileDirectory(children[i])) { File[] grandchildren = listFilesRecursive(children[i]); if (grandchildren.length > 0) { File[] tmp = new File[combined.length + grandchildren.length]; System.arraycopy(combined, 0, tmp, 0, combined.length); System.arraycopy( grandchildren, 0, tmp, combined.length, grandchildren.length); combined = tmp; } } } return combined; } } }felix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/cache/BundleArchiveRevision.java0000644000175000017500000001163111644651230033365 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework.cache; import java.io.File; import java.util.Map; import org.apache.felix.framework.Logger; /** *

* This class implements an abstract revision of a bundle archive. A revision * is an abstraction of a bundle's actual content and is associated with a * parent bundle archive. A bundle archive may have multiple revisions assocaited * with it at one time, since updating a bundle results in a new version of the * bundle's content until the bundle is refreshed. Upon a refresh, then old * revisions are then purged. This abstract class is the base class for all * concrete types of revisions, such as ones for a JAR file or directories. All * revisions are assigned a root directory into which all of their state should * be stored, if necessary. Clean up of this directory is the responsibility * of the parent bundle archive and not of the revision itself. *

* @see org.apache.felix.framework.cache.BundleCache * @see org.apache.felix.framework.cache.BundleArchive **/ public abstract class BundleArchiveRevision { private final Logger m_logger; private final Map m_configMap; private final File m_revisionRootDir; private final String m_location; /** *

* This class is abstract and cannot be created. It represents a revision * of a bundle, i.e., its content. A revision is associated with a particular * location string, which is typically in URL format. Subclasses of this * class provide particular functionality, such as a revision in the form * of a JAR file or a directory. Each revision subclass is expected to use * the root directory associated with the abstract revision instance to * store any state; this will ensure that resources used by the revision are * properly freed when the revision is no longer needed. *

* @param logger a logger for use by the revision. * @param revisionRootDir the root directory to be used by the revision * subclass for storing any state. * @param location the location string associated with the revision. * @param trustedCaCerts the trusted CA certificates if any. * @throws Exception if any errors occur. **/ public BundleArchiveRevision(Logger logger, Map configMap, File revisionRootDir, String location) throws Exception { m_logger = logger; m_configMap = configMap; m_revisionRootDir = revisionRootDir; m_location = location; } /** *

* Returns the logger for this revision. *

* @return the logger instance for this revision. **/ public Logger getLogger() { return m_logger; } /** *

* Returns the configuration map for this revision. *

* @return the configuration map for this revision. **/ public Map getConfig() { return m_configMap; } /** *

* Returns the root directory for this revision. *

* @return the root directory for this revision. **/ public File getRevisionRootDir() { return m_revisionRootDir; } /** *

* Returns the location string this revision. *

* @return the location string for this revision. **/ public String getLocation() { return m_location; } /** *

* Returns the main attributes of the JAR file manifest header of the * revision. The returned map is case insensitive. *

* @return the case-insensitive JAR file manifest header of the revision. * @throws java.lang.Exception if any error occurs. **/ public abstract Map getManifestHeader() throws Exception; public abstract Content getContent() throws Exception; /** *

* This method is called when the revision is no longer needed. The directory * associated with the revision will automatically be removed for each * revision, so this method only needs to be concerned with other issues, * such as open files. *

* @throws Exception if any error occurs. **/ protected abstract void close() throws Exception; }felix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/cache/DirectoryRevision.java0000644000175000017500000000756311644651230032627 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework.cache; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.Map; import java.util.jar.Manifest; import org.apache.felix.framework.Logger; import org.apache.felix.framework.util.StringMap; import org.apache.felix.framework.util.WeakZipFileFactory; /** *

* This class implements a bundle archive revision for exploded bundle * JAR files. It uses the specified location directory "in-place" to * execute the bundle and does not copy the bundle content at all. *

**/ class DirectoryRevision extends BundleArchiveRevision { private final WeakZipFileFactory m_zipFactory; private final File m_refDir; public DirectoryRevision( Logger logger, Map configMap, WeakZipFileFactory zipFactory, File revisionRootDir, String location) throws Exception { super(logger, configMap, revisionRootDir, location); m_zipFactory = zipFactory; m_refDir = new File(location.substring( location.indexOf(BundleArchive.FILE_PROTOCOL) + BundleArchive.FILE_PROTOCOL.length())); // If the revision directory exists, then we don't // need to initialize since it has already been done. if (BundleCache.getSecureAction().fileExists(getRevisionRootDir())) { return; } // Create revision directory, we only need this to store the // revision location, since nothing else needs to be extracted // since we are referencing a read directory already. if (!BundleCache.getSecureAction().mkdir(getRevisionRootDir())) { getLogger().log( Logger.LOG_ERROR, getClass().getName() + ": Unable to create revision directory."); throw new IOException("Unable to create archive directory."); } } public synchronized Map getManifestHeader() throws Exception { // Read the header file from the reference directory. InputStream is = null; try { // Open manifest file. is = BundleCache.getSecureAction() .getFileInputStream(new File(m_refDir, "META-INF/MANIFEST.MF")); // Error if no jar file. if (is == null) { throw new IOException("No manifest file found."); } // Get manifest. Manifest mf = new Manifest(is); // Create a case insensitive map of manifest attributes. return new StringMap(mf.getMainAttributes(), false); } finally { if (is != null) is.close(); } } public synchronized Content getContent() throws Exception { return new DirectoryContent(getLogger(), getConfig(), m_zipFactory, this, getRevisionRootDir(), m_refDir); } protected void close() throws Exception { // Nothing to close since we don't maintain any state outside // of the revision directory, which will be automatically deleted // by the parent bundle archive. } }felix-framework-4.0.1.orig/src/main/java/org/apache/felix/framework/cache/BundleCache.java0000644000175000017500000003662111644651230031276 0ustar drazzibdrazzib/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.framework.cache; import java.io.*; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.util.*; import org.apache.felix.framework.Logger; import org.apache.felix.framework.util.SecureAction; import org.apache.felix.framework.util.WeakZipFileFactory; import org.osgi.framework.Constants; /** *

* This class, combined with BundleArchive, and concrete * BundleRevision subclasses, implement the Felix bundle cache. * It is possible to configure the default behavior of this class by * passing properties into Felix' constructor. The configuration properties * for this class are (properties starting with "felix" are specific * to Felix, while those starting with "org.osgi" are standard OSGi * properties): *

*