Compare commits
No commits in common. 'master' and 'kern_tomcat10_test_his' have entirely different histories.
master
...
kern_tomca
1529 changed files with 697723 additions and 145984 deletions
@ -1,16 +0,0 @@ |
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
|
||||||
<launchConfiguration type="org.eclipse.ant.AntBuilderLaunchConfigurationType"> |
|
||||||
<stringAttribute key="org.eclipse.ant.ui.ATTR_ANT_AFTER_CLEAN_TARGETS" value="get_git_info,"/> |
|
||||||
<stringAttribute key="org.eclipse.ant.ui.ATTR_ANT_MANUAL_TARGETS" value="get_git_info,"/> |
|
||||||
<booleanAttribute key="org.eclipse.ant.ui.ATTR_TARGETS_UPDATED" value="true"/> |
|
||||||
<booleanAttribute key="org.eclipse.ant.ui.DEFAULT_VM_INSTALL" value="false"/> |
|
||||||
<booleanAttribute key="org.eclipse.debug.core.ATTR_REFRESH_RECURSIVE" value="false"/> |
|
||||||
<stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <resources/>}"/> |
|
||||||
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/> |
|
||||||
<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="org.eclipse.ant.ui.AntClasspathProvider"/> |
|
||||||
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="true"/> |
|
||||||
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="superx"/> |
|
||||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="/home/superx/git/kern/superx-build/build.xml"/> |
|
||||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,"/> |
|
||||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/> |
|
||||||
</launchConfiguration> |
|
||||||
@ -1,270 +1,46 @@ |
|||||||
# agent and copilot context - local/temporary files |
# ignore all log files |
||||||
.github/ |
*.log |
||||||
|
*.err |
||||||
|
*.log.* |
||||||
|
|
||||||
# Gradle build output and wrapper cache |
|
||||||
build/ |
|
||||||
.gradle/ |
|
||||||
|
|
||||||
# ignore /dist/* |
# ignore all CVS + sub dirs |
||||||
*dist/ |
*CVS/ |
||||||
|
|
||||||
# ignore swap files |
|
||||||
superx/WEB-INF/reports/swap_* |
|
||||||
|
|
||||||
# ignore eclipse settings |
|
||||||
.settings/org.eclipse.ltk.core.refactoring.prefs |
|
||||||
|
|
||||||
# vim .swp files |
|
||||||
*.swp |
|
||||||
|
|
||||||
# ignore gradle bin |
|
||||||
scripts/gradle/bin/ |
|
||||||
scripts/gradle/.gradle/ |
|
||||||
|
|
||||||
# cobertura |
|
||||||
superx-build/cobertura* |
|
||||||
|
|
||||||
# classes |
|
||||||
superx/WEB-INF/classes/ |
|
||||||
|
|
||||||
# tag files |
|
||||||
**/tags |
|
||||||
|
|
||||||
# .orig files |
|
||||||
**/*.orig |
|
||||||
|
|
||||||
# datum.alt files |
|
||||||
**/superx.datum.alt |
|
||||||
|
|
||||||
# script artefacts |
|
||||||
scripts/**/build/ |
|
||||||
scripts/**/log/ |
|
||||||
|
|
||||||
# build artefacts |
|
||||||
superx-build/declared-jars.txt |
|
||||||
superx-build/cobertura_build_tests/ |
|
||||||
superx-build/cobertura_build_classes/ |
|
||||||
superx-build/coveragereport/ |
|
||||||
superx-build/results/ |
|
||||||
superx-build/tmp_build/ |
|
||||||
|
|
||||||
# Eclipse launch configurations are causing conflicts on 'pull' if you've got local ones; so they should not be under SCM |
|
||||||
scripts/eclipseExternalTools/ |
|
||||||
|
|
||||||
# extracted h1-modules. These should only be links to folders in cs.bia.his_components |
|
||||||
src-modules/module/prom/ |
|
||||||
src-modules/module/res/ |
|
||||||
src-modules/module/astat/ |
|
||||||
src-modules/module/tt/ |
|
||||||
src-modules/module/star/ |
|
||||||
src-modules/module/kern_s/ |
|
||||||
src-modules/module/res_s/ |
|
||||||
# also ignore symlinks on linux |
|
||||||
src-modules/module/prom |
|
||||||
src-modules/module/res |
|
||||||
src-modules/module/astat |
|
||||||
src-modules/module/tt |
|
||||||
src-modules/module/star |
|
||||||
src-modules/module/kern_s |
|
||||||
src-modules/module/res_s |
|
||||||
src-modules/module/biad |
|
||||||
|
|
||||||
# artifact folders for reduced/cleaned modules |
|
||||||
superx/WEB-INF/conf/edustore/db/module/prom/ |
|
||||||
superx/WEB-INF/conf/edustore/db/module/res/ |
|
||||||
superx/WEB-INF/conf/edustore/db/module/zul/ |
|
||||||
superx/WEB-INF/conf/edustore/db/module/sos/ |
|
||||||
superx/WEB-INF/conf/edustore/db/module/sva/ |
|
||||||
superx/WEB-INF/conf/edustore/db/module/ivs/ |
|
||||||
superx/WEB-INF/conf/edustore/db/module/astat/ |
|
||||||
superx/WEB-INF/conf/edustore/db/module/tt/ |
|
||||||
superx/WEB-INF/conf/edustore/db/module/lm/ |
|
||||||
superx/WEB-INF/conf/edustore/db/module/etl/ |
|
||||||
superx/WEB-INF/conf/edustore/db/module/star/ |
|
||||||
superx/WEB-INF/conf/edustore/db/module/cob/ |
|
||||||
superx/WEB-INF/conf/edustore/db/module/kern_s/ |
|
||||||
superx/WEB-INF/conf/edustore/db/module/res_s/ |
|
||||||
superx/WEB-INF/conf/edustore/db/module/bau/ |
|
||||||
superx/WEB-INF/conf/edustore/db/module/fin/ |
|
||||||
superx/WEB-INF/conf/edustore/db/module/biad/ |
|
||||||
superx/WEB-INF/conf/edustore/db/module/gang/ |
|
||||||
superx/WEB-INF/conf/edustore/db/module/erfolg/ |
|
||||||
superx/WEB-INF/conf/edustore/db/module/man/ |
|
||||||
superx/WEB-INF/conf/edustore/db/module/kenn/ |
|
||||||
superx/WEB-INF/conf/edustore/db/module/kennx/ |
|
||||||
|
|
||||||
# module generation artifacts for module fin |
|
||||||
src/edustore/edustore_fin.xml |
|
||||||
superx/WEB-INF/fin_dbforms-config_ids.xml |
|
||||||
superx/WEB-INF/fin_dbforms-config_pg.xml |
|
||||||
|
|
||||||
# module generation artifacts for module bau |
|
||||||
src/edustore/edustore_bau.xml |
|
||||||
superx/WEB-INF/bau_dbforms-config_ids.xml |
|
||||||
superx/WEB-INF/bau_dbforms-config_pg.xml |
|
||||||
|
|
||||||
# module generation artifacts for module prom |
|
||||||
src/edustore/edustore_prom.xml |
|
||||||
superx/WEB-INF/prom_dbforms-config_ids.xml |
|
||||||
superx/WEB-INF/prom_dbforms-config_pg.xml |
|
||||||
superx/edit/prom/ |
|
||||||
|
|
||||||
# module generation artifacts for module res |
|
||||||
src/edustore/edustore_res.xml |
|
||||||
superx/WEB-INF/res_dbforms-config_ids.xml |
|
||||||
superx/WEB-INF/res_dbforms-config_pg.xml |
|
||||||
|
|
||||||
# module generation artifacts for module gang |
|
||||||
src/edustore/edustore_gang.xml |
|
||||||
superx/WEB-INF/gang_dbforms-config_ids.xml |
|
||||||
superx/WEB-INF/gang_dbforms-config_pg.xml |
|
||||||
superx/edit/gang/*edit.jsp |
|
||||||
superx/edit/gang/*list.jsp |
|
||||||
|
|
||||||
|
# ignore java classes |
||||||
|
*classes/ |
||||||
|
|
||||||
# module generation artifacts for module kenn |
# ignore files in directory rohdaten |
||||||
src/edustore/edustore_kenn.xml |
superx/WEB-INF/conf/edustore/db/module/*/rohdaten/unl/*.unl |
||||||
superx/WEB-INF/kenn_dbforms-config_ids.xml |
superx/WEB-INF/conf/edustore/db/install/rohdaten/unl/*.unl |
||||||
superx/WEB-INF/kenn_dbforms-config_pg.xml |
|
||||||
superx/edit/kenn/*edit.jsp |
|
||||||
superx/edit/kenn/*list.jsp |
|
||||||
|
|
||||||
# module generation artifacts for module kennx |
# ignore temporary files |
||||||
src/edustore/edustore_kennx.xml |
*.tmp |
||||||
superx/WEB-INF/kennx_dbforms-config_ids.xml |
*.tmp.sql |
||||||
superx/WEB-INF/kennx_dbforms-config_pg.xml |
temp.xml |
||||||
superx/edit/kennx/*edit.jsp |
tmp.fo |
||||||
superx/edit/kennx/*list.jsp |
|
||||||
|
|
||||||
|
# ignore auto generated files |
||||||
|
db.properties |
||||||
|
dbforms-config.xml |
||||||
|
superx/WEB-INF/dbforms-config.old |
||||||
|
superx.datum |
||||||
|
|
||||||
# module generation artifacts for module man |
# ignore iReport Designer |
||||||
src/edustore/edustore_man.xml |
*.jasper |
||||||
superx/WEB-INF/man_dbforms-config_ids.xml |
|
||||||
superx/WEB-INF/man_dbforms-config_pg.xml |
|
||||||
superx/edit/man/catdesc.jsp |
|
||||||
superx/edit/man/cat.jsp |
|
||||||
superx/edit/man/grouping.jsp |
|
||||||
superx/edit/man/man_reports.jsp |
|
||||||
superx/edit/man/organigramm_dialog.jsp |
|
||||||
superx/edit/man/rpt.jsp |
|
||||||
superx/edit/man/*edit.jsp |
|
||||||
superx/edit/man/*list.jsp |
|
||||||
|
|
||||||
# module generation artifacts for module erfolg |
|
||||||
src/edustore/edustore_erfolg.xml |
|
||||||
superx/WEB-INF/erfolg_dbforms-config_ids.xml |
|
||||||
superx/WEB-INF/erfolg_dbforms-config_pg.xml |
|
||||||
|
|
||||||
# module generation artifacts for module sos |
|
||||||
src/edustore/edustore_sos.xml |
|
||||||
superx/WEB-INF/sos_dbforms-config_ids.xml |
|
||||||
superx/WEB-INF/sos_dbforms-config_pg.xml |
|
||||||
superx/edit/sos/hoererstatus_edit.jsp |
|
||||||
superx/edit/sos/koepfe_oder_faelle_edit.jsp |
|
||||||
superx/edit/sos/lehr_stg_ab_edit.jsp |
|
||||||
superx/edit/sos/semester_edit.jsp |
|
||||||
superx/edit/sos/semester_list.jsp |
|
||||||
superx/edit/sos/sos_status_edit.jsp |
|
||||||
superx/edit/sos/sos_stichtag_edit.jsp |
|
||||||
superx/edit/sos/sos_stichtag_list.jsp |
|
||||||
superx/edit/sos/statistik_edit.jsp |
|
||||||
superx/edit/sos/studierendenuebertragung_edit.jsp |
|
||||||
|
|
||||||
# module generation artifacts for module sva |
|
||||||
src/edustore/edustore_sva.xml |
|
||||||
superx/WEB-INF/sva_dbforms-config_ids.xml |
|
||||||
superx/WEB-INF/sva_dbforms-config_pg.xml |
|
||||||
superx/edit/sva/konstanten_sva_edit.jsp |
|
||||||
superx/edit/sva/sichten_sva_dienstart_edit.jsp |
|
||||||
superx/edit/sva/sichten_sva_klr_geldgeber_kurz_edit.jsp |
|
||||||
superx/edit/sva/sva_stichtag_list.jsp |
|
||||||
superx/edit/sva/sx_repository_sva_edit.jsp |
|
||||||
superx/edit/sva/user_sva.jsp |
|
||||||
superx/edit/sva/user_sva_manuell.jsp |
|
||||||
|
|
||||||
# module generation artifacts for module ivs |
|
||||||
src/edustore/edustore_ivs.xml |
|
||||||
superx/edit/ivs/user_inventar_edit.jsp |
|
||||||
superx/WEB-INF/ivs_dbforms-config_ids.xml |
|
||||||
superx/WEB-INF/ivs_dbforms-config_pg.xml |
|
||||||
|
|
||||||
# module generation artifacts for module zul |
|
||||||
src/edustore/edustore_zul.xml |
|
||||||
superx/WEB-INF/zul_dbforms-config_ids.xml |
|
||||||
superx/WEB-INF/zul_dbforms-config_pg.xml |
|
||||||
|
|
||||||
# module generation artifacts for module astat |
|
||||||
src/edustore/edustore_astat.xml |
|
||||||
superx/WEB-INF/astat_dbforms-config_ids.xml |
|
||||||
superx/WEB-INF/astat_dbforms-config_pg.xml |
|
||||||
|
|
||||||
# module generation artifacts for module tt |
|
||||||
src/edustore/edustore_tt.xml |
|
||||||
superx/WEB-INF/tt_dbforms-config_ids.xml |
|
||||||
superx/WEB-INF/tt_dbforms-config_pg.xml |
|
||||||
superx/edit/tt/ |
|
||||||
|
|
||||||
# module generation artifacts for module lm |
|
||||||
src/edustore/edustore_lm.xml |
|
||||||
superx/WEB-INF/lm_dbforms-config_ids.xml |
|
||||||
superx/WEB-INF/lm_dbforms-config_pg.xml |
|
||||||
superx/edit/lm/ |
|
||||||
|
|
||||||
# module generation artifacts for module etl |
|
||||||
src/edustore/edustore_etl.xml |
|
||||||
superx/WEB-INF/etl_dbforms-config_ids.xml |
|
||||||
superx/WEB-INF/etl_dbforms-config_pg.xml |
|
||||||
superx/edit/etl/etl_job_edit.jsp |
|
||||||
superx/edit/etl/etl_step_edit.jsp |
|
||||||
superx/edit/etl/etl_step_type_list.jsp |
|
||||||
|
|
||||||
# module generation artifacts for module star |
|
||||||
src/edustore/edustore_star.xml |
|
||||||
superx/WEB-INF/star_dbforms-config_ids.xml |
|
||||||
superx/WEB-INF/star_dbforms-config_pg.xml |
|
||||||
|
|
||||||
# module generation artifacts for module cob |
|
||||||
src/edustore/edustore_cob.xml |
|
||||||
superx/WEB-INF/cob_dbforms-config_ids.xml |
|
||||||
superx/WEB-INF/cob_dbforms-config_pg.xml |
|
||||||
superx/edit/cob/sx_repository_cob_edit.jsp |
|
||||||
|
|
||||||
# module generation artifacts for module kern_s |
|
||||||
src/edustore/edustore_kern_s.xml |
|
||||||
superx/WEB-INF/kern_s_dbforms-config_ids.xml |
|
||||||
superx/WEB-INF/kern_s_dbforms-config_pg.xml |
|
||||||
|
|
||||||
# module generation artifacts for module res_s |
|
||||||
src/edustore/edustore_res_s.xml |
|
||||||
superx/WEB-INF/res_s_dbforms-config_ids.xml |
|
||||||
superx/WEB-INF/res_s_dbforms-config_pg.xml |
|
||||||
|
|
||||||
# module generation artifacts for module biad |
|
||||||
src/edustore/edustore_biad.xml |
|
||||||
superx/WEB-INF/biad_dbforms-config_ids.xml |
|
||||||
superx/WEB-INF/biad_dbforms-config_pg.xml |
|
||||||
|
|
||||||
# dbt project generation backups |
|
||||||
superx/dbt/projects/*_backup/ |
|
||||||
|
|
||||||
# Saiku his icons |
|
||||||
superx/saiku/css/saiku/src/saiku_his.css |
|
||||||
|
|
||||||
# Dateifunktionalität im kenn und kennx Modul |
|
||||||
superx\WEB-INF\downloads |
|
||||||
|
|
||||||
# vscode personal settings |
# ignore /dist/* |
||||||
.vscode/ |
*dist/ |
||||||
.metadata/ |
|
||||||
|
|
||||||
# edustore.xml soll nicht mehr ausgeliefert werden siehe #313658 |
# ignore swap files |
||||||
src/edustore/edustore.xml |
superx/WEB-INF/reports/swap_* |
||||||
|
|
||||||
# package folder und config file für statisch generierte JSPs |
src/edustore/edustore_*.xml |
||||||
src/de/superx/jsp/ |
|
||||||
superx/WEB-INF/jsp_servlet_config.xml |
|
||||||
|
|
||||||
# jaspers werden nicht mehr commitet, sondern im build gebaut |
# ignore eclipse settings |
||||||
*.jasper |
.settings/org.eclipse.ltk.core.refactoring.prefs |
||||||
# updateUnmodifiedJars backup |
#rpta files: |
||||||
superx/WEB-INF/lib/backup/ |
superx/WEB-INF/reports/simple_table.jrtx |
||||||
|
superx/WEB-INF/reports/tabelle_jrxml_a4_quer.xsl.jrxml |
||||||
|
superx/xml/jr_templates.xsl |
||||||
|
superx/xml/rpta_assistent.xsl |
||||||
|
|||||||
@ -1,58 +1,36 @@ |
|||||||
<?xml version="1.0" encoding="UTF-8"?> |
<?xml version="1.0" encoding="UTF-8"?> |
||||||
<projectDescription> |
<projectDescription> |
||||||
<name>eduStore_superX</name> |
<name>eduStore_superX</name> |
||||||
<comment></comment> |
<comment></comment> |
||||||
<projects> |
<projects> |
||||||
</projects> |
</projects> |
||||||
<buildSpec> |
<buildSpec> |
||||||
<buildCommand> |
<buildCommand> |
||||||
<name>org.eclipse.jdt.core.javabuilder</name> |
<name>org.eclipse.jdt.core.javabuilder</name> |
||||||
<arguments> |
<arguments> |
||||||
</arguments> |
</arguments> |
||||||
</buildCommand> |
</buildCommand> |
||||||
<buildCommand> |
<buildCommand> |
||||||
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name> |
<name>org.eclipse.babel.editor.rbeBuilder</name> |
||||||
<triggers>full,incremental,</triggers> |
<arguments> |
||||||
<arguments> |
</arguments> |
||||||
<dictionary> |
</buildCommand> |
||||||
<key>LaunchConfigHandle</key> |
</buildSpec> |
||||||
<value><project>/.externalToolBuilders/Ant Superx Version.launch</value> |
<natures> |
||||||
</dictionary> |
<nature>org.eclipse.jdt.groovy.core.groovyNature</nature> |
||||||
</arguments> |
<nature>org.eclipse.jdt.core.javanature</nature> |
||||||
</buildCommand> |
<nature>com.sysdeo.eclipse.tomcat.tomcatnature</nature> |
||||||
</buildSpec> |
<nature>com.jaspersoft.studio.babel.editor.rbeNature</nature> |
||||||
<natures> |
</natures> |
||||||
<nature>org.eclipse.jdt.core.javanature</nature> |
<filteredResources> |
||||||
<nature>com.sysdeo.eclipse.tomcat.tomcatnature</nature> |
<filter> |
||||||
<nature>com.jaspersoft.studio.babel.editor.rbeNature</nature> |
<id>1459344926910</id> |
||||||
</natures> |
<name></name> |
||||||
<filteredResources> |
<type>10</type> |
||||||
<filter> |
<matcher> |
||||||
<id>1617792163171</id> |
<id>org.eclipse.ui.ide.multiFilter</id> |
||||||
<name></name> |
<arguments>1.0-name-matches-false-false-dist</arguments> |
||||||
<type>10</type> |
</matcher> |
||||||
<matcher> |
</filter> |
||||||
<id>org.eclipse.ui.ide.multiFilter</id> |
</filteredResources> |
||||||
<arguments>1.0-name-matches-false-false-dist</arguments> |
</projectDescription> |
||||||
</matcher> |
|
||||||
</filter> |
|
||||||
<filter> |
|
||||||
<id>1617792163186</id> |
|
||||||
<name></name> |
|
||||||
<type>6</type> |
|
||||||
<matcher> |
|
||||||
<id>org.eclipse.ui.ide.multiFilter</id> |
|
||||||
<arguments>1.0-name-matches-false-true-.+\.class</arguments> |
|
||||||
</matcher> |
|
||||||
</filter> |
|
||||||
<filter> |
|
||||||
<id>1687335947806</id> |
|
||||||
<name></name> |
|
||||||
<type>30</type> |
|
||||||
<matcher> |
|
||||||
<id>org.eclipse.core.resources.regexFilterMatcher</id> |
|
||||||
<arguments>node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments> |
|
||||||
</matcher> |
|
||||||
</filter> |
|
||||||
</filteredResources> |
|
||||||
</projectDescription> |
|
||||||
|
|||||||
@ -1,901 +0,0 @@ |
|||||||
/* |
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
|
||||||
* |
|
||||||
* Copyright (c) 2010-2013 Oracle and/or its affiliates. All rights reserved. |
|
||||||
* |
|
||||||
* The contents of this file are subject to the terms of either the GNU |
|
||||||
* General Public License Version 2 only ("GPL") or the Common Development |
|
||||||
* and Distribution License("CDDL") (collectively, the "License"). You |
|
||||||
* may not use this file except in compliance with the License. You can |
|
||||||
* obtain a copy of the License at |
|
||||||
* http://glassfish.java.net/public/CDDL+GPL_1_1.html
|
|
||||||
* or packager/legal/LICENSE.txt. See the License for the specific |
|
||||||
* language governing permissions and limitations under the License. |
|
||||||
* |
|
||||||
* When distributing the software, include this License Header Notice in each |
|
||||||
* file and include the License file at packager/legal/LICENSE.txt. |
|
||||||
* |
|
||||||
* GPL Classpath Exception: |
|
||||||
* Oracle designates this particular file as subject to the "Classpath" |
|
||||||
* exception as provided by Oracle in the GPL Version 2 section of the License |
|
||||||
* file that accompanied this code. |
|
||||||
* |
|
||||||
* Modifications: |
|
||||||
* If applicable, add the following below the License Header, with the fields |
|
||||||
* enclosed by brackets [] replaced by your own identifying information: |
|
||||||
* "Portions Copyright [year] [name of copyright owner]" |
|
||||||
* |
|
||||||
* Contributor(s): |
|
||||||
* If you wish your version of this file to be governed by only the CDDL or |
|
||||||
* only the GPL Version 2, indicate your decision by adding "[Contributor] |
|
||||||
* elects to include this software in this distribution under the [CDDL or GPL |
|
||||||
* Version 2] license." If you don't indicate a single choice of license, a |
|
||||||
* recipient has the option to distribute your version of this file under |
|
||||||
* either the CDDL, the GPL Version 2 or to extend the choice of license to |
|
||||||
* its licensees as provided above. However, if you add GPL Version 2 code |
|
||||||
* and therefore, elected the GPL Version 2 license, then the option applies |
|
||||||
* only if the new code is made subject to such option by the copyright |
|
||||||
* holder. |
|
||||||
*/ |
|
||||||
|
|
||||||
/* gepatchtes class-File: |
|
||||||
* im Rahmen von #331613 muss mit dem Update auf Tomcat 10 auch die Anwendung von Serlvet API 4.0 auf 6.0 umgestellt werden. |
|
||||||
* Dies leistet ein Migrationstool, welches in erster Linie den Packagenamen von 'javax' auf 'jakarta' umstellt. |
|
||||||
* Allerdings bestand danach immer noch in der 'jersey-bunde-1.19.4.jar' ein Zugriff auf die entfernte Methode |
|
||||||
* 'HttpServletResponse.setStatus(int, String)', welcher beim Laden von Saiku zu einer Exception geführt hat, |
|
||||||
* wodurch das Frontend in der Ladeanzeige geblieben ist. |
|
||||||
* Der Patch ändert die Klasse derart, dass sie die noch vorhandene Methode 'HttpServletResponse.setStatus(int)' aufruft, |
|
||||||
* was zu funktionieren scheint. |
|
||||||
* Ursprung entspricht https://github.com/javaee/jersey-1.x/blob/864a01d7be490ab93d2424da3e446ad8eb84b1e8/jersey-servlet/src/main/java/com/sun/jersey/spi/container/servlet/WebComponent.java
|
|
||||||
*/ |
|
||||||
|
|
||||||
package com.sun.jersey.spi.container.servlet; |
|
||||||
|
|
||||||
import java.io.BufferedInputStream; |
|
||||||
import java.io.IOException; |
|
||||||
import java.io.InputStream; |
|
||||||
import java.io.OutputStream; |
|
||||||
import java.lang.reflect.Constructor; |
|
||||||
import java.lang.reflect.Proxy; |
|
||||||
import java.lang.reflect.Type; |
|
||||||
import java.net.URI; |
|
||||||
import java.security.Principal; |
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.Arrays; |
|
||||||
import java.util.Enumeration; |
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.Iterator; |
|
||||||
import java.util.LinkedList; |
|
||||||
import java.util.List; |
|
||||||
import java.util.Map; |
|
||||||
import java.util.logging.Level; |
|
||||||
import java.util.logging.Logger; |
|
||||||
|
|
||||||
import javax.ws.rs.WebApplicationException; |
|
||||||
import javax.ws.rs.core.Application; |
|
||||||
import javax.ws.rs.core.Context; |
|
||||||
import javax.ws.rs.core.GenericEntity; |
|
||||||
import javax.ws.rs.core.MediaType; |
|
||||||
import javax.ws.rs.core.MultivaluedMap; |
|
||||||
import javax.ws.rs.core.Response; |
|
||||||
import javax.ws.rs.core.SecurityContext; |
|
||||||
|
|
||||||
import javax.naming.NamingException; |
|
||||||
import jakarta.servlet.ServletContext; |
|
||||||
import jakarta.servlet.ServletException; |
|
||||||
import jakarta.servlet.http.HttpServletRequest; |
|
||||||
import jakarta.servlet.http.HttpServletResponse; |
|
||||||
|
|
||||||
import com.sun.jersey.api.container.ContainerException; |
|
||||||
import com.sun.jersey.api.container.MappableContainerException; |
|
||||||
import com.sun.jersey.api.core.ApplicationAdapter; |
|
||||||
import com.sun.jersey.api.core.ClasspathResourceConfig; |
|
||||||
import com.sun.jersey.api.core.PackagesResourceConfig; |
|
||||||
import com.sun.jersey.api.core.ResourceConfig; |
|
||||||
import com.sun.jersey.api.core.TraceInformation; |
|
||||||
import com.sun.jersey.api.core.servlet.WebAppResourceConfig; |
|
||||||
import com.sun.jersey.api.representation.Form; |
|
||||||
import com.sun.jersey.core.header.InBoundHeaders; |
|
||||||
import com.sun.jersey.core.header.MediaTypes; |
|
||||||
import com.sun.jersey.core.reflection.ReflectionHelper; |
|
||||||
import com.sun.jersey.core.util.ReaderWriter; |
|
||||||
import com.sun.jersey.server.impl.InitialContextHelper; |
|
||||||
import com.sun.jersey.server.impl.ThreadLocalInvoker; |
|
||||||
import com.sun.jersey.server.impl.application.DeferredResourceConfig; |
|
||||||
import com.sun.jersey.server.impl.cdi.CDIComponentProviderFactoryInitializer; |
|
||||||
import com.sun.jersey.server.impl.container.servlet.JSPTemplateProcessor; |
|
||||||
import com.sun.jersey.server.impl.ejb.EJBComponentProviderFactoryInitilizer; |
|
||||||
import com.sun.jersey.server.impl.managedbeans.ManagedBeanComponentProviderFactoryInitilizer; |
|
||||||
import com.sun.jersey.server.impl.model.method.dispatch.FormDispatchProvider; |
|
||||||
import com.sun.jersey.server.impl.monitoring.GlassFishMonitoringInitializer; |
|
||||||
import com.sun.jersey.server.probes.UriRuleProbeProvider; |
|
||||||
import com.sun.jersey.spi.container.ContainerListener; |
|
||||||
import com.sun.jersey.spi.container.ContainerNotifier; |
|
||||||
import com.sun.jersey.spi.container.ContainerRequest; |
|
||||||
import com.sun.jersey.spi.container.ContainerResponse; |
|
||||||
import com.sun.jersey.spi.container.ContainerResponseWriter; |
|
||||||
import com.sun.jersey.spi.container.ReloadListener; |
|
||||||
import com.sun.jersey.spi.container.WebApplication; |
|
||||||
import com.sun.jersey.spi.container.WebApplicationFactory; |
|
||||||
import com.sun.jersey.spi.inject.SingletonTypeInjectableProvider; |
|
||||||
import java.security.AccessController; |
|
||||||
import java.security.PrivilegedActionException; |
|
||||||
|
|
||||||
/** |
|
||||||
* An abstract Web component that may be extended a Servlet and/or |
|
||||||
* Filter implementation, or encapsulated by a Servlet or Filter implementation. |
|
||||||
* |
|
||||||
* @author Paul Sandoz (paul.sandoz at oracle.com) |
|
||||||
*/ |
|
||||||
public class WebComponent implements ContainerListener { |
|
||||||
/** |
|
||||||
* The servlet initialization property whose value is a fully qualified |
|
||||||
* class name of a class that implements {@link ResourceConfig} or |
|
||||||
* {@link Application}. |
|
||||||
*/ |
|
||||||
public static final String APPLICATION_CONFIG_CLASS = |
|
||||||
"javax.ws.rs.Application"; |
|
||||||
|
|
||||||
/** |
|
||||||
* The servlet initialization property whose value is a fully qualified |
|
||||||
* class name of a class that implements {@link ResourceConfig} or |
|
||||||
* {@link Application}. |
|
||||||
*/ |
|
||||||
public static final String RESOURCE_CONFIG_CLASS = |
|
||||||
"com.sun.jersey.config.property.resourceConfigClass"; |
|
||||||
|
|
||||||
/** |
|
||||||
* The base path in the Web Pages where JSP templates, associated with |
|
||||||
* viewables of resource classes, are located. |
|
||||||
* <p/> |
|
||||||
* If this property is not set then the base path will be the root path |
|
||||||
* of the Web Pages. |
|
||||||
*/ |
|
||||||
public static final String JSP_TEMPLATES_BASE_PATH = |
|
||||||
"com.sun.jersey.config.property.JSPTemplatesBasePath"; |
|
||||||
|
|
||||||
|
|
||||||
private static final Logger LOGGER = |
|
||||||
Logger.getLogger(WebComponent.class.getName()); |
|
||||||
|
|
||||||
private final ThreadLocalInvoker<HttpServletRequest> requestInvoker = |
|
||||||
new ThreadLocalInvoker<HttpServletRequest>(); |
|
||||||
|
|
||||||
private final ThreadLocalInvoker<HttpServletResponse> responseInvoker = |
|
||||||
new ThreadLocalInvoker<HttpServletResponse>(); |
|
||||||
|
|
||||||
|
|
||||||
private WebConfig config; |
|
||||||
|
|
||||||
private ResourceConfig resourceConfig; |
|
||||||
|
|
||||||
private WebApplication application; |
|
||||||
|
|
||||||
public WebComponent() { |
|
||||||
} |
|
||||||
|
|
||||||
public WebComponent(Application app) { |
|
||||||
if (app == null) |
|
||||||
throw new IllegalArgumentException(); |
|
||||||
|
|
||||||
if (app instanceof ResourceConfig) { |
|
||||||
resourceConfig = (ResourceConfig) app; |
|
||||||
} else { |
|
||||||
resourceConfig = new ApplicationAdapter(app); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Get the Web configuration. |
|
||||||
* |
|
||||||
* @return the Web configuration. |
|
||||||
*/ |
|
||||||
public WebConfig getWebConfig() { |
|
||||||
return config; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Get the resource configuration. |
|
||||||
* |
|
||||||
* @return the resource configuration. |
|
||||||
*/ |
|
||||||
public ResourceConfig getResourceConfig() { |
|
||||||
return resourceConfig; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Initiate the Web component. |
|
||||||
* |
|
||||||
* @param webConfig the Web configuration. |
|
||||||
* @throws javax.servlet.ServletException in case of any initialization error |
|
||||||
*/ |
|
||||||
public void init(WebConfig webConfig) throws ServletException { |
|
||||||
config = webConfig; |
|
||||||
|
|
||||||
if (resourceConfig == null) |
|
||||||
resourceConfig = createResourceConfig(config); |
|
||||||
|
|
||||||
load(); |
|
||||||
|
|
||||||
Object o = resourceConfig.getProperties().get( |
|
||||||
ResourceConfig.PROPERTY_CONTAINER_NOTIFIER); |
|
||||||
if (o instanceof List) { |
|
||||||
List list = (List) o; |
|
||||||
for (Object elem : list) { |
|
||||||
if (elem instanceof ContainerNotifier) { |
|
||||||
ContainerNotifier crf = (ContainerNotifier) elem; |
|
||||||
crf.addListener(this); |
|
||||||
} |
|
||||||
} |
|
||||||
} else if (o instanceof ContainerNotifier) { |
|
||||||
ContainerNotifier crf = (ContainerNotifier) o; |
|
||||||
crf.addListener(this); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Destroy this Web component. |
|
||||||
* <p/> |
|
||||||
* This will destroy the Web application created by this this Web component. |
|
||||||
*/ |
|
||||||
public void destroy() { |
|
||||||
if (application != null) |
|
||||||
application.destroy(); |
|
||||||
} |
|
||||||
|
|
||||||
private final static class Writer extends OutputStream implements ContainerResponseWriter { |
|
||||||
final HttpServletResponse response; |
|
||||||
|
|
||||||
ContainerResponse cResponse; |
|
||||||
|
|
||||||
long contentLength; |
|
||||||
|
|
||||||
OutputStream out; |
|
||||||
|
|
||||||
boolean statusAndHeadersWritten = false; |
|
||||||
|
|
||||||
Writer(HttpServletResponse response) { |
|
||||||
this.response = response; |
|
||||||
} |
|
||||||
|
|
||||||
public OutputStream writeStatusAndHeaders(long contentLength, |
|
||||||
ContainerResponse cResponse) throws IOException { |
|
||||||
this.contentLength = contentLength; |
|
||||||
this.cResponse = cResponse; |
|
||||||
this.statusAndHeadersWritten = false; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public void finish() throws IOException { |
|
||||||
if (statusAndHeadersWritten) |
|
||||||
return; |
|
||||||
|
|
||||||
// Note that the writing of headers MUST be performed before
|
|
||||||
// the invocation of sendError as on some Servlet implementations
|
|
||||||
// modification of the response headers will have no effect
|
|
||||||
// after the invocation of sendError.
|
|
||||||
writeHeaders(); |
|
||||||
|
|
||||||
|
|
||||||
writeStatus(); |
|
||||||
} |
|
||||||
|
|
||||||
private void writeStatus() { |
|
||||||
Response.StatusType statusType = cResponse.getStatusType(); |
|
||||||
final String reasonPhrase = statusType.getReasonPhrase(); |
|
||||||
|
|
||||||
// if (reasonPhrase != null) {
|
|
||||||
// response.setStatus(statusType.getStatusCode(), reasonPhrase);
|
|
||||||
// } else {
|
|
||||||
response.setStatus(statusType.getStatusCode()); |
|
||||||
// }
|
|
||||||
} |
|
||||||
|
|
||||||
public void write(int b) throws IOException { |
|
||||||
initiate(); |
|
||||||
out.write(b); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void write(byte b[]) throws IOException { |
|
||||||
if (b.length > 0) { |
|
||||||
initiate(); |
|
||||||
out.write(b); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void write(byte b[], int off, int len) throws IOException { |
|
||||||
if (len > 0) { |
|
||||||
initiate(); |
|
||||||
out.write(b, off, len); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void flush() throws IOException { |
|
||||||
writeStatusAndHeaders(); |
|
||||||
if (out != null) |
|
||||||
out.flush(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void close() throws IOException { |
|
||||||
initiate(); |
|
||||||
out.close(); |
|
||||||
} |
|
||||||
|
|
||||||
void initiate() throws IOException { |
|
||||||
if (out == null) { |
|
||||||
writeStatusAndHeaders(); |
|
||||||
out = response.getOutputStream(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void writeStatusAndHeaders() { |
|
||||||
if (statusAndHeadersWritten) |
|
||||||
return; |
|
||||||
|
|
||||||
writeHeaders(); |
|
||||||
writeStatus(); |
|
||||||
statusAndHeadersWritten = true; |
|
||||||
} |
|
||||||
|
|
||||||
void writeHeaders() { |
|
||||||
if (contentLength != -1 && contentLength < Integer.MAX_VALUE) |
|
||||||
response.setContentLength((int) contentLength); |
|
||||||
|
|
||||||
MultivaluedMap<String, Object> headers = cResponse.getHttpHeaders(); |
|
||||||
for (Map.Entry<String, List<Object>> e : headers.entrySet()) { |
|
||||||
for (Object v : e.getValue()) { |
|
||||||
response.addHeader(e.getKey(), ContainerResponse.getHeaderValue(v)); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Dispatch client requests to a resource class. |
|
||||||
* |
|
||||||
* @param baseUri the base URI of the request. |
|
||||||
* @param requestUri the URI of the request. |
|
||||||
* @param request the {@link HttpServletRequest} object that |
|
||||||
* contains the request the client made to |
|
||||||
* the Web component. |
|
||||||
* @param response the {@link HttpServletResponse} object that |
|
||||||
* contains the response the Web component returns |
|
||||||
* to the client. |
|
||||||
* @return the status code of the response. |
|
||||||
* @throws IOException if an input or output error occurs |
|
||||||
* while the Web component is handling the |
|
||||||
* HTTP request. |
|
||||||
* @throws ServletException if the HTTP request cannot |
|
||||||
* be handled. |
|
||||||
*/ |
|
||||||
public int service(URI baseUri, URI requestUri, |
|
||||||
final HttpServletRequest request, |
|
||||||
final HttpServletResponse response) |
|
||||||
throws ServletException, IOException { |
|
||||||
// Copy the application field to local instance to ensure that the
|
|
||||||
// currently loaded web application is used to process
|
|
||||||
// request
|
|
||||||
final WebApplication _application = application; |
|
||||||
|
|
||||||
final ContainerRequest cRequest = createRequest( |
|
||||||
_application, |
|
||||||
request, |
|
||||||
baseUri, |
|
||||||
requestUri); |
|
||||||
|
|
||||||
cRequest.setSecurityContext(new SecurityContext() { |
|
||||||
public Principal getUserPrincipal() { |
|
||||||
return request.getUserPrincipal(); |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isUserInRole(String role) { |
|
||||||
return request.isUserInRole(role); |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isSecure() { |
|
||||||
return request.isSecure(); |
|
||||||
} |
|
||||||
|
|
||||||
public String getAuthenticationScheme() { |
|
||||||
return request.getAuthType(); |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
try { |
|
||||||
// Check if any servlet filters have consumed a request entity
|
|
||||||
// of the media type application/x-www-form-urlencoded
|
|
||||||
// This can happen if a filter calls request.getParameter(...)
|
|
||||||
filterFormParameters(request, cRequest); |
|
||||||
|
|
||||||
UriRuleProbeProvider.requestStart(requestUri); |
|
||||||
|
|
||||||
requestInvoker.set(request); |
|
||||||
responseInvoker.set(response); |
|
||||||
|
|
||||||
final Writer w = new Writer(response); |
|
||||||
_application.handleRequest(cRequest, w); |
|
||||||
return w.cResponse.getStatus(); |
|
||||||
} catch (WebApplicationException ex) { |
|
||||||
final Response exResponse = ex.getResponse(); |
|
||||||
final String entity = exResponse.getEntity() != null ? exResponse.getEntity().toString() : null; |
|
||||||
|
|
||||||
response.sendError(exResponse.getStatus(), entity); |
|
||||||
|
|
||||||
return exResponse.getStatus(); |
|
||||||
} catch (MappableContainerException ex) { |
|
||||||
traceOnException(cRequest, response); |
|
||||||
throw new ServletException(ex.getCause()); |
|
||||||
} catch (ContainerException ex) { |
|
||||||
traceOnException(cRequest, response); |
|
||||||
throw new ServletException(ex); |
|
||||||
} catch (RuntimeException ex) { |
|
||||||
traceOnException(cRequest, response); |
|
||||||
throw ex; |
|
||||||
} finally { |
|
||||||
UriRuleProbeProvider.requestEnd(); |
|
||||||
requestInvoker.set(null); |
|
||||||
responseInvoker.set(null); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Extension point for creating your custom container request. |
|
||||||
* |
|
||||||
* @param app the web app |
|
||||||
* @param request the current servlet api request |
|
||||||
* @param baseUri the base uri |
|
||||||
* @param requestUri the request uri |
|
||||||
* @return the request container |
|
||||||
* @throws IOException if any error occurs when getting the input stream |
|
||||||
*/ |
|
||||||
protected ContainerRequest createRequest(WebApplication app, |
|
||||||
HttpServletRequest request, URI baseUri, URI requestUri) throws IOException { |
|
||||||
return new ContainerRequest( |
|
||||||
app, |
|
||||||
request.getMethod(), |
|
||||||
baseUri, |
|
||||||
requestUri, |
|
||||||
getHeaders(request), |
|
||||||
request.getInputStream()); |
|
||||||
} |
|
||||||
|
|
||||||
private void traceOnException(final ContainerRequest cRequest, final HttpServletResponse response) { |
|
||||||
if (cRequest.isTracingEnabled()) { |
|
||||||
final TraceInformation ti = (TraceInformation) cRequest.getProperties(). |
|
||||||
get(TraceInformation.class.getName()); |
|
||||||
|
|
||||||
ti.addTraceHeaders(new TraceInformation.TraceHeaderListener() { |
|
||||||
public void onHeader(String name, String value) { |
|
||||||
response.addHeader(name, value); |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Create a new instance of a {@link WebApplication}. |
|
||||||
* |
|
||||||
* @return the {@link WebApplication} instance. |
|
||||||
*/ |
|
||||||
protected WebApplication create() { |
|
||||||
return WebApplicationFactory.createWebApplication(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* A helper class for creating an injectable provider that supports |
|
||||||
* {@link Context} with a type and constant value. |
|
||||||
* |
|
||||||
* @param <T> the type of the constant value. |
|
||||||
*/ |
|
||||||
protected static class ContextInjectableProvider<T> extends |
|
||||||
SingletonTypeInjectableProvider<Context, T> { |
|
||||||
|
|
||||||
/** |
|
||||||
* Create a new instance. |
|
||||||
* |
|
||||||
* @param type the type of the constant value. |
|
||||||
* @param instance the constant value. |
|
||||||
*/ |
|
||||||
protected ContextInjectableProvider(Type type, T instance) { |
|
||||||
super(type, instance); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Configure the {@link ResourceConfig}. |
|
||||||
* <p/> |
|
||||||
* The {@link ResourceConfig} is configured such that the following classes |
|
||||||
* may be injected onto the field of a root resource class or a parameter |
|
||||||
* of a method of root resource class that is annotated with |
|
||||||
* {@link javax.ws.rs.core.Context}: {@link HttpServletRequest}, {@link HttpServletResponse} |
|
||||||
* , {@link ServletContext} and {@link WebConfig}. |
|
||||||
* <p/> |
|
||||||
* Any root resource class in registered in the resource configuration |
|
||||||
* that is an interface is processed as follows. |
|
||||||
* If the class is an interface and there exists a JNDI named object |
|
||||||
* with the fully qualified class name as the JNDI name then that named |
|
||||||
* object is added as a singleton root resource and the class is removed |
|
||||||
* from the set of root resource classes. |
|
||||||
* <p/> |
|
||||||
* An inheriting class may override this method to configure the |
|
||||||
* {@link ResourceConfig} to provide alternative or additional instances |
|
||||||
* that are resource or provider classes or instances, and may modify the |
|
||||||
* features and properties of the {@link ResourceConfig}. For an inheriting |
|
||||||
* class to extend configuration behaviour the overriding method MUST call |
|
||||||
* <code>super.configure(servletConfig, rc, wa)</code> as the first statement |
|
||||||
* of that method. |
|
||||||
* <p/> |
|
||||||
* This method will be called only once at initiation. Subsequent |
|
||||||
* reloads of the Web application will not result in subsequence calls to |
|
||||||
* this method. |
|
||||||
* |
|
||||||
* @param wc the Web configuration |
|
||||||
* @param rc the Resource configuration |
|
||||||
* @param wa the Web application |
|
||||||
*/ |
|
||||||
protected void configure(WebConfig wc, ResourceConfig rc, WebApplication wa) { |
|
||||||
configureJndiResources(rc); |
|
||||||
|
|
||||||
rc.getSingletons().add(new ContextInjectableProvider<HttpServletRequest>( |
|
||||||
HttpServletRequest.class, |
|
||||||
(HttpServletRequest) Proxy.newProxyInstance( |
|
||||||
this.getClass().getClassLoader(), |
|
||||||
new Class[]{HttpServletRequest.class}, |
|
||||||
requestInvoker))); |
|
||||||
|
|
||||||
rc.getSingletons().add(new ContextInjectableProvider<HttpServletResponse>( |
|
||||||
HttpServletResponse.class, |
|
||||||
(HttpServletResponse) Proxy.newProxyInstance( |
|
||||||
this.getClass().getClassLoader(), |
|
||||||
new Class[]{HttpServletResponse.class}, |
|
||||||
responseInvoker))); |
|
||||||
|
|
||||||
GenericEntity<ThreadLocal<HttpServletRequest>> requestThreadLocal = |
|
||||||
new GenericEntity<ThreadLocal<HttpServletRequest>>(requestInvoker.getImmutableThreadLocal()) { |
|
||||||
}; |
|
||||||
rc.getSingletons().add(new ContextInjectableProvider<ThreadLocal<HttpServletRequest>>( |
|
||||||
requestThreadLocal.getType(), requestThreadLocal.getEntity())); |
|
||||||
|
|
||||||
GenericEntity<ThreadLocal<HttpServletResponse>> responseThreadLocal = |
|
||||||
new GenericEntity<ThreadLocal<HttpServletResponse>>(responseInvoker.getImmutableThreadLocal()) { |
|
||||||
}; |
|
||||||
rc.getSingletons().add(new ContextInjectableProvider<ThreadLocal<HttpServletResponse>>( |
|
||||||
responseThreadLocal.getType(), responseThreadLocal.getEntity())); |
|
||||||
|
|
||||||
rc.getSingletons().add(new ContextInjectableProvider<ServletContext>( |
|
||||||
ServletContext.class, |
|
||||||
wc.getServletContext())); |
|
||||||
|
|
||||||
rc.getSingletons().add(new ContextInjectableProvider<WebConfig>( |
|
||||||
WebConfig.class, |
|
||||||
wc)); |
|
||||||
|
|
||||||
rc.getClasses().add(JSPTemplateProcessor.class); |
|
||||||
|
|
||||||
// TODO
|
|
||||||
// If CDI is enabled should EJB injection be disabled?
|
|
||||||
EJBComponentProviderFactoryInitilizer.initialize(rc); |
|
||||||
|
|
||||||
CDIComponentProviderFactoryInitializer.initialize(wc, rc, wa); |
|
||||||
|
|
||||||
// TODO
|
|
||||||
// If CDI is enabled then no need to initialize managed beans
|
|
||||||
ManagedBeanComponentProviderFactoryInitilizer.initialize(rc); |
|
||||||
|
|
||||||
GlassFishMonitoringInitializer.initialize(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Initiate the {@link WebApplication}. |
|
||||||
* <p/> |
|
||||||
* This method will be called once at initiation and for |
|
||||||
* each reload of the Web application. |
|
||||||
* <p/> |
|
||||||
* An inheriting class may override this method to initiate the |
|
||||||
* Web application with different parameters. |
|
||||||
* |
|
||||||
* @param rc the Resource configuration |
|
||||||
* @param wa the Web application |
|
||||||
*/ |
|
||||||
protected void initiate(ResourceConfig rc, WebApplication wa) { |
|
||||||
wa.initiate(rc); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Load the Web application. This will create, configure and initiate |
|
||||||
* the web application. |
|
||||||
*/ |
|
||||||
public void load() { |
|
||||||
WebApplication _application = create(); |
|
||||||
configure(config, resourceConfig, _application); |
|
||||||
initiate(resourceConfig, _application); |
|
||||||
application = _application; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Get the default resource configuration if one is not declared in the |
|
||||||
* web.xml. |
|
||||||
* <p/> |
|
||||||
* This implementation returns an instance of {@link WebAppResourceConfig} |
|
||||||
* that scans in files and directories as declared by the |
|
||||||
* {@link ClasspathResourceConfig#PROPERTY_CLASSPATH} if present, otherwise |
|
||||||
* in the "WEB-INF/lib" and "WEB-INF/classes" directories. |
|
||||||
* <p/> |
|
||||||
* An inheriting class may override this method to supply a different |
|
||||||
* default resource configuration implementation. |
|
||||||
* |
|
||||||
* @param props the properties to pass to the resource configuration. |
|
||||||
* @param wc the web configuration. |
|
||||||
* @return the default resource configuration. |
|
||||||
* @throws javax.servlet.ServletException in case of any issues with providing \ |
|
||||||
* the default resource configuration |
|
||||||
*/ |
|
||||||
protected ResourceConfig getDefaultResourceConfig(Map<String, Object> props, |
|
||||||
WebConfig wc) throws ServletException { |
|
||||||
return getWebAppResourceConfig(props, wc); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
// ContainerListener
|
|
||||||
|
|
||||||
/** |
|
||||||
* Reload the Web application. This will create and initiate the web |
|
||||||
* application using the same {@link ResourceConfig} implementation |
|
||||||
* that was used to load the Web application. |
|
||||||
* <p/> |
|
||||||
* This method may be called at runtime, more than once, to reload the |
|
||||||
* Web application. For example, if a {@link ResourceConfig} implementation |
|
||||||
* is capable of detecting changes to resource classes (addition or removal) |
|
||||||
* or providers then this method may be invoked to reload the web |
|
||||||
* application for such changes to take effect. |
|
||||||
* <p/> |
|
||||||
* If this method is called when there are pending requests then such |
|
||||||
* requests will be processed using the previously loaded web application. |
|
||||||
*/ |
|
||||||
public void onReload() { |
|
||||||
WebApplication oldApplication = application; |
|
||||||
WebApplication newApplication = create(); |
|
||||||
initiate(resourceConfig, newApplication); |
|
||||||
application = newApplication; |
|
||||||
|
|
||||||
if (resourceConfig instanceof ReloadListener) |
|
||||||
((ReloadListener) resourceConfig).onReload(); |
|
||||||
|
|
||||||
oldApplication.destroy(); |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
/* package */ ResourceConfig getWebAppResourceConfig(Map<String, Object> props, |
|
||||||
WebConfig webConfig) throws ServletException { |
|
||||||
// Default to using Web app resource config
|
|
||||||
return new WebAppResourceConfig(props, webConfig.getServletContext()); |
|
||||||
} |
|
||||||
|
|
||||||
private ResourceConfig createResourceConfig(WebConfig webConfig) |
|
||||||
throws ServletException { |
|
||||||
final Map<String, Object> props = getInitParams(webConfig); |
|
||||||
final ResourceConfig rc = createResourceConfig(webConfig, props); |
|
||||||
rc.setPropertiesAndFeatures(props); |
|
||||||
return rc; |
|
||||||
} |
|
||||||
|
|
||||||
private ResourceConfig createResourceConfig(WebConfig webConfig, Map<String, Object> props) |
|
||||||
throws ServletException { |
|
||||||
// Check if the resource config class property is present
|
|
||||||
String resourceConfigClassName = webConfig.getInitParameter(RESOURCE_CONFIG_CLASS); |
|
||||||
// Otherwise check if the JAX-RS application config class property is
|
|
||||||
// present
|
|
||||||
if (resourceConfigClassName == null) |
|
||||||
resourceConfigClassName = webConfig.getInitParameter(APPLICATION_CONFIG_CLASS); |
|
||||||
|
|
||||||
// If no resource config class property is present
|
|
||||||
if (resourceConfigClassName == null) { |
|
||||||
// If the packages property is present then
|
|
||||||
// use the packages resource config
|
|
||||||
String packages = webConfig.getInitParameter( |
|
||||||
PackagesResourceConfig.PROPERTY_PACKAGES); |
|
||||||
if (packages != null) { |
|
||||||
props.put(PackagesResourceConfig.PROPERTY_PACKAGES, packages); |
|
||||||
return new PackagesResourceConfig(props); |
|
||||||
} |
|
||||||
|
|
||||||
ResourceConfig defaultConfig = webConfig.getDefaultResourceConfig(props); |
|
||||||
if (defaultConfig != null) |
|
||||||
return defaultConfig; |
|
||||||
|
|
||||||
return getDefaultResourceConfig(props, webConfig); |
|
||||||
} |
|
||||||
|
|
||||||
try { |
|
||||||
Class<?> resourceConfigClass = AccessController.doPrivileged(ReflectionHelper. |
|
||||||
classForNameWithExceptionPEA(resourceConfigClassName)); |
|
||||||
|
|
||||||
// TODO add support for WebAppResourceConfig
|
|
||||||
if (resourceConfigClass == ClasspathResourceConfig.class) { |
|
||||||
String[] paths = getPaths(webConfig.getInitParameter( |
|
||||||
ClasspathResourceConfig.PROPERTY_CLASSPATH)); |
|
||||||
props.put(ClasspathResourceConfig.PROPERTY_CLASSPATH, paths); |
|
||||||
return new ClasspathResourceConfig(props); |
|
||||||
} else if (ResourceConfig.class.isAssignableFrom(resourceConfigClass)) { |
|
||||||
try { |
|
||||||
Constructor constructor = resourceConfigClass.getConstructor(Map.class); |
|
||||||
if (ClasspathResourceConfig.class.isAssignableFrom(resourceConfigClass)) { |
|
||||||
String[] paths = getPaths(webConfig.getInitParameter( |
|
||||||
ClasspathResourceConfig.PROPERTY_CLASSPATH)); |
|
||||||
props.put(ClasspathResourceConfig.PROPERTY_CLASSPATH, paths); |
|
||||||
} |
|
||||||
return (ResourceConfig) constructor.newInstance(props); |
|
||||||
} catch (NoSuchMethodException ex) { |
|
||||||
// Pass through and try the default constructor
|
|
||||||
} catch (Exception e) { |
|
||||||
throw new ServletException(e); |
|
||||||
} |
|
||||||
|
|
||||||
return new DeferredResourceConfig(resourceConfigClass.asSubclass(ResourceConfig.class)); |
|
||||||
} else if (Application.class.isAssignableFrom(resourceConfigClass)) { |
|
||||||
return new DeferredResourceConfig(resourceConfigClass.asSubclass(Application.class)); |
|
||||||
} else { |
|
||||||
String message = "Resource configuration class, " + resourceConfigClassName + |
|
||||||
", is not a super class of " + Application.class; |
|
||||||
throw new ServletException(message); |
|
||||||
} |
|
||||||
} catch (ClassNotFoundException e) { |
|
||||||
String message = "Resource configuration class, " + resourceConfigClassName + |
|
||||||
", could not be loaded"; |
|
||||||
throw new ServletException(message, e); |
|
||||||
} catch (PrivilegedActionException e) { |
|
||||||
String message = "Resource configuration class, " + resourceConfigClassName + |
|
||||||
", could not be loaded"; |
|
||||||
throw new ServletException(message, e.getCause()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private Map<String, Object> getInitParams(WebConfig webConfig) { |
|
||||||
Map<String, Object> props = new HashMap<String, Object>(); |
|
||||||
Enumeration names = webConfig.getInitParameterNames(); |
|
||||||
while (names.hasMoreElements()) { |
|
||||||
String name = (String) names.nextElement(); |
|
||||||
props.put(name, webConfig.getInitParameter(name)); |
|
||||||
} |
|
||||||
return props; |
|
||||||
} |
|
||||||
|
|
||||||
private String[] getPaths(String classpath) throws ServletException { |
|
||||||
final ServletContext context = config.getServletContext(); |
|
||||||
if (classpath == null) { |
|
||||||
String[] paths = { |
|
||||||
context.getRealPath("/WEB-INF/lib"), |
|
||||||
context.getRealPath("/WEB-INF/classes") |
|
||||||
}; |
|
||||||
if (paths[0] == null && paths[1] == null) { |
|
||||||
String message = "The default deployment configuration that scans for " + |
|
||||||
"classes in /WEB-INF/lib and /WEB-INF/classes is not supported " + |
|
||||||
"for the application server." + |
|
||||||
"Try using the package scanning configuration, see the JavaDoc for " + |
|
||||||
PackagesResourceConfig.class.getName() + " and the property " + |
|
||||||
PackagesResourceConfig.PROPERTY_PACKAGES + "."; |
|
||||||
throw new ServletException(message); |
|
||||||
} |
|
||||||
return paths; |
|
||||||
} else { |
|
||||||
String[] virtualPaths = classpath.split(";"); |
|
||||||
List<String> resourcePaths = new ArrayList<String>(); |
|
||||||
for (String virtualPath : virtualPaths) { |
|
||||||
virtualPath = virtualPath.trim(); |
|
||||||
if (virtualPath.length() == 0) continue; |
|
||||||
String path = context.getRealPath(virtualPath); |
|
||||||
if (path != null) resourcePaths.add(path); |
|
||||||
} |
|
||||||
if (resourcePaths.isEmpty()) { |
|
||||||
String message = "None of the declared classpath locations, " + |
|
||||||
classpath + |
|
||||||
", could be resolved. " + |
|
||||||
"This could be because the default deployment configuration that scans for " + |
|
||||||
"classes in classpath locations is not supported. " + |
|
||||||
"Try using the package scanning configuration, see the JavaDoc for " + |
|
||||||
PackagesResourceConfig.class.getName() + " and the property " + |
|
||||||
PackagesResourceConfig.PROPERTY_PACKAGES + "."; |
|
||||||
throw new ServletException(message); |
|
||||||
} |
|
||||||
return resourcePaths.toArray(new String[resourcePaths.size()]); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private void configureJndiResources(ResourceConfig rc) { |
|
||||||
// Obtain any instances that are registered in JNDI
|
|
||||||
// Assumes such instances are singletons
|
|
||||||
// Registered classes have to be interfaces
|
|
||||||
javax.naming.Context x = InitialContextHelper.getInitialContext(); |
|
||||||
if (x != null) { |
|
||||||
Iterator<Class<?>> i = rc.getClasses().iterator(); |
|
||||||
while (i.hasNext()) { |
|
||||||
Class<?> c = i.next(); |
|
||||||
if (!c.isInterface()) continue; |
|
||||||
|
|
||||||
try { |
|
||||||
Object o = x.lookup(c.getName()); |
|
||||||
if (o != null) { |
|
||||||
i.remove(); |
|
||||||
rc.getSingletons().add(o); |
|
||||||
LOGGER.log(Level.INFO, |
|
||||||
"An instance of the class " + c.getName() + |
|
||||||
" is found by JNDI look up using the class name as the JNDI name. " + |
|
||||||
"The instance will be registered as a singleton."); |
|
||||||
} |
|
||||||
} catch (NamingException ex) { |
|
||||||
LOGGER.log(Level.CONFIG, |
|
||||||
"JNDI lookup failed for Jersey application resource " + c.getName(), |
|
||||||
ex); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private void filterFormParameters(HttpServletRequest servletRequest, ContainerRequest containerRequet) throws IOException { |
|
||||||
if (MediaTypes.typeEquals(MediaType.APPLICATION_FORM_URLENCODED_TYPE, containerRequet.getMediaType()) |
|
||||||
&& !isEntityPresent(containerRequet)) { |
|
||||||
Form f = new Form(); |
|
||||||
|
|
||||||
Enumeration e = servletRequest.getParameterNames(); |
|
||||||
while (e.hasMoreElements()) { |
|
||||||
String name = (String) e.nextElement(); |
|
||||||
String[] values = servletRequest.getParameterValues(name); |
|
||||||
|
|
||||||
f.put(name, Arrays.asList(values)); |
|
||||||
} |
|
||||||
|
|
||||||
if (!f.isEmpty()) { |
|
||||||
containerRequet.getProperties().put(FormDispatchProvider.FORM_PROPERTY, f); |
|
||||||
if (LOGGER.isLoggable(Level.WARNING)) { |
|
||||||
LOGGER.log(Level.WARNING, |
|
||||||
"A servlet request, to the URI " + containerRequet.getRequestUri() + ", " + |
|
||||||
"contains form parameters in " + |
|
||||||
"the request body but the request body has been consumed " + |
|
||||||
"by the servlet or a servlet filter accessing the request " + |
|
||||||
"parameters. Only resource methods using @FormParam " + |
|
||||||
"will work as expected. Resource methods consuming the " + |
|
||||||
"request body by other means will not work as expected."); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private boolean isEntityPresent(ContainerRequest cr) throws IOException { |
|
||||||
InputStream in = cr.getEntityInputStream(); |
|
||||||
if (!in.markSupported()) { |
|
||||||
in = new BufferedInputStream(in, ReaderWriter.BUFFER_SIZE); |
|
||||||
cr.setEntityInputStream(in); |
|
||||||
} |
|
||||||
|
|
||||||
in.mark(1); |
|
||||||
if (in.read() == -1) |
|
||||||
return false; |
|
||||||
else { |
|
||||||
in.reset(); |
|
||||||
return true; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private InBoundHeaders getHeaders(HttpServletRequest request) { |
|
||||||
InBoundHeaders rh = new InBoundHeaders(); |
|
||||||
|
|
||||||
for (Enumeration<String> names = request.getHeaderNames(); names.hasMoreElements();) { |
|
||||||
String name = names.nextElement(); |
|
||||||
List<String> valueList = new LinkedList<String>(); |
|
||||||
for (Enumeration<String> values = request.getHeaders(name); values.hasMoreElements();) { |
|
||||||
valueList.add(values.nextElement()); |
|
||||||
} |
|
||||||
rh.put(name, valueList); |
|
||||||
} |
|
||||||
|
|
||||||
return rh; |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,366 +0,0 @@ |
|||||||
/* |
|
||||||
* $Header: /cvsroot/jdbforms/dbforms/src/org/dbforms/util/MultipartRequest.java,v 1.19 2005/02/19 21:26:32 hkollmann Exp $ |
|
||||||
* $Revision: 1.19 $ |
|
||||||
* $Date: 2005/02/19 21:26:32 $ |
|
||||||
* |
|
||||||
* DbForms - a Rapid Application Development Framework |
|
||||||
* Copyright (C) 2001 Joachim Peer <joepeer@excite.com> |
|
||||||
* |
|
||||||
* This library is free software; you can redistribute it and/or |
|
||||||
* modify it under the terms of the GNU Lesser General Public |
|
||||||
* License as published by the Free Software Foundation; either |
|
||||||
* version 2.1 of the License, or (at your option) any later version. |
|
||||||
* |
|
||||||
* This library is distributed in the hope that it will be useful, |
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
||||||
* Lesser General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU Lesser General Public |
|
||||||
* License along with this library; if not, write to the Free Software |
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.dbforms.util; |
|
||||||
|
|
||||||
import org.apache.commons.fileupload.DiskFileUpload; |
|
||||||
import org.apache.commons.fileupload.FileItem; |
|
||||||
import org.apache.commons.logging.Log; |
|
||||||
import org.apache.commons.logging.LogFactory; |
|
||||||
|
|
||||||
import java.io.File; |
|
||||||
import java.io.IOException; |
|
||||||
import java.io.InputStream; |
|
||||||
|
|
||||||
import java.util.Enumeration; |
|
||||||
import java.util.Hashtable; |
|
||||||
import java.util.Iterator; |
|
||||||
import java.util.List; |
|
||||||
import java.util.Vector; |
|
||||||
|
|
||||||
import jakarta.servlet.ServletRequest; |
|
||||||
import jakarta.servlet.ServletRequestWrapper; |
|
||||||
import jakarta.servlet.http.HttpServletRequest; |
|
||||||
import org.dbforms.util.external.FileUtil; |
|
||||||
|
|
||||||
import de.superx.util.multipart.support.DefaultMultipartHttpServletRequest; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* A utility class to handle <code>multipart/form-data</code> requests, the |
|
||||||
* kind of requests that support file uploads. This class emulates the interface
|
|
||||||
* of <code>HttpServletRequest</code>, making it familiar to use. It uses a |
|
||||||
* "push" model where any incoming files are read and saved directly to disk in |
|
||||||
* the constructor. If you wish to have more flexibility, e.g. write the files |
|
||||||
* to a database, use the "pull" model <code>MultipartParser</code> instead. |
|
||||||
* <p> |
|
||||||
* This class can receive arbitrarily large files (up to an artificial limit you |
|
||||||
* can set), and fairly efficiently too. It cannot handle nested data (multipart |
|
||||||
* content within multipart content) or internationalized content (such as non |
|
||||||
* Latin-1 filenames). |
|
||||||
* </p> |
|
||||||
* <p> |
|
||||||
* See the included <a href="upload.war">upload.war </a> for an example of how |
|
||||||
* to use this class. |
|
||||||
* <p> |
|
||||||
* The full file upload specification is contained in experimental RFC 1867, |
|
||||||
* available at <a href="http://www.ietf.org/rfc/rfc1867.txt" |
|
||||||
* http://www.ietf.org/rfc/rfc1867.txt </a>.
|
|
||||||
* </p> |
|
||||||
* <p> |
|
||||||
* PLEASE NOTE: this class uses Multipart Support Classes by Jason Hunter. |
|
||||||
* Copyright (C) 1998 by Jason Hunter. All rights reserved. |
|
||||||
* Use of this class is limited. Please see the LICENSE for more information. |
|
||||||
* Make sure that you project meets the requierements defined by Jason Hunter |
|
||||||
* respective O'reilly! |
|
||||||
* </p> |
|
||||||
* |
|
||||||
* @see MultipartParser |
|
||||||
* |
|
||||||
* @author Jason Hunter |
|
||||||
* @author Geoff Soutter |
|
||||||
* @author Joe Peer - _changed_ it for use in DbForms (i apologize) |
|
||||||
*/ |
|
||||||
/* Witt: am 28.05.2026 als Basis für gepatchte Datei nach 'src-patches' übernommen, Basis waren meine |
|
||||||
* lokalen 'dbforms_2.5_20050226' Sourcen */ |
|
||||||
public class MultipartRequest { |
|
||||||
private static Log logCat = LogFactory.getLog(MultipartRequest.class); // logging category
|
|
||||||
private Hashtable files = new Hashtable(); // name - UploadedFile
|
|
||||||
|
|
||||||
// for this class
|
|
||||||
//private File dir;
|
|
||||||
private Hashtable parameters = new Hashtable(); // name - Vector of values
|
|
||||||
|
|
||||||
/** |
|
||||||
* Constructs a new MultipartRequest to handle the specified request, |
|
||||||
* {saving any uploaded files to the given directory}, and limiting the |
|
||||||
* upload size to the specified length. If the content is too large, an |
|
||||||
* IOException is thrown. This constructor actually parses the |
|
||||||
* <tt>multipart/form-data</tt> and throws an IOException if there's any |
|
||||||
* problem reading or parsing the request. |
|
||||||
* |
|
||||||
* @param request |
|
||||||
* the servlet request. |
|
||||||
* @param maxPostSize |
|
||||||
* the maximum size of the POST content. |
|
||||||
* @exception IOException |
|
||||||
* if the uploaded content is larger than |
|
||||||
* <tt>maxPostSize</tt> or there's a problem reading or |
|
||||||
* parsing the request. |
|
||||||
*/ |
|
||||||
public MultipartRequest(HttpServletRequest request, |
|
||||||
int maxPostSize) |
|
||||||
throws IOException { |
|
||||||
// Sanity check values
|
|
||||||
if (request == null) { |
|
||||||
throw new IllegalArgumentException("request cannot be null"); |
|
||||||
} |
|
||||||
|
|
||||||
// Create a new file upload handler
|
|
||||||
DiskFileUpload upload = new DiskFileUpload(); |
|
||||||
|
|
||||||
// Set upload parameters
|
|
||||||
upload.setSizeMax(maxPostSize); |
|
||||||
|
|
||||||
String tmpDir = System.getProperty("java.io.tmpdir"); |
|
||||||
upload.setRepositoryPath(tmpDir); |
|
||||||
|
|
||||||
// Parse the request
|
|
||||||
try { |
|
||||||
// we initilize this list with 'null', as the following unwrapping code should do the work - contrary to the 'org.dbforms.util.MultipartRequest code, from which this is copied
|
|
||||||
List<FileItem> items = null; //upload.parseRequest(request);
|
|
||||||
|
|
||||||
if (items == null || items.size() == 0) { |
|
||||||
ServletRequest originalRequest = request; |
|
||||||
DefaultMultipartHttpServletRequest dmhsr = null; |
|
||||||
while (originalRequest instanceof ServletRequestWrapper) { |
|
||||||
if (originalRequest instanceof DefaultMultipartHttpServletRequest) { |
|
||||||
dmhsr = (DefaultMultipartHttpServletRequest) originalRequest; |
|
||||||
items = dmhsr.getFileItems(); |
|
||||||
break; |
|
||||||
} |
|
||||||
originalRequest = ((ServletRequestWrapper) originalRequest).getRequest(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
Iterator iter = items.iterator(); |
|
||||||
|
|
||||||
while (iter.hasNext()) { |
|
||||||
FileItem item = (FileItem) iter.next(); |
|
||||||
String name = item.getFieldName(); |
|
||||||
|
|
||||||
if (item.isFormField()) { |
|
||||||
String value = item.getString(); |
|
||||||
|
|
||||||
// plain parameters get allways into parameters structure
|
|
||||||
Vector existingValues = (Vector) parameters.get(name); |
|
||||||
|
|
||||||
if (existingValues == null) { |
|
||||||
existingValues = new Vector(); |
|
||||||
parameters.put(name, existingValues); |
|
||||||
} |
|
||||||
|
|
||||||
existingValues.addElement(value); |
|
||||||
} else { |
|
||||||
String fileName = item.getName(); |
|
||||||
|
|
||||||
if (!Util.isNull(fileName)) { |
|
||||||
File f = new File(fileName); |
|
||||||
// 2004-08-05-HKK/Dziugas Baltrunas:
|
|
||||||
// FileItem always returns the full pathname!
|
|
||||||
fileName = FileUtil.filename(f.getName()); |
|
||||||
|
|
||||||
// The part actually contained a file
|
|
||||||
// #changes by joe peer:
|
|
||||||
// we must delay storing the file-inputstream (into
|
|
||||||
// database, filesystem or whatever)
|
|
||||||
// until we know exactly what should happen with it
|
|
||||||
FileHolder fileHolder = new FileHolder(fileName, item); |
|
||||||
files.put(name, fileHolder); |
|
||||||
logCat.info("buffered and now added as " + name |
|
||||||
+ " the following fileHolder:" |
|
||||||
+ fileHolder.getFileName()); |
|
||||||
|
|
||||||
// #changes by joe peer:
|
|
||||||
// if a file parameter is not null it gets into the
|
|
||||||
// parameters structures as well
|
|
||||||
// this is important to provide a simple access to
|
|
||||||
// request (no distinction between files and plain
|
|
||||||
// params)
|
|
||||||
Vector existingValues = (Vector) parameters.get(name); |
|
||||||
|
|
||||||
if (existingValues == null) { |
|
||||||
existingValues = new Vector(); |
|
||||||
parameters.put(name, existingValues); |
|
||||||
} |
|
||||||
|
|
||||||
existingValues.addElement(fileName); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} catch (Exception e) { |
|
||||||
logCat.error("MultipartRequest", e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns the content type of the specified file (as supplied by the client |
|
||||||
* browser), or null if the file was not included in the upload. |
|
||||||
* |
|
||||||
* @param name |
|
||||||
* the file name. |
|
||||||
* @return the content type of the file. |
|
||||||
*/ |
|
||||||
public String getContentType(String name) { |
|
||||||
try { |
|
||||||
//#changed by joe peer
|
|
||||||
//UploadedFile file = (UploadedFile)files.get(name);
|
|
||||||
FileHolder filePart = (FileHolder) files.get(name); |
|
||||||
|
|
||||||
return filePart.getContentType(); // may be null
|
|
||||||
} catch (Exception e) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Returns a FilePart object for the specified file this method was added by |
|
||||||
* joe peer |
|
||||||
* |
|
||||||
* @param name |
|
||||||
* the file name. |
|
||||||
* @return a FilePart object for the named file. |
|
||||||
*/ |
|
||||||
public FileHolder getFileHolder(String name) { |
|
||||||
try { |
|
||||||
return (FileHolder) files.get(name); |
|
||||||
} catch (Exception e) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Returns a InputStream object for the specified file saved on the server's |
|
||||||
* filesystem, or null if the file was not included in the upload. |
|
||||||
* |
|
||||||
* @param name |
|
||||||
* the file name. |
|
||||||
* @return a InputStream object for the named file. |
|
||||||
*/ |
|
||||||
public InputStream getFileInputStream(String name) { |
|
||||||
try { |
|
||||||
//#changed by joe peer
|
|
||||||
//UploadedFile file = (UploadedFile)files.get(name);
|
|
||||||
FileHolder filePart = (FileHolder) files.get(name); |
|
||||||
|
|
||||||
return filePart.getInputStreamFromBuffer(); // may be null
|
|
||||||
} catch (Exception e) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Returns the names of all the uploaded files as an Enumeration of Strings. |
|
||||||
* It returns an empty Enumeration if there are no uploaded files. Each file |
|
||||||
* name is the name specified by the form, not by the user. |
|
||||||
* |
|
||||||
* @return the names of all the uploaded files as an Enumeration of Strings. |
|
||||||
*/ |
|
||||||
public Enumeration getFileNames() { |
|
||||||
return files.keys(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Returns the filesystem name of the specified file, or null if the file |
|
||||||
* was not included in the upload. A filesystem name is the name specified |
|
||||||
* by the user. It is also the name under which the file is actually saved. |
|
||||||
* |
|
||||||
* @param name |
|
||||||
* the file name. |
|
||||||
* @return the filesystem name of the file. |
|
||||||
*/ |
|
||||||
public String getFilesystemName(String name) { |
|
||||||
try { |
|
||||||
//#changed by joe peer
|
|
||||||
//UploadedFile file = (UploadedFile)files.get(name);
|
|
||||||
FileHolder filePart = (FileHolder) files.get(name); |
|
||||||
|
|
||||||
return filePart.getFileName(); // may be null
|
|
||||||
} catch (Exception e) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Returns the value of the named parameter as a String, or null if the |
|
||||||
* parameter was not sent or was sent without a value. The value is |
|
||||||
* guaranteed to be in its normal, decoded form. If the parameter has |
|
||||||
* multiple values, only the last one is returned (for backward |
|
||||||
* compatibility). For parameters with multiple values, it's possible the |
|
||||||
* last "value" may be null. |
|
||||||
* |
|
||||||
* @param name |
|
||||||
* the parameter name. |
|
||||||
* @return the parameter value. |
|
||||||
*/ |
|
||||||
public String getParameter(String name) { |
|
||||||
try { |
|
||||||
Vector values = (Vector) parameters.get(name); |
|
||||||
|
|
||||||
if ((values == null) || (values.size() == 0)) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
String value = (String) values.elementAt(0); |
|
||||||
|
|
||||||
return value; |
|
||||||
} catch (Exception e) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Returns the names of all the parameters as an Enumeration of Strings. It |
|
||||||
* returns an empty Enumeration if there are no parameters. |
|
||||||
* |
|
||||||
* @return the names of all the parameters as an Enumeration of Strings. |
|
||||||
*/ |
|
||||||
public Enumeration getParameterNames() { |
|
||||||
return parameters.keys(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Returns the values of the named parameter as a String array, or null if |
|
||||||
* the parameter was not sent. The array has one entry for each parameter |
|
||||||
* field sent. If any field was sent without a value that entry is stored in |
|
||||||
* the array as a null. The values are guaranteed to be in their normal, |
|
||||||
* decoded form. A single value is returned as a one-element array. |
|
||||||
* |
|
||||||
* @param name |
|
||||||
* the parameter name. |
|
||||||
* @return the parameter values. |
|
||||||
*/ |
|
||||||
public String[] getParameterValues(String name) { |
|
||||||
try { |
|
||||||
Vector values = (Vector) parameters.get(name); |
|
||||||
|
|
||||||
if ((values == null) || (values.size() == 0)) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
String[] valuesArray = new String[values.size()]; |
|
||||||
values.copyInto(valuesArray); |
|
||||||
|
|
||||||
return valuesArray; |
|
||||||
} catch (Exception e) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,699 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2002-2016 the original author or authors. |
|
||||||
* |
|
||||||
* 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 |
|
||||||
* |
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
/* taken/copied from 'spring-security-web-6.2.8.jar' as a base for patching */ |
|
||||||
|
|
||||||
package org.springframework.security.web.util; |
|
||||||
|
|
||||||
import java.io.IOException; |
|
||||||
import java.io.PrintWriter; |
|
||||||
import java.util.Locale; |
|
||||||
|
|
||||||
import jakarta.servlet.ServletOutputStream; |
|
||||||
import jakarta.servlet.WriteListener; |
|
||||||
import jakarta.servlet.http.HttpServletResponse; |
|
||||||
import jakarta.servlet.http.HttpServletResponseWrapper; |
|
||||||
|
|
||||||
/** |
|
||||||
* Base class for response wrappers which encapsulate the logic for handling an event when |
|
||||||
* the {@link jakarta.servlet.http.HttpServletResponse} is committed. |
|
||||||
* |
|
||||||
* @author Rob Winch |
|
||||||
* @since 4.0.2 |
|
||||||
*/ |
|
||||||
public abstract class OnCommittedResponseWrapper extends HttpServletResponseWrapper { |
|
||||||
|
|
||||||
private boolean disableOnCommitted; |
|
||||||
|
|
||||||
/** |
|
||||||
* The Content-Length response header. If this is greater than 0, then once |
|
||||||
* {@link #contentWritten} is larger than or equal the response is considered |
|
||||||
* committed. |
|
||||||
*/ |
|
||||||
private long contentLength; |
|
||||||
|
|
||||||
/** |
|
||||||
* The size of data written to the response body. The field will only be updated when |
|
||||||
* {@link #disableOnCommitted} is false. |
|
||||||
*/ |
|
||||||
private long contentWritten; |
|
||||||
|
|
||||||
/** |
|
||||||
* @param response the response to be wrapped |
|
||||||
*/ |
|
||||||
public OnCommittedResponseWrapper(HttpServletResponse response) { |
|
||||||
super(response); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void addHeader(String name, String value) { |
|
||||||
checkContentLengthHeader(name, value); |
|
||||||
super.addHeader(name, value); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void addIntHeader(String name, int value) { |
|
||||||
checkContentLengthHeader(name, value); |
|
||||||
super.addIntHeader(name, value); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setHeader(String name, String value) { |
|
||||||
checkContentLengthHeader(name, value); |
|
||||||
super.setHeader(name, value); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setIntHeader(String name, int value) { |
|
||||||
checkContentLengthHeader(name, value); |
|
||||||
super.setIntHeader(name, value); |
|
||||||
} |
|
||||||
|
|
||||||
private void checkContentLengthHeader(String name, int value) { |
|
||||||
if ("Content-Length".equalsIgnoreCase(name)) { |
|
||||||
setContentLength(value); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private void checkContentLengthHeader(String name, String value) { |
|
||||||
if ("Content-Length".equalsIgnoreCase(name)) { |
|
||||||
setContentLength(Long.parseLong(value)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setContentLength(int len) { |
|
||||||
setContentLength((long) len); |
|
||||||
super.setContentLength(len); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setContentLengthLong(long len) { |
|
||||||
setContentLength(len); |
|
||||||
super.setContentLengthLong(len); |
|
||||||
} |
|
||||||
|
|
||||||
private void setContentLength(long len) { |
|
||||||
this.contentLength = len; |
|
||||||
checkContentLength(0); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Invoke this method to disable invoking |
|
||||||
* {@link OnCommittedResponseWrapper#onResponseCommitted()} when the |
|
||||||
* {@link jakarta.servlet.http.HttpServletResponse} is committed. This can be useful |
|
||||||
* in the event that Async Web Requests are made. |
|
||||||
*/ |
|
||||||
protected void disableOnResponseCommitted() { |
|
||||||
this.disableOnCommitted = true; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns true if {@link #onResponseCommitted()} will be invoked when the response is |
|
||||||
* committed, else false. |
|
||||||
* @return if {@link #onResponseCommitted()} is enabled |
|
||||||
*/ |
|
||||||
protected boolean isDisableOnResponseCommitted() { |
|
||||||
return this.disableOnCommitted; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Implement the logic for handling the |
|
||||||
* {@link jakarta.servlet.http.HttpServletResponse} being committed |
|
||||||
*/ |
|
||||||
protected abstract void onResponseCommitted(); |
|
||||||
|
|
||||||
/** |
|
||||||
* Makes sure {@link OnCommittedResponseWrapper#onResponseCommitted()} is invoked |
|
||||||
* before calling the superclass <code>sendError()</code> |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public final void sendError(int sc) throws IOException { |
|
||||||
doOnResponseCommitted(); |
|
||||||
super.sendError(sc); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Makes sure {@link OnCommittedResponseWrapper#onResponseCommitted()} is invoked |
|
||||||
* before calling the superclass <code>sendError()</code> |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public final void sendError(int sc, String msg) throws IOException { |
|
||||||
doOnResponseCommitted(); |
|
||||||
super.sendError(sc, msg); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Makes sure {@link OnCommittedResponseWrapper#onResponseCommitted()} is invoked |
|
||||||
* before calling the superclass <code>sendRedirect()</code> |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public final void sendRedirect(String location) throws IOException { |
|
||||||
doOnResponseCommitted(); |
|
||||||
super.sendRedirect(location); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Makes sure {@link OnCommittedResponseWrapper#onResponseCommitted()} is invoked |
|
||||||
* before calling the calling <code>getOutputStream().close()</code> or |
|
||||||
* <code>getOutputStream().flush()</code> |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public ServletOutputStream getOutputStream() throws IOException { |
|
||||||
return new SaveContextServletOutputStream(super.getOutputStream()); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Makes sure {@link OnCommittedResponseWrapper#onResponseCommitted()} is invoked |
|
||||||
* before calling the <code>getWriter().close()</code> or |
|
||||||
* <code>getWriter().flush()</code> |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public PrintWriter getWriter() throws IOException { |
|
||||||
return new SaveContextPrintWriter(super.getWriter()); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Makes sure {@link OnCommittedResponseWrapper#onResponseCommitted()} is invoked |
|
||||||
* before calling the superclass <code>flushBuffer()</code> |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public void flushBuffer() throws IOException { |
|
||||||
doOnResponseCommitted(); |
|
||||||
super.flushBuffer(); |
|
||||||
} |
|
||||||
|
|
||||||
private void trackContentLength(boolean content) { |
|
||||||
if (!this.disableOnCommitted) { |
|
||||||
checkContentLength(content ? 4 : 5); // TODO Localization
|
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private void trackContentLength(char content) { |
|
||||||
if (!this.disableOnCommitted) { |
|
||||||
checkContentLength(1); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private void trackContentLength(Object content) { |
|
||||||
if (!this.disableOnCommitted) { |
|
||||||
trackContentLength(String.valueOf(content)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private void trackContentLength(byte[] content) { |
|
||||||
if (!this.disableOnCommitted) { |
|
||||||
checkContentLength((content != null) ? content.length : 0); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private void trackContentLength(char[] content) { |
|
||||||
if (!this.disableOnCommitted) { |
|
||||||
checkContentLength((content != null) ? content.length : 0); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private void trackContentLength(int content) { |
|
||||||
if (!this.disableOnCommitted) { |
|
||||||
trackContentLength(String.valueOf(content)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private void trackContentLength(float content) { |
|
||||||
if (!this.disableOnCommitted) { |
|
||||||
trackContentLength(String.valueOf(content)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private void trackContentLength(double content) { |
|
||||||
if (!this.disableOnCommitted) { |
|
||||||
trackContentLength(String.valueOf(content)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private void trackContentLengthLn() { |
|
||||||
if (!this.disableOnCommitted) { |
|
||||||
trackContentLength("\r\n"); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private void trackContentLength(String content) { |
|
||||||
if (!this.disableOnCommitted) { |
|
||||||
int contentLength = (content != null) ? content.length() : 4; |
|
||||||
checkContentLength(contentLength); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Adds the contentLengthToWrite to the total contentWritten size and checks to see if |
|
||||||
* the response should be written. |
|
||||||
* @param contentLengthToWrite the size of the content that is about to be written. |
|
||||||
*/ |
|
||||||
private void checkContentLength(long contentLengthToWrite) { |
|
||||||
this.contentWritten += contentLengthToWrite; |
|
||||||
boolean isBodyFullyWritten = this.contentLength > 0 && this.contentWritten >= this.contentLength; |
|
||||||
int bufferSize = getBufferSize(); |
|
||||||
boolean requiresFlush = bufferSize > 0 && this.contentWritten >= bufferSize; |
|
||||||
if (isBodyFullyWritten || requiresFlush) { |
|
||||||
doOnResponseCommitted(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Calls <code>onResponseCommmitted()</code> with the current contents as long as |
|
||||||
* {@link #disableOnResponseCommitted()} was not invoked. |
|
||||||
*/ |
|
||||||
private void doOnResponseCommitted() { |
|
||||||
if (!this.disableOnCommitted) { |
|
||||||
onResponseCommitted(); |
|
||||||
disableOnResponseCommitted(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Ensures {@link OnCommittedResponseWrapper#onResponseCommitted()} is invoked before |
|
||||||
* calling the prior to methods that commit the response. We delegate all methods to |
|
||||||
* the original {@link java.io.PrintWriter} to ensure that the behavior is as close to |
|
||||||
* the original {@link java.io.PrintWriter} as possible. See SEC-2039 |
|
||||||
* |
|
||||||
* @author Rob Winch |
|
||||||
*/ |
|
||||||
private class SaveContextPrintWriter extends PrintWriter { |
|
||||||
|
|
||||||
private final PrintWriter delegate; |
|
||||||
|
|
||||||
SaveContextPrintWriter(PrintWriter delegate) { |
|
||||||
super(delegate); |
|
||||||
this.delegate = delegate; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void flush() { |
|
||||||
doOnResponseCommitted(); |
|
||||||
this.delegate.flush(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void close() { |
|
||||||
doOnResponseCommitted(); |
|
||||||
this.delegate.close(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean equals(Object obj) { |
|
||||||
return this.delegate.equals(obj); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public int hashCode() { |
|
||||||
return this.delegate.hashCode(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public String toString() { |
|
||||||
return getClass().getName() + "[delegate=" + this.delegate.toString() + "]"; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean checkError() { |
|
||||||
return this.delegate.checkError(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void write(int c) { |
|
||||||
trackContentLength(c); |
|
||||||
this.delegate.write(c); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void write(char[] buf, int off, int len) { |
|
||||||
checkContentLength(len); |
|
||||||
this.delegate.write(buf, off, len); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void write(char[] buf) { |
|
||||||
trackContentLength(buf); |
|
||||||
this.delegate.write(buf); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void write(String s, int off, int len) { |
|
||||||
checkContentLength(len); |
|
||||||
this.delegate.write(s, off, len); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void write(String s) { |
|
||||||
trackContentLength(s); |
|
||||||
this.delegate.write(s); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void print(boolean b) { |
|
||||||
trackContentLength(b); |
|
||||||
this.delegate.print(b); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void print(char c) { |
|
||||||
trackContentLength(c); |
|
||||||
this.delegate.print(c); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void print(int i) { |
|
||||||
trackContentLength(i); |
|
||||||
this.delegate.print(i); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void print(long l) { |
|
||||||
trackContentLength(l); |
|
||||||
this.delegate.print(l); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void print(float f) { |
|
||||||
trackContentLength(f); |
|
||||||
this.delegate.print(f); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void print(double d) { |
|
||||||
trackContentLength(d); |
|
||||||
this.delegate.print(d); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void print(char[] s) { |
|
||||||
trackContentLength(s); |
|
||||||
this.delegate.print(s); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void print(String s) { |
|
||||||
trackContentLength(s); |
|
||||||
this.delegate.print(s); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void print(Object obj) { |
|
||||||
trackContentLength(obj); |
|
||||||
this.delegate.print(obj); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void println() { |
|
||||||
trackContentLengthLn(); |
|
||||||
this.delegate.println(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void println(boolean x) { |
|
||||||
trackContentLength(x); |
|
||||||
trackContentLengthLn(); |
|
||||||
this.delegate.println(x); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void println(char x) { |
|
||||||
trackContentLength(x); |
|
||||||
trackContentLengthLn(); |
|
||||||
this.delegate.println(x); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void println(int x) { |
|
||||||
trackContentLength(x); |
|
||||||
trackContentLengthLn(); |
|
||||||
this.delegate.println(x); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void println(long x) { |
|
||||||
trackContentLength(x); |
|
||||||
trackContentLengthLn(); |
|
||||||
this.delegate.println(x); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void println(float x) { |
|
||||||
trackContentLength(x); |
|
||||||
trackContentLengthLn(); |
|
||||||
this.delegate.println(x); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void println(double x) { |
|
||||||
trackContentLength(x); |
|
||||||
trackContentLengthLn(); |
|
||||||
this.delegate.println(x); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void println(char[] x) { |
|
||||||
trackContentLength(x); |
|
||||||
trackContentLengthLn(); |
|
||||||
this.delegate.println(x); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void println(String x) { |
|
||||||
trackContentLength(x); |
|
||||||
trackContentLengthLn(); |
|
||||||
this.delegate.println(x); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void println(Object x) { |
|
||||||
trackContentLength(x); |
|
||||||
trackContentLengthLn(); |
|
||||||
this.delegate.println(x); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public PrintWriter printf(String format, Object... args) { |
|
||||||
return this.delegate.printf(format, args); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public PrintWriter printf(Locale l, String format, Object... args) { |
|
||||||
return this.delegate.printf(l, format, args); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public PrintWriter format(String format, Object... args) { |
|
||||||
return this.delegate.format(format, args); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public PrintWriter format(Locale l, String format, Object... args) { |
|
||||||
return this.delegate.format(l, format, args); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public PrintWriter append(CharSequence csq) { |
|
||||||
checkContentLength(csq.length()); |
|
||||||
return this.delegate.append(csq); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public PrintWriter append(CharSequence csq, int start, int end) { |
|
||||||
checkContentLength(end - start); |
|
||||||
return this.delegate.append(csq, start, end); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public PrintWriter append(char c) { |
|
||||||
trackContentLength(c); |
|
||||||
return this.delegate.append(c); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Ensures{@link OnCommittedResponseWrapper#onResponseCommitted()} is invoked before |
|
||||||
* calling methods that commit the response. We delegate all methods to the original |
|
||||||
* {@link jakarta.servlet.ServletOutputStream} to ensure that the behavior is as close |
|
||||||
* to the original {@link jakarta.servlet.ServletOutputStream} as possible. See |
|
||||||
* SEC-2039 |
|
||||||
* |
|
||||||
* @author Rob Winch |
|
||||||
*/ |
|
||||||
private class SaveContextServletOutputStream extends ServletOutputStream { |
|
||||||
|
|
||||||
private final ServletOutputStream delegate; |
|
||||||
|
|
||||||
SaveContextServletOutputStream(ServletOutputStream delegate) { |
|
||||||
this.delegate = delegate; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void write(int b) throws IOException { |
|
||||||
trackContentLength(b); |
|
||||||
this.delegate.write(b); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void flush() throws IOException { |
|
||||||
doOnResponseCommitted(); |
|
||||||
this.delegate.flush(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void close() throws IOException { |
|
||||||
doOnResponseCommitted(); |
|
||||||
this.delegate.close(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void print(boolean b) throws IOException { |
|
||||||
trackContentLength(b); |
|
||||||
this.delegate.print(b); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void print(char c) throws IOException { |
|
||||||
trackContentLength(c); |
|
||||||
this.delegate.print(c); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void print(double d) throws IOException { |
|
||||||
trackContentLength(d); |
|
||||||
this.delegate.print(d); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void print(float f) throws IOException { |
|
||||||
trackContentLength(f); |
|
||||||
this.delegate.print(f); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void print(int i) throws IOException { |
|
||||||
trackContentLength(i); |
|
||||||
this.delegate.print(i); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void print(long l) throws IOException { |
|
||||||
trackContentLength(l); |
|
||||||
this.delegate.print(l); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void print(String s) throws IOException { |
|
||||||
trackContentLength(s); |
|
||||||
this.delegate.print(s); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void println() throws IOException { |
|
||||||
trackContentLengthLn(); |
|
||||||
this.delegate.println(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void println(boolean b) throws IOException { |
|
||||||
trackContentLength(b); |
|
||||||
trackContentLengthLn(); |
|
||||||
this.delegate.println(b); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void println(char c) throws IOException { |
|
||||||
trackContentLength(c); |
|
||||||
trackContentLengthLn(); |
|
||||||
this.delegate.println(c); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void println(double d) throws IOException { |
|
||||||
trackContentLength(d); |
|
||||||
trackContentLengthLn(); |
|
||||||
this.delegate.println(d); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void println(float f) throws IOException { |
|
||||||
trackContentLength(f); |
|
||||||
trackContentLengthLn(); |
|
||||||
this.delegate.println(f); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void println(int i) throws IOException { |
|
||||||
trackContentLength(i); |
|
||||||
trackContentLengthLn(); |
|
||||||
this.delegate.println(i); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void println(long l) throws IOException { |
|
||||||
trackContentLength(l); |
|
||||||
trackContentLengthLn(); |
|
||||||
this.delegate.println(l); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void println(String s) throws IOException { |
|
||||||
trackContentLength(s); |
|
||||||
trackContentLengthLn(); |
|
||||||
this.delegate.println(s); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void write(byte[] b) throws IOException { |
|
||||||
trackContentLength(b); |
|
||||||
this.delegate.write(b); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void write(byte[] b, int off, int len) throws IOException { |
|
||||||
checkContentLength(len); |
|
||||||
this.delegate.write(b, off, len); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean isReady() { |
|
||||||
return this.delegate.isReady(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setWriteListener(WriteListener writeListener) { |
|
||||||
this.delegate.setWriteListener(writeListener); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean equals(Object obj) { |
|
||||||
return this.delegate.equals(obj); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public int hashCode() { |
|
||||||
return this.delegate.hashCode(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public String toString() { |
|
||||||
return getClass().getName() + "[delegate=" + this.delegate.toString() + "]"; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
Can't render this file because it is too large.
|
File diff suppressed because it is too large
Load Diff
@ -1,11 +0,0 @@ |
|||||||
package de.superx.bianalysis.service; |
|
||||||
|
|
||||||
public class IllegalMetaDataOperation extends Exception { |
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L; |
|
||||||
|
|
||||||
public IllegalMetaDataOperation(String message) { |
|
||||||
super(message); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,110 +0,0 @@ |
|||||||
package de.superx.db.export; |
|
||||||
|
|
||||||
import java.io.File; |
|
||||||
import java.io.FileOutputStream; |
|
||||||
import java.io.IOException; |
|
||||||
import java.io.OutputStream; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
import org.jdom2.Document; |
|
||||||
import org.jdom2.Element; |
|
||||||
import org.jdom2.output.Format; |
|
||||||
import org.jdom2.output.XMLOutputter; |
|
||||||
import org.springframework.stereotype.Component; |
|
||||||
|
|
||||||
/** |
|
||||||
* Writes an {@link ExportConfig} to XML, producing the same format |
|
||||||
* that {@link ExportConfigReader} can parse. |
|
||||||
* |
|
||||||
* <p>Example output: |
|
||||||
* <pre>{@code |
|
||||||
* <export-config> |
|
||||||
* <group name="my_group" schema="staging"> |
|
||||||
* <filter column="tid" source="SELECT tid FROM organigramm"/> |
|
||||||
* <table column="id" columns="id, name" orderBy="name ASC">my_table</table> |
|
||||||
* </group> |
|
||||||
* </export-config> |
|
||||||
* }</pre> |
|
||||||
*/ |
|
||||||
@Component |
|
||||||
public class ExportConfigWriter { |
|
||||||
|
|
||||||
/** |
|
||||||
* Write the config to a file. |
|
||||||
*/ |
|
||||||
public void write(ExportConfig config, File outputFile) throws IOException { |
|
||||||
try (FileOutputStream fos = new FileOutputStream(outputFile)) { |
|
||||||
write(config, fos); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Write the config to an output stream. |
|
||||||
*/ |
|
||||||
public void write(ExportConfig config, OutputStream out) throws IOException { |
|
||||||
Document doc = buildDocument(config); |
|
||||||
XMLOutputter outputter = new XMLOutputter( |
|
||||||
Format.getPrettyFormat().setEncoding("UTF-8")); |
|
||||||
outputter.output(doc, out); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Build the JDOM2 Document representing the config. |
|
||||||
*/ |
|
||||||
public Document buildDocument(ExportConfig config) { |
|
||||||
Document doc = new Document(); |
|
||||||
Element root = new Element("export-config"); |
|
||||||
doc.setRootElement(root); |
|
||||||
|
|
||||||
for (ExportGroup group : config.getGroups()) { |
|
||||||
root.addContent(buildGroupElement(group)); |
|
||||||
} |
|
||||||
|
|
||||||
return doc; |
|
||||||
} |
|
||||||
|
|
||||||
private Element buildGroupElement(ExportGroup group) { |
|
||||||
Element groupEl = new Element("group"); |
|
||||||
groupEl.setAttribute("name", group.getName()); |
|
||||||
|
|
||||||
if (group.getSchema() != null) { |
|
||||||
groupEl.setAttribute("schema", group.getSchema()); |
|
||||||
} |
|
||||||
|
|
||||||
if (group.hasFilter()) { |
|
||||||
Element filterEl = new Element("filter"); |
|
||||||
filterEl.setAttribute("column", group.getFilterColumn()); |
|
||||||
filterEl.setAttribute("source", group.getFilterSource()); |
|
||||||
groupEl.addContent(filterEl); |
|
||||||
} |
|
||||||
|
|
||||||
for (ExportTableConfig tableConfig : group.getTableConfigs()) { |
|
||||||
groupEl.addContent(buildTableElement(tableConfig)); |
|
||||||
} |
|
||||||
|
|
||||||
return groupEl; |
|
||||||
} |
|
||||||
|
|
||||||
private Element buildTableElement(ExportTableConfig tableConfig) { |
|
||||||
Element tableEl = new Element("table"); |
|
||||||
tableEl.setText(tableConfig.getTableName()); |
|
||||||
|
|
||||||
if (tableConfig.getFilterColumn() != null) { |
|
||||||
tableEl.setAttribute("column", tableConfig.getFilterColumn()); |
|
||||||
} |
|
||||||
|
|
||||||
if (tableConfig.hasFilterSource()) { |
|
||||||
tableEl.setAttribute("source", tableConfig.getFilterSource()); |
|
||||||
} |
|
||||||
|
|
||||||
if (tableConfig.hasColumns()) { |
|
||||||
tableEl.setAttribute("columns", String.join(", ", tableConfig.getColumns())); |
|
||||||
} |
|
||||||
|
|
||||||
if (tableConfig.hasOrderBy()) { |
|
||||||
tableEl.setAttribute("orderBy", tableConfig.getOrderBy()); |
|
||||||
} |
|
||||||
|
|
||||||
return tableEl; |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,11 +0,0 @@ |
|||||||
package de.superx.dbt; |
|
||||||
|
|
||||||
public enum DbtAction { |
|
||||||
BUILD, |
|
||||||
TEST, |
|
||||||
GENERATE_DOCS, |
|
||||||
STAGING_TABLES, |
|
||||||
SQLFLUFF_LINT, |
|
||||||
NODE_COUNT_BUILD, |
|
||||||
NODE_COUNT_TEST |
|
||||||
} |
|
||||||
@ -1,8 +0,0 @@ |
|||||||
package de.superx.dbt; |
|
||||||
|
|
||||||
public enum DbtExecutionState { |
|
||||||
ACTIVE, // dbt-Lauf ist noch nicht beendet - evtl. braucht es mehr als nur "active"!?
|
|
||||||
SUCCESS, // dbt-Lauf wurde erfolgreich abgeschlossen
|
|
||||||
FAILURE, // dbt-Lauf endete in einem Fehler
|
|
||||||
TIMEOUT |
|
||||||
} |
|
||||||
@ -0,0 +1,59 @@ |
|||||||
|
package de.superx.dbt; |
||||||
|
|
||||||
|
import java.util.regex.Matcher; |
||||||
|
import java.util.regex.Pattern; |
||||||
|
|
||||||
|
public class DbtMetrics { |
||||||
|
|
||||||
|
private static final String METRICS_LINE = "Found (\\d+) models, (\\d+) snapshots, (\\d+) data tests, (\\d+) seeds," |
||||||
|
+ " (\\d+) sources, (\\d+) macros"; |
||||||
|
private static final Pattern METRICS_PATTERN = Pattern.compile(METRICS_LINE); |
||||||
|
|
||||||
|
private int models; |
||||||
|
private int snapshots; |
||||||
|
private int tests; |
||||||
|
private int seeds; |
||||||
|
private int sources; |
||||||
|
private int macros; |
||||||
|
|
||||||
|
public DbtMetrics(String metricLine) { |
||||||
|
Matcher metricsMatcher = METRICS_PATTERN.matcher(metricLine); |
||||||
|
if (metricsMatcher.find()) { |
||||||
|
models = Integer.parseInt(metricsMatcher.group(1)); |
||||||
|
snapshots = Integer.parseInt(metricsMatcher.group(2)); |
||||||
|
tests = Integer.parseInt(metricsMatcher.group(3)); |
||||||
|
seeds = Integer.parseInt(metricsMatcher.group(4)); |
||||||
|
sources = Integer.parseInt(metricsMatcher.group(5)); |
||||||
|
macros = Integer.parseInt(metricsMatcher.group(6)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public int getExecCount(boolean isTests) { |
||||||
|
return isTests ? tests : models + snapshots + seeds; |
||||||
|
} |
||||||
|
|
||||||
|
public int getModels() { |
||||||
|
return models; |
||||||
|
} |
||||||
|
|
||||||
|
public int getSnapshots() { |
||||||
|
return snapshots; |
||||||
|
} |
||||||
|
|
||||||
|
public int getTests() { |
||||||
|
return tests; |
||||||
|
} |
||||||
|
|
||||||
|
public int getSeeds() { |
||||||
|
return seeds; |
||||||
|
} |
||||||
|
|
||||||
|
public int getSources() { |
||||||
|
return sources; |
||||||
|
} |
||||||
|
|
||||||
|
public int getMacros() { |
||||||
|
return macros; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -1,7 +0,0 @@ |
|||||||
package de.superx.dbt; |
|
||||||
|
|
||||||
public class DbtPermissionException extends Exception { |
|
||||||
DbtPermissionException(String message, Throwable cause) { |
|
||||||
super(message, cause); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,443 +0,0 @@ |
|||||||
package de.superx.dbt; |
|
||||||
|
|
||||||
import java.io.BufferedReader; |
|
||||||
import java.io.IOException; |
|
||||||
import java.io.InputStream; |
|
||||||
import java.io.InputStreamReader; |
|
||||||
import java.nio.file.Path; |
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.Arrays; |
|
||||||
import java.util.List; |
|
||||||
import java.util.Map; |
|
||||||
import java.util.Optional; |
|
||||||
import java.util.concurrent.Callable; |
|
||||||
import java.util.concurrent.CompletableFuture; |
|
||||||
import java.util.stream.Collectors; |
|
||||||
|
|
||||||
import org.apache.commons.lang.SystemUtils; |
|
||||||
import org.slf4j.Logger; |
|
||||||
import org.slf4j.LoggerFactory; |
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode; |
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper; |
|
||||||
|
|
||||||
public final class DbtRun implements Callable<DbtRunResult> { |
|
||||||
|
|
||||||
static Logger logger = LoggerFactory.getLogger(DbtRun.class); |
|
||||||
private static final boolean isLinux = SystemUtils.IS_OS_LINUX; |
|
||||||
|
|
||||||
private final DbtRunRequest request; |
|
||||||
private final Map<String, String> environment; |
|
||||||
private final Path projectPath; |
|
||||||
|
|
||||||
public Process process; |
|
||||||
|
|
||||||
DbtRun(DbtRunRequest request, Map<String, String> environment, Path projectPath) { |
|
||||||
this.request = request; |
|
||||||
this.environment = environment; |
|
||||||
this.projectPath = projectPath; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public DbtRunResult call() throws Exception { |
|
||||||
return execute(); |
|
||||||
} |
|
||||||
|
|
||||||
private DbtRunResult execute() { |
|
||||||
return switch (request.action()) { |
|
||||||
case BUILD -> runDbtCommand(createBuildCommand()); |
|
||||||
case TEST -> runDbtCommand(createTestCommand()); |
|
||||||
case NODE_COUNT_BUILD -> nodeCount(true); |
|
||||||
case NODE_COUNT_TEST -> nodeCount(false); |
|
||||||
case GENERATE_DOCS -> generateDocs(); |
|
||||||
case STAGING_TABLES -> findDbtStagingTablesForSelection(); |
|
||||||
case SQLFLUFF_LINT -> lintDbtModelsUsingSQLFluff(); |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
private List<String> createTestCommand() { |
|
||||||
List<String> baseCommand = new ArrayList<>(DbtUtils.getDbtCommandBase()); |
|
||||||
baseCommand.addAll(Arrays.asList( "--log-format", "json", "--no-use-colors", "test")); |
|
||||||
if(request.select() != null && !request.select().isBlank()) { |
|
||||||
baseCommand.add("--select"); |
|
||||||
baseCommand.add(request.select()); |
|
||||||
} |
|
||||||
return baseCommand; |
|
||||||
} |
|
||||||
|
|
||||||
private List<String> createBuildCommand() { |
|
||||||
List<String> baseCommand = new ArrayList<>(DbtUtils.getDbtCommandBase()); |
|
||||||
baseCommand.addAll(Arrays.asList( |
|
||||||
"--log-format", "json", |
|
||||||
"--no-use-colors", |
|
||||||
"build", |
|
||||||
"--resource-types", |
|
||||||
"snapshot", |
|
||||||
"seed", |
|
||||||
"model" |
|
||||||
)); |
|
||||||
|
|
||||||
if(request.select() != null && !request.select().isBlank()) { |
|
||||||
baseCommand.add("--select"); |
|
||||||
baseCommand.add(request.select()); |
|
||||||
} |
|
||||||
return baseCommand; |
|
||||||
} |
|
||||||
|
|
||||||
public DbtRunResult runDbtCommand(List<String> pbCommand) { |
|
||||||
DbtRunResult result = new DbtRunResult(); |
|
||||||
logger.info(Arrays.toString(pbCommand.toArray())); |
|
||||||
ProcessBuilder p = new ProcessBuilder(pbCommand).directory(projectPath.toFile()); |
|
||||||
p.environment().putAll(this.environment); |
|
||||||
p.redirectErrorStream(false); |
|
||||||
List<JsonNode> dbtLog = new ArrayList<>(); |
|
||||||
JsonNode stats = null; |
|
||||||
try { |
|
||||||
int progress = 0; |
|
||||||
|
|
||||||
process = p.start(); |
|
||||||
logger.info("ProcessBuilder start"); |
|
||||||
logger.info("PYTHONUSERBASE: " + p.environment().get("PYTHONUSERBASE")); |
|
||||||
logger.info("PATH: " + p.environment().get((isLinux) ? "PATH" : "Path")); |
|
||||||
|
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); |
|
||||||
CompletableFuture<String> errFuture = readOutStream(process.getErrorStream()); |
|
||||||
|
|
||||||
var line = ""; |
|
||||||
ObjectMapper objectMapper = new ObjectMapper(); |
|
||||||
while ((line = reader.readLine()) != null) { |
|
||||||
JsonNode node = objectMapper.readTree(line.getBytes()); |
|
||||||
logger.info(node.get("info").get("msg").asText()); |
|
||||||
JsonNode data = node.get("data"); |
|
||||||
if (data.get("stats") != null) { |
|
||||||
stats = node; |
|
||||||
} else { |
|
||||||
if (data.has("index")) { |
|
||||||
progress = Math.max(progress, data.get("index").asInt()); |
|
||||||
if(request.progressCallback() != null) { |
|
||||||
request.progressCallback().accept(Integer.valueOf(progress)); |
|
||||||
} |
|
||||||
} |
|
||||||
dbtLog.add(node); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
int exitCode = process.waitFor(); |
|
||||||
String error = errFuture.join(); |
|
||||||
|
|
||||||
result.setErrorMessages(getErrorMessages(dbtLog, error)); |
|
||||||
result.setState(getExecutionState(stats)); |
|
||||||
result.setExitCode(Integer.valueOf(exitCode)); |
|
||||||
} catch (Exception e) { |
|
||||||
logger.error("Couldn't start dbt run!", e); |
|
||||||
result.setErrorMessages(List.of(e.getMessage())); |
|
||||||
result.setState(DbtExecutionState.FAILURE); |
|
||||||
} |
|
||||||
return result; |
|
||||||
} |
|
||||||
|
|
||||||
public DbtRunResult generateDocs() { |
|
||||||
DbtRunResult result = new DbtRunResult(); |
|
||||||
try { |
|
||||||
List<String> pbCommand = new ArrayList<>(DbtUtils.getDbtCommandBase()); |
|
||||||
pbCommand.addAll(Arrays.asList("--no-use-colors", "docs", "generate")); |
|
||||||
if(request.select() != null && !request.select().isBlank()) { |
|
||||||
pbCommand.add("--select"); |
|
||||||
pbCommand.add(request.select()); |
|
||||||
} |
|
||||||
ProcessBuilder pb = new ProcessBuilder(pbCommand).directory(projectPath.toFile()); |
|
||||||
pb.environment().putAll(environment); |
|
||||||
pb.redirectErrorStream(true); |
|
||||||
Process p = pb.start(); |
|
||||||
final InputStream stdoutInputStream = p.getInputStream(); |
|
||||||
final BufferedReader stdoutReader = |
|
||||||
new BufferedReader(new InputStreamReader(stdoutInputStream)); |
|
||||||
String line = null; |
|
||||||
while ((line = stdoutReader.readLine()) != null) { |
|
||||||
logger.info(line); |
|
||||||
} |
|
||||||
result.setState(DbtExecutionState.SUCCESS); |
|
||||||
} catch (Exception iox) { |
|
||||||
String message = "Couldn't run dbt generate docs "; |
|
||||||
logger.error(message, iox); |
|
||||||
result.setState(DbtExecutionState.FAILURE); |
|
||||||
result.setErrorMessages(List.of(message)); |
|
||||||
} |
|
||||||
return result; |
|
||||||
} |
|
||||||
|
|
||||||
public DbtRunResult nodeCount(boolean test) { |
|
||||||
DbtRunResult result = new DbtRunResult(); |
|
||||||
int lineNr = 0; |
|
||||||
try { |
|
||||||
List<String> pbCommand = new ArrayList<>(DbtUtils.getDbtCommandBase()); |
|
||||||
pbCommand.addAll(Arrays.asList("ls", "--resource-types")); |
|
||||||
if(test) { |
|
||||||
pbCommand.add("test"); |
|
||||||
} else { |
|
||||||
pbCommand.addAll(Arrays.asList( |
|
||||||
"snapshot", |
|
||||||
"seed", |
|
||||||
"model" |
|
||||||
)); |
|
||||||
} |
|
||||||
if(request.select() != null && !request.select().isBlank()) { |
|
||||||
pbCommand.add("--select"); |
|
||||||
pbCommand.add(request.select()); |
|
||||||
} |
|
||||||
ProcessBuilder pb = new ProcessBuilder(pbCommand).directory(projectPath.toFile()); |
|
||||||
pb.environment().putAll(environment); |
|
||||||
pb.redirectErrorStream(true); |
|
||||||
Process p = pb.start(); |
|
||||||
final InputStream stdoutInputStream = p.getInputStream(); |
|
||||||
final BufferedReader stdoutReader = |
|
||||||
new BufferedReader(new InputStreamReader(stdoutInputStream)); |
|
||||||
String line = ""; |
|
||||||
while ((line = stdoutReader.readLine()) != null) { |
|
||||||
if (!line.matches("(\\w+\\.)+\\w+$")) { |
|
||||||
continue; |
|
||||||
} |
|
||||||
lineNr += 1; |
|
||||||
logger.info(line); |
|
||||||
} |
|
||||||
result.setNodeCount(lineNr); |
|
||||||
result.setState(DbtExecutionState.SUCCESS); |
|
||||||
} catch (Exception iox) { |
|
||||||
String message = "Couldn't run dbt ls "; |
|
||||||
logger.error(message, iox); |
|
||||||
result.setErrorMessages(List.of(message)); |
|
||||||
result.setState(DbtExecutionState.FAILURE); |
|
||||||
} |
|
||||||
return result; |
|
||||||
} |
|
||||||
|
|
||||||
private static CompletableFuture<String> readOutStream(InputStream is) { |
|
||||||
return CompletableFuture.supplyAsync(() -> { |
|
||||||
try ( |
|
||||||
InputStreamReader isr = new InputStreamReader(is); |
|
||||||
BufferedReader br = new BufferedReader(isr); |
|
||||||
) { |
|
||||||
StringBuilder res = new StringBuilder(); |
|
||||||
String inputLine; |
|
||||||
while ((inputLine = br.readLine()) != null) { |
|
||||||
res.append(inputLine).append(System.lineSeparator()); |
|
||||||
} |
|
||||||
return res.toString(); |
|
||||||
} catch (Throwable e) { |
|
||||||
throw new RuntimeException("problem with executing program", e); |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Finds staging tables for a dbt selection by running {@code dbt ls}. |
|
||||||
* <p> |
|
||||||
* Matches models from staging schemas such as {@code staging}, |
|
||||||
* {@code staging_xyz}, or {@code staging_vmpostgres}, and returns only the |
|
||||||
* table name without the schema prefix. |
|
||||||
* |
|
||||||
* @param selectOption the dbt selector to inspect |
|
||||||
* @return |
|
||||||
* @return staging table names without schema prefix |
|
||||||
*/ |
|
||||||
public DbtRunResult findDbtStagingTablesForSelection() { |
|
||||||
DbtRunResult result = new DbtRunResult(); |
|
||||||
logger.info("Finding dbt staging tables for selection: {}", request.select()); |
|
||||||
try { |
|
||||||
List<String> command = new ArrayList<>(DbtUtils.getDbtCommandBase()); |
|
||||||
command.addAll(Arrays.asList( |
|
||||||
"ls", |
|
||||||
"--select", request.select(), |
|
||||||
"--output", "name" |
|
||||||
)); |
|
||||||
|
|
||||||
logger.info("Dbt transform Dir: {}", projectPath); |
|
||||||
logger.info("Command: {}", String.join(" ", command)); |
|
||||||
|
|
||||||
ProcessBuilder builder = new ProcessBuilder(command) |
|
||||||
.directory(projectPath.toFile()); |
|
||||||
|
|
||||||
builder.environment().putAll(environment); |
|
||||||
|
|
||||||
this.process = builder.start(); |
|
||||||
|
|
||||||
CompletableFuture<String> errFuture = readOutStream(process.getErrorStream()); |
|
||||||
|
|
||||||
List<String> results; |
|
||||||
try (BufferedReader reader = new BufferedReader( |
|
||||||
new InputStreamReader(process.getInputStream()) |
|
||||||
)) { |
|
||||||
results = reader.lines().collect(Collectors.toList()); |
|
||||||
} |
|
||||||
|
|
||||||
int exitCode = process.waitFor(); |
|
||||||
String error = errFuture.join(); |
|
||||||
|
|
||||||
String output = String.join(System.lineSeparator(), results); |
|
||||||
|
|
||||||
if (exitCode != 0) { |
|
||||||
String message = "dbt ls failed for selection '" + request.select() + "' with exit code " + exitCode |
|
||||||
+ "\n\nstdout:\n" + output |
|
||||||
+ "\n\nstderr:\n" + error; |
|
||||||
result.setState(DbtExecutionState.FAILURE); |
|
||||||
result.setErrorMessages(List.of(message)); |
|
||||||
return result; |
|
||||||
} |
|
||||||
|
|
||||||
if (!error.isBlank()) { |
|
||||||
logger.debug("dbt ls stderr for selection '{}': {}", request.select(), error); |
|
||||||
} |
|
||||||
|
|
||||||
List<String> tables = new ArrayList<>(); |
|
||||||
|
|
||||||
for (String model : results) { |
|
||||||
int dotIndex = model.indexOf("."); |
|
||||||
if (dotIndex > 0 && model.substring(0, dotIndex).startsWith("staging")) { |
|
||||||
tables.add(model.substring(dotIndex + 1)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
logger.info( |
|
||||||
"Found {} dbt staging table(s) for selection '{}': {}", |
|
||||||
new Object[] { Integer.valueOf(tables.size()), request.select(), tables } |
|
||||||
); |
|
||||||
|
|
||||||
result.setOutputMessages(tables); |
|
||||||
result.setExitCode(Integer.valueOf(exitCode)); |
|
||||||
if(!error.isBlank()) { |
|
||||||
result.setErrorMessages(List.of(error)); |
|
||||||
result.setState(DbtExecutionState.FAILURE); |
|
||||||
} else { |
|
||||||
result.setState(DbtExecutionState.SUCCESS); |
|
||||||
} |
|
||||||
} catch (InterruptedException e) { |
|
||||||
Thread.currentThread().interrupt(); |
|
||||||
String message = "Interrupted while running dbt ls for selection: " + request.select(); |
|
||||||
logger.error(message, e); |
|
||||||
result.setState(DbtExecutionState.FAILURE); |
|
||||||
result.setErrorMessages(List.of(message)); |
|
||||||
} catch (IOException e) { |
|
||||||
String message = "Could not start dbt ls for selection: " + request.select(); |
|
||||||
logger.error(message , e); |
|
||||||
result.setState(DbtExecutionState.FAILURE); |
|
||||||
result.setErrorMessages(List.of(message)); |
|
||||||
} |
|
||||||
return result; |
|
||||||
} |
|
||||||
|
|
||||||
public DbtRunResult lintDbtModelsUsingSQLFluff() { |
|
||||||
DbtRunResult result = new DbtRunResult(); |
|
||||||
List<String> command = new ArrayList<>(DbtUtils.getSqlFluffCommandBase()); |
|
||||||
command.addAll(Arrays.asList( |
|
||||||
"lint", |
|
||||||
"--verbose", |
|
||||||
"--nocolor", |
|
||||||
"--disable-progress-bar" |
|
||||||
)); |
|
||||||
logger.info("sqlfluff command: " + command); |
|
||||||
|
|
||||||
ProcessBuilder builder = new ProcessBuilder(command) |
|
||||||
.directory(projectPath.toFile()); |
|
||||||
|
|
||||||
builder.environment().putAll(environment); |
|
||||||
|
|
||||||
try { |
|
||||||
this.process = builder.start(); |
|
||||||
|
|
||||||
// read stdout
|
|
||||||
List<String> lintingErrors = new ArrayList<String>(); |
|
||||||
int progress = 0; |
|
||||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))){ |
|
||||||
String line; |
|
||||||
while((line = reader.readLine()) != null) { |
|
||||||
logger.info(line); |
|
||||||
if(line.contains(".sql")) { |
|
||||||
if (line.contains("FAIL")) { |
|
||||||
lintingErrors.add(line); |
|
||||||
} |
|
||||||
if(request.progressCallback() != null) { |
|
||||||
request.progressCallback().accept(Integer.valueOf(progress++)); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
List<String> errorsFromErrorStream = new ArrayList<String>(); |
|
||||||
// read stderr
|
|
||||||
try (InputStream es = process.getErrorStream(); |
|
||||||
InputStreamReader esr = new InputStreamReader(es); |
|
||||||
BufferedReader errReader = new BufferedReader(esr)) { |
|
||||||
String line; |
|
||||||
while ((line = errReader.readLine()) != null) { |
|
||||||
logger.error(line); |
|
||||||
errorsFromErrorStream.add(line); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// SQLFluff exit codes: 0 = clean, 1 = linting issues found, 2 = execution failed.
|
|
||||||
int exitCode = process.waitFor(); |
|
||||||
result.setExitCode(Integer.valueOf(exitCode)); |
|
||||||
|
|
||||||
if(exitCode == 0) { |
|
||||||
result.setState(DbtExecutionState.SUCCESS); |
|
||||||
} else if(exitCode == 1) { |
|
||||||
result.setErrorMessages(lintingErrors); |
|
||||||
result.setState(DbtExecutionState.FAILURE); |
|
||||||
} else { |
|
||||||
result.setErrorMessages(errorsFromErrorStream); |
|
||||||
result.setState(DbtExecutionState.FAILURE); |
|
||||||
} |
|
||||||
|
|
||||||
return result; |
|
||||||
} catch (Exception e) { |
|
||||||
logger.error("Failed running sqlfluff.", e); |
|
||||||
result.setErrorMessages(List.of(e.getMessage())); |
|
||||||
result.setState(DbtExecutionState.FAILURE); |
|
||||||
return result; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public DbtExecutionState getExecutionState(JsonNode stats) { |
|
||||||
if (stats == null) { |
|
||||||
return DbtExecutionState.ACTIVE; |
|
||||||
} |
|
||||||
if (stats.get("data").get("stats").get("error").asInt() == 0) { |
|
||||||
return DbtExecutionState.SUCCESS; |
|
||||||
} |
|
||||||
return DbtExecutionState.FAILURE; |
|
||||||
} |
|
||||||
|
|
||||||
private List<String> getErrorMessages(List<JsonNode> dbtLog, String errors) { |
|
||||||
var result = new ArrayList<String>(); |
|
||||||
if(errors == null) { |
|
||||||
return result; |
|
||||||
} |
|
||||||
if (!errors.isEmpty()) { |
|
||||||
// stderr was not empty!
|
|
||||||
result.add(errors); |
|
||||||
} else { |
|
||||||
// "regular" errors during dbt execution
|
|
||||||
for (var node : dbtLog) { |
|
||||||
var level = findFirstOccurence("level", node); |
|
||||||
if (level.isPresent() && "error".equals(level.get().asText())) { |
|
||||||
var msg = findFirstOccurence("msg", node); |
|
||||||
if (msg.isPresent()) { |
|
||||||
result.add(msg.get().asText()); |
|
||||||
} else { |
|
||||||
logger.warn("No msg property found in dbt log " + node); |
|
||||||
} |
|
||||||
} else { |
|
||||||
logger.warn("No level property found in dbt log " + node); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
return result; |
|
||||||
} |
|
||||||
|
|
||||||
private static Optional<JsonNode> findFirstOccurence(String name, JsonNode searchNode) { |
|
||||||
JsonNode parent = searchNode.findParent(name); |
|
||||||
JsonNode result = parent != null ? parent.get(name) : null; |
|
||||||
return Optional.of(result); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,24 +0,0 @@ |
|||||||
package de.superx.dbt; |
|
||||||
|
|
||||||
import java.util.function.Consumer; |
|
||||||
|
|
||||||
public record DbtRunRequest( |
|
||||||
DbtAction action, |
|
||||||
String project, |
|
||||||
String select, |
|
||||||
long timeoutMillis, |
|
||||||
Consumer<Integer> progressCallback |
|
||||||
) { |
|
||||||
|
|
||||||
public DbtRunRequest(DbtAction action, String project, String select, long timeoutMillis) { |
|
||||||
this(action, project, select, timeoutMillis, null); |
|
||||||
} |
|
||||||
|
|
||||||
public DbtRunRequest(DbtAction action, String project, Consumer<Integer> progressCallback) { |
|
||||||
this(action, project, null, 0, progressCallback); |
|
||||||
} |
|
||||||
|
|
||||||
public DbtRunRequest(DbtAction action, String project, String select) { |
|
||||||
this(action, project, select, 0, null); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,62 +0,0 @@ |
|||||||
package de.superx.dbt; |
|
||||||
|
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
public class DbtRunResult { |
|
||||||
private Integer exitCode; |
|
||||||
private DbtExecutionState state; |
|
||||||
private List<String> outputMessages; |
|
||||||
private List<String> errorMessages; |
|
||||||
|
|
||||||
private int nodeCount; // used for DbtAction.NODE_COUNT*
|
|
||||||
// private List<String> stagingTables;// used for DbtAction.STAGING_TABLES
|
|
||||||
|
|
||||||
public Integer getExitCode() { |
|
||||||
return exitCode; |
|
||||||
} |
|
||||||
|
|
||||||
public void setExitCode(Integer exitCode) { |
|
||||||
this.exitCode = exitCode; |
|
||||||
} |
|
||||||
|
|
||||||
public DbtExecutionState getState() { |
|
||||||
return state; |
|
||||||
} |
|
||||||
|
|
||||||
public void setState(DbtExecutionState state) { |
|
||||||
this.state = state; |
|
||||||
} |
|
||||||
|
|
||||||
public List<String> getErrorMessages() { |
|
||||||
return errorMessages; |
|
||||||
} |
|
||||||
|
|
||||||
public void setErrorMessages(List<String> errorMessages) { |
|
||||||
this.errorMessages = errorMessages; |
|
||||||
} |
|
||||||
|
|
||||||
public int getNodeCount() { |
|
||||||
return nodeCount; |
|
||||||
} |
|
||||||
|
|
||||||
public void setNodeCount(int nodeCount) { |
|
||||||
this.nodeCount = nodeCount; |
|
||||||
} |
|
||||||
|
|
||||||
//public List<String> getStagingTables() {
|
|
||||||
// return stagingTables;
|
|
||||||
//}
|
|
||||||
|
|
||||||
//public void setStagingTables(List<String> stagingTables) {
|
|
||||||
// this.stagingTables = stagingTables;
|
|
||||||
//}
|
|
||||||
|
|
||||||
public List<String> getOutputMessages() { |
|
||||||
return outputMessages; |
|
||||||
} |
|
||||||
|
|
||||||
public void setOutputMessages(List<String> outputMessages) { |
|
||||||
this.outputMessages = outputMessages; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,43 +0,0 @@ |
|||||||
package de.superx.jdbc.entity; |
|
||||||
|
|
||||||
import org.springframework.data.annotation.Id; |
|
||||||
import org.springframework.data.relational.core.mapping.Table; |
|
||||||
|
|
||||||
import de.superx.jdbc.model.DynamicFieldType; |
|
||||||
import de.superx.jdbc.model.EntityDescriptor; |
|
||||||
|
|
||||||
@Table("cifx_customize") |
|
||||||
public class CifxCustomize extends EntityBase { |
|
||||||
|
|
||||||
@Id |
|
||||||
@DynamicFieldType(label = "ID", visibleInSimplifiedForm = false, readOnly = true) |
|
||||||
public Integer tid; |
|
||||||
|
|
||||||
@DynamicFieldType(label = "CIFX Tabelle") |
|
||||||
public String cifx_table; |
|
||||||
|
|
||||||
@DynamicFieldType(label = "Schlüsselgruppe (key)") |
|
||||||
public Integer key; |
|
||||||
|
|
||||||
@EntityDescriptor |
|
||||||
@DynamicFieldType(label = "Schlüssel (apnr)") |
|
||||||
public String apnr; |
|
||||||
|
|
||||||
@DynamicFieldType(label = "Kurztext") |
|
||||||
public String kurz; |
|
||||||
|
|
||||||
@DynamicFieldType(label = "Drucktext") |
|
||||||
public String druck; |
|
||||||
|
|
||||||
@DynamicFieldType(label = "Langbesch. 1", visibleInSimplifiedForm = false) |
|
||||||
public String lang_1; |
|
||||||
|
|
||||||
@DynamicFieldType(label = "Schlüssel (uniquename)") |
|
||||||
public String uniquename; |
|
||||||
|
|
||||||
@DynamicFieldType(label = "struktur_c", visibleInSimplifiedForm = true) |
|
||||||
public String struktur_c; |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} |
|
||||||
@ -1,9 +0,0 @@ |
|||||||
package de.superx.jdbc.repository; |
|
||||||
|
|
||||||
import org.springframework.data.repository.RepositoryDefinition; |
|
||||||
|
|
||||||
import de.superx.jdbc.entity.CifxCustomize; |
|
||||||
|
|
||||||
@RepositoryDefinition(domainClass = CifxCustomize.class, idClass = Integer.class) |
|
||||||
public interface CifxCustomizeRepository extends BiaAdminCrudRepository<CifxCustomize> { |
|
||||||
} |
|
||||||
@ -0,0 +1,446 @@ |
|||||||
|
package de.superx.servlet; |
||||||
|
|
||||||
|
import org.apache.commons.logging.Log; |
||||||
|
import org.apache.commons.logging.LogFactory; |
||||||
|
|
||||||
|
import org.dbforms.config.DbFormsConfig; |
||||||
|
import org.dbforms.config.DbFormsConfigRegistry; |
||||||
|
import org.dbforms.config.MultipleValidationException; |
||||||
|
import org.dbforms.config.Table; |
||||||
|
|
||||||
|
import org.dbforms.event.DatabaseEvent; |
||||||
|
import org.dbforms.event.EventEngine; |
||||||
|
import org.dbforms.event.WebEvent; |
||||||
|
|
||||||
|
import org.dbforms.util.MessageResources; |
||||||
|
import org.dbforms.util.MultipartRequest; |
||||||
|
import org.dbforms.util.ParseUtil; |
||||||
|
import org.dbforms.util.SqlUtil; |
||||||
|
import org.dbforms.util.Util; |
||||||
|
|
||||||
|
import org.dbforms.validation.ValidatorConstants; |
||||||
|
|
||||||
|
import de.superx.util.DbFormsMultipartRequest; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.io.PrintWriter; |
||||||
|
|
||||||
|
import java.sql.Connection; |
||||||
|
import java.sql.SQLException; |
||||||
|
|
||||||
|
import java.util.Enumeration; |
||||||
|
import java.util.Hashtable; |
||||||
|
import java.util.Locale; |
||||||
|
import java.util.Vector; |
||||||
|
|
||||||
|
import jakarta.servlet.ServletException; |
||||||
|
import jakarta.servlet.http.HttpServlet; |
||||||
|
import jakarta.servlet.http.HttpServletRequest; |
||||||
|
import jakarta.servlet.http.HttpServletResponse; |
||||||
|
import jakarta.servlet.http.HttpSession; |
||||||
|
import static de.superx.servlet.SxSQL_Server.DEFAULT_MANDANTEN_ID; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author Witt |
||||||
|
* This class inherits from the DbForms Controller: |
||||||
|
* As CSRF protection broke the file upload, we need to adjust some classes...and this is the way we "inject" them to DbForms... |
||||||
|
*/ |
||||||
|
public class DbFormsController extends HttpServlet { |
||||||
|
/** logging category for this class */ |
||||||
|
private static Log logCat = LogFactory.getLog(DbFormsController.class.getName()); |
||||||
|
|
||||||
|
/** 100KB default upload size */ |
||||||
|
private int maxUploadSize = 102400; |
||||||
|
|
||||||
|
/** |
||||||
|
* Process an HTTP "GET" request. |
||||||
|
* |
||||||
|
* @param request The servlet request we are processing |
||||||
|
* @param response The servlet response we are creating |
||||||
|
* |
||||||
|
* @exception IOException if an input/output error occurs |
||||||
|
* @exception ServletException if a servlet exception occurs |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { |
||||||
|
process(request, response); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Process an HTTP "POST" request. |
||||||
|
* |
||||||
|
* @param request The servlet request we are processing |
||||||
|
* @param response The servlet response we are creating |
||||||
|
* |
||||||
|
* @exception IOException if an input/output error occurs |
||||||
|
* @exception ServletException if a servlet exception occurs |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { |
||||||
|
process(request, response); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Initialize this servlet. |
||||||
|
* |
||||||
|
* @exception ServletException if the initialization fails |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void init() throws ServletException { |
||||||
|
// if existing and valid, override default maxUploadSize, which determinates how
|
||||||
|
// big the http/multipart uploads may get
|
||||||
|
String maxUploadSizeStr = this.getServletConfig().getInitParameter("maxUploadSize"); |
||||||
|
|
||||||
|
if (maxUploadSizeStr != null) { |
||||||
|
try { |
||||||
|
this.maxUploadSize = Integer.parseInt(maxUploadSizeStr); |
||||||
|
} catch (NumberFormatException nfe) { |
||||||
|
logCat.error("maxUploadSize not a valid number => using default."); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Gets the connection object. Holds a list of all used connections. So they |
||||||
|
* stay open between calls an can be reused |
||||||
|
* |
||||||
|
* @param request the request object |
||||||
|
* @param tableId the table identifier |
||||||
|
* @param connectionsTable the connections hash table |
||||||
|
* |
||||||
|
* @return The connection object |
||||||
|
*/ |
||||||
|
private Connection getConnection(DbFormsConfig config, HttpServletRequest request, int tableId, Hashtable connectionsTable) throws SQLException { |
||||||
|
String connectionName = null; |
||||||
|
Connection con = null; |
||||||
|
|
||||||
|
// get the connection name from the request;
|
||||||
|
if (tableId != -1) { |
||||||
|
connectionName = ParseUtil.getParameter(request, "invname_" + tableId); |
||||||
|
} |
||||||
|
|
||||||
|
connectionName = Util.isNull(connectionName) ? DEFAULT_MANDANTEN_ID : connectionName; |
||||||
|
|
||||||
|
if ((con = (Connection) connectionsTable.get(connectionName)) == null) { |
||||||
|
con = config.getConnection(connectionName); |
||||||
|
connectionsTable.put(connectionName, con); |
||||||
|
} |
||||||
|
|
||||||
|
return con; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* In our development, we sometimes set the connection object to autoCommit |
||||||
|
* = false in the interceptor (Pre... methods). This allows us to have |
||||||
|
* dbForms do part of the required transaction (other parts are done via |
||||||
|
* jdbc calls). If the database throws an exception, then we need to make |
||||||
|
* sure that the connection is reinitialized (rollbacked) before it is sent |
||||||
|
* back into the connection pool. Grunikiewicz.philip&at;hydro.qc.ca |
||||||
|
* 2001-10-29 |
||||||
|
* |
||||||
|
* @param con the connection object |
||||||
|
*/ |
||||||
|
private void cleanUpConnectionAfterException(Connection con) { |
||||||
|
try { |
||||||
|
// Do only if autoCommit is disabled
|
||||||
|
if ((con != null) && (!con.getAutoCommit())) { |
||||||
|
con.rollback(); |
||||||
|
con.setAutoCommit(true); |
||||||
|
} |
||||||
|
} catch (java.sql.SQLException e) { |
||||||
|
SqlUtil.logSqlException(e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Close all the connections stored into the the connections HashTable. |
||||||
|
* |
||||||
|
* @param connectionsTable the connections HashTable |
||||||
|
*/ |
||||||
|
private void closeConnections(Hashtable connectionsTable) { |
||||||
|
Enumeration cons = connectionsTable.keys(); |
||||||
|
|
||||||
|
while (cons.hasMoreElements()) { |
||||||
|
String dbConnectionName = (String) cons.nextElement(); |
||||||
|
Connection con = (Connection) connectionsTable.get(dbConnectionName); |
||||||
|
|
||||||
|
try { |
||||||
|
// Do only if autoCommit is disabled
|
||||||
|
if ((con != null) && (!con.getAutoCommit())) { |
||||||
|
con.commit(); |
||||||
|
con.setAutoCommit(true); |
||||||
|
} |
||||||
|
} catch (java.sql.SQLException e) { |
||||||
|
SqlUtil.logSqlException(e); |
||||||
|
} |
||||||
|
|
||||||
|
SqlUtil.closeConnection(con); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Process the incoming requests. |
||||||
|
* |
||||||
|
* @param request the request object |
||||||
|
* @param response the response object |
||||||
|
* |
||||||
|
* @throws IOException |
||||||
|
* @throws ServletException |
||||||
|
*/ |
||||||
|
private void process(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { |
||||||
|
HttpSession session = request.getSession(true); |
||||||
|
logCat.debug("session timeout: " + session.getMaxInactiveInterval()); |
||||||
|
|
||||||
|
// take Config-Object from application context - this object should have been
|
||||||
|
// initalized by Config-Servlet on Webapp/server-startup!
|
||||||
|
DbFormsConfig config = null; |
||||||
|
|
||||||
|
try { |
||||||
|
config = DbFormsConfigRegistry.instance().lookup(); |
||||||
|
} catch (Exception e) { |
||||||
|
logCat.error(e); |
||||||
|
throw new ServletException(e); |
||||||
|
} |
||||||
|
|
||||||
|
// create RFC-1867 data wrapper for the case the form was sent in multipart mode
|
||||||
|
// this is needed because common HttpServletRequestImpl - classes do not support it
|
||||||
|
// the whole application has to access Request via the "ParseUtil" class
|
||||||
|
// this is also true for jsp files written by the user
|
||||||
|
// #fixme taglib needed for convenient access to ParseUtil wrapper methods
|
||||||
|
Hashtable connections = new Hashtable(); |
||||||
|
String contentType = request.getContentType(); |
||||||
|
|
||||||
|
// Verify if Locale have been setted in session with "LOCALE_KEY"
|
||||||
|
// if not, take the request.getLocale() as default and put it in session
|
||||||
|
// Verify if Locale have been setted in session with "LOCALE_KEY"
|
||||||
|
// if not, take the request.getLocale() as default and put it in session
|
||||||
|
processLocale(request); |
||||||
|
|
||||||
|
if ((contentType != null) && contentType.startsWith("multipart")) { |
||||||
|
try { |
||||||
|
MultipartRequest multipartRequest = new DbFormsMultipartRequest(request, maxUploadSize); |
||||||
|
request.setAttribute("multipartRequest", multipartRequest); |
||||||
|
} catch (IOException ioe) { |
||||||
|
logCat.error("::process - check if uploaded file(s) exceeded allowed size", ioe); |
||||||
|
sendErrorMessage("Check if uploaded file(s) exceeded allowed size.", response); |
||||||
|
|
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Connection con = null; |
||||||
|
WebEvent e = null; |
||||||
|
Vector errors = new Vector(); |
||||||
|
|
||||||
|
try { |
||||||
|
request.setAttribute("errors", errors); |
||||||
|
|
||||||
|
EventEngine engine = new EventEngine(request, config); |
||||||
|
e = engine.generatePrimaryEvent(); |
||||||
|
|
||||||
|
// send as info to dbForms (=> Taglib)
|
||||||
|
if (e != null) { |
||||||
|
request.setAttribute("webEvent", e); |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
con = getConnection(config, request, ((e == null) || (e.getTable() == null)) ? (-1) : e.getTable().getId(), connections); |
||||||
|
|
||||||
|
// primary event can be any kind of event (database, navigation...)
|
||||||
|
if (e instanceof DatabaseEvent) { |
||||||
|
try { |
||||||
|
// if hidden formValidatorName exist and it's an Update or Insert event,
|
||||||
|
// doValidation with Commons-Validator
|
||||||
|
String formValidatorName = request.getParameter(ValidatorConstants.FORM_VALIDATOR_NAME + "_" + e.getTable().getId()); |
||||||
|
|
||||||
|
if (formValidatorName != null) { |
||||||
|
((DatabaseEvent) e).doValidation(formValidatorName, getServletContext()); |
||||||
|
} |
||||||
|
|
||||||
|
((DatabaseEvent) e).processEvent(con); |
||||||
|
} catch (SQLException sqle) { |
||||||
|
logCat.error("::process - SQLException:", sqle); |
||||||
|
errors.addElement(sqle); |
||||||
|
cleanUpConnectionAfterException(con); |
||||||
|
} catch (MultipleValidationException mve) { |
||||||
|
processMultipleValidationException(con, errors, mve); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//else
|
||||||
|
//{
|
||||||
|
// currently, we support db events ONLY
|
||||||
|
// but in future there may be events with processEvent() method which do not need a jdbc con!
|
||||||
|
// (you may think: "what about navigation events?" - well they are created by the
|
||||||
|
// controller but they get executed in the referncing "DbFormTag" at the jsp -- that's why we
|
||||||
|
// do not any further operations on them right here...we just put them into the request)
|
||||||
|
//}
|
||||||
|
// secondary Events are always database events
|
||||||
|
// (in fact, they all are SQL UPDATEs)
|
||||||
|
if (engine.getInvolvedTables() != null) { |
||||||
|
processInvolvedTables(config, request, connections, e, errors, engine); |
||||||
|
} |
||||||
|
} catch (SQLException exc) { |
||||||
|
throw new ServletException(exc); |
||||||
|
} |
||||||
|
} finally { |
||||||
|
// close all the connections stored into the connections hash table;
|
||||||
|
closeConnections(connections); |
||||||
|
|
||||||
|
if (e != null) { |
||||||
|
// PG - if form contained errors, use followupOnError (if available!)
|
||||||
|
String followUp = null; |
||||||
|
|
||||||
|
if (errors.size() != 0) { |
||||||
|
followUp = e.getFollowUpOnError(); |
||||||
|
} |
||||||
|
|
||||||
|
if (Util.isNull(followUp)) { |
||||||
|
followUp = e.getFollowUp(); |
||||||
|
} |
||||||
|
|
||||||
|
logCat.info("*** e = " + e + "*** e.getFollowUp() = " + e.getFollowUp()); |
||||||
|
|
||||||
|
if (!Util.isNull(followUp)) { |
||||||
|
request.getRequestDispatcher(followUp).forward(request, response); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* PRIVATE METHODS here |
||||||
|
* |
||||||
|
* @param request DOCUMENT ME! |
||||||
|
* @param connections DOCUMENT ME! |
||||||
|
* @param e DOCUMENT ME! |
||||||
|
* @param errors DOCUMENT ME! |
||||||
|
* @param engine DOCUMENT ME! |
||||||
|
*/ |
||||||
|
/** |
||||||
|
* Process tables related to the main event table. <br> |
||||||
|
* For every table related to the parent one, generate secundary (update) |
||||||
|
* events for that table and execute them. |
||||||
|
* |
||||||
|
* @param request the request object |
||||||
|
* @param connections the connections hashTable |
||||||
|
* @param e the main webEvent object |
||||||
|
* @param errors the errors vector |
||||||
|
* @param engine the eventEngine reference |
||||||
|
*/ |
||||||
|
private void processInvolvedTables(DbFormsConfig config, HttpServletRequest request, Hashtable connections, WebEvent e, Vector errors, EventEngine engine) throws SQLException { |
||||||
|
Connection con; |
||||||
|
|
||||||
|
// may be null if empty form!
|
||||||
|
Enumeration tableEnum = engine.getInvolvedTables().elements(); |
||||||
|
|
||||||
|
while (tableEnum.hasMoreElements()) { |
||||||
|
Table t = (Table) tableEnum.nextElement(); |
||||||
|
Enumeration eventEnum = engine.generateSecundaryEvents(t, e); |
||||||
|
|
||||||
|
// scan all the secundary events for the current secundary table;
|
||||||
|
while (eventEnum.hasMoreElements()) { |
||||||
|
DatabaseEvent dbE = (DatabaseEvent) eventEnum.nextElement(); |
||||||
|
|
||||||
|
// 2003-02-03 HKK: do not do the work twice - without this every event
|
||||||
|
// would be generated for each table and event
|
||||||
|
if (t.getId() == dbE.getTable().getId()) { |
||||||
|
con = getConnection(config, request, dbE.getTable().getId(), connections); |
||||||
|
|
||||||
|
// 2003-02-03 HKK: do not do the work twice!!!
|
||||||
|
String formValidatorName = request.getParameter(ValidatorConstants.FORM_VALIDATOR_NAME + "_" + dbE.getTable().getId()); |
||||||
|
|
||||||
|
try { |
||||||
|
// if hidden formValidatorName exist and it's an Update or Insert event,
|
||||||
|
// doValidation with Commons-Validator
|
||||||
|
if (formValidatorName != null) { |
||||||
|
dbE.doValidation(formValidatorName, getServletContext()); |
||||||
|
} |
||||||
|
|
||||||
|
dbE.processEvent(con); |
||||||
|
} catch (SQLException sqle2) { |
||||||
|
SqlUtil.logSqlException(sqle2, "::process - exception while process secundary events"); |
||||||
|
errors.addElement(sqle2); |
||||||
|
cleanUpConnectionAfterException(con); |
||||||
|
} catch (MultipleValidationException mve) { |
||||||
|
processMultipleValidationException(con, errors, mve); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Set the default locale |
||||||
|
* |
||||||
|
* @param request the request object |
||||||
|
*/ |
||||||
|
private void processLocale(HttpServletRequest request) { |
||||||
|
String lang = ParseUtil.getParameter(request, "lang"); |
||||||
|
String country = ParseUtil.getParameter(request, "country", ""); |
||||||
|
Locale locale = null; |
||||||
|
|
||||||
|
if (!Util.isNull(lang)) { |
||||||
|
locale = new Locale(lang, country); |
||||||
|
} else if (MessageResources.getLocale(request) == null) { |
||||||
|
MessageResources.setLocale(request, request.getLocale()); |
||||||
|
} |
||||||
|
|
||||||
|
if (locale != null) { |
||||||
|
MessageResources.setLocale(request, locale); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Process the input MultipleValidationException object. |
||||||
|
* |
||||||
|
* @param con the connection object to close |
||||||
|
* @param errors the errors vector to fill |
||||||
|
* @param mve the MultipleValidationException to process |
||||||
|
*/ |
||||||
|
private void processMultipleValidationException(Connection con, Vector errors, MultipleValidationException mve) { |
||||||
|
java.util.Vector v = null; |
||||||
|
|
||||||
|
logCat.error("::processMultipleValidationException - exception", mve); |
||||||
|
|
||||||
|
if ((v = mve.getMessages()) != null) { |
||||||
|
Enumeration e = v.elements(); |
||||||
|
|
||||||
|
while (e.hasMoreElements()) { |
||||||
|
errors.addElement(e.nextElement()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
cleanUpConnectionAfterException(con); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Send error messages to the servlet's output stream |
||||||
|
* |
||||||
|
* @param message the message to display |
||||||
|
* @param response the response object |
||||||
|
*/ |
||||||
|
private void sendErrorMessage(String message, HttpServletResponse response) { |
||||||
|
try { |
||||||
|
PrintWriter out = response.getWriter(); |
||||||
|
|
||||||
|
response.setContentType("text/html"); |
||||||
|
out.println("<html><body><h1>ERROR:</h1><p>"); |
||||||
|
out.println(message); |
||||||
|
out.println("</p></body></html>"); |
||||||
|
} catch (IOException ioe) { |
||||||
|
logCat.error("::sendErrorMessage - senderror message crashed", ioe); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
File diff suppressed because it is too large
Load Diff
@ -1,281 +0,0 @@ |
|||||||
package de.superx.spring; |
|
||||||
|
|
||||||
|
|
||||||
import java.io.File; |
|
||||||
import java.nio.file.Path; |
|
||||||
import java.security.InvalidKeyException; |
|
||||||
import java.security.NoSuchAlgorithmException; |
|
||||||
import java.sql.Connection; |
|
||||||
import java.sql.DatabaseMetaData; |
|
||||||
import java.sql.ResultSet; |
|
||||||
import java.sql.SQLException; |
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.Map; |
|
||||||
import java.util.Map.Entry; |
|
||||||
|
|
||||||
import javax.crypto.BadPaddingException; |
|
||||||
import javax.crypto.IllegalBlockSizeException; |
|
||||||
import javax.crypto.NoSuchPaddingException; |
|
||||||
import javax.sql.DataSource; |
|
||||||
|
|
||||||
import org.apache.log4j.Logger; |
|
||||||
import org.springframework.batch.core.Job; |
|
||||||
import org.springframework.batch.core.Step; |
|
||||||
import org.springframework.batch.core.configuration.JobLocator; |
|
||||||
import org.springframework.batch.core.configuration.JobRegistry; |
|
||||||
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; |
|
||||||
import org.springframework.batch.core.explore.JobExplorer; |
|
||||||
import org.springframework.batch.core.job.builder.JobBuilder; |
|
||||||
import org.springframework.batch.core.launch.JobLauncher; |
|
||||||
import org.springframework.batch.core.launch.JobOperator; |
|
||||||
import org.springframework.batch.core.launch.support.SimpleJobOperator; |
|
||||||
import org.springframework.batch.core.launch.support.TaskExecutorJobLauncher; |
|
||||||
import org.springframework.batch.core.repository.JobRepository; |
|
||||||
import org.springframework.batch.core.step.builder.StepBuilder; |
|
||||||
import org.springframework.beans.factory.annotation.Autowired; |
|
||||||
import org.springframework.beans.factory.annotation.Qualifier; |
|
||||||
import org.springframework.beans.factory.annotation.Value; |
|
||||||
import org.springframework.context.annotation.Bean; |
|
||||||
import org.springframework.context.annotation.ComponentScan; |
|
||||||
import org.springframework.context.annotation.Configuration; |
|
||||||
import org.springframework.context.annotation.Primary; |
|
||||||
import org.springframework.context.annotation.PropertySource; |
|
||||||
import org.springframework.core.io.ClassPathResource; |
|
||||||
import org.springframework.core.io.FileSystemResource; |
|
||||||
import org.springframework.core.task.SimpleAsyncTaskExecutor; |
|
||||||
import org.springframework.jdbc.core.JdbcTemplate; |
|
||||||
import org.springframework.jdbc.datasource.DataSourceTransactionManager; |
|
||||||
import org.springframework.jdbc.datasource.init.ScriptUtils; |
|
||||||
import org.springframework.transaction.PlatformTransactionManager; |
|
||||||
|
|
||||||
import com.zaxxer.hikari.HikariDataSource; |
|
||||||
|
|
||||||
import de.superx.spring.batch.His1DataSources; |
|
||||||
import de.superx.spring.batch.job.JobUtils; |
|
||||||
import de.superx.spring.batch.tasklet.RemoveSpringBatchHistoryTasklet; |
|
||||||
import de.superx.spring.config.DataSourceDiscardingUserStuff; |
|
||||||
import de.superx.util.PathAndFileUtils; |
|
||||||
|
|
||||||
|
|
||||||
@Configuration |
|
||||||
@EnableBatchProcessing(transactionManagerRef = "batchTransactionManager", dataSourceRef = "unrestrictedDataSource") |
|
||||||
@PropertySource("classpath:spring-batch.properties") |
|
||||||
@PropertySource("classpath:hikari.properties") |
|
||||||
@ComponentScan(basePackages = {"de.superx.spring.service", "de.superx.spring.batch.tasklet", "de.superx.rest", "de.superx.dbt", |
|
||||||
"de.superx.bianalysis.service", "de.superx.bianalysis.rest", "de.superx.access"}) |
|
||||||
public class AppConfig { |
|
||||||
|
|
||||||
// time in milliseconds after which an exception is
|
|
||||||
// thrown if no connection available in pool
|
|
||||||
@Value("${hikari.connection_timeout:180000}") |
|
||||||
protected Long connectionTimeout; |
|
||||||
|
|
||||||
// time in milliseconds a connection can be out of pool
|
|
||||||
// before an execption gets thrown to prevent connection leaks
|
|
||||||
// (for debug purposes, 0 means disable leak detection)
|
|
||||||
@Value("${hikari.leak_detection_threshold:0}") |
|
||||||
protected Long leakDetectionThreshold; |
|
||||||
|
|
||||||
public static final int DEFAULT_POOL_SIZE = 5; |
|
||||||
public static final int EDUETL_POOL_SIZE = 20; // low pool size led to hanging application on 'muster-head' - former value: 6;
|
|
||||||
|
|
||||||
private static Logger logger = Logger.getLogger(AppConfig.class); |
|
||||||
|
|
||||||
@Autowired |
|
||||||
private JobRepository jobRepository; |
|
||||||
|
|
||||||
@Autowired |
|
||||||
private JobRegistry jobRegistry; |
|
||||||
|
|
||||||
@Autowired |
|
||||||
private JobExplorer jobExplorer; |
|
||||||
|
|
||||||
@Bean |
|
||||||
public PlatformTransactionManager transactionManager(DataSource dataSource) { |
|
||||||
return new DataSourceTransactionManager(dataSource); |
|
||||||
} |
|
||||||
|
|
||||||
@Bean |
|
||||||
public PlatformTransactionManager batchTransactionManager() { |
|
||||||
return new DataSourceTransactionManager(unrestrictedDataSource()); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Bean |
|
||||||
public JobLauncher jobLauncher() throws Exception { |
|
||||||
TaskExecutorJobLauncher jobLauncher = new TaskExecutorJobLauncher(); |
|
||||||
jobLauncher.setJobRepository(jobRepository); |
|
||||||
jobLauncher.setTaskExecutor(new SimpleAsyncTaskExecutor()); |
|
||||||
jobLauncher.afterPropertiesSet(); |
|
||||||
return jobLauncher; |
|
||||||
} |
|
||||||
|
|
||||||
@Bean |
|
||||||
public JobLocator jobLocator() { |
|
||||||
return jobRegistry; |
|
||||||
} |
|
||||||
|
|
||||||
@Bean |
|
||||||
public JobLauncher syncJobLauncher() throws Exception { |
|
||||||
TaskExecutorJobLauncher jobLauncher = new TaskExecutorJobLauncher(); |
|
||||||
jobLauncher.setJobRepository(jobRepository); |
|
||||||
jobLauncher.afterPropertiesSet(); |
|
||||||
return jobLauncher; |
|
||||||
} |
|
||||||
|
|
||||||
@Bean |
|
||||||
public JobOperator jobOperator() throws Exception { |
|
||||||
SimpleJobOperator jobOperator = new SimpleJobOperator(); |
|
||||||
jobOperator.setJobLauncher(jobLauncher()); |
|
||||||
jobOperator.setJobExplorer(jobExplorer); |
|
||||||
jobOperator.setJobRepository(jobRepository); |
|
||||||
jobOperator.setJobRegistry(jobRegistry); |
|
||||||
JobUtils.terminateAllJobExecutions(jobExplorer, jobOperator); |
|
||||||
return jobOperator; |
|
||||||
} |
|
||||||
|
|
||||||
@Bean |
|
||||||
public His1DataSources dataSources() { |
|
||||||
//Map<String, DataSourceDiscardingUserStuff> dataSources = new HashMap<>();
|
|
||||||
Map<String, HikariDataSource> dataSources = new HashMap<>(); |
|
||||||
try { |
|
||||||
for(Entry<String, Map<String,String>> co : DatabaseUtils.getValidConnections().entrySet()) { |
|
||||||
HikariDataSource hs = DatabaseUtils.convertConnection(co.getKey().toString(), co.getValue(), |
|
||||||
leakDetectionThreshold.longValue(), connectionTimeout.longValue()); |
|
||||||
//DataSourceDiscardingUserStuff dsdu = new DataSourceDiscardingUserStuff(hs);
|
|
||||||
dataSources.put(co.getKey().toString(), hs); |
|
||||||
logger.info(String.format("Connection to %s added to dataSources bean", co.getKey())); |
|
||||||
} |
|
||||||
} catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException |
|
||||||
| BadPaddingException e) { |
|
||||||
logger.fatal(e); |
|
||||||
} |
|
||||||
return new His1DataSources(dataSources); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Bean |
|
||||||
public Map<String, String> dbtProfile() { |
|
||||||
Map<String, String> attributes = new HashMap<>(); |
|
||||||
Map<String, String> con; |
|
||||||
try { |
|
||||||
con = DatabaseUtils.getConnection("eduetl"); |
|
||||||
attributes.put("DBT_HOST", con.get("host")); |
|
||||||
attributes.put("DBT_PORT", con.get("dbserverport")); |
|
||||||
attributes.put("DBT_USER", con.get("user")); |
|
||||||
attributes.put("DBT_ENV_SECRET_PW", con.get("password")); |
|
||||||
attributes.put("DBT_DB", con.get("database")); |
|
||||||
} catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException |
|
||||||
| BadPaddingException e) { |
|
||||||
logger.fatal("dbt profile could not be initalized.", e); |
|
||||||
} |
|
||||||
return attributes; |
|
||||||
} |
|
||||||
|
|
||||||
@Bean |
|
||||||
public DataSource unrestrictedDataSource() { |
|
||||||
DataSource ds = dataSources().get("eduetl"); |
|
||||||
if (!batchSchemaExists(ds)) { |
|
||||||
dropBatchSchema(ds); |
|
||||||
createBatchSchema(ds); |
|
||||||
} |
|
||||||
upgradeBatchSchema(ds); |
|
||||||
if (!quartzSchemaExists(ds)) { |
|
||||||
createQuartzSchema(ds); |
|
||||||
} |
|
||||||
return ds; |
|
||||||
} |
|
||||||
|
|
||||||
@Bean |
|
||||||
@Primary |
|
||||||
public DataSource dataSource() { |
|
||||||
DataSource ds = new DataSourceDiscardingUserStuff(); |
|
||||||
return ds; |
|
||||||
} |
|
||||||
@Bean |
|
||||||
public Step removeStep(@Qualifier("transactionManager" )PlatformTransactionManager transactionManager, @Qualifier("dataSource") DataSource dataSource) { |
|
||||||
RemoveSpringBatchHistoryTasklet tasklet = new RemoveSpringBatchHistoryTasklet(); |
|
||||||
tasklet.setJdbcTemplate(new JdbcTemplate(dataSource)); |
|
||||||
|
|
||||||
String name = "removeStep"; |
|
||||||
return new StepBuilder(name, jobRepository) |
|
||||||
.tasklet(tasklet, transactionManager) |
|
||||||
.build(); |
|
||||||
} |
|
||||||
|
|
||||||
@Bean |
|
||||||
public Job removeSpringBatchHistoryJob(Step removeStep) { |
|
||||||
return new JobBuilder("removeSpringBatchHistoryJob", jobRepository) |
|
||||||
.start(removeStep) |
|
||||||
.build(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
//Checks whether the necessary tables for spring batch exist
|
|
||||||
//TODO: Should implement method of creating a dump before creating new schema in case not all tables exist
|
|
||||||
private static boolean batchSchemaExists(DataSource dataSource) { |
|
||||||
int count = 0; |
|
||||||
try(Connection con = dataSource.getConnection()) { |
|
||||||
DatabaseMetaData meta = con.getMetaData(); |
|
||||||
ResultSet resultSet = meta.getTables(null, "public", "batch_%" , new String[] {"TABLE"}); |
|
||||||
while (resultSet.next()) { |
|
||||||
count++; |
|
||||||
} |
|
||||||
} catch (SQLException e) { |
|
||||||
throw new RuntimeException("Couldn't check for spring batch tables", e); |
|
||||||
} |
|
||||||
return count == 6; |
|
||||||
} |
|
||||||
|
|
||||||
private static boolean quartzSchemaExists(DataSource dataSource) { |
|
||||||
try(Connection con = dataSource.getConnection()) { |
|
||||||
DatabaseMetaData meta = con.getMetaData(); |
|
||||||
ResultSet resultSet = meta.getTables(null, "public", "qrtz_%" , new String[] {"TABLE"}); |
|
||||||
if (resultSet.next()) { |
|
||||||
return true; |
|
||||||
} |
|
||||||
} catch (SQLException e) { |
|
||||||
throw new RuntimeException("Couldn't check for spring batch tables", e); |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
private static void createBatchSchema(DataSource dataSource) { |
|
||||||
try (Connection con = dataSource.getConnection()){ |
|
||||||
ScriptUtils.executeSqlScript(con, new ClassPathResource("/org/springframework/batch/core/schema-postgresql.sql")); |
|
||||||
logger.info("Spring Batch schema created;"); |
|
||||||
} catch (Exception e) { |
|
||||||
logger.error("Couldn't create Spring Batch schema!", e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private static void dropBatchSchema(DataSource dataSource) { |
|
||||||
try (Connection con = dataSource.getConnection()){ |
|
||||||
ScriptUtils.executeSqlScript(con, new ClassPathResource("/org/springframework/batch/core/schema-drop-postgresql.sql")); |
|
||||||
logger.info("Spring Batch schema dropped;"); |
|
||||||
} catch (Exception e) { |
|
||||||
logger.error("Couldn't drop Spring Batch schema!", e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private static void createQuartzSchema(DataSource dataSource) { |
|
||||||
try (Connection con = dataSource.getConnection()){ |
|
||||||
ScriptUtils.executeSqlScript(con, new ClassPathResource("/org/quartz/impl/jdbcjobstore/tables_postgres.sql")); |
|
||||||
logger.info("Quartz schema created;"); |
|
||||||
} catch (Exception e) { |
|
||||||
logger.error("Couldn't create Quartz schema!", e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static void upgradeBatchSchema(DataSource dataSource) { |
|
||||||
try (Connection con = dataSource.getConnection()){ |
|
||||||
File file = new File(String.format("%s/conf/edustore/db/install/upgrade/spring_batch_schema_upgrade.sql", PathAndFileUtils.getWebinfPath())); |
|
||||||
ScriptUtils.executeSqlScript(con, new FileSystemResource(file)); |
|
||||||
logger.info("Spring Batch schema upgraded;"); |
|
||||||
} catch (Exception e) { |
|
||||||
logger.error("Couldn't upgrade Spring Batch schema!", e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,130 +0,0 @@ |
|||||||
package de.superx.spring; |
|
||||||
|
|
||||||
import java.io.File; |
|
||||||
import java.io.FileInputStream; |
|
||||||
import java.io.IOException; |
|
||||||
import java.nio.charset.StandardCharsets; |
|
||||||
import java.security.NoSuchAlgorithmException; |
|
||||||
import java.security.InvalidKeyException; |
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.HashSet; |
|
||||||
import java.util.Map; |
|
||||||
import java.util.List; |
|
||||||
import java.util.Properties; |
|
||||||
import org.apache.log4j.Logger; |
|
||||||
import de.superx.util.PathAndFileUtils; |
|
||||||
import java.util.regex.Matcher; |
|
||||||
import java.util.regex.Pattern; |
|
||||||
import java.util.stream.Collectors; |
|
||||||
import javax.crypto.Cipher; |
|
||||||
|
|
||||||
import javax.crypto.BadPaddingException; |
|
||||||
import javax.crypto.IllegalBlockSizeException; |
|
||||||
import javax.crypto.NoSuchPaddingException; |
|
||||||
import javax.crypto.spec.SecretKeySpec; |
|
||||||
|
|
||||||
import java.util.Set; |
|
||||||
|
|
||||||
public class CustomDatabases{ |
|
||||||
|
|
||||||
private static Logger logger = Logger.getLogger(CustomDatabases.class); |
|
||||||
private static SecretKeySpec KEY; |
|
||||||
private static Cipher desCipher; |
|
||||||
|
|
||||||
public static Map<String, Map<String,String>> getCustomConnections() throws |
|
||||||
InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException{ |
|
||||||
Map<String,Map<String,String>> connections = new HashMap<>(); |
|
||||||
//loop over all properties and map them to connections
|
|
||||||
//automatically compute dbconnections from the name property
|
|
||||||
Properties props = fetchProperties(); |
|
||||||
List<String> dbconnections = getDBConnectionsFromNameProperty(props); |
|
||||||
final Set<String> propertyNames = props.stringPropertyNames(); |
|
||||||
for (String s : dbconnections) { |
|
||||||
Map<String,String> properties = new HashMap<>(); |
|
||||||
logger.info(String.format("%s connection retrieved from HISinOne", s)); |
|
||||||
List<String> keys = propertyNames.stream().filter(it -> it.startsWith("db." + s + ".")).collect(Collectors.toList()); |
|
||||||
for (String key : keys) { |
|
||||||
String value = props.getProperty(key); |
|
||||||
if (key.endsWith("password")) { |
|
||||||
value = decryptDbPassword(value.trim()); |
|
||||||
} |
|
||||||
properties.put(key.substring(key.lastIndexOf('.') + 1), value); |
|
||||||
} |
|
||||||
connections.put(s, properties); |
|
||||||
} |
|
||||||
|
|
||||||
return connections; |
|
||||||
} |
|
||||||
|
|
||||||
private static List<String> getPropertyValuesByRegex(Properties properties, String regex) { |
|
||||||
List<String> values = new ArrayList<>(); |
|
||||||
Pattern pattern = Pattern.compile(regex); |
|
||||||
|
|
||||||
for (String key : properties.stringPropertyNames()) { |
|
||||||
Matcher matcher = pattern.matcher(key); |
|
||||||
if (matcher.matches()) { |
|
||||||
values.add(properties.getProperty(key)); |
|
||||||
} |
|
||||||
} |
|
||||||
return values; |
|
||||||
} |
|
||||||
|
|
||||||
public static List<String> getDBConnectionsFromNameProperty(Properties props){ |
|
||||||
ArrayList<String> connection_names = new ArrayList<String>(); |
|
||||||
String regex = "db.*.name"; |
|
||||||
connection_names = (ArrayList<String>) getPropertyValuesByRegex(props, regex); |
|
||||||
|
|
||||||
//check for duplicate names
|
|
||||||
Set<String> seen = new HashSet<>(); |
|
||||||
for (String db_name : connection_names) { |
|
||||||
if(!seen.add(db_name)) { |
|
||||||
logger.warn("Found atleast two databases with the name" + db_name); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return connection_names; |
|
||||||
} |
|
||||||
|
|
||||||
private static String decryptDbPassword(String password) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { |
|
||||||
if(password == null || password.equals("")) { |
|
||||||
return null; |
|
||||||
}else if(!password.startsWith("sx_des")) { |
|
||||||
return password; |
|
||||||
} |
|
||||||
|
|
||||||
if(desCipher == null) { |
|
||||||
desCipher = getDesCipher(); |
|
||||||
} |
|
||||||
|
|
||||||
String[] stext = password.substring(7).split("#"); |
|
||||||
byte[] bstext = new byte[stext.length]; |
|
||||||
for(int i = 0; i<stext.length;i++) { |
|
||||||
bstext[i] = Byte.parseByte(stext[i]); |
|
||||||
} |
|
||||||
desCipher.init(Cipher.DECRYPT_MODE, KEY); |
|
||||||
byte[] decrypted = desCipher.doFinal(bstext); |
|
||||||
return new String(decrypted, StandardCharsets.UTF_8); |
|
||||||
} |
|
||||||
|
|
||||||
public static void copy_encryption_key(SecretKeySpec key){ |
|
||||||
KEY = key; |
|
||||||
} |
|
||||||
|
|
||||||
private static Cipher getDesCipher() throws NoSuchAlgorithmException, NoSuchPaddingException { |
|
||||||
return Cipher.getInstance("DES"); |
|
||||||
} |
|
||||||
|
|
||||||
private static Properties fetchProperties(){ |
|
||||||
Properties props = new Properties(); |
|
||||||
String FileName = "extra_connections.properties"; |
|
||||||
File extra_connections_file_path = new File(PathAndFileUtils.getWebinfPath() + File.separator + "conf" + File.separator + FileName); |
|
||||||
try (FileInputStream s = new FileInputStream(extra_connections_file_path)){ |
|
||||||
props.load(s); |
|
||||||
} catch (IOException e1) { |
|
||||||
logger.info("Unable to access properties file where extra connections as described: " + e1.getMessage()); |
|
||||||
} |
|
||||||
|
|
||||||
return props; |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,340 +0,0 @@ |
|||||||
package de.superx.spring; |
|
||||||
|
|
||||||
import static java.util.Map.entry; |
|
||||||
|
|
||||||
import java.io.File; |
|
||||||
import java.io.FileInputStream; |
|
||||||
import java.io.FileReader; |
|
||||||
import java.io.IOException; |
|
||||||
import java.nio.charset.StandardCharsets; |
|
||||||
import java.security.InvalidKeyException; |
|
||||||
import java.security.NoSuchAlgorithmException; |
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.Iterator; |
|
||||||
import java.util.List; |
|
||||||
import java.util.Map; |
|
||||||
import java.util.Map.Entry; |
|
||||||
import java.util.Properties; |
|
||||||
import java.util.Set; |
|
||||||
import java.util.stream.Collectors; |
|
||||||
import java.util.stream.Stream; |
|
||||||
|
|
||||||
import javax.crypto.BadPaddingException; |
|
||||||
import javax.crypto.Cipher; |
|
||||||
import javax.crypto.IllegalBlockSizeException; |
|
||||||
import javax.crypto.NoSuchPaddingException; |
|
||||||
import javax.crypto.spec.SecretKeySpec; |
|
||||||
|
|
||||||
import org.apache.log4j.Logger; |
|
||||||
import org.springframework.core.io.ClassPathResource; |
|
||||||
|
|
||||||
import com.zaxxer.hikari.HikariConfig; |
|
||||||
import com.zaxxer.hikari.HikariDataSource; |
|
||||||
|
|
||||||
import de.superx.servlet.SuperXManager; |
|
||||||
import de.superx.util.PathAndFileUtils; |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public class DatabaseUtils { |
|
||||||
|
|
||||||
public static final String HIS1_DATABASES_PROPERTIES = "HIS1_DATABASES_PROPERTIES"; |
|
||||||
private static final byte[] KEY_DATA = { -108, -50, -5, -75, -98, 28, -116, 107 }; |
|
||||||
private static final SecretKeySpec KEY = new SecretKeySpec(KEY_DATA, "DES"); |
|
||||||
private static Cipher desCipher; |
|
||||||
|
|
||||||
private static Logger logger = Logger.getLogger(DatabaseUtils.class); |
|
||||||
|
|
||||||
private DatabaseUtils() { //Mit Ausnahmegenehmigung
|
|
||||||
//Prevent instantiation
|
|
||||||
} |
|
||||||
|
|
||||||
private static void check_for_duplicate_names__in_properties_lists(Properties regular_properties, Properties extra_properties) { |
|
||||||
List<String> regular_names = CustomDatabases.getDBConnectionsFromNameProperty(regular_properties); |
|
||||||
List<String> extra_names = CustomDatabases.getDBConnectionsFromNameProperty(extra_properties); |
|
||||||
|
|
||||||
for (String conn_name : extra_names) { |
|
||||||
if(regular_names.contains(conn_name)) { |
|
||||||
logger.warn("Found a custom connection with the same name as a regular connection"); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static Map<String,Map<String,String>> getAllConnections() throws |
|
||||||
InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException{ |
|
||||||
Map<String, Map<String,String>> his1_connections = fetchConnections(); |
|
||||||
CustomDatabases.copy_encryption_key(KEY); |
|
||||||
Map<String, Map<String,String>> custom_connections = CustomDatabases.getCustomConnections(); |
|
||||||
|
|
||||||
//check_for_duplicate_properties(his1_connections, custom_connections);
|
|
||||||
|
|
||||||
Map<String, Map<String,String>> all_connections = new HashMap<>(his1_connections); |
|
||||||
all_connections.putAll(custom_connections); |
|
||||||
|
|
||||||
return all_connections; |
|
||||||
} |
|
||||||
|
|
||||||
public static Map<String,Map<String,String>> getValidConnections() throws |
|
||||||
InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException{ |
|
||||||
Map<String,Map<String,String>> conns = getAllConnections(); |
|
||||||
logger.info("Got connections: " + conns.keySet()); |
|
||||||
Map<String,Map<String,String>> validConns = new HashMap<>(); |
|
||||||
for (String key : conns.keySet()) { |
|
||||||
Map<String,String> connectionProperties = conns.get(key); |
|
||||||
if ( |
|
||||||
connectionProperties.get(DbPropertyName.database.name()) != null |
|
||||||
&&connectionProperties.get(DbPropertyName.user.name()) != null |
|
||||||
&& connectionProperties.get(DbPropertyName.url.name()) != null |
|
||||||
&& connectionProperties.get(DbPropertyName.protocol.name()) != null |
|
||||||
&& connectionProperties.get(DbPropertyName.jdbcDriver.name()) != null |
|
||||||
|
|
||||||
) { |
|
||||||
logger.info("Valid connection: " + key); |
|
||||||
validConns.put(key, connectionProperties); |
|
||||||
} else { |
|
||||||
logger.warn("Invalid connection: " + key); |
|
||||||
} |
|
||||||
} |
|
||||||
return validConns; |
|
||||||
} |
|
||||||
|
|
||||||
public static Map<String,String> getConnection(String connectionName) throws |
|
||||||
InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException{ |
|
||||||
Map<String,Map<String,String>> connections = fetchConnections(); |
|
||||||
return connections.get(connectionName) != null ? connections.get(connectionName) : new HashMap<>(); |
|
||||||
} |
|
||||||
|
|
||||||
private static Properties fetchProperties() { |
|
||||||
Properties props = new Properties(); |
|
||||||
String databasesPropertiesFileName = System.getProperty(HIS1_DATABASES_PROPERTIES); |
|
||||||
if (databasesPropertiesFileName != null) { |
|
||||||
File databasePropertiesFile = new File(databasesPropertiesFileName); |
|
||||||
if (databasePropertiesFile.exists()) { |
|
||||||
logger.info("Reading database properties from " + databasesPropertiesFileName); |
|
||||||
try { |
|
||||||
props.load(new FileInputStream(databasePropertiesFile)); |
|
||||||
} catch (Exception e) { |
|
||||||
logger.error("Couldn't load database properties from " + databasesPropertiesFileName,e); |
|
||||||
} |
|
||||||
} else { |
|
||||||
logger.error("HIS1_DATABASES_PROPERTIES file not found: " + databasesPropertiesFileName); |
|
||||||
} |
|
||||||
} |
|
||||||
if (props.size() == 0) { |
|
||||||
// no external properties file, loading from classpath
|
|
||||||
File propFile = new File(PathAndFileUtils.getWebinfPath() + File.separator + "conf" + File.separator + "his1_databases.properties"); |
|
||||||
if (!propFile.exists()) { |
|
||||||
logger.warn("No his1_databasees.properties found. Will try to load from db.properties!"); |
|
||||||
return readDbProperties(); |
|
||||||
} |
|
||||||
try(FileInputStream s = new FileInputStream(propFile)){ |
|
||||||
props.load(s); |
|
||||||
} catch (IOException e1) { |
|
||||||
logger.fatal(String.format("Unable to access his1_databases file: %s",e1.getMessage())); |
|
||||||
e1.printStackTrace(); |
|
||||||
} |
|
||||||
} |
|
||||||
Properties manualConfig = manualConfiguration(); |
|
||||||
return mergeProperties(props, manualConfig); |
|
||||||
} |
|
||||||
|
|
||||||
@Deprecated |
|
||||||
|
|
||||||
private static void inject_extra_connections_properties(Properties props){ |
|
||||||
String FileName = "extra_connections.properties"; |
|
||||||
File extra_connections_file_path = new File(PathAndFileUtils.getWebinfPath() + File.separator + "conf" + File.separator + FileName); |
|
||||||
try (FileInputStream s = new FileInputStream(extra_connections_file_path)){ |
|
||||||
props.load(s); |
|
||||||
} catch (IOException e1) { |
|
||||||
logger.info("Unable to access properties file where extra connections as described: " + e1.getMessage()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private static Properties manualConfiguration() { |
|
||||||
Properties optProps = new Properties(); |
|
||||||
File poolConf = new File(PathAndFileUtils.getWebinfPath() + File.separator + "conf" + File.separator + "his1_db_poolsize.properties"); |
|
||||||
try(FileInputStream s = new FileInputStream(poolConf)){ |
|
||||||
optProps.load(s); |
|
||||||
//inject_extra_connections_properties(optProps);
|
|
||||||
} catch (IOException e1) { |
|
||||||
logger.info("Unable to access manual poolsize configuration\nSkipping manual poolsize configuration - setting defaults: "+e1.getMessage()); |
|
||||||
} |
|
||||||
return optProps; |
|
||||||
} |
|
||||||
|
|
||||||
private static Properties mergeProperties(Properties... properties) { |
|
||||||
return Stream.of(properties).collect(Properties::new, Map::putAll, Map::putAll); |
|
||||||
} |
|
||||||
|
|
||||||
private static Cipher getDesCipher() throws NoSuchAlgorithmException, NoSuchPaddingException { |
|
||||||
return Cipher.getInstance("DES"); |
|
||||||
} |
|
||||||
|
|
||||||
private static String decryptDbPassword(String password) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { |
|
||||||
if(password == null || password.equals("")) { |
|
||||||
return null; |
|
||||||
}else if(!password.startsWith("sx_des")) { |
|
||||||
return password; |
|
||||||
} |
|
||||||
|
|
||||||
if(desCipher == null) { |
|
||||||
desCipher = getDesCipher(); |
|
||||||
} |
|
||||||
|
|
||||||
String[] stext = password.substring(7).split("#"); |
|
||||||
byte[] bstext = new byte[stext.length]; |
|
||||||
for(int i = 0; i<stext.length;i++) { |
|
||||||
bstext[i] = Byte.parseByte(stext[i]); |
|
||||||
} |
|
||||||
desCipher.init(Cipher.DECRYPT_MODE, KEY); |
|
||||||
byte[] decrypted = desCipher.doFinal(bstext); |
|
||||||
return new String(decrypted, StandardCharsets.UTF_8); |
|
||||||
} |
|
||||||
|
|
||||||
private static Map<String,Map<String,String>> fetchConnections() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { |
|
||||||
Map<String,Map<String,String>> connections = new HashMap<>(); |
|
||||||
Properties props = fetchProperties(); |
|
||||||
String[] dbconnections = props.get("dbconnections").toString().split(","); |
|
||||||
final Set<String> propertyNames = props.stringPropertyNames(); |
|
||||||
for (String s : dbconnections) { |
|
||||||
Map<String,String> properties = new HashMap<>(); |
|
||||||
logger.info(String.format("%s connection retrieved from HISinOne", s)); |
|
||||||
List<String> keys = propertyNames.stream().filter(it -> it.startsWith("db." + s + ".")).collect(Collectors.toList()); |
|
||||||
for (String key : keys) { |
|
||||||
String value = props.getProperty(key); |
|
||||||
if (key.endsWith("password")) { |
|
||||||
value = decryptDbPassword(value.trim()); |
|
||||||
} |
|
||||||
properties.put(key.substring(key.lastIndexOf('.') + 1), value); |
|
||||||
} |
|
||||||
connections.put(s, properties); |
|
||||||
} |
|
||||||
return connections; |
|
||||||
} |
|
||||||
|
|
||||||
private static Properties readDbProperties() { |
|
||||||
Properties properties = new Properties(); |
|
||||||
String webinfpfad=PathAndFileUtils.getWebinfPath(); |
|
||||||
|
|
||||||
File dbPropertiesFile = new File( webinfpfad |
|
||||||
+ File.separator |
|
||||||
+ "db.properties"); |
|
||||||
if (dbPropertiesFile.exists()) { |
|
||||||
try { |
|
||||||
Properties dbProperties = new Properties(); |
|
||||||
dbProperties.load(new FileReader(dbPropertiesFile)); |
|
||||||
properties = convertDbProperties(dbProperties); |
|
||||||
} catch (Exception e) { |
|
||||||
throw new RuntimeException("Couldn't read db.properties!", e); |
|
||||||
} |
|
||||||
} else { |
|
||||||
throw new RuntimeException("Couldn't read " + dbPropertiesFile.getAbsolutePath() + " because file doesn't exist!"); |
|
||||||
} |
|
||||||
return properties; |
|
||||||
} |
|
||||||
|
|
||||||
public static Properties convertDbProperties(Properties dbProperties) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException { |
|
||||||
Properties his1Properties = new Properties(); |
|
||||||
String jdbcUrl = dbProperties.getProperty("connectionURL"); |
|
||||||
String user = dbProperties.getProperty("connectionName"); |
|
||||||
String password = decryptDbPassword(dbProperties.getProperty("connectionPassword")); |
|
||||||
String sslmode = dbProperties.getProperty("sslmode"); |
|
||||||
String driver = dbProperties.getProperty("driverName"); |
|
||||||
String[] urlParts = analyzeJdbcUrl(jdbcUrl); |
|
||||||
String prefix = "db.eduetl."; |
|
||||||
Map<String,String> config = Map.ofEntries( |
|
||||||
entry(prefix + DbPropertyName.user.name(), user), |
|
||||||
entry(prefix + DbPropertyName.password.name(), password), |
|
||||||
entry(prefix + DbPropertyName.jdbcDriver.name(), driver), |
|
||||||
entry(prefix + DbPropertyName.ssl.name(), sslmode != null && sslmode.equalsIgnoreCase("require") ? "true" : "false"), |
|
||||||
entry(prefix + DbPropertyName.protocol.name(), urlParts[0]), |
|
||||||
entry(prefix + DbPropertyName.host.name(), urlParts[1]), |
|
||||||
entry(prefix + DbPropertyName.dbserverport.name(), urlParts[2]), |
|
||||||
entry(prefix + DbPropertyName.database.name(), urlParts[3]), |
|
||||||
entry(prefix + DbPropertyName.url.name(), jdbcUrl), |
|
||||||
entry(DbPropertyName.dbconnections.name(), "eduetl") |
|
||||||
|
|
||||||
); |
|
||||||
his1Properties.putAll(config); |
|
||||||
return his1Properties; |
|
||||||
} |
|
||||||
|
|
||||||
public static String[] analyzeJdbcUrl(String jdbcUrl) { |
|
||||||
int protocolEndIndex = jdbcUrl.indexOf("//"); |
|
||||||
int portBeginIndex = jdbcUrl.indexOf(":", protocolEndIndex); |
|
||||||
int dbBeginIndex = jdbcUrl.indexOf("/", portBeginIndex); |
|
||||||
int dbEndIndex = jdbcUrl.indexOf("?"); String protocol = jdbcUrl.substring(0, protocolEndIndex); |
|
||||||
String host = jdbcUrl.substring(protocolEndIndex + 2, portBeginIndex); |
|
||||||
String port = jdbcUrl.substring(portBeginIndex + 1, dbBeginIndex); |
|
||||||
String db = jdbcUrl.substring(dbBeginIndex + 1, dbEndIndex == -1 ? jdbcUrl.length() : dbEndIndex); |
|
||||||
return new String[] { |
|
||||||
protocol, host, port, db |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public static HikariDataSource convertConnection(String connectionName, Map<String,String> co, long leakDetectionThreshold, long connectionTimeout){ |
|
||||||
HikariConfig conf = new HikariConfig(); |
|
||||||
conf.setUsername(co.get(DbPropertyName.user.name())); |
|
||||||
conf.setPassword(co.get(DbPropertyName.password.name())); |
|
||||||
conf.setDriverClassName(co.get(DbPropertyName.jdbcDriver.name())); |
|
||||||
conf.setJdbcUrl(co.get(DbPropertyName.url.name())); |
|
||||||
if (co.get(DbPropertyName.pgschema.name()) != null) { |
|
||||||
conf.setSchema(co.get(DbPropertyName.pgschema.name())); |
|
||||||
} else if ("hisinone".equals(connectionName)) { |
|
||||||
conf.setSchema("hisinone"); |
|
||||||
} |
|
||||||
if (co.get(DbPropertyName.reconnectAfter.name()) != null) { |
|
||||||
// Angabe reconnectAfter in der databases.xml ist in Minuten!
|
|
||||||
conf.setMaxLifetime(Long.parseLong(co.get(DbPropertyName.reconnectAfter.name())) * 60000); |
|
||||||
} |
|
||||||
conf.setPoolName(connectionName); |
|
||||||
conf.setLeakDetectionThreshold(leakDetectionThreshold); |
|
||||||
conf.setConnectionTimeout(connectionTimeout); |
|
||||||
// in HISinOne-BI context: Set PostgreSQL variables to be consistent with
|
|
||||||
// HISinOne itself (which also does some settings - see "DbHandler")
|
|
||||||
if (co.get(DbPropertyName.jdbcDriver.name()).equals(org.postgresql.Driver.class.getCanonicalName())) { |
|
||||||
if (System.getProperty(SuperXManager.SUPER_X_HISINONE_VERSION) != null) { |
|
||||||
conf.setConnectionInitSql( |
|
||||||
"SET standard_conforming_strings TO 'off'; SET datestyle TO 'ISO, DMY';" |
|
||||||
); |
|
||||||
} else if ("eduetl".equals(connectionName)) { |
|
||||||
conf.setConnectionInitSql( |
|
||||||
"SET datestyle TO 'ISO, DMY';" |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
||||||
String minConnectionsStr = co.get("poolsize_min"); |
|
||||||
String maxConnectionsStr = co.get("poolsize_max"); |
|
||||||
int defaultPoolSize = "eduetl".equals(connectionName) ? AppConfig.EDUETL_POOL_SIZE : AppConfig.DEFAULT_POOL_SIZE; |
|
||||||
int maxConnections = maxConnectionsStr != null ? Integer.parseInt(maxConnectionsStr) : defaultPoolSize; |
|
||||||
int minConnections = minConnectionsStr != null ? Integer.parseInt(minConnectionsStr) : maxConnections; |
|
||||||
conf.setMinimumIdle(minConnections); |
|
||||||
logger.info(String.format("HikariPool for %s initialized with a minimum of %s idle connections.", connectionName, Integer.toString(minConnections))); |
|
||||||
conf.setMaximumPoolSize(maxConnections); |
|
||||||
logger.info(String.format("HikariPool for %s initialized with a maximum of %s connections", connectionName, Integer.toString(maxConnections))); |
|
||||||
addDataSourceProperties(conf, co); |
|
||||||
conf.setExceptionOverrideClassName("de.superx.db.HikariSqlExceptionOverride"); |
|
||||||
HikariDataSource ds = null; |
|
||||||
try { |
|
||||||
ds = new HikariDataSource(conf); |
|
||||||
} catch(Exception ex) { |
|
||||||
logger.error("Couldn't create Hikaripool for " + connectionName, ex); |
|
||||||
} |
|
||||||
return ds; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
private static void addDataSourceProperties(HikariConfig conf, Map<String, String> co) { |
|
||||||
for (Entry<String,String> e : co.entrySet()) { |
|
||||||
if (!DbPropertyName.isStandard(e.getKey())) { |
|
||||||
conf.addDataSourceProperty(e.getKey(), e.getValue()); |
|
||||||
logger.debug("Set additional db property " + e.getKey() + " to " + e.getValue()); |
|
||||||
} |
|
||||||
} |
|
||||||
conf.addDataSourceProperty("ApplicationName", "HIS-BI"); |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -0,0 +1,301 @@ |
|||||||
|
package de.superx.spring; |
||||||
|
|
||||||
|
import static java.util.Map.entry; |
||||||
|
|
||||||
|
import java.io.File; |
||||||
|
import java.io.FileInputStream; |
||||||
|
import java.io.FileReader; |
||||||
|
import java.io.IOException; |
||||||
|
import java.nio.charset.StandardCharsets; |
||||||
|
import java.security.InvalidKeyException; |
||||||
|
import java.security.NoSuchAlgorithmException; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.Map.Entry; |
||||||
|
import java.util.Properties; |
||||||
|
import java.util.Set; |
||||||
|
import java.util.stream.Collectors; |
||||||
|
import java.util.stream.Stream; |
||||||
|
|
||||||
|
import javax.crypto.BadPaddingException; |
||||||
|
import javax.crypto.Cipher; |
||||||
|
import javax.crypto.IllegalBlockSizeException; |
||||||
|
import javax.crypto.NoSuchPaddingException; |
||||||
|
import javax.crypto.spec.SecretKeySpec; |
||||||
|
|
||||||
|
import org.apache.log4j.Logger; |
||||||
|
import org.springframework.core.io.ClassPathResource; |
||||||
|
|
||||||
|
import com.zaxxer.hikari.HikariConfig; |
||||||
|
import com.zaxxer.hikari.HikariDataSource; |
||||||
|
|
||||||
|
import de.superx.servlet.SuperXManager; |
||||||
|
import de.superx.spring.config.BatchConfig; |
||||||
|
import de.superx.util.PathAndFileUtils; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class HIS1Databases { |
||||||
|
|
||||||
|
public static final String HIS1_DATABASES_PROPERTIES = "HIS1_DATABASES_PROPERTIES"; |
||||||
|
private static final byte[] KEY_DATA = { -108, -50, -5, -75, -98, 28, -116, 107 }; |
||||||
|
private static final SecretKeySpec KEY = new SecretKeySpec(KEY_DATA, "DES"); |
||||||
|
private static Cipher desCipher; |
||||||
|
|
||||||
|
private static Logger logger = Logger.getLogger(HIS1Databases.class); |
||||||
|
|
||||||
|
private HIS1Databases() { //Mit Ausnahmegenehmigung
|
||||||
|
//Prevent instantiation
|
||||||
|
} |
||||||
|
|
||||||
|
public static Map<String,Map<String,String>> getAllConnections() throws |
||||||
|
InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException{ |
||||||
|
return fetchConnections(); |
||||||
|
} |
||||||
|
|
||||||
|
public static Map<String,Map<String,String>> getValidConnections() throws |
||||||
|
InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException{ |
||||||
|
Map<String,Map<String,String>> conns = getAllConnections(); |
||||||
|
logger.info("Got connections: " + conns.keySet()); |
||||||
|
Map<String,Map<String,String>> validConns = new HashMap<>(); |
||||||
|
for (String key : conns.keySet()) { |
||||||
|
Map<String,String> connectionProperties = conns.get(key); |
||||||
|
if ( |
||||||
|
connectionProperties.get(DbPropertyName.database.name()) != null |
||||||
|
&&connectionProperties.get(DbPropertyName.user.name()) != null |
||||||
|
&& connectionProperties.get(DbPropertyName.url.name()) != null |
||||||
|
&& connectionProperties.get(DbPropertyName.protocol.name()) != null |
||||||
|
&& connectionProperties.get(DbPropertyName.jdbcDriver.name()) != null |
||||||
|
|
||||||
|
) { |
||||||
|
logger.info("Valid connection: " + key); |
||||||
|
validConns.put(key, connectionProperties); |
||||||
|
} else { |
||||||
|
logger.warn("Invalid connection: " + key); |
||||||
|
} |
||||||
|
} |
||||||
|
return validConns; |
||||||
|
} |
||||||
|
|
||||||
|
public static Map<String,String> getConnection(String connectionName) throws |
||||||
|
InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException{ |
||||||
|
Map<String,Map<String,String>> connections = fetchConnections(); |
||||||
|
return connections.get(connectionName) != null ? connections.get(connectionName) : new HashMap<>(); |
||||||
|
} |
||||||
|
|
||||||
|
private static Properties fetchProperties() { |
||||||
|
Properties props = new Properties(); |
||||||
|
String databasesPropertiesFileName = System.getProperty(HIS1_DATABASES_PROPERTIES); |
||||||
|
if (databasesPropertiesFileName != null) { |
||||||
|
File databasePropertiesFile = new File(databasesPropertiesFileName); |
||||||
|
if (databasePropertiesFile.exists()) { |
||||||
|
logger.info("Reading database properties from " + databasesPropertiesFileName); |
||||||
|
try { |
||||||
|
props.load(new FileInputStream(databasePropertiesFile)); |
||||||
|
} catch (Exception e) { |
||||||
|
logger.error("Couldn't load database properties from " + databasesPropertiesFileName,e); |
||||||
|
} |
||||||
|
} else { |
||||||
|
logger.error("HIS1_DATABASES_PROPERTIES file not found: " + databasesPropertiesFileName); |
||||||
|
} |
||||||
|
} |
||||||
|
if (props.size() == 0) { |
||||||
|
// no external properties file, loading from classpath
|
||||||
|
File propFile = new File(PathAndFileUtils.getWebinfPath() + File.separator + "conf" + File.separator + "his1_databases.properties"); |
||||||
|
if (!propFile.exists()) { |
||||||
|
logger.warn("No his1_databasees.properties found. Will try to load from db.properties!"); |
||||||
|
return readDbProperties(); |
||||||
|
} |
||||||
|
try(FileInputStream s = new FileInputStream(propFile)){ |
||||||
|
props.load(s); |
||||||
|
} catch (IOException e1) { |
||||||
|
logger.fatal(String.format("Unable to access his1_databases file: %s",e1.getMessage())); |
||||||
|
e1.printStackTrace(); |
||||||
|
} |
||||||
|
} |
||||||
|
Properties manualConfig = manualConfiguration(); |
||||||
|
return mergeProperties(props, manualConfig); |
||||||
|
} |
||||||
|
|
||||||
|
private static Properties manualConfiguration() { |
||||||
|
Properties optProps = new Properties(); |
||||||
|
File poolConf = new File(PathAndFileUtils.getWebinfPath() + File.separator + "conf" + File.separator + "his1_db_poolsize.properties"); |
||||||
|
try(FileInputStream s = new FileInputStream(poolConf)){ |
||||||
|
optProps.load(s); |
||||||
|
} catch (IOException e1) { |
||||||
|
logger.info("Unable to access manual poolsize configuration\nSkipping manual poolsize configuration - setting defaults: "+e1.getMessage()); |
||||||
|
} |
||||||
|
return optProps; |
||||||
|
} |
||||||
|
|
||||||
|
private static Properties mergeProperties(Properties... properties) { |
||||||
|
return Stream.of(properties).collect(Properties::new, Map::putAll, Map::putAll); |
||||||
|
} |
||||||
|
|
||||||
|
private static Cipher getDesCipher() throws NoSuchAlgorithmException, NoSuchPaddingException { |
||||||
|
return Cipher.getInstance("DES"); |
||||||
|
} |
||||||
|
|
||||||
|
private static String decryptDbPassword(String password) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { |
||||||
|
if(password == null || password.equals("")) { |
||||||
|
return null; |
||||||
|
}else if(!password.startsWith("sx_des")) { |
||||||
|
return password; |
||||||
|
} |
||||||
|
|
||||||
|
if(desCipher == null) { |
||||||
|
desCipher = getDesCipher(); |
||||||
|
} |
||||||
|
|
||||||
|
String[] stext = password.substring(7).split("#"); |
||||||
|
byte[] bstext = new byte[stext.length]; |
||||||
|
for(int i = 0; i<stext.length;i++) { |
||||||
|
bstext[i] = Byte.parseByte(stext[i]); |
||||||
|
} |
||||||
|
desCipher.init(Cipher.DECRYPT_MODE, KEY); |
||||||
|
byte[] decrypted = desCipher.doFinal(bstext); |
||||||
|
return new String(decrypted, StandardCharsets.UTF_8); |
||||||
|
} |
||||||
|
|
||||||
|
private static Map<String,Map<String,String>> fetchConnections() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { |
||||||
|
Map<String,Map<String,String>> connections = new HashMap<>(); |
||||||
|
Properties props = fetchProperties(); |
||||||
|
String[] dbconnections = props.get("dbconnections").toString().split(","); |
||||||
|
final Set<String> propertyNames = props.stringPropertyNames(); |
||||||
|
for (String s : dbconnections) { |
||||||
|
Map<String,String> properties = new HashMap<>(); |
||||||
|
logger.info(String.format("%s connection retrieved from HISinOne", s)); |
||||||
|
List<String> keys = propertyNames.stream().filter(it -> it.startsWith("db." + s + ".")).collect(Collectors.toList()); |
||||||
|
for (String key : keys) { |
||||||
|
String value = props.getProperty(key); |
||||||
|
if (key.endsWith("password")) { |
||||||
|
value = decryptDbPassword(value.trim()); |
||||||
|
} |
||||||
|
properties.put(key.substring(key.lastIndexOf('.') + 1), value); |
||||||
|
} |
||||||
|
connections.put(s, properties); |
||||||
|
} |
||||||
|
return connections; |
||||||
|
} |
||||||
|
|
||||||
|
private static Properties readDbProperties() { |
||||||
|
Properties properties = new Properties(); |
||||||
|
String webinfpfad=PathAndFileUtils.getWebinfPath(); |
||||||
|
|
||||||
|
File dbPropertiesFile = new File( webinfpfad |
||||||
|
+ File.separator |
||||||
|
+ "db.properties"); |
||||||
|
if (dbPropertiesFile.exists()) { |
||||||
|
try { |
||||||
|
Properties dbProperties = new Properties(); |
||||||
|
dbProperties.load(new FileReader(dbPropertiesFile)); |
||||||
|
properties = convertDbProperties(dbProperties); |
||||||
|
} catch (Exception e) { |
||||||
|
throw new RuntimeException("Couldn't read db.properties!", e); |
||||||
|
} |
||||||
|
} else { |
||||||
|
throw new RuntimeException("Couldn't read " + dbPropertiesFile.getAbsolutePath() + " because file doesn't exist!"); |
||||||
|
} |
||||||
|
return properties; |
||||||
|
} |
||||||
|
|
||||||
|
public static Properties convertDbProperties(Properties dbProperties) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException { |
||||||
|
Properties his1Properties = new Properties(); |
||||||
|
String jdbcUrl = dbProperties.getProperty("connectionURL"); |
||||||
|
String user = dbProperties.getProperty("connectionName"); |
||||||
|
String password = decryptDbPassword(dbProperties.getProperty("connectionPassword")); |
||||||
|
String sslmode = dbProperties.getProperty("sslmode"); |
||||||
|
String driver = dbProperties.getProperty("driverName"); |
||||||
|
String[] urlParts = analyzeJdbcUrl(jdbcUrl); |
||||||
|
String prefix = "db.eduetl."; |
||||||
|
Map<String,String> config = Map.ofEntries( |
||||||
|
entry(prefix + DbPropertyName.user.name(), user), |
||||||
|
entry(prefix + DbPropertyName.password.name(), password), |
||||||
|
entry(prefix + DbPropertyName.jdbcDriver.name(), driver), |
||||||
|
entry(prefix + DbPropertyName.ssl.name(), sslmode != null && sslmode.equalsIgnoreCase("require") ? "true" : "false"), |
||||||
|
entry(prefix + DbPropertyName.protocol.name(), urlParts[0]), |
||||||
|
entry(prefix + DbPropertyName.host.name(), urlParts[1]), |
||||||
|
entry(prefix + DbPropertyName.dbserverport.name(), urlParts[2]), |
||||||
|
entry(prefix + DbPropertyName.database.name(), urlParts[3]), |
||||||
|
entry(prefix + DbPropertyName.url.name(), jdbcUrl), |
||||||
|
entry(DbPropertyName.dbconnections.name(), "eduetl") |
||||||
|
|
||||||
|
); |
||||||
|
his1Properties.putAll(config); |
||||||
|
return his1Properties; |
||||||
|
} |
||||||
|
|
||||||
|
public static String[] analyzeJdbcUrl(String jdbcUrl) { |
||||||
|
int protocolEndIndex = jdbcUrl.indexOf("//"); |
||||||
|
int portBeginIndex = jdbcUrl.indexOf(":", protocolEndIndex); |
||||||
|
int dbBeginIndex = jdbcUrl.indexOf("/", portBeginIndex); |
||||||
|
int dbEndIndex = jdbcUrl.indexOf("?"); String protocol = jdbcUrl.substring(0, protocolEndIndex); |
||||||
|
String host = jdbcUrl.substring(protocolEndIndex + 2, portBeginIndex); |
||||||
|
String port = jdbcUrl.substring(portBeginIndex + 1, dbBeginIndex); |
||||||
|
String db = jdbcUrl.substring(dbBeginIndex + 1, dbEndIndex == -1 ? jdbcUrl.length() : dbEndIndex); |
||||||
|
return new String[] { |
||||||
|
protocol, host, port, db |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public static HikariDataSource convertConnection(String connectionName, Map<String,String> co, long leakDetectionThreshold, long connectionTimeout){ |
||||||
|
HikariConfig conf = new HikariConfig(); |
||||||
|
conf.setUsername(co.get(DbPropertyName.user.name())); |
||||||
|
conf.setPassword(co.get(DbPropertyName.password.name())); |
||||||
|
conf.setDriverClassName(co.get(DbPropertyName.jdbcDriver.name())); |
||||||
|
conf.setJdbcUrl(co.get(DbPropertyName.url.name())); |
||||||
|
if (co.get(DbPropertyName.pgschema.name()) != null) { |
||||||
|
conf.setSchema(co.get(DbPropertyName.pgschema.name())); |
||||||
|
} else if ("hisinone".equals(connectionName)) { |
||||||
|
conf.setSchema("hisinone"); |
||||||
|
} |
||||||
|
if (co.get(DbPropertyName.reconnectAfter.name()) != null) { |
||||||
|
// Angabe reconnectAfter in der databases.xml ist in Minuten!
|
||||||
|
conf.setMaxLifetime(Long.parseLong(co.get(DbPropertyName.reconnectAfter.name())) * 60000); |
||||||
|
} |
||||||
|
conf.setPoolName(connectionName); |
||||||
|
conf.setLeakDetectionThreshold(leakDetectionThreshold); |
||||||
|
conf.setConnectionTimeout(connectionTimeout); |
||||||
|
// in HISinOne-BI context: Set PostgreSQL variables to be consistent with
|
||||||
|
// HISinOne itself (which also does some settings - see "DbHandler")
|
||||||
|
if (co.get(DbPropertyName.jdbcDriver.name()).equals(org.postgresql.Driver.class.getCanonicalName()) && |
||||||
|
System.getProperty(SuperXManager.SUPER_X_HISINONE_VERSION) != null) { |
||||||
|
conf.setConnectionInitSql("SET standard_conforming_strings TO 'off'; SET datestyle TO 'ISO, DMY';"); |
||||||
|
} |
||||||
|
|
||||||
|
String minConnectionsStr = co.get("poolsize_min"); |
||||||
|
String maxConnectionsStr = co.get("poolsize_max"); |
||||||
|
int defaultPoolSize = "eduetl".equals(connectionName) ? BatchConfig.EDUETL_POOL_SIZE : BatchConfig.DEFAULT_POOL_SIZE; |
||||||
|
int maxConnections = maxConnectionsStr != null ? Integer.parseInt(maxConnectionsStr) : defaultPoolSize; |
||||||
|
int minConnections = minConnectionsStr != null ? Integer.parseInt(minConnectionsStr) : maxConnections; |
||||||
|
conf.setMinimumIdle(minConnections); |
||||||
|
logger.info(String.format("HikariPool for %s initialized with a minimum of %s idle connections.", connectionName, Integer.toString(minConnections))); |
||||||
|
conf.setMaximumPoolSize(maxConnections); |
||||||
|
logger.info(String.format("HikariPool for %s initialized with a maximum of %s connections", connectionName, Integer.toString(maxConnections))); |
||||||
|
addDataSourceProperties(conf, co); |
||||||
|
conf.setExceptionOverrideClassName("de.superx.db.HikariSqlExceptionOverride"); |
||||||
|
HikariDataSource ds = null; |
||||||
|
try { |
||||||
|
ds = new HikariDataSource(conf); |
||||||
|
} catch(Exception ex) { |
||||||
|
logger.error("Couldn't create Hikaripool for " + connectionName, ex); |
||||||
|
} |
||||||
|
return ds; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
private static void addDataSourceProperties(HikariConfig conf, Map<String, String> co) { |
||||||
|
for (Entry<String,String> e : co.entrySet()) { |
||||||
|
if (!DbPropertyName.isStandard(e.getKey())) { |
||||||
|
conf.addDataSourceProperty(e.getKey(), e.getValue()); |
||||||
|
logger.debug("Set additional db property " + e.getKey() + " to " + e.getValue()); |
||||||
|
} |
||||||
|
} |
||||||
|
conf.addDataSourceProperty("ApplicationName", "HIS-BI"); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,257 @@ |
|||||||
|
package de.superx.spring.config; |
||||||
|
|
||||||
|
|
||||||
|
import java.io.File; |
||||||
|
import java.nio.file.Path; |
||||||
|
import java.security.InvalidKeyException; |
||||||
|
import java.security.NoSuchAlgorithmException; |
||||||
|
import java.sql.Connection; |
||||||
|
import java.sql.DatabaseMetaData; |
||||||
|
import java.sql.ResultSet; |
||||||
|
import java.sql.SQLException; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.Map.Entry; |
||||||
|
|
||||||
|
import javax.crypto.BadPaddingException; |
||||||
|
import javax.crypto.IllegalBlockSizeException; |
||||||
|
import javax.crypto.NoSuchPaddingException; |
||||||
|
import javax.sql.DataSource; |
||||||
|
|
||||||
|
import org.apache.log4j.Logger; |
||||||
|
import org.springframework.batch.core.Job; |
||||||
|
import org.springframework.batch.core.Step; |
||||||
|
import org.springframework.batch.core.configuration.JobLocator; |
||||||
|
import org.springframework.batch.core.configuration.JobRegistry; |
||||||
|
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; |
||||||
|
import org.springframework.batch.core.explore.JobExplorer; |
||||||
|
import org.springframework.batch.core.job.builder.JobBuilder; |
||||||
|
import org.springframework.batch.core.launch.JobLauncher; |
||||||
|
import org.springframework.batch.core.launch.JobOperator; |
||||||
|
import org.springframework.batch.core.launch.support.SimpleJobOperator; |
||||||
|
import org.springframework.batch.core.launch.support.TaskExecutorJobLauncher; |
||||||
|
import org.springframework.batch.core.repository.JobRepository; |
||||||
|
import org.springframework.batch.core.step.builder.StepBuilder; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.beans.factory.annotation.Value; |
||||||
|
import org.springframework.context.annotation.Bean; |
||||||
|
import org.springframework.context.annotation.ComponentScan; |
||||||
|
import org.springframework.context.annotation.Configuration; |
||||||
|
import org.springframework.context.annotation.Primary; |
||||||
|
import org.springframework.context.annotation.PropertySource; |
||||||
|
import org.springframework.core.io.ClassPathResource; |
||||||
|
import org.springframework.core.io.FileSystemResource; |
||||||
|
import org.springframework.core.task.SimpleAsyncTaskExecutor; |
||||||
|
import org.springframework.jdbc.core.JdbcTemplate; |
||||||
|
import org.springframework.jdbc.datasource.DataSourceTransactionManager; |
||||||
|
import org.springframework.jdbc.datasource.init.ScriptUtils; |
||||||
|
import org.springframework.transaction.PlatformTransactionManager; |
||||||
|
|
||||||
|
import com.zaxxer.hikari.HikariDataSource; |
||||||
|
|
||||||
|
import de.superx.spring.HIS1Databases; |
||||||
|
import de.superx.spring.batch.His1DataSources; |
||||||
|
import de.superx.spring.batch.job.JobUtils; |
||||||
|
import de.superx.spring.batch.tasklet.RemoveSpringBatchHistoryTasklet; |
||||||
|
import de.superx.util.PathAndFileUtils; |
||||||
|
|
||||||
|
|
||||||
|
@Configuration |
||||||
|
@EnableBatchProcessing |
||||||
|
@PropertySource("classpath:spring-batch.properties") |
||||||
|
@PropertySource("classpath:hikari.properties") |
||||||
|
@ComponentScan(basePackages = {"de.superx.spring.service", "de.superx.spring.batch.tasklet", "de.superx.rest", "de.superx.dbt", |
||||||
|
"de.superx.bianalysis.service", "de.superx.bianalysis.rest", "de.superx.access"}) |
||||||
|
public class BatchConfig { |
||||||
|
|
||||||
|
// time in milliseconds after which an exception is
|
||||||
|
// thrown if no connection available in pool
|
||||||
|
@Value("${hikari.connection_timeout:180000}") |
||||||
|
protected Long connectionTimeout; |
||||||
|
|
||||||
|
// time in milliseconds a connection can be out of pool
|
||||||
|
// before an execption gets thrown to prevent connection leaks
|
||||||
|
// (for debug purposes, 0 means disable leak detection)
|
||||||
|
@Value("${hikari.leak_detection_threshold:0}") |
||||||
|
protected Long leakDetectionThreshold; |
||||||
|
|
||||||
|
public static final int DEFAULT_POOL_SIZE = 5; |
||||||
|
public static final int EDUETL_POOL_SIZE = 20; // low pool size led to hanging application on 'muster-head' - former value: 6;
|
||||||
|
|
||||||
|
private static Logger logger = Logger.getLogger(BatchConfig.class); |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private JobRepository jobRepository; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private JobRegistry jobRegistry; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private JobExplorer jobExplorer; |
||||||
|
|
||||||
|
@Bean |
||||||
|
public PlatformTransactionManager transactionManager(DataSource dataSource) { |
||||||
|
return new DataSourceTransactionManager(dataSource); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Bean |
||||||
|
public JobLauncher jobLauncher() throws Exception { |
||||||
|
TaskExecutorJobLauncher jobLauncher = new TaskExecutorJobLauncher(); |
||||||
|
jobLauncher.setJobRepository(jobRepository); |
||||||
|
jobLauncher.setTaskExecutor(new SimpleAsyncTaskExecutor()); |
||||||
|
jobLauncher.afterPropertiesSet(); |
||||||
|
return jobLauncher; |
||||||
|
} |
||||||
|
|
||||||
|
@Bean |
||||||
|
public JobLocator jobLocator() { |
||||||
|
return jobRegistry; |
||||||
|
} |
||||||
|
|
||||||
|
@Bean |
||||||
|
public JobLauncher syncJobLauncher() throws Exception { |
||||||
|
TaskExecutorJobLauncher jobLauncher = new TaskExecutorJobLauncher(); |
||||||
|
jobLauncher.setJobRepository(jobRepository); |
||||||
|
jobLauncher.afterPropertiesSet(); |
||||||
|
return jobLauncher; |
||||||
|
} |
||||||
|
|
||||||
|
@Bean |
||||||
|
public JobOperator jobOperator() throws Exception { |
||||||
|
SimpleJobOperator jobOperator = new SimpleJobOperator(); |
||||||
|
jobOperator.setJobLauncher(jobLauncher()); |
||||||
|
jobOperator.setJobExplorer(jobExplorer); |
||||||
|
jobOperator.setJobRepository(jobRepository); |
||||||
|
jobOperator.setJobRegistry(jobRegistry); |
||||||
|
JobUtils.terminateAllJobExecutions(jobExplorer, jobOperator); |
||||||
|
return jobOperator; |
||||||
|
} |
||||||
|
|
||||||
|
@Bean |
||||||
|
public His1DataSources dataSources() { |
||||||
|
//Map<String, DataSourceDiscardingUserStuff> dataSources = new HashMap<>();
|
||||||
|
Map<String, HikariDataSource> dataSources = new HashMap<>(); |
||||||
|
try { |
||||||
|
for(Entry<String, Map<String,String>> co : HIS1Databases.getValidConnections().entrySet()) { |
||||||
|
HikariDataSource hs = HIS1Databases.convertConnection(co.getKey().toString(), co.getValue(), |
||||||
|
leakDetectionThreshold.longValue(), connectionTimeout.longValue()); |
||||||
|
//DataSourceDiscardingUserStuff dsdu = new DataSourceDiscardingUserStuff(hs);
|
||||||
|
dataSources.put(co.getKey().toString(), hs); |
||||||
|
logger.info(String.format("Connection to %s added to dataSources bean", co.getKey())); |
||||||
|
} |
||||||
|
} catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException |
||||||
|
| BadPaddingException e) { |
||||||
|
logger.fatal(e); |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
return new His1DataSources(dataSources); |
||||||
|
} |
||||||
|
|
||||||
|
@Bean |
||||||
|
public DataSource unrestrictedDataSource() { |
||||||
|
DataSource ds = dataSources().get("eduetl"); |
||||||
|
if (!batchSchemaExists(ds)) { |
||||||
|
dropBatchSchema(ds); |
||||||
|
createBatchSchema(ds); |
||||||
|
} |
||||||
|
upgradeBatchSchema(ds); |
||||||
|
if (!quartzSchemaExists(ds)) { |
||||||
|
createQuartzSchema(ds); |
||||||
|
} |
||||||
|
return ds; |
||||||
|
} |
||||||
|
|
||||||
|
@Bean |
||||||
|
@Primary |
||||||
|
public DataSource dataSource() { |
||||||
|
DataSource ds = new DataSourceDiscardingUserStuff(); |
||||||
|
return ds; |
||||||
|
} |
||||||
|
@Bean |
||||||
|
public Step removeStep(PlatformTransactionManager transactionManager, DataSource dataSource) { |
||||||
|
RemoveSpringBatchHistoryTasklet tasklet = new RemoveSpringBatchHistoryTasklet(); |
||||||
|
tasklet.setJdbcTemplate(new JdbcTemplate(dataSource)); |
||||||
|
|
||||||
|
String name = "removeStep"; |
||||||
|
return new StepBuilder(name, jobRepository) |
||||||
|
.tasklet(tasklet, transactionManager) |
||||||
|
.build(); |
||||||
|
} |
||||||
|
|
||||||
|
@Bean |
||||||
|
public Job removeSpringBatchHistoryJob(Step removeStep) { |
||||||
|
return new JobBuilder("removeSpringBatchHistoryJob", jobRepository) |
||||||
|
.start(removeStep) |
||||||
|
.build(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
//Checks whether the necessary tables for spring batch exist
|
||||||
|
//TODO: Should implement method of creating a dump before creating new schema in case not all tables exist
|
||||||
|
private static boolean batchSchemaExists(DataSource dataSource) { |
||||||
|
int count = 0; |
||||||
|
try(Connection con = dataSource.getConnection()) { |
||||||
|
DatabaseMetaData meta = con.getMetaData(); |
||||||
|
ResultSet resultSet = meta.getTables(null, "public", "batch_%" , new String[] {"TABLE"}); |
||||||
|
while (resultSet.next()) { |
||||||
|
count++; |
||||||
|
} |
||||||
|
} catch (SQLException e) { |
||||||
|
throw new RuntimeException("Couldn't check for spring batch tables", e); |
||||||
|
} |
||||||
|
return count == 6; |
||||||
|
} |
||||||
|
|
||||||
|
private static boolean quartzSchemaExists(DataSource dataSource) { |
||||||
|
try(Connection con = dataSource.getConnection()) { |
||||||
|
DatabaseMetaData meta = con.getMetaData(); |
||||||
|
ResultSet resultSet = meta.getTables(null, "public", "qrtz_%" , new String[] {"TABLE"}); |
||||||
|
if (resultSet.next()) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
} catch (SQLException e) { |
||||||
|
throw new RuntimeException("Couldn't check for spring batch tables", e); |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
private static void createBatchSchema(DataSource dataSource) { |
||||||
|
try (Connection con = dataSource.getConnection()){ |
||||||
|
ScriptUtils.executeSqlScript(con, new ClassPathResource("/org/springframework/batch/core/schema-postgresql.sql")); |
||||||
|
logger.info("Spring Batch schema created;"); |
||||||
|
} catch (Exception e) { |
||||||
|
logger.error("Couldn't create Spring Batch schema!", e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static void dropBatchSchema(DataSource dataSource) { |
||||||
|
try (Connection con = dataSource.getConnection()){ |
||||||
|
ScriptUtils.executeSqlScript(con, new ClassPathResource("/org/springframework/batch/core/schema-drop-postgresql.sql")); |
||||||
|
logger.info("Spring Batch schema dropped;"); |
||||||
|
} catch (Exception e) { |
||||||
|
logger.error("Couldn't drop Spring Batch schema!", e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static void createQuartzSchema(DataSource dataSource) { |
||||||
|
try (Connection con = dataSource.getConnection()){ |
||||||
|
ScriptUtils.executeSqlScript(con, new ClassPathResource("/org/quartz/impl/jdbcjobstore/tables_postgres.sql")); |
||||||
|
logger.info("Quartz schema created;"); |
||||||
|
} catch (Exception e) { |
||||||
|
logger.error("Couldn't create Quartz schema!", e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static void upgradeBatchSchema(DataSource dataSource) { |
||||||
|
try (Connection con = dataSource.getConnection()){ |
||||||
|
File file = new File(String.format("%s/conf/edustore/db/install/upgrade/spring_batch_schema_upgrade.sql", PathAndFileUtils.getWebinfPath())); |
||||||
|
ScriptUtils.executeSqlScript(con, new FileSystemResource(file)); |
||||||
|
logger.info("Spring Batch schema upgraded;"); |
||||||
|
} catch (Exception e) { |
||||||
|
logger.error("Couldn't upgrade Spring Batch schema!", e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -1,48 +0,0 @@ |
|||||||
package de.superx.spring.service; |
|
||||||
|
|
||||||
import org.springframework.context.ApplicationContext; |
|
||||||
import org.springframework.context.ApplicationContextAware; |
|
||||||
import org.springframework.stereotype.Component; |
|
||||||
|
|
||||||
/** |
|
||||||
* Holds the Spring ApplicationContext in a static field. |
|
||||||
* Implemented as a Spring bean so Spring itself injects the context. |
|
||||||
*/ |
|
||||||
@Component |
|
||||||
public class ApplicationContextHolder implements ApplicationContextAware { |
|
||||||
|
|
||||||
private static volatile ApplicationContext context; |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setApplicationContext(ApplicationContext ctx) { |
|
||||||
context = ctx; // called once during startup
|
|
||||||
} |
|
||||||
|
|
||||||
public static <T> T getBean(String beanName, Class<T> requiredType) { |
|
||||||
if (getContext() != null) { |
|
||||||
if (beanName != null && !beanName.isEmpty()) { |
|
||||||
return getContext().getBean(beanName, requiredType); |
|
||||||
} |
|
||||||
return getContext().getBean(requiredType); |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
public static Object getBean(String name) { |
|
||||||
return getContext().getBean(name); |
|
||||||
} |
|
||||||
|
|
||||||
public static <T> T getBean(Class<T> requiredType) { |
|
||||||
return getContext().getBean(requiredType); |
|
||||||
} |
|
||||||
|
|
||||||
/** Public static accessor */ |
|
||||||
public static ApplicationContext getContext() { |
|
||||||
return context; |
|
||||||
} |
|
||||||
|
|
||||||
/** Optional: clear the reference when the webapp stops (helps GC) */ |
|
||||||
public static void clear() { |
|
||||||
context = null; |
|
||||||
} |
|
||||||
} |
|
||||||
@ -0,0 +1,375 @@ |
|||||||
|
/* |
||||||
|
* $Header: /cvsroot/jdbforms/dbforms/src/org/dbforms/util/MultipartRequest.java,v 1.19 2005/02/19 21:26:32 hkollmann Exp $ |
||||||
|
* $Revision: 1.19 $ |
||||||
|
* $Date: 2005/02/19 21:26:32 $ |
||||||
|
* |
||||||
|
* DbForms - a Rapid Application Development Framework |
||||||
|
* Copyright (C) 2001 Joachim Peer <joepeer@excite.com> |
||||||
|
* |
||||||
|
* This library is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU Lesser General Public |
||||||
|
* License as published by the Free Software Foundation; either |
||||||
|
* version 2.1 of the License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* This library is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||||
|
* Lesser General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Lesser General Public |
||||||
|
* License along with this library; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||||
|
*/ |
||||||
|
|
||||||
|
package de.superx.util; |
||||||
|
|
||||||
|
import org.apache.commons.fileupload.DiskFileUpload; |
||||||
|
import org.apache.commons.fileupload.FileItem; |
||||||
|
import org.apache.commons.logging.Log; |
||||||
|
import org.apache.commons.logging.LogFactory; |
||||||
|
|
||||||
|
import java.io.File; |
||||||
|
import java.io.IOException; |
||||||
|
import java.io.InputStream; |
||||||
|
|
||||||
|
import java.util.Enumeration; |
||||||
|
import java.util.Hashtable; |
||||||
|
import java.util.Iterator; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Vector; |
||||||
|
|
||||||
|
import jakarta.servlet.ServletRequest; |
||||||
|
import jakarta.servlet.ServletRequestWrapper; |
||||||
|
import jakarta.servlet.http.HttpServletRequest; |
||||||
|
|
||||||
|
import org.dbforms.util.FileHolder; |
||||||
|
import org.dbforms.util.MultipartRequest; |
||||||
|
import org.dbforms.util.Util; |
||||||
|
import org.dbforms.util.external.FileUtil; |
||||||
|
|
||||||
|
import de.superx.util.multipart.support.DefaultMultipartHttpServletRequest; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* A utility class to handle <code>multipart/form-data</code> requests, the |
||||||
|
* kind of requests that support file uploads. This class emulates the interface
|
||||||
|
* of <code>HttpServletRequest</code>, making it familiar to use. It uses a |
||||||
|
* "push" model where any incoming files are read and saved directly to disk in |
||||||
|
* the constructor. If you wish to have more flexibility, e.g. write the files |
||||||
|
* to a database, use the "pull" model <code>MultipartParser</code> instead. |
||||||
|
* <p> |
||||||
|
* This class can receive arbitrarily large files (up to an artificial limit you |
||||||
|
* can set), and fairly efficiently too. It cannot handle nested data (multipart |
||||||
|
* content within multipart content) or internationalized content (such as non |
||||||
|
* Latin-1 filenames). |
||||||
|
* </p> |
||||||
|
* <p> |
||||||
|
* See the included <a href="upload.war">upload.war </a> for an example of how |
||||||
|
* to use this class. |
||||||
|
* <p> |
||||||
|
* The full file upload specification is contained in experimental RFC 1867, |
||||||
|
* available at <a href="http://www.ietf.org/rfc/rfc1867.txt" |
||||||
|
* http://www.ietf.org/rfc/rfc1867.txt </a>.
|
||||||
|
* </p> |
||||||
|
* <p> |
||||||
|
* PLEASE NOTE: this class uses Multipart Support Classes by Jason Hunter. |
||||||
|
* Copyright (C) 1998 by Jason Hunter. All rights reserved. |
||||||
|
* Use of this class is limited. Please see the LICENSE for more information. |
||||||
|
* Make sure that you project meets the requierements defined by Jason Hunter |
||||||
|
* respective O'reilly! |
||||||
|
* </p> |
||||||
|
* |
||||||
|
* @see MultipartParser |
||||||
|
* |
||||||
|
* @author Jason Hunter |
||||||
|
* @author Geoff Soutter |
||||||
|
* @author Joe Peer - _changed_ it for use in DbForms (i apologize) |
||||||
|
*/ |
||||||
|
public class DbFormsMultipartRequest extends MultipartRequest { |
||||||
|
private static Log logCat = LogFactory.getLog(DbFormsMultipartRequest.class); // logging category
|
||||||
|
|
||||||
|
private Hashtable files = new Hashtable(); // name - UploadedFile
|
||||||
|
|
||||||
|
// for this class
|
||||||
|
//private File dir;
|
||||||
|
private Hashtable parameters = new Hashtable(); // name - Vector of values
|
||||||
|
|
||||||
|
/** |
||||||
|
* Constructs a new MultipartRequest to handle the specified request, |
||||||
|
* {saving any uploaded files to the given directory}, and limiting the |
||||||
|
* upload size to the specified length. If the content is too large, an |
||||||
|
* IOException is thrown. This constructor actually parses the |
||||||
|
* <tt>multipart/form-data</tt> and throws an IOException if there's any |
||||||
|
* problem reading or parsing the request. |
||||||
|
* |
||||||
|
* @param request |
||||||
|
* the servlet request. |
||||||
|
* @param maxPostSize |
||||||
|
* the maximum size of the POST content. |
||||||
|
* @exception IOException |
||||||
|
* if the uploaded content is larger than |
||||||
|
* <tt>maxPostSize</tt> or there's a problem reading or |
||||||
|
* parsing the request. |
||||||
|
*/ |
||||||
|
public DbFormsMultipartRequest(HttpServletRequest request, int maxPostSize) throws IOException { |
||||||
|
super(request, maxPostSize); |
||||||
|
// Sanity check values
|
||||||
|
if (request == null) { |
||||||
|
throw new IllegalArgumentException("request cannot be null"); |
||||||
|
} |
||||||
|
|
||||||
|
// Create a new file upload handler
|
||||||
|
DiskFileUpload upload = new DiskFileUpload(); |
||||||
|
|
||||||
|
// Set upload parameters
|
||||||
|
upload.setSizeMax(maxPostSize); |
||||||
|
|
||||||
|
String tmpDir = System.getProperty("java.io.tmpdir"); |
||||||
|
upload.setRepositoryPath(tmpDir); |
||||||
|
|
||||||
|
// Parse the request
|
||||||
|
try { |
||||||
|
|
||||||
|
// we initilize this list with 'null', as the following unwrapping code should do the work - contrary to the 'org.dbforms.util.MultipartRequest code, from which this is copied
|
||||||
|
List<FileItem> items = null; //upload.parseRequest(request);
|
||||||
|
|
||||||
|
if (items == null || items.size() == 0) { |
||||||
|
ServletRequest originalRequest = request; |
||||||
|
DefaultMultipartHttpServletRequest dmhsr = null; |
||||||
|
while (originalRequest instanceof ServletRequestWrapper) { |
||||||
|
if (originalRequest instanceof DefaultMultipartHttpServletRequest) { |
||||||
|
dmhsr = (DefaultMultipartHttpServletRequest) originalRequest; |
||||||
|
items = dmhsr.getFileItems(); |
||||||
|
break; |
||||||
|
} |
||||||
|
originalRequest = ((ServletRequestWrapper) originalRequest).getRequest(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Iterator iter = items.iterator(); |
||||||
|
|
||||||
|
while (iter.hasNext()) { |
||||||
|
FileItem item = (FileItem) iter.next(); |
||||||
|
String name = item.getFieldName(); |
||||||
|
|
||||||
|
if (item.isFormField()) { |
||||||
|
String value = item.getString(); |
||||||
|
|
||||||
|
// plain parameters get allways into parameters structure
|
||||||
|
Vector existingValues = (Vector) parameters.get(name); |
||||||
|
|
||||||
|
if (existingValues == null) { |
||||||
|
existingValues = new Vector(); |
||||||
|
parameters.put(name, existingValues); |
||||||
|
} |
||||||
|
|
||||||
|
existingValues.addElement(value); |
||||||
|
} else { |
||||||
|
String fileName = item.getName(); |
||||||
|
|
||||||
|
if (!Util.isNull(fileName)) { |
||||||
|
File f = new File(fileName); |
||||||
|
// 2004-08-05-HKK/Dziugas Baltrunas:
|
||||||
|
// FileItem always returns the full pathname!
|
||||||
|
fileName = FileUtil.filename(f.getName()); |
||||||
|
|
||||||
|
// The part actually contained a file
|
||||||
|
// #changes by joe peer:
|
||||||
|
// we must delay storing the file-inputstream (into
|
||||||
|
// database, filesystem or whatever)
|
||||||
|
// until we know exactly what should happen with it
|
||||||
|
FileHolder fileHolder = new FileHolder(fileName, item); |
||||||
|
files.put(name, fileHolder); |
||||||
|
logCat.info("buffered and now added as " + name + " the following fileHolder:" + fileHolder.getFileName()); |
||||||
|
|
||||||
|
// #changes by joe peer:
|
||||||
|
// if a file parameter is not null it gets into the
|
||||||
|
// parameters structures as well
|
||||||
|
// this is important to provide a simple access to
|
||||||
|
// request (no distinction between files and plain
|
||||||
|
// params)
|
||||||
|
Vector existingValues = (Vector) parameters.get(name); |
||||||
|
|
||||||
|
if (existingValues == null) { |
||||||
|
existingValues = new Vector(); |
||||||
|
parameters.put(name, existingValues); |
||||||
|
} |
||||||
|
|
||||||
|
existingValues.addElement(fileName); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (Exception e) { |
||||||
|
logCat.error("MultipartRequest", e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the content type of the specified file (as supplied by the client |
||||||
|
* browser), or null if the file was not included in the upload. |
||||||
|
* |
||||||
|
* @param name |
||||||
|
* the file name. |
||||||
|
* @return the content type of the file. |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public String getContentType(String name) { |
||||||
|
try { |
||||||
|
//#changed by joe peer
|
||||||
|
//UploadedFile file = (UploadedFile)files.get(name);
|
||||||
|
FileHolder filePart = (FileHolder) files.get(name); |
||||||
|
|
||||||
|
return filePart.getContentType(); // may be null
|
||||||
|
} catch (Exception e) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Returns a FilePart object for the specified file this method was added by |
||||||
|
* joe peer |
||||||
|
* |
||||||
|
* @param name |
||||||
|
* the file name. |
||||||
|
* @return a FilePart object for the named file. |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public FileHolder getFileHolder(String name) { |
||||||
|
try { |
||||||
|
return (FileHolder) files.get(name); |
||||||
|
} catch (Exception e) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Returns a InputStream object for the specified file saved on the server's |
||||||
|
* filesystem, or null if the file was not included in the upload. |
||||||
|
* |
||||||
|
* @param name |
||||||
|
* the file name. |
||||||
|
* @return a InputStream object for the named file. |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public InputStream getFileInputStream(String name) { |
||||||
|
try { |
||||||
|
//#changed by joe peer
|
||||||
|
//UploadedFile file = (UploadedFile)files.get(name);
|
||||||
|
FileHolder filePart = (FileHolder) files.get(name); |
||||||
|
|
||||||
|
return filePart.getInputStreamFromBuffer(); // may be null
|
||||||
|
} catch (Exception e) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the names of all the uploaded files as an Enumeration of Strings. |
||||||
|
* It returns an empty Enumeration if there are no uploaded files. Each file |
||||||
|
* name is the name specified by the form, not by the user. |
||||||
|
* |
||||||
|
* @return the names of all the uploaded files as an Enumeration of Strings. |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Enumeration getFileNames() { |
||||||
|
return files.keys(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the filesystem name of the specified file, or null if the file |
||||||
|
* was not included in the upload. A filesystem name is the name specified |
||||||
|
* by the user. It is also the name under which the file is actually saved. |
||||||
|
* |
||||||
|
* @param name |
||||||
|
* the file name. |
||||||
|
* @return the filesystem name of the file. |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public String getFilesystemName(String name) { |
||||||
|
try { |
||||||
|
//#changed by joe peer
|
||||||
|
//UploadedFile file = (UploadedFile)files.get(name);
|
||||||
|
FileHolder filePart = (FileHolder) files.get(name); |
||||||
|
|
||||||
|
return filePart.getFileName(); // may be null
|
||||||
|
} catch (Exception e) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the value of the named parameter as a String, or null if the |
||||||
|
* parameter was not sent or was sent without a value. The value is |
||||||
|
* guaranteed to be in its normal, decoded form. If the parameter has |
||||||
|
* multiple values, only the last one is returned (for backward |
||||||
|
* compatibility). For parameters with multiple values, it's possible the |
||||||
|
* last "value" may be null. |
||||||
|
* |
||||||
|
* @param name |
||||||
|
* the parameter name. |
||||||
|
* @return the parameter value. |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public String getParameter(String name) { |
||||||
|
try { |
||||||
|
Vector values = (Vector) parameters.get(name); |
||||||
|
|
||||||
|
if ((values == null) || (values.size() == 0)) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
String value = (String) values.elementAt(0); |
||||||
|
|
||||||
|
return value; |
||||||
|
} catch (Exception e) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the names of all the parameters as an Enumeration of Strings. It |
||||||
|
* returns an empty Enumeration if there are no parameters. |
||||||
|
* |
||||||
|
* @return the names of all the parameters as an Enumeration of Strings. |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Enumeration getParameterNames() { |
||||||
|
return parameters.keys(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the values of the named parameter as a String array, or null if |
||||||
|
* the parameter was not sent. The array has one entry for each parameter |
||||||
|
* field sent. If any field was sent without a value that entry is stored in |
||||||
|
* the array as a null. The values are guaranteed to be in their normal, |
||||||
|
* decoded form. A single value is returned as a one-element array. |
||||||
|
* |
||||||
|
* @param name |
||||||
|
* the parameter name. |
||||||
|
* @return the parameter values. |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public String[] getParameterValues(String name) { |
||||||
|
try { |
||||||
|
Vector values = (Vector) parameters.get(name); |
||||||
|
|
||||||
|
if ((values == null) || (values.size() == 0)) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
String[] valuesArray = new String[values.size()]; |
||||||
|
values.copyInto(valuesArray); |
||||||
|
|
||||||
|
return valuesArray; |
||||||
|
} catch (Exception e) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue