835 changed files with 123577 additions and 124172 deletions
@ -0,0 +1,16 @@ |
|||||||
|
<?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,46 +1,270 @@ |
|||||||
# ignore all log files |
# agent and copilot context - local/temporary files |
||||||
*.log |
.github/ |
||||||
*.err |
|
||||||
*.log.* |
|
||||||
|
|
||||||
|
# Gradle build output and wrapper cache |
||||||
|
build/ |
||||||
|
.gradle/ |
||||||
|
|
||||||
# ignore all CVS + sub dirs |
# ignore /dist/* |
||||||
*CVS/ |
*dist/ |
||||||
|
|
||||||
# ignore java classes |
# ignore swap files |
||||||
*classes/ |
superx/WEB-INF/reports/swap_* |
||||||
|
|
||||||
# ignore files in directory rohdaten |
# ignore eclipse settings |
||||||
superx/WEB-INF/conf/edustore/db/module/*/rohdaten/unl/*.unl |
.settings/org.eclipse.ltk.core.refactoring.prefs |
||||||
superx/WEB-INF/conf/edustore/db/install/rohdaten/unl/*.unl |
|
||||||
|
|
||||||
# ignore temporary files |
# vim .swp files |
||||||
*.tmp |
*.swp |
||||||
*.tmp.sql |
|
||||||
temp.xml |
|
||||||
tmp.fo |
|
||||||
|
|
||||||
# ignore auto generated files |
# ignore gradle bin |
||||||
db.properties |
scripts/gradle/bin/ |
||||||
dbforms-config.xml |
scripts/gradle/.gradle/ |
||||||
superx/WEB-INF/dbforms-config.old |
|
||||||
superx.datum |
|
||||||
|
|
||||||
# ignore iReport Designer |
# cobertura |
||||||
*.jasper |
superx-build/cobertura* |
||||||
|
|
||||||
# ignore /dist/* |
# classes |
||||||
*dist/ |
superx/WEB-INF/classes/ |
||||||
|
|
||||||
# ignore swap files |
# tag files |
||||||
superx/WEB-INF/reports/swap_* |
**/tags |
||||||
|
|
||||||
src/edustore/edustore_*.xml |
# .orig files |
||||||
|
**/*.orig |
||||||
|
|
||||||
# ignore eclipse settings |
# datum.alt files |
||||||
.settings/org.eclipse.ltk.core.refactoring.prefs |
**/superx.datum.alt |
||||||
#rpta files: |
|
||||||
superx/WEB-INF/reports/simple_table.jrtx |
# script artefacts |
||||||
superx/WEB-INF/reports/tabelle_jrxml_a4_quer.xsl.jrxml |
scripts/**/build/ |
||||||
superx/xml/jr_templates.xsl |
scripts/**/log/ |
||||||
superx/xml/rpta_assistent.xsl |
|
||||||
|
# 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 |
||||||
|
|
||||||
|
|
||||||
|
# module generation artifacts for module kenn |
||||||
|
src/edustore/edustore_kenn.xml |
||||||
|
superx/WEB-INF/kenn_dbforms-config_ids.xml |
||||||
|
superx/WEB-INF/kenn_dbforms-config_pg.xml |
||||||
|
superx/edit/kenn/*edit.jsp |
||||||
|
superx/edit/kenn/*list.jsp |
||||||
|
|
||||||
|
# module generation artifacts for module kennx |
||||||
|
src/edustore/edustore_kennx.xml |
||||||
|
superx/WEB-INF/kennx_dbforms-config_ids.xml |
||||||
|
superx/WEB-INF/kennx_dbforms-config_pg.xml |
||||||
|
superx/edit/kennx/*edit.jsp |
||||||
|
superx/edit/kennx/*list.jsp |
||||||
|
|
||||||
|
|
||||||
|
# module generation artifacts for module man |
||||||
|
src/edustore/edustore_man.xml |
||||||
|
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 |
||||||
|
.vscode/ |
||||||
|
.metadata/ |
||||||
|
|
||||||
|
# edustore.xml soll nicht mehr ausgeliefert werden siehe #313658 |
||||||
|
src/edustore/edustore.xml |
||||||
|
|
||||||
|
# package folder und config file für statisch generierte JSPs |
||||||
|
src/de/superx/jsp/ |
||||||
|
superx/WEB-INF/jsp_servlet_config.xml |
||||||
|
|
||||||
|
# jaspers werden nicht mehr commitet, sondern im build gebaut |
||||||
|
*.jasper |
||||||
|
# updateUnmodifiedJars backup |
||||||
|
superx/WEB-INF/lib/backup/ |
||||||
|
|||||||
@ -0,0 +1,901 @@ |
|||||||
|
/* |
||||||
|
* 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; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,366 @@ |
|||||||
|
/* |
||||||
|
* $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; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,699 @@ |
|||||||
|
/* |
||||||
|
* 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.
|
@ -0,0 +1,11 @@ |
|||||||
|
package de.superx.bianalysis.service; |
||||||
|
|
||||||
|
public class IllegalMetaDataOperation extends Exception { |
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L; |
||||||
|
|
||||||
|
public IllegalMetaDataOperation(String message) { |
||||||
|
super(message); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,110 @@ |
|||||||
|
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; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,11 @@ |
|||||||
|
package de.superx.dbt; |
||||||
|
|
||||||
|
public enum DbtAction { |
||||||
|
BUILD, |
||||||
|
TEST, |
||||||
|
GENERATE_DOCS, |
||||||
|
STAGING_TABLES, |
||||||
|
SQLFLUFF_LINT, |
||||||
|
NODE_COUNT_BUILD, |
||||||
|
NODE_COUNT_TEST |
||||||
|
} |
||||||
@ -0,0 +1,8 @@ |
|||||||
|
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 |
||||||
|
} |
||||||
@ -1,59 +0,0 @@ |
|||||||
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; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -0,0 +1,7 @@ |
|||||||
|
package de.superx.dbt; |
||||||
|
|
||||||
|
public class DbtPermissionException extends Exception { |
||||||
|
DbtPermissionException(String message, Throwable cause) { |
||||||
|
super(message, cause); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,443 @@ |
|||||||
|
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); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,24 @@ |
|||||||
|
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); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,62 @@ |
|||||||
|
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; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,43 @@ |
|||||||
|
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; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,9 @@ |
|||||||
|
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> { |
||||||
|
} |
||||||
@ -1,446 +0,0 @@ |
|||||||
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
@ -0,0 +1,130 @@ |
|||||||
|
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; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,48 @@ |
|||||||
|
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; |
||||||
|
} |
||||||
|
} |
||||||
@ -1,375 +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 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; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -0,0 +1,18 @@ |
|||||||
|
package de.superx.util; |
||||||
|
|
||||||
|
import javax.sql.DataSource; |
||||||
|
import org.springframework.jdbc.core.JdbcTemplate; |
||||||
|
|
||||||
|
public final class DbUtils { |
||||||
|
|
||||||
|
private DbUtils() { } |
||||||
|
|
||||||
|
public static boolean isModuleInstalled(DataSource dataSource, String moduleAbbreviation) { |
||||||
|
String sql = "SELECT COUNT(*) FROM db_version WHERE his_system = ?"; |
||||||
|
|
||||||
|
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); |
||||||
|
Integer count = jdbcTemplate.queryForObject(sql, Integer.class, moduleAbbreviation); |
||||||
|
|
||||||
|
return count != null && count.intValue() > 0; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,4 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<!--Automatisch generiert von Edustore durch mondrian_schema_3.xsl 01.07.2023 10:52:04--> |
||||||
|
<Schema name="HISinOne"> |
||||||
|
</Schema> |
||||||
@ -1,24 +0,0 @@ |
|||||||
clean |
|
||||||
cleanBuildPath |
|
||||||
cleanTestDirs |
|
||||||
compile |
|
||||||
compile-testclasses |
|
||||||
compileJasperFiles |
|
||||||
compileSuperx |
|
||||||
create_all_modules |
|
||||||
create_test_db_eduetl |
|
||||||
cvs_checkout_eduetl_dbconv_sch |
|
||||||
delete_test_db_eduetl |
|
||||||
distApplet |
|
||||||
distApplet2 |
|
||||||
distServer |
|
||||||
dist_his1 |
|
||||||
his_icons_for_saiku |
|
||||||
initTestDirs |
|
||||||
initTimestamp |
|
||||||
module_checksum |
|
||||||
standalone |
|
||||||
test |
|
||||||
testcase |
|
||||||
war |
|
||||||
war_his1 |
|
||||||
@ -1,3 +0,0 @@ |
|||||||
Application-Name: SuperX |
|
||||||
Main-Class: de.superx.applet.SuperX |
|
||||||
Permissions: all-permissions |
|
||||||
@ -1,4 +0,0 @@ |
|||||||
de/memtext/**/*.* |
|
||||||
de/superx/applet/*.class |
|
||||||
de/superx/common/*.class |
|
||||||
*.properties |
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue