initial public commit

This commit is contained in:
2021-09-06 17:46:59 +03:00
commit b744b08829
824 changed files with 91593 additions and 0 deletions

201
system/LICENSE.txt Normal file
View File

@ -0,0 +1,201 @@
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.

201
system/auth/LICENSE.txt Normal file
View File

@ -0,0 +1,201 @@
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.

View File

@ -0,0 +1,201 @@
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.

View File

@ -0,0 +1,71 @@
# SYSTEM :: ENTAXY :: AUTH BASIC
Реализация web-сервиса для загрузки актуальных или измененных пользователей и их параметры аутентификации (логин АД или данные Basic авторизации)
##Admin
Стартовый пользователь **admin/admin**, записывается через liquibase, без связанной системы.
По умолчанию выданы права на управленческий слой, сервисы:
- system-management
- basic-auth-management
- permission-management
- topic-management
!!!Требуется сменить пароль!!!
Файл Htpasswd не генерируется до первого обращения к сервису basic-auth-management.
## Сборка
Сборка осуществляется командой
```
mvn clean install
```
По умолчанию запускается профиль dev, в котором прописаны параметры соединения к разработческой базе.
Запуск профиля для production:
```
mvn clean install -Denv=prod
```
Параметры соединения хранятся в свойствах профилей в pom.xml
## Установка в karaf
Добавление репозитория в karaf
```
feature:repo-add mvn:ru.entaxy.esb/karaf-features/LATEST/xml/features
```
Установка auth basic
```
feature:install basic-auth
```
## Подключение cxf interceptor для идентификации систем
```
<reference id="serviceInterceptor" interface="org.apache.cxf.phase.PhaseInterceptor"
filter="(type=service)"/>
<cxf:bus id="esb-entaxy">
<cxf:inInterceptors>
<ref component-id="serviceInterceptor"/>
</cxf:inInterceptors>
</cxf:bus>
```
Интерцептор принимает заголовок с логином **X-ForwardedUser** от nginX
Данные по определённой системе записываются в заголовки
- **X-SystemName**
- **X-SystemUuid**
- **X-SystemId**

View File

@ -0,0 +1,201 @@
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.

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>ru.entaxy.esb.system.auth.basic</groupId>
<artifactId>basic-auth</artifactId>
<version>1.8.0</version>
</parent>
<groupId>ru.entaxy.esb.system.auth.basic.api</groupId>
<artifactId>basic-auth-api</artifactId>
<packaging>bundle</packaging>
<name>SYSTEM :: ENTAXY :: BASIC AUTH SERVICE API</name>
<description>SYSTEM :: ENTAXY :: BASIC AUTH SERVICE API</description>
<properties>
<bundle.osgi.export.pkg>
ru.entaxy.esb.system.auth.basic.jpa.api,
ru.entaxy.esb.system.auth.basic.jpa.api.entity,
ru.entaxy.esb.system.auth.basic.jpa.api.entity.field,
ru.entaxy.esb.system.auth.basic.jpa.api.exception
</bundle.osgi.export.pkg>
<bundle.osgi.import.pkg>
javax.persistence;version="[2,3)",
org.hibernate.proxy;version="[5,6)",
javassist.util.proxy,
*
</bundle.osgi.import.pkg>
</properties>
<dependencies>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>javax.persistence</artifactId>
<version>${jpa.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>ru.entaxy.esb.system.commons</groupId>
<artifactId>system-commons</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,51 @@
/*-
* ~~~~~~licensing~~~~~~
* basic-auth-api
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.auth.basic.jpa.api;
import ru.entaxy.esb.system.auth.basic.jpa.api.entity.BasicAuthAccount;
import ru.entaxy.esb.system.auth.basic.jpa.api.exception.BadPasswordException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.Optional;
public interface BasicAuthService {
List<BasicAuthAccount> list();
Optional<BasicAuthAccount> get(String login);
Optional<BasicAuthAccount> getByAuthorizationHeaderHash(String authorizationHeaderHash);
BasicAuthAccount save(BasicAuthAccount basicAuthAccount, boolean isExist);
public BasicAuthAccount saveFull(String login, String passwordHash, String encryptionAlgorithm, String systemUUID,
String authorizationHeaderHash, String description, String createdBy, String editedBy);
BasicAuthAccount saveCommon(String login, String passwordHash, String systemUUID, String createdBy, String editedBy)
throws NoSuchAlgorithmException, BadPasswordException;
BasicAuthAccount saveShort(String login, String passwordHash, String createdBy, String editedBy) throws NoSuchAlgorithmException, BadPasswordException;
void remove(String login);
boolean check(String login, String password);
}

View File

@ -0,0 +1,185 @@
/*-
* ~~~~~~licensing~~~~~~
* basic-auth-api
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.auth.basic.jpa.api.entity;
import com.sun.istack.NotNull;
import ru.entaxy.esb.system.auth.basic.jpa.api.entity.field.EncryptionAlgorithm;
import ru.entaxy.esb.system.auth.basic.jpa.api.entity.field.EncryptionAlgorithmAttributeConverter;
import javax.persistence.*;
import java.util.Date;
import java.util.Objects;
@Entity
@Table(name = "basic_auth_account")
public class BasicAuthAccount {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotNull
@Column(name = "login")
private String login;
@NotNull
@Column(name = "password_hash")
private String passwordHash;
@Column(name = "encryption_algorithm")
@Convert(converter = EncryptionAlgorithmAttributeConverter.class)
private EncryptionAlgorithm encryptionAlgorithm;
@Column(name = "system_uuid")
private String systemUUID;
@NotNull
@Column(name = "authorization_header_hash")
private String authorizationHeaderHash;
@Column(name = "description")
private String description;
@NotNull
@Column(name = "create_date")
private Date createDate;
@Column(name = "edit_date")
private Date editDate;
@NotNull
@Column(name = "created_by")
private String createdBy;
@Column(name = "edited_by")
private String editedBy;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getPasswordHash() {
return passwordHash;
}
public void setPasswordHash(String passwordHash) {
this.passwordHash = passwordHash;
}
public EncryptionAlgorithm getEncryptionAlgorithm() {
return encryptionAlgorithm;
}
public void setEncryptionAlgorithm(EncryptionAlgorithm encryptionAlgorithm) {
this.encryptionAlgorithm = encryptionAlgorithm;
}
public String getSystemUUID() {
return systemUUID;
}
public void setSystemUUID(String systemUUID) {
this.systemUUID = systemUUID;
}
public String getAuthorizationHeaderHash() {
return authorizationHeaderHash;
}
public void setAuthorizationHeaderHash(String authorizationHeaderHash) {
this.authorizationHeaderHash = authorizationHeaderHash;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
public Date getEditDate() {
return editDate;
}
public void setEditDate(Date editDate) {
this.editDate = editDate;
}
public String getCreatedBy() {
return createdBy;
}
public void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
}
public String getEditedBy() {
return editedBy;
}
public void setEditedBy(String editedBy) {
this.editedBy = editedBy;
}
@Override
public int hashCode() {
return Objects.hash(authorizationHeaderHash, createDate, createdBy, description, editDate, editedBy,
encryptionAlgorithm, login, passwordHash, systemUUID);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
BasicAuthAccount other = (BasicAuthAccount) obj;
return Objects.equals(authorizationHeaderHash, other.authorizationHeaderHash)
&& Objects.equals(createDate, other.createDate) && Objects.equals(createdBy, other.createdBy)
&& Objects.equals(description, other.description) && Objects.equals(editDate, other.editDate)
&& Objects.equals(editedBy, other.editedBy)
&& Objects.equals(encryptionAlgorithm, other.encryptionAlgorithm) && Objects.equals(login, other.login)
&& Objects.equals(passwordHash, other.passwordHash)
&& Objects.equals(systemUUID, other.systemUUID);
}
@Override
public String toString() {
return "BasicAuthAccount [login=" + login + ", passwordHash=" + passwordHash + ", encryptionAlgorithm="
+ encryptionAlgorithm + ", systemUUID=" + systemUUID + ", authorizationHeaderHash=" + authorizationHeaderHash
+ ", description=" + description + ", createDate=" + createDate + ", editDate=" + editDate
+ ", createdBy=" + createdBy + ", editedBy=" + editedBy + "]";
}
}

View File

@ -0,0 +1,59 @@
/*-
* ~~~~~~licensing~~~~~~
* basic-auth-api
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.auth.basic.jpa.api.entity.field;
import java.util.Arrays;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
public enum EncryptionAlgorithm {
PLAIN("PLAIN"),
MD5("MD5"),
SHA1("SHA-1"),
SHA256("SHA-256"),
SHA384("SHA-384"),
SHA512("SHA-512");
private static Map<String, EncryptionAlgorithm> map = null;
private final String name;
EncryptionAlgorithm(String name) {
this.name = name;
}
public String getAlgorithmName() {
return name;
}
public boolean equalsName(String checkingName) {
return checkingName != null && this.name.equals(checkingName.toUpperCase());
}
public static EncryptionAlgorithm getByName(String name) {
return map.get(name.toUpperCase());
}
static {
map = Arrays.stream(EncryptionAlgorithm.values())
.collect(Collectors.toMap(EncryptionAlgorithm::getAlgorithmName, Function.identity()));
}
}

View File

@ -0,0 +1,38 @@
/*-
* ~~~~~~licensing~~~~~~
* basic-auth-api
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.auth.basic.jpa.api.entity.field;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
@Converter
public class EncryptionAlgorithmAttributeConverter implements AttributeConverter<EncryptionAlgorithm, String> {
@Override
public String convertToDatabaseColumn(EncryptionAlgorithm attribute) {
return attribute.getAlgorithmName();
}
@Override
public EncryptionAlgorithm convertToEntityAttribute(String dbData) {
return EncryptionAlgorithm.getByName(dbData.toUpperCase());
}
}

View File

@ -0,0 +1,46 @@
/*-
* ~~~~~~licensing~~~~~~
* basic-auth-api
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.auth.basic.jpa.api.exception;
public class BadPasswordException extends Exception {
private static final long serialVersionUID = -1675249900871877617L;
public BadPasswordException() {
}
public BadPasswordException(String message) {
super(message);
}
public BadPasswordException(Throwable cause) {
super(cause);
}
public BadPasswordException(String message, Throwable cause) {
super(message, cause);
}
public BadPasswordException(String message, Throwable cause, boolean enableSuppression,
boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

View File

@ -0,0 +1,201 @@
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.

View File

@ -0,0 +1,141 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>ru.entaxy.esb.system.auth.basic</groupId>
<artifactId>basic-auth</artifactId>
<version>1.8.0</version>
</parent>
<groupId>ru.entaxy.esb.system.auth.basic.impl</groupId>
<artifactId>basic-auth-impl</artifactId>
<packaging>bundle</packaging>
<name>SYSTEM :: ENTAXY :: BASIC AUTH SERVICE IMPL</name>
<description>SYSTEM :: ENTAXY :: BASIC AUTH SERVICE IMPL</description>
<properties>
<bundle.osgi.import.pkg>
ru.entaxy.esb.system.auth.basic.jpa.api,
ru.entaxy.esb.system.auth.basic.jpa.api.entity,
ru.entaxy.esb.system.auth.basic.jpa.api.entity.field,
ru.entaxy.esb.system.auth.basic.htpasswd,
ru.entaxy.esb.system.auth.basic.jpa.api.exception,
ru.entaxy.esb.system.core.permission.jpa.entity,
ru.entaxy.esb.system.common.util,
javax.persistence;version="[2,3)",
org.hibernate,
org.hibernate.cfg,
org.hibernate.service,
org.hibernate.jpa,
org.hibernate.proxy,
javassist.util.proxy,
org.apache.commons.codec.binary,
*
</bundle.osgi.import.pkg>
</properties>
<dependencies>
<dependency>
<groupId>ru.entaxy.esb.system.auth.basic.api</groupId>
<artifactId>basic-auth-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ru.entaxy.esb.system.auth.basic.htpasswd</groupId>
<artifactId>htpasswd</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ru.entaxy.esb.system.registry.systems</groupId>
<artifactId>system-api</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ru.entaxy.esb.system.core.permission</groupId>
<artifactId>permission-api</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>ru.entaxy.esb.system.core.permission</groupId>
<artifactId>permission-common</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>ru.entaxy.esb.system.commons</groupId>
<artifactId>system-commons</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>osgi.core</artifactId>
<version>${osgi.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>javax.persistence</artifactId>
<version>${jpa.version}</version>
</dependency>
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>javax.transaction-api</artifactId>
<version>${javax.transaction.version}</version>
</dependency>
<dependency>
<groupId>javax.interceptor</groupId>
<artifactId>javax.interceptor-api</artifactId>
<version>${javax.interceptor.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commons-codec.version}</version>
</dependency>
</dependencies>
<profiles>
<!-- Development settings, -Denv=dev -->
<profile>
<id>dev</id>
<activation>
<property>
<name>env</name>
<value>dev</value>
</property>
</activation>
<properties>
<hibernate.show_sql>true</hibernate.show_sql>
<hibernate.format_sql>true</hibernate.format_sql>
</properties>
</profile>
<!-- Production settings, -Denv=prod -->
<profile>
<id>prod</id>
<activation>
<property>
<name>env</name>
<value>!dev</value>
</property>
</activation>
<properties>
<hibernate.show_sql>false</hibernate.show_sql>
<hibernate.format_sql>false</hibernate.format_sql>
</properties>
</profile>
</profiles>
</project>

View File

@ -0,0 +1,131 @@
/*-
* ~~~~~~licensing~~~~~~
* basic-auth-impl
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.auth.basic.interceptor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.cxf.common.util.Base64Exception;
import org.apache.cxf.common.util.Base64Utility;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.interceptor.security.AuthenticationException;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.apache.cxf.transport.http.Headers;
import ru.entaxy.esb.system.auth.basic.jpa.api.BasicAuthService;
import ru.entaxy.esb.system.common.util.SystemHeadersConstants;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public class AuthenticationInterceptor extends AbstractPhaseInterceptor<Message> {
private static final Log LOG = LogFactory.getLog(AuthenticationInterceptor.class);
private boolean enabled = false;
private BasicAuthService basicAuthService;
private static final String BASIC = "Basic";
private static final String AUTHORIZATION = "Authorization";
private static final String WWW_AUTHENTICATE = "WWW-Authenticate";
private static final String WWW_AUTHENTICATE_MESSAGE = "Basic realm=\"Access to Entaxy\"";
public AuthenticationInterceptor() {
super(Phase.RECEIVE);
}
@Override
public void handleMessage(Message message) throws Fault {
LOG.debug("AuthenticationInterceptor enabled=" + enabled);
if (!enabled) {
return;
}
Map<String, List<String>> headers = Headers.getSetProtocolHeaders(message);
//reset passed value
headers.put(SystemHeadersConstants.HEADER_USER_LOGIN, Collections.emptyList());
Optional<String> auth = Optional.ofNullable(headers.get(AUTHORIZATION)).
orElse(Collections.emptyList())
.stream().findFirst();
if (auth.isPresent()) {
String[] namePassword = prepareAuthData(message, auth);
if (namePassword.length == 2 && isAuthenticated(namePassword[0], namePassword[1])) {
// let request to continue
LOG.trace(namePassword[0] + " authenticated");
headers.put(SystemHeadersConstants.HEADER_USER_LOGIN, Collections.singletonList(namePassword[0]));
} else {
faultAction(message);
}
} else {
faultAction(message);
}
}
private String[] prepareAuthData(Message message, Optional<String> auth) {
String[] parts = auth.get().split(" ");
if (parts.length != 2 || !BASIC.equals(parts[0])) {
faultAction(message);
}
String decodedValue = null;
try {
decodedValue = new String(Base64Utility.decode(parts[1]));
} catch (Base64Exception ex) {
faultAction(message);
}
String[] namePassword = decodedValue.split(":");
return namePassword;
}
private void faultAction(Message message) {
Map<String, List<String>> headers = Headers.getSetProtocolHeaders(message);
headers.put(WWW_AUTHENTICATE, Collections.singletonList(WWW_AUTHENTICATE_MESSAGE));
Fault fault = new Fault(new AuthenticationException("Unauthorized Access"));
fault.setFaultCode(Fault.FAULT_CODE_CLIENT);
fault.setStatusCode(401);
throw fault;
}
private boolean isAuthenticated(String name, String password) {
return basicAuthService.check(name, password);
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public BasicAuthService getBasicAuthService() {
return basicAuthService;
}
public void setBasicAuthService(BasicAuthService basicAuthService) {
this.basicAuthService = basicAuthService;
}
}

View File

@ -0,0 +1,110 @@
/*-
* ~~~~~~licensing~~~~~~
* basic-auth-impl
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.auth.basic.interceptor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.apache.cxf.transport.http.Headers;
import ru.entaxy.esb.system.auth.basic.jpa.api.BasicAuthService;
import ru.entaxy.esb.system.auth.basic.jpa.api.entity.BasicAuthAccount;
import ru.entaxy.esb.system.common.util.SystemHeadersConstants;
import ru.entaxy.esb.system.jpa.SystemService;
import ru.entaxy.esb.system.jpa.entity.System;
import javax.ws.rs.ForbiddenException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public class SystemInterceptor extends AbstractPhaseInterceptor<Message> {
private static final Log LOG = LogFactory.getLog(SystemInterceptor.class);
private BasicAuthService basicAuthService;
private SystemService systemService;
public SystemInterceptor() {
super(Phase.PRE_PROTOCOL);
}
@Override
public void handleMessage(Message message) throws Fault {
Map<String, List<String>> headers = Headers.getSetProtocolHeaders(message);
Optional<String> login = Optional.ofNullable(headers.get(SystemHeadersConstants.HEADER_USER_LOGIN)).
orElse(Collections.emptyList())
.stream().findFirst();
//TEST
// login = Optional.of("user");
LOG.trace(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>SystemInterceptor <<< headers.get( HEADER_USER_LOGIN ) " + login.orElse("NULL"));
if (login.isPresent()) {
Optional<BasicAuthAccount> accountOpt = basicAuthService.get(login.get());
if (accountOpt.isPresent()) {
BasicAuthAccount account = accountOpt.get();
headers.put(SystemHeadersConstants.HEADER_USER_ID, Collections.singletonList(String.valueOf(account.getId())));
headers.put(SystemHeadersConstants.HEADER_SYSTEM_UUID, Collections.singletonList(account.getSystemUUID()));
System system = account.getSystemUUID() != null && !account.getSystemUUID().isEmpty()
? systemService.getByUuid(account.getSystemUUID())
: null;
if (system != null) {
headers.put(SystemHeadersConstants.HEADER_SYSTEM_NAME, Collections.singletonList(system.getName()));
headers.put(SystemHeadersConstants.HEADER_SYSTEM_ID, Collections.singletonList(String.valueOf(system.getId())));
}
} else {
throw new ForbiddenException();
}
}
// It stops the process
// else {
// message.getInterceptorChain().abort();
// }
}
public BasicAuthService getBasicAuthService() {
return basicAuthService;
}
public void setBasicAuthService(BasicAuthService basicAuthService) {
this.basicAuthService = basicAuthService;
}
public SystemService getSystemService() {
return systemService;
}
public void setSystemService(SystemService systemService) {
this.systemService = systemService;
}
}

View File

@ -0,0 +1,247 @@
/*-
* ~~~~~~licensing~~~~~~
* basic-auth-impl
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.auth.basic.jpa.impl;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.entaxy.esb.system.auth.basic.jpa.api.BasicAuthService;
import ru.entaxy.esb.system.auth.basic.jpa.api.entity.BasicAuthAccount;
import ru.entaxy.esb.system.auth.basic.jpa.api.entity.field.EncryptionAlgorithm;
import ru.entaxy.esb.system.auth.basic.jpa.api.exception.BadPasswordException;
import ru.entaxy.esb.system.auth.basic.jpa.util.EncryptionHelper;
import ru.entaxy.esb.system.core.permission.common.PermissionConstants;
import ru.entaxy.esb.system.core.permission.jpa.PermissionService;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.List;
import java.util.Optional;
public class BasicAuthServiceImpl implements BasicAuthService {
private static final Logger LOG = LoggerFactory.getLogger(BasicAuthServiceImpl.class);
private SessionFactory sessionFactory;
private String еncryptionAlgorithm;
private String encryptionSalt;
private PermissionService permissionService;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public Session getSession() {
return sessionFactory.openSession();
}
public void setЕncryptionAlgorithm(String еncryptionAlgorithm) {
this.еncryptionAlgorithm = еncryptionAlgorithm;
}
public void setEncryptionSalt(String encryptionSalt) {
this.encryptionSalt = encryptionSalt;
}
public PermissionService getPermissionService() {
return permissionService;
}
public void setPermissionService(PermissionService permissionService) {
this.permissionService = permissionService;
}
@Override
public List<BasicAuthAccount> list() {
List<BasicAuthAccount> list;
try (Session s = getSession()) {
s.getTransaction().begin();
CriteriaQuery<BasicAuthAccount> cq = s.getCriteriaBuilder().createQuery(BasicAuthAccount.class);
cq.from(BasicAuthAccount.class);
list = s.createQuery(cq).getResultList();
s.getTransaction().commit();
s.close();
}
return list;
}
@Override
public Optional<BasicAuthAccount> get(String login) {
Optional<BasicAuthAccount> basicAuthAccount;
try (Session s = getSession()) {
s.getTransaction().begin();
CriteriaBuilder builder = s.getCriteriaBuilder();
CriteriaQuery<BasicAuthAccount> criteriaQuery = builder.createQuery(BasicAuthAccount.class);
Root<BasicAuthAccount> root = criteriaQuery.from(BasicAuthAccount.class);
criteriaQuery.where(builder.equal(root.get("login"), login));
basicAuthAccount = s.createQuery(criteriaQuery).uniqueResultOptional();
s.getTransaction().commit();
s.close();
}
return basicAuthAccount;
}
public Optional<BasicAuthAccount> get(Session session, String login) {
Optional<BasicAuthAccount> basicAuthAccount;
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<BasicAuthAccount> criteriaQuery = builder.createQuery(BasicAuthAccount.class);
Root<BasicAuthAccount> root = criteriaQuery.from(BasicAuthAccount.class);
criteriaQuery.where(builder.equal(root.get("login"), login));
basicAuthAccount = session.createQuery(criteriaQuery).uniqueResultOptional();
return basicAuthAccount;
}
@Override
public Optional<BasicAuthAccount> getByAuthorizationHeaderHash(String authorizationHeaderHash) {
Optional<BasicAuthAccount> basicAuthAccount;
try (Session s = getSession()) {
s.getTransaction().begin();
CriteriaBuilder builder = s.getCriteriaBuilder();
CriteriaQuery<BasicAuthAccount> criteriaQuery = builder.createQuery(BasicAuthAccount.class);
Root<BasicAuthAccount> root = criteriaQuery.from(BasicAuthAccount.class);
criteriaQuery.where(builder.equal(root.get("authorizationHeaderHash"), authorizationHeaderHash));
basicAuthAccount = s.createQuery(criteriaQuery).uniqueResultOptional();
s.getTransaction().commit();
s.close();
}
return basicAuthAccount;
}
@Override
public BasicAuthAccount save(BasicAuthAccount basicAuthAccount, boolean isExist) {
try (Session s = getSession()) {
s.getTransaction().begin();
if (isExist) {
s.update(basicAuthAccount);
} else {
s.persist(basicAuthAccount);
}
s.getTransaction().commit();
s.close();
}
return basicAuthAccount;
}
@Override
public BasicAuthAccount saveFull(String login, String passwordHash, String encryptionAlgorithm, String systemUUID,
String authorizationHeaderHash, String description, String createdBy, String editedBy) {
LOG.debug("Parameters " + login + " " + passwordHash + " " + encryptionAlgorithm
+ " " + systemUUID + " " + authorizationHeaderHash + " " + description + " " + createdBy + " " + editedBy);
Optional<BasicAuthAccount> existingBasicAuthAccount = get(login);
EncryptionAlgorithm encryptionAlgorithmObj = EncryptionAlgorithm.getByName(encryptionAlgorithm.toUpperCase());
BasicAuthAccount basicAuthAccount = existingBasicAuthAccount.orElseGet(BasicAuthAccount::new);
settingBasicAuthAccount(login, passwordHash, encryptionAlgorithmObj, systemUUID, authorizationHeaderHash,
description, createdBy, editedBy, basicAuthAccount, existingBasicAuthAccount.isPresent());
return save(basicAuthAccount, existingBasicAuthAccount.isPresent());
}
private BasicAuthAccount settingBasicAuthAccount(String login, String passwordHash, EncryptionAlgorithm encryptionAlgorithm,
String systemUUID, String authorizationHeaderHash,
String description, String createdBy, String editedBy,
BasicAuthAccount basicAuthAccount, boolean isExist) {
if (!isExist) {
basicAuthAccount.setLogin(login);
basicAuthAccount.setCreateDate(new Date());
basicAuthAccount.setCreatedBy(createdBy);
} else {
basicAuthAccount.setEditDate(new Date());
basicAuthAccount.setEditedBy(editedBy);
}
basicAuthAccount.setPasswordHash(passwordHash);
basicAuthAccount.setEncryptionAlgorithm(encryptionAlgorithm);
basicAuthAccount.setSystemUUID(systemUUID);
basicAuthAccount.setAuthorizationHeaderHash(authorizationHeaderHash);
basicAuthAccount.setDescription(description);
return basicAuthAccount;
}
@Override
public BasicAuthAccount saveCommon(String login, String passwordHash, String systemUUID, String createdBy, String editedBy)
throws NoSuchAlgorithmException, BadPasswordException {
if (null != passwordHash && !passwordHash.isEmpty()) {
passwordHash = EncryptionHelper.encrypt(passwordHash, this.еncryptionAlgorithm, this.encryptionSalt);
} else {
throw new BadPasswordException("Password not passed or empty!");
}
return saveFull(login, passwordHash, this.еncryptionAlgorithm, systemUUID, "", "", createdBy, editedBy);
}
@Override
public BasicAuthAccount saveShort(String login, String passwordHash, String createdBy, String editedBy)
throws NoSuchAlgorithmException, BadPasswordException {
return saveCommon(login, passwordHash, "", createdBy, editedBy);
}
@Override
public void remove(String login) {
try (Session s = getSession()) {
s.getTransaction().begin();
Optional<BasicAuthAccount> basicAuthAccount = get(s, login);
basicAuthAccount.ifPresent((basicAuthAccount1) -> removeProc(s, basicAuthAccount1));
s.getTransaction().commit();
s.close();
}
}
private void removeProc(Session session, BasicAuthAccount account) {
permissionService.removeAll(session, account.getId(), PermissionConstants.TYPE_ACCOUNT);
session.flush();
session.delete(BasicAuthAccount.class.getName(), account);
}
@Override
public boolean check(String login, String password) {
if (login != null && password != null) {
Optional<BasicAuthAccount> basicAuthAccountOpt = get(login);
if (basicAuthAccountOpt.isPresent()) {
BasicAuthAccount basicAuthAccount = basicAuthAccountOpt.get();
try {
String passedPasswordHash = EncryptionHelper.encrypt(password,
basicAuthAccount.getEncryptionAlgorithm().getAlgorithmName(),
this.encryptionSalt);
if (passedPasswordHash.equals(basicAuthAccount.getPasswordHash())) {
return true;
}
} catch (NoSuchAlgorithmException e) {
LOG.error("Encription algorithm error", e);
}
}
}
return false;
}
}

View File

@ -0,0 +1,118 @@
/*-
* ~~~~~~licensing~~~~~~
* basic-auth-impl
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.auth.basic.jpa.listener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.event.spi.*;
import org.hibernate.persister.entity.EntityPersister;
import ru.entaxy.esb.system.auth.basic.htpasswd.HtpasswdGenerator;
import ru.entaxy.esb.system.auth.basic.jpa.api.BasicAuthService;
import ru.entaxy.esb.system.auth.basic.jpa.api.entity.BasicAuthAccount;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
public class BasicAuthPostEventListener implements PostCommitInsertEventListener, PostCommitUpdateEventListener, PostCommitDeleteEventListener {
private static final long serialVersionUID = -6603994118756820823L;
private static final Log LOG = LogFactory.getLog(BasicAuthPostEventListener.class);
private BasicAuthService basicAuthService;
private HtpasswdGenerator htpasswdGenerator;
private String encryptionSalt;
public void setEncryptionSalt(String encryptionSalt) {
this.encryptionSalt = encryptionSalt;
}
@Override
public boolean requiresPostCommitHanding(EntityPersister persister) {
return true;
}
@Override
public void onPostDelete(PostDeleteEvent event) {
LOG.debug("Delete handler event " + event.getSession());
LOG.debug("Delete handler event " + event.getEntity());
if (event.getEntity() instanceof BasicAuthAccount) {
generateHtpasswd();
}
}
@Override
public void onPostUpdate(PostUpdateEvent event) {
LOG.debug("Update handler event " + event);
LOG.debug("Update handler event " + event.getEntity());
generateHtpasswd();
}
@Override
public void onPostInsert(PostInsertEvent event) {
LOG.debug("Insert handler event " + event);
LOG.debug("Insert handler event " + event.getEntity());
generateHtpasswd();
}
private void generateHtpasswd() {
List<BasicAuthAccount> accounts = basicAuthService.list();
try {
htpasswdGenerator.generateHtpasswd(accounts, encryptionSalt);
} catch (NoSuchAlgorithmException | IOException e) {
LOG.error(e);
}
}
@Override
public void onPostDeleteCommitFailed(PostDeleteEvent event) {
LOG.debug("Delete failed event " + event.getEntity());
}
@Override
public void onPostUpdateCommitFailed(PostUpdateEvent event) {
LOG.debug("Update failed event " + event.getEntity());
}
@Override
public void onPostInsertCommitFailed(PostInsertEvent event) {
LOG.debug("Insert failed event " + event.getEntity());
}
public BasicAuthService getBasicAuthService() {
return basicAuthService;
}
public void setBasicAuthService(BasicAuthService basicAuthService) {
this.basicAuthService = basicAuthService;
}
public HtpasswdGenerator getHtpasswdGenerator() {
return htpasswdGenerator;
}
public void setHtpasswdGenerator(HtpasswdGenerator htpasswdGenerator) {
this.htpasswdGenerator = htpasswdGenerator;
}
}

View File

@ -0,0 +1,87 @@
/*-
* ~~~~~~licensing~~~~~~
* basic-auth-impl
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.auth.basic.jpa.listener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.SessionFactory;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.EventType;
public class EntityEventListenerRegistry {
private static final Log LOG = LogFactory.getLog(EntityEventListenerRegistry.class);
private static final int SESSION_WAIT_TIMEOUT = 5000;
private SessionFactory sessionFactory;
private BasicAuthPostEventListener basicAuthPostEventListener;
private int initLimiter = 0;
public void registerListeners() {
LOG.info("Init EntityEventListenerRegistry " + sessionFactory.getClass().getName());
EventListenerRegistry registry = prepareRegistry();
registry.getEventListenerGroup(EventType.POST_COMMIT_INSERT).appendListener(basicAuthPostEventListener);
registry.getEventListenerGroup(EventType.POST_COMMIT_UPDATE).appendListener(basicAuthPostEventListener);
registry.getEventListenerGroup(EventType.POST_COMMIT_DELETE).appendListener(basicAuthPostEventListener);
}
private EventListenerRegistry prepareRegistry() {
try {
SessionFactoryImplementor sessionFactoryImpl = sessionFactory.unwrap(SessionFactoryImplementor.class);
EventListenerRegistry registry = sessionFactoryImpl.getServiceRegistry().getService(EventListenerRegistry.class);
return registry;
} catch (Exception e) {
LOG.error(e.getMessage());
if (initLimiter == 10) {
LOG.error(e);
}
try {
LOG.warn("Wait sessionFactory initialization...");
Thread.sleep(SESSION_WAIT_TIMEOUT);
} catch (InterruptedException e1) {
}
}
return initLimiter++ <= 9
? prepareRegistry()
: null;
}
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public BasicAuthPostEventListener getBasicAuthPostEventListener() {
return basicAuthPostEventListener;
}
public void setBasicAuthPostEventListener(BasicAuthPostEventListener basicAuthPostEventListener) {
this.basicAuthPostEventListener = basicAuthPostEventListener;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
}

View File

@ -0,0 +1,65 @@
/*-
* ~~~~~~licensing~~~~~~
* basic-auth-impl
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.auth.basic.jpa.util;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.codec.digest.Md5Crypt;
import org.apache.commons.codec.digest.Sha2Crypt;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.entaxy.esb.system.auth.basic.jpa.api.entity.field.EncryptionAlgorithm;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
public class EncryptionHelper {
private static final Logger LOG = LoggerFactory.getLogger(EncryptionHelper.class);
static final String APR1_PREFIX = "$apr1$";
static final String SHA512_PREFIX = "$6$";
private EncryptionHelper() {
throw new IllegalStateException("Utility class");
}
public static String encrypt(String plaintext, String cipher, String salt) throws NoSuchAlgorithmException {
String passwordHash;
if (EncryptionAlgorithm.MD5.equalsName(cipher)) {
passwordHash = Md5Crypt.apr1Crypt((plaintext.getBytes(StandardCharsets.UTF_8)), salt);
passwordHash = passwordHash.substring(passwordHash.lastIndexOf("$") + 1);
} else if (EncryptionAlgorithm.SHA1.equalsName(cipher)) {
passwordHash = Base64.encodeBase64String(
DigestUtils.sha1((plaintext + salt).getBytes(StandardCharsets.UTF_8)));
} else if (EncryptionAlgorithm.SHA512.equalsName(cipher)) {
passwordHash = Sha2Crypt.sha512Crypt((plaintext.getBytes(StandardCharsets.UTF_8)), SHA512_PREFIX + salt);
passwordHash = passwordHash.substring(passwordHash.lastIndexOf("$"));
} else if (EncryptionAlgorithm.PLAIN.equalsName(cipher)) {
passwordHash = plaintext;
} else {
throw new NoSuchAlgorithmException();
}
return passwordHash;
}
}

View File

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~~~~~~licensing~~~~~~
basic-auth-impl
==========
Copyright (C) 2020 - 2021 EmDev LLC
==========
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.
~~~~~~/licensing~~~~~~
-->
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0"
xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 https://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
<cm:property-placeholder persistent-id="ru.entaxy.esb.system.basic_auth" update-strategy="reload">
<cm:default-properties>
<cm:property name="еncryption.algorithm" value="SHA-1"/>
<cm:property name="еncryption.salt" value="kDfq0qZJ"/>
<cm:property name="internal.authentication.enabled" value="false"/>
</cm:default-properties>
</cm:property-placeholder>
<reference id="sessionFactory"
interface="org.hibernate.SessionFactory"
timeout="30000"/>
<reference id="permissionService"
interface="ru.entaxy.esb.system.core.permission.jpa.PermissionService"
timeout="30000"
availability="mandatory"/>
<service ref="basicAuthService" interface="ru.entaxy.esb.system.auth.basic.jpa.api.BasicAuthService"/>
<bean id="basicAuthService" class="ru.entaxy.esb.system.auth.basic.jpa.impl.BasicAuthServiceImpl">
<property name="sessionFactory" ref="sessionFactory"/>
<property name="еncryptionAlgorithm" value="${еncryption.algorithm}"/>
<property name="encryptionSalt" value="${еncryption.salt}"/>
<property name="permissionService" ref="permissionService"/>
</bean>
<reference xmlns:ext="http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.0.0"
id="htpasswdGenerator"
interface="ru.entaxy.esb.system.auth.basic.htpasswd.HtpasswdGenerator"
timeout="30000"
availability="mandatory"
ext:proxy-method="classes"/>
<bean id="basicAuthPostEventListener"
class="ru.entaxy.esb.system.auth.basic.jpa.listener.BasicAuthPostEventListener">
<property name="basicAuthService" ref="basicAuthService"/>
<property name="encryptionSalt" value="${еncryption.salt}"/>
<property name="htpasswdGenerator" ref="htpasswdGenerator"/>
</bean>
<bean id="baseAuthPostDeleteEventListener"
class="ru.entaxy.esb.system.auth.basic.jpa.listener.EntityEventListenerRegistry"
init-method="registerListeners">
<property name="sessionFactory" ref="sessionFactory"/>
<property name="basicAuthPostEventListener" ref="basicAuthPostEventListener"/>
</bean>
<reference id="systemService"
interface="ru.entaxy.esb.system.jpa.SystemService"
timeout="30000"
availability="mandatory"/>
<bean id="systemInterceptor" class="ru.entaxy.esb.system.auth.basic.interceptor.SystemInterceptor">
<property name="basicAuthService" ref="basicAuthService"/>
<property name="systemService" ref="systemService"/>
</bean>
<service ref="systemInterceptor" interface="org.apache.cxf.phase.PhaseInterceptor">
<service-properties>
<entry key="type" value="system"/>
</service-properties>
</service>
<bean id="authInterceptor" class="ru.entaxy.esb.system.auth.basic.interceptor.AuthenticationInterceptor">
<property name="basicAuthService" ref="basicAuthService"/>
<property name="enabled" value="${internal.authentication.enabled}"/>
</bean>
<service ref="authInterceptor" interface="org.apache.cxf.phase.PhaseInterceptor">
<service-properties>
<entry key="type" value="authentication"/>
</service-properties>
</service>
</blueprint>

View File

@ -0,0 +1,38 @@
<?xml version='1.0' encoding='utf-8'?>
<!--
~~~~~~licensing~~~~~~
basic-auth-impl
==========
Copyright (C) 2020 - 2021 EmDev LLC
==========
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.
~~~~~~/licensing~~~~~~
-->
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.datasource">osgi:service/entaxy.esb.storage</property>
<property name="hibernate.hbm2ddl.auto">validate</property>
<property name="hibernate.enable_lazy_load_no_trans">true</property>
<mapping class="ru.entaxy.esb.system.auth.basic.jpa.api.entity.BasicAuthAccount"/>
<mapping class="ru.entaxy.esb.system.core.permission.jpa.entity.Permission"/>
</session-factory>
</hibernate-configuration>

View File

@ -0,0 +1,30 @@
###
# ~~~~~~licensing~~~~~~
# basic-auth-impl
# ==========
# Copyright (C) 2020 - 2021 EmDev LLC
# ==========
# 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.
# ~~~~~~/licensing~~~~~~
###
appender.file.type=File
appender.file.name=file
appender.file.fileName=target/camel-test.log
appender.file.layout.type=PatternLayout
appender.file.layout.pattern=%d %-5p %c{1} - %m %n
appender.out.type=Console
appender.out.name=out
appender.out.layout.type=PatternLayout
appender.out.layout.pattern=[%30.30t] %-30.30c{1} %-5p %m%n
rootLogger.level=DEBUG
rootLogger.appenderRef.out.ref=out

View File

@ -0,0 +1,201 @@
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.

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>basic-auth</artifactId>
<groupId>ru.entaxy.esb.system.auth.basic</groupId>
<version>1.8.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>basic-auth-soap</artifactId>
<packaging>bundle</packaging>
<name>SYSTEM :: ENTAXY :: BASIC AUTH SOAP</name>
<description>SYSTEM :: ENTAXY :: BASIC AUTH SOAP</description>
</project>

View File

@ -0,0 +1,242 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~~~~~~licensing~~~~~~
basic-auth-soap
==========
Copyright (C) 2020 - 2021 EmDev LLC
==========
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.
~~~~~~/licensing~~~~~~
-->
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0"
xmlns:cxf="http://cxf.apache.org/blueprint/core"
xmlns:camelcxf="http://camel.apache.org/schema/blueprint/cxf"
xmlns:bas="http://www.entaxy.ru/basic-auth-service/"
xsi:schemaLocation="
http://www.osgi.org/xmlns/blueprint/v1.0.0 https://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
http://cxf.apache.org/blueprint/core http://cxf.apache.org/schemas/blueprint/core.xsd
">
<cm:property-placeholder persistent-id="ru.entaxy.esb.system.basic_auth" update-strategy="reload">
<cm:default-properties>
<cm:property name="basic_auth_endpoint.address" value="/basic-auth-management"/>
</cm:default-properties>
</cm:property-placeholder>
<reference id="basicAuthService"
interface="ru.entaxy.esb.system.auth.basic.jpa.api.BasicAuthService"
timeout="30000"/>
<reference id="permissionService"
interface="ru.entaxy.esb.system.core.permission.jpa.PermissionService"
timeout="30000"/>
<reference id="serviceInterceptor" interface="org.apache.cxf.phase.PhaseInterceptor"
filter="(type=service)"/>
<reference id="authInterceptor" interface="org.apache.cxf.phase.PhaseInterceptor"
filter="(type=authentication)"/>
<camelcxf:cxfEndpoint id="basic-auth-endpoint"
address="${basic_auth_endpoint.address}"
endpointName="bas:basic-auth-serviceSOAP"
serviceName="bas:basic-auth-service"
wsdlURL="wsdl/basic-auth-service.wsdl">
<camelcxf:properties>
<entry key="dataFormat" value="PAYLOAD"/>
<entry key="mtom-enabled" value="false"/>
</camelcxf:properties>
<camelcxf:inInterceptors>
<ref component-id="authInterceptor"/>
<ref component-id="serviceInterceptor"/>
</camelcxf:inInterceptors>
</camelcxf:cxfEndpoint>
<camelContext id="basic-auth-service-camel-context" xmlns="http://camel.apache.org/schema/blueprint">
<route id="basic-auth-endpoint" streamCache="true">
<from uri="cxf:bean:basic-auth-endpoint"/>
<log message="${body}" loggingLevel="INFO"/>
<choice>
<when>
<simple>${headers.operationName} in 'addAccount,updateAccount'</simple>
<to uri="direct:update-account"/>
</when>
<when>
<simple>${headers.operationName} == 'removeAccount'</simple>
<to uri="direct:remove-account"/>
</when>
<when>
<simple>${headers.operationName} in 'addAccountPermission,removeAccountPermission'</simple>
<to uri="direct:update-account-permission"/>
</when>
</choice>
</route>
<route id="updateAccount">
<from uri="direct:update-account"/>
<doTry>
<split>
<xpath>//bas:accountList/bas:account</xpath>
<log message="\r\n${body}\r\n" loggingLevel="DEBUG"/>
<setHeader name="NTX_AccountLogin">
<xpath resultType="String">//bas:account/bas:login</xpath>
</setHeader>
<setHeader name="NTX_AccountPassword">
<xpath resultType="String">//bas:account/bas:password</xpath>
</setHeader>
<setHeader name="NTX_AccountSystemUUID">
<xpath resultType="String">//bas:account/bas:systemUUID</xpath>
</setHeader>
<log message="\r\n${headers.NTX_AccountLogin}\r\n" loggingLevel="DEBUG"/>
<log message="\r\n${headers.NTX_AccountPassword}\r\n" loggingLevel="DEBUG"/>
<log message="\r\n${headers.NTX_AccountSystemUUID}\r\n" loggingLevel="DEBUG"/>
<to uri="bean-fix:basicAuthService?method=saveCommon(${headers.NTX_AccountLogin}, ${headers.NTX_AccountPassword},
${headers.NTX_AccountSystemUUID}, ${headers.X-ForwardedUser}, ${headers.X-ForwardedUser})"/>
</split>
<setBody>
<constant>&lt;response xmlns="http://www.entaxy.ru/basic-auth-service/"&gt;true&lt;/response&gt;
</constant>
</setBody>
<doCatch>
<exception>java.lang.Exception</exception>
<log message="${exception.message}" loggingLevel="ERROR"/>
<log message="${exception.stacktrace}" loggingLevel="DEBUG"/>
<setBody>
<constant>&lt;response xmlns="http://www.entaxy.ru/basic-auth-service/"&gt;false&lt;/response&gt;</constant>
</setBody>
</doCatch>
</doTry>
</route>
<route id="removeAccount">
<from uri="direct:remove-account"/>
<doTry>
<split>
<xpath>//bas:loginList/bas:login</xpath>
<log message="\r\n${body}\r\n" loggingLevel="DEBUG"/>
<setHeader name="NTX_Login">
<xpath resultType="String">//bas:login</xpath>
</setHeader>
<log message="\r\n${headers.NTX_Login}\r\n" loggingLevel="DEBUG"/>
<to uri="bean-fix:basicAuthService?method=remove(${headers.NTX_Login})"/>
</split>
<setBody>
<constant>&lt;response xmlns="http://www.entaxy.ru/basic-auth-service/"&gt;true&lt;/response&gt;
</constant>
</setBody>
<doCatch>
<exception>java.lang.Exception</exception>
<log message="${exception.message}" loggingLevel="ERROR"/>
<setBody>
<constant>&lt;response xmlns="http://www.entaxy.ru/basic-auth-service/"&gt;false&lt;/response&gt;</constant>
</setBody>
</doCatch>
</doTry>
</route>
<route id="addAccountPermission">
<from uri="direct:update-account-permission"/>
<doTry>
<split>
<xpath>//bas:permissionList/bas:permission</xpath>
<to uri="direct:permission-request"/>
<log message="${headers.operationName} for ${exchangeProperty.NTX_Login} by user ${headers.X-ForwardedUser}"/>
<log message="\r\n${exchangeProperty.NTX_Login}\r\n" loggingLevel="DEBUG"/>
<log message="\r\n${exchangeProperty.NTX_Subject}\r\n" loggingLevel="DEBUG"/>
<log message="\r\n${exchangeProperty.NTX_SubjectType}\r\n" loggingLevel="DEBUG"/>
<log message="\r\n${exchangeProperty.NTX_Action}\r\n" loggingLevel="DEBUG"/>
<to uri="bean-fix:basicAuthService?method=get(${exchangeProperty.NTX_Login})"/>
<choice>
<when>
<simple>${body.isPresent()}</simple>
<setProperty name="account">
<simple>${body.get()}</simple>
</setProperty>
<choice>
<when>
<simple>${headers.operationName} == 'addAccountPermission'</simple>
<to uri="bean-fix:permissionService?method=addIfNotExist(${exchangeProperty.NTX_Action.id}, 'account', ${exchangeProperty.NTX_Subject},
${exchangeProperty.NTX_SubjectType}, ${exchangeProperty.NTX_Action})"/>
</when>
<when>
<simple>${headers.operationName} == 'removeAccountPermission'</simple>
<to uri="bean-fix:permissionService?method=remove(${exchangeProperty.NTX_Action.id}, 'account', ${exchangeProperty.NTX_Subject},
${exchangeProperty.NTX_SubjectType}, ${exchangeProperty.NTX_Action})"/>
</when>
</choice>
<to uri="bean-fix:basicAuthService?method=saveFull(${exchangeProperty.NTX_Action.login}, ${exchangeProperty.NTX_Action.passwordHash},
${exchangeProperty.NTX_Action.encryptionAlgorithm.getAlgorithmName()},
${exchangeProperty.NTX_Action.getSystemUUID()}, ${exchangeProperty.NTX_Action.authorizationHeaderHash},
${exchangeProperty.NTX_Action.description}, ${exchangeProperty.NTX_Action.createdBy},
${headers.X-ForwardedUser})"/>
</when>
<otherwise>
<throwException exceptionType="java.lang.IllegalArgumentException"
message="Account with current login not found"/>
</otherwise>
</choice>
</split>
<setBody>
<constant>&lt;response xmlns="http://www.entaxy.ru/basic-auth-service/"&gt;true&lt;/response&gt;
</constant>
</setBody>
<doCatch>
<exception>java.lang.Exception</exception>
<log message="${exception.message}" loggingLevel="ERROR"/>
<log message="${exception.stacktrace}" loggingLevel="DEBUG"/>
<setBody>
<constant>&lt;response xmlns="http://www.entaxy.ru/basic-auth-service/"&gt;false&lt;/response&gt;</constant>
</setBody>
</doCatch>
</doTry>
</route>
<route id="permissionRequest">
<from uri="direct:permission-request"/>
<setProperty name="NTX_Login">
<xpath resultType="String">//bas:permission/bas:login</xpath>
</setProperty>
<setProperty name="NTX_Subject">
<xpath resultType="String">//bas:permission/bas:subject</xpath>
</setProperty>
<setProperty name="NTX_SubjectType">
<xpath resultType="String">//bas:permission/bas:subjectType</xpath>
</setProperty>
<setProperty name="NTX_Action">
<xpath resultType="String">//bas:permission/bas:action</xpath>
</setProperty>
</route>
</camelContext>
</blueprint>

View File

@ -0,0 +1,157 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://www.entaxy.ru/basic-auth-service/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
name="basic-auth-service"
targetNamespace="http://www.entaxy.ru/basic-auth-service/">
<wsdl:types>
<xsd:schema targetNamespace="http://www.entaxy.ru/basic-auth-service/" elementFormDefault="qualified">
<xsd:element name="accountList" type="tns:accountListType"/>
<xsd:element name="response" type="xsd:boolean"/>
<xsd:complexType name="accountListType">
<xsd:sequence>
<xsd:element name="account" type="tns:accountType" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="accountType">
<xsd:sequence>
<xsd:element name="login" type="xsd:string"/>
<xsd:element name="password" type="xsd:string"/>
<xsd:element name="systemUUID" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="loginList" type="tns:loginListType"/>
<xsd:complexType name="loginListType">
<xsd:sequence>
<xsd:element name="login" type="xsd:string" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="permissionList" type="tns:permissionListType"/>
<xsd:complexType name="permissionListType">
<xsd:sequence>
<xsd:element name="permission" type="tns:permissionType" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="permissionType">
<xsd:sequence>
<xsd:element name="login" type="xsd:string"/>
<xsd:element name="subject" type="xsd:string"/>
<xsd:element name="subjectType" type="xsd:string"/>
<xsd:element name="action" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
</wsdl:types>
<wsdl:message name="addAccountRequest">
<wsdl:part name="request" element="tns:accountList"/>
</wsdl:message>
<wsdl:message name="addAccountResponse">
<wsdl:part name="response" element="tns:response"/>
</wsdl:message>
<wsdl:message name="updateAccountRequest">
<wsdl:part name="request" element="tns:accountList"/>
</wsdl:message>
<wsdl:message name="updateAccountResponse">
<wsdl:part name="response" element="tns:response"/>
</wsdl:message>
<wsdl:message name="removeAccountRequest">
<wsdl:part name="request" element="tns:loginList"/>
</wsdl:message>
<wsdl:message name="removeAccountResponse">
<wsdl:part name="response" element="tns:response"/>
</wsdl:message>
<wsdl:message name="addAccountPermissionRequest">
<wsdl:part name="request" element="tns:permissionList"/>
</wsdl:message>
<wsdl:message name="addAccountPermissionResponse">
<wsdl:part name="response" element="tns:response"/>
</wsdl:message>
<wsdl:message name="removeAccountPermissionRequest">
<wsdl:part name="request" element="tns:permissionList"/>
</wsdl:message>
<wsdl:message name="removeAccountPermissionResponse">
<wsdl:part name="response" element="tns:response"/>
</wsdl:message>
<wsdl:portType name="basic-auth-service">
<wsdl:operation name="addAccount">
<wsdl:input message="tns:addAccountRequest"/>
<wsdl:output message="tns:addAccountResponse"/>
</wsdl:operation>
<wsdl:operation name="updateAccount">
<wsdl:input message="tns:updateAccountRequest"/>
<wsdl:output message="tns:updateAccountResponse"/>
</wsdl:operation>
<wsdl:operation name="removeAccount">
<wsdl:input message="tns:removeAccountRequest"/>
<wsdl:output message="tns:removeAccountResponse"/>
</wsdl:operation>
<wsdl:operation name="addAccountPermission">
<wsdl:input message="tns:addAccountPermissionRequest"/>
<wsdl:output message="tns:addAccountPermissionResponse"/>
</wsdl:operation>
<wsdl:operation name="removeAccountPermission">
<wsdl:input message="tns:removeAccountPermissionRequest"/>
<wsdl:output message="tns:removeAccountPermissionResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="basic-auth-serviceSOAP" type="tns:basic-auth-service">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="addAccount">
<soap:operation soapAction="http://www.entaxy.ru/basic-auth-service/add-account"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="updateAccount">
<soap:operation soapAction="http://www.entaxy.ru/basic-auth-service/update-account"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="removeAccount">
<soap:operation soapAction="http://www.entaxy.ru/basic-auth-service/update-account"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="addAccountPermission">
<soap:operation soapAction="http://www.entaxy.ru/basic-auth-service/add-account-permission"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="removeAccountPermission">
<soap:operation soapAction="http://www.entaxy.ru/basic-auth-service/remove-account-permission"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="basic-auth-service">
<wsdl:port name="basic-auth-serviceSOAP" binding="tns:basic-auth-serviceSOAP">
<soap:address location="http://dev.esbHost.ru/"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>

View File

@ -0,0 +1,201 @@
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.

View File

@ -0,0 +1,78 @@
# SYSTEM :: ENTAXY :: BASIC AUTH :: HTPASSWD
Генерация htpasswd файла, сервис выдачи файла и checksum
Работает с nginX шифрования MD5 и SHA-1
Описание данного подхода аутентификации:
1. Nginx по умолчанию собран с модулем
ngx_http_auth_basic_module, который проводит
базовую аутентификацию через файлы htpasswd.
2. Файл passwd периодически или по событиям
синхронизируется между нодами при помощи скрипта синхронизации,
который вызывает Rest сервис
шины. (Rsync использовать нельзя, так как порты
закрыты.)
3. Аутентификация делается только на Nginx без доп.
нагрузки на шину
4. Файл хранится на сервере nginx и аутентификация
будет работать всегда
5. Подход рассчитан на балансировщики реализующие basic аутентификацию
с использованием htpasswd
## Сборка
Сборка осуществляется командой
```
mvn clean install
```
Файл конфигурации модуля ru.entaxy.esb.system.basic_auth.htpasswd.cfg хранится в SYSTEM :: ENTAXY :: Features
## Сервис Htpasswd
**Настраивается свойствами**
htpasswd.service.host по умолчанию 0.0.0.0
htpasswd.service.port по умолчанию 9091
htpasswd.service.root.path по умолчанию /htpasswd
**Методы:**
GET http://localhost:9091/htpasswd - получение содержимого файла htpasswd
GET http://localhost:9091/htpasswd/checksum - получение checksum текущего htpasswd
**Кластер:**
Для избежания рассинхронизации файлов htpasswd на разных серверах требуется настроить шару между карафами и установить адрес этой папки в свойство
htpasswd.file.directory=/mnt/share
## Скрипт сихронизации htpasswd для nginX
Расположен в папке resources/script/htpasswd-checker.sh
Запускается из любой папки расположенной на сервере.
Перед запуском проверить и при необходимости поправить переменные в скрипте
* KARAF_HOST_NAMES=("http://192.168.122.93:9091" "http://192.168.122.94:9091") - караф сервера с запущеным сервисом htpasswd
* HTPASSWD_STORAGE=/etc/nginx/htpasswd - адрес файла htpasswd, на который настроен nginX
Добавить запуск скрипта через cron
sudo crontab -e
```
раз в минут
*/5 * * * * <path_to_script>
либо раз в минуту
*/1 * * * * <path_to_script>
```

View File

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>ru.entaxy.esb.system.auth.basic</groupId>
<artifactId>basic-auth</artifactId>
<version>1.8.0</version>
</parent>
<groupId>ru.entaxy.esb.system.auth.basic.htpasswd</groupId>
<artifactId>htpasswd</artifactId>
<packaging>bundle</packaging>
<name>SYSTEM :: ENTAXY :: BASIC AUTH :: HTPASSWD</name>
<description>SYSTEM :: ENTAXY :: BASIC AUTH :: HTPASSWD</description>
<properties>
<bundle.osgi.export.pkg>
ru.entaxy.esb.system.auth.basic.htpasswd,
</bundle.osgi.export.pkg>
<bundle.osgi.import.pkg>
ru.entaxy.esb.system.auth.basic.jpa.api,
ru.entaxy.esb.system.auth.basic.jpa.api.entity,
ru.entaxy.esb.system.auth.basic.jpa.api.entity.field,
org.apache.cxf.jaxrs.impl,
org.apache.camel.component.cxf.jaxrs.blueprint,
org.apache.camel.component.cxf.blueprint,
org.apache.commons.codec.binary,
*
</bundle.osgi.import.pkg>
</properties>
<dependencies>
<dependency>
<groupId>ru.entaxy.esb.system.auth.basic.api</groupId>
<artifactId>basic-auth-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commons-codec.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-cxf</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel.karaf</groupId>
<artifactId>camel-cxf-blueprint</artifactId>
<version>${camel.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,93 @@
/*-
* ~~~~~~licensing~~~~~~
* htpasswd
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.auth.basic.htpasswd;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import ru.entaxy.esb.system.auth.basic.htpasswd.entity.Htpasswd;
import ru.entaxy.esb.system.auth.basic.jpa.api.entity.BasicAuthAccount;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.NoSuchAlgorithmException;
import java.util.List;
public class HtpasswdGenerator {
private static final Log LOG = LogFactory.getLog(HtpasswdGenerator.class);
private String checkSumFileName;
public Htpasswd htpasswd;
public void generateHtpasswd(List<BasicAuthAccount> accounts, String salt) throws IOException, NoSuchAlgorithmException {
htpasswd.setMasterSalt(salt);
htpasswd.prepare(accounts);
createFile();
}
private void createFile() throws IOException {
String content = htpasswd.toString();
LOG.trace("HTTPASSWD " + content);
String storeFolder = htpasswd.getDirectory();
File folder = new File(storeFolder);
folder.mkdirs();
File htpasswdFile = new File(folder.getAbsolutePath() + File.separator + htpasswd.getFileName());
Path path = Paths.get(htpasswdFile.getAbsolutePath());
Files.write(path, content.getBytes());
String checkSum = calculateCheckSum(path);
File checkSumFile = new File(folder.getAbsolutePath() + File.separator + checkSumFileName);
path = Paths.get(checkSumFile.getAbsolutePath());
Files.write(path, checkSum.getBytes());
}
private String calculateCheckSum(Path path) throws IOException {
String md5;
try (InputStream is = Files.newInputStream(path)) {
md5 = DigestUtils.md5Hex(is);
}
return md5;
}
public Htpasswd getHtpasswd() {
return htpasswd;
}
public void setHtpasswd(Htpasswd htpasswd) {
this.htpasswd = htpasswd;
}
public String getCheckSumFileName() {
return checkSumFileName;
}
public void setCheckSumFileName(String checkSumFileName) {
this.checkSumFileName = checkSumFileName;
}
}

View File

@ -0,0 +1,98 @@
/*-
* ~~~~~~licensing~~~~~~
* htpasswd
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.auth.basic.htpasswd.entity;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import ru.entaxy.esb.system.auth.basic.jpa.api.entity.BasicAuthAccount;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
public class Htpasswd {
private static final Log LOG = LogFactory.getLog(Htpasswd.class);
private String directory;
private String fileName;
private String masterSalt = null;
private final List<HtpasswdEntry> entries = new ArrayList<>();
public Htpasswd() {
}
public void prepare(List<BasicAuthAccount> accounts) throws NoSuchAlgorithmException {
if (masterSalt == null || masterSalt.isEmpty()) {
throw new IllegalArgumentException("masterSalt not setted!");
}
if (accounts != null && accounts.size() > 0) {
entries.clear();
for (BasicAuthAccount account : accounts) {
entries.add(new HtpasswdEntry(
account.getLogin(),
account.getPasswordHash(),
masterSalt,
account.getEncryptionAlgorithm().getAlgorithmName()));
}
}
}
public void addString(String login, String passwordHash, String encryptionAlgorithm) throws NoSuchAlgorithmException {
entries.add(new HtpasswdEntry(
login,
passwordHash,
masterSalt,
encryptionAlgorithm));
}
public String getDirectory() {
return directory;
}
public void setDirectory(String directory) {
this.directory = directory;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getMasterSalt() {
return masterSalt;
}
public void setMasterSalt(String masterSalt) {
this.masterSalt = masterSalt;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
for (HtpasswdEntry entry : entries) {
builder.append(entry.toString());
}
return builder.toString();
}
}

View File

@ -0,0 +1,86 @@
/*-
* ~~~~~~licensing~~~~~~
* htpasswd
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.auth.basic.htpasswd.entity;
import org.apache.commons.codec.binary.Base64;
import ru.entaxy.esb.system.auth.basic.jpa.api.entity.field.EncryptionAlgorithm;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
public class HtpasswdEntry {
private static final String APR1_PREFIX = "$apr1$";
private static final String SHA512_PREFIX = "$6$";
private static final String SALTED_SHA1_PREFIX = "{SSHA}";
private static final String PLAIN_PREFIX = "{PLAIN}";
private static final String COLON = ":";
private final String resultLine;
public HtpasswdEntry(String login, String passwordHash, String salt, String encryptionAlgorithm) throws NoSuchAlgorithmException {
this(login, passwordHash, salt, encryptionAlgorithm, true);
}
public HtpasswdEntry(String login, String passwordHash, String salt, String encryptionAlgorithm, boolean addLineSeparator) throws NoSuchAlgorithmException {
StringBuilder content = new StringBuilder();
content.append(login).append(COLON);
if (EncryptionAlgorithm.MD5.equalsName(encryptionAlgorithm)) {
content
.append(APR1_PREFIX)
.append(salt)
.append("$")
.append(passwordHash);
} else if (EncryptionAlgorithm.SHA1.equalsName(encryptionAlgorithm)) {
content.append(SALTED_SHA1_PREFIX);
byte[] digest = Base64.decodeBase64(passwordHash);
byte[] saltBytes = salt.getBytes(StandardCharsets.UTF_8);
int l1 = digest.length;
int l2 = saltBytes.length;
byte[] resultArr = new byte[l1 + l2];
System.arraycopy(digest, 0, resultArr, 0, l1);
System.arraycopy(saltBytes, 0, resultArr, l1, l2);
content.append(Base64.encodeBase64String(resultArr));
} else if (EncryptionAlgorithm.SHA512.equalsName(encryptionAlgorithm)) {
content
.append(SHA512_PREFIX)
.append(salt)
.append("$")
.append(passwordHash);
} else if (EncryptionAlgorithm.PLAIN.equalsName(encryptionAlgorithm)) {
content
.append(PLAIN_PREFIX)
.append(passwordHash);
} else {
content.append(passwordHash);
}
content.append(System.lineSeparator());
this.resultLine = content.toString();
}
@Override
public String toString() {
return resultLine;
}
}

View File

@ -0,0 +1,43 @@
/*-
* ~~~~~~licensing~~~~~~
* htpasswd
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.auth.basic.htpasswd.rest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import java.io.File;
@Path("/")
public class HtpasswdService {
@GET
@Produces("application/octet-stream")
public File getFile() {
return null;
}
@GET
@Path("/checksum")
@Produces("plain/text")
public String getCheckSum() {
return null;
}
}

View File

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~~~~~~licensing~~~~~~
htpasswd
==========
Copyright (C) 2020 - 2021 EmDev LLC
==========
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.
~~~~~~/licensing~~~~~~
-->
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0"
xmlns:camelcxf="http://camel.apache.org/schema/blueprint/cxf"
xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 https://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
<cm:property-placeholder persistent-id="ru.entaxy.esb.system.basic_auth.htpasswd" update-strategy="reload">
<cm:default-properties>
<cm:property name="htpasswd.file.directory" value="securityTest"/>
<cm:property name="htpasswd.file.name" value="htpasswd"/>
<cm:property name="htpasswd.file.checksum" value="MD5.md5"/>
<cm:property name="htpasswd.service.host" value="http://localhost"/>
<cm:property name="htpasswd.service.port" value="9091"/>
<cm:property name="htpasswd.service.root.path" value="/htpasswd"/>
</cm:default-properties>
</cm:property-placeholder>
<bean id="htpasswd" class="ru.entaxy.esb.system.auth.basic.htpasswd.entity.Htpasswd">
<property name="fileName" value="${htpasswd.file.name}"/>
<property name="directory" value="${htpasswd.file.directory}"/>
</bean>
<service ref="htpasswdGenerator" interface="ru.entaxy.esb.system.auth.basic.htpasswd.HtpasswdGenerator"/>
<bean id="htpasswdGenerator" class="ru.entaxy.esb.system.auth.basic.htpasswd.HtpasswdGenerator">
<property name="htpasswd" ref="htpasswd"/>
<property name="checkSumFileName" value="${htpasswd.file.checksum}"/>
</bean>
<!-- <reference id="phaseInterceptor" -->
<!-- interface="org.apache.cxf.phase.PhaseInterceptor" -->
<!-- filter="(type=system)" -->
<!-- timeout="30000" -->
<!-- availability="optional"/> -->
<!-- <cxf:bus id="entaxy"> -->
<!-- <cxf:inInterceptors> -->
<!-- <ref component-id="phaseInterceptor"/> -->
<!-- </cxf:inInterceptors> -->
<!-- </cxf:bus> -->
<camelcxf:rsServer id="rsServer"
address="${htpasswd.service.host}:${htpasswd.service.port}${htpasswd.service.root.path}"
serviceClass="ru.entaxy.esb.system.auth.basic.htpasswd.rest.HtpasswdService"
loggingFeatureEnabled="false" loggingSizeLimit="20"/>
<camelContext id="htpasswd-camel-context" xmlns="http://camel.apache.org/schema/blueprint">
<route id="htpasswdServiceRouter">
<from uri="cxfrs:bean:rsServer?bindingStyle=SimpleConsumer"/>
<log message="Htpassed service operation ${header.operationName}" loggingLevel="DEBUG"/>
<toD uri="direct:${header.operationName}"/>
</route>
<route id="file">
<from uri="direct:getFile"/>
<log message="Request direct:getFile: type=${header.type}, active=${header.active}, customerData=${body}"/>
<pollEnrich timeout="0">
<simple>file:${properties:htpasswd.file.directory}?noop=true&amp;fileName=${properties:htpasswd.file.name}&amp;idempotent=false</simple>
</pollEnrich>
<convertBodyTo type="String"/>
</route>
<route id="checkSum">
<from uri="direct:getCheckSum"/>
<log message="Request direct:getCheckSum: type=${header.type}, active=${header.active}, customerData=${body}"/>
<pollEnrich timeout="0">
<simple>file:${properties:htpasswd.file.directory}?noop=true&amp;fileName=${properties:htpasswd.file.checksum}&amp;idempotent=false</simple>
</pollEnrich>
<convertBodyTo type="String"/>
</route>
</camelContext>
</blueprint>

View File

@ -0,0 +1,67 @@
###
# ~~~~~~licensing~~~~~~
# htpasswd
# ==========
# Copyright (C) 2020 - 2021 EmDev LLC
# ==========
# 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.
# ~~~~~~/licensing~~~~~~
###
# !/bin/sh
KARAF_HOST_NAMES=("http://192.168.122.93:9091" "http://192.168.122.94:9091")
HTPASSWD_PATH=/htpasswd
CHECKSUM_PATH=$HTPASSWD_PATH/checksum
HTPASSWD_STORAGE=/etc/nginx/htpasswd
LOGFILE="htpasswd-sync.log"
TIMESTAMP=`date "+%Y-%m-%d %H:%M:%S"`
currentChecksum=`md5sum $HTPASSWD_STORAGE | awk '{ print $1 }'`
log(){
echo "$TIMESTAMP $1" >> $LOGFILE
}
#download actual checksum from karaf
for actualHost in ${KARAF_HOST_NAMES[*]}; do
wget -O checksum $actualHost$CHECKSUM_PATH
newChecksum=`cat checksum`
rm checksum
if [[ -n $newChecksum ]]
then
log "checksum received from host $actualHost"
break
else
log "host $actualHost did not give checksum data"
fi
done
log "newChecksum $newChecksum"
log "currentChecksum $currentChecksum"
if [[ -n $newChecksum ]] && { [[ -z $currentChecksum ]] || [ $currentChecksum != $newChecksum ]; };
then
wget -O htpasswd $actualHost$HTPASSWD_PATH
sudo mv htpasswd $HTPASSWD_STORAGE
sudo chmod 644 $HTPASSWD_STORAGE
sudo chown root:root $HTPASSWD_STORAGE
sudo systemctl reload nginx
log ">>>>>>>>>>>>>>>>> Htpasswd updated"
else
if [[ -n $newChecksum ]]
then
log ">>>>>>>>>>>>>>>>> Htpasswd is up to date"
else
log ">>>>>>>>>>>>>>>>> Script finished with error: new checksum not received!"
#error action
fi
fi

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>ru.entaxy.esb.system.auth</groupId>
<artifactId>system-auth</artifactId>
<version>1.8.0</version>
</parent>
<groupId>ru.entaxy.esb.system.auth.basic</groupId>
<artifactId>basic-auth</artifactId>
<packaging>pom</packaging>
<name>SYSTEM :: ENTAXY :: AUTH BASIC</name>
<description>SYSTEM :: ENTAXY :: AUTH BASIC</description>
<modules>
<module>basic-auth-api</module>
<module>basic-auth-impl</module>
<module>htpasswd</module>
<module>basic-auth-soap</module>
</modules>
</project>

24
system/auth/pom.xml Normal file
View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>ru.entaxy.esb.system</groupId>
<artifactId>system-parent</artifactId>
<version>1.8.0</version>
</parent>
<groupId>ru.entaxy.esb.system.auth</groupId>
<artifactId>system-auth</artifactId>
<packaging>pom</packaging>
<name>SYSTEM :: ENTAXY :: AUTH</name>
<description>SYSTEM :: ENTAXY :: AUTH</description>
<modules>
<module>basic-auth</module>
</modules>
</project>

201
system/commons/LICENSE.txt Normal file
View File

@ -0,0 +1,201 @@
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.

4
system/commons/README.md Normal file
View File

@ -0,0 +1,4 @@
# SYSTEM :: ENTAXY :: COMMONS
модуль osgi - общий механизм регистрации профилей систем и групп систем(в виде bundle, реализующий определнный интерфейс,
для системы и для групп систем свой), в котором как минимум есть метод отправить сообщение.

162
system/commons/pom.xml Normal file
View File

@ -0,0 +1,162 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>ru.entaxy.esb.system</groupId>
<artifactId>system-parent</artifactId>
<version>1.8.0</version>
</parent>
<groupId>ru.entaxy.esb.system.commons</groupId>
<artifactId>system-commons</artifactId>
<packaging>bundle</packaging>
<name>SYSTEM :: ENTAXY :: COMMONS</name>
<description>SYSTEM :: ENTAXY :: COMMONS</description>
<properties>
<bundle.osgi.export.pkg>
ru.entaxy.esb.system.common.osgi,
ru.entaxy.esb.system.common.osgi.impl,
ru.entaxy.esb.system.common.exception,
ru.entaxy.esb.system.common.aggregation.*,
ru.entaxy.esb.system.common.interceptor,
ru.entaxy.esb.system.common.util,
ru.entaxy.esb.system.common.validator
</bundle.osgi.export.pkg>
<bundle.osgi.import.pkg>
com.google.gson,
org.osgi.service.blueprint.container,
javax.xml.soap*;version="[1.3,2)",
javax.jws.*;version="[2.0.0,3.0.0)",
javax.jws.soap.*;version="[2.0.0,3.0.0)",
javax.xml.ws.*;version="[2.2.0,3.0.0)",
!com.sun.xml.*,
javax.xml.bind;version="[2,3)",
javax.xml.bind.annotation;version="[2,3)",
javax.persistence;version="[2,3)",
org.hibernate,
org.hibernate.cfg,
org.hibernate.service,
org.hibernate.jpa,
org.hibernate.proxy,
org.apache.ignite,
org.apache.ignite.internal.processors.cluster,
org.apache.ignite.internal.processors.marshaller,
org.apache.ignite.internal.util.lang.gridfunc,
org.apache.ignite.spi.discovery.tcp.internal,
org.apache.ignite.transactions,
org.apache.ignite.internal.*,
javassist.util.proxy,
org.apache.commons.lang3,
*
</bundle.osgi.import.pkg>
</properties>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
<dependency>
<groupId>xerces</groupId>
<artifactId>xercesImpl</artifactId>
<version>${xerces.version}</version>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
<version>${osgi.version}</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>${commons-lang.version}</version>
</dependency>
<dependency>
<groupId>org.apache.aries.blueprint</groupId>
<artifactId>org.apache.aries.blueprint.cm</artifactId>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>osgi.core</artifactId>
<version>${osgi.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>javax.persistence</artifactId>
<version>${jpa.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>javax.transaction-api</artifactId>
<version>${javax.transaction.version}</version>
</dependency>
<dependency>
<groupId>javax.interceptor</groupId>
<artifactId>javax.interceptor-api</artifactId>
<version>${javax.interceptor.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
<dependency>
<groupId>org.apache.ignite</groupId>
<artifactId>ignite-core</artifactId>
<version>${ignite.version}</version>
</dependency>
<dependency>
<groupId>org.apache.ignite</groupId>
<artifactId>ignite-jcl</artifactId>
<version>${ignite.version}</version>
</dependency>
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast</artifactId>
<version>${hazelcast.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jms</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-sql</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-cxf</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,221 @@
/*-
* ~~~~~~licensing~~~~~~
* system-commons
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.common.aggregation;
import com.hazelcast.core.HazelcastInstance;
import org.apache.camel.*;
import org.apache.camel.model.OptionalIdentifiedDefinition;
import org.apache.camel.model.ToDefinition;
import org.apache.camel.model.language.SimpleExpression;
import org.apache.camel.processor.CamelInternalProcessor;
import org.apache.camel.processor.aggregate.AggregationStrategyBeanAdapter;
import org.apache.camel.reifier.ProcessorReifier;
import org.apache.camel.spi.AggregationRepository;
import org.apache.camel.spi.IdAware;
import org.apache.camel.spi.RouteIdAware;
import org.apache.camel.util.concurrent.SynchronousExecutorService;
import ru.entaxy.esb.system.common.aggregation.hazelcast.DisconnectedMembershipListener;
import ru.entaxy.esb.system.common.aggregation.repo.IgniteAggregationRepository;
public class AggregationProcessorBean implements Processor {
private static final String routeName = "aggregation";
private CamelContext camelContext;
private String aggregationStrategyRef;
private AggregationStrategy aggregationStrategy;
private String aggregationStrategyMethodName;
private String aggregateExpression = "ENTAXY_AcknowledgeMsgID";
private String toDefinition = "direct-vm:common-revert-no-acknowledge-messages?block=true&timeout=60000";
private int completionSize = 2;
//10 min in mc
private int completionTimeout = 600_000;
private String aggregationRepositoryRef;
private AggregationRepository aggregationRepository;
private HazelcastInstance hazelcastInstance;
private AggregationProcessorWithRestoreTimeout aggregationProcessorWithRestoreTimeout;
public void initAggregateProcessor() throws Exception {
Route route = camelContext.getRoute(routeName);
aggregationProcessorWithRestoreTimeout = new AggregationProcessorWithRestoreTimeout(camelContext,
getCamelDestinationProcessor(route),
getCorrelationExpression(route),
createAggregationStrategy(camelContext),
new SynchronousExecutorService(),
false);
settingsAggregationProcessorWithRestoreTimeout(route);
aggregationProcessorWithRestoreTimeout.doStart();
addHazelcastMembershipListener();
}
private void settingsAggregationProcessorWithRestoreTimeout(Route route) {
AggregationRepository repository = createAggregationRepository(route);
if (repository != null) {
aggregationProcessorWithRestoreTimeout.setAggregationRepository(repository);
}
aggregationProcessorWithRestoreTimeout.setCompletionSize(completionSize);
aggregationProcessorWithRestoreTimeout.setCompletionTimeout(completionTimeout);
}
private void addHazelcastMembershipListener() {
hazelcastInstance.getCluster().addMembershipListener(new DisconnectedMembershipListener(aggregationProcessorWithRestoreTimeout, camelContext));
}
private Expression getCorrelationExpression(Route route) {
return new SimpleExpression(aggregateExpression);
}
private CamelInternalProcessor getCamelDestinationProcessor(Route route) throws Exception {
Processor childProcessor = createChildProcessor(route, true);
// wrap the aggregate route in a unit of work processor
CamelInternalProcessor internal = new CamelInternalProcessor(camelContext, childProcessor);
internal.addAdvice(new CamelInternalProcessor.UnitOfWorkProcessorAdvice(route, camelContext));
return internal;
}
private Processor createChildProcessor(Route route, boolean mandatory) throws Exception {
Processor children = null;
ToDefinition definition = new ToDefinition(toDefinition);
// at first use custom factory
if (camelContext.adapt(ExtendedCamelContext.class).getProcessorFactory() != null) {
children = camelContext.adapt(ExtendedCamelContext.class).getProcessorFactory().createChildProcessor(route,
definition, mandatory);
}
// fallback to default implementation if factory did not create the
// child
if (children == null) {
children = createOutputsProcessor(route, definition);
}
if (children == null && mandatory) {
throw new IllegalArgumentException("Definition has no children on " + definition);
}
return children;
}
protected Processor createOutputsProcessor(Route route, ToDefinition definition) throws Exception {
Processor processor = ProcessorReifier.reifier(route, definition).createProcessor();
// inject id
if (processor instanceof IdAware) {
String id = getId(definition);
((IdAware) processor).setId(id);
}
if (processor instanceof RouteIdAware) {
((RouteIdAware) processor).setRouteId(route.getRouteId());
}
return processor;
}
protected String getId(OptionalIdentifiedDefinition<?> def) {
return def.idOrCreate(camelContext.adapt(ExtendedCamelContext.class).getNodeIdFactory());
}
private AggregationRepository createAggregationRepository(Route route) {
if (aggregationRepository == null && aggregationRepositoryRef != null) {
aggregationRepository = (AggregationRepository) route.getCamelContext().getRegistry().lookupByName(aggregationRepositoryRef);
}
return aggregationRepository;
}
private AggregationStrategy createAggregationStrategy(CamelContext camelContext) {
if (aggregationStrategy == null && aggregationStrategyRef != null) {
Object aggStrategy = camelContext.getRegistry().lookupByNameAndType(aggregationStrategyRef, Object.class);
if (aggStrategy instanceof AggregationStrategy) {
aggregationStrategy = (AggregationStrategy) aggStrategy;
} else if (aggStrategy != null) {
aggregationStrategy = new AggregationStrategyBeanAdapter(aggStrategy, aggregationStrategyMethodName);
} else {
throw new IllegalArgumentException("Cannot find AggregationStrategy in Registry with name: " + aggregationStrategyRef);
}
}
if (aggregationStrategy == null) {
throw new IllegalArgumentException("AggregationStrategy or AggregationStrategyRef must be set on " + this);
}
if (aggregationStrategy instanceof CamelContextAware) {
((CamelContextAware) aggregationStrategy).setCamelContext(camelContext);
}
return aggregationStrategy;
}
@Override
public void process(Exchange exchange) throws Exception {
aggregationProcessorWithRestoreTimeout.process(exchange);
}
public void setCamelContext(CamelContext camelContext) {
this.camelContext = camelContext;
}
public void setAggregationStrategyRef(String aggregationStrategyRef) {
this.aggregationStrategyRef = aggregationStrategyRef;
}
public void setAggregationStrategy(AggregationStrategy aggregationStrategy) {
this.aggregationStrategy = aggregationStrategy;
}
public void setAggregationStrategyMethodName(String aggregationStrategyMethodName) {
this.aggregationStrategyMethodName = aggregationStrategyMethodName;
}
public void setAggregateExpression(String aggregateExpression) {
this.aggregateExpression = aggregateExpression;
}
public void setToDefinition(String toDefinition) {
this.toDefinition = toDefinition;
}
public void setCompletionSize(int completionSize) {
this.completionSize = completionSize;
}
public void setCompletionTimeout(int completionTimeout) {
this.completionTimeout = completionTimeout;
}
public void setAggregationRepositoryRef(String aggregationRepositoryRef) {
this.aggregationRepositoryRef = aggregationRepositoryRef;
}
public void setHazelcastInstance(HazelcastInstance hazelcastInstance) {
this.hazelcastInstance = hazelcastInstance;
}
public void init() throws Exception {
camelContext.addStartupListener((a, b) -> initAggregateProcessor());
}
public void doStop() throws Exception {
aggregationProcessorWithRestoreTimeout.doStop();
if (aggregationRepository instanceof IgniteAggregationRepository)
((IgniteAggregationRepository) aggregationRepository).doStop();
}
}

View File

@ -0,0 +1,44 @@
/*-
* ~~~~~~licensing~~~~~~
* system-commons
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.common.aggregation;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.camel.AggregationStrategy;
import org.apache.camel.Exchange;
public class HeaderMergeAggregatorImpl implements AggregationStrategy {
@Override
public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
if (oldExchange != null && newExchange != null) {
Map<String, Object> oldHeaders = oldExchange.getIn().getHeaders();
Map<String, Object> newHeaders = newExchange.getIn().getHeaders();
oldHeaders = oldHeaders.entrySet().stream()
.filter(e -> !newHeaders.containsKey(e.getKey()))
.collect(Collectors.toMap(e->e.getKey(), e->e.getValue()));
newExchange.getIn().getHeaders().putAll(oldHeaders);
}
return newExchange;
}
}

View File

@ -0,0 +1,55 @@
/*-
* ~~~~~~licensing~~~~~~
* system-commons
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.common.aggregation;
import org.apache.camel.AggregationStrategy;
import org.apache.camel.Exchange;
public class TimeoutAwareAggregationStrategyImpl implements AggregationStrategy {
private static final String ACK_MESSAGE_HEADER = "NTX_AckMessage";
private final String nameHeaderAcknowledge;
public TimeoutAwareAggregationStrategyImpl(String nameHeaderAcknowledge) {
this.nameHeaderAcknowledge = nameHeaderAcknowledge;
}
@Override
public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
if (oldExchange == null) {
return newExchange;
} else {
oldExchange.getMessage().setHeader(nameHeaderAcknowledge, checkOnCorrectPair(oldExchange, newExchange));
return oldExchange;
}
}
private boolean checkOnCorrectPair(Exchange oldExchange, Exchange newExchange) {
return (oldExchange != null && oldExchange.getMessage().getHeader(ACK_MESSAGE_HEADER) == null &&
(newExchange == null || newExchange.getMessage().getHeader(ACK_MESSAGE_HEADER) == null));
}
@Override
public void timeout(Exchange oldExchange, int index, int total, long timeout) {
oldExchange.getMessage().setHeader(nameHeaderAcknowledge,
(oldExchange.getMessage().getHeader(ACK_MESSAGE_HEADER) == null));
}
}

View File

@ -0,0 +1,59 @@
/*-
* ~~~~~~licensing~~~~~~
* system-commons
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.common.aggregation.hazelcast;
import com.hazelcast.core.MemberAttributeEvent;
import com.hazelcast.core.MembershipEvent;
import com.hazelcast.core.MembershipListener;
import org.apache.camel.CamelContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.entaxy.esb.system.common.aggregation.AggregationProcessorWithRestoreTimeout;
public class DisconnectedMembershipListener implements MembershipListener {
protected static final Logger log = LoggerFactory.getLogger(DisconnectedMembershipListener.class);
private final AggregationProcessorWithRestoreTimeout aggregationProcessorWithRestoreTimeout;
private final CamelContext camelContext;
public DisconnectedMembershipListener(AggregationProcessorWithRestoreTimeout aggregationProcessorWithRestoreTimeout,
CamelContext camelContext) {
this.aggregationProcessorWithRestoreTimeout = aggregationProcessorWithRestoreTimeout;
this.camelContext = camelContext;
}
@Override
public void memberAdded(MembershipEvent membershipEvent) {
}
@Override
public void memberRemoved(MembershipEvent membershipEvent) {
try {
aggregationProcessorWithRestoreTimeout.recoverCompletedMessageFromAggregationRepository(camelContext);
aggregationProcessorWithRestoreTimeout.restoreTimeoutMapFromAggregationRepository();
} catch (Exception e) {
log.error("Can't restore Timeout from Aggregator. Please restart bundle.", e);
}
}
@Override
public void memberAttributeChanged(MemberAttributeEvent memberAttributeEvent) {
}
}

View File

@ -0,0 +1,427 @@
/*-
* ~~~~~~licensing~~~~~~
* system-commons
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.common.aggregation.repo;
import org.apache.camel.CamelContext;
import org.apache.camel.Exchange;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.processor.aggregate.jdbc.DefaultJdbcOptimisticLockingExceptionMapper;
import org.apache.camel.processor.aggregate.jdbc.JdbcCamelCodec;
import org.apache.camel.processor.aggregate.jdbc.JdbcOptimisticLockingExceptionMapper;
import org.apache.camel.spi.OptimisticLockingAggregationRepository;
import org.apache.camel.spi.RecoverableAggregationRepository;
import org.apache.camel.support.service.ServiceSupport;
import org.apache.camel.util.ObjectHelper;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteCache;
import org.apache.ignite.IgniteTransactions;
import org.apache.ignite.Ignition;
import org.apache.ignite.cache.CacheAtomicityMode;
import org.apache.ignite.cache.CacheMode;
import org.apache.ignite.cache.CacheRebalanceMode;
import org.apache.ignite.cache.query.ScanQuery;
import org.apache.ignite.configuration.CacheConfiguration;
import org.apache.ignite.configuration.DataStorageConfiguration;
import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.configuration.TransactionConfiguration;
import org.apache.ignite.logger.jcl.JclLogger;
import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
import org.apache.ignite.transactions.Transaction;
import org.jetbrains.annotations.NotNull;
import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.EmptyResultDataAccessException;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import static org.apache.ignite.IgniteSystemProperties.IGNITE_QUIET;
public class IgniteAggregationRepository extends ServiceSupport implements RecoverableAggregationRepository, OptimisticLockingAggregationRepository {
private static final Logger LOG = LoggerFactory.getLogger(IgniteAggregationRepository.class);
public static final String AGGREGATION = "aggregation";
public static final String AGGREGATION_COMPLETED = "aggregationCompleted";
public static final int MAX_ATTEMPT_COUNT = 3;
private JdbcOptimisticLockingExceptionMapper jdbcOptimisticLockingExceptionMapper = new DefaultJdbcOptimisticLockingExceptionMapper();
private boolean returnOldExchange;
private final JdbcCamelCodec codec = new JdbcCamelCodec();
private long recoveryInterval = 5000;
private boolean useRecovery = true;
private int maximumRedeliveries;
private String deadLetterUri;
private boolean allowSerializedHeaders;
private int backups = 2;
private String workDirectory;
private String addresses = "127.0.0.1:47500,127.0.0.1:47501";
private Ignite ignite;
private IgniteTransactions transactions;
private IgniteCache<String, byte[]> aggregationCache;
private CacheConfiguration<String, byte[]> aggregationCfg;
private IgniteCache<String, byte[]> aggregationCompleted;
private CacheConfiguration<String, byte[]> aggregationCompletedCfg;
private BundleContext bundleContext;
/**
* Creates an ignite aggregation repository
*/
public IgniteAggregationRepository() {
}
/**
* Creates an ignite aggregation repository with the two mandatory parameters
*/
public IgniteAggregationRepository(BundleContext bundleContext, String workDirectory) {
this.setBundleContext(bundleContext);
this.setWorkDirectory(workDirectory);
}
@Override
public Exchange add(final CamelContext camelContext, final String correlationId,
final Exchange oldExchange, final Exchange newExchange) throws OptimisticLockingException {
try {
return add(camelContext, correlationId, newExchange);
} catch (Exception e) {
if (jdbcOptimisticLockingExceptionMapper != null && jdbcOptimisticLockingExceptionMapper.isOptimisticLocking(e)) {
throw new OptimisticLockingException();
} else {
throw RuntimeCamelException.wrapRuntimeCamelException(e);
}
}
}
@Override
public Exchange add(final CamelContext camelContext, final String correlationId, final Exchange exchange) {
Exchange result = null;
final String key = correlationId;
try {
LOG.debug("Adding exchange with key: [{}]", key);
boolean present = aggregationCache.get(key) != null;
// Recover existing exchange with that ID
if (isReturnOldExchange() && present) {
result = get(key, camelContext);
}
final byte[] data = codec.marshallExchange(camelContext, exchange, allowSerializedHeaders);
try (Transaction tx = transactions.txStart()) {
aggregationCache.put(key, data);
tx.commit();
}
} catch (Exception e) {
throw new RuntimeException("Error adding with key " + key, e);
}
return result;
}
public Exchange insert(final CamelContext camelContext, final String correlationId, final Exchange exchange) throws IOException {
Exchange result = null;
LOG.debug("Adding exchange with key: [{}]", correlationId);
final byte[] data = codec.marshallExchange(camelContext, exchange, allowSerializedHeaders);
aggregationCompleted.put(correlationId, data);
return result;
}
@Override
public Exchange get(final CamelContext camelContext, final String correlationId) {
Exchange result = get(correlationId, camelContext);
LOG.debug("Getting key [{}] -> {}", correlationId, result);
return result;
}
private Exchange get(final String key, final CamelContext camelContext) {
try {
final byte[] data = aggregationCache.get(key);
return codec.unmarshallExchange(camelContext, data);
} catch (EmptyResultDataAccessException | NullPointerException ex) {
return null;
} catch (IOException | ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
@Override
public void remove(final CamelContext camelContext, final String correlationId, final Exchange exchange) {
try (Transaction tx = transactions.txStart()) {
insert(camelContext, correlationId, exchange);
if (!aggregationCache.remove(correlationId)) {
throw new RuntimeException("Error removing key " + correlationId + " from repository " + AGGREGATION);
}
tx.commit();
} catch (Exception exception) {
throw new RuntimeException("Error removing key " + correlationId + " from repository " + AGGREGATION, exception);
}
}
@Override
public void confirm(final CamelContext camelContext, final String exchangeId) {
confirm(camelContext, exchangeId, 0);
}
private void confirm(final CamelContext camelContext, final String exchangeId, int attemptCount) {
if (attemptCount <= MAX_ATTEMPT_COUNT) {
try (Transaction tx = transactions.txStart()) {
aggregationCompleted.remove(exchangeId);
tx.commit();
} catch (Exception exception) {
confirm(camelContext, exchangeId, ++attemptCount);
}
}
}
@Override
public Set<String> getKeys() {
Set<String> keys = new HashSet<>();
aggregationCache.query(new ScanQuery<>(null)).forEach(entry -> keys.add((String) entry.getKey()));
return keys;
}
@Override
public Set<String> scan(CamelContext camelContext) {
Set<String> keys = new HashSet<>();
aggregationCompleted.query(new ScanQuery<>(null)).forEach(entry -> keys.add((String) entry.getKey()));
return keys;
}
@Override
public Exchange recover(CamelContext camelContext, String exchangeId) {
final byte[] data = aggregationCompleted.get(exchangeId);
Exchange answer = null;
try {
answer = codec.unmarshallExchange(camelContext, data);
} catch (IOException | ClassNotFoundException e) {
LOG.error("Exception in recovering exchangeId {}", exchangeId, e);
}
LOG.debug("Recovering exchangeId [{}] -> {}", exchangeId, answer);
return answer;
}
/**
* If recovery is enabled then a background task is run every x'th time to scan for failed exchanges to recover
* and resubmit. By default this interval is 5000 millis.
*
* @param interval the interval
* @param timeUnit the time unit
*/
public void setRecoveryInterval(long interval, TimeUnit timeUnit) {
this.recoveryInterval = timeUnit.toMillis(interval);
}
public void setRecoveryInterval(long interval) {
this.recoveryInterval = interval;
}
public long getRecoveryIntervalInMillis() {
return recoveryInterval;
}
public boolean isUseRecovery() {
return useRecovery;
}
/**
* @param useRecovery Whether or not recovery is enabled. This option is by default true. When enabled the Camel
* Aggregator automatic recover failed aggregated exchange and have them resubmittedd
*/
public void setUseRecovery(boolean useRecovery) {
this.useRecovery = useRecovery;
}
public int getMaximumRedeliveries() {
return maximumRedeliveries;
}
public void setMaximumRedeliveries(int maximumRedeliveries) {
this.maximumRedeliveries = maximumRedeliveries;
}
public String getDeadLetterUri() {
return deadLetterUri;
}
/**
* @param deadLetterUri An endpoint uri for a Dead Letter Channel where exhausted recovered Exchanges will be
* moved. If this option is used then the maximumRedeliveries option must also be provided.
* Important note : if the deadletter route throws an exception, it will be send again to DLQ
* until it succeed !
*/
public void setDeadLetterUri(String deadLetterUri) {
this.deadLetterUri = deadLetterUri;
}
public boolean isReturnOldExchange() {
return returnOldExchange;
}
/**
* @param returnOldExchange Whether the get operation should return the old existing Exchange if any existed.
* By default this option is false to optimize as we do not need the old exchange when
* aggregating
*/
public void setReturnOldExchange(boolean returnOldExchange) {
this.returnOldExchange = returnOldExchange;
}
public boolean isAllowSerializedHeaders() {
return allowSerializedHeaders;
}
public void setAllowSerializedHeaders(boolean allowSerializedHeaders) {
this.allowSerializedHeaders = allowSerializedHeaders;
}
public JdbcOptimisticLockingExceptionMapper getJdbcOptimisticLockingExceptionMapper() {
return jdbcOptimisticLockingExceptionMapper;
}
public void setJdbcOptimisticLockingExceptionMapper(JdbcOptimisticLockingExceptionMapper jdbcOptimisticLockingExceptionMapper) {
this.jdbcOptimisticLockingExceptionMapper = jdbcOptimisticLockingExceptionMapper;
}
@Override
protected void doStart() throws Exception {
ObjectHelper.notNull(bundleContext, "BundleContext");
ObjectHelper.notNull(workDirectory, "WorkDirectory");
settingsIgnite();
// log number of existing exchanges
int current = getKeys().size();
int completed = scan(null).size();
if (current > 0) {
LOG.info("On startup there are " + current + " aggregate exchanges (not completed) in repository: " + AGGREGATION);
} else {
LOG.info("On startup there are no existing aggregate exchanges (not completed) in repository: {}", AGGREGATION);
}
if (completed > 0) {
LOG.warn("On startup there are " + completed + " completed exchanges to be recovered in repository: " + AGGREGATION_COMPLETED);
} else {
LOG.info("On startup there are no completed exchanges to be recovered in repository: {}", AGGREGATION_COMPLETED);
}
}
@Override
public void doStop() throws Exception {
if (ignite != null) {
ignite.close();
}
}
private void settingsIgnite() {
IgniteConfiguration cfg = new IgniteConfiguration();
cfg.setDiscoverySpi(getTcpDiscoverySpi());
cfg.setGridLogger(new JclLogger());
cfg.setTransactionConfiguration(new TransactionConfiguration());
settingsPersistence(cfg);
aggregationCfg = getCacheConfiguration(AGGREGATION);
cfg.setCacheConfiguration(aggregationCfg);
aggregationCompletedCfg = getCacheConfiguration(AGGREGATION_COMPLETED);
cfg.setCacheConfiguration(aggregationCompletedCfg);
startIgnite(cfg);
createCache();
}
private void settingsPersistence(IgniteConfiguration cfg) {
DataStorageConfiguration storageCfg = new DataStorageConfiguration();
storageCfg.getDefaultDataRegionConfiguration().setPersistenceEnabled(true);
cfg.setWorkDirectory(workDirectory);
cfg.setDataStorageConfiguration(storageCfg);
}
private void createCache() {
transactions = ignite.transactions();
aggregationCache = ignite.getOrCreateCache(aggregationCfg);
aggregationCompleted = ignite.getOrCreateCache(aggregationCompletedCfg);
// Set the baseline topology that is represented by these nodes.
ignite.cluster().setBaselineTopology(ignite.cluster().localNode().order());
}
private void startIgnite(IgniteConfiguration cfg) {
System.setProperty(IGNITE_QUIET, "false");
ignite = Ignition.getOrStart(cfg);
ignite.cluster().active(true);
}
@NotNull
private CacheConfiguration<String, byte[]> getCacheConfiguration(String cacheName) {
CacheConfiguration<String, byte[]> cacheCfg = new CacheConfiguration<String, byte[]>();
cacheCfg.setName(cacheName);
cacheCfg.setRebalanceMode(CacheRebalanceMode.SYNC);
cacheCfg.setCacheMode(CacheMode.REPLICATED);
cacheCfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
cacheCfg.setBackups(backups);
return cacheCfg;
}
@NotNull
private TcpDiscoverySpi getTcpDiscoverySpi() {
TcpDiscoverySpi spi = new TcpDiscoverySpi();
spi.setIpFinder(new TcpDiscoveryVmIpFinder(false) {
{
setAddresses(Arrays.asList(addresses.split(",")));
}
});
return spi;
}
public void setBundleContext(BundleContext bundleContext) {
this.bundleContext = bundleContext;
}
public void setWorkDirectory(String workDirectory) {
this.workDirectory = workDirectory;
}
public void setBackups(int backups) {
this.backups = backups;
}
public void setAddresses(String addresses) {
this.addresses = addresses;
}
}

View File

@ -0,0 +1,649 @@
/*-
* ~~~~~~licensing~~~~~~
* system-commons
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.common.aggregation.repo;
import org.apache.camel.CamelContext;
import org.apache.camel.Exchange;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.processor.aggregate.jdbc.DefaultJdbcOptimisticLockingExceptionMapper;
import org.apache.camel.processor.aggregate.jdbc.JdbcCamelCodec;
import org.apache.camel.processor.aggregate.jdbc.JdbcOptimisticLockingExceptionMapper;
import org.apache.camel.spi.OptimisticLockingAggregationRepository;
import org.apache.camel.spi.RecoverableAggregationRepository;
import org.apache.camel.support.service.ServiceSupport;
import org.apache.camel.util.ObjectHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Constants;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.support.AbstractLobCreatingPreparedStatementCallback;
import org.springframework.jdbc.support.lob.DefaultLobHandler;
import org.springframework.jdbc.support.lob.LobCreator;
import org.springframework.jdbc.support.lob.LobHandler;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import javax.sql.DataSource;
import java.io.IOException;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Types;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* JDBC based {@link org.apache.camel.spi.AggregationRepository} JdbcAggregationRepository will only preserve any
* Serializable compatible data types. If a data type is not such a type its dropped and a WARN is logged. And it only
* persists the Message body and the Message headers. The Exchange properties are not persisted.
*/
public class JdbcAggregationRepository extends ServiceSupport
implements RecoverableAggregationRepository, OptimisticLockingAggregationRepository {
protected static final String EXCHANGE = "exchange";
protected static final String ID = "id";
protected static final String BODY = "body";
// optimistic locking: version identifier needed to avoid the lost update problem
private static final String VERSION = "version";
private static final String VERSION_PROPERTY = "CamelOptimisticLockVersion";
private static final Logger LOG = LoggerFactory.getLogger(JdbcAggregationRepository.class);
private static final Constants PROPAGATION_CONSTANTS = new Constants(TransactionDefinition.class);
private JdbcOptimisticLockingExceptionMapper jdbcOptimisticLockingExceptionMapper
= new DefaultJdbcOptimisticLockingExceptionMapper();
private PlatformTransactionManager transactionManager;
private DataSource dataSource;
private TransactionTemplate transactionTemplate;
private TransactionTemplate transactionTemplateReadOnly;
private int propagationBehavior = TransactionDefinition.PROPAGATION_REQUIRED;
private JdbcTemplate jdbcTemplate;
private LobHandler lobHandler = new DefaultLobHandler();
private String repositoryName;
private boolean returnOldExchange;
private JdbcCamelCodec codec = new JdbcCamelCodec();
private long recoveryInterval = 5000;
private boolean useRecovery = true;
private int maximumRedeliveries;
private String deadLetterUri;
private List<String> headersToStoreAsText;
private boolean storeBodyAsText;
private boolean allowSerializedHeaders;
/**
* Creates an aggregation repository
*/
public JdbcAggregationRepository() {
}
/**
* Creates an aggregation repository with the three mandatory parameters
*/
public JdbcAggregationRepository(PlatformTransactionManager transactionManager, String repositoryName,
DataSource dataSource) {
this.setRepositoryName(repositoryName);
this.setTransactionManager(transactionManager);
this.setDataSource(dataSource);
}
/**
* Sets the name of the repository
*/
public final void setRepositoryName(String repositoryName) {
this.repositoryName = repositoryName;
}
public final void setTransactionManager(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
/**
* Sets the DataSource to use for accessing the database
*/
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
jdbcTemplate = new JdbcTemplate(dataSource);
}
@Override
public Exchange add(
final CamelContext camelContext, final String correlationId,
final Exchange oldExchange, final Exchange newExchange)
throws OptimisticLockingException {
try {
return add(camelContext, correlationId, newExchange);
} catch (Exception e) {
if (jdbcOptimisticLockingExceptionMapper != null && jdbcOptimisticLockingExceptionMapper.isOptimisticLocking(e)) {
throw new OptimisticLockingException();
} else {
throw RuntimeCamelException.wrapRuntimeCamelException(e);
}
}
}
@Override
public Exchange add(final CamelContext camelContext, final String correlationId, final Exchange exchange) {
return transactionTemplate.execute(status -> {
Exchange result = null;
final String key = correlationId;
try {
LOG.debug("Adding exchange with key {}", key);
boolean present = jdbcTemplate.queryForObject(
"SELECT COUNT(1) FROM " + getRepositoryName() + " WHERE " + ID + " = ?", Integer.class, key) != 0;
// Recover existing exchange with that ID
if (isReturnOldExchange() && present) {
result = get(key, getRepositoryName(), camelContext);
}
if (present) {
long version = exchange.getProperty(VERSION_PROPERTY, Long.class);
LOG.debug("Updating record with key {} and version {}", key, version);
update(camelContext, correlationId, exchange, getRepositoryName(), version);
} else {
LOG.debug("Inserting record with key {}", key);
insert(camelContext, correlationId, exchange, getRepositoryName(), 1L);
}
} catch (Exception e) {
throw new RuntimeException("Error adding to repository " + repositoryName + " with key " + key, e);
}
return result;
});
}
/**
* Updates the current exchange details in the given repository table.
*
* @param camelContext Current CamelContext
* @param key Correlation key
* @param exchange Aggregated exchange
* @param repositoryName Table's name
* @param version Version identifier
*/
protected void update(
final CamelContext camelContext, final String key, final Exchange exchange, String repositoryName, Long version)
throws Exception {
StringBuilder queryBuilder = new StringBuilder()
.append("UPDATE ").append(repositoryName)
.append(" SET ")
.append(EXCHANGE).append(" = ?")
.append(", ")
.append(VERSION).append(" = ?");
if (storeBodyAsText) {
queryBuilder.append(", ").append(BODY).append(" = ?");
}
if (hasHeadersToStoreAsText()) {
for (String headerName : headersToStoreAsText) {
queryBuilder.append(", ").append(headerName).append(" = ?");
}
}
queryBuilder.append(" WHERE ")
.append(ID).append(" = ?")
.append(" AND ")
.append(VERSION).append(" = ?");
String sql = queryBuilder.toString();
updateHelper(camelContext, key, exchange, sql, version);
}
/**
* Inserts a new record into the given repository table. Note: the exchange properties are NOT persisted.
*
* @param camelContext Current CamelContext
* @param correlationId Correlation key
* @param exchange Aggregated exchange to insert
* @param repositoryName Table's name
* @param version Version identifier
*/
protected void insert(
final CamelContext camelContext, final String correlationId, final Exchange exchange, String repositoryName,
Long version)
throws Exception {
// The default totalParameterIndex is 3 for ID, Exchange and version. Depending on logic this will be increased.
int totalParameterIndex = 3;
StringBuilder queryBuilder = new StringBuilder()
.append("INSERT INTO ").append(repositoryName)
.append('(').append(EXCHANGE)
.append(", ").append(ID)
.append(", ").append(VERSION);
if (storeBodyAsText) {
queryBuilder.append(", ").append(BODY);
totalParameterIndex++;
}
if (hasHeadersToStoreAsText()) {
for (String headerName : headersToStoreAsText) {
queryBuilder.append(", ").append(headerName);
totalParameterIndex++;
}
}
queryBuilder.append(") VALUES (");
for (int i = 0; i < totalParameterIndex - 1; i++) {
queryBuilder.append("?, ");
}
queryBuilder.append("?)");
String sql = queryBuilder.toString();
insertHelper(camelContext, correlationId, exchange, sql, version);
}
protected int insertHelper(
final CamelContext camelContext, final String key, final Exchange exchange, String sql, final Long version)
throws Exception {
final byte[] data = codec.marshallExchange(camelContext, exchange, allowSerializedHeaders);
Integer insertCount = jdbcTemplate.execute(sql,
new AbstractLobCreatingPreparedStatementCallback(getLobHandler()) {
@Override
protected void setValues(PreparedStatement ps, LobCreator lobCreator) throws SQLException {
int totalParameterIndex = 0;
lobCreator.setBlobAsBytes(ps, ++totalParameterIndex, data);
ps.setString(++totalParameterIndex, key);
ps.setLong(++totalParameterIndex, version);
if (storeBodyAsText) {
ps.setString(++totalParameterIndex, exchange.getIn().getBody(String.class));
}
if (hasHeadersToStoreAsText()) {
for (String headerName : headersToStoreAsText) {
String headerValue = exchange.getIn().getHeader(headerName, String.class);
ps.setString(++totalParameterIndex, headerValue);
}
}
}
});
return insertCount == null ? 0 : insertCount;
}
protected int updateHelper(
final CamelContext camelContext, final String key, final Exchange exchange, String sql, final Long version)
throws Exception {
final byte[] data = codec.marshallExchange(camelContext, exchange, allowSerializedHeaders);
Integer updateCount = jdbcTemplate.execute(sql,
new AbstractLobCreatingPreparedStatementCallback(getLobHandler()) {
@Override
protected void setValues(PreparedStatement ps, LobCreator lobCreator) throws SQLException {
int totalParameterIndex = 0;
lobCreator.setBlobAsBytes(ps, ++totalParameterIndex, data);
ps.setLong(++totalParameterIndex, version + 1);
if (storeBodyAsText) {
ps.setString(++totalParameterIndex, exchange.getIn().getBody(String.class));
}
if (hasHeadersToStoreAsText()) {
for (String headerName : headersToStoreAsText) {
String headerValue = exchange.getIn().getHeader(headerName, String.class);
ps.setString(++totalParameterIndex, headerValue);
}
}
ps.setString(++totalParameterIndex, key);
ps.setLong(++totalParameterIndex, version);
}
});
if (updateCount == 1) {
return updateCount;
} else {
// Found stale version while updating record
throw new OptimisticLockingException();
}
}
@Override
public Exchange get(final CamelContext camelContext, final String correlationId) {
final String key = correlationId;
Exchange result = get(key, getRepositoryName(), camelContext);
LOG.debug("Getting key {} -> {}", key, result);
return result;
}
private Exchange get(final String key, final String repositoryName, final CamelContext camelContext) {
return transactionTemplateReadOnly.execute(status -> {
try {
Map<String, Object> columns = jdbcTemplate.queryForMap(
String.format("SELECT %1$s, %2$s FROM %3$s WHERE %4$s=?", EXCHANGE, VERSION, repositoryName, ID),
new Object[]{key}, new int[]{Types.VARCHAR});
byte[] marshalledExchange = (byte[]) columns.get(EXCHANGE);
long version = (long) columns.get(VERSION);
Exchange result = codec.unmarshallExchange(camelContext, marshalledExchange);
result.setProperty(VERSION_PROPERTY, version);
return result;
} catch (EmptyResultDataAccessException ex) {
return null;
} catch (IOException ex) {
// Rollback the transaction
throw new RuntimeException("Error getting key " + key + " from repository " + repositoryName, ex);
} catch (ClassNotFoundException ex) {
// Rollback the transaction
throw new RuntimeException(ex);
}
});
}
@Override
public void remove(final CamelContext camelContext, final String correlationId, final Exchange exchange) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
final String key = correlationId;
final String confirmKey = exchange.getExchangeId();
final long version = exchange.getProperty(VERSION_PROPERTY, Long.class);
try {
LOG.debug("Removing key {}", key);
// добавлена проверка на корректное удаление из таблицы, т к возникала ситуация гонки на узлах.
// один узел уже удалил из completed, а второй в процессе, соответственно ошибки дублирования
// не появляется появляется дубликат в очереди
if (jdbcTemplate.update("DELETE FROM " + getRepositoryName() + " WHERE " + ID + " = ? AND " + VERSION + " = ?",
key, version) == 1) {
insert(camelContext, confirmKey, exchange, getRepositoryNameCompleted(), version);
} else {
throw new RuntimeException("Error removing key " + key + " from repository " + repositoryName);
}
} catch (Exception e) {
throw new RuntimeException("Error removing key " + key + " from repository " + repositoryName, e);
}
}
});
}
@Override
public void confirm(final CamelContext camelContext, final String exchangeId) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
LOG.debug("Confirming exchangeId {}", exchangeId);
final String confirmKey = exchangeId;
jdbcTemplate.update("DELETE FROM " + getRepositoryNameCompleted() + " WHERE " + ID + " = ?",
confirmKey);
}
});
}
@Override
public Set<String> getKeys() {
return getKeys(getRepositoryName());
}
@Override
public Set<String> scan(CamelContext camelContext) {
return getKeys(getRepositoryNameCompleted());
}
/**
* Returns the keys in the given repository
*
* @param repositoryName The name of the table
* @return Set of keys in the given repository name
*/
protected Set<String> getKeys(final String repositoryName) {
return transactionTemplateReadOnly.execute(status -> {
List<String> keys = jdbcTemplate.query("SELECT " + ID + " FROM " + repositoryName,
(rs, rowNum) -> {
String id = rs.getString(ID);
LOG.trace("getKey {}", id);
return id;
});
return new LinkedHashSet<>(keys);
});
}
@Override
public Exchange recover(CamelContext camelContext, String exchangeId) {
final String key = exchangeId;
Exchange answer = get(key, getRepositoryNameCompleted(), camelContext);
LOG.debug("Recovering exchangeId {} -> {}", key, answer);
return answer;
}
/**
* If recovery is enabled then a background task is run every x'th time to scan for failed exchanges to recover and
* resubmit. By default this interval is 5000 millis.
*/
@Override
public void setRecoveryInterval(long interval, TimeUnit timeUnit) {
this.recoveryInterval = timeUnit.toMillis(interval);
}
@Override
public void setRecoveryInterval(long interval) {
this.recoveryInterval = interval;
}
@Override
public long getRecoveryIntervalInMillis() {
return recoveryInterval;
}
@Override
public boolean isUseRecovery() {
return useRecovery;
}
/**
* Whether or not recovery is enabled. This option is by default true. When enabled the Camel Aggregator automatic
* recover failed aggregated exchange and have them resubmitted.
*/
@Override
public void setUseRecovery(boolean useRecovery) {
this.useRecovery = useRecovery;
}
@Override
public int getMaximumRedeliveries() {
return maximumRedeliveries;
}
@Override
public void setMaximumRedeliveries(int maximumRedeliveries) {
this.maximumRedeliveries = maximumRedeliveries;
}
@Override
public String getDeadLetterUri() {
return deadLetterUri;
}
/**
* An endpoint uri for a Dead Letter Channel where exhausted recovered Exchanges will be moved. If this option is
* used then the maximumRedeliveries option must also be provided. Important note : if the deadletter route throws
* an exception, it will be send again to DLQ until it succeed !
*/
@Override
public void setDeadLetterUri(String deadLetterUri) {
this.deadLetterUri = deadLetterUri;
}
public boolean isReturnOldExchange() {
return returnOldExchange;
}
/**
* Whether the get operation should return the old existing Exchange if any existed. By default this option is false
* to optimize as we do not need the old exchange when aggregating.
*/
public void setReturnOldExchange(boolean returnOldExchange) {
this.returnOldExchange = returnOldExchange;
}
public void setJdbcCamelCodec(JdbcCamelCodec codec) {
this.codec = codec;
}
public boolean hasHeadersToStoreAsText() {
return this.headersToStoreAsText != null && !this.headersToStoreAsText.isEmpty();
}
public List<String> getHeadersToStoreAsText() {
return headersToStoreAsText;
}
/**
* Allows to store headers as String which is human readable. By default this option is disabled, storing the
* headers in binary format.
*
* @param headersToStoreAsText the list of headers to store as String
*/
public void setHeadersToStoreAsText(List<String> headersToStoreAsText) {
this.headersToStoreAsText = headersToStoreAsText;
}
public boolean isStoreBodyAsText() {
return storeBodyAsText;
}
/**
* Whether to store the message body as String which is human readable. By default this option is false storing the
* body in binary format.
*/
public void setStoreBodyAsText(boolean storeBodyAsText) {
this.storeBodyAsText = storeBodyAsText;
}
public boolean isAllowSerializedHeaders() {
return allowSerializedHeaders;
}
public void setAllowSerializedHeaders(boolean allowSerializedHeaders) {
this.allowSerializedHeaders = allowSerializedHeaders;
}
public int getPropagationBehavior() {
return propagationBehavior;
}
/**
* Sets propagation behavior to use with spring transaction templates which are used for database access. The
* default is TransactionDefinition.PROPAGATION_REQUIRED.
*/
public void setPropagationBehavior(int propagationBehavior) {
this.propagationBehavior = propagationBehavior;
}
/**
* Sets propagation behavior to use with spring transaction templates which are used for database access. The
* default is TransactionDefinition.PROPAGATION_REQUIRED. This setter accepts names of the constants, like
* "PROPAGATION_REQUIRED".
*
* @param propagationBehaviorName
*/
public void setPropagationBehaviorName(String propagationBehaviorName) {
if (!propagationBehaviorName.startsWith(DefaultTransactionDefinition.PREFIX_PROPAGATION)) {
throw new IllegalArgumentException("Only propagation constants allowed");
}
setPropagationBehavior(PROPAGATION_CONSTANTS.asNumber(propagationBehaviorName).intValue());
}
public LobHandler getLobHandler() {
return lobHandler;
}
/**
* Sets a custom LobHandler to use
*/
public void setLobHandler(LobHandler lobHandler) {
this.lobHandler = lobHandler;
}
public JdbcOptimisticLockingExceptionMapper getJdbcOptimisticLockingExceptionMapper() {
return jdbcOptimisticLockingExceptionMapper;
}
public void setJdbcOptimisticLockingExceptionMapper(
JdbcOptimisticLockingExceptionMapper jdbcOptimisticLockingExceptionMapper) {
this.jdbcOptimisticLockingExceptionMapper = jdbcOptimisticLockingExceptionMapper;
}
public String getRepositoryName() {
return repositoryName;
}
public String getRepositoryNameCompleted() {
return getRepositoryName() + "_completed";
}
@Override
protected void doInit() throws Exception {
super.doInit();
ObjectHelper.notNull(repositoryName, "RepositoryName");
ObjectHelper.notNull(transactionManager, "TransactionManager");
ObjectHelper.notNull(dataSource, "DataSource");
transactionTemplate = new TransactionTemplate(transactionManager);
transactionTemplate.setPropagationBehavior(propagationBehavior);
transactionTemplateReadOnly = new TransactionTemplate(transactionManager);
transactionTemplateReadOnly.setPropagationBehavior(propagationBehavior);
transactionTemplateReadOnly.setReadOnly(true);
}
@Override
protected void doStart() throws Exception {
super.doStart();
// log number of existing exchanges
int current = getKeys().size();
int completed = scan(null).size();
if (current > 0) {
LOG.info("On startup there are " + current + " aggregate exchanges (not completed) in repository: "
+ getRepositoryName());
} else {
LOG.info("On startup there are no existing aggregate exchanges (not completed) in repository: {}",
getRepositoryName());
}
if (completed > 0) {
LOG.warn("On startup there are " + completed + " completed exchanges to be recovered in repository: "
+ getRepositoryNameCompleted());
} else {
LOG.info("On startup there are no completed exchanges to be recovered in repository: {}",
getRepositoryNameCompleted());
}
}
@Override
protected void doStop() throws Exception {
// noop
}
}

View File

@ -0,0 +1,97 @@
/*-
* ~~~~~~licensing~~~~~~
* system-commons
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.common.aggregation.repo;
import org.apache.camel.CamelContext;
import org.apache.camel.Exchange;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
/**
* PostgreSQL specific {@link JdbcAggregationRepository} that deals with SQL Violation Exceptions using special
* {@code INSERT INTO .. ON CONFLICT DO NOTHING} claues.
*/
public class PostgresAggregationRepository extends JdbcAggregationRepository {
/**
* Creates an aggregation repository
*/
public PostgresAggregationRepository() {
}
/**
* Creates an aggregation repository with the three mandatory parameters
*/
public PostgresAggregationRepository(PlatformTransactionManager transactionManager, String repositoryName,
DataSource dataSource) {
super(transactionManager, repositoryName, dataSource);
}
/**
* Inserts a new record into the given repository table
*
* @param camelContext the current CamelContext
* @param correlationId the correlation key
* @param exchange the aggregated exchange
* @param repositoryName The name of the table
*/
protected void insert(
final CamelContext camelContext, final String correlationId, final Exchange exchange, String repositoryName)
throws Exception {
// The default totalParameterIndex is 2 for ID and Exchange. Depending on logic this will be increased
int totalParameterIndex = 2;
StringBuilder queryBuilder = new StringBuilder()
.append("INSERT INTO ").append(repositoryName)
.append('(')
.append(EXCHANGE).append(", ")
.append(ID);
if (isStoreBodyAsText()) {
queryBuilder.append(", ").append(BODY);
totalParameterIndex++;
}
if (hasHeadersToStoreAsText()) {
for (String headerName : getHeadersToStoreAsText()) {
queryBuilder.append(", ").append(headerName);
totalParameterIndex++;
}
}
queryBuilder.append(") VALUES (");
for (int i = 0; i < totalParameterIndex - 1; i++) {
queryBuilder.append("?, ");
}
queryBuilder.append("?)");
queryBuilder.append(" ON CONFLICT DO NOTHING");
String sql = queryBuilder.toString();
int updateCount = insertHelper(camelContext, correlationId, exchange, sql, 1L);
if (updateCount == 0 && getRepositoryName().equals(repositoryName)) {
throw new DataIntegrityViolationException("No row was inserted due to data violation");
}
}
}

View File

@ -0,0 +1,44 @@
/*-
* ~~~~~~licensing~~~~~~
* system-commons
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.common.exception;
public class BundleNotFound extends RuntimeException {
public BundleNotFound() {
super();
}
public BundleNotFound(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public BundleNotFound(String message, Throwable cause) {
super(message, cause);
}
public BundleNotFound(String message) {
super(message);
}
public BundleNotFound(Throwable cause) {
super(cause);
}
}

View File

@ -0,0 +1,44 @@
/*-
* ~~~~~~licensing~~~~~~
* system-commons
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.common.exception;
public class ConnectorNotFound extends RuntimeException {
public ConnectorNotFound() {
super();
}
public ConnectorNotFound(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public ConnectorNotFound(String message, Throwable cause) {
super(message, cause);
}
public ConnectorNotFound(String message) {
super(message);
}
public ConnectorNotFound(Throwable cause) {
super(cause);
}
}

View File

@ -0,0 +1,44 @@
/*-
* ~~~~~~licensing~~~~~~
* system-commons
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.common.exception;
public class EsbNotFound extends RuntimeException {
public EsbNotFound() {
super();
}
public EsbNotFound(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public EsbNotFound(String message, Throwable cause) {
super(message, cause);
}
public EsbNotFound(String message) {
super(message);
}
public EsbNotFound(Throwable cause) {
super(cause);
}
}

View File

@ -0,0 +1,46 @@
/*-
* ~~~~~~licensing~~~~~~
* system-commons
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.common.exception;
public class ProfileNotFound extends RuntimeException {
private static final long serialVersionUID = 6701844035750412423L;
public ProfileNotFound() {
super();
}
public ProfileNotFound(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public ProfileNotFound(String message, Throwable cause) {
super(message, cause);
}
public ProfileNotFound(String message) {
super(message);
}
public ProfileNotFound(Throwable cause) {
super(cause);
}
}

View File

@ -0,0 +1,44 @@
/*-
* ~~~~~~licensing~~~~~~
* system-commons
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.common.exception;
public class TemplateNotFound extends RuntimeException {
public TemplateNotFound() {
super();
}
public TemplateNotFound(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public TemplateNotFound(String message, Throwable cause) {
super(message, cause);
}
public TemplateNotFound(String message) {
super(message);
}
public TemplateNotFound(Throwable cause) {
super(cause);
}
}

View File

@ -0,0 +1,70 @@
/*-
* ~~~~~~licensing~~~~~~
* system-commons
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.common.interceptor;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
import org.apache.cxf.headers.Header;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.jaxb.JAXBDataBinding;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.Phase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.xml.bind.JAXBException;
import javax.xml.namespace.QName;
import java.util.List;
import java.util.Map;
public class SoapHeaderInterceptor extends AbstractSoapInterceptor {
private static final Logger log = LoggerFactory.getLogger(SoapHeaderInterceptor.class);
private static final String HEADER_USER_LOGIN = "X-ForwardedUser";
private static final String HEADER_CREATED_BY = "createdBy";
private String namespaceUri = "";
public SoapHeaderInterceptor() {
super(Phase.READ);
}
public void handleMessage(SoapMessage message) throws Fault {
try {
Map<String, List<String>> headers = (Map<String, List<String>>) message.get(Message.PROTOCOL_HEADERS);
List<Header> soapHeaders = message.getHeaders();
soapHeaders.add(new Header(new QName(namespaceUri, HEADER_CREATED_BY),
getSystemName(headers), new JAXBDataBinding(String.class)));
message.put(Header.HEADER_LIST, soapHeaders);
} catch (JAXBException e) {
log.error("Error", e);
throw new Fault(e);
}
}
private String getSystemName(Map<String, List<String>> headers) {
List<String> list = headers.get(HEADER_USER_LOGIN);
return list != null && !list.isEmpty() ? headers.get(HEADER_USER_LOGIN).get(0) : null;
}
public void setNamespaceUri(String namespaceUri) {
this.namespaceUri = namespaceUri;
}
}

View File

@ -0,0 +1,37 @@
/*-
* ~~~~~~licensing~~~~~~
* system-commons
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.common.osgi;
import java.util.List;
/**
* @author starovoitenkov_sv
*
*/
public interface BundleMarkerService {
public static final String CATEGORY_PROPERTY_NAME = "ru.entaxy.esb.system.common.marker.category";
public long getBundleId();
public String getMarkerCategory();
public List<String> getMarkers();
}

View File

@ -0,0 +1,32 @@
/*-
* ~~~~~~licensing~~~~~~
* system-commons
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.common.osgi;
import java.util.List;
public interface NamedReferenceListener<T> extends ReferenceListener<T> {
public List<String> getReferenceNames();
public T getReference(String referenceName);
public boolean isRegistered(String referenceName);
}

View File

@ -0,0 +1,36 @@
/*-
* ~~~~~~licensing~~~~~~
* system-commons
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.common.osgi;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
public class OSGIUtils {
static public Object getServiceReference(BundleContext bundle, String className) {
Object result = null;
ServiceReference ref = bundle.getServiceReference(className);
if (ref != null) {
result = bundle.getService(ref);
}
return result;
}
}

View File

@ -0,0 +1,26 @@
/*-
* ~~~~~~licensing~~~~~~
* system-commons
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.common.osgi;
public interface ReferenceListener<T> {
public void register(T service) throws Exception;
public void unregister(T service) throws Exception;
}

View File

@ -0,0 +1,58 @@
/*-
* ~~~~~~licensing~~~~~~
* system-commons
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.common.osgi;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleEvent;
import org.osgi.util.tracker.BundleTrackerCustomizer;
public abstract class UniformBundleTracker implements BundleTrackerCustomizer {
@Override
public Object addingBundle(Bundle bundle, BundleEvent event) {
if (event == null) {
// existing bundles first added to the tracker with no event change
checkInitialBundle(bundle);
} else {
bundleChanged(event);
}
return bundle;
}
@Override
public void modifiedBundle(Bundle bundle, BundleEvent event, Object object) {
if (event == null) {
// cannot think of why we would be interested in a modified bundle with no bundle event
return;
}
bundleChanged(event);
}
@Override
public void removedBundle(Bundle bundle, BundleEvent event, Object object) {
// TODO Auto-generated method stub
}
protected abstract void checkInitialBundle(Bundle bundle);
protected abstract void bundleChanged(BundleEvent event);
}

View File

@ -0,0 +1,113 @@
/*-
* ~~~~~~licensing~~~~~~
* system-commons
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.common.osgi.impl;
import org.osgi.framework.Bundle;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.blueprint.container.BlueprintContainer;
import ru.entaxy.esb.system.common.osgi.BundleMarkerService;
import java.util.*;
/**
* @author starovoitenkov_sv
*
*/
public class BundleMarkerServiceImpl implements BundleMarkerService {
protected Bundle bundle = null;
protected BlueprintContainer container = null;
protected List<String> markers = new ArrayList<String>();
protected String category = null;
protected ServiceRegistration serviceRegistration = null;
protected Map<String, String> serviceProperties = new HashMap<String, String>();
/* (non-Javadoc)
* @see ru.entaxy.esb.system.common.osgi.BundleMarkerService#getBundleId()
*/
@Override
public long getBundleId() {
return (bundle == null ? -1 : bundle.getBundleId());
}
/* (non-Javadoc)
* @see ru.entaxy.esb.system.common.osgi.BundleMarkerService#getMarkerCategory()
*/
@Override
public String getMarkerCategory() {
return category;
}
/* (non-Javadoc)
* @see ru.entaxy.esb.system.common.osgi.BundleMarkerService#getMarkers()
*/
@Override
public List<String> getMarkers() {
return markers;
}
// LOCAL
@SuppressWarnings({"rawtypes", "unchecked"})
public void init() throws Exception {
if (bundle == null)
throw new Exception("Bundle not set");
if (container == null)
throw new Exception("Container not set");
Dictionary properties = new Hashtable();
for (Map.Entry<String, String> entry : serviceProperties.entrySet())
properties.put(entry.getKey(), entry.getValue());
properties.put(BundleMarkerService.CATEGORY_PROPERTY_NAME, category);
serviceRegistration = bundle.getBundleContext().registerService(BundleMarkerService.class.getName(), this, properties);
}
public void destroy() {
if (serviceRegistration != null)
serviceRegistration.unregister();
}
// ACCESSORS
public void setBundle(Bundle bundle) {
this.bundle = bundle;
}
public void setContainer(BlueprintContainer container) {
this.container = container;
}
public void setMarkers(List<String> markers) {
this.markers = markers;
}
public void setCategory(String category) {
this.category = category;
}
public Map<String, String> getServiceProperties() {
return serviceProperties;
}
public void setServiceProperties(Map<String, String> serviceProperties) {
this.serviceProperties = serviceProperties;
}
}

View File

@ -0,0 +1,71 @@
/*-
* ~~~~~~licensing~~~~~~
* system-commons
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.common.osgi.impl;
import org.osgi.framework.ServiceReference;
import ru.entaxy.esb.system.common.osgi.NamedReferenceListener;
import java.util.*;
public abstract class CommonNamedReferenceListener<T> implements NamedReferenceListener<T> {
protected Map<String, T> registeredReferences = new HashMap<String, T>();
public void register(T service) throws Exception {
if (service instanceof ServiceReference)
return;
String key = getObjectName(service);
registeredReferences.put(key, service);
doAfterRegister(service);
}
protected void doAfterRegister(T service) throws Exception {
}
protected void doBeforeUnregister(T service) throws Exception {
}
public void unregister(T service) throws Exception {
if (service == null || service instanceof ServiceReference)
return;
doBeforeUnregister(service);
registeredReferences.remove(getObjectName(service));
}
@Override
public List<String> getReferenceNames() {
List<String> result = new ArrayList<String>(registeredReferences.keySet());
Collections.sort(result);
return result;
}
@Override
public T getReference(String referenceName) {
return registeredReferences.get(referenceName);
}
public boolean isRegistered(String referenceName) {
return registeredReferences.containsKey(referenceName);
}
protected abstract String getObjectName(T object);
}

View File

@ -0,0 +1,56 @@
/*-
* ~~~~~~licensing~~~~~~
* system-commons
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.common.osgi.impl;
import org.osgi.framework.ServiceReference;
import ru.entaxy.esb.system.common.osgi.ReferenceListener;
import java.util.ArrayList;
import java.util.List;
public class CommonReferenceListener<T> implements ReferenceListener<T> {
protected List<T> registeredReferences = new ArrayList<T>();
public void register(T service) {
if (service instanceof ServiceReference)
return;
registeredReferences.add(service);
doAfterRegister(service);
}
protected void doAfterRegister(T service) {
// to override
}
protected void doBeforeUnregister(T service) {
// to override
}
public void unregister(T service) {
if (service instanceof ServiceReference)
return;
if (registeredReferences.contains(service)) {
doBeforeUnregister(service);
registeredReferences.remove(service);
}
}
}

View File

@ -0,0 +1,60 @@
/*-
* ~~~~~~licensing~~~~~~
* system-commons
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.common.util;
public class CustomHeader {
private String id;
private String type;
private String value;
public CustomHeader() {
}
public CustomHeader(String id, String type, String value) {
this.id = id;
this.type = type;
this.value = value;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}

View File

@ -0,0 +1,183 @@
/*-
* ~~~~~~licensing~~~~~~
* system-commons
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.common.util;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.apache.camel.Exchange;
import org.apache.xerces.dom.DocumentImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class HeadersConverter {
protected static final Logger log = LoggerFactory.getLogger(HeadersConverter.class);
private String customHeaders;
private String customHeaderPrefix;
private String namespace;
public void xml2camelHeaders(Exchange exchange) {
NodeList nodes = exchange.getIn().getHeader(customHeaders, NodeList.class);
if (nodes == null) {
log.warn(customHeaders + " not found");
return;
}
for (int i = 0; i < nodes.getLength(); ++i) {
Node child = nodes.item(i).getFirstChild();
String headerName = "";
String headerValue = "";
while (child != null) {
if ("id".equals(child.getLocalName())) {
headerName = customHeaderPrefix + child.getTextContent();
} else if ("value".equals(child.getLocalName())) {
headerValue = child.getTextContent();
}
child = child.getNextSibling();
}
if (!headerName.isEmpty()) {
exchange.getIn().setHeader(headerName, headerValue);
}
}
log.debug("Parsed xml custom headers count {}", nodes.getLength());
}
public void camelHeaders2xml(Exchange exchange) {
Node item = null;
Node child = null;
Document xmlDoc = new DocumentImpl();
Node list = xmlDoc.createElement("list");
for (Map.Entry<String, Object> entry : exchange.getIn().getHeaders().entrySet()) {
if (entry.getKey().startsWith(customHeaderPrefix)) {
String name = entry.getKey().substring(customHeaderPrefix.length());
if (entry.getValue() == null) break;
String value = entry.getValue().toString();
item = xmlDoc.createElementNS(namespace, "customHeader");
child = xmlDoc.createElementNS(namespace, "id");
child.appendChild(xmlDoc.createTextNode(name));
item.appendChild(child);
child = xmlDoc.createElementNS(namespace, "value");
child.appendChild(xmlDoc.createTextNode(value));
item.appendChild(child);
list.appendChild(item);
}
}
exchange.getIn().setHeader(customHeaders, list);
}
public void xml2Json(Exchange exchange) {
NodeList nodes = exchange.getIn().getHeader(customHeaders, NodeList.class);
if (nodes == null) {
log.warn(customHeaders + " not found");
return;
}
List<CustomHeader> customHeaders = new ArrayList<>();
for (int i = 0; i < nodes.getLength(); ++i) {
Node child = nodes.item(i).getFirstChild();
String headerName = "";
String headerValue = "";
String headerType = "";
while (child != null) {
if ("id".equals(child.getLocalName())) {
headerName = child.getTextContent();
} else if ("value".equals(child.getLocalName())) {
headerValue = child.getTextContent();
} else if ("type".equals(child.getLocalName())) {
headerType = child.getTextContent();
}
child = child.getNextSibling();
}
if (!headerName.isEmpty()) {
customHeaders.add(new CustomHeader(headerName, headerType, headerValue));
}
}
Gson gson = new Gson();
exchange.getIn().setHeader(this.customHeaders, gson.toJson(customHeaders));
log.debug("Parsed xml custom headers count {}", nodes.getLength());
}
public void json2xml(Exchange exchange) {
String headers = exchange.getIn().getHeader(customHeaders, String.class);
if (headers == null) {
log.warn(customHeaders + " not found");
return;
}
Gson gson = new Gson();
List<CustomHeader> customHeaders = gson.fromJson(headers, new TypeToken<ArrayList<CustomHeader>>() {
}.getType());
Node item = null;
Node child = null;
Document xmlDoc = new DocumentImpl();
Node list = xmlDoc.createElement("list");
for (CustomHeader customHeader : customHeaders) {
item = xmlDoc.createElementNS(namespace, "customHeader");
child = xmlDoc.createElementNS(namespace, "id");
child.appendChild(xmlDoc.createTextNode(customHeader.getId()));
item.appendChild(child);
child = xmlDoc.createElementNS(namespace, "type");
child.appendChild(xmlDoc.createTextNode(customHeader.getType()));
item.appendChild(child);
child = xmlDoc.createElementNS(namespace, "value");
child.appendChild(xmlDoc.createTextNode(customHeader.getValue()));
item.appendChild(child);
list.appendChild(item);
}
exchange.getIn().setHeader(this.customHeaders, list);
}
public void setCustomHeaderPrefix(String customHeaderPrefix) {
this.customHeaderPrefix = customHeaderPrefix;
}
public void setCustomHeaders(String customHeaders) {
this.customHeaders = customHeaders;
}
public void setNamespace(String namespace) {
this.namespace = namespace;
}
}

View File

@ -0,0 +1,151 @@
/*-
* ~~~~~~licensing~~~~~~
* system-commons
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.common.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class PropertiesHelper {
private static final Log LOG = LogFactory.getLog(PropertiesHelper.class.getName());
private static final String EMPTY_STRING = "";
private String configPath;
private static final String karafEtcPath = System.getProperty("karaf.etc");
private String configFile;
private Properties properties;
public PropertiesHelper() {
}
public PropertiesHelper(String configPath) {
LOG.debug("Set custom path: " + configPath + " file: " + configFile);
this.configPath = configPath;
}
public PropertiesHelper(String configPath, String configFile) {
LOG.debug("Load properties from custom path: " + configPath + " file: " + configFile);
this.configPath = configPath;
this.configFile = configFile;
loadProperties(configPath, configFile);
}
public PropertiesHelper(String configFile, boolean loadKarafEtc) {
this.configFile = configFile;
LOG.debug("Load properties from karaf etc: " + karafEtcPath + " file: " + configFile);
if (loadKarafEtc) {
loadProperties(karafEtcPath, configFile);
LOG.debug("Loaded properties: " + (properties != null ? properties.size() : "null"));
}
}
public Properties load() {
if (this.configPath != null && !this.configPath.isEmpty()
&& this.configFile != null && !this.configFile.isEmpty()) {
return loadProperties(configPath, configFile);
} else if (this.configFile != null && !this.configFile.isEmpty()) {
return loadProperties(karafEtcPath, configFile);
} else {
throw new IllegalArgumentException("configPath OR configFile NOT SETTED");
}
}
protected Properties loadProperties(String path, String configFile) {
try (InputStream input = new FileInputStream(path + File.separator + configFile)) {
properties = new Properties();
properties.load(input);
} catch (IOException ex) {
LOG.error(ex);
}
return properties;
}
public long getInteger(String name) {
return getInteger(name, 0);
}
public long getInteger(String name, int defaultValue) {
String value = this.properties.getProperty(name);
return value != null && !EMPTY_STRING.equals(value) ? Integer.valueOf(value) : defaultValue;
}
public int getInteger(String name, String defaultValue) {
return Integer.valueOf(this.properties.getProperty(name, defaultValue));
}
public long getLong(String name) {
return getLong(name, 0L);
}
public long getLong(String name, long defaultValue) {
String value = this.properties.getProperty(name);
return value != null && !EMPTY_STRING.equals(value) ? Long.valueOf(value) : defaultValue;
}
public long getLong(String name, String defaultValue) {
return Long.valueOf(this.properties.getProperty(name, defaultValue));
}
public String getString(String name) {
return this.properties.getProperty(name, EMPTY_STRING);
}
public String getString(String name, String defaultValue) {
return this.properties.getProperty(name, defaultValue);
}
public String[] getStringArray(String name, String[] defaultValue) {
String value = this.properties.getProperty(name, EMPTY_STRING);
return !value.equals(EMPTY_STRING) ? value.split(",") : defaultValue;
}
public String getConfigPath() {
return configPath;
}
public void setConfigPath(String configPath) {
this.configPath = configPath;
}
public String getConfigFile() {
return configFile;
}
public void setConfigFile(String configFile) {
this.configFile = configFile;
}
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
}

View File

@ -0,0 +1,50 @@
/*-
* ~~~~~~licensing~~~~~~
* system-commons
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.common.util;
import org.apache.camel.Exchange;
import org.apache.camel.spi.HeaderFilterStrategy;
import java.util.HashSet;
import java.util.Set;
public class SimpleOutHeaderFilterStrategy implements HeaderFilterStrategy {
private Set<String> outFilter;
public void setOutFilter(Set<String> value) {
if (value == null) {
outFilter = new HashSet<>();
} else {
outFilter = value;
}
}
@Override
public boolean applyFilterToCamelHeaders(String headerName, Object headerValue, Exchange exchange) {
return !outFilter.contains(headerName);
}
@Override
public boolean applyFilterToExternalHeaders(String headerName, Object headerValue, Exchange exchange) {
return false;
}
}

View File

@ -0,0 +1,31 @@
/*-
* ~~~~~~licensing~~~~~~
* system-commons
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.common.util;
public class SystemHeadersConstants {
public static final String HEADER_USER_LOGIN = "X-ForwardedUser";
public static final String HEADER_USER_ID = "X-ForwardedUserId";
public static final String HEADER_SYSTEM_NAME = "X-SystemName";
public static final String HEADER_SYSTEM_UUID = "X-SystemUuid";
public static final String HEADER_SYSTEM_ID = "X-SystemId";
private SystemHeadersConstants() {
}
}

View File

@ -0,0 +1,116 @@
/*-
* ~~~~~~licensing~~~~~~
* system-commons
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.common.validator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.saaj.SAAJInInterceptor;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.apache.cxf.service.Service;
import org.apache.cxf.service.model.ServiceModelUtil;
import org.apache.cxf.ws.addressing.EndpointReferenceUtils;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
import javax.xml.soap.SOAPMessage;
import javax.xml.stream.XMLStreamException;
import javax.xml.transform.dom.DOMSource;
import javax.xml.validation.Schema;
import javax.xml.validation.Validator;
import javax.xml.xpath.XPathExpressionException;
import java.io.IOException;
import java.util.List;
public class ValidateInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
private static final Log LOG = LogFactory.getLog(ValidateInterceptor.class);
private final SAAJInInterceptor saajIn;
private final XmlParser xmlParser;
private boolean schemaValidationEnabled;
public ValidateInterceptor() {
super(Phase.PRE_PROTOCOL);
saajIn = new SAAJInInterceptor();
xmlParser = new XmlParser();
getAfter().add(SAAJInInterceptor.class.getName());
}
@Override
public void handleMessage(SoapMessage message) throws Fault {
try {
Node body = getMessageBody((DOMSource) getSOAPMessage(message).getSOAPPart().getContent());
if (body != null)
validate(body, message);
else
throw new XMLStreamException("Can't find the tag \"Body\"");
} catch (RuntimeException re) {
throw re;
} catch (Exception e) {
throw new Fault(e);
}
}
private Node getMessageBody(DOMSource source) throws XPathExpressionException {
Node node = source.getNode().cloneNode(true);
List<Node> nodeList = xmlParser.getNodes(node.getLastChild(), "Body");
return !nodeList.isEmpty() ? nodeList.get(0) : null;
}
private void validate(Node node, SoapMessage soapMessage) throws IOException, SAXException, XPathExpressionException {
Validator validator = getValidator(soapMessage);
validator.validate(new DOMSource(getNodeForValidate(node)));
}
private Node getNodeForValidate(Node node) throws XPathExpressionException {
if (schemaValidationEnabled && node.getLocalName().contains("packets")) {
Element element = (Element) node;
for (Node content : xmlParser.getNodes(element, "content")) {
content.getParentNode().removeChild(content);
}
return element;
}
return node;
}
private Validator getValidator(SoapMessage soapMessage) {
Service service = ServiceModelUtil.getService(soapMessage.getExchange());
Schema schema = EndpointReferenceUtils.getSchema(service.getServiceInfos().get(0), soapMessage.getExchange().getBus());
return schema.newValidator();
}
private SOAPMessage getSOAPMessage(SoapMessage smsg) {
SOAPMessage soapMessage = smsg.getContent(SOAPMessage.class);
if (soapMessage == null) {
saajIn.handleMessage(smsg);
soapMessage = smsg.getContent(SOAPMessage.class);
}
return soapMessage;
}
public void setSchemaValidationEnabled(boolean schemaValidationEnabled) {
this.schemaValidationEnabled = schemaValidationEnabled;
}
}

View File

@ -0,0 +1,50 @@
/*-
* ~~~~~~licensing~~~~~~
* system-commons
* ==========
* Copyright (C) 2020 - 2021 EmDev LLC
* ==========
* 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.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.esb.system.common.validator;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.xpath.*;
import java.util.ArrayList;
import java.util.List;
public class XmlParser {
public List<Node> getNodes(Node node, String elementName) throws XPathExpressionException {
XPath xpath = XPathFactory.newInstance().newXPath();
XPathExpression expr = xpath.compile("//*[local-name()='" + elementName + "']/child::node()");
NodeList nodeList = (NodeList) expr.evaluate(node.getOwnerDocument(), XPathConstants.NODESET);
return getNotNullNodes(nodeList);
}
private List<Node> getNotNullNodes(NodeList nodeList) {
List<Node> result = new ArrayList<>();
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if (node.getLocalName() != null) {
result.add(node);
}
}
return result;
}
}

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~~~~~~licensing~~~~~~
system-commons
==========
Copyright (C) 2020 - 2021 EmDev LLC
==========
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.
~~~~~~/licensing~~~~~~
-->
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0"
xsi:schemaLocation="
http://www.osgi.org/xmlns/blueprint/v1.0.0 https://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
">
<cm:property-placeholder persistent-id="ru.entaxy.esb" update-strategy="reload">
<cm:default-properties>
</cm:default-properties>
</cm:property-placeholder>
<bean id="artemisConnectionFactory" class="org.apache.activemq.artemis.jms.client.ActiveMQJMSConnectionFactory">
<argument index="0" value="${common.jms.url}"/>
<argument index="1" value="${common.jms.username}"/>
<argument index="2" value="${common.jms.password}"/>
</bean>
<bean id="pooledConnectionFactory" class="org.messaginghub.pooled.jms.JmsPoolConnectionFactory"
init-method="start" destroy-method="stop">
<property name="maxConnections" value="${common.jms.maxConnections}"/>
<property name="maxSessionsPerConnection"
value="${common.jms.maxSessionsPerConnection}"/>
<property name="connectionFactory" ref="artemisConnectionFactory"/>
</bean>
<service interface="javax.jms.ConnectionFactory" ref="pooledConnectionFactory"/>
</blueprint>

View File

@ -0,0 +1,20 @@
###
# ~~~~~~licensing~~~~~~
# system-commons
# ==========
# Copyright (C) 2020 - 2021 EmDev LLC
# ==========
# 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.
# ~~~~~~/licensing~~~~~~
###
output.charset=Cp1251

View File

@ -0,0 +1,201 @@
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.

View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>ru.entaxy.esb.system</groupId>
<artifactId>system-parent</artifactId>
<version>1.8.0</version>
</parent>
<artifactId>component-bean-fix</artifactId>
<version>1.8.0</version>
<packaging>bundle</packaging>
<name>CAMEL COMPONENT :: BEAN :: FIX</name>
<description>CAMEL COMPONENT :: BEAN :: FIX</description>
<dependencies>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-support</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-bean</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>license-maven-plugin</artifactId>
<executions>
<execution>
<id>update-file-header</id>
<phase>none</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,249 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT 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.camel.component.bean.fix;
import org.apache.camel.*;
import org.apache.camel.support.AsyncProcessorSupport;
import org.apache.camel.support.service.ServiceHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A {@link Processor} which converts the inbound exchange to a method
* invocation on a POJO
*/
public abstract class AbstractBeanProcessor extends AsyncProcessorSupport {
private static final Logger LOG = LoggerFactory.getLogger(AbstractBeanProcessor.class);
private final BeanHolder beanHolder;
private transient Processor processor;
private transient boolean lookupProcessorDone;
private final Object lock = new Object();
private BeanScope scope;
private String method;
private boolean shorthandMethod;
public AbstractBeanProcessor(Object pojo, BeanInfo beanInfo) {
this(new ConstantBeanHolder(pojo, beanInfo));
}
public AbstractBeanProcessor(Object pojo, CamelContext camelContext, ParameterMappingStrategy parameterMappingStrategy) {
this(pojo, new BeanInfo(camelContext, pojo.getClass(), parameterMappingStrategy));
}
public AbstractBeanProcessor(Object pojo, CamelContext camelContext) {
this(pojo, camelContext, BeanInfo.createParameterMappingStrategy(camelContext));
}
public AbstractBeanProcessor(BeanHolder beanHolder) {
this.beanHolder = beanHolder;
}
@Override
public String toString() {
return "BeanProcessor[" + beanHolder + (method != null ? "#" + method : "") + "]";
}
@Override
public boolean process(Exchange exchange, AsyncCallback callback) {
// do we have an explicit method name we always should invoke (either configured on endpoint or as a header)
String explicitMethodName = exchange.getIn().getHeader(Exchange.BEAN_METHOD_NAME, method, String.class);
Object bean;
BeanInfo beanInfo;
try {
bean = beanHolder.getBean(exchange);
// get bean info for this bean instance (to avoid thread issue)
beanInfo = beanHolder.getBeanInfo(bean);
if (beanInfo == null) {
// fallback and use old way
beanInfo = beanHolder.getBeanInfo();
}
} catch (Throwable e) {
exchange.setException(e);
callback.done(true);
return true;
}
// do we have a custom adapter for this POJO to a Processor
// but only do this if allowed
// we need to check beanHolder is Processor is support, to avoid the bean cached issue
if (allowProcessor(explicitMethodName, beanInfo)) {
Processor target = getProcessor();
if (target == null) {
// only attempt to lookup the processor once or nearly once
// allow cache by default or if the scope is singleton
boolean allowCache = scope == null || scope == BeanScope.Singleton;
if (allowCache) {
if (!lookupProcessorDone) {
synchronized (lock) {
lookupProcessorDone = true;
// so if there is a custom type converter for the bean to processor
target = exchange.getContext().getTypeConverter().tryConvertTo(Processor.class, exchange, bean);
processor = target;
}
}
} else {
// so if there is a custom type converter for the bean to processor
target = exchange.getContext().getTypeConverter().tryConvertTo(Processor.class, exchange, bean);
}
}
if (target != null) {
if (LOG.isTraceEnabled()) {
LOG.trace("Using a custom adapter as bean invocation: {}", target);
}
try {
target.process(exchange);
} catch (Throwable e) {
exchange.setException(e);
}
callback.done(true);
return true;
}
}
Message in = exchange.getIn();
// set explicit method name to invoke as a header, which is how BeanInfo can detect it
if (explicitMethodName != null) {
in.setHeader(Exchange.BEAN_METHOD_NAME, explicitMethodName);
}
MethodInvocation invocation;
try {
invocation = beanInfo.createInvocation(bean, exchange);
} catch (Throwable e) {
exchange.setException(e);
callback.done(true);
return true;
} finally {
// must remove headers as they were provisional
if (explicitMethodName != null) {
in.removeHeader(Exchange.BEAN_METHOD_NAME);
}
}
if (invocation == null) {
exchange.setException(new IllegalStateException("No method invocation could be created, no matching method could be found on: " + bean));
callback.done(true);
return true;
}
// invoke invocation
return invocation.proceed(callback);
}
protected Processor getProcessor() {
return processor;
}
protected BeanHolder getBeanHolder() {
return this.beanHolder;
}
public Object getBean() {
return beanHolder.getBean(null);
}
// Properties
// -----------------------------------------------------------------------
public String getMethod() {
return method;
}
public BeanScope getScope() {
return scope;
}
public void setScope(BeanScope scope) {
this.scope = scope;
}
/**
* Sets the method name to use
*/
public void setMethod(String method) {
this.method = method;
}
public boolean isShorthandMethod() {
return shorthandMethod;
}
/**
* Sets whether to support getter style method name, so you can
* say the method is called 'name' but it will invoke the 'getName' method.
* <p/>
* Is by default turned off.
*/
public void setShorthandMethod(boolean shorthandMethod) {
this.shorthandMethod = shorthandMethod;
}
// Implementation methods
//-------------------------------------------------------------------------
@Override
protected void doStart() throws Exception {
// optimize to only get (create) a processor if really needed
if (beanHolder.supportProcessor() && allowProcessor(method, beanHolder.getBeanInfo())) {
processor = beanHolder.getProcessor();
ServiceHelper.startService(processor);
} else if (beanHolder instanceof ConstantBeanHolder) {
try {
// Start the bean if it implements Service interface and if cached
// so meant to be reused
ServiceHelper.startService(beanHolder.getBean(null));
} catch (NoSuchBeanException e) {
// ignore
}
}
}
@Override
protected void doStop() throws Exception {
if (processor != null) {
ServiceHelper.stopService(processor);
} else if (beanHolder instanceof ConstantBeanHolder) {
try {
// Stop the bean if it implements Service interface and if cached
// so meant to be reused
ServiceHelper.stopService(beanHolder.getBean(null));
} catch (NoSuchBeanException e) {
// ignore
}
}
}
private boolean allowProcessor(String explicitMethodName, BeanInfo info) {
if (explicitMethodName != null) {
// don't allow if explicit method name is given, as we then must invoke this method
return false;
}
// don't allow if any of the methods has a @Handler annotation
// as the @Handler annotation takes precedence and is supposed to trigger invocation
// of the given method
if (info.hasAnyMethodHandlerAnnotation()) {
return false;
}
// fallback and allow using the processor
return true;
}
}

View File

@ -0,0 +1,321 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT 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.camel.component.bean.fix;
import org.apache.camel.*;
import org.apache.camel.support.DefaultExchange;
import org.apache.camel.util.ObjectHelper;
import org.apache.camel.util.StringHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
public abstract class AbstractCamelInvocationHandler implements InvocationHandler {
private static final Logger LOG = LoggerFactory.getLogger(CamelInvocationHandler.class);
private static final List<Method> EXCLUDED_METHODS = new ArrayList<>();
private static ExecutorService executorService;
protected final Endpoint endpoint;
protected final Producer producer;
static {
// exclude all java.lang.Object methods as we dont want to invoke them
EXCLUDED_METHODS.addAll(Arrays.asList(Object.class.getMethods()));
}
public AbstractCamelInvocationHandler(Endpoint endpoint, Producer producer) {
this.endpoint = endpoint;
this.producer = producer;
}
private static Object getBody(Exchange exchange, Class<?> type) throws InvalidPayloadException {
if (exchange.getMessage().getBody() != null) {
return exchange.getMessage().getMandatoryBody(type);
} else {
return null;
}
}
@Override
public final Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
if (isValidMethod(method)) {
return doInvokeProxy(proxy, method, args);
} else {
// invalid method then invoke methods on this instead
if ("toString".equals(method.getName())) {
return this.toString();
} else if ("hashCode".equals(method.getName())) {
return this.hashCode();
} else if ("equals".equals(method.getName())) {
return Boolean.FALSE;
}
return null;
}
}
public abstract Object doInvokeProxy(Object proxy, Method method, Object[] args) throws Throwable;
@SuppressWarnings("unchecked")
protected Object invokeProxy(final Method method, final ExchangePattern pattern, Object[] args, boolean binding) throws Throwable {
final Exchange exchange = new DefaultExchange(endpoint, pattern);
//Need to check if there are mutiple arguments and the parameters have no annotations for binding,
//then use the original bean invocation.
boolean canUseBinding = method.getParameterCount() == 1;
if (!canUseBinding) {
for (Parameter parameter : method.getParameters()) {
if (parameter.isAnnotationPresent(Header.class)
|| parameter.isAnnotationPresent(Headers.class)
|| parameter.isAnnotationPresent(ExchangeProperty.class)
|| parameter.isAnnotationPresent(Body.class)) {
canUseBinding = true;
}
}
}
if (binding && canUseBinding) {
// in binding mode we bind the passed in arguments (args) to the created exchange
// using the existing Camel @Body, @Header, @Headers, @ExchangeProperty annotations
// if no annotation then its bound as the message body
int index = 0;
for (Annotation[] row : method.getParameterAnnotations()) {
Object value = args[index];
if (row == null || row.length == 0) {
// assume its message body when there is no annotations
exchange.getIn().setBody(value);
} else {
for (Annotation ann : row) {
if (ann.annotationType().isAssignableFrom(Header.class)) {
Header header = (Header) ann;
String name = header.value();
exchange.getIn().setHeader(name, value);
} else if (ann.annotationType().isAssignableFrom(Headers.class)) {
Map map = exchange.getContext().getTypeConverter().tryConvertTo(Map.class, exchange, value);
if (map != null) {
exchange.getIn().getHeaders().putAll(map);
}
} else if (ann.annotationType().isAssignableFrom(ExchangeProperty.class)) {
ExchangeProperty ep = (ExchangeProperty) ann;
String name = ep.value();
exchange.setProperty(name, value);
} else if (ann.annotationType().isAssignableFrom(Body.class)) {
exchange.getIn().setBody(value);
} else {
// assume its message body when there is no annotations
exchange.getIn().setBody(value);
}
}
}
index++;
}
} else {
if (args != null) {
if (args.length == 1) {
exchange.getIn().setBody(args[0]);
} else {
exchange.getIn().setBody(args);
}
}
}
if (binding) {
LOG.trace("Binding to service interface as @Body,@Header,@ExchangeProperty detected when calling proxy method: {}", method);
} else {
LOG.trace("No binding to service interface as @Body,@Header,@ExchangeProperty not detected when calling proxy method: {}", method);
}
return doInvoke(method, exchange);
}
protected Object invokeWithBody(final Method method, Object body, final ExchangePattern pattern) throws Throwable {
final Exchange exchange = new DefaultExchange(endpoint, pattern);
exchange.getIn().setBody(body);
return doInvoke(method, exchange);
}
protected Object doInvoke(final Method method, final Exchange exchange) throws Throwable {
// is the return type a future
final boolean isFuture = method.getReturnType() == Future.class;
// create task to execute the proxy and gather the reply
FutureTask<Object> task = new FutureTask<>(new Callable<Object>() {
public Object call() throws Exception {
// process the exchange
LOG.trace("Proxied method call {} invoking producer: {}", method.getName(), producer);
producer.process(exchange);
Object answer = afterInvoke(method, exchange, exchange.getPattern(), isFuture);
LOG.trace("Proxied method call {} returning: {}", method.getName(), answer);
return answer;
}
});
if (isFuture) {
// submit task and return future
if (LOG.isTraceEnabled()) {
LOG.trace("Submitting task for exchange id {}", exchange.getExchangeId());
}
getExecutorService(exchange.getContext()).submit(task);
return task;
} else {
// execute task now
try {
task.run();
return task.get();
} catch (ExecutionException e) {
// we don't want the wrapped exception from JDK
throw e.getCause();
}
}
}
protected Object afterInvoke(Method method, Exchange exchange, ExchangePattern pattern, boolean isFuture) throws Exception {
// check if we had an exception
Throwable cause = exchange.getException();
if (cause != null) {
Throwable found = findSuitableException(cause, method);
if (found != null) {
if (found instanceof Exception) {
throw (Exception) found;
} else {
// wrap as exception
throw new CamelExchangeException("Error processing exchange", exchange, cause);
}
}
// special for runtime camel exceptions as they can be nested
if (cause instanceof RuntimeCamelException) {
// if the inner cause is a runtime exception we can throw it
// directly
if (cause.getCause() instanceof RuntimeException) {
throw (RuntimeException) ((RuntimeCamelException) cause).getCause();
}
throw (RuntimeCamelException) cause;
}
// okay just throw the exception as is
if (cause instanceof Exception) {
throw (Exception) cause;
} else {
// wrap as exception
throw new CamelExchangeException("Error processing exchange", exchange, cause);
}
}
Class<?> to = isFuture ? getGenericType(exchange.getContext(), method.getGenericReturnType()) : method.getReturnType();
// do not return a reply if the method is VOID
if (to == Void.TYPE) {
return null;
}
return getBody(exchange, to);
}
protected static Class<?> getGenericType(CamelContext context, Type type) throws ClassNotFoundException {
if (type == null) {
// fallback and use object
return Object.class;
}
// unfortunately java dont provide a nice api for getting the generic
// type of the return type
// due type erasure, so we have to gather it based on a String
// representation
String name = StringHelper.between(type.toString(), "<", ">");
if (name != null) {
if (name.contains("<")) {
// we only need the outer type
name = StringHelper.before(name, "<");
}
return context.getClassResolver().resolveMandatoryClass(name);
} else {
// fallback and use object
return Object.class;
}
}
protected static synchronized ExecutorService getExecutorService(CamelContext context) {
// CamelContext will shutdown thread pool when it shutdown so we can
// lazy create it on demand
// but in case of hot-deploy or the likes we need to be able to
// re-create it (its a shared static instance)
if (executorService == null || executorService.isTerminated() || executorService.isShutdown()) {
// try to lookup a pool first based on id/profile
executorService = context.getRegistry().lookupByNameAndType("CamelInvocationHandler", ExecutorService.class);
if (executorService == null) {
executorService = context.getExecutorServiceManager().newThreadPool(CamelInvocationHandler.class, "CamelInvocationHandler", "CamelInvocationHandler");
}
if (executorService == null) {
executorService = context.getExecutorServiceManager().newDefaultThreadPool(CamelInvocationHandler.class, "CamelInvocationHandler");
}
}
return executorService;
}
/**
* Tries to find the best suited exception to throw.
* <p/>
* It looks in the exception hierarchy from the caused exception and matches
* this against the declared exceptions being thrown on the method.
*
* @param cause the caused exception
* @param method the method
* @return the exception to throw, or <tt>null</tt> if not possible to find
* a suitable exception
*/
protected Throwable findSuitableException(Throwable cause, Method method) {
if (method.getExceptionTypes() == null || method.getExceptionTypes().length == 0) {
return null;
}
// see if there is any exception which matches the declared exception on
// the method
for (Class<?> type : method.getExceptionTypes()) {
Object fault = ObjectHelper.getException(type, cause);
if (fault != null) {
return Throwable.class.cast(fault);
}
}
return null;
}
protected boolean isValidMethod(Method method) {
// must not be in the excluded list
for (Method excluded : EXCLUDED_METHODS) {
if (ObjectHelper.isOverridingMethod(excluded, method)) {
// the method is overriding an excluded method so its not valid
return false;
}
}
return true;
}
}

View File

@ -0,0 +1,43 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.bean.fix;
import org.apache.camel.Exchange;
import org.apache.camel.RuntimeExchangeException;
import java.util.Collection;
/**
* An exception thrown if an attempted method invocation resulted in an ambiguous method
* such that multiple methods match the inbound message exchange
*/
public class AmbiguousMethodCallException extends RuntimeExchangeException {
private final Collection<MethodInfo> methods;
public AmbiguousMethodCallException(Exchange exchange, Collection<MethodInfo> methods) {
super("Ambiguous method invocations possible: " + methods, exchange);
this.methods = methods;
}
/**
* The ambiguous methods for which a single method could not be chosen
*/
public Collection<MethodInfo> getMethods() {
return methods;
}
}

View File

@ -0,0 +1,67 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.bean.fix;
import org.apache.camel.CamelContext;
import org.apache.camel.Expression;
import org.apache.camel.spi.Language;
import org.apache.camel.support.ObjectHelper;
import org.apache.camel.support.language.DefaultAnnotationExpressionFactory;
import org.apache.camel.support.language.LanguageAnnotation;
import org.apache.camel.util.StringHelper;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
public class BeanAnnotationExpressionFactory extends DefaultAnnotationExpressionFactory {
@Override
public Expression createExpression(CamelContext camelContext, Annotation annotation, LanguageAnnotation languageAnnotation, Class<?> expressionReturnType) {
String beanName = getFromAnnotation(annotation, "ref");
String method = getFromAnnotation(annotation, "method");
// ref is mandatory
StringHelper.notEmpty(beanName, "ref", annotation);
// method is optional but provide it as null to the bean expression
if (org.apache.camel.util.ObjectHelper.isEmpty(method)) {
method = null;
}
Language lan = camelContext.resolveLanguage("bean");
if (method != null) {
return lan.createExpression(beanName + "?method=" + method);
} else {
return lan.createExpression(beanName);
}
}
protected String getFromAnnotation(Annotation annotation, String attribute) {
try {
Method method = annotation.getClass().getMethod(attribute);
Object value = ObjectHelper.invokeMethod(method, annotation);
if (value == null) {
throw new IllegalArgumentException("Cannot determine the " + attribute + " from the annotation: " + annotation);
}
return value.toString();
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Cannot determine the " + attribute
+ " of the annotation: " + annotation + " as it does not have a " + attribute + "() method");
}
}
}

View File

@ -0,0 +1,117 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.bean.fix;
import org.apache.camel.BeanScope;
import org.apache.camel.Endpoint;
import org.apache.camel.spi.Metadata;
import org.apache.camel.support.DefaultComponent;
import org.apache.camel.support.LRUCache;
import org.apache.camel.support.LRUCacheFactory;
import org.apache.camel.util.PropertiesHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
/**
* The bean component is for invoking Java beans from Camel.
*/
@org.apache.camel.spi.annotations.Component("bean-fix")
public class BeanComponent extends DefaultComponent {
private static final Logger LOG = LoggerFactory.getLogger(BeanComponent.class);
// use an internal soft cache for BeanInfo as they are costly to introspect
// for example the bean language using OGNL expression runs much faster reusing the BeanInfo from this cache
@SuppressWarnings("unchecked")
private final Map<BeanInfoCacheKey, BeanInfo> beanInfoCache = LRUCacheFactory.newLRUSoftCache(1000);
@Deprecated
@Metadata(defaultValue = "true", description = "Use singleton option instead.")
private Boolean cache;
@Metadata(defaultValue = "Singleton", description = "Scope of bean."
+ " When using singleton scope (default) the bean is created or looked up only once and reused for the lifetime of the endpoint."
+ " The bean should be thread-safe in case concurrent threads is calling the bean at the same time."
+ " When using request scope the bean is created or looked up once per request (exchange). This can be used if you want to store state on a bean"
+ " while processing a request and you want to call the same bean instance multiple times while processing the request."
+ " The bean does not have to be thread-safe as the instance is only called from the same request."
+ " When using delegate scope, then the bean will be looked up or created per call. However in case of lookup then this is delegated "
+ " to the bean registry such as Spring or CDI (if in use), which depends on their configuration can act as either singleton or prototype scope."
+ " so when using prototype then this depends on the delegated registry.")
private BeanScope scope = BeanScope.Singleton;
public BeanComponent() {
}
// Implementation methods
//-----------------------------------------------------------------------
@Override
protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
BeanEndpoint endpoint = new BeanEndpoint(uri, this);
endpoint.setBeanName(remaining);
if (cache != null) {
endpoint.setCache(cache);
}
endpoint.setScope(scope);
setProperties(endpoint, parameters);
// the bean.xxx options is for the bean
Map<String, Object> options = PropertiesHelper.extractProperties(parameters, "bean.");
endpoint.setParameters(options);
return endpoint;
}
BeanInfo getBeanInfoFromCache(BeanInfoCacheKey key) {
return beanInfoCache.get(key);
}
void addBeanInfoToCache(BeanInfoCacheKey key, BeanInfo beanInfo) {
beanInfoCache.put(key, beanInfo);
}
@Override
protected void doShutdown() throws Exception {
if (LOG.isDebugEnabled() && beanInfoCache instanceof LRUCache) {
LRUCache cache = (LRUCache) this.beanInfoCache;
LOG.debug("Clearing BeanInfo cache[size={}, hits={}, misses={}, evicted={}]", cache.size(), cache.getHits(), cache.getMisses(), cache.getEvicted());
}
beanInfoCache.clear();
}
@Deprecated
public Boolean getCache() {
return scope == BeanScope.Singleton;
}
@Deprecated
public void setCache(Boolean cache) {
if (cache) {
scope = BeanScope.Singleton;
} else {
scope = BeanScope.Prototype;
}
}
public BeanScope getScope() {
return scope;
}
public void setScope(BeanScope scope) {
this.scope = scope;
}
}

View File

@ -0,0 +1,26 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.bean.fix;
public final class BeanConstants {
public static final String BEAN_PARAMETER_MAPPING_STRATEGY = "CamelBeanParameterMappingStrategy";
private BeanConstants() {
// Utility class
}
}

View File

@ -0,0 +1,185 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT 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.camel.component.bean.fix;
import org.apache.camel.*;
import org.apache.camel.spi.Metadata;
import org.apache.camel.spi.UriEndpoint;
import org.apache.camel.spi.UriParam;
import org.apache.camel.spi.UriPath;
import org.apache.camel.support.DefaultEndpoint;
import java.util.Map;
/**
* Invoke methods of Java beans stored in Camel registry.
*/
@UriEndpoint(firstVersion = "1.0.0", scheme = "bean", title = "Bean", syntax = "bean:beanName", producerOnly = true, category = {Category.CORE, Category.JAVA})
public class BeanEndpoint extends DefaultEndpoint {
private transient BeanHolder beanHolder;
private transient BeanProcessor processor;
@UriPath(label = "common", description = "Sets the name of the bean to invoke")
@Metadata(required = true)
private String beanName;
@UriParam(label = "common", description = "Sets the name of the method to invoke on the bean")
private String method;
@Deprecated
@UriParam(label = "common", description = "Use scope option instead.")
private Boolean cache;
@UriParam(label = "common", defaultValue = "Singleton", description = "Scope of bean."
+ " When using singleton scope (default) the bean is created or looked up only once and reused for the lifetime of the endpoint."
+ " The bean should be thread-safe in case concurrent threads is calling the bean at the same time."
+ " When using request scope the bean is created or looked up once per request (exchange). This can be used if you want to store state on a bean"
+ " while processing a request and you want to call the same bean instance multiple times while processing the request."
+ " The bean does not have to be thread-safe as the instance is only called from the same request."
+ " When using prototype scope, then the bean will be looked up or created per call. However in case of lookup then this is delegated "
+ " to the bean registry such as Spring or CDI (if in use), which depends on their configuration can act as either singleton or prototype scope."
+ " so when using prototype then this depends on the delegated registry.")
private BeanScope scope = BeanScope.Singleton;
@UriParam(prefix = "bean.", label = "advanced", description = "Used for configuring additional properties on the bean", multiValue = true)
private Map<String, Object> parameters;
public BeanEndpoint() {
setExchangePattern(ExchangePattern.InOut);
}
public BeanEndpoint(String endpointUri, Component component, BeanProcessor processor) {
super(endpointUri, component);
this.processor = processor;
setExchangePattern(ExchangePattern.InOut);
}
public BeanEndpoint(String endpointUri, Component component) {
super(endpointUri, component);
setExchangePattern(ExchangePattern.InOut);
}
@Override
public Producer createProducer() throws Exception {
return new BeanProducer(this, processor);
}
@Override
public Consumer createConsumer(Processor processor) throws Exception {
throw new UnsupportedOperationException("You cannot consume from a bean endpoint");
}
public BeanProcessor getProcessor() {
return processor;
}
@Override
protected void doInit() throws Exception {
super.doInit();
if (processor == null) {
BeanHolder holder = getBeanHolder();
if (holder == null) {
RegistryBean registryBean = new RegistryBean(getCamelContext(), beanName);
if (scope == BeanScope.Singleton) {
// if singleton then create a cached holder that use the same singleton instance
holder = registryBean.createCacheHolder();
} else {
holder = registryBean;
}
}
if (scope == BeanScope.Request) {
// wrap in registry scoped
holder = new RequestBeanHolder(holder);
}
processor = new BeanProcessor(holder);
if (method != null) {
processor.setMethod(method);
}
processor.setScope(scope);
if (parameters != null) {
holder.setOptions(parameters);
}
}
}
@Override
protected void doStop() throws Exception {
super.doStop();
// noop
}
// Properties
//-------------------------------------------------------------------------
public String getBeanName() {
return beanName;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
@Deprecated
public Boolean getCache() {
return scope == BeanScope.Singleton;
}
@Deprecated
public void setCache(Boolean cache) {
if (cache) {
scope = BeanScope.Singleton;
} else {
scope = BeanScope.Prototype;
}
}
public BeanScope getScope() {
return scope;
}
public void setScope(BeanScope scope) {
this.scope = scope;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public BeanHolder getBeanHolder() {
return beanHolder;
}
public void setBeanHolder(BeanHolder beanHolder) {
this.beanHolder = beanHolder;
}
public Map<String, Object> getParameters() {
return parameters;
}
public void setParameters(Map<String, Object> parameters) {
this.parameters = parameters;
}
// Implementation methods
//-------------------------------------------------------------------------
@Override
protected String createEndpointUri() {
return "bean:" + getBeanName() + (method != null ? "?method=" + method : "");
}
}

View File

@ -0,0 +1,28 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.bean.fix;
/**
* A bean processor that is optimised for being invoked one time from an {@link org.apache.camel.language.bean.BeanExpression}.
* Where as {@link BeanProcessor} is a bean that is a {@link org.apache.camel.Service} and intended for long lifecycle.
*/
public class BeanExpressionProcessor extends AbstractBeanProcessor {
public BeanExpressionProcessor(BeanHolder beanHolder) {
super(beanHolder);
}
}

View File

@ -0,0 +1,136 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT 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.camel.component.bean.fix;
import org.apache.camel.spi.ClassResolver;
import org.apache.camel.util.ObjectHelper;
import org.apache.camel.util.StringHelper;
/**
* Helper for the bean component.
*/
public final class BeanHelper {
private BeanHelper() {
// utility class
}
/**
* Determines and maps the given value is valid according to the supported
* values by the bean component.
*
* @param value the value
* @return the parameter type the given value is being mapped as, or <tt>null</tt> if not valid.
*/
public static Class<?> getValidParameterType(String value) {
if (ObjectHelper.isEmpty(value)) {
return null;
}
// trim value
value = value.trim();
// single quoted is valid
if (value.startsWith("'") && value.endsWith("'")) {
return String.class;
}
// double quoted is valid
if (value.startsWith("\"") && value.endsWith("\"")) {
return String.class;
}
// true or false is valid (boolean)
if (value.equals("true") || value.equals("false")) {
return Boolean.class;
}
// null is valid (to force a null value)
if (value.equals("null")) {
return Object.class;
}
// simple language tokens is valid
if (StringHelper.hasStartToken(value, "simple")) {
return Object.class;
}
// numeric is valid
boolean numeric = true;
for (char ch : value.toCharArray()) {
if (!Character.isDigit(ch)) {
numeric = false;
break;
}
}
if (numeric) {
return Number.class;
}
// not valid
return null;
}
/**
* Determines if the given value is valid according to the supported
* values by the bean component.
*
* @param value the value
* @return <tt>true</tt> if valid, <tt>false</tt> otherwise
*/
public static boolean isValidParameterValue(String value) {
if (ObjectHelper.isEmpty(value)) {
// empty value is valid
return true;
}
return getValidParameterType(value) != null;
}
/**
* Determines if the given parameter type is assignable to the expected type.
* <p/>
* This implementation will check if the given parameter type matches the expected type as class using either
* <ul>
* <li>FQN class name - com.foo.MyOrder</li>
* <li>Simple class name - MyOrder</li>
* </ul>
* If the given parameter type is <b>not</b> a class, then <tt>null</tt> is returned
*
* @param resolver the class resolver
* @param parameterType the parameter type as a String, can be a FQN or a simple name of the class
* @param expectedType the expected type
* @return <tt>null</tt> if parameter type is <b>not</b> a class, <tt>true</tt> if parameter type is assignable, <tt>false</tt> if not assignable
*/
public static Boolean isAssignableToExpectedType(ClassResolver resolver, String parameterType, Class<?> expectedType) {
// if its a class, then it should be assignable
Class<?> parameterClass = resolver.resolveClass(parameterType);
if (parameterClass == null && parameterType.equals(expectedType.getSimpleName())) {
// it was not the FQN class name, but the simple name instead, which matched
return true;
}
// not a class so return null
if (parameterClass == null) {
return null;
}
// if there was a class, then it must be assignable to match
return parameterClass.isAssignableFrom(expectedType);
}
}

View File

@ -0,0 +1,76 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.bean.fix;
import org.apache.camel.Exchange;
import org.apache.camel.NoSuchBeanException;
import org.apache.camel.Processor;
import java.util.Map;
/**
* Object holder for a bean.
*/
public interface BeanHolder {
/**
* Additional options that should be configured on the bean
*/
Map<String, Object> getOptions();
/**
* Sets additional options that should be configured on the bean
*/
void setOptions(Map<String, Object> options);
/**
* Gets the bean.
*
* @throws NoSuchBeanException is thrown if the bean cannot be found.
*/
Object getBean(Exchange exchange) throws NoSuchBeanException;
/**
* Gets a {@link Processor} for this bean, if supported.
*
* @return the {@link Processor}, or <tt>null</tt> if not supported.
*/
Processor getProcessor();
/**
* Whether a {@link Processor} is supported by this bean holder.
*
* @return <tt>true</tt> if the holder can supporting using a processor, <tt>false</tt> otherwise
*/
boolean supportProcessor();
/**
* Gets bean info for the bean.
*/
BeanInfo getBeanInfo();
/**
* Gets bean info for the given bean.
* <p/>
* This implementation allows a thread safe usage for {@link BeanHolder} implementations
* such as the {@link RegistryBean}.
*
* @param bean the bean
* @return <tt>null</tt> if not supported, then use {@link #getBeanInfo()} instead.
*/
BeanInfo getBeanInfo(Object bean);
}

View File

@ -0,0 +1,61 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.bean.fix;
import java.lang.reflect.Method;
/**
* A key used for caching {@link BeanInfo} by the {@link BeanComponent}
*/
public final class BeanInfoCacheKey {
private final Class<?> type;
private final Method explicitMethod;
public BeanInfoCacheKey(Class<?> type, Method explicitMethod) {
this.type = type;
this.explicitMethod = explicitMethod;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
BeanInfoCacheKey that = (BeanInfoCacheKey) o;
if (explicitMethod != null ? !explicitMethod.equals(that.explicitMethod) : that.explicitMethod != null) {
return false;
}
if (!type.equals(that.type)) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = type.hashCode();
result = 31 * result + (explicitMethod != null ? explicitMethod.hashCode() : 0);
return result;
}
}

View File

@ -0,0 +1,129 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.bean.fix;
import org.apache.camel.*;
import org.apache.camel.support.service.ServiceSupport;
import java.util.concurrent.CompletableFuture;
public class BeanProcessor extends ServiceSupport implements AsyncProcessor {
private final DelegateBeanProcessor delegate;
public BeanProcessor(Object pojo, BeanInfo beanInfo) {
this.delegate = new DelegateBeanProcessor(pojo, beanInfo);
}
public BeanProcessor(Object pojo, CamelContext camelContext, ParameterMappingStrategy parameterMappingStrategy) {
this.delegate = new DelegateBeanProcessor(pojo, camelContext, parameterMappingStrategy);
}
public BeanProcessor(Object pojo, CamelContext camelContext) {
this.delegate = new DelegateBeanProcessor(pojo, camelContext);
}
public BeanProcessor(BeanHolder beanHolder) {
this.delegate = new DelegateBeanProcessor(beanHolder);
}
@Override
public void process(Exchange exchange) throws Exception {
delegate.process(exchange);
}
@Override
public boolean process(Exchange exchange, AsyncCallback callback) {
return delegate.process(exchange, callback);
}
@Override
public CompletableFuture<Exchange> processAsync(Exchange exchange) {
return delegate.processAsync(exchange);
}
public Processor getProcessor() {
return delegate.getProcessor();
}
public BeanHolder getBeanHolder() {
return delegate.getBeanHolder();
}
public Object getBean() {
return delegate.getBean();
}
public String getMethod() {
return delegate.getMethod();
}
public void setMethod(String method) {
delegate.setMethod(method);
}
public BeanScope getScope() {
return delegate.getScope();
}
public void setScope(BeanScope scope) {
delegate.setScope(scope);
}
public boolean isShorthandMethod() {
return delegate.isShorthandMethod();
}
public void setShorthandMethod(boolean shorthandMethod) {
delegate.setShorthandMethod(shorthandMethod);
}
@Override
protected void doStart() throws Exception {
delegate.doStart();
}
@Override
protected void doStop() throws Exception {
delegate.doStop();
}
@Override
public String toString() {
return delegate.toString();
}
private static final class DelegateBeanProcessor extends AbstractBeanProcessor {
public DelegateBeanProcessor(Object pojo, BeanInfo beanInfo) {
super(pojo, beanInfo);
}
public DelegateBeanProcessor(Object pojo, CamelContext camelContext, ParameterMappingStrategy parameterMappingStrategy) {
super(pojo, camelContext, parameterMappingStrategy);
}
public DelegateBeanProcessor(Object pojo, CamelContext camelContext) {
super(pojo, camelContext);
}
public DelegateBeanProcessor(BeanHolder beanHolder) {
super(beanHolder);
}
}
}

View File

@ -0,0 +1,73 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.bean.fix;
import org.apache.camel.AsyncCallback;
import org.apache.camel.Exchange;
import org.apache.camel.NoSuchBeanException;
import org.apache.camel.support.DefaultAsyncProducer;
import org.apache.camel.support.service.ServiceHelper;
/**
* Bean {@link org.apache.camel.Producer}
*/
public class BeanProducer extends DefaultAsyncProducer {
private final BeanProcessor processor;
private boolean beanStarted;
public BeanProducer(BeanEndpoint endpoint, BeanProcessor processor) {
super(endpoint);
this.processor = processor;
this.beanStarted = false;
}
@Override
public boolean process(Exchange exchange, AsyncCallback callback) {
return processor.process(exchange, callback);
}
@Override
protected void doStart() throws Exception {
super.doStart();
if (processor.getBeanHolder() instanceof ConstantBeanHolder) {
try {
// Start the bean if it implements Service interface and if cached
// so meant to be reused
ServiceHelper.startService(processor.getBean());
beanStarted = true;
} catch (NoSuchBeanException e) {
}
}
}
@Override
protected void doStop() throws Exception {
if (beanStarted) {
try {
// Stop the bean if it implements Service interface and if cached
// so meant to be reused
ServiceHelper.stopService(processor.getBean());
beanStarted = false;
} catch (NoSuchBeanException e) {
}
}
super.doStop();
}
}

View File

@ -0,0 +1,26 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.bean.fix;
/**
* Object holder for a bean type.
*/
public interface BeanTypeHolder extends BeanHolder {
Class<?> getType();
}

View File

@ -0,0 +1,47 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.bean.fix;
import org.apache.camel.Endpoint;
import org.apache.camel.ExchangePattern;
import org.apache.camel.Producer;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* An {@link java.lang.reflect.InvocationHandler} which invokes a message
* exchange on a camel {@link Endpoint}
*/
public class CamelInvocationHandler extends AbstractCamelInvocationHandler implements InvocationHandler {
private final MethodInfoCache methodInfoCache;
private final boolean binding;
public CamelInvocationHandler(Endpoint endpoint, boolean binding, Producer producer, MethodInfoCache methodInfoCache) {
super(endpoint, producer);
this.binding = binding;
this.methodInfoCache = methodInfoCache;
}
@Override
public Object doInvokeProxy(Object proxy, Method method, Object[] args) throws Throwable {
MethodInfo methodInfo = methodInfoCache.getMethodInfo(method);
final ExchangePattern pattern = methodInfo != null ? methodInfo.getPattern() : ExchangePattern.InOut;
return invokeProxy(method, pattern, args, binding);
}
}

View File

@ -0,0 +1,105 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.bean.fix;
import org.apache.camel.CamelContext;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.support.CamelContextHelper;
import org.apache.camel.support.PropertyBindingSupport;
import org.apache.camel.util.ObjectHelper;
import java.util.Map;
/**
* A constant (singleton) bean implementation of {@link org.apache.camel.component.bean.BeanHolder}
*/
public class ConstantBeanHolder implements BeanHolder {
private final Object bean;
private final BeanInfo beanInfo;
private Processor processor;
private Map<String, Object> options;
public ConstantBeanHolder(Object bean, BeanInfo beanInfo) {
ObjectHelper.notNull(bean, "bean");
ObjectHelper.notNull(beanInfo, "beanInfo");
this.bean = bean;
this.beanInfo = beanInfo;
}
public ConstantBeanHolder(Object bean, CamelContext context) {
ObjectHelper.notNull(bean, "bean");
this.bean = bean;
this.beanInfo = new BeanInfo(context, bean.getClass());
}
@Override
public Map<String, Object> getOptions() {
return options;
}
@Override
public void setOptions(Map<String, Object> options) {
this.options = options;
// since its a constant we can set the options immediately on the bean
if (options != null && !options.isEmpty()) {
PropertyBindingSupport.build()
.withRemoveParameters(false)
.withCamelContext(getBeanInfo().getCamelContext())
.withProperties(options)
.withTarget(bean)
.bind();
}
}
@Override
public String toString() {
// avoid invoke toString on bean as it may be a remote proxy
return ObjectHelper.className(bean) + "(" + ObjectHelper.getIdentityHashCode(bean) + ")";
}
@Override
public Object getBean(Exchange exchange) {
return bean;
}
@Override
public Processor getProcessor() {
if (this.processor == null) {
this.processor = CamelContextHelper.convertTo(beanInfo.getCamelContext(), Processor.class, bean);
}
return this.processor;
}
@Override
public boolean supportProcessor() {
return true;
}
@Override
public BeanInfo getBeanInfo() {
return beanInfo;
}
@Override
public BeanInfo getBeanInfo(Object bean) {
return null;
}
}

View File

@ -0,0 +1,37 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.bean.fix;
import org.apache.camel.CamelContext;
import org.apache.camel.Exchange;
/**
* A constant {@link org.apache.camel.component.bean.BeanHolder} for a class or static class
* where the intention is to only invoke static methods, without the need for creating an instance of the type.
*/
public class ConstantStaticTypeBeanHolder extends ConstantTypeBeanHolder {
public ConstantStaticTypeBeanHolder(Class<?> type, CamelContext context) {
super(type, context);
}
@Override
public Object getBean(Exchange exchange) {
// we cannot create a bean as there is no default constructor
return null;
}
}

View File

@ -0,0 +1,116 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.bean.fix;
import org.apache.camel.CamelContext;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.support.PropertyBindingSupport;
import org.apache.camel.util.ObjectHelper;
import java.util.Map;
/**
* A constant (singleton) bean implementation of {@link org.apache.camel.component.bean.BeanTypeHolder}
*/
public class ConstantTypeBeanHolder implements BeanTypeHolder {
private final Class<?> type;
private final BeanInfo beanInfo;
private Map<String, Object> options;
public ConstantTypeBeanHolder(Class<?> type, CamelContext context) {
this(type, new BeanInfo(context, type));
}
public ConstantTypeBeanHolder(Class<?> type, BeanInfo beanInfo) {
ObjectHelper.notNull(type, "type");
ObjectHelper.notNull(beanInfo, "beanInfo");
this.type = type;
this.beanInfo = beanInfo;
}
@Override
public Map<String, Object> getOptions() {
return options;
}
@Override
public void setOptions(Map<String, Object> options) {
this.options = options;
}
/**
* Creates a cached and constant {@link org.apache.camel.component.bean.BeanHolder} from this holder.
*
* @return a new {@link org.apache.camel.component.bean.BeanHolder} that has cached the lookup of the bean.
*/
public ConstantBeanHolder createCacheHolder() throws Exception {
Object bean = getBean(null);
return new ConstantBeanHolder(bean, beanInfo);
}
@Override
public String toString() {
return type.toString();
}
@Override
public Object getBean(Exchange exchange) {
// only create a bean if we have a default no-arg constructor
if (beanInfo.hasPublicNoArgConstructors()) {
Object bean = getBeanInfo().getCamelContext().getInjector().newInstance(type, false);
if (options != null && !options.isEmpty()) {
PropertyBindingSupport.build()
.withRemoveParameters(false)
.withCamelContext(getBeanInfo().getCamelContext())
.withProperties(options)
.withTarget(bean)
.bind();
}
return bean;
} else {
return null;
}
}
@Override
public Processor getProcessor() {
return null;
}
@Override
public boolean supportProcessor() {
return false;
}
@Override
public BeanInfo getBeanInfo() {
return beanInfo;
}
@Override
public BeanInfo getBeanInfo(Object bean) {
return null;
}
@Override
public Class<?> getType() {
return type;
}
}

View File

@ -0,0 +1,159 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.bean.fix;
import org.apache.camel.BeanScope;
import org.apache.camel.CamelContext;
import org.apache.camel.Processor;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.spi.BeanProcessorFactory;
import org.apache.camel.spi.annotations.JdkService;
import org.apache.camel.support.CamelContextHelper;
import org.apache.camel.util.ObjectHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Method;
@JdkService(BeanProcessorFactory.FACTORY)
public final class DefaultBeanProcessorFactory implements BeanProcessorFactory {
private static final Logger LOG = LoggerFactory.getLogger(DefaultBeanProcessorFactory.class);
public DefaultBeanProcessorFactory() {
}
@Override
public Processor createBeanProcessor(CamelContext camelContext, Object bean, Method method) throws Exception {
BeanInfo info = new BeanInfo(camelContext, method);
return new BeanProcessor(bean, info);
}
@Override
public Processor createBeanProcessor(CamelContext camelContext, Object bean, String beanType, Class<?> beanClass, String ref,
String method, BeanScope scope) throws Exception {
BeanProcessor answer;
Class<?> clazz = bean != null ? bean.getClass() : null;
BeanHolder beanHolder;
if (ObjectHelper.isNotEmpty(ref)) {
if (scope == BeanScope.Singleton) {
// cache the registry lookup which avoids repeat lookup in the registry
beanHolder = new RegistryBean(camelContext, ref).createCacheHolder();
// bean holder will check if the bean exists
bean = beanHolder.getBean(null);
} else {
// we do not cache so we invoke on-demand
beanHolder = new RegistryBean(camelContext, ref);
}
if (scope == BeanScope.Request) {
// wrap in registry scoped holder
beanHolder = new RequestBeanHolder(beanHolder);
}
answer = new BeanProcessor(beanHolder);
} else {
if (bean == null) {
if (beanType == null && beanClass == null) {
throw new IllegalArgumentException("bean, ref or beanType must be provided");
}
// the clazz is either from beanType or beanClass
if (beanType != null) {
try {
clazz = camelContext.getClassResolver().resolveMandatoryClass(beanType);
} catch (ClassNotFoundException e) {
throw RuntimeCamelException.wrapRuntimeCamelException(e);
}
} else {
clazz = beanClass;
}
// attempt to create bean using injector which supports auto-wiring
if (scope == BeanScope.Singleton && camelContext.getInjector().supportsAutoWiring()) {
try {
LOG.debug("Attempting to create new bean instance from class: {} via auto-wiring enabled", clazz);
bean = CamelContextHelper.newInstance(camelContext, clazz);
} catch (Throwable e) {
LOG.debug("Error creating new bean instance from class: " + clazz + ". This exception is ignored", e);
}
}
// create a bean if there is a default public no-arg constructor
if (bean == null && scope == BeanScope.Singleton && ObjectHelper.hasDefaultPublicNoArgConstructor(clazz)) {
LOG.debug("Class has default no-arg constructor so creating a new bean instance: {}", clazz);
bean = CamelContextHelper.newInstance(camelContext, clazz);
ObjectHelper.notNull(bean, "bean", this);
}
}
// validate the bean type is not from java so you by mistake think its a reference
// to a bean name but the String is being invoke instead
if (bean instanceof String) {
throw new IllegalArgumentException("The bean instance is a java.lang.String type: " + bean
+ ". We suppose you want to refer to a bean instance by its id instead. Please use ref.");
}
// the holder should either be bean or type based
if (bean != null) {
beanHolder = new ConstantBeanHolder(bean, camelContext);
} else {
if (scope == BeanScope.Singleton && ObjectHelper.hasDefaultPublicNoArgConstructor(clazz)) {
// we can only cache if we can create an instance of the bean, and for that we need a public constructor
beanHolder = new ConstantTypeBeanHolder(clazz, camelContext).createCacheHolder();
} else {
if (ObjectHelper.hasDefaultPublicNoArgConstructor(clazz)) {
beanHolder = new ConstantTypeBeanHolder(clazz, camelContext);
} else {
// this is only for invoking static methods on the bean
beanHolder = new ConstantStaticTypeBeanHolder(clazz, camelContext);
}
}
}
if (scope == BeanScope.Request) {
// wrap in registry scoped holder
beanHolder = new RequestBeanHolder(beanHolder);
}
answer = new BeanProcessor(beanHolder);
}
// check for method exists
if (method != null) {
answer.setMethod(method);
// check there is a method with the given name, and leverage BeanInfo for that
// which we only do if we are caching the bean as otherwise we will create a bean instance for this check
// which we only want to do if we cache the bean
if (scope == BeanScope.Singleton) {
BeanInfo beanInfo = beanHolder.getBeanInfo();
if (bean != null) {
// there is a bean instance, so check for any methods
if (!beanInfo.hasMethod(method)) {
throw RuntimeCamelException.wrapRuntimeCamelException(new MethodNotFoundException(null, bean, method));
}
} else if (clazz != null) {
// there is no bean instance, so check for static methods only
if (!beanInfo.hasStaticMethod(method)) {
throw RuntimeCamelException.wrapRuntimeCamelException(new MethodNotFoundException(null, clazz, method, true));
}
}
}
}
return answer;
}
}

View File

@ -0,0 +1,34 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.bean.fix;
import org.apache.camel.Endpoint;
import org.apache.camel.spi.BeanProxyFactory;
import org.apache.camel.spi.annotations.JdkService;
@JdkService(BeanProxyFactory.FACTORY)
public final class DefaultBeanProxyFactory implements BeanProxyFactory {
public DefaultBeanProxyFactory() {
}
@SafeVarargs
@Override
public final <T> T createProxy(Endpoint endpoint, boolean binding, Class<T>... interfaceClasses) throws Exception {
return ProxyHelper.createProxy(endpoint, binding, interfaceClasses);
}
}

View File

@ -0,0 +1,54 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.bean.fix;
import org.apache.camel.*;
import org.apache.camel.spi.Registry;
import org.apache.camel.support.builder.ExpressionBuilder;
import java.util.HashMap;
import java.util.Map;
/**
* Represents the strategy used to figure out how to map a message exchange to a POJO method invocation
*/
public final class DefaultParameterMappingStrategy implements ParameterMappingStrategy {
public static final DefaultParameterMappingStrategy INSTANCE = new DefaultParameterMappingStrategy();
private static final Map<Class<?>, Expression> MAP = new HashMap<>(6);
static {
MAP.put(Exchange.class, ExpressionBuilder.exchangeExpression());
MAP.put(Message.class, ExpressionBuilder.inMessageExpression());
MAP.put(Exception.class, ExpressionBuilder.exchangeExceptionExpression());
MAP.put(TypeConverter.class, ExpressionBuilder.typeConverterExpression());
MAP.put(Registry.class, ExpressionBuilder.registryExpression());
MAP.put(CamelContext.class, ExpressionBuilder.camelContextExpression());
}
;
private DefaultParameterMappingStrategy() {
}
@Override
public Expression getDefaultParameterTypeExpression(Class<?> parameterType) {
return MAP.get(parameterType);
}
}

View File

@ -0,0 +1,68 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.bean.fix;
import java.io.Serializable;
import java.lang.reflect.Method;
/**
* Represents a {@link Serializable} version of a {@link Method}
*/
public class MethodBean implements Serializable {
private static final long serialVersionUID = -789408217201706532L;
private String name;
private Class<?> type;
private Class<?>[] parameterTypes;
public MethodBean() {
}
public MethodBean(Method method) {
this.name = method.getName();
this.type = method.getDeclaringClass();
this.parameterTypes = method.getParameterTypes();
}
public Method getMethod() throws NoSuchMethodException {
return type.getMethod(name, parameterTypes);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Class<?>[] getParameterTypes() {
return parameterTypes;
}
public void setParameterTypes(Class<?>[] parameterTypes) {
this.parameterTypes = parameterTypes;
}
public Class<?> getType() {
return type;
}
public void setType(Class<?> type) {
this.type = type;
}
}

View File

@ -0,0 +1,755 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT 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.camel.component.bean.fix;
import org.apache.camel.*;
import org.apache.camel.component.bean.BeanHelper;
import org.apache.camel.support.*;
import org.apache.camel.support.service.ServiceHelper;
import org.apache.camel.util.StringHelper;
import org.apache.camel.util.StringQuoteHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionStage;
import static org.apache.camel.util.ObjectHelper.asList;
import static org.apache.camel.util.ObjectHelper.asString;
/**
* Information about a method to be used for invocation.
*/
public class MethodInfo {
private static final Logger LOG = LoggerFactory.getLogger(MethodInfo.class);
private CamelContext camelContext;
private Class<?> type;
private Method method;
private final List<ParameterInfo> parameters;
private final List<ParameterInfo> bodyParameters;
private final boolean hasCustomAnnotation;
private final boolean hasHandlerAnnotation;
private Expression parametersExpression;
private ExchangePattern pattern = ExchangePattern.InOut;
private AsyncProcessor recipientList;
private AsyncProcessor routingSlip;
private AsyncProcessor dynamicRouter;
/**
* Adapter to invoke the method which has been annotated with the @DynamicRouter
*/
private final class DynamicRouterExpression extends ExpressionAdapter {
private final Object pojo;
private DynamicRouterExpression(Object pojo) {
this.pojo = pojo;
}
@Override
public Object evaluate(Exchange exchange) {
// evaluate arguments on each invocation as the parameters can have changed/updated since last invocation
final Object[] arguments = parametersExpression.evaluate(exchange, Object[].class);
try {
return invoke(method, pojo, arguments, exchange);
} catch (Exception e) {
throw RuntimeCamelException.wrapRuntimeCamelException(e);
}
}
@Override
public String toString() {
return "DynamicRouter[invoking: " + method + " on bean: " + pojo + "]";
}
}
public MethodInfo(CamelContext camelContext, Class<?> type, Method method, List<ParameterInfo> parameters, List<ParameterInfo> bodyParameters,
boolean hasCustomAnnotation, boolean hasHandlerAnnotation) {
this.camelContext = camelContext;
this.type = type;
this.method = method;
this.parameters = parameters;
this.bodyParameters = bodyParameters;
this.hasCustomAnnotation = hasCustomAnnotation;
this.hasHandlerAnnotation = hasHandlerAnnotation;
this.parametersExpression = createParametersExpression();
Map<Class<?>, Annotation> collectedMethodAnnotation = collectMethodAnnotations(type, method);
Pattern oneway = findOneWayAnnotation(method);
if (oneway != null) {
pattern = oneway.value();
}
org.apache.camel.RoutingSlip routingSlipAnnotation =
(org.apache.camel.RoutingSlip) collectedMethodAnnotation.get(org.apache.camel.RoutingSlip.class);
if (routingSlipAnnotation != null) {
routingSlip = camelContext.adapt(ExtendedCamelContext.class).getAnnotationBasedProcessorFactory().createRoutingSlip(camelContext, routingSlipAnnotation);
// add created routingSlip as a service so we have its lifecycle managed
try {
camelContext.addService(routingSlip);
} catch (Exception e) {
throw RuntimeCamelException.wrapRuntimeCamelException(e);
}
}
org.apache.camel.DynamicRouter dynamicRouterAnnotation =
(org.apache.camel.DynamicRouter) collectedMethodAnnotation.get(org.apache.camel.DynamicRouter.class);
if (dynamicRouterAnnotation != null) {
dynamicRouter = camelContext.adapt(ExtendedCamelContext.class).getAnnotationBasedProcessorFactory().createDynamicRouter(camelContext, dynamicRouterAnnotation);
// add created dynamicRouter as a service so we have its lifecycle managed
try {
camelContext.addService(dynamicRouter);
} catch (Exception e) {
throw RuntimeCamelException.wrapRuntimeCamelException(e);
}
}
org.apache.camel.RecipientList recipientListAnnotation =
(org.apache.camel.RecipientList) collectedMethodAnnotation.get(org.apache.camel.RecipientList.class);
if (recipientListAnnotation != null) {
recipientList = camelContext.adapt(ExtendedCamelContext.class).getAnnotationBasedProcessorFactory().createRecipientList(camelContext, recipientListAnnotation);
// add created recipientList as a service so we have its lifecycle managed
try {
camelContext.addService(recipientList);
} catch (Exception e) {
throw RuntimeCamelException.wrapRuntimeCamelException(e);
}
}
}
private Map<Class<?>, Annotation> collectMethodAnnotations(Class<?> c, Method method) {
Map<Class<?>, Annotation> annotations = new HashMap<>();
collectMethodAnnotations(c, method, annotations);
return annotations;
}
private void collectMethodAnnotations(Class<?> c, Method method, Map<Class<?>, Annotation> annotations) {
for (Class<?> i : c.getInterfaces()) {
collectMethodAnnotations(i, method, annotations);
}
if (!c.isInterface() && c.getSuperclass() != null) {
collectMethodAnnotations(c.getSuperclass(), method, annotations);
}
// make sure the sub class can override the definition
try {
Annotation[] ma = c.getDeclaredMethod(method.getName(), method.getParameterTypes()).getAnnotations();
for (Annotation a : ma) {
annotations.put(a.annotationType(), a);
}
} catch (SecurityException | NoSuchMethodException e) {
// do nothing here
}
}
@Override
public String toString() {
return method.toString();
}
public MethodInvocation createMethodInvocation(final Object pojo, boolean hasParameters, final Exchange exchange) {
final Object[] arguments;
if (hasParameters) {
arguments = parametersExpression.evaluate(exchange, Object[].class);
} else {
arguments = null;
}
return new MethodInvocation() {
public Method getMethod() {
return method;
}
public Object[] getArguments() {
return arguments;
}
public boolean proceed(AsyncCallback callback) {
try {
// reset cached streams so they can be read again
MessageHelper.resetStreamCache(exchange.getIn());
return doProceed(callback);
} catch (InvocationTargetException e) {
exchange.setException(e.getTargetException());
callback.done(true);
return true;
} catch (Throwable e) {
exchange.setException(e);
callback.done(true);
return true;
}
}
private boolean doProceed(AsyncCallback callback) throws Exception {
// dynamic router should be invoked beforehand
if (dynamicRouter != null) {
if (!ServiceHelper.isStarted(dynamicRouter)) {
ServiceHelper.startService(dynamicRouter);
}
// TODO: Maybe use a new constant than EVALUATE_EXPRESSION_RESULT
// use a expression which invokes the method to be used by dynamic router
Expression expression = new DynamicRouterExpression(pojo);
exchange.setProperty(Exchange.EVALUATE_EXPRESSION_RESULT, expression);
return dynamicRouter.process(exchange, callback);
}
// invoke pojo
if (LOG.isTraceEnabled()) {
LOG.trace(">>>> invoking: {} on bean: {} with arguments: {} for exchange: {}", method, pojo, asString(arguments), exchange);
}
Object result = invoke(method, pojo, arguments, exchange);
// the method may be a closure or chained method returning a callable which should be called
if (result instanceof Callable) {
LOG.trace("Method returned Callback which will be called: {}", result);
Object callableResult = ((Callable) result).call();
if (callableResult != null) {
result = callableResult;
} else {
// if callable returned null we should not change the body
result = Void.TYPE;
}
}
if (recipientList != null) {
// ensure its started
if (!ServiceHelper.isStarted(recipientList)) {
ServiceHelper.startService(recipientList);
}
exchange.setProperty(Exchange.EVALUATE_EXPRESSION_RESULT, result);
return recipientList.process(exchange, callback);
}
if (routingSlip != null) {
if (!ServiceHelper.isStarted(routingSlip)) {
ServiceHelper.startService(routingSlip);
}
exchange.setProperty(Exchange.EVALUATE_EXPRESSION_RESULT, result);
return routingSlip.process(exchange, callback);
}
//If it's Java 8 async result
if (CompletionStage.class.isAssignableFrom(method.getReturnType())) {
CompletionStage<?> completionStage = (CompletionStage<?>) result;
completionStage
.whenComplete((resultObject, e) -> {
if (e != null) {
exchange.setException(e);
} else if (resultObject != null) {
fillResult(exchange, resultObject);
}
callback.done(false);
});
return false;
}
// if the method returns something then set the value returned on the Exchange
if (result != Void.TYPE && !method.getReturnType().equals(Void.TYPE)) {
fillResult(exchange, result);
}
// we did not use any of the eips, but just invoked the bean
// so notify the callback we are done synchronously
callback.done(true);
return true;
}
public Object getThis() {
return pojo;
}
public AccessibleObject getStaticPart() {
return method;
}
};
}
private void fillResult(Exchange exchange, Object result) {
LOG.trace("Setting bean invocation result : {}", result);
// the bean component forces OUT if the MEP is OUT capable
boolean out = exchange.hasOut() || ExchangeHelper.isOutCapable(exchange);
Message old;
if (out) {
old = exchange.getOut();
// propagate headers
exchange.getOut().getHeaders().putAll(exchange.getIn().getHeaders());
} else {
old = exchange.getIn();
}
// create a new message container so we do not drag specialized message objects along
// but that is only needed if the old message is a specialized message
boolean copyNeeded = !(old.getClass().equals(DefaultMessage.class));
if (copyNeeded) {
Message msg = new DefaultMessage(exchange.getContext());
msg.copyFromWithNewBody(old, result);
// replace message on exchange
ExchangeHelper.replaceMessage(exchange, msg, false);
} else {
// no copy needed so set replace value directly
old.setBody(result);
}
}
public Class<?> getType() {
return type;
}
public Method getMethod() {
return method;
}
/**
* Returns the {@link org.apache.camel.ExchangePattern} that should be used when invoking this method. This value
* defaults to {@link org.apache.camel.ExchangePattern#InOut} unless some {@link org.apache.camel.Pattern} annotation is used
* to override the message exchange pattern.
*
* @return the exchange pattern to use for invoking this method.
*/
public ExchangePattern getPattern() {
return pattern;
}
public Expression getParametersExpression() {
return parametersExpression;
}
public List<ParameterInfo> getBodyParameters() {
return bodyParameters;
}
public Class<?> getBodyParameterType() {
if (bodyParameters.isEmpty()) {
return null;
}
ParameterInfo parameterInfo = bodyParameters.get(0);
return parameterInfo.getType();
}
public boolean bodyParameterMatches(Class<?> bodyType) {
Class<?> actualType = getBodyParameterType();
return actualType != null && org.apache.camel.util.ObjectHelper.isAssignableFrom(bodyType, actualType);
}
public List<ParameterInfo> getParameters() {
return parameters;
}
public boolean hasBodyParameter() {
return !bodyParameters.isEmpty();
}
public boolean hasCustomAnnotation() {
return hasCustomAnnotation;
}
public boolean hasHandlerAnnotation() {
return hasHandlerAnnotation;
}
public boolean hasParameters() {
return !parameters.isEmpty();
}
public boolean isReturnTypeVoid() {
return method.getReturnType().getName().equals("void");
}
public boolean isStaticMethod() {
return Modifier.isStatic(method.getModifiers());
}
/**
* Returns true if this method is covariant with the specified method
* (this method may above or below the specified method in the class hierarchy)
*/
public boolean isCovariantWith(MethodInfo method) {
return
method.getMethod().getName().equals(this.getMethod().getName())
&& (method.getMethod().getReturnType().isAssignableFrom(this.getMethod().getReturnType())
|| this.getMethod().getReturnType().isAssignableFrom(method.getMethod().getReturnType()))
&& Arrays.deepEquals(method.getMethod().getParameterTypes(), this.getMethod().getParameterTypes());
}
protected Object invoke(Method mth, Object pojo, Object[] arguments, Exchange exchange) throws InvocationTargetException {
try {
return ObjectHelper.invokeMethodSafe(mth, pojo, arguments);
} catch (IllegalAccessException e) {
throw new RuntimeExchangeException("IllegalAccessException occurred invoking method: " + mth + " using arguments: " + asList(arguments), exchange, e);
} catch (IllegalArgumentException e) {
throw new RuntimeExchangeException("IllegalArgumentException occurred invoking method: " + mth + " using arguments: " + asList(arguments), exchange, e);
}
}
protected Expression[] createParameterExpressions() {
final int size = parameters.size();
LOG.trace("Creating parameters expression for {} parameters", size);
final Expression[] expressions = new Expression[size];
for (int i = 0; i < size; i++) {
Expression parameterExpression = parameters.get(i).getExpression();
expressions[i] = parameterExpression;
LOG.trace("Parameter #{} has expression: {}", i, parameterExpression);
}
return expressions;
}
protected Expression createParametersExpression() {
return new ParameterExpression(createParameterExpressions());
}
/**
* Finds the oneway annotation in priority order; look for method level annotations first, then the class level annotations,
* then super class annotations then interface annotations
*
* @param method the method on which to search
* @return the first matching annotation or none if it is not available
*/
protected Pattern findOneWayAnnotation(Method method) {
Pattern answer = getPatternAnnotation(method);
if (answer == null) {
Class<?> type = method.getDeclaringClass();
// create the search order of types to scan
List<Class<?>> typesToSearch = new ArrayList<>();
addTypeAndSuperTypes(type, typesToSearch);
Class<?>[] interfaces = type.getInterfaces();
for (Class<?> anInterface : interfaces) {
addTypeAndSuperTypes(anInterface, typesToSearch);
}
// now let's scan for a type which the current declared class overloads
answer = findOneWayAnnotationOnMethod(typesToSearch, method);
if (answer == null) {
answer = findOneWayAnnotation(typesToSearch);
}
}
return answer;
}
/**
* Returns the pattern annotation on the given annotated element; either as a direct annotation or
* on an annotation which is also annotated
*
* @param annotatedElement the element to look for the annotation
* @return the first matching annotation or null if none could be found
*/
protected Pattern getPatternAnnotation(AnnotatedElement annotatedElement) {
return getPatternAnnotation(annotatedElement, 2);
}
/**
* Returns the pattern annotation on the given annotated element; either as a direct annotation or
* on an annotation which is also annotated
*
* @param annotatedElement the element to look for the annotation
* @param depth the current depth
* @return the first matching annotation or null if none could be found
*/
protected Pattern getPatternAnnotation(AnnotatedElement annotatedElement, int depth) {
Pattern answer = annotatedElement.getAnnotation(Pattern.class);
int nextDepth = depth - 1;
if (nextDepth > 0) {
// look at all the annotations to see if any of those are annotated
Annotation[] annotations = annotatedElement.getAnnotations();
for (Annotation annotation : annotations) {
Class<? extends Annotation> annotationType = annotation.annotationType();
if (annotation instanceof Pattern || annotationType.equals(annotatedElement)) {
continue;
} else {
Pattern another = getPatternAnnotation(annotationType, nextDepth);
if (pattern != null) {
if (answer == null) {
answer = another;
} else {
LOG.warn("Duplicate pattern annotation: {} found on annotation: {} which will be ignored", another, annotation);
}
}
}
}
}
return answer;
}
/**
* Adds the current class and all of its base classes (apart from {@link Object} to the given list
*/
protected void addTypeAndSuperTypes(Class<?> type, List<Class<?>> result) {
for (Class<?> t = type; t != null && t != Object.class; t = t.getSuperclass()) {
result.add(t);
}
}
/**
* Finds the first annotation on the base methods defined in the list of classes
*/
protected Pattern findOneWayAnnotationOnMethod(List<Class<?>> classes, Method method) {
for (Class<?> type : classes) {
try {
Method definedMethod = type.getMethod(method.getName(), method.getParameterTypes());
Pattern answer = getPatternAnnotation(definedMethod);
if (answer != null) {
return answer;
}
} catch (NoSuchMethodException e) {
// ignore
}
}
return null;
}
/**
* Finds the first annotation on the given list of classes
*/
protected Pattern findOneWayAnnotation(List<Class<?>> classes) {
for (Class<?> type : classes) {
Pattern answer = getPatternAnnotation(type);
if (answer != null) {
return answer;
}
}
return null;
}
protected boolean hasExceptionParameter() {
for (ParameterInfo parameter : parameters) {
if (Exception.class.isAssignableFrom(parameter.getType())) {
return true;
}
}
return false;
}
/**
* Expression to evaluate the bean parameter parameters and provide the correct values when the method is invoked.
*/
private final class ParameterExpression implements Expression {
private final Expression[] expressions;
ParameterExpression(Expression[] expressions) {
this.expressions = expressions;
}
@Override
@SuppressWarnings("unchecked")
public <T> T evaluate(Exchange exchange, Class<T> type) {
Object body = exchange.getIn().getBody();
// if there was an explicit method name to invoke, then we should support using
// any provided parameter values in the method name
String methodName = exchange.getIn().getHeader(Exchange.BEAN_METHOD_NAME, String.class);
// the parameter values is between the parenthesis
String methodParameters = StringHelper.betweenOuterPair(methodName, '(', ')');
// use an iterator to walk the parameter values
Iterator<?> it = null;
if (methodParameters != null) {
// split the parameters safely separated by comma, but beware that we can have
// quoted parameters which contains comma as well, so do a safe quote split
String[] parameters = StringQuoteHelper.splitSafeQuote(methodParameters, ',', true);
it = ObjectHelper.createIterator(parameters, ",", true);
}
// remove headers as they should not be propagated
// we need to do this before the expressions gets evaluated as it may contain
// a @Bean expression which would by mistake read these headers. So the headers
// must be removed at this point of time
if (methodName != null) {
exchange.getIn().removeHeader(Exchange.BEAN_METHOD_NAME);
}
Object[] answer = evaluateParameterExpressions(exchange, body, it);
return (T) answer;
}
/**
* Evaluates all the parameter expressions
*/
private Object[] evaluateParameterExpressions(Exchange exchange, Object body, Iterator<?> it) {
Object[] answer = new Object[expressions.length];
for (int i = 0; i < expressions.length; i++) {
if (body instanceof StreamCache) {
// need to reset stream cache for each expression as you may access the message body in multiple parameters
((StreamCache) body).reset();
}
// grab the parameter value for the given index
Object parameterValue = it != null && it.hasNext() ? it.next() : null;
// and the expected parameter type
Class<?> parameterType = parameters.get(i).getType();
// the value for the parameter to use
Object value = null;
// prefer to use parameter value if given, as they override any bean parameter binding
// we should skip * as its a type placeholder to indicate any type
if (parameterValue != null && !parameterValue.equals("*")) {
// evaluate the parameter value binding
value = evaluateParameterValue(exchange, i, parameterValue, parameterType);
}
// use bean parameter binding, if still no value
Expression expression = expressions[i];
if (value == null && expression != null) {
value = evaluateParameterBinding(exchange, expression, i, parameterType);
}
// remember the value to use
if (value != Void.TYPE) {
answer[i] = value;
}
}
return answer;
}
/**
* Evaluate using parameter values where the values can be provided in the method name syntax.
* <p/>
* This methods returns accordingly:
* <ul>
* <li><tt>null</tt> - if not a parameter value</li>
* <li><tt>Void.TYPE</tt> - if an explicit null, forcing Camel to pass in <tt>null</tt> for that given parameter</li>
* <li>a non <tt>null</tt> value - if the parameter was a parameter value, and to be used</li>
* </ul>
*
* @since 2.9
*/
private Object evaluateParameterValue(Exchange exchange, int index, Object parameterValue, Class<?> parameterType) {
Object answer = null;
// convert the parameter value to a String
String exp = exchange.getContext().getTypeConverter().convertTo(String.class, exchange, parameterValue);
if (exp != null) {
// check if its a valid parameter value
boolean valid = org.apache.camel.component.bean.BeanHelper.isValidParameterValue(exp);
if (!valid) {
// it may be a parameter type instead, and if so, then we should return null,
// as this method is only for evaluating parameter values
Boolean isClass = org.apache.camel.component.bean.BeanHelper.isAssignableToExpectedType(exchange.getContext().getClassResolver(), exp, parameterType);
// the method will return a non null value if exp is a class
if (isClass != null) {
return null;
}
}
// use simple language to evaluate the expression, as it may use the simple language to refer to message body, headers etc.
Expression expression = null;
try {
expression = exchange.getContext().resolveLanguage("simple").createExpression(exp);
parameterValue = expression.evaluate(exchange, Object.class);
// use "null" to indicate the expression returned a null value which is a valid response we need to honor
if (parameterValue == null) {
parameterValue = "null";
}
} catch (Exception e) {
throw new ExpressionEvaluationException(expression, "Cannot create/evaluate simple expression: " + exp
+ " to be bound to parameter at index: " + index + " on method: " + getMethod(), exchange, e);
}
// special for explicit null parameter values (as end users can explicit indicate they want null as parameter)
// see method javadoc for details
if ("null".equals(parameterValue)) {
return Void.TYPE;
}
// the parameter value may match the expected type, then we use it as-is
if (parameterType.isAssignableFrom(parameterValue.getClass())) {
valid = true;
} else {
// the parameter value was not already valid, but since the simple language have evaluated the expression
// which may change the parameterValue, so we have to check it again to see if its now valid
exp = exchange.getContext().getTypeConverter().tryConvertTo(String.class, parameterValue);
// String values from the simple language is always valid
if (!valid) {
// re validate if the parameter was not valid the first time (String values should be accepted)
valid = parameterValue instanceof String || BeanHelper.isValidParameterValue(exp);
}
}
if (valid) {
// we need to unquote String parameters, as the enclosing quotes is there to denote a parameter value
if (parameterValue instanceof String) {
parameterValue = StringHelper.removeLeadingAndEndingQuotes((String) parameterValue);
}
if (parameterValue != null) {
try {
// its a valid parameter value, so convert it to the expected type of the parameter
answer = exchange.getContext().getTypeConverter().mandatoryConvertTo(parameterType, exchange, parameterValue);
if (LOG.isTraceEnabled()) {
LOG.trace("Parameter #{} evaluated as: {} type: {}", index, answer, org.apache.camel.util.ObjectHelper.type(answer));
}
} catch (Exception e) {
if (LOG.isDebugEnabled()) {
LOG.debug("Cannot convert from type: {} to type: {} for parameter #{}", org.apache.camel.util.ObjectHelper.type(parameterValue), parameterType, index);
}
throw new ParameterBindingException(e, method, index, parameterType, parameterValue);
}
}
}
}
return answer;
}
/**
* Evaluate using classic parameter binding using the pre compute expression
*/
private Object evaluateParameterBinding(Exchange exchange, Expression expression, int index, Class<?> parameterType) {
Object answer = null;
// use object first to avoid type conversion so we know if there is a value or not
Object result = expression.evaluate(exchange, Object.class);
if (result != null) {
try {
if (parameterType.isInstance(result)) {
// optimize if the value is already the same type
answer = result;
} else {
// we got a value now try to convert it to the expected type
answer = exchange.getContext().getTypeConverter().mandatoryConvertTo(parameterType, result);
}
if (LOG.isTraceEnabled()) {
LOG.trace("Parameter #{} evaluated as: {} type: {}", index, answer, org.apache.camel.util.ObjectHelper.type(answer));
}
} catch (NoTypeConversionAvailableException e) {
if (LOG.isDebugEnabled()) {
LOG.debug("Cannot convert from type: {} to type: {} for parameter #{}", org.apache.camel.util.ObjectHelper.type(result), parameterType, index);
}
throw new ParameterBindingException(e, method, index, parameterType, result);
}
} else {
LOG.trace("Parameter #{} evaluated as null", index);
}
return answer;
}
@Override
public String toString() {
return "ParametersExpression: " + Arrays.asList(expressions);
}
}
}

View File

@ -0,0 +1,89 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.bean.fix;
import org.apache.camel.CamelContext;
import org.apache.camel.support.LRUCacheFactory;
import java.lang.reflect.Method;
import java.util.Map;
/**
* Represents a cache of {@link org.apache.camel.component.bean.MethodInfo} objects to avoid the expense of introspection for each
* invocation of a method via a proxy.
*/
public class MethodInfoCache {
private final CamelContext camelContext;
private Map<Method, MethodInfo> methodCache;
private Map<Class<?>, BeanInfo> classCache;
public MethodInfoCache(CamelContext camelContext) {
this(camelContext, 1000, 10000);
}
public MethodInfoCache(CamelContext camelContext, int classCacheSize, int methodCacheSize) {
this(camelContext, createClassCache(classCacheSize), createMethodCache(methodCacheSize));
}
public MethodInfoCache(CamelContext camelContext, Map<Class<?>, BeanInfo> classCache, Map<Method, MethodInfo> methodCache) {
this.camelContext = camelContext;
this.classCache = classCache;
this.methodCache = methodCache;
}
public synchronized MethodInfo getMethodInfo(Method method) {
MethodInfo answer = methodCache.get(method);
if (answer == null) {
answer = createMethodInfo(method);
methodCache.put(method, answer);
}
return answer;
}
protected MethodInfo createMethodInfo(Method method) {
Class<?> declaringClass = method.getDeclaringClass();
BeanInfo info = getBeanInfo(declaringClass);
return info.getMethodInfo(method);
}
protected synchronized BeanInfo getBeanInfo(Class<?> declaringClass) {
BeanInfo beanInfo = classCache.get(declaringClass);
if (beanInfo == null) {
beanInfo = createBeanInfo(declaringClass);
classCache.put(declaringClass, beanInfo);
}
return beanInfo;
}
protected BeanInfo createBeanInfo(Class<?> declaringClass) {
return new BeanInfo(camelContext, declaringClass);
}
@SuppressWarnings("unchecked")
protected static <K, V> Map<K, V> createLruCache(int size) {
// use a soft cache
return LRUCacheFactory.newLRUSoftCache(size);
}
private static Map<Class<?>, BeanInfo> createClassCache(int size) {
return createLruCache(size);
}
private static Map<Method, MethodInfo> createMethodCache(int size) {
return createLruCache(size);
}
}

View File

@ -0,0 +1,44 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.bean.fix;
import org.apache.camel.AsyncCallback;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
/**
* Information used by Camel to perform method invocation.
*/
public interface MethodInvocation {
Method getMethod();
Object[] getArguments();
/**
* Proceed and invokes the method.
*
* @param callback the callback
* @return see {@link org.apache.camel.AsyncProcessor#process(org.apache.camel.Exchange, org.apache.camel.AsyncCallback)}
*/
boolean proceed(AsyncCallback callback);
Object getThis();
AccessibleObject getStaticPart();
}

View File

@ -0,0 +1,65 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.bean.fix;
import org.apache.camel.Exchange;
import org.apache.camel.RuntimeExchangeException;
import org.apache.camel.util.ObjectHelper;
public class MethodNotFoundException extends RuntimeExchangeException {
private final Object bean;
private final String methodName;
public MethodNotFoundException(Exchange exchange, Object pojo, String methodName) {
super("Method with name: " + methodName + " not found on bean: " + pojo + " of type: " + ObjectHelper.className(pojo), exchange);
this.methodName = methodName;
this.bean = pojo;
}
public MethodNotFoundException(Exchange exchange, Object pojo, String methodName, String postfix) {
super("Method with name: " + methodName + " " + postfix + " not found on bean: " + pojo + " of type: " + ObjectHelper.className(pojo), exchange);
this.methodName = methodName;
this.bean = pojo;
}
public MethodNotFoundException(Exchange exchange, Class<?> type, String methodName, boolean isStaticMethod) {
super((isStaticMethod ? "Static method" : "Method") + " with name: " + methodName + " not found on class: " + ObjectHelper.name(type), exchange);
this.methodName = methodName;
this.bean = null;
}
public MethodNotFoundException(Object pojo, String methodName, Throwable cause) {
super("Method with name: " + methodName + " not found on bean: " + pojo + " of type:" + ObjectHelper.className(pojo), null, cause);
this.methodName = methodName;
this.bean = pojo;
}
public MethodNotFoundException(Class<?> type, String methodName, Throwable cause) {
super("Method with name: " + methodName + " not found on class: " + ObjectHelper.className(type), null, cause);
this.methodName = methodName;
this.bean = null;
}
public String getMethodName() {
return methodName;
}
public Object getBean() {
return bean;
}
}

Some files were not shown because too many files have changed in this diff Show More