From 88f587963bbd80a300e22d463c22e3fd70b765f8 Mon Sep 17 00:00:00 2001 From: Daniel Quathamer Date: Mon, 26 Oct 2026 09:59:06 +0100 Subject: [PATCH] Anpassung Kern 6.0, HISinOne BI 2026.12 #2 --- .classpath | 52 +- build.xml | 38 +- src-modules/module/etl/conf/etl.xml | 4 +- .../etl/schluesseltabellen/etl_step_type.unl | 10 +- .../elt/ActionHandler/EtlActionHandler.java | 131 --- .../EtlActionHandlerDoquery.java | 48 -- .../ActionHandler/EtlActionHandlerDosql.java | 71 -- .../elt/ActionHandler/EtlActionHandlerI.java | 34 - .../ActionHandler/EtlActionHandlerMsg.java | 30 - .../EtlActionHandlerUnloadRecords.java | 43 - .../EtlActionHandlerUploadRecords.java | 58 -- src/de/superx/elt/EtlAction.java | 201 ----- src/de/superx/elt/EtlActionJob.java | 243 ------ src/de/superx/elt/EtlFmParser.java | 137 --- src/de/superx/elt/EtlStep.java | 239 ------ src/de/superx/elt/EtlUtils.java | 353 -------- src/de/superx/elt/QueryResultSerializer.java | 437 ---------- src/de/superx/elt/SqlExecutor.java | 344 -------- src/de/superx/elt/TableUploader.java | 779 ----------------- src/de/superx/elt/bin/Doquery.java | 212 ----- src/de/superx/elt/bin/Dosql.java | 192 ----- src/de/superx/elt/bin/EtlJobExecutor.java | 70 -- src/de/superx/elt/bin/SxTransformer.java | 796 ------------------ src/de/superx/elt/bin/UnloadRecords.java | 214 ----- src/de/superx/elt/bin/UploadRecords.java | 94 --- src/de/superx/elt/util/FileUtils.java | 98 --- src/de/superx/elt/util/GetOpts.java | 155 ---- src/de/superx/elt/util/GetOptsBackport.java | 220 ----- src/de/superx/rest/JobEtlXml.java | 134 +++ src/de/superx/sxrest/JobEtlXml.java | 213 ----- src/de/superx/sxrest/JobExecutor.java | 47 -- src/de/superx/sxrest/LaunchUpgrade.java | 81 -- src/de/superx/sxrest/MaskXml.java | 200 ----- .../lib/spring-context-indexer-6.2.19.jar | Bin 0 -> 27487 bytes superx/WEB-INF/lib/superx-etl.jar | Bin 86206 -> 3903 bytes superx/edit/etl/etl_manager.jsp | 30 +- superx/edit/etl/saveEtlXml.jsp | 8 +- 37 files changed, 231 insertions(+), 5785 deletions(-) delete mode 100644 src/de/superx/elt/ActionHandler/EtlActionHandler.java delete mode 100644 src/de/superx/elt/ActionHandler/EtlActionHandlerDoquery.java delete mode 100644 src/de/superx/elt/ActionHandler/EtlActionHandlerDosql.java delete mode 100644 src/de/superx/elt/ActionHandler/EtlActionHandlerI.java delete mode 100644 src/de/superx/elt/ActionHandler/EtlActionHandlerMsg.java delete mode 100644 src/de/superx/elt/ActionHandler/EtlActionHandlerUnloadRecords.java delete mode 100644 src/de/superx/elt/ActionHandler/EtlActionHandlerUploadRecords.java delete mode 100644 src/de/superx/elt/EtlAction.java delete mode 100644 src/de/superx/elt/EtlActionJob.java delete mode 100644 src/de/superx/elt/EtlFmParser.java delete mode 100644 src/de/superx/elt/EtlStep.java delete mode 100644 src/de/superx/elt/EtlUtils.java delete mode 100644 src/de/superx/elt/QueryResultSerializer.java delete mode 100644 src/de/superx/elt/SqlExecutor.java delete mode 100644 src/de/superx/elt/TableUploader.java delete mode 100644 src/de/superx/elt/bin/Doquery.java delete mode 100644 src/de/superx/elt/bin/Dosql.java delete mode 100644 src/de/superx/elt/bin/EtlJobExecutor.java delete mode 100644 src/de/superx/elt/bin/SxTransformer.java delete mode 100644 src/de/superx/elt/bin/UnloadRecords.java delete mode 100644 src/de/superx/elt/bin/UploadRecords.java delete mode 100644 src/de/superx/elt/util/FileUtils.java delete mode 100644 src/de/superx/elt/util/GetOpts.java delete mode 100644 src/de/superx/elt/util/GetOptsBackport.java create mode 100644 src/de/superx/rest/JobEtlXml.java delete mode 100644 src/de/superx/sxrest/JobEtlXml.java delete mode 100644 src/de/superx/sxrest/JobExecutor.java delete mode 100644 src/de/superx/sxrest/LaunchUpgrade.java delete mode 100644 src/de/superx/sxrest/MaskXml.java create mode 100644 superx/WEB-INF/lib/spring-context-indexer-6.2.19.jar diff --git a/.classpath b/.classpath index fb26529..eecfe1c 100644 --- a/.classpath +++ b/.classpath @@ -1,23 +1,39 @@ - + + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build.xml b/build.xml index 39d50af..98b4145 100644 --- a/build.xml +++ b/build.xml @@ -13,6 +13,7 @@ ant -DWEBAPP=$WEBAPP distEtl ant -DWEBAPP=$WEBAPP cleanBuildPath --> + @@ -20,8 +21,10 @@ ant -DWEBAPP=$WEBAPP cleanBuildPath + + @@ -55,7 +58,12 @@ ant -DWEBAPP=$WEBAPP cleanBuildPath - + + + + + + @@ -149,7 +157,7 @@ ant -DWEBAPP=$WEBAPP cleanBuildPath - + @@ -163,26 +171,32 @@ ant -DWEBAPP=$WEBAPP cleanBuildPath - - - - - - - - + + + + + + + + + + - + listfiles="false" encoding="UTF-8" nowarn="on" debug="true" debuglevel="lines,vars,source"> + + + + diff --git a/src-modules/module/etl/conf/etl.xml b/src-modules/module/etl/conf/etl.xml index b40ecde..b78d287 100644 --- a/src-modules/module/etl/conf/etl.xml +++ b/src-modules/module/etl/conf/etl.xml @@ -10,7 +10,7 @@ rightname="CS_BIA_STANDARDREPORTS_ADMIN[ETL]" /> - + Schlüsseltabelle für Metadaten Ladejobs diff --git a/src-modules/module/etl/schluesseltabellen/etl_step_type.unl b/src-modules/module/etl/schluesseltabellen/etl_step_type.unl index 38ff924..8c108c2 100644 --- a/src-modules/module/etl/schluesseltabellen/etl_step_type.unl +++ b/src-modules/module/etl/schluesseltabellen/etl_step_type.unl @@ -1,5 +1,5 @@ -1^LOAD^Tabelle hochladen^de.superx.elt.ActionHandler.EtlActionHandlerUploadRecords^ -2^DOSQL^SQL-Script ausführen^de.superx.elt.ActionHandler.EtlActionHandlerDosql^ -3^DOQUERY^SQL-Query ausführen^de.superx.elt.ActionHandler.EtlActionHandlerDoquery^ -4^UNLOAD^SQL-Ergebnis entladen^de.superx.elt.ActionHandler.EtlActionHandlerUnloadRecords^ -5^MSG^Logausgabe^de.superx.elt.ActionHandler.EtlActionHandlerMsg^ +1^LOAD^Tabelle hochladen^de.superx.etl.ActionHandler.EtlActionHandlerUploadRecords^ +2^DOSQL^SQL-Script ausführen^de.superx.etl.ActionHandler.EtlActionHandlerDosql^ +3^DOQUERY^SQL-Query ausführen^de.superx.etl.ActionHandler.EtlActionHandlerDoquery^ +4^UNLOAD^SQL-Ergebnis entladen^de.superx.etl.ActionHandler.EtlActionHandlerUnloadRecords^ +5^MSG^Logausgabe^de.superx.etl.ActionHandler.EtlActionHandlerMsg^ diff --git a/src/de/superx/elt/ActionHandler/EtlActionHandler.java b/src/de/superx/elt/ActionHandler/EtlActionHandler.java deleted file mode 100644 index 7587ebe..0000000 --- a/src/de/superx/elt/ActionHandler/EtlActionHandler.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * de.superx.etl - a package for controlling ETL routines - * Copyright (C) 2021 Daniel Quathamer - * - * This package is licensed under the CampusSource License; - * http://www.campussource.de/org/license/ - */ -package de.superx.elt.ActionHandler; - -import java.io.StringWriter; -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.Properties; -import java.util.logging.Logger; - -import de.superx.bin.SxConnection; -import de.superx.elt.EtlStep; - - - - -public class EtlActionHandler { - public Properties handlerSpecificProperties; - public Properties runTimeParams; - public Logger logger; - private String handlerType; - protected String logOutput=""; - protected long numberOfRows=0; - protected int returnCode; - protected SxConnection stepSxConnection; - protected Connection stepConnection; - public String propFile; - public StringWriter outputStringWriter; - - public EtlActionHandler(String handlerType, Properties hsp,Logger logger) { - this.handlerType=handlerType; - this.handlerSpecificProperties=hsp; - this.logger=logger; - } - public EtlActionHandler() { - //reflection API needs an empty constructor - } - - public void setReturnCode(int returnCode) { - this.returnCode=returnCode; - } - public int getReturnCode() { - - return returnCode; - } - - public void setNumberOfRows(long numberOfRows) { - this.numberOfRows=numberOfRows; - } - public long getNumberOfRows() { - - return numberOfRows; - } - - - public void setConnection(Connection con) { - // TODO Auto-generated method stub - - } - public void setLogOutput(String log) - { - logOutput=log; - } - public String getLogOutput() - { - return logOutput; - } - public String getPropFile() { - return propFile; - } - - - public void setPropFile(String propFile) { - this.propFile = propFile; - } - - - public StringWriter getOutputStringWriter() { - return outputStringWriter; - } - - - public void setOutputStringWriter(StringWriter sw) { - this.outputStringWriter = sw; - } - - - public Properties getHandlerSpecificProperties() { - return handlerSpecificProperties; - } - public void setHandlerSpecificProperties(Properties hsp) { - this.handlerSpecificProperties = hsp; - } - public Properties getRunTimeParams() { - return runTimeParams; - } - public void setRunTimeParams(Properties runTimeParams) { - this.runTimeParams = runTimeParams; - } - public Logger getLogger() { - return logger; - } - public void setLogger(Logger logger) { - this.logger = logger; - } - protected void getConnection() throws SQLException { - Statement st; - DatabaseMetaData dbmd; - stepSxConnection = new SxConnection(); - stepSxConnection.setPropfile(propFile); - logger.config("Starting Connection..."); - try { - stepConnection = stepSxConnection.getConnection(); - st = stepConnection.createStatement(); - dbmd = stepConnection.getMetaData(); - } catch (Exception e) { - e.printStackTrace(); - logger.severe("Keine DB-Verbindung: " + e.toString()); - throw new SQLException("Keine DB-Verbindung: " + e.toString()); - } - - - } -} diff --git a/src/de/superx/elt/ActionHandler/EtlActionHandlerDoquery.java b/src/de/superx/elt/ActionHandler/EtlActionHandlerDoquery.java deleted file mode 100644 index b3b71f0..0000000 --- a/src/de/superx/elt/ActionHandler/EtlActionHandlerDoquery.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * de.superx.etl - a package for controlling ETL routines - * Copyright (C) 2021 Daniel Quathamer - * - * This package is licensed under the CampusSource License; - * http://www.campussource.de/org/license/ - */ -package de.superx.elt.ActionHandler; - -import java.io.StringWriter; -import java.sql.Connection; -import java.sql.SQLException; -import java.util.Properties; -import java.util.logging.Logger; - -import de.superx.bin.SxConnection; -import de.superx.elt.QueryResultSerializer; -import de.superx.elt.SqlExecutor; - -public class EtlActionHandlerDoquery extends EtlActionHandler implements EtlActionHandlerI { - - public EtlActionHandlerDoquery() { - - } - @Override - public int execute(StringWriter sw, String mandantid, String stepUniquename,String outFormat) - throws SQLException, Exception - { - int returnCode=0; - long numberOfRows=0; - this.getConnection(); - String query=handlerSpecificProperties.getProperty("select_stmt"); - this.getConnection(); - SqlExecutor mySqlExecutor=new SqlExecutor("default", stepSxConnection,query,runTimeParams); - returnCode=mySqlExecutor.executeQueries(); - numberOfRows=mySqlExecutor.getNumberOfRows(); - super.setNumberOfRows(numberOfRows); - stepSxConnection.close(); - super.setReturnCode(returnCode); - - - //System.out.println(sw.toString()); - stepSxConnection.close(); - //super.setLogOutput(msg); - return returnCode; - } - -} diff --git a/src/de/superx/elt/ActionHandler/EtlActionHandlerDosql.java b/src/de/superx/elt/ActionHandler/EtlActionHandlerDosql.java deleted file mode 100644 index b30eb2d..0000000 --- a/src/de/superx/elt/ActionHandler/EtlActionHandlerDosql.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * de.superx.etl - a package for controlling ETL routines - * Copyright (C) 2021 Daniel Quathamer - * - * This package is licensed under the CampusSource License; - * http://www.campussource.de/org/license/ - */ -package de.superx.elt.ActionHandler; - -import java.io.File; -import java.io.StringWriter; -import java.sql.Connection; -import java.sql.SQLException; -import java.util.Properties; -import java.util.logging.Logger; - -import de.superx.bin.SxConnection; -import de.superx.elt.EtlUtils; -import de.superx.elt.QueryResultSerializer; -import de.superx.elt.SqlExecutor; - -public class EtlActionHandlerDosql extends EtlActionHandler implements EtlActionHandlerI { - - public EtlActionHandlerDosql() { - - } - @Override - public int execute(StringWriter sw, String mandantid, String stepUniquename,String outFormat) - throws SQLException, Exception - { - int returnCode=0; - String log=""; - long numberOfRows=0; - this.getConnection(); - Properties myProps=EtlUtils.replaceSUPERX_DIRandETL_PFAD(handlerSpecificProperties); - - String filename=myProps.getProperty("PATH_TO_INPUTFILE"); - File sqlScriptFile = null; - try { - sqlScriptFile = new File(filename); - } catch (Exception e1) { - returnCode=1; - log+=" beim Öffnen der Datei "+ filename+": "+e1.toString(); - super.setLogOutput(log); - } - if(returnCode==0) - { - try { - SqlExecutor mySqlExecutor = new SqlExecutor("default", stepSxConnection,sqlScriptFile,runTimeParams); - returnCode=mySqlExecutor.executeQueries(); - String output=mySqlExecutor.getOutString().toString(); - numberOfRows=mySqlExecutor.getNumberOfRows(); - } catch (Exception e) { - returnCode=1; - log+=" beim Ausführen der Datei "+ filename+": "+e.toString(); - super.setLogOutput(log); - } - super.setNumberOfRows(numberOfRows); - } - stepSxConnection.close(); - super.setReturnCode(returnCode); - stepSxConnection.close(); - - if(returnCode==1) - throw new Exception("Fehler " + log); - //System.out.println(sw.toString()); - //super.setLogOutput(msg); - return returnCode; - } - -} diff --git a/src/de/superx/elt/ActionHandler/EtlActionHandlerI.java b/src/de/superx/elt/ActionHandler/EtlActionHandlerI.java deleted file mode 100644 index bf1d674..0000000 --- a/src/de/superx/elt/ActionHandler/EtlActionHandlerI.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * de.superx.etl - a package for controlling ETL routines - * Copyright (C) 2021 Daniel Quathamer - * - * This package is licensed under the CampusSource License; - * http://www.campussource.de/org/license/ - */ -package de.superx.elt.ActionHandler; - -import java.io.StringWriter; -import java.sql.Connection; -import java.sql.SQLException; -import java.util.Properties; -import java.util.logging.Logger; - -import de.superx.bin.SxConnection; - -public interface EtlActionHandlerI { - - int getReturnCode(); - long getNumberOfRows(); - StringWriter getOutputStringWriter(); - - String getLogOutput(); - void setConnection(Connection con); - void setLogger(Logger logger); - void setHandlerSpecificProperties(Properties hsp); - void setRunTimeParams(Properties runTimeParams); - void setOutputStringWriter(StringWriter sw); - - int execute(StringWriter sw, String mandantid, String stepUniquename,String outFormat) throws SQLException,Exception; - void setPropFile(String propfile); - -} diff --git a/src/de/superx/elt/ActionHandler/EtlActionHandlerMsg.java b/src/de/superx/elt/ActionHandler/EtlActionHandlerMsg.java deleted file mode 100644 index f60dd97..0000000 --- a/src/de/superx/elt/ActionHandler/EtlActionHandlerMsg.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * de.superx.etl - a package for controlling ETL routines - * Copyright (C) 2021 Daniel Quathamer - * - * This package is licensed under the CampusSource License; - * http://www.campussource.de/org/license/ - */ -package de.superx.elt.ActionHandler; - -import java.io.StringWriter; -import java.sql.Connection; -import java.sql.SQLException; -import java.util.Properties; -import java.util.logging.Logger; - -public class EtlActionHandlerMsg extends EtlActionHandler implements EtlActionHandlerI { - - public EtlActionHandlerMsg() { - //reflection API needs an empty constructor - } - @Override - public int execute(StringWriter sw, String mandantid, String stepUniquename, String outFormat) - throws SQLException, Exception { - int ret=0; - String msg=handlerSpecificProperties.getProperty("msg"); - super.setLogOutput(stepUniquename+":"+ msg); - return ret; - } - -} diff --git a/src/de/superx/elt/ActionHandler/EtlActionHandlerUnloadRecords.java b/src/de/superx/elt/ActionHandler/EtlActionHandlerUnloadRecords.java deleted file mode 100644 index 454bbb4..0000000 --- a/src/de/superx/elt/ActionHandler/EtlActionHandlerUnloadRecords.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * de.superx.etl - a package for controlling ETL routines - * Copyright (C) 2021 Daniel Quathamer - * - * This package is licensed under the CampusSource License; - * http://www.campussource.de/org/license/ - */ -package de.superx.elt.ActionHandler; - -import java.io.StringWriter; -import java.sql.Connection; -import java.sql.SQLException; -import java.util.Properties; -import java.util.logging.Logger; - -import de.superx.bin.SxConnection; -import de.superx.elt.QueryResultSerializer; - -public class EtlActionHandlerUnloadRecords extends EtlActionHandler implements EtlActionHandlerI { - - public EtlActionHandlerUnloadRecords() { - - } - @Override - public int execute(StringWriter sw, String mandantid, String stepUniquename,String outFormat) - throws SQLException, Exception - { - int returnCode=0; - this.getConnection(); - String query=handlerSpecificProperties.getProperty("select_stmt"); - QueryResultSerializer myQueryResultSerializer=new QueryResultSerializer("default", stepSxConnection,query,sw); - myQueryResultSerializer.setLogger(logger); - super.setNumberOfRows(myQueryResultSerializer.unloadQueryResults(stepUniquename,outFormat,"",true)); - super.setReturnCode(myQueryResultSerializer.getReturnCode()); - super.setOutputStringWriter(myQueryResultSerializer.getOutputString()); - - //System.out.println(sw.toString()); - stepSxConnection.close(); - //super.setLogOutput(msg); - return returnCode; - } - -} diff --git a/src/de/superx/elt/ActionHandler/EtlActionHandlerUploadRecords.java b/src/de/superx/elt/ActionHandler/EtlActionHandlerUploadRecords.java deleted file mode 100644 index 3e679e0..0000000 --- a/src/de/superx/elt/ActionHandler/EtlActionHandlerUploadRecords.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * de.superx.etl - a package for controlling ETL routines - * Copyright (C) 2021 Daniel Quathamer - * - * This package is licensed under the CampusSource License; - * http://www.campussource.de/org/license/ - */ -package de.superx.elt.ActionHandler; - -import java.io.StringWriter; -import java.sql.Connection; -import java.sql.SQLException; -import java.util.Properties; -import java.util.logging.Logger; - -import de.superx.bin.SxConnection; -import de.superx.elt.QueryResultSerializer; -import de.superx.elt.TableUploader; - -public class EtlActionHandlerUploadRecords extends EtlActionHandler implements EtlActionHandlerI { - - public EtlActionHandlerUploadRecords() { - - } - @Override - public int execute(StringWriter sw, String mandantid, String stepUniquename,String outFormat) - throws SQLException, Exception - { - int returnCode=0; - this.getConnection(); - String target_table=handlerSpecificProperties.getProperty("target_table"); - String inputfile=handlerSpecificProperties.getProperty("path_to_inputfile"); - String xml_search_path=handlerSpecificProperties.getProperty("search_path"); - String format=handlerSpecificProperties.getProperty("format"); - String truncateTargetTable=handlerSpecificProperties.getProperty("truncateTargetTable"); - - long numberOfRows=0; - //getConnection(logger, this.getPropfile()); - TableUploader myUploader=new TableUploader(); - //myUploader.setDbpropfile(this.getPropfile()); - myUploader.setInFormat(format); - myUploader.setTargetTable(target_table); - myUploader.setSrcFile(inputfile); - myUploader.setXml_search_path(xml_search_path); - myUploader.getConnection(stepSxConnection.getConnection(),null); - myUploader.setUploadConnection(stepSxConnection.getConnection()); - myUploader.setTruncateTargetTable(truncateTargetTable); - numberOfRows=myUploader.uploadFile(); - super.setLogOutput("Number of rows loaded: "+numberOfRows); - - - //System.out.println(sw.toString()); - stepSxConnection.close(); - //super.setLogOutput(msg); - return returnCode; - } - -} diff --git a/src/de/superx/elt/EtlAction.java b/src/de/superx/elt/EtlAction.java deleted file mode 100644 index 804357e..0000000 --- a/src/de/superx/elt/EtlAction.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * de.superx.etl - a package for controlling ETL routines - * Copyright (C) 2021 Daniel Quathamer - * - * This package is licensed under the CampusSource License; - * http://www.campussource.de/org/license/ - */ -package de.superx.elt; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.PrintStream; -import java.io.StringWriter; -import java.io.UnsupportedEncodingException; -import java.sql.Connection; -import java.sql.SQLException; -import java.util.Properties; -import de.memtext.util.PropUtils; - -import javax.sql.DataSource; - -import de.superx.bin.SxConnection; -import de.superx.common.Sichten; -import de.superx.etl.EtlUtils; - -public class EtlAction { - protected Properties params; - private boolean contOnError; - private String targetTable; - private String logoutput; - protected StringWriter actionOutput=new StringWriter(); - protected StringWriter actionLog=new StringWriter(); - - private String loglevel="INFO"; - private long starttime = new java.util.Date().getTime() ; - protected long endtime ; - private int returnCode; - private Connection dbconnection; - private Properties env; - private String uniquename; - protected String logfile; - protected String propfile; - private String encoding="UTF-8"; - protected DataSource dataSource; - - - public EtlAction(String uniquename, String logfile, String propfile) { - this.uniquename = uniquename; - this.logfile = logfile; - this.propfile=propfile; - this.addActionLog("Action initialized"+EtlUtils.NEWLINE); - - } - public EtlAction(String uniquename) { - this.uniquename = uniquename; - this.addActionLog("Action initialized"+EtlUtils.NEWLINE); - - } - public DataSource getDataSource() { - return dataSource; - } - public void setDataSource(DataSource dataSource) { - this.dataSource = dataSource; - } - public Connection getDbconnection() { - return dbconnection; - } - public void setDbconnection(Connection dbconnection) { - this.dbconnection = dbconnection; - } - - public String getUniquename() { - return uniquename; - } - public void setUniquename(String uniquename) { - this.uniquename = uniquename; - } - public String getLogfile() { - return logfile; - } - public void setLogfile(String logfile) { - this.logfile = logfile; - } - public Properties getEnv() { - return env; - } - public void setEnv(Properties env) { - this.env = env; - } - public Properties getParams() { - return params; - } - public void setParams(Properties params) { - this.params = params; - } - - public boolean isContOnError() { - return contOnError; - } - public void setContOnError(boolean contOnError) { - this.contOnError = contOnError; - } - public String getTargetTable() { - return targetTable; - } - public void setTargetTable(String targetTable) { - this.targetTable = targetTable; - } - public String getLogoutput() { - return logoutput; - } - protected void setLogoutput(String log) { - this.logoutput = log; - } - protected void appendLog(String log) { - this.logoutput+= log; - } - public String getLoglevel() { - return loglevel; - } - public void setLoglevel(String loglevel) { - this.loglevel = loglevel; - } - public long getStarttime() { - return starttime; - } - public void setStarttime(long starttime) { - this.starttime = starttime; - } - public long getEndtime() { - return endtime; - } - public void setEndtime(long endtime) { - this.endtime = endtime; - } - public long getDuration() { - return (this.endtime - this.starttime)/1000; - } - - - public String getPropfile() { - return propfile; - } - - public void setPropfile(String propfile) { - this.propfile = propfile; - } - - public int getReturnCode() { - return returnCode; - } - public StringWriter getActionOutput() { - return actionOutput; - } - public void setActionOutput(StringWriter actionOutput) { - this.actionOutput = actionOutput; - } - public StringWriter getActionLog() { - return actionLog; - } - - public void setActionLog(StringWriter actionLog) { - this.actionLog = actionLog; - } - public void addActionLog(String actionLog) { - - String log=de.memtext.util.DateUtils.getTodayString()+ " " + de.memtext.util.DateUtils.getNowString(); - this.actionLog.append(log+"- "+ actionLog+EtlUtils.NEWLINE); - } - protected void setReturnCode(int returnCode) { - this.returnCode = returnCode; - } - public int execute() throws SQLException, Exception - { - int returncode=0; - endtime=new java.util.Date().getTime() ; - return returncode; - } - - public Connection getConnection(Connection myConnection) throws Exception { - String myDefaultPropFile=de.superx.elt.EtlUtils.WEBINFDIR+de.superx.elt.EtlUtils.PATHSEP+"db.properties"; - if(myConnection==null) - { - if(propfile==null) - propfile=myDefaultPropFile; - SxConnection mySxConnection = null; - mySxConnection = new SxConnection(); - mySxConnection.setPropfile(propfile); - - myConnection = mySxConnection.getConnection(); - - - } - return myConnection; - } -} diff --git a/src/de/superx/elt/EtlActionJob.java b/src/de/superx/elt/EtlActionJob.java deleted file mode 100644 index f19ecda..0000000 --- a/src/de/superx/elt/EtlActionJob.java +++ /dev/null @@ -1,243 +0,0 @@ -/* - * de.superx.etl - a package for controlling ETL routines - * Copyright (C) 2021 Daniel Quathamer - * - * This package is licensed under the CampusSource License; - * http://www.campussource.de/org/license/ - */ -package de.superx.elt; - -import java.io.IOException; -import java.io.PrintStream; -import java.io.StringWriter; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.Iterator; -import java.util.Properties; - -import javax.sql.DataSource; - -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.RowCallbackHandler; -import org.springframework.jdbc.datasource.DriverManagerDataSource; - -import de.memtext.rights.RightsKeyEntry; -import de.superx.common.SuperX_el; -import de.superx.common.SxResultRow; -import de.superx.common.SxResultSet; -import de.superx.common.SxSqlHelper; -import de.superx.etl.EtlUtils; -import de.superx.servlet.SxPools; -import de.superx.util.SqlStringUtils; -import freemarker.template.TemplateBooleanModel; - -public class EtlActionJob extends EtlAction { - private String mandantenID; - private String jobTid; - private String jobUniquename; - private String jobLogfile; - private String jobCaption; - private Properties runTimeParams; - - private StringWriter sw; - public EtlActionJob(String uniquename, String logfile, String propfile) { - super(uniquename, logfile, propfile); - sw=new StringWriter(); - } - public EtlActionJob(String uniquename) { - super(uniquename); - sw=new StringWriter(); - } - - public StringWriter getSw() { - return sw; - } - public void setSw(StringWriter sw) { - this.sw = sw; - } - public void setRunTimeParams(String runTimeParamsArg) throws IOException { - if(runTimeParamsArg!=null) - this.runTimeParams = EtlUtils.convertStringToProperty(runTimeParamsArg); - } - - - public void initJob(String job,String runtimeParamsArg) throws Exception - { - long jetzt = new java.util.Date().getTime() ; - EtlUtils.initJobEnvironment(); - String paramName=null; - String paramCaption; - String paramDefault=""; - String paramProperties=""; - if(runtimeParamsArg==null) - runtimeParamsArg=""; - runtimeParamsArg="SUPERX_DIR="+EtlUtils.SUPERX_DIR+EtlUtils.NEWLINE+runtimeParamsArg; - //super.addActionLog("runtimeParamsArg:"+runtimeParamsArg); - this.setStarttime(jetzt); - Connection myConnection=this.getDbconnection(); - if(myConnection==null) - myConnection=this.getConnection(myConnection); - this.setDbconnection(myConnection); - if(!SqlStringUtils.checkValidKeyEntry(job)) - throw new SQLException("Invalid job "+job); - String sql = "select J.tid,J.uniquename,J.caption,J.logfile, P.uniquename as param_name,P.name as param_caption, P.param_default from etl_job J left outer join etl_job_param P on (J.tid=P.etl_job_id) where J.uniquename='"+job+"';"; - - SuperX_el el = new SuperX_el(); - SxSqlHelper sh=new SxSqlHelper(); - - sh.execute(sql, myConnection, el); - if (el.getError_String() != null - && !el.getError_String().trim().equals("")) - throw new SQLException("\nProblem bei Job DETAILS:" + "\n\n Meldung:" - + el.getError_String() + "\n sql:" + sql); - SxResultSet result= el.getResultSet(); - int rownr=0; - for (Iterator it = result.iterator(); it.hasNext();) { - rownr++; - SxResultRow row = (SxResultRow) it.next(); - jobTid=row.get(0).toString().trim(); - jobUniquename=row.get(1).toString().trim(); - jobCaption=row.get(2).toString().trim(); - jobLogfile=row.get(3).toString().trim(); - if(row.get(4)!=null) - paramName=row.get(4).toString().trim(); - if(row.get(5)!=null) - paramCaption=row.get(5).toString().trim(); - if(row.get(4)!=null) - paramDefault=row.get(6).toString().trim(); - if(paramName!=null) - paramProperties+=(paramName+"="+paramDefault+EtlUtils.NEWLINE); - - } - if(rownr==0) - throw new Exception("Job "+job+" unbekannt"); - //this.setLogfile(jobLogfile); - //this.appendLog("Job gefunden: "+jobCaption+EtlUtils.NEWLINE); - super.addActionLog("Job gefunden: "+jobCaption+EtlUtils.NEWLINE); - if(!paramProperties.equals("")) - this.setParams(EtlUtils.convertStringToProperty(paramProperties)); - if(runtimeParamsArg!=null) - { - this.setRunTimeParams(runtimeParamsArg); - super.addActionLog("Runtime Params: "+runtimeParamsArg); - } - if(runTimeParams!=null) - this.setParams(de.superx.elt.EtlUtils.mergeParamProperties(this.getParams(), runTimeParams)); - super.addActionLog("Job "+jobCaption+ " initialized"); - } - public int execute(String outfile) throws SQLException, Exception - { - Integer stepTid; - String stepUniquename; - String stepCaption; - String stepLogfile; - Integer stepSortnr; - Integer stepForceContinue; - Integer stepParentStepId; - String stepTypeUniquename; - String stepTypeCaption; - String stepTypeHandler; - - - int jobReturnCode=0; - String sql = "select S.tid,"+ - "S.uniquename,"+ - "S.caption,"+ - "S.systeminfo_id,"+ - "R.sortnr,"+ - "R.force_continue::integer as force_continue,"+ - "R.parent_step_id,"+ - "S.logfile,"+ - "T.uniquename,"+ - "T.caption,"+ - "T.handler"; - sql +=" FROM etl_step S, etl_step_type T, etl_step_relation R where T.tid=S.step_type_id and R.step_id=S.tid and R.job_id="+jobTid+" order by R.sortnr,R.tid;"; - - SuperX_el el = new SuperX_el(); - SxSqlHelper sh=new SxSqlHelper(); - - try { - sh.execute(sql, this.getConnection(null), el); - } catch (Exception e1) { - - super.addActionLog("Fehler beim SQL: "+sql+EtlUtils.NEWLINE+el.getError_String().trim()); - return 1; - } - if (el.getError_String() != null - && !el.getError_String().trim().equals("")) - throw new SQLException("\nProblem bei Steps DETAILS:" + "\n\n Meldung:" - + el.getError_String() + "\n sql:" + sql); - SxResultSet result= el.getResultSet(); - int rownr=0; - super.addActionLog("Steps found: "+ result.size()); - //erstmal nicht mit Zeit: executionTime=\""+de.memtext.util.DateUtils.getTodayString()+" " + de.memtext.util.DateUtils.getNowString()+"\" - sw.write("\n"); - for (Iterator it = result.iterator(); it.hasNext();) { - int stepReturnCode=0; - rownr++; - SxResultRow row = (SxResultRow) it.next(); - stepTid=(Integer) row.get(0); - stepUniquename=row.get(1).toString().trim(); - stepCaption=row.get(2).toString().trim(); - stepSortnr=(Integer) row.get(4); - stepForceContinue=(Integer) row.get(5); - stepParentStepId=(Integer) row.get(6); - stepLogfile=row.get(7).toString().trim(); - stepTypeUniquename=row.get(8).toString().trim();; - stepTypeCaption=row.get(9).toString().trim();; - stepTypeHandler=row.get(10).toString().trim();; - EtlStep myStep=new EtlStep(stepUniquename,jobLogfile,propfile); - myStep.setOutputStringWriter(sw); - myStep.initStep(jobUniquename, this.getParams(), stepTid, - stepUniquename, - stepLogfile, - stepCaption, - stepSortnr, - stepForceContinue, - stepParentStepId, - stepTypeUniquename, - stepTypeCaption, - stepTypeHandler); - stepReturnCode=myStep.execute(); - super.addActionLog(myStep.getActionLog().toString()); - sw=myStep.getOutputStringWriter(); - if(stepReturnCode!=0) - { - if(stepForceContinue.intValue()==0) - jobReturnCode=1; - break; - } - } - if(rownr==0) - throw new Exception("Steps unbekannt"); - sw.write("\n\n"); - if(outfile==null || outfile.equals("")) - { - System.out.println(sw.toString()); - System.out.println(super.getActionLog()); - } - else - { - if(jobReturnCode==1) - { - System.err.println(super.getActionLog()); - throw new Exception("Fehler bei Jobausführung"); - } - else - System.out.println("Jobausführung Erfolg"); - try { - de.superx.elt.EtlUtils.saveFileContentsWithEncoding(outfile, sw.toString(), null); - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - jobReturnCode=1; - } - } - long jetzt = new java.util.Date().getTime() ; - this.setEndtime(jetzt); - - - return jobReturnCode; - } -} diff --git a/src/de/superx/elt/EtlFmParser.java b/src/de/superx/elt/EtlFmParser.java deleted file mode 100644 index 50a1177..0000000 --- a/src/de/superx/elt/EtlFmParser.java +++ /dev/null @@ -1,137 +0,0 @@ -package de.superx.elt; -import static de.superx.servlet.SxSQL_Server.DEFAULT_MANDANTEN_ID; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.sql.DatabaseMetaData; -import java.util.HashMap; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.Properties; -import java.util.StringTokenizer; -import java.util.logging.Level; -import java.util.logging.Logger; - -import de.memtext.db.ConnectionCreator; -import de.memtext.util.DateUtils; -import de.memtext.util.GetOpts; -import de.memtext.util.StringUtils; -import de.superx.common.DBServletException; -import de.superx.common.FieldContainer; -import de.superx.common.Sichten; -import de.superx.common.StandaloneSicht; -import de.superx.common.SuperX_el; -import de.superx.common.SxResultRow; -import de.superx.common.SxResultSet; -import de.superx.common.SxSqlHelper; -import de.superx.common.SxUser; -import de.superx.common.TableFieldExists; -import de.superx.common.TemplateProcessor; -import de.superx.servlet.SuperXManager; -import de.superx.servlet.SxPools; -import de.superx.servlet.SxSQL_Server; -import de.superx.util.PropsReader; -import de.superx.util.SqlStringUtils; - -public class EtlFmParser extends TemplateProcessor { - private String dbprop, infile, outfile; - private Properties props; - - private Statement stm; - private String isSimpleParser; - private static String sqlDialect; - - EtlFmParser(String mandantenID, Connection con) { - super(mandantenID,con); - - } - - - - private void initConAndParser() throws IOException, SQLException, - ClassNotFoundException { - - stm = con.createStatement(); - if(SqlStringUtils.tableExists(con,"fm_templates",DEFAULT_MANDANTEN_ID)) - { - setTemplates(readFromDb("select trim(both from id),content from fm_templates")); - repositoryToMap(readFromDb(REPOSITORY_SELECT), repositoryMap); - } - if(SqlStringUtils.tableExists(con,"konstanten",DEFAULT_MANDANTEN_ID)) - { - SxResultSet rs = readFromDb("select trim(both from beschreibung),apnr from konstanten"); - for (Iterator it = rs.iterator(); it.hasNext();) { - SxResultRow row = (SxResultRow) it.next(); - String beschreibung = (String) row.get(0); - - repositoryMap.put("K_" + beschreibung.trim(), row.get(1)); - } - } - } - - - - protected SxResultSet readFromDb(String sql) throws SQLException { - SuperX_el el = new SuperX_el(); - - SxSqlHelper sh=new SxSqlHelper(); - sh.execute(sql, this.con, el); - - - if (el.getError_String() != null - && !el.getError_String().trim().equals("")) - throw new SQLException("\nProblem bei:" + "\n\n Meldung:" - + el.getError_String() + "\n sql:" + sql); - - return el.getResultSet(); - - - } - - - - - - - - - /* - * Einfacher Parser für Fremddatenbanken, nur sqlDialect wird übergeben wird - * von DOSQL direkt aufgerufen - */ - public String simpleParser( String input) - throws FileNotFoundException, IOException, Exception { - String output = ""; - sqlDialect = "Postgres";// de.superx.util.SqlStringUtils.getSqlDialect(props .getProperty("driverName")); - initConAndParser(); - HashMap map = new HashMap(); - try { - output = "--automatically created by SuperX/Freemarker for " - + sqlDialect - + " (" - + DateUtils.getTodayString() - + " " - + DateUtils.getNowString() - + ")\n" - + process("FM-Parsing ", input, map, - sqlDialect); - - } catch (Exception e) { - System.err.println("Fehler beim FM-Parsen "); - e.printStackTrace(); - System.exit(1); - } - return output; - - } - - } - - // Created on 08.12.2006 at 18:03:46 - - - diff --git a/src/de/superx/elt/EtlStep.java b/src/de/superx/elt/EtlStep.java deleted file mode 100644 index 0b4bb5e..0000000 --- a/src/de/superx/elt/EtlStep.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * de.superx.etl - a package for controlling ETL routines - * Copyright (C) 2021 Daniel Quathamer - * - * This package is licensed under the CampusSource License; - * http://www.campussource.de/org/license/ - */ -package de.superx.elt; - - -import java.io.InputStream; -import java.io.PrintStream; -import java.io.StringWriter; -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.Properties; -import java.util.logging.Logger; - -import javax.sql.DataSource; - -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.RowCallbackHandler; -import org.springframework.jdbc.datasource.DriverManagerDataSource; - -import de.memtext.rights.RightsKeyEntry; -import de.memtext.util.GetOpts; -import de.superx.bin.Doquery; -import de.superx.bin.SxConnection; -import de.superx.common.SuperX_el; -import de.superx.common.SxResultRow; -import de.superx.common.SxResultSet; -import de.superx.common.SxSqlHelper; -import de.superx.elt.ActionHandler.*; -import de.superx.servlet.SxPools; -import de.superx.util.SqlStringUtils; -import freemarker.template.TemplateBooleanModel; - -public class EtlStep extends EtlAction { - private String mandantenID; - private Integer stepTid; - private String stepUniquename; - private String stepLogfile; - private String stepCaption; - private Integer stepSortnr; - private Integer stepForceContinue; - private Integer stepParentStepId; - private String stepTypeUniquename; - private String stepTypeCaption; - private String stepTypeHandler; - private Properties jobRunTimeParams; - private Properties stepProperties; - private SxConnection stepSxConnection; - private Connection stepConnection; - public EtlStep(String uniquename, String logfile, String propfile) { - super(uniquename, logfile, propfile); - //this.setLogoutput("Step "+uniquename); - super.addActionLog("Step "+uniquename +" loaded"); - - } - public StringWriter getOutputStringWriter() { - return sw; - } - - - public void setOutputStringWriter(StringWriter sw) { - this.sw = sw; - } - private StringWriter sw; - - - - public void initStep(String job,Properties runTimeParams, Integer tid, - String uniquename, - String logfile, - String caption, - Integer sortnr, - Integer forceContinue, - Integer parentStepId, - String typeUniquename, - String typeCaption, - String typeHandler - ) throws Exception - { - jobRunTimeParams=runTimeParams; - stepTypeHandler=typeHandler; - stepTid=tid; - stepUniquename=uniquename; - stepLogfile=logfile; - stepCaption=caption; - stepSortnr=sortnr; - stepForceContinue=forceContinue; - stepParentStepId=parentStepId; - stepTypeUniquename=typeUniquename; - stepTypeCaption=typeCaption; - this.setLogfile(logfile); - super.addActionLog("Initializing Step: "+caption); - super.addActionLog("Handler: "+typeHandler); - //this.appendLog("Params: "+runTimeParams.toString()); - //get Params: - Connection myConnection=this.getDbconnection(); - if(myConnection==null) - myConnection=this.getConnection(myConnection); - this.setDbconnection(myConnection); - if(!SqlStringUtils.checkValidKeyEntry(job)) - throw new SQLException("Invalid job"); - String sql = "select tid,prop_name,prop_value from etl_step_property where etl_step_id="+tid.toString()+";"; - - SuperX_el el = new SuperX_el(); - SxSqlHelper sh=new SxSqlHelper(); - sh.execute(sql, myConnection, el); - if (el.getError_String() != null - && !el.getError_String().trim().equals("")) - throw new SQLException("\nProblem bei Step DETAILS:" + "\n\n Meldung:" - + el.getError_String() + "\n sql:" + sql); - SxResultSet result= el.getResultSet(); - stepProperties=null; - stepProperties=new Properties(); - int rownr=0; - for (Iterator it = result.iterator(); it.hasNext();) { - rownr++; - SxResultRow row = (SxResultRow) it.next(); - String paramName=row.get(1).toString().trim(); - String paramValue=row.get(2).toString().trim(); - String paramValueParsed=parseParams(paramValue); - stepProperties.setProperty(paramName, paramValueParsed); - super.addActionLog("Parameter "+paramName+":"+paramValueParsed); - - } - - } - private String parseParams(String paramValue) - { - String parsedParam=paramValue; - Enumeration runTimeParamNames = jobRunTimeParams.propertyNames(); - while (runTimeParamNames.hasMoreElements()) { - String runTimeParamName = (String)runTimeParamNames.nextElement(); - String runTimeParamValue = jobRunTimeParams.getProperty(runTimeParamName); - parsedParam=de.memtext.util.StringUtils.replace(parsedParam,"$"+runTimeParamName, runTimeParamValue); - - } - return parsedParam; - - } - - public int execute() - throws Exception - { - int returnCode=0; - long numberOfRows=0; - Logger logger =(Logger) Logger.getLogger(EtlStep.class.toString()); - - super.addActionLog("Executing Step "+this.stepUniquename); - Class handlerClass = Class.forName(stepTypeHandler); - Object handlerObject = handlerClass.newInstance(); - ((EtlActionHandlerI) handlerObject).setLogger(logger); - ((EtlActionHandlerI) handlerObject).setHandlerSpecificProperties(stepProperties); - ((EtlActionHandlerI) handlerObject).setRunTimeParams(jobRunTimeParams); - ((EtlActionHandlerI) handlerObject).setOutputStringWriter(this.getOutputStringWriter()); - ((EtlActionHandlerI) handlerObject).setPropFile(this.getPropfile()); - - try { - returnCode=((EtlActionHandlerI) handlerObject).execute(this.getOutputStringWriter(),"default",this.stepUniquename,"xml"); - } catch (Exception e) { - returnCode=1; - super.addActionLog("Fehler beim Step "+ this.stepUniquename+ ": "+e.toString()); - //TODO forceContinue auswerten - } - this.setOutputStringWriter(((EtlActionHandlerI) handlerObject).getOutputStringWriter()); - - super.addActionLog(((EtlActionHandlerI) handlerObject).getLogOutput()); - - - /* - if(stepTypeHandler.equals("de.superx.bin.UnloadRecords")) - { - getConnection(logger, this.getPropfile()); - String query=stepParams.getProperty("select_stmt"); - - sw=this.getSw(); - QueryResultSerializer myQueryResultSerializer=new QueryResultSerializer("default", stepSxConnection,query,sw); - myQueryResultSerializer.setLogger(logger); - NumberOfRows=myQueryResultSerializer.unloadQueryResults(this.stepUniquename,"xml","",true); - this.setReturnCode(myQueryResultSerializer.getReturnCode()); - - sw=myQueryResultSerializer.getOutputString(); - this.setSw(sw); - //System.out.println(sw.toString()); - stepSxConnection.close(); - } - if(stepTypeHandler.equals("de.superx.bin.Doquery")) - - { - String query=stepParams.getProperty("select_stmt"); - getConnection(logger, this.getPropfile()); - SqlExecutor mySqlExecutor=new SqlExecutor("default", stepSxConnection,query,jobRunTimeParams); - returnCode=mySqlExecutor.executeQueries(); - - stepSxConnection.close(); - } - - if(stepTypeHandler.equals("de.superx.bin.UploadRecords")) - - { - String target_table=stepParams.getProperty("target_table"); - String inputfile=stepParams.getProperty("path_to_inputfile"); - String xml_search_path=stepParams.getProperty("search_path"); - long numberOfRows=0; - //getConnection(logger, this.getPropfile()); - TableUploader myUploader=new TableUploader(); - myUploader.setDbpropfile(this.getPropfile()); - myUploader.setInFormat("xml"); - myUploader.setTargetTable(target_table); - myUploader.setSrcFile(inputfile); - myUploader.setXml_search_path(xml_search_path); - //myUploader.setUploadConnection(stepSxConnection.getConnection()); - myUploader.setUploadConnection(myUploader.getConnection(null,this.getPropfile())); - //SqlExecutor mySqlExecutor=new SqlExecutor("default", stepSxConnection,query); - numberOfRows=myUploader.uploadFile(); - this.appendLog("Number of rows loaded: "+numberOfRows); - - - } - if(stepTypeHandler.trim().equals("msg")) - - { - String msg=stepParams.getProperty("msg"); - - this.appendLog(msg); - }*/ - //logger.info(this.getLogoutput()); - return returnCode; - } - -} diff --git a/src/de/superx/elt/EtlUtils.java b/src/de/superx/elt/EtlUtils.java deleted file mode 100644 index d6853ea..0000000 --- a/src/de/superx/elt/EtlUtils.java +++ /dev/null @@ -1,353 +0,0 @@ -/* - * de.superx.etl - a package for controlling ETL routines - * Copyright (C) 2021 Daniel Quathamer - * - * This package is licensed under the CampusSource License; - * http://www.campussource.de/org/license/ - */ -package de.superx.elt; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.StringReader; -import java.io.StringWriter; -import java.io.UnsupportedEncodingException; -import java.net.URISyntaxException; -import java.util.Enumeration; -import java.util.NoSuchElementException; -import java.util.Properties; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; - -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - -import de.superx.servlet.SuperXManager; - -/** - - */ -public class EtlUtils { -public static final String NEWLINE=System.getProperty("line.separator"); -public static final String PATHSEP=File.separator; -public static String WEBINFDIR=SuperXManager.getWEB_INFPfad(); -public static String SUPERX_DIR=(System.getProperties().containsKey("SUPERX_DIR")? System.getProperty("SUPERX_DIR"):""); - -public static void main(String args[]) { - - try { - String tidInXmlFile=""; - Document mydomres =de.superx.elt.EtlUtils.buildDocumentFromXmlFile("/home/superx/devel_module/community/tomcat/temp/myTempFile6460222908896375059.xml"); - XPathFactory factory = new net.sf.saxon.xpath.XPathFactoryImpl(); - - XPath xPath = factory.newXPath(); - //String searchPath="/etlAction[@name=\"sx_select_mask\"]/unload/row/fld[@name=\"tid\"]"; - String searchPath="/etlAction[@name=\"sx_select_mask\"]/unload[@name=\"unload_maskeninfo\"]/rs/row/fld[@name=\"tid\"]"; - - Node tidNode=(Node) xPath.compile(searchPath).evaluate( - mydomres, XPathConstants.NODE); - if(tidNode!=null) - tidInXmlFile=de.memtext.util.XMLUtils.getTheValue(tidNode); - else - System.out.println("node not found"); - System.out.println(tidInXmlFile); - } catch (FileNotFoundException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (XPathExpressionException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (ParserConfigurationException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (SAXException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } -} - -public static Properties convertStringToProperty(String inp) throws IOException -{ - Properties myProps = new Properties(); - myProps.load(new StringReader(inp)); - return myProps; -} -public static Properties replaceSUPERX_DIRandETL_PFAD(Properties params) throws IOException -{ - Properties returnProperties=new Properties(); - Properties pathParams =convertStringToProperty("SUPERX_DIR="+SUPERX_DIR); - returnProperties=mergeParamProperties(params,pathParams); - return returnProperties; -} - -public static Properties mergeParamProperties(Properties params, Properties runTimeParams) - -{ - String parsedParam; - Enumeration runTimeParamNames = runTimeParams.propertyNames(); - while (runTimeParamNames.hasMoreElements()) { - String runTimeParamName = (String)runTimeParamNames.nextElement(); - String runTimeParamValue = runTimeParams.getProperty(runTimeParamName); - Enumeration paramNames = params.propertyNames(); - while (paramNames.hasMoreElements()) { - String paramName=(String)paramNames.nextElement(); - String paramValue=params.getProperty(paramName); - if(paramName.equals(runTimeParamName) ) - { - paramValue=runTimeParamValue; - params.setProperty(paramName, paramValue); - } - if(paramValue.indexOf("$"+runTimeParamName)>-1) - { - paramValue=de.memtext.util.StringUtils.replace(paramValue,"$"+runTimeParamName, runTimeParamValue); - params.setProperty(paramName, paramValue); - } - - } - } - return params; - -} -public static void initJobEnvironment() -{ - String initVar=""; - if(System.getProperty("WEBINFDIR") ==null) - { - - try { - initVar=de.superx.servlet.SuperXManager.getWEB_INFPfad(); - if(initVar==null || initVar.equals(".")) - { - //ermittle webinfdir - initVar=getWebinfDirectory(); - - } - } catch (Exception e) { - // do nothing, try another - } - - WEBINFDIR=initVar; - - } - - if(System.getProperty("SUPERX_DIR") ==null) - { - SUPERX_DIR=WEBINFDIR+PATHSEP+"conf"+PATHSEP+"edustore"; - - } - -} -private static String getJarName() -{ - return new File(EtlUtils.class.getProtectionDomain() - .getCodeSource() - .getLocation() - .getPath()) - .getName(); -} - -private static boolean runningFromJar() -{ - String jarName = getJarName(); - return jarName.contains(".jar"); -} - -public static String getWebinfDirectory() throws URISyntaxException -{ - if (runningFromJar()) - { - return getWebinfDirectoryFromJar(); - } else - { - return getWebinfDirectoryFromClass(); - } -} - -private static String getWebinfDirectoryFromClass() -{ - File f= new File(EtlUtils.class.getProtectionDomain() - .getCodeSource() - .getLocation() - .getPath()+PATHSEP+".."); - String class_path=f.getAbsolutePath(); - return class_path; - -} - -private static String getWebinfDirectoryFromJar() throws URISyntaxException -{ - String pathOfJarFile=new File(EtlUtils.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParent(); - String webinfDir=new File(pathOfJarFile+PATHSEP+"..").getAbsolutePath(); - return webinfDir; - -} -/* die folgenden 2 Methoden - * getFileContentsWithEncoding - * saveFileContentsWithEncoding - * sind in kern5.0 in de.superx.util.FileUtils - * wg. abwärtskompatiblität hierhin kopiert, sollten langfristig wieder weg - */ -public static String getFileContentsWithEncoding(String filePath, String encoding) { - File f = new File(filePath); - if (!f.exists()) { - System.out.println("Fehler: Datei " + filePath + " existiert nicht."); - return null; - } - String fileContents = ""; - if (encoding == null || encoding.trim().equals("")) { - encoding = System.getProperty("file.encoding"); - } - try { - // --- IputStream und OutputStream generieren ---// - FileInputStream fis = new FileInputStream(f); - // Wenn Quelldatei Unicode, dann speziellen Reader nutzen - BufferedReader in; - //BufferedReader ist schneller bei großen Dateien - in = new BufferedReader(new InputStreamReader(fis, encoding)); - // --- Output-Stream der temporären Datei erzeugen ---// - StringWriter out = new StringWriter(); - // --- Verarbeiten der Datei ---// - String text; - text = in.readLine(); - while (text != null) { // Datei nicht leer - out.write(text); - out.write(System.getProperty("line.separator")); - text = in.readLine(); - } - if (!(out == null)) { - fileContents = out.toString(); - } - } catch (FileNotFoundException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (UnsupportedEncodingException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return fileContents; - } - - public static void saveFileContentsWithEncoding(String filename, String contents, String encoding) throws - - FileNotFoundException, - IOException - { - - - File f = new File(filename); - BufferedReader in; - BufferedWriter out; - - //Default encoding ist utf-8 - if (encoding == null) encoding = System.getProperty("file.encoding"); - // --- Output-Stream der temporären Datei erzeugen ---// - out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f), encoding)); - - out.write(contents); - - out.close(); - - - }//Ende der Methode - - -/*SAX Document aus XML-Datei erzeugen */ - public static Document buildDocumentFromXmlFile(String srcFile) - throws ParserConfigurationException, FileNotFoundException, SAXException, IOException { - Document mydomres; - org.xml.sax.InputSource is; - DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = dfactory.newDocumentBuilder(); - FileInputStream in = new FileInputStream(srcFile); - - is=new org.xml.sax.InputSource(in); - mydomres = builder.newDocument(); - mydomres = builder.parse(is); - return mydomres; - } - /*** - * TODO: nach merge in master diese Methode löschen, und auf de.memtext.util.XMLUtils.parseXml(String) verweisen - * @author Witt This function parses XML-containing string into documents while - * preserving the namespaces and is primarily meant to be used withing - * (jUnit) test cases - * @param xmlString - * @return - * @throws ParserConfigurationException - * @throws SAXException - * @throws IOException - */ - public static Document parseXml(String xmlString) throws ParserConfigurationException, SAXException, IOException { - DocumentBuilderFactory myFactory = DocumentBuilderFactory.newInstance(); - myFactory.setNamespaceAware(true); - DocumentBuilder myBuilder; - myBuilder = myFactory.newDocumentBuilder(); - Document myDocument = myBuilder.parse(new InputSource(new StringReader(xmlString))); - return myDocument; - } - /** - * @param src - * @param tidInXmlFile - * @return - * @throws ParserConfigurationException - * @throws SAXException - * @throws IOException - * @throws XPathExpressionException - */ - public static boolean isNodeValueInXml(String src, String searchPath, String expectedValue,String jobuniquename) - throws ParserConfigurationException, SAXException, IOException, XPathExpressionException { - boolean b=false; - Document mydomres =de.superx.elt.EtlUtils.parseXml(src); - XPathFactory factory = new net.sf.saxon.xpath.XPathFactoryImpl(); - - XPath xPath = factory.newXPath(); - - Node myNode=(Node) xPath.compile(searchPath).evaluate( - mydomres, XPathConstants.NODE); - if(myNode!=null) - { - String foundValue=de.memtext.util.XMLUtils.getTheValue(myNode); - if(!(foundValue==null) && foundValue.trim().equals(expectedValue)) - b=true; - } - return b; - - } - public static String translateReturnCode(int returnCode) - { - String returnString="Fehlerhaft"; - if(returnCode==0) - returnString="Erfolg"; - return returnString; - } - public static String translateReturnCode2Html(int returnCode) - { - String returnString=translateReturnCode(returnCode); - if(returnCode==0) - returnString=""+returnString+""; - else - returnString=""+returnString+""; - return returnString; - } -} diff --git a/src/de/superx/elt/QueryResultSerializer.java b/src/de/superx/elt/QueryResultSerializer.java deleted file mode 100644 index d3f774e..0000000 --- a/src/de/superx/elt/QueryResultSerializer.java +++ /dev/null @@ -1,437 +0,0 @@ -/* - * de.superx.etl - a package for controlling ETL routines - * Copyright (C) 2021 Daniel Quathamer - * - * This package is licensed under the CampusSource License; - * http://www.campussource.de/org/license/ - */ -package de.superx.elt; -import java.io.BufferedOutputStream; -import java.io.FileNotFoundException; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintStream; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.JDBCType; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.sql.Statement; -import java.sql.Types; -import java.util.logging.LogManager; -import java.util.logging.Logger; -import java.util.logging.Level; - -import de.memtext.util.StringUtils; -import de.superx.bin.SxConnection; -import de.superx.bin.SxDBUtils; -import de.superx.bin.SxJdbcClient; - -import java.util.Iterator; -import java.util.StringTokenizer; - -import de.superx.common.SxResultSet; -import de.superx.elt.bin.SxTransformer; -import de.superx.servlet.ServletUtils; -import de.superx.servlet.SxSQL_Server; -import de.superx.util.SqlStringUtils; -/** - * @author Daniel Quathamer Projektgruppe SuperX - * doquery.java - * @ - * Dieses Javaprogramm führt einen SQL-Ausdruck aus und gibt das Ergebnis aus.
- * Gebrauch:
java doquery (optional) (optional) (optional) - * - - */ -/* - * SQL-Abfragen Ergebnis serialisieren nach CSV / XML - */ -public class QueryResultSerializer { - public QueryResultSerializer(String mandantenId,SxConnection mySxConnection, String query,StringWriter sw) { - super(); - this.mySxConnection = mySxConnection; - this.query = prepareQuery(query); - this.mandantenId = mandantenId; - this.logger = Logger.getLogger("superx_" + mandantenId); - this.outputString=sw; - } - public QueryResultSerializer(String mandantenId,SxConnection mySxConnection, String query,FileWriter fw) { - super(); - this.mySxConnection = mySxConnection; - this.query = prepareQuery(query); - this.mandantenId = mandantenId; - this.logger = Logger.getLogger("superx_" + mandantenId); - this.outputFile=fw; - } - public QueryResultSerializer(String mandantenId,SxConnection mySxConnection, ResultSet rs,FileWriter fw) { - super(); - this.mySxConnection = mySxConnection; - this.myrs=rs; - this.mandantenId = mandantenId; - this.logger = Logger.getLogger("superx_" + mandantenId); - this.outputFile=fw; - } - public QueryResultSerializer(String mandantenId,SxConnection mySxConnection, ResultSet rs,StringWriter sw) { - super(); - this.mySxConnection = mySxConnection; - this.myrs=rs; - this.mandantenId = mandantenId; - this.logger = Logger.getLogger("superx_" + mandantenId); - this.outputString=sw; - } - public final String NEWLINE=System.getProperty("line.separator"); - private String outfile; - private SxConnection mySxConnection; - private String query; - private String CSVdelim; - private Boolean printColNames; - private String outFormat; - private Logger logger; - private String mandantenId="default"; - private Statement st; - private Connection myConnection; - private String[] colnames; - private int[] coltypes; - private int columnCount; - private StringBuffer outString=new StringBuffer(""); - //private PrintStream stringOutWriter=new PrintStream(outString); - //private PrintWriter output=new PrintWriter(stringOutWriter); - private String outputHeader=""; - private String outputFooter=""; - private BufferedOutputStream outputStream; - public StringWriter outputString; - public FileWriter outputFile; - private int returnCode; - private ResultSet myrs; - - public String getOutfile() { - return outfile; - } - public void setOutfile(String outfile) { - this.outfile = outfile; - } - public SxConnection getMySxConnection() { - return mySxConnection; - } - public void setMyConnection(SxConnection mySxConnection) { - this.mySxConnection = mySxConnection; - } - public String getQuery() { - return query; - } - public void setQuery(String query) { - this.query = query; - - } - - public String getOutFormat() { - return outFormat; - } - public void setOutFormat(String outFormat) { - this.outFormat = outFormat; - } - public Logger getLogger() { - return logger; - } - public void setLogger(Logger logger) { - this.logger = logger; - } - public String getMandantenId() { - return mandantenId; - } - public void setMandantenId(String mandantenId) { - this.mandantenId = mandantenId; - } - public String[] getColnames() { - return colnames; - } - public void setColnames(String[] colnames) { - this.colnames = colnames; - } - public int[] getColtypes() { - return coltypes; - } - public void setColtypes(int[] coltypes) { - this.coltypes = coltypes; - } - public StringWriter getOutputString() { - return outputString; - } - public void setOutputString(StringWriter output) { - this.outputString = output; - } - public FileWriter getOutputFile() { - return outputFile; - } - public void setOutputFile(FileWriter outputFile) { - this.outputFile = outputFile; - } - public int getColumnCount() { - return columnCount; - } - public void setColumnCount(int columnCount) { - this.columnCount = columnCount; - } - - - - public int getReturnCode() { - return returnCode; - } - public void setReturnCode(int returnCode) { - this.returnCode = returnCode; - } - protected ResultSet getMyrs() { - return myrs; - } - protected void setMyrs(ResultSet myrs) { - this.myrs = myrs; - } - public long unloadQueryResults(String uniquename, String outformat,String delim,boolean printColname) throws Exception - { - returnCode=0; - long numberOfRows=0; - String zs=""; - if(myrs==null) - { - SxResultSet rs = null; - - SxJdbcClient myClient = new SxJdbcClient(logger, mySxConnection.getPropfile(), query); - - - //logger.info("Executing sql: " + query); - myClient.Rs_executeALL(); - logger.info("Getting resultset") ; - myrs = myClient.getRs(); - //logger.info("Starting output for: " + query); - } - if(myrs != null ) - { - ResultSetMetaData rsmd = myrs.getMetaData(); - setColnamesAndTypes(rsmd); - - - if(outformat.equalsIgnoreCase("xml")) - { - zs+=""; - if(printColname) - zs+=this.getColnamesXML(); - } - else - { - //CSV: - if(printColname) - zs+=this.getColnamesCSV(delim)+"\n"; - } - //this.outputStream.w - //StringWriter sw = new StringWriter(); - //sw.write(zs); - //this.setOutputString(sw); - - try { - numberOfRows=printResult(outformat,zs,myrs,delim); - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - returnCode=1; - } - } - return numberOfRows; - } - private long printResult(String outformat,String header,ResultSet outrs,String delim) throws SQLException, IOException - { - StringBuffer line = new StringBuffer(); - int types[]=this.getColtypes(); - String lbl[]=this.getColnames(); - String f_wert=null; - Object o = null; - int rowCounterBeforeFlush = 0; - long rowCounter = 0; - FileWriter fw = null; - StringWriter sw=null; - String rowDelim1=(outformat.equalsIgnoreCase("xml"))?"":""; - String rowDelim2=(outformat.equalsIgnoreCase("xml"))?""+NEWLINE:"\n"; //bei CSV ist Zeilentrenner immer \n, nicht DOS-Anpassung - String footer=(outformat.equalsIgnoreCase("xml"))?"":""; - - boolean writeFileOutput=(this.outputFile==null)?false:true; - int colNumber=this.getColumnCount(); - if(writeFileOutput) - { - fw=this.getOutputFile(); - fw.write(header); - } - else - { - sw=this.getOutputString(); - sw.write(header); - } - while (outrs.next()) - { - line.setLength(0); - line.append(rowDelim1); - for (int i = 1; i <= colNumber; i++) { - if (types[i-1] == Types.LONGVARCHAR) { - //Der Informix-Treiber verlangt hier getString - // statt getObject! - o = outrs.getString(i); - } else { - o = outrs.getObject(i); - } - //vergl. de.superx.common.Maske.getCSV - f_wert = SxDBUtils.field_value(o); - f_wert = prepareFieldValue(outformat,lbl[i-1],f_wert,delim); - - if (i < colNumber) - line.append( f_wert ); - else { - line.append(f_wert ); - line.append(rowDelim2); - } - - } - - if(writeFileOutput) - { - //fw=this.getOutputFile(); - - fw.write(line.toString()); - rowCounterBeforeFlush++; - if (rowCounterBeforeFlush > 10000) { - de.memtext.util.MemoryUtils.printfree(); - fw.flush(); - - rowCounterBeforeFlush = 0; - } - } - else - { - //sw=this.getOutputString(); - sw.write(line.toString()); - } - rowCounter++; - - - } ; //von while - outrs.close(); - - if(writeFileOutput) - { - if(outformat.equalsIgnoreCase("xml")) - fw.write(footer); - fw.flush(); - fw.close(); - } - else - { - if(outformat.equalsIgnoreCase("xml")) - sw.write(footer); - sw.close(); - this.setOutputString(sw); - } - return rowCounter; - - - - - - - } - private void setColnamesAndTypes(ResultSetMetaData rsmd) throws SQLException - { - int cols = rsmd.getColumnCount(); - int[] types = new int[cols]; - String[] lbl = new String[cols]; - - // Print the result column names? - for (int i = 0; i < cols; i++) { - lbl[i] = rsmd.getColumnLabel(i+1); - types[i] = rsmd.getColumnType(i+1); - } - - this.setColnames(lbl); - this.setColtypes(types); - this.setColumnCount(cols); - } - - - - private String getColnamesCSV(String delim) { - String headZs = ""; - int colNumber = this.getColnames().length; - for (int i = 0; i < colNumber; i++) { - headZs += ( this.getColnames()[i] +delim); - } - - return headZs; - } - private String getColnamesXML() { - String headZs = ""; - int colNumber = this.getColnames().length; - for (int i = 0; i < colNumber; i++) { - headZs += " "+NEWLINE; - - } - headZs+=""; - - return headZs; - } - private String prepareQuery(String query) - { - query = query.trim(); - //DOS produces unnecessary ".." around the stmt - if (query.length() > 0) { - - if (query.startsWith("\"")) - query = query.substring(1, query.length()); - if (query.endsWith("\"")) - query = query.substring(0, query.length() - 1); - } - return query; - } - private String prepareFieldValue(String outformat,String fieldName, String f_wert,String delim) - { - String fieldValue=""; - if (outformat.equals("xml")) - { - fieldValue+=""; - f_wert=encodeCDATA(f_wert); - if(f_wert.indexOf("&") > -1 || f_wert.indexOf("<") > -1 || f_wert.indexOf(">") > -1) - fieldValue += ""; - else - fieldValue += f_wert; - fieldValue+=""+NEWLINE; - } - //wenn der Feldwert zufällig das Trennzeichen enthält, wird es mit "\" maskiert - if (outformat.equals("txt")) { - fieldValue = SxDBUtils.prepareInformixCsv(f_wert); - if (fieldValue != null && (fieldValue.indexOf(delim) > -1)) fieldValue = de.memtext.util.StringUtils.replace(fieldValue, delim, "\\" + delim); - fieldValue+=delim; - } - - - return fieldValue; - } - /** - * Beim XML Export darf der Feldinhalt nicht CDATA-Tags enthalten, dies wrürde beim Import - * Probleme machen. Daher durch Platzhalter ersetzen - * - * @param Feldinhalt - * PG/IDS - * @return Feldinhalt (ersetzt) - */ - private String encodeCDATA(String x) - { - if (x==null) x=""; - x = StringUtils.replace(x,"", - "CDATAEND"); - return x; - - } -} diff --git a/src/de/superx/elt/SqlExecutor.java b/src/de/superx/elt/SqlExecutor.java deleted file mode 100644 index 370a8d2..0000000 --- a/src/de/superx/elt/SqlExecutor.java +++ /dev/null @@ -1,344 +0,0 @@ -/* - * de.superx.etl - a package for controlling ETL routines - * Copyright (C) 2021 Daniel Quathamer - * - * This package is licensed under the CampusSource License; - * http://www.campussource.de/org/license/ - */ -package de.superx.elt; -import java.io.BufferedOutputStream; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.PrintStream; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.JDBCType; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.sql.Statement; -import java.sql.Types; -import java.util.logging.LogManager; -import java.util.logging.Logger; -import java.util.logging.Level; - -import de.memtext.util.DateUtils; -import de.memtext.util.StringUtils; -import de.superx.bin.FMParser; -import de.superx.bin.SxConnection; -import de.superx.bin.SxDBUtils; -import de.superx.bin.SxJdbcClient; - -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Properties; -import java.util.StringTokenizer; - -import de.superx.bin.XUpdater; -import de.superx.common.FieldContainer; -import de.superx.elt.bin.SxTransformer; -import de.superx.servlet.ServletUtils; -import de.superx.servlet.SuperXManager; -import de.superx.servlet.SxPools; -import de.superx.servlet.SxSQL_Server; -import de.superx.util.SqlStringUtils; -/** - * @author Daniel Quathamer Projektgruppe SuperX - * doquery.java - * @ - * Dieses Javaprogramm führt einen SQL-Ausdruck aus und gibt das Ergebnis aus.
- * Gebrauch:
java doquery (optional) (optional) (optional) - * - - */ -/* - * SQL-Abfragen Ergebnis serialisieren nach CSV / XML - */ -public class SqlExecutor { - public SqlExecutor(String mandantenId,SxConnection mySxConnection, String sqlScript, Properties params) { - super(); - this.mySxConnection = mySxConnection; - this.sqlScript = sqlScript; - this.mandantenId = mandantenId; - this.logger = Logger.getLogger("superx_" + mandantenId); - this.params=params; - - } - public SqlExecutor(String mandantenId,SxConnection mySxConnection, File sqlScriptFile, Properties params) throws IOException { - super(); - this.mySxConnection = mySxConnection; - this.mandantenId = mandantenId; - this.sqlScriptFile=sqlScriptFile; - this.logger = Logger.getLogger("superx_" + mandantenId); - this.params=params; - - if (!sqlScriptFile.exists()) { - throw new IOException("Datei nicht gefunden: " + sqlScriptFile.getAbsolutePath()); - } - BufferedReader in; - //--- InputStream generieren ---// - in = new BufferedReader(new InputStreamReader(new FileInputStream(sqlScriptFile))); - - //--- Verarbeiten der Datei ---// - String sql = ""; - String text = ""; - while ((text = in.readLine()) != null) { - //MB auskommentiert 27.4.05 - //löschte ( in - //insert into - //( - //tid,... - //if (text.length() > 1) - sql += NEWLINE + text.trim(); - } - in.close(); - this.sqlScript =sql; - - } - public final String NEWLINE=System.getProperty("line.separator"); - private SxConnection mySxConnection; - private String sqlScript; - private File sqlScriptFile; - private Logger logger; - private String mandantenId="default"; - private Statement st; - private Connection myConnection; - private StringBuffer outString=new StringBuffer(""); - //private PrintStream stringOutWriter=new PrintStream(outString); - //private PrintWriter output=new PrintWriter(stringOutWriter); - private int returnCode; - private String outfile=""; - private String CSVdelim="^"; - private boolean printColNames=false; - private String outFormat="txt"; - private long numberOfRows; - - private Properties params; - - - public SxConnection getMySxConnection() { - return mySxConnection; - } - public void setMyConnection(SxConnection mySxConnection) { - this.mySxConnection = mySxConnection; - } - public String getSqlScript() { - return sqlScript; - } - public void setSqlScript(String sqlScript) { - this.sqlScript = sqlScript; - - } - - public Logger getLogger() { - return logger; - } - public void setLogger(Logger logger) { - this.logger = logger; - } - public String getMandantenId() { - return mandantenId; - } - public void setMandantenId(String mandantenId) { - this.mandantenId = mandantenId; - } - - public String getOutfile() { - return outfile; - } - public void setOutfile(String outfile) { - this.outfile = outfile; - } - public String getCSVdelim() { - return CSVdelim; - } - public void setCSVdelim(String cSVdelim) { - CSVdelim = cSVdelim; - } - public boolean getPrintColNames() { - return printColNames; - } - public void setPrintColNames(boolean printColNames) { - this.printColNames = printColNames; - } - public String getOutFormat() { - return outFormat; - } - public void setOutFormat(String outFormat) { - this.outFormat = outFormat; - } - public int getReturnCode() { - return returnCode; - } - public void setReturnCode(int returnCode) { - this.returnCode = returnCode; - } - public long getNumberOfRows() { - return numberOfRows; - } - public void setNumberOfRows(long numberOfRows) { - this.numberOfRows = numberOfRows; - } - public Properties getParams() { - return params; - } - public void setParams(Properties params) { - this.params = params; - } - public StringBuffer getOutString() { - return outString; - } - public void setOutString(StringBuffer outString) { - this.outString = outString; - } - public int executeQueries() throws Exception - { - returnCode=0; - FileWriter fw; - StringWriter sw; - SxTransformer myTransformer; - QueryResultSerializer myQueryResultSerializer=null; - if (sqlScript.toLowerCase().indexOf("")>-1) - { - SxConnection myConnection = new SxConnection(); - myConnection.setPropfile(mySxConnection.getPropfile()); - Connection con = myConnection.getConnection(); - - new XUpdater().execute(con, myConnection.getDatabaseAbbr(), sqlScript,logger); - } - else - { - if(sqlScript.toLowerCase().indexOf("--freemarker template")>-1) - { - /* boolean isTemplate = getSelect_stmt().toUpperCase().indexOf("FREEMARKER TEMPLATE") > -1; - String select_string = SqlStringUtils.generateSQL(SxPools.get(mandantenID).getDatabaseAbbr(), - individualFields.getFormular(), getSelect_stmt() + "\n" + getCleanup_stmt()); - - // select_string=select_string.replaceAll("Fächer.elements", - // "Fächer.xx"); - // map.clear(); - if (isTemplate) { - SuperXManager.setLastFMMaskenSql( - "-- " + getMaskInfo() + " " + DateUtils.getNowString() + "\n" + select_string); - select_string = SxPools.get(mandantenID).getTemplateProcessor().process(map, (Integer) getId(), - getMaskInfo(), select_string, individualFields, SxPools.get(mandantenID).getRepository(), - SxPools.get(mandantenID).getSqlDialect()); - // danach enthält map alle vars inkl. sqlvars - } - // MB 07/2010 macht Probleme bei Freemarker hashes - // generell deaktiviert, hier falls doch noch in alten Masken - // vorhanden - select_string = SqlStringUtils.removeComment(select_string, "{", "}"); -*/ - /* alt: sqlScript=de.superx.bin.FMParser.simpleParser(mySxConnection.getPropfile(), sqlScript);*/ - //Die map und der FieldContainer sind null, werden nur in Masken genutzt - HashMap map = new HashMap(); - FieldContainer individualFields = new FieldContainer(); - if(SxPools.hasMandanten()){ - //Servlet Betrieb: - sqlScript= SxPools.get(mandantenId).getTemplateProcessor().process(map, -1, - "SQL-Script", sqlScript, individualFields, SxPools.get(mandantenId).getRepository(), - SxPools.get(mandantenId).getSqlDialect()); - } - else - { - //Kommandozeile: TODO hier sind noch keine FM Scripte mit SQLVAR möglich: - //FMParser myParser=new FMParser() - Connection con = mySxConnection.getConnection(); - EtlFmParser myParser=new EtlFmParser("default",con); - - sqlScript=myParser.simpleParser(sqlScript); - } - String keepGenerated=System.getProperty("FreemarkerKeepGenerated"); - if(keepGenerated!=null && keepGenerated.equalsIgnoreCase("true")) - { - FileWriter sqlScriptTmp ; - - if(sqlScriptFile==null) - { - File tempFile = File.createTempFile("fm_output", ".sql"); - sqlScriptTmp = new FileWriter(tempFile); - logger.info("FM generated SQL: "+tempFile.getAbsolutePath()); - } - else - sqlScriptTmp = new FileWriter(sqlScriptFile.getAbsolutePath()+".tmp.sql"); - sqlScriptTmp.write(sqlScript); - sqlScriptTmp.close(); - } - - } - sqlScript = sqlScript.trim(); - sqlScript = SqlStringUtils.removeComment(sqlScript, "{", "}"); - if (sqlScript.startsWith("\"")) - sqlScript = sqlScript.substring(1, sqlScript.length()); - if (sqlScript.endsWith("\"")) - sqlScript = sqlScript.substring(0, sqlScript.length() - 1); - //replace CLI-params: - if (params==null) - { - //do nothing - } - else - { - Enumeration paramEnum = params.propertyNames(); - while (paramEnum.hasMoreElements()) { - String paramName = (String)paramEnum.nextElement(); - String paramValue = params.getProperty(paramName); - sqlScript=de.memtext.util.StringUtils.replace(sqlScript,"$"+paramName, paramValue); - } - } - logger.config("Inhalt der sql-Datei: "+NEWLINE+"--" + sqlScript + "--"); - SxJdbcClient myClient = new SxJdbcClient(logger, mySxConnection.getPropfile(), sqlScript); - myClient.Rs_executeALL(); - ResultSet myrs = myClient.getRs(); - if (myrs != null) { - //Letzter SQL liefert Ergebnisse: - if(!outfile.equals("")) - { - try { - fw = new FileWriter(outfile); - if(outFormat.equalsIgnoreCase("xml")) - fw.write(""); - myQueryResultSerializer=new QueryResultSerializer("default", mySxConnection, myrs,fw); - numberOfRows=myQueryResultSerializer.unloadQueryResults("DOQUERY",outFormat,this.CSVdelim,printColNames); - returnCode=myQueryResultSerializer.getReturnCode(); - - } catch (IOException e) { - logger.severe ("Fehler beim Erstellen der Datei "+outfile); - returnCode=1; - } - - } - else - { - sw=new StringWriter(); - if(outFormat.equalsIgnoreCase("xml")) - sw.write(""); - myQueryResultSerializer=new QueryResultSerializer("default", mySxConnection, myrs,sw); - numberOfRows=myQueryResultSerializer.unloadQueryResults("DOQUERY",outFormat,this.CSVdelim,printColNames); - returnCode=myQueryResultSerializer.getReturnCode(); - outString= myQueryResultSerializer.getOutputString().getBuffer(); - - } - - - - - } else - logger.info("Keine Rückgabewerte aus SQL-Script"); - } - return returnCode; - } - - - -} diff --git a/src/de/superx/elt/TableUploader.java b/src/de/superx/elt/TableUploader.java deleted file mode 100644 index 1e925cd..0000000 --- a/src/de/superx/elt/TableUploader.java +++ /dev/null @@ -1,779 +0,0 @@ -/* - * de.superx.etl - a package for controlling ETL routines - * Copyright (C) 2021 Daniel Quathamer - * - * This package is licensed under the CampusSource License; - * http://www.campussource.de/org/license/ - */ -package de.superx.elt; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.PrintStream; -import java.io.Reader; -import java.io.UnsupportedEncodingException; -import java.nio.charset.CodingErrorAction; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.SQLException; -import java.sql.Statement; -import java.sql.Types; -import java.text.ParseException; -import java.util.Iterator; -import java.util.Properties; - -import de.superx.util.SqlStringUtils; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.xpath.XPathFactory; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; - -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.*; - - -import org.postgresql.PGConnection; -import org.postgresql.copy.CopyManager; - -import de.superx.bin.SxConnection; -import de.superx.bin.SxJdbcClient; -import de.superx.bin.UploadRecords; -import de.superx.elt.util.FileUtils; -import de.memtext.util.DateUtils; -import de.memtext.util.GetOpts; -import de.memtext.util.StringUtils; -import de.memtext.util.XMLUtils; -public class TableUploader { - private String logfile; - private String dbpropfile; - private String mode="stop"; - private String inFormat; - private String targetTable; - private String srcFile; - private boolean header=false; - - private String delim="^"; - private String encoding=SqlStringUtils.getEncoding(); - private String inserts=""; - private boolean truncateTargetTable=true; - private boolean continueAfterError; - private boolean removeTrailingDelim=true; - private boolean isPostgres; - private boolean useBatch=false; - private static int maxCols=1000; - private String[] insert_cols = new String[maxCols]; - private int[] insert_types = new int[maxCols]; - private int numberOfColumns; - public long numberOfRows; - private int returnCode; - private String xml_search_path; - private Connection uploadConnection; - private DatabaseMetaData dbmd; - private PreparedStatement pst; - - - public TableUploader() { - // TODO Auto-generated constructor stub - - } - - public Connection getUploadConnection() { - return uploadConnection; - } - public void setUploadConnection(Connection uploadConnection) { - this.uploadConnection = uploadConnection; - } - public boolean isRemoveTrailingDelim() { - return removeTrailingDelim; - } - public void setRemoveTrailingDelim(boolean removeTrailingDelim) { - this.removeTrailingDelim = removeTrailingDelim; - } - public void setHeader(boolean header) { - this.header = header; - } - - - public String getDbpropfile() { - return dbpropfile; - } - public void setDbpropfile(String dbpropfile) { - this.dbpropfile = dbpropfile; - } - public String getMode() { - return mode; - } - public void setMode(String mode) { - if (!mode.equals("stop") && !mode.equals("exclude-field")&& !mode.equals("transaction")) - mode = "exclude-row"; - this.mode = mode; - } - public String getInFormat() { - return inFormat; - } - public void setInFormat(String inFormat) { - this.inFormat = inFormat; - } - public String getTargetTable() { - return targetTable; - } - public void setTargetTable(String targetTable) { - this.targetTable = targetTable; - } - public String getSrcFile() { - return srcFile; - } - public void setSrcFile(String srcFile) { - this.srcFile = srcFile; - } - - public String getDelim() { - return delim; - } - public void setDelim(String delim) { - if (delim.equals("tab")) - delim = "\t"; //Tab - if (delim.equals("")) - delim = "^"; //default Delimiter - this.delim = delim; - } - public String getEncoding() { - return encoding; - } - public void setEncoding(String encoding) { - if(encoding==null || encoding.equals("")) - encoding="UTF-8"; - this.encoding = encoding; - } - public String getInserts() { - return inserts; - } - public void setInserts(String inserts) { - if(inserts.equalsIgnoreCase("batch")) - useBatch=true; - if(inserts.equalsIgnoreCase("simple")) - useBatch=false; - - this.inserts = inserts; - } - public boolean isTruncateTargetTable() { - return truncateTargetTable; - } - - public void setTruncateTargetTable(boolean truncateTargetTable) { - this.truncateTargetTable = truncateTargetTable; - } - public void setTruncateTargetTable(String truncateTargetTable) { - if(truncateTargetTable!=null) - {if(truncateTargetTable.equalsIgnoreCase("true")) - this.truncateTargetTable =true; - else - this.truncateTargetTable =false; - } - else - this.truncateTargetTable =false; - } - - public int getReturnCode() { - return returnCode; - } - - public void setReturnCode(int returnCode) { - this.returnCode = returnCode; - } - - public boolean isContinueAfterError() { - return continueAfterError; - } - public void setContinueAfterError(boolean continueAfterError) { - this.continueAfterError = continueAfterError; - } - public String getXml_search_path() { - return xml_search_path; - } - - public void setXml_search_path(String xml_search_path) { - this.xml_search_path = xml_search_path; - } - - public long uploadFile() throws Exception - { - String protokoll=""; - long numberOfRows=0; - returnCode=0; - try { - //dbmd=uploadConnection.getMetaData(); - String dbname=uploadConnection.getCatalog(); - if(truncateTargetTable) - { - Statement stm=uploadConnection.createStatement(); - stm.execute("delete from "+this.targetTable+";"); - stm.close(); - } - if(inFormat.equalsIgnoreCase("xml")) - { - numberOfRows=uploadXML(); - } - else - numberOfRows=uploadCSV(); - } catch (Exception e) { - returnCode=1; - throw new Exception(e); - } - return numberOfRows; - - } - private long uploadXML() throws Exception - { - String feld_wert; - String errmsg=""; - Document mydomres=null; - numberOfRows=0; - org.xml.sax.InputSource is; - NodeList rowlist; - - mydomres = de.superx.elt.EtlUtils.buildDocumentFromXmlFile(srcFile); - - if(xml_search_path==null) - { - rowlist = mydomres.getElementsByTagName("row"); - } - else - - { - //XPath xPath = XPathFactory.newInstance().newXPath(); - File inputFile = new File(srcFile); - //XPathFactory factory = XPathFactory.newInstance(); - XPathFactory factory = new net.sf.saxon.xpath.XPathFactoryImpl(); - - XPath xPath = factory.newXPath(); - //Document doc = builder.parse(inputFile); - //doc.getDocumentElement().normalize(); - rowlist=(NodeList) xPath.compile(xml_search_path).evaluate( - mydomres, XPathConstants.NODESET); - } - Node rownode; - initializeColumnSchema(); - String insertHead=createPreparedStatementHead(); - pst = uploadConnection.prepareStatement(insertHead); - if(useBatch) - pst.clearBatch(); - int anz_rows = rowlist.getLength(); - for (int zeilennr = 0; zeilennr < anz_rows; zeilennr++) { - //Schleife über jede Zeile des XML-Stroms - rownode = rowlist.item(zeilennr); - //pst.clearParameters(); - - for(int col=0; col < numberOfColumns;col++) - { - for (Iterator it = XMLUtils.getChildNodeIterator(rownode); it.hasNext();) { - Node fldNode = (Node) it.next(); - //System.out.println(XMLUtils.getTheValue(fldNode)); - if (XMLUtils.getAttribValue(fldNode,"name").equalsIgnoreCase(insert_cols[col])) { - //int p; - feld_wert=""; - try{ - feld_wert = XMLUtils.getTheValue(fldNode).trim(); - feld_wert=StringUtils.replace(feld_wert, - "CDATASTART", ""); - - - } - catch (IllegalArgumentException e) - { - //Node ist NULL, keine Warnung notwendig - } - - errmsg = feld_wert_to_pst(zeilennr, col, errmsg, feld_wert); - - } //Wenn Feldname übereinstimmt - } - } //Ende der Schleife über die Spalten - if(!errmsg.equals("") && mode.equals("stop")) - { - break; - } - if(useBatch) - pst.addBatch(); - else - pst.executeUpdate(); - - numberOfRows++; - - } //Ende der Schleife über die Zeilen - if(useBatch) - pst.executeBatch(); - return numberOfRows; - } - - - - private long uploadCSV() throws Exception - { - String line; - String line2; - File outFile=null; - String protokoll=""; - long numberOfRows=0; - if(isPostgres && !inserts.equalsIgnoreCase("simple") && !inserts.equalsIgnoreCase("batch")) - { - if(removeTrailingDelim) - srcFile=removeTrailingDelim(srcFile); - numberOfRows=uploadCSVinPostgres(srcFile,removeTrailingDelim); - } - else - numberOfRows=uploadCSVwithAnsiSQL(srcFile); - return numberOfRows; - - - } - private String removeTrailingDelim(String srcFile) throws UnsupportedEncodingException, FileNotFoundException, IOException { - String line; - File outFile; - String returnSrcFile=srcFile+".tmp"; - BufferedReader in2 = new BufferedReader(new InputStreamReader(new FileInputStream(srcFile), encoding)); - - outFile=new File(srcFile+".tmp"); - FileOutputStream out = new FileOutputStream(outFile, false); - PrintStream out2 = new PrintStream(out, true, encoding); - - - while ((line = in2.readLine()) != null) { - - if (line.endsWith(delim)) - line=line.substring(0,line.length()-delim.length()); - out2.println(line); - out2.flush(); - - } - return returnSrcFile; - } - private long uploadCSVinPostgres(String srcFile, boolean deleteSrcFile) { - long numOfRows=0; - String copySql = "COPY " + targetTable + " FROM STDIN WITH DELIMITER '" + delim + "' NULL '' ENCODING '"+ encoding+"'"; - copySql += header ? " HEADER" : ""; - - String srcFileContent=de.superx.elt.EtlUtils.getFileContentsWithEncoding(srcFile, encoding); - String msg=""; - try { - //dbmd=uploadConnection.getMetaData(); - String dbname=uploadConnection.getCatalog(); - Statement stm=uploadConnection.createStatement(); - int isIso=0; - ResultSet rs=stm.executeQuery("SELECT distinct 1 FROM pg_catalog.pg_database where datname='"+dbname+"' and datctype ilike '%euro%' or datctype ilike '%1252%' or datctype ilike '%8859%';"); - while (rs.next()) { - if(rs.getObject(1)!=null) - isIso= Integer.parseInt(rs.getObject(1).toString()); - - } - rs.close(); - stm.close(); - Reader in4=null; - final CopyManager cpm = ((PGConnection) uploadConnection).getCopyAPI(); - long anz = 0; - msg = ""; - - if(isIso==1) - { - String srcFileIso=srcFile+"_iso.tmp"; - String srcFileContentValidIso = FileUtils.convertToIso(srcFileContent,"postgres") ;//new String(srcFileContent.getBytes("ISO-8859-1")); - de.superx.elt.EtlUtils.saveFileContentsWithEncoding(srcFileIso, srcFileContentValidIso, "iso-8859-9"); - FileInputStream fis = new FileInputStream(srcFileIso); - in4 = new BufferedReader(new InputStreamReader(fis, "iso-8859-9")); - - } - else - { - FileReader in3 = new FileReader(srcFile); - in4 = new BufferedReader(in3); - - } - - numOfRows= cpm.copyIn(copySql, in4); - numberOfRows =numOfRows; - if(deleteSrcFile) - { - File outFile=new File(srcFile); - if(outFile!=null) - outFile.delete(); - } - } catch (Exception e) { - // TODO Auto-generated catch block - msg=e.toString(); - } - return numOfRows; - } - - private long uploadCSVwithAnsiSQL(String srcFile) throws SQLException, FileNotFoundException, IOException { - numberOfRows=0; - String text; - String text2; - String msg=""; - int zeilennr=1; - int fehlerSaetze=0; - - BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(srcFile), encoding)); - initializeColumnSchema(); - String insertHead=createPreparedStatementHead(); - pst = uploadConnection.prepareStatement(insertHead); - if(useBatch) - pst.clearBatch(); - - while ((text = in.readLine()) != null) { - if (text.endsWith("\\")) { - text=text.substring(0, text.length()-1); - text2 = in.readLine(); - if (text2 != null) { - text += "\n"+ text2; - while (text2.endsWith("\\")) { - text=text.substring(0, text.length()-1); - text2 = in.readLine(); - if (text2 != null) - text += "\n"+text2; - - } - } - } - - String prepare = - createPreparedInsertStatement(zeilennr, - insertHead, - text); - if(!prepare.equals("") && mode.equals("stop")) - { - msg=prepare; - break; - } - if(useBatch) - pst.addBatch(); - else - pst.executeUpdate(); - numberOfRows++; - - - - } - if(useBatch) - pst.executeBatch(); - //TODO: msg - return numberOfRows; - } - - private String createPreparedInsertStatement( - int line, - String insertHead, - String text) - throws SQLException { - int p; - int i=0; - int k=0; - String errmsg = ""; - String feld_wert; - //pst.clearParameters(); - do { - //ggf. Trennzeichen am Ende hinzufügen: - if(!text.endsWith(delim)) - text+= delim; - p = text.indexOf(delim, i); - //logger.config("Type "+types[k]); - //maskierte Trennzeichen abfangen: - if(p>0 && text.substring(p-1, p).equals("\\")) - p = text.indexOf(delim, p+1); - - if (p > -1 ) { - if(p==-1) - feld_wert = text.substring(i); - else - feld_wert = text.substring(i, p); - //wenn der Feldwert zufällig das Zeichen "\\n" enthält, wird es zu "\n" - if(feld_wert != null && (feld_wert.indexOf("\\\\n") >0 )) - { - feld_wert=de.memtext.util.StringUtils.replace(feld_wert, "\\\\n", "\\n"); - } - //wenn der Feldwert das Zeichen "\Trennzeichen" enthält, wird der \ entfernt - if(feld_wert != null && (feld_wert.indexOf("\\"+delim) >0 )) - { - feld_wert=de.memtext.util.StringUtils.replace(feld_wert, "\\", ""); - } - //wenn der Feldwert das Zeichen "\\" enthält, wird ein \ entfernt - if(feld_wert != null && (feld_wert.indexOf("\\\\") >0 )) - { - feld_wert=de.memtext.util.StringUtils.replace(feld_wert, "\\\\", "\\"); - } - - errmsg = feld_wert_to_pst(line,k, errmsg, feld_wert); - k++; - i = p + 1; - } - - } while (p > -1); - return errmsg; - } - private String feld_wert_to_pst(int line, int col, String errmsg, String feld_wert) throws SQLException { - - - if( col >= numberOfColumns) - errmsg+= "Anzahl Spalten in Datei ist "+col+", aber es sollten nur "+(numberOfColumns-1)+" Spalten sein. Bitte prüfen Sie das Trennzeichen"; - else - { - if (feld_wert.equals("")) - try { - pst.setNull(col + 1, insert_types[col]); - } catch (SQLException e1) { - errmsg += e1.toString(); - } else { - - switch (insert_types[col]) { - case Types.BIGINT : - case Types.TINYINT : - case Types.SMALLINT : - case Types.INTEGER : - - try { - int myInt = (int) Integer.parseInt(feld_wert.trim()); - pst.setInt(col + 1, myInt); - } catch (NumberFormatException e1) { - errmsg += e1.toString(); - setFieldToNull(col, insert_types, pst); - } catch (SQLException e1) { - errmsg += conversionException(line, col, feld_wert,e1.toString()); - setFieldToNull(col, insert_types, pst); - } - break; - case Types.FLOAT : - try { - float myFloat = - (float) Float.parseFloat(feld_wert.trim()); - pst.setFloat(col + 1, myFloat); - } catch (NumberFormatException e1) { - errmsg += conversionException(line, col, feld_wert,e1.toString()); - setFieldToNull(col, insert_types, pst); - } catch (SQLException e1) { - errmsg += conversionException(line, col, feld_wert,e1.toString()); - setFieldToNull(col, insert_types, pst); - } - break; - - case Types.REAL : - case Types.DOUBLE : - case Types.NUMERIC : - case Types.DECIMAL : - try { - double myDouble = - (double) Double.parseDouble(feld_wert.trim()); - pst.setDouble(col + 1, myDouble); - } catch (NumberFormatException e1) { - errmsg += conversionException(line, col, feld_wert,e1.toString()); - setFieldToNull(col, insert_types, pst); - } catch (SQLException e1) { - errmsg += conversionException(line, col, feld_wert, e1.toString()); - setFieldToNull(col, insert_types, pst); - } - break; - - case Types.CHAR : - case Types.VARCHAR : - default : - if(feld_wert.equals(" ")) - feld_wert=""; //Leerzeichen im UNL-File wird zu Leerstring - try { - pst.setString(col + 1, feld_wert); - } catch (SQLException e1) { - errmsg += conversionException(line, col, feld_wert,e1.toString()); - setFieldToNull(col, insert_types, pst); - } - break; - case Types.LONGVARCHAR : - ByteArrayInputStream by = - new ByteArrayInputStream(feld_wert.getBytes()); - pst.setAsciiStream( - col + 1, - by, - feld_wert.length()); - break; - case Types.DATE : - try { - java.util.Date datum = - DateUtils.parse(feld_wert.trim()); - feld_wert = DateUtils.formatUS(datum); - //Leider ist dieser Schritt wg java.sql.Date nötig - pst.setDate( - col + 1, - java.sql.Date.valueOf(feld_wert)); - - } catch (SQLException e1) { - errmsg += conversionException(line, col, feld_wert, e1.toString()); - setFieldToNull(col, insert_types, pst); - } catch (ParseException e1) { - errmsg += conversionException(line, col, feld_wert, e1.toString()); - setFieldToNull(col, insert_types, pst); - } - catch (IllegalArgumentException e1) { - errmsg += conversionException(line, col, feld_wert, e1.toString()); - setFieldToNull(col, insert_types, pst); - } - - break; - case Types.TIME : - - try { - //Time zeit = (java.sql.Time) - //DateUtils.timeParse(feld_wert); - pst.setTime(col + 1, java.sql.Time.valueOf( - feld_wert.trim())); - } catch (SQLException e1) { - errmsg += conversionException(line, col, feld_wert, e1.toString()); - setFieldToNull(col, insert_types, pst); - } - catch (IllegalArgumentException e1) { - errmsg += conversionException(line, col, feld_wert, e1.toString()); - setFieldToNull(col, insert_types, pst); - } - - break; - case Types.TIMESTAMP : - try { - java.util.Date datum = - DateUtils.dateTimeParse(feld_wert.trim()); - feld_wert = DateUtils.dateTimeFormatUS(datum); - //Leider ist dieser Schritt wg java.sql.Date nötig - pst.setTimestamp( - col + 1, - java.sql.Timestamp.valueOf( - feld_wert + ".0")); - - } catch (SQLException e1) { - errmsg += conversionException(line, col,feld_wert, e1.toString()); - setFieldToNull(col, insert_types, pst); - } catch (ParseException e1) { - errmsg += conversionException(line, col, feld_wert, e1.toString()); - setFieldToNull(col, insert_types, pst); - } - catch (IllegalArgumentException e1) { - errmsg += conversionException(line, col, feld_wert, e1.toString()); - setFieldToNull(col, insert_types, pst); - } - - break; - - case Types.BIT : - // Types.BOOLEAN gibt es im jdk 1.3 nicht - try { - boolean wf = - (boolean) Boolean.getBoolean(feld_wert.trim()); - pst.setBoolean(col + 1, wf); - } catch (SQLException e1) { - errmsg += conversionException(line, col, feld_wert, e1.toString()); - setFieldToNull(col, insert_types, pst); - } - //Boolean wird vom Informix-Treiber als OTHER (1111) erkannt - //Da aber default '' ist, klappt es trotzdem - break; - } - - } - } - return errmsg; - } - private void setFieldToNull( - int k, - int[] insert_types, - PreparedStatement pst) { - if (mode.equals("exclude-field")) - try { - pst.setNull(k + 1, insert_types[k]); - } catch (SQLException e3) { - System.err.println("Invalid Field " + (k + 1) + " could not be set to null"); - } - - } - private String conversionException(int line,int col, String field_value, String error) { - String err_msg = ""; - - err_msg = "Error in line "+line+" in Column " + (col + 1) + " "+insert_cols[col]+" value "+ field_value+ ": " + error.toString() + "; "; - - return err_msg; - } - private void initializeColumnSchema() throws SQLException - { - int i=0; - - ResultSet rs = null; - ResultSetMetaData rsmd = null; - String tabelle=targetTable; - if (!dbmd.storesLowerCaseIdentifiers()) - tabelle = tabelle.toUpperCase(); - rs =dbmd.getColumns(uploadConnection.getCatalog(), null, tabelle, null); - rsmd = rs.getMetaData(); - while (rs.next()) { - insert_cols[i] = rs.getObject("COLUMN_NAME").toString(); - insert_types[i] = rs.getInt("DATA_TYPE"); - i++; - } - numberOfColumns=i; - if(!dbmd.supportsBatchUpdates()) - useBatch=false; - - } - private String createPreparedStatementHead() throws SQLException - { - - String sql=null; - - String insert_head = "insert into " + targetTable+"("; - String insert_val=""; - for (int i = 0; i < numberOfColumns; i++) - { - insert_head += insert_cols[i] + ", "; - insert_val+="?, "; - } - insert_head = insert_head.substring(0, insert_head.length() - 2); - insert_val = insert_val.substring(0, insert_val.length() - 2); - insert_head +=") values( "; - sql=insert_head + insert_val+");"; - return sql; - - } - public Connection getConnection(Connection myConnection,String propfile) throws Exception { - - if(myConnection==null) - { - SxConnection mySxConnection = null; - mySxConnection = new SxConnection(); - mySxConnection.setPropfile(propfile); - - myConnection = mySxConnection.getConnection(); - - String db_driver = mySxConnection.m_DriverClass; - if(db_driver.equals("org.postgresql.Driver")) - isPostgres=true; - } - dbmd = myConnection.getMetaData(); - - return myConnection; - - } - -} diff --git a/src/de/superx/elt/bin/Doquery.java b/src/de/superx/elt/bin/Doquery.java deleted file mode 100644 index a1d3e6d..0000000 --- a/src/de/superx/elt/bin/Doquery.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * de.superx.etl - a package for controlling ETL routines - * Copyright (C) 2021 Daniel Quathamer - * - * This package is licensed under the CampusSource License; - * http://www.campussource.de/org/license/ - */ -package de.superx.elt.bin; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileWriter; -import java.io.IOException; -import java.io.StringWriter; -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.logging.LogManager; -import java.util.logging.Logger; -import java.util.StringTokenizer; -import de.superx.util.SqlStringUtils; -import de.superx.bin.SxConnection; -import de.superx.common.SuperX_el; -import de.superx.elt.QueryResultSerializer; -import de.superx.servlet.SxPools; -import de.superx.servlet.SxSQL_Server; - -/** - * @author Daniel Quathamer Projektgruppe SuperX - * doquery.java - * @ - * Dieses Javaprogramm führt einen SQL-Ausdruck aus und gibt das Ergebnis aus.
- * Gebrauch:
java doquery (optional) (optional) (optional) - * - - */ - -public class Doquery { - private static Connection myDb; - private static Statement st; // Our statement to run queries with - private static DatabaseMetaData dbmd; - // This defines the structure of the database - private static boolean done = false; // Added by CWJ to permit \q command - private static String delim = "^"; - private static String header = "false"; - private static String outFormat = "txt"; - private static String logfile = "../conf/logging.properties"; - private static String tabelle = ""; - private static String dbpropfile = "../conf/db.properties"; - private static SxConnection myConnection = null; - private static String db_driver; - private static String mandantenID="default"; - private static String outfile = ""; - private static Logger logger = - (Logger) Logger.getLogger(Doquery.class.toString()); - private static String usage = - "-------------------------------------\nGebrauch: java de.superx.bin.Doquery $LOGGER_PROPERTIES $DB_PROPERTIES $sql (optional: )$outformat $DBDELIMITER $header $filename \n---------------------------------------------------"; - - public static int go(String args[]) - throws - Exception { - if (args.length > 0) { - logfile = args[0].trim(); - } else { - throw new IllegalArgumentException("Mindestens drei Parameter (Pfad zu den logger.properties, Pfad zu den db.properties, sql-String) erfoderlich"); - - } - File f = new File(logfile); - if (!f.exists()) { - throw new IOException("Datei nicht gefunden: " + logfile); - } - - FileInputStream ins = new FileInputStream(logfile); - LogManager MyLogManager = java.util.logging.LogManager.getLogManager(); - MyLogManager.readConfiguration(ins); - logfile = MyLogManager.getProperty(".level"); - logger.info("Using Loggging-Level " + logfile); - String query = ""; - long numberOfRows=0; - int returnCode=0; - - if (args.length > 1) { - dbpropfile = args[1].trim(); - } else { - logger.severe( - "Mindestens drei Parameter (Pfad zu den logger.properties, Pfad zu den db.properties, sql-String) erfoderlich"); - System.exit(1); - } - if (args.length <= 2) { - logger.severe( - "Mindestens drei Parameter (Pfad zu den logger.properties, Pfad zu den db.properties, sql-String) erfoderlich"); - System.exit(1); - } - query=args[2].trim(); - - if (args.length > 3) { - outFormat = args[3].trim(); - } - - if (args.length > 4) { - delim = args[4].trim(); - } - if (args.length > 5) { - header = args[5].trim(); - - } - if (args.length > 6) { - outfile = args[6].trim(); - - } - if (delim.equals("")) - delim = "^"; //default Delimiter - - - long jetzt = new java.util.Date().getTime() ; - getConnection(logger, dbpropfile); - QueryResultSerializer myQueryResultSerializer = null; - FileWriter fw; - StringWriter sw; - boolean printColname=(header.equalsIgnoreCase("true")?true:false); - if(!outfile.equals("")) - { - try { - fw = new FileWriter(outfile); - if(outFormat.equalsIgnoreCase("xml")) - fw.write(""); - myQueryResultSerializer=new QueryResultSerializer("default", myConnection, query,fw); - - } catch (IOException e) { - logger.severe ("Fehler beim Erstellen der Datei "+outfile); - returnCode=1; - } - - } - else - { - sw=new StringWriter(); - if(outFormat.equalsIgnoreCase("xml")) - sw.write(""); - myQueryResultSerializer=new QueryResultSerializer("default", myConnection, query,sw); - } - - numberOfRows=myQueryResultSerializer.unloadQueryResults("DOQUERY",outFormat,delim,printColname); - returnCode=myQueryResultSerializer.getReturnCode(); - if(outfile.equals("")) - { - sw=myQueryResultSerializer.getOutputString(); - System.out.println(sw.toString()); - } - long erstrecht = new java.util.Date().getTime() ; - System.out.println( numberOfRows+" rows unloaded in "+(erstrecht-jetzt)/1000 +" Sec."); - System.out.println( "returnCode= "+returnCode); - myQueryResultSerializer = null; - return returnCode; - - - } - - /* - * Display some instructions on how to run the example - */ - public static void instructions() { - System.out.println("SuperX @version@\n"); - System.out.println( - "\nDieses Java-Programm führt einen SQL-Ausdruck aus und gibt das Ergebnis aus.\n"); - System.out.println( - "Gebrauch:\n java doquery (optional) (optional) (optional)\n"); - System.exit(1); - } - - public static void main(String args[]) { - int returnCode=0; - try { - returnCode=go(args); - - } catch (Exception ex) { - System.err.println("Doquery Aufruf fehlgeschlagen.\n" + ex); - ex.printStackTrace(); - System.exit(1); - } - System.out.println("Doquery Aufruf ausgeführt.\n" ); - System.exit(returnCode); - } - public static void getConnection(Logger logger,String propFile) throws SQLException { - myConnection = new SxConnection(); - myConnection.setPropfile(propFile); - logger.config("Starting Connection..."); - try { - myDb = myConnection.getConnection(); - st = myDb.createStatement(); - //st = myDb.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY, - // java.sql.ResultSet.CONCUR_READ_ONLY); - //st.setFetchSize(100); - dbmd = myDb.getMetaData(); - //st = myDb.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, - //ResultSet.CONCUR_UPDATABLE); - } catch (Exception e) { - e.printStackTrace(); - logger.severe("Keine DB-Verbindung: " + e.toString()); - throw new SQLException("Keine DB-Verbindung: " + e.toString()); - } - db_driver = myConnection.m_DriverClass; - - } - - -} diff --git a/src/de/superx/elt/bin/Dosql.java b/src/de/superx/elt/bin/Dosql.java deleted file mode 100644 index 51720a1..0000000 --- a/src/de/superx/elt/bin/Dosql.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * de.superx.etl - a package for controlling ETL routines - * Copyright (C) 2021 Daniel Quathamer - * - * This package is licensed under the CampusSource License; - * http://www.campussource.de/org/license/ - */ -package de.superx.elt.bin; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.Properties; -import java.util.StringTokenizer; -import java.util.logging.LogManager; -import java.util.logging.Logger; - -import de.memtext.util.ExceptionHandler; -import de.memtext.util.PropUtils; -import de.superx.bin.SxConnection; -import de.superx.elt.EtlUtils; -import de.superx.elt.SqlExecutor; -import de.superx.elt.util.GetOpts; - -/** - * @author Daniel Quathamer Projektgruppe SuperX - * Dosql.java - * @ - * Dieses Javaprogramm führt einen oder mehrere SQL-Ausdrück in einer Datei aus und gibt das Ergebnis aus.
- * Gebrauch:
java dosql (optional) (optional) (optional) - * - */ - -/* Änderungen - -15.4.2004 MB wenn keine Ausgabedatei und Ausgabeformat txt, alle selects von SxJdbcClient - loggen lassen -6.4.2004 MB Code static main verlegt - nach erfolgreicher Durchführung ein system.out - -**/ -public class Dosql { - private static Connection myDb; - private static DatabaseMetaData dbmd; - - private static Statement st; // Our statement to run queries with - private static boolean done = false; // Added by CWJ to permit \q command - private static String delim = "^"; - private static String header = "false"; - private static String logfile = "../conf/logging.properties"; - private static String tabelle = ""; - private static String dbpropfile = "../conf/db.properties"; - private static String outfile = ""; - private static String outFormat = "txt"; - private static String _dateiPfad = ""; - //LogUtils logger=null; - private static Logger logger = - (Logger) Logger.getLogger(Dosql.class.toString()); - //static Logger logger = Logger.getLogger(dosql.class); - private static ExceptionHandler exceptionHandler = - new ExceptionHandler(false); - private static SxConnection myConnection = null; - private static String usage = - "-------------------------------------\n" - + "Gebrauch: java de.superx.bin.Dosql -logger=<> -dbproperties=<> " - + "-sqlfile: -params: -outFormat:(optional) -delim: -header:(optional) -outfile:(optional) \n---------------------------------------------------"; - - /* - * Display some instructions on how to run the example - */ - public static void instructions() { - System.out.println("SuperX @version@\n"); - System.out.println( - "\nDieses Javaprogramm führt ein beliebiges sql-Script mit einer oder mehr sql-Anweisungen aus"); - System.out.println( - "Im Classpath muss superx@version@.jar sowie der zugehörige jdbc-Treiber sein."); - System.out.println( - "Befehl:\n java dosql (optional) true"); - System.exit(1); - } - - public static void main(String args[]) { - try { - execute(args); - } catch (Exception e) { - logger.severe( - "Fehler beim sql-Script: " + _dateiPfad + " " + e.toString()); - e.printStackTrace(); - System.exit(1); - } - - } - - public static void execute(String[] args) - throws Exception { - - String params = ""; - GetOpts.setOpts(args); - String isdrin = - GetOpts.isAllRequiredOptionsPresent( - "-logger,-dbproperties,-sqlfile"); - if (isdrin != null) { - System.err.println("Folgende Optionen fehlen: " + isdrin); - System.err.println(usage); - System.exit(1); - } - - //GetOpts myOpts=new GetOpts(); - if (GetOpts.isPresent("-logger")) - logfile = GetOpts.getValue("-logger"); - if (GetOpts.isPresent("-dbproperties")) - dbpropfile = GetOpts.getValue("-dbproperties"); - if (GetOpts.isPresent("-sqlfile")) - _dateiPfad = GetOpts.getValue("-sqlfile"); - if (GetOpts.isPresent("-outFormat")) - outFormat = GetOpts.getValue("-outFormat"); - if (GetOpts.isPresent("-delim")) - delim = GetOpts.getValue("-delim"); - if (GetOpts.isPresent("-header")) - header = GetOpts.getValue("-header"); - if (GetOpts.isPresent("-outfile")) - outfile = GetOpts.getValue("-outfile"); - if (GetOpts.isPresent("-params")) - params = GetOpts.getValue("-params"); - - if (delim.equals("")) - delim = "^"; //default Delimiter - - int returnCode=0; - File f = new File(logfile); - if (!f.exists()) { - throw new IOException("Datei nicht gefunden: " + logfile); - } - FileInputStream ins = new FileInputStream(logfile); - LogManager MyLogManager = java.util.logging.LogManager.getLogManager(); - MyLogManager.readConfiguration(ins); - logfile = MyLogManager.getProperty(".level"); - logger.info("Using Loggging-Level " + logfile); - File sqlScriptFile = new File(_dateiPfad); - getConnection(logger, dbpropfile); - Properties paramProperties=null; - if(!params.equals("")) - { - params=de.memtext.util.StringUtils.replace(params, "|", System.getProperty("line.separator")); - paramProperties=EtlUtils.convertStringToProperty(params); - } - SqlExecutor mySqlExecutor=new SqlExecutor("default", myConnection,sqlScriptFile,paramProperties); - if(!outfile.equals("")) - mySqlExecutor.setOutfile(outfile); - returnCode=mySqlExecutor.executeQueries(); - String output=mySqlExecutor.getOutString().toString(); - - myConnection.close(); - - System.out.println( - "Dosql hat das Script " + _dateiPfad + " erfolgreich durchgeführt"); - System.out.println(output); - logger.info("dosql erfolgreich beendet"); - - } - public static void getConnection(Logger logger,String propFile) throws SQLException { - myConnection = new SxConnection(); - myConnection.setPropfile(propFile); - logger.config("Starting Connection..."); - try { - myDb = myConnection.getConnection(); - st = myDb.createStatement(); - //st = myDb.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY, - // java.sql.ResultSet.CONCUR_READ_ONLY); - //st.setFetchSize(100); - dbmd = myDb.getMetaData(); - //st = myDb.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, - //ResultSet.CONCUR_UPDATABLE); - } catch (Exception e) { - e.printStackTrace(); - logger.severe("Keine DB-Verbindung: " + e.toString()); - throw new SQLException("Keine DB-Verbindung: " + e.toString()); - } - - - } -} - diff --git a/src/de/superx/elt/bin/EtlJobExecutor.java b/src/de/superx/elt/bin/EtlJobExecutor.java deleted file mode 100644 index 796d4a8..0000000 --- a/src/de/superx/elt/bin/EtlJobExecutor.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * de.superx.etl - a package for controlling ETL routines - * Copyright (C) 2021 Daniel Quathamer - * - * This package is licensed under the CampusSource License; - * http://www.campussource.de/org/license/ - */ -package de.superx.elt.bin; - -import java.sql.Connection; - -import de.superx.elt.EtlActionJob; -import de.superx.elt.EtlUtils; -import de.superx.elt.util.GetOpts; - -public class EtlJobExecutor { - - public EtlJobExecutor() { - // TODO Auto-generated constructor stub - } - - public static void main(String[] args) { - String usage="usage: java de.superx.elt.bin.EtlJobExecutor -dbproperties:$DB_PROPERTIES -job:abc -params:TID=16000 (optional) -outfile:Ausgabedatei (optional)" ; - GetOpts.setOpts(args); - - String isdrin = GetOpts.isAllRequiredOptionsPresent("-dbproperties,-job"); - if (isdrin != null) { - - System.err.println(usage); - System.exit(1); - } - int returnCode=0; - String dbpropfile = GetOpts.getValue("-dbproperties"); - String job = GetOpts.getValue("-job"); - String params =null; - if (GetOpts.isPresent("-params")) - params=GetOpts.getValue("-params"); - if(!(params==null)) - params=de.memtext.util.StringUtils.replace(params, ",", EtlUtils.NEWLINE); - String outfile=null; - if (GetOpts.isPresent("-outfile")) - outfile=GetOpts.getValue("-outfile"); - //System.out.println("param:"+params); - - EtlActionJob myJob=new EtlActionJob(job,"",dbpropfile); //TODO:Mandantid - try { - myJob.initJob(job,params); - } catch (Exception e) { - // TODO Auto-generated catch block - - e.printStackTrace(); - System.err.println(myJob.getLogoutput()); - System.exit(1); - } - System.out.println("Job "+ job+" initialized"); - try { - returnCode= myJob.execute(outfile); - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - System.err.println(myJob.getLogoutput()); - System.exit(1); - } - System.out.println("Job "+ job+" executed in " +myJob.getDuration()+" Sec."); - - System.exit(returnCode); - - } - -} diff --git a/src/de/superx/elt/bin/SxTransformer.java b/src/de/superx/elt/bin/SxTransformer.java deleted file mode 100644 index 54cacd1..0000000 --- a/src/de/superx/elt/bin/SxTransformer.java +++ /dev/null @@ -1,796 +0,0 @@ -/* - * de.superx.etl - a package for controlling ETL routines - * Copyright (C) 2021 Daniel Quathamer - * - * This package is licensed under the CampusSource License; - * http://www.campussource.de/org/license/ - */ -package de.superx.elt.bin; - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PrintStream; -import java.io.PrintWriter; -import java.io.StringReader; -import java.io.Writer; -import java.net.URI; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.SQLException; -import java.sql.Types; -import java.util.StringTokenizer; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.xml.transform.Result; -import javax.xml.transform.Source; -import javax.xml.transform.TransformerException; -import javax.xml.transform.URIResolver; -import javax.xml.transform.sax.SAXResult; -import javax.xml.transform.stream.StreamResult; -import javax.xml.transform.stream.StreamSource; - -import org.xml.sax.InputSource; - -import de.superx.bin.SxDBUtils; -import de.superx.util.SqlStringUtils; - -// ACHTUNG - PDF ERZEUGUNG WIEDER AKTIV DQ 27.12.2005!!! - -/** - * @author Daniel Quathamer Projektgruppe SuperX SxTransformer.java @ Dieses - * Javaprogramm transformiert ResultSets in text, html oder xml und gibt - * das Ergebnis als Ausgabestrom für stdout oder eine Datei aus. - * - * - * - */ -public class SxTransformer { - - /** - * - */ - private String head_delim1 = ""; - - private String head_delim2 = "\t"; - - private String header_delim1 = ""; - - private String header_delim2 = "\n"; - - private String fld_delim1 = ""; - - private String fld_delim2 = "\t"; - - private String row_delim1 = ""; - - private String row_delim2 = "\n";//we only user unix newline, even under - // DOS - - private String rs_delim1 = ""; - - private String rs_delim2 = ""; - - private String delim = "\t"; - - private String header = "false"; - - private String outHeader = ""; - - private String outFooter = ""; - - public String format = "txt"; - - public String params = ""; - - public String[] XslPipeline; - - public String stylesheet = ""; - - public PrintWriter myOutwriter; - - public OutputStream myOutputStream; - - public ResultSet outrs = null; - - public ResultSetMetaData outrsmd = null; - - public String quellstring = null; - - public String outfile = ""; - private File fopxconfFile=null; - public void setFopxconfFile(File fopxconfFile) { - this.fopxconfFile = fopxconfFile; - } - - Logger myLogger; - - String loglevel; - - //PrintStream outputstream=null; - - //TODO ggfs. auf Saxon umstellen - //TransletUtils.initFactory("net.sf.saxon.TransformerFactoryImpl", - // "org.apache.xalan.xsltc.trax.TransformerFactoryImpl"); - //System.out.println("Using xsl processor: " - // + TransletUtils.getUsedProcessor()); - public SxTransformer(Logger logger, PrintStream myStream) { - super(); - myLogger = logger; - myLogger.config("Starting the Transformer with Stdout-Output."); - myOutwriter = new PrintWriter(myStream); - } - - public SxTransformer(Logger logger, String myFile) { - super(); - myLogger = logger; - myLogger.config("Starting the Transformer with File-Output."); - outfile = myFile; - myLogger.setLevel(Level.SEVERE); - - } - - public SxTransformer(Logger logger, FileWriter myFilewriter) { - super(); - myLogger = logger; - myLogger.config("Starting the Transformer with File-Output."); - myOutwriter = new PrintWriter(new BufferedWriter(myFilewriter)); - } - - public SxTransformer(Logger logger, PrintWriter myWriter) { - super(); - myLogger = logger; - myLogger.config("Starting the Transformer with StringWriter-Output."); - myOutwriter = myWriter; - } - public SxTransformer(Logger logger) { - super(); - myLogger = logger; - myLogger.config("Starting the Transformer without Stream"); - } - - public void printResult(String outFormat) { - //loglevel=myLogger.getRootLogger().getLevel().toString().trim(); - assignDelims(outFormat); - myLogger.config("Resultset wird formatiert"); - String f_wert = ""; - //ResultSetMetaData rsmd = rs.getMetaData(); - - String zs = ""; - String headZs = ""; - int cols = 0; - Object o = null; - String[] lbl = null; - int[] types = new int[1255]; - // de.memtext.util.MemoryUtils.printfree(); - if (outrs != null) { - - try { - cols = outrsmd.getColumnCount(); - lbl = new String[1255]; - zs = outHeader + rs_delim1; - headZs = header_delim1; - ; - // Print the result column names? - for (int i = 1; i <= cols; i++) { - lbl[i] = outrsmd.getColumnLabel(i); - types[i] = outrsmd.getColumnType(i); - if (outFormat.equals("xml")) { - fld_delim1 = ""; - fld_delim2 = ""; - } else { - - if (i < cols) - headZs += (head_delim1 + lbl[i] + head_delim2); - else { - headZs += (head_delim1 + lbl[i] + head_delim2); - headZs += (header_delim2); - //out.newLine(); - } - } - } - } catch (SQLException e1) { - myLogger.severe("Fehler beim Einlesen der Feldnamen: " + e1.toString()); - e1.printStackTrace(); - } - if (header.equals("true")) zs += headZs; - - // try { - myOutwriter.write(zs); - myOutwriter.flush(); - /* - * } catch (IOException e) { myLogger.severe("Fehler beim Ausgeben - * der Feldnamen: " + e.toString()); - * } - */ - - //now the results - StringBuffer line = new StringBuffer(); - try { - int rowCounter = 0; - - do { - - line.setLength(0); - - line.append(row_delim1); - for (int i = 1; i <= cols; i++) { - if (outFormat.equals("xml")) { - fld_delim1 = ""; - fld_delim2 = ""; - } - if (types[i] == Types.LONGVARCHAR) { - //Der Informix-Treiber verlangt hier getString - // statt getObject! - o = outrs.getString(i); - } else { - o = outrs.getObject(i); - } - if (outrs.wasNull()) - if (i < cols) - line.append(fld_delim1 + "" + fld_delim2); - else { - line.append(fld_delim1 + "" + fld_delim2); - line.append(row_delim2); - //out.newLine(); - } - else { - //vergl. de.superx.common.Maske.getCSV - f_wert = SxDBUtils.field_value(o); - if (outFormat.equals("xml") && (f_wert.indexOf("&") > -1 || f_wert.indexOf("<") > -1 || f_wert.indexOf(">") > -1)) - f_wert = ""; - //wenn der Feldwert zufällig das Trennzeichen enthält, wird es mit "\" maskiert - if (outFormat.equals("txt")) { - f_wert = SxDBUtils.prepareInformixCsv(f_wert); - if (f_wert != null && (f_wert.indexOf(fld_delim2) > -1)) f_wert = de.memtext.util.StringUtils.replace(f_wert, fld_delim2, "\\" + fld_delim2); - } - if (i < cols) - line.append(fld_delim1 + f_wert + fld_delim2); - else { - line.append(fld_delim1 + f_wert + fld_delim2); - line.append(row_delim2); - } - } - } - myOutwriter.write(line.toString()); - rowCounter++; - if (rowCounter > 10000) { - de.memtext.util.MemoryUtils.printfree(); - myOutwriter.flush(); - - rowCounter = 0; - } - } while (outrs.next()); //von while - - myOutwriter.write(rs_delim2 + outFooter); - - myOutwriter.flush(); - outrs.close(); - myOutwriter.close(); - - } /* - * catch (IOException e) { myLogger.severe("Fehler beim Ausgeben - * der Feldwerte: " + e.toString()); } - */ - catch (SQLException e) { - myLogger.warning("SQL-Fehler beim Ausgeben der Feldwerte: " + e.toString()); - try { - myOutwriter.write(rs_delim2 + outFooter); - myOutwriter.flush(); - myOutwriter.close(); - outrs.close(); - } - /* - * catch (IOException e1) { myLogger.severe("Fehler beim - * Ausgeben der Feldwerte: " + e1.toString()); } - */ - catch (SQLException e1) { - myLogger.warning("SQL-Fehler beim Ausgeben der Feldwerte: " + e1.toString()); - } - } - - } - - else //wenn outrs=null - { - - myOutwriter.flush(); - myOutwriter.close(); - - } - myLogger.info("resultset printed"); - - } - - public void transformString(String methode) throws TransformerException { - try { - - javax.xml.transform.TransformerFactory tFactory = javax.xml.transform.TransformerFactory.newInstance(); - - javax.xml.transform.Transformer transformer = tFactory.newTransformer(new javax.xml.transform.stream.StreamSource(stylesheet)); - StringReader s1 = new StringReader(quellstring); - transformer.setOutputProperty(javax.xml.transform.OutputKeys.ENCODING, SqlStringUtils.getEncoding()); - transformer.setOutputProperty(javax.xml.transform.OutputKeys.METHOD, methode); - transformer.setParameter("sx_client", format); - String result = null; - if (!params.endsWith(",")) params += ","; - StringTokenizer st = new StringTokenizer(params, ","); - for (; st.hasMoreTokens();) { - String param = st.nextToken(); - if (!param.equals("")) { - String paramname = param.substring(0, param.indexOf("=")); - String paramvalue = param.substring(param.indexOf("=") + 1, param.length()); - transformer.setParameter(paramname, paramvalue); - } - } - transformer.transform(new javax.xml.transform.stream.StreamSource(s1), new javax.xml.transform.stream.StreamResult(myOutwriter)); - } catch (Exception e) { - myLogger.severe("XSL-Transformation fehlgeschlagen: " + e.toString()); - - } - - } - - public void transformFile(String methode) throws TransformerException, Exception - { - - javax.xml.transform.TransformerFactory tFactory = javax.xml.transform.TransformerFactory.newInstance("net.sf.saxon.TransformerFactoryImpl", null); - - javax.xml.transform.Transformer transformer = tFactory.newTransformer(new javax.xml.transform.stream.StreamSource(this.stylesheet)); - //StringReader s1 = new StringReader(quellstring); - transformer.setOutputProperty(javax.xml.transform.OutputKeys.ENCODING, SqlStringUtils.getEncoding()); - if (methode.equals("pdf") || methode.equals("rtf")) - transformer.setOutputProperty(javax.xml.transform.OutputKeys.METHOD, "xml"); - else - transformer.setOutputProperty(javax.xml.transform.OutputKeys.METHOD, methode); - - transformer.setParameter("sx_client", format); - transformer.setParameter("versionParam", "2.0"); - - // String result = null; - if (!params.endsWith(",")) params += ","; - StringTokenizer st = new StringTokenizer(params, ","); - for (; st.hasMoreTokens();) { - String param = st.nextToken(); - if (!param.equals("")) { - String paramname = param.substring(0, param.indexOf("=")); - String paramvalue = param.substring(param.indexOf("=") + 1, param.length()); - transformer.setParameter(paramname, paramvalue); - } - } - - - - - } - - public void outputString() { - BufferedWriter out = new BufferedWriter(myOutwriter); - try { - out.write(quellstring); - out.flush(); - } catch (IOException e) { - myLogger.severe("Fehler beim Ausgeben des Ergebnisses: " + e.toString()); - } - - } - - public String getResult(String outFormat) throws SQLException { - - //loglevel=myLogger.getRootLogger().getLevel().toString().trim(); - assignDelims(outFormat); - myLogger.config("Resultset wird formatiert"); - String f_wert = ""; - //ResultSetMetaData rsmd = rs.getMetaData(); - int cols = outrsmd.getColumnCount(); - String[] lbl = new String[255]; - String zs = rs_delim1; - String headZs = header_delim1; - ; - // Print the result column names? - for (int i = 1; i <= cols; i++) { - lbl[i] = outrsmd.getColumnLabel(i); - if (outFormat.equals("xml")) { - fld_delim1 = ""; - fld_delim2 = ""; - } else { - - if (i < cols) - headZs += (head_delim1 + lbl[i] + head_delim2); - else { - headZs += (head_delim1 + lbl[i] + head_delim2); - headZs += (header_delim2); - //out.newLine(); - } - } - } - if (header.equals("true")) zs += headZs; - - //now the results - try { - while (outrs.next()) - - { - zs += (row_delim1); - for (int i = 1; i <= cols; i++) { - Object o = outrs.getObject(i); - f_wert = SxDBUtils.field_value(o); - if (outFormat.equals("xml")) { - fld_delim1 = ""; - fld_delim2 = "\n"; - } - if (outrs.wasNull()) - if (i < cols) - zs += (fld_delim1 + "" + fld_delim2); - else { - zs += (fld_delim1 + "" + fld_delim2); - zs += (row_delim2); - //out.newLine(); - } - else if (i < cols) - zs += (fld_delim1 + f_wert.trim() + fld_delim2); - else { - zs += (fld_delim1 + f_wert.trim() + fld_delim2); - zs += (row_delim2); - - // out.newLine(); - } - - // } - // catch (IOException e) - // { - // myLogger.severe("Fehler beim Ausgeben der Feldwerte: - // "+e.toString()); - // - // } - - } - } //von while - zs += (rs_delim2); - - } catch (Exception e) { - myLogger.severe("Fehler beim Ausgeben der Feldwerte: " + e.toString()); - } - outrs.close(); - - return zs; - } - - private void assignDelims(String outFormat) { - if (outFormat.equals("html")) { - outHeader = ""; - outFooter = ""; - rs_delim1 = "
\n"; - rs_delim2 = "
"; - head_delim1 = ""; - head_delim2 = ""; - header_delim1 = ""; - header_delim2 = "\n"; - row_delim1 = ""; - row_delim2 = ""; - fld_delim1 = ""; - fld_delim2 = ""; - } - if (outFormat.equals("xml")) { - outHeader = ""; - outFooter = ""; - rs_delim1 = "\n"; - rs_delim2 = ""; - head_delim1 = ""; - head_delim2 = ""; - header_delim1 = ""; - header_delim2 = ""; - row_delim1 = "\n"; - row_delim2 = "\n"; - fld_delim1 = ""; - fld_delim2 = ""; - } - } - - /** - * @return - */ - public String getDelim() { - return delim; - } - - /** - * @return - */ - public String getFld_delim1() { - return fld_delim1; - } - - /** - * @return - */ - public String getFld_delim2() { - return fld_delim2; - } - - /** - * @return - */ - public String getFormat() { - return format; - } - - /** - * @return - */ - public String getHead_delim1() { - return head_delim1; - } - - /** - * @return - */ - public String getHead_delim2() { - return head_delim2; - } - - /** - * @return - */ - public String getHeader() { - return header; - } - - /** - * @return - */ - public String getHeader_delim1() { - return header_delim1; - } - - /** - * @return - */ - public String getHeader_delim2() { - return header_delim2; - } - - /** - * @return - */ - public ResultSet getOutrs() { - return outrs; - } - - /** - * @return - */ - public ResultSetMetaData getOutrsmd() { - return outrsmd; - } - - /** - * @return - */ - public String getRow_delim1() { - return row_delim1; - } - - /** - * @return - */ - public String getRow_delim2() { - return row_delim2; - } - - /** - * @return - */ - public String getRs_delim1() { - return rs_delim1; - } - - /** - * @return - */ - public String getRs_delim2() { - return rs_delim2; - } - - /** - * @return - */ - public String[] getXslPipeline() { - return XslPipeline; - } - - /** - * @param string - */ - public void setDelim(String string) { - delim = string; - fld_delim1 = ""; - fld_delim2 = string; - head_delim2 = string; - } - - /** - * @param string - */ - public void setFld_delim1(String string) { - fld_delim1 = string; - } - - /** - * @param string - */ - public void setFld_delim2(String string) { - fld_delim2 = string; - } - - /** - * @param string - */ - public void setFormat(String string) { - format = string; - } - - /** - * @param string - */ - public void setHead_delim1(String string) { - head_delim1 = string; - } - - /** - * @param string - */ - public void setHead_delim2(String string) { - head_delim2 = string; - } - - /** - * @param string - */ - public void setHeader(String string) { - header = string; - } - - /** - * @param string - */ - public void setHeader_delim1(String string) { - header_delim1 = string; - } - - /** - * @param string - */ - public void setHeader_delim2(String string) { - header_delim2 = string; - } - - /** - * @param set - */ - - public void setOutrs(ResultSet set) { - outrs = set; - } - - /** - * @param data - */ - public void setOutrsmd(ResultSetMetaData data) { - outrsmd = data; - } - - /** - * @param string - */ - public void setRow_delim1(String string) { - row_delim1 = string; - } - - /** - * @param string - */ - public void setRow_delim2(String string) { - row_delim2 = string; - } - - /** - * @param string - */ - public void setRs_delim1(String string) { - rs_delim1 = string; - } - - /** - * @param string - */ - public void setRs_delim2(String string) { - rs_delim2 = string; - } - - /** - * @param strings - */ - public void setXslPipeline(String[] strings) { - XslPipeline = strings; - } - - /** - * @return - */ - public String getOutFooter() { - return outFooter; - } - - /** - * @return - */ - public String getOutHeader() { - return outHeader; - } - - /** - * @param string - */ - public void setOutFooter(String string) { - outFooter = string; - } - - /** - * @param string - */ - public void setOutHeader(String string) { - outHeader = string; - } - - /** - * @return - */ - public String getParams() { - return params; - } - - /** - * @param string - */ - public void setParams(String string) { - params = string; - } - - //-- nur zum Testen --// - public static void main(String[] args) throws Exception { - Logger log = Logger.getLogger(SxTransformer.class.getName()); - String rootDir = "/home/superx/tmp/"; - String quelle = rootDir + "Buchungsbericht_ids_Test.xml"; - String zielFile = rootDir + "testneu.pdf"; - String sxlSheet = "/home/superx/dev/edustore/webserver/tomcat/webapps/superx/xml/tabelle_fo_pdf.xsl"; - - SxTransformer sxTrans = new SxTransformer(log, zielFile); - - sxTrans.quellstring = quelle; - sxTrans.outfile = zielFile; - sxTrans.stylesheet = sxlSheet; - sxTrans.transformFile("pdf"); - - - }//Ende der Methode - - public class ClasspathUriResolver implements URIResolver { - - public Source resolve(String href, String base) throws TransformerException { - Source source = null; - InputStream inputStream = ClassLoader.getSystemResourceAsStream(href); - if (inputStream != null) { - source = new StreamSource(inputStream); - } - return source; - } - } -}//Ende der Klasse - - diff --git a/src/de/superx/elt/bin/UnloadRecords.java b/src/de/superx/elt/bin/UnloadRecords.java deleted file mode 100644 index fe03097..0000000 --- a/src/de/superx/elt/bin/UnloadRecords.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * de.superx.etl - a package for controlling ETL routines - * Copyright (C) 2021 Daniel Quathamer - * - * This package is licensed under the CampusSource License; - * http://www.campussource.de/org/license/ - */ -package de.superx.elt.bin; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileWriter; -import java.io.IOException; -import java.io.StringWriter; -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.logging.LogManager; -import java.util.logging.Logger; -import java.util.StringTokenizer; -import de.superx.util.SqlStringUtils; -import de.superx.bin.SxConnection; -import de.superx.common.SuperX_el; -import de.superx.elt.QueryResultSerializer; -import de.superx.servlet.SxPools; -import de.superx.servlet.SxSQL_Server; - -/** - * @author Daniel Quathamer Projektgruppe SuperX - * doquery.java - * @ - * Dieses Javaprogramm führt einen SQL-Ausdruck aus und gibt das Ergebnis aus.
- * Gebrauch:
java doquery (optional) (optional) (optional) - * - - */ -//Änderungen -/* - * 16.4.04 Wenn kein outfile angegeben, werden alle select results auf die Console geloggt - * 19.1.2006 dq: Unload großer Tabellen unter Postgres ermöglicht. - */ -public class UnloadRecords { - private static Connection myDb; - private static Statement st; // Our statement to run queries with - private static DatabaseMetaData dbmd; - // This defines the structure of the database - private static boolean done = false; // Added by CWJ to permit \q command - private static String delim = "^"; - private static String header = "false"; - private static String outFormat = "txt"; - private static String logfile = "../conf/logging.properties"; - private static String tabelle = ""; - private static String dbpropfile = "../conf/db.properties"; - private static SxConnection myConnection = null; - private static String db_driver; - private static String mandantenID="default"; - private static String outfile = ""; - private static Logger logger = - (Logger) Logger.getLogger(Doquery.class.toString()); - private static String usage = - "-------------------------------------\nGebrauch: java de.superx.bin.UnloadRecords $LOGGER_PROPERTIES $DB_PROPERTIES $sql (optional: )$outformat $DBDELIMITER $header $filename \n---------------------------------------------------"; - - public static int go(String args[]) - throws - Exception { - if (args.length > 0) { - logfile = args[0].trim(); - } else { - throw new IllegalArgumentException("Mindestens drei Parameter (Pfad zu den logger.properties, Pfad zu den db.properties, sql-String) erfoderlich"); - - } - File f = new File(logfile); - if (!f.exists()) { - throw new IOException("Datei nicht gefunden: " + logfile); - } - - FileInputStream ins = new FileInputStream(logfile); - LogManager MyLogManager = java.util.logging.LogManager.getLogManager(); - MyLogManager.readConfiguration(ins); - logfile = MyLogManager.getProperty(".level"); - logger.info("Using Loggging-Level " + logfile); - String query = ""; - long numberOfRows=0; - int returnCode=0; - - if (args.length > 1) { - dbpropfile = args[1].trim(); - } else { - logger.severe( - "Mindestens drei Parameter (Pfad zu den logger.properties, Pfad zu den db.properties, sql-String) erfoderlich"); - System.exit(1); - } - if (args.length <= 2) { - logger.severe( - "Mindestens drei Parameter (Pfad zu den logger.properties, Pfad zu den db.properties, sql-String) erfoderlich"); - System.exit(1); - } - query=args[2].trim(); - - if (args.length > 3) { - outFormat = args[3].trim(); - } - - if (args.length > 4) { - delim = args[4].trim(); - } - if (args.length > 5) { - header = args[5].trim(); - - } - if (args.length > 6) { - outfile = args[6].trim(); - - } - if (delim.equals("")) - delim = "^"; //default Delimiter - - boolean printColname=(header.equalsIgnoreCase("true")?true:false); - FileWriter fw; - StringWriter sw; - long jetzt = new java.util.Date().getTime() ; - getConnection(logger, dbpropfile); - QueryResultSerializer myQueryResultSerializer = null; - if(!outfile.equals("")) - { - try { - fw = new FileWriter(outfile); - if(outFormat.equalsIgnoreCase("xml")) - fw.write(""); - myQueryResultSerializer=new QueryResultSerializer("default", myConnection, query,fw); - - } catch (IOException e) { - logger.severe ("Fehler beim Erstellen der Datei "+outfile); - returnCode=1; - } - - } - else - { - sw=new StringWriter(); - if(outFormat.equalsIgnoreCase("xml")) - sw.write(""); - myQueryResultSerializer=new QueryResultSerializer("default", myConnection, query,sw); - } - - numberOfRows=myQueryResultSerializer.unloadQueryResults("DOQUERY",outFormat,delim,printColname); - returnCode=myQueryResultSerializer.getReturnCode(); - if(outfile.equals("")) - { - sw=myQueryResultSerializer.getOutputString(); - System.out.println(sw.toString()); - } - long erstrecht = new java.util.Date().getTime() ; - System.out.println( numberOfRows+" rows unloaded in "+(erstrecht-jetzt)/1000 +" Sec."); - System.out.println( "returnCode= "+returnCode); - myQueryResultSerializer = null; - return returnCode; - - - } - - /* - * Display some instructions on how to run the example - */ - public static void instructions() { - System.out.println("SuperX @version@\n"); - System.out.println( - "\nDieses Java-Programm führt einen SQL-Ausdruck aus und gibt das Ergebnis aus.\n"); - System.out.println( - "Gebrauch:\n java doquery (optional) (optional) (optional)\n"); - System.exit(1); - } - - public static void main(String args[]) { - int returnCode=0; - try { - returnCode=go(args); - - } catch (Exception ex) { - System.err.println("Doquery Aufruf fehlgeschlagen.\n" + ex); - ex.printStackTrace(); - System.exit(1); - } - System.out.println("Doquery Aufruf ausgeführt.\n" ); - System.exit(returnCode); - } - public static void getConnection(Logger logger,String propFile) throws SQLException { - myConnection = new SxConnection(); - myConnection.setPropfile(propFile); - logger.config("Starting Connection..."); - try { - myDb = myConnection.getConnection(); - st = myDb.createStatement(); - //st = myDb.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY, - // java.sql.ResultSet.CONCUR_READ_ONLY); - //st.setFetchSize(100); - dbmd = myDb.getMetaData(); - //st = myDb.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, - //ResultSet.CONCUR_UPDATABLE); - } catch (Exception e) { - e.printStackTrace(); - logger.severe("Keine DB-Verbindung: " + e.toString()); - throw new SQLException("Keine DB-Verbindung: " + e.toString()); - } - db_driver = myConnection.m_DriverClass; - - } - - -} diff --git a/src/de/superx/elt/bin/UploadRecords.java b/src/de/superx/elt/bin/UploadRecords.java deleted file mode 100644 index 61eb385..0000000 --- a/src/de/superx/elt/bin/UploadRecords.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * de.superx.etl - a package for controlling ETL routines - * Copyright (C) 2021 Daniel Quathamer - * - * This package is licensed under the CampusSource License; - * http://www.campussource.de/org/license/ - */ -package de.superx.elt.bin; -import de.superx.elt.TableUploader; -import de.superx.elt.util.GetOpts; - -/* - * @author Daniel Quathamer Projektgruppe SuperX - * upload_records.java -* Dieses Javaprogramm lädt Inhalte einer Datei in eine Tabelle hoch") -* DQ 5.1.2006 Upload vom XML-Dateien möglich - * - */ - -public class UploadRecords { - private static String usage = - "-------------------------------------\n" - + "Gebrauch: java de.superx.bin.UploadRecords \n-dbproperties: \n" - + "-table: \n-unl:(optional, default ist Tabellenname.unl) \n-delim:(optional, default ist ^) \n-header:(optional, mit Feldüberschriften, default ist false)\n" - + "-mode:(optional, default is stop) #Bei Fehlerhaften Daten kann das Hochladen gestoppt werden, oder der Datensatz wird übersprungen" - + "\n-inserts:(optional, default is false) #Bei -inserts:simple und batch werden Die Rohdaten in Insert-sql-Statements übersetzt (nur für Debugging-Zwecke, sehr langsam. Der Modus exclude-field ist darüberhinaus nicht anwendbar)" - + "\n-encoding:" - + "\n---------------------------------------------------"; - - public static void main(String args[]) { - try { - GetOpts.setOpts(args); - String isdrin = - GetOpts.isAllRequiredOptionsPresent("-dbproperties,-table,-unl"); - if (isdrin != null) { - System.err.println("Folgende Optionen fehlen: " + isdrin); - System.err.println(usage); - System.exit(1); - } - TableUploader myUploader=new TableUploader(); - //GetOpts myOpts=new GetOpts(); - if (GetOpts.isPresent("-dbproperties")) - myUploader.setDbpropfile(GetOpts.getValue("-dbproperties")); - if (GetOpts.isPresent("-informat")) - myUploader.setInFormat(GetOpts.getValue("-informat")); - if (GetOpts.isPresent("-table")) - myUploader.setTargetTable( GetOpts.getValue("-table")); - - if (GetOpts.isPresent("-unl")) - myUploader.setSrcFile(GetOpts.getValue("-unl")); - else - myUploader.setSrcFile(myUploader.getTargetTable() + ".unl"); - if (GetOpts.isPresent("-header")) - myUploader.setHeader(GetOpts.getValue("-header").equalsIgnoreCase("true")?true:false); - if (GetOpts.isPresent("-delim")) - myUploader.setDelim(GetOpts.getValue("-delim")); - if (GetOpts.isPresent("-encoding")) - { - String encodingParam=GetOpts.getValue("-encoding"); - - if(encodingParam != null && !encodingParam.equals("") ) - myUploader.setEncoding(encodingParam); - } - else - myUploader.setEncoding(System.getProperty("file.encoding")); - if (GetOpts.isPresent("-mode")) { - myUploader.setMode(GetOpts.getValue("-mode").toLowerCase()); - - } - if (GetOpts.isPresent("-inserts")) - myUploader.setInserts(GetOpts.getValue("-inserts")); - long jetzt = new java.util.Date().getTime() ; - long numberOfRows=0; - myUploader.setUploadConnection(myUploader.getConnection(null,myUploader.getDbpropfile())); - numberOfRows=myUploader.uploadFile(); - long erstrecht = new java.util.Date().getTime() ; - System.out.println(numberOfRows+" lines loaded"); - System.out.println("File "+myUploader.getSrcFile() +" uploaded, returnCode="+myUploader.getReturnCode()); - myUploader=null; - //if(protokoll.equals("")) - // protokoll= " in "+(erstrecht-jetzt)/1000 +" Sec."; - //System.out.println(protokoll); - -} catch (Exception ex) { - System.err.println("Upload fehlgeschlagen: " + ex); - System.exit(1); -} -} - } - - - - - diff --git a/src/de/superx/elt/util/FileUtils.java b/src/de/superx/elt/util/FileUtils.java deleted file mode 100644 index 69cbfe1..0000000 --- a/src/de/superx/elt/util/FileUtils.java +++ /dev/null @@ -1,98 +0,0 @@ -package de.superx.elt.util; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.StringWriter; -import java.io.UnsupportedEncodingException; - -public class FileUtils { - /* - * Liest eine Datei mit vorgegebenem Encoding ein in einen String. - * Wenn Datei nicht existiert, wird NULL zurückgegeben, - * Wenn sie leer ist, kommt Leerstring zurück - * @author Quathamer - * @param filePath - * @param encoding (Default ist utf-8) - */ - - public static String getFileContentsWithEncoding(String filePath, String encoding) { - File f = new File(filePath); - if (!f.exists()) { - System.out.println("Fehler: Datei " + filePath + " existiert nicht."); - return null; - } - String fileContents = ""; - if (encoding == null || encoding.trim().equals("")) { - encoding = System.getProperty("file.encoding"); - } - try { - // --- IputStream und OutputStream generieren ---// - FileInputStream fis = new FileInputStream(f); - // Wenn Quelldatei Unicode, dann speziellen Reader nutzen - BufferedReader in; - //BufferedReader ist schneller bei großen Dateien - in = new BufferedReader(new InputStreamReader(fis, encoding)); - // --- Output-Stream der temporären Datei erzeugen ---// - StringWriter out = new StringWriter(); - // --- Verarbeiten der Datei ---// - String text; - text = in.readLine(); - while (text != null) { // Datei nicht leer - out.write(text); - out.write(System.getProperty("line.separator")); - text = in.readLine(); - } - if (!(out == null)) { - fileContents = out.toString(); - } - } catch (FileNotFoundException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (UnsupportedEncodingException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return fileContents; - } - - public static void saveFileContentsWithEncoding(String filename, String contents, String encoding) throws - - FileNotFoundException, - IOException - { - - - File f = new File(filename); - BufferedReader in; - BufferedWriter out; - - //Default encoding ist utf-8 - if (encoding == null) encoding = System.getProperty("file.encoding"); - // --- Output-Stream der temporären Datei erzeugen ---// - out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f), encoding)); - - out.write(contents); - - out.close(); - - - }//Ende der Methode -public static String convertToIso(String inp, String dbsystem) throws java.io.UnsupportedEncodingException -{ - String outp = new String(inp.getBytes("ISO-8859-1")); - if (dbsystem.equalsIgnoreCase("postgres")) { - outp = outp.replaceAll("´", " "); - } - return outp; -} -} diff --git a/src/de/superx/elt/util/GetOpts.java b/src/de/superx/elt/util/GetOpts.java deleted file mode 100644 index 51bc0b4..0000000 --- a/src/de/superx/elt/util/GetOpts.java +++ /dev/null @@ -1,155 +0,0 @@ -package de.superx.elt.util; - - -import java.util.StringTokenizer; - -/** - * Original von de.memtext.util.GetOpts, - * für Abwärtskompatibilität mit Kern 4.9/BI 2021.06 - * - */ -public class GetOpts { - private static String[] arguments = null; - - //don't instantiate - private GetOpts() { - - } - - /** - * If you pass the arguments you want to analyse to this static helper class - * using setOpts, you can later use the short form of the methods e.g. - * isPresent(String option) without having to pass the arguments again. - * - * @param args - */ - public static void setOpts(String args[]) { - arguments = args; - } - - /** - * checks if the arguments passed before by setOpts contain the given option - * - * @param String - * option - * @return true if arguments contain the option, i.e. one String which - * starts with the option-String - */ - public static boolean isPresent(String option) { - if (arguments == null) - throw new IllegalStateException( - "must either use setOpts before or call the long version of this method"); - return isPresent(arguments, option); - } - - /** - * checks if the arguments contain the given option - * - * @param args - * @param String - * option - * @return true if arguments contain the option, i.e. one String which - * starts with the option-String - */ - public static boolean isPresent(String args[], String option) { - boolean result = false; - for (int i = 0; i < args.length; i++) - if (args[i] != null && args[i].startsWith(option)) - result = true; - return result; - } - - /** - * Gets a named option from the arguments passed before with setOps. E.g. - * getOpt("--log") would return the "--log:true" in the arguments - * - * @param option - - * name/start of the option - * @return String whole option - */ - public static String getOpt(String option) { - if (arguments == null) - throw new IllegalStateException( - "must either use setOpts before or call the long version of this method"); - return getOpt(option, arguments); - } - - /** - * Gets a named option from the arguments. E.g. getOpt("--log") would return - * the "--log:true" in the arguments - * - * @param option - - * name/start of the option - * @return String whole option - */ - public static String getOpt(String option, String args[]) { - if (args == null) - throw new IllegalStateException("args must not be null"); - String result = null; - for (int i = 0; i < args.length; i++) - if (args[i].startsWith(option)) - result = args[i]; - if (result == null) - throw new RuntimeException("Option " + option + " not found!"); - return result; - } - - /** - * Gets the value of an option from the arguments passed before with setOpts - * if for example, you ask getValue("--log:") and the arguments passed - * before with setOpts contain a String "--log:true") "true" is returned - * - * @param String - * option - * @return String value of the option - */ - public static String getValue(String option) { - if (arguments == null) - throw new IllegalStateException( - "must either use setOpts before or call the long version of this method"); - return getValue(option, arguments); - } - - /** - * Gets the value of an option, if for example, you ask getValue("--log:") - * and the arguments passed before with setOpts contain a String - * "--log:true") "true" is returned - * - * @param String - * option - * @return String value of the option - */ - public static String getValue(String option, String args[]) { - String result = ""; - String raw = getOpt(option, args); - int pos = option.length(); - if (raw.charAt(pos) == ':') - pos++; - result = raw.substring(pos, raw.length()); - return result; - } - - /** - * Prüft, ob alle notwendigen Optionen angegeben sind, z.B. String - * "-loggingProperties:,-dbProperties" übergeben, die beiden müssen dabei - * sein - * - * @param options - * z.B. "-loggingProperties:,-dbProperties,..." - * @return null - alles OK, ansonsten String mit den fehlenden Optionen - */ - public static String isAllRequiredOptionsPresent(String options) { - String result = null; - StringTokenizer st = new StringTokenizer(options, ","); - for (; st.hasMoreTokens();) { - String optionName = st.nextToken(); - if (!isPresent(optionName)) { - if (result == null) - result = optionName; - else - result += "," + optionName; - } - } - return result; - } -} diff --git a/src/de/superx/elt/util/GetOptsBackport.java b/src/de/superx/elt/util/GetOptsBackport.java deleted file mode 100644 index 4a68d15..0000000 --- a/src/de/superx/elt/util/GetOptsBackport.java +++ /dev/null @@ -1,220 +0,0 @@ -package de.superx.elt.util; - -/** - * Class to analyze arguments passed to Java class - * Makes ETL compatible to BI 2021.06 and higher - */ -public class GetOptsBackport{ - - public enum Options{ - opt_logger("-logger"), - opt_dbprops("-dbproperties"), - opt_table("-table"), - opt_outFormat("-outFormat"), - opt_outFile("-outfile"), - opt_outfileAttribute("-outfileattribute"), - opt_cancel("-cancel"), - opt_sql("-sqlfile"), - opt_sqlAttribute("-sqlattribute"), - opt_delim("-delim"), - opt_header("-header"), - opt_params("-params"), - opt_param("-param"), - opt_in("-in"), - opt_inFormat("-informat"), - opt_out("-out"), - opt_xsl("-xsl"), - opt_xslPfad("-xslpfad"), - opt_fopxconf("-fopxconf"), - opt_user("-user"), - opt_tid("-tid"), - opt_mandID("-mandantenid"), - opt_locale("-locale"), - opt_simpPars("-simpleParser"), - opt_webinf("-web_inf_pfad"), - opt_module("-module_pfad"), - opt_jobUniqueName("-job_uniquename"), - opt_uploadpath("-path_to_uploadfile"), - opt_method("-method"), - opt_xml("-xml"), - opt_xmlconfig("-xmlconfig"), - opt_db("-database"), - opt_version("-version"), - opt_unl("-unl"), - opt_unlParams("-unload_params"), - opt_jrxml("-jrxml"), - opt_jasper("-jasper"), - opt_jrPrint("-jrprint"), - opt_ignorePagination("-ignore_pagination"), - opt_idescr("-i_descr"), - opt_odescr("-o_descr"), - opt_element("-element"), - opt_function("-function"), - opt_mode("-mode"), - opt_inserts("-inserts"), - opt_encoding("-encoding"), - opt_hsnr("-hsnr"), - opt_noDelete("-nodelete"), - opt_pause("-pause"), - opt_jahr("-jahr"), - opt_datentyp("-datentyp"), - opt_runs("-runs"), - opt_checkval("-checkval"), - opt_url("-url"), - opt_setname("-setname"), - - opt_kernTabellenFreischalten("-kern_tabellen_freischalten"), - opt_noguiVar0("-nogui"), opt_noguiVar1("-no-gui"), opt_noguiVar2("--no-gui"), - opt_job("-job"); - - private String value; - private Options(String value) { - this.value = value; - } - - public String stringValue() { - return value; - } - } - - private static String[] arguments = null; - private GetOptsBackport(){} //Do not instatiate - - /** - * If you pass the arguments you want to analyse to this static helper class - * using setOpts, you can later use the short form of the methods e.g. - * isPresent(String option) without having to pass the arguments again. - * - * @param args - */ - public static void setOpts(String args[]) { - arguments = args; - } - - /** - * checks if the arguments passed before by setOpts contain the given option - * - * @param Options - * option - * @return true if arguments contain the option, i.e. one String which - * starts with the option-String - */ - public static boolean isPresent(Options option){ - if(arguments == null){ - throw new IllegalStateException("must either call setOpts() before or call the long version of this method"); - } - return isPresent(arguments, option); - } - - /** - * checks if the arguments contain the given option - * - * @param args - * @param Options - * option - * @return true if arguments contain the option, i.e. one String which - * starts with the option-String - */ - public static boolean isPresent(String args[], Options option){ - boolean result = false; - - for(int i = 0; i < args.length; i++){ - if (args[i] != null && args[i].toLowerCase().startsWith(option.stringValue())){ - result = true; - } - } - - return result; - } - - /** - * Gets a named option from the arguments passed before with setOps. E.g. - * getOpt("--log") would return the "--log:true" in the arguments - * - * @param Options - * option - * @return String option and value - */ - public static String getOpt(Options option){ - if (arguments == null){ - throw new IllegalStateException("must either call setOpts() before or call the long version of this method"); - } - return getOpt(arguments, option); - } - - /** - * Gets a named option from the arguments. E.g. getOpt("--log") would return - * the "--log:true" in the arguments - * - * @param Options - * option - * @return String option and value - */ - public static String getOpt(String args[], Options option){ - String result = null; - for(int i=0; i < args.length; i++){ - if(args[i].toLowerCase().startsWith(option.stringValue())){ - result = args[i]; - } - } - return result; - } - - /** - * Gets the value of an option from the arguments passed before with setOpts - * if for example, you ask getValue("--log:") and the arguments passed - * before with setOpts contain a String "--log:true") "true" is returned - * - * @param Options - * option - * @return String value of the option - */ - public static String getValue(Options option){ - if (arguments == null){ - throw new IllegalStateException("must either call setOpts() before or call the long version of this method"); - } - return getValue(arguments, option); - } - - /** - * Gets the value of an option, if for example, you ask getValue("--log:") - * and the arguments passed before with setOpts contain a String - * "--log:true") "true" is returned - * - * @param Options - * option - * @return String value of the option - */ - public static String getValue(String args[], Options option) { - String value = null, temp = getOpt(args, option); - int pos = option.stringValue().length(); - if(temp.charAt(pos) == ':') { - pos++; - } - value = temp.substring(pos); - return value; - } - - /** - * Prüft, ob alle notwendigen Optionen angegeben sind. - * - * @param Options[] - * opts, ein Array mit Optionen die überprüft werden sollen - * @return null - alles OK, ansonsten String mit den fehlenden Optionen - */ - public static String isAllRequiredOptionsPresent(Options[] opts){ - String missingOpts = null; - for (Options o : opts){ - if(!isPresent(o)){ - if(missingOpts == null){ - missingOpts = o.stringValue()+", "; - }else{ - missingOpts += o.stringValue()+", "; - } - } - } - return missingOpts; - } - - -} diff --git a/src/de/superx/rest/JobEtlXml.java b/src/de/superx/rest/JobEtlXml.java new file mode 100644 index 0000000..f24a418 --- /dev/null +++ b/src/de/superx/rest/JobEtlXml.java @@ -0,0 +1,134 @@ +/* + * de.superx.etl - a package for controlling ETL routines + * Copyright (C) 2021 Daniel Quathamer + * + * This package is licensed under the CampusSource License; + * http://www.campussource.de/org/license/ + */ +package de.superx.rest; +import jakarta.servlet.http.HttpServletRequest; + +import javax.ws.rs.core.Context; +import javax.xml.transform.TransformerConfigurationException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import de.memtext.util.DateUtils; +import de.superx.common.SxUser; +import de.superx.etl.EtlActionJob; +import de.superx.etl.EtlUtils; +import de.superx.servlet.SuperXManager; +import de.superx.util.SqlStringUtils; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.nio.charset.StandardCharsets; +import java.sql.SQLException; + + + +@RestController +@RequestMapping("/api/jobetlxml") + + +public class JobEtlXml { + private static Logger logger = LoggerFactory.getLogger(Cache.class); + HttpServletRequest request; + //TODO: mehrere params + @RequestMapping(path = "/view/{jobUniquename}", method = RequestMethod.GET, + produces=MediaType.APPLICATION_XML_VALUE + //produces={"text/xml"} + ) + public ResponseEntity printXml(@Context HttpServletRequest httpRequest, + @PathVariable("jobUniquename") String jobUniquename, + @RequestParam("jobParamName") String jobParamName, + @RequestParam(value = "param") String param + ) throws Exception{ + this.request=httpRequest; + + if(!SqlStringUtils.checkValidKeyEntry(jobUniquename)) + throw new Exception("Invalid job "+jobUniquename); + if(!SqlStringUtils.checkValidKeyEntry(jobParamName)) + throw new Exception("Invalid jobParamName "+jobParamName); + if(!SqlStringUtils.checkValidKeyEntry(param)) + throw new Exception("Invalid param "+param); + String returntext = getJobEtlXml(jobUniquename,jobParamName, param ); + + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(new MediaType("text", "xml", StandardCharsets.UTF_8)); + ResponseEntity myResponse=new ResponseEntity(returntext,httpHeaders,200); + return myResponse; + } + + private String getJobEtlXml(String jobUniquename, + String jobParamName, + String param + ) { + String returntext; + SxUser user = (SxUser) request.getSession().getAttribute("user"); + System.out.println("JOB"+jobUniquename + " mit param "+jobParamName); + String mandantenid= (String) request.getSession().getAttribute("MandantenID"); + if(mandantenid==null || mandantenid.equals("")) + mandantenid="default"; + + if (user == null || !user.isAdmin()) { + returntext="Fehlende Rechte"; + } + else + { + + int returnCode=0; + EtlActionJob myJob=new EtlActionJob(jobUniquename); //TODO:Mandantid + try { + myJob.initJob("etl",jobUniquename,jobParamName+"="+param); + } catch (Exception e) { + // TODO Auto-generated catch block + + returntext=e.toString(); + returntext+=myJob.getLogoutput(); + + } + System.out.println("Job "+ jobUniquename+" initialized"); + try { + returnCode= myJob.execute(""); + returntext=myJob.getSw().toString(); + + } catch (Exception e) { + // TODO Auto-generated catch block + returntext=e.toString(); + returntext+=myJob.getLogoutput(); + } + } + return returntext; + } + + + + + +} diff --git a/src/de/superx/sxrest/JobEtlXml.java b/src/de/superx/sxrest/JobEtlXml.java deleted file mode 100644 index 1b29b26..0000000 --- a/src/de/superx/sxrest/JobEtlXml.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * de.superx.etl - a package for controlling ETL routines - * Copyright (C) 2021 Daniel Quathamer - * - * This package is licensed under the CampusSource License; - * http://www.campussource.de/org/license/ - */ -package de.superx.sxrest; -import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; -import javax.ws.rs.FormParam; -import javax.ws.rs.GET; -import javax.ws.rs.HEAD; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.core.Response; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; - - -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; - -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Request; -import de.memtext.util.DateUtils; -import de.superx.common.SxUser; -import de.superx.elt.EtlActionJob; -import de.superx.elt.EtlUtils; -import de.superx.servlet.SuperXManager; - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; - -import javax.servlet.http.HttpServletRequest; - - -@Path("/jobetlxml/get/{jobUniquename}/{jobParamName}") - - -public class JobEtlXml { - @Context - Request request; - - - @GET - @Path("/view/{param}") - @Produces(MediaType.APPLICATION_XML) - - public Document printXml(@PathParam("jobUniquename") String jobUniquename, - @PathParam("jobParamName") String jobParamName, - @PathParam("param") String param, - @Context HttpServletRequest request) { - String returntext=""; - returntext = getJobEtlXml(jobUniquename,jobParamName, param, request); - - return de.memtext.util.XMLUtils.buildDocumentFromString(returntext, false); - } - private String getJobEtlXml(String jobUniquename, - String jobParamName, - String param, - HttpServletRequest request) { - String returntext; - SxUser user = (SxUser) request.getSession().getAttribute("user"); - //TODO: valide Einträge prüfen: - //ebenso param - System.out.println("JOB"+jobUniquename + " mit param "+jobParamName); - String mandantenid= (String) request.getSession().getAttribute("MandantenID"); - if(mandantenid==null || mandantenid.equals("")) - mandantenid="default"; - - if (user == null || !user.isAdmin()) { - returntext="Fehlende Rechte"; - } - else - { - - int returnCode=0; - EtlActionJob myJob=new EtlActionJob(jobUniquename); //TODO:Mandantid - try { - myJob.initJob(jobUniquename,jobParamName+"="+param); - } catch (Exception e) { - // TODO Auto-generated catch block - - returntext=e.toString(); - returntext+=myJob.getLogoutput(); - - } - System.out.println("Job "+ jobUniquename+" initialized"); - try { - returnCode= myJob.execute(""); - returntext=myJob.getSw().toString(); - - } catch (Exception e) { - // TODO Auto-generated catch block - returntext=e.toString(); - returntext+=myJob.getLogoutput(); - } - } - return returntext; - } - @GET - @Path("/download/{param}") - @Produces(MediaType.APPLICATION_XML) - public String createDownloadXml( - @PathParam("jobUniquename") String jobUniquename, - @PathParam("jobParamName") String jobParamName, - @PathParam("param") String param, - @Context HttpServletRequest request) { - String returntext=""; - returntext = getJobEtlXml(jobUniquename,jobParamName,param, request); - return returntext; - //return de.memtext.util.XMLUtils.buildDocumentFromString(returntext, false); - } - /* Aktuell noch nicht genutzt: */ - @GET - @Path("/saveget/{params}") - @Produces(MediaType.TEXT_PLAIN) - - - public String saveGetXml(@QueryParam("param") String tid, - @QueryParam("Inhalt") String src, - @Context HttpServletRequest request) { - String returntext=""; - SxUser user = (SxUser) request.getSession().getAttribute("user"); - String mandantenid= (String) request.getSession().getAttribute("MandantenID"); - if(mandantenid==null || mandantenid.equals("")) - mandantenid="default"; - - if (user == null || !user.isAdmin()) { - returntext="Fehlende Rechte"; - } - else - { - returntext="tid="+tid+"-src="+src; - } - - return returntext; - } - /* Aktuell noch nicht genutzt: */ - @POST - @Path("/save") - @Consumes("application/x-www-form-urlencoded") - //@Consumes(MediaType.APPLICATION_FORM_URLENCODED) - @Produces(MediaType.TEXT_PLAIN) - - public String saveXml(@FormParam("tid") String tid, - @FormParam("Inhalt") String src, - @Context HttpServletRequest request) { - String returntext=""; - String jobuniquename="sx_select_mask"; - int returnCode=0; - tid="16000"; - SxUser user = (SxUser) request.getSession().getAttribute("user"); - String mandantenid= (String) request.getSession().getAttribute("MandantenID"); - String searchString="/etlAction[@name=\""+jobuniquename+"\"]/unload[@name=\"unload_maskeninfo\"]/rs/row/fld[@name=\"tid\"]"; - if(mandantenid==null || mandantenid.equals("")) - mandantenid="default"; - - if (user == null || !user.isAdmin()) { - returntext="Fehlende Rechte"; - - } - else - { - try { - if(de.superx.elt.EtlUtils.isNodeValueInXml(src,searchString,tid,jobuniquename)) - { - String job="sx_insert_mask"; - returntext="TID="+tid; - String params="TID="+tid; - File temp; - temp = File.createTempFile("myTempFile", ".xml"); - - BufferedWriter bw = new BufferedWriter(new FileWriter(temp)); - bw.write(src); - - bw.close(); - params+=EtlUtils.NEWLINE+"PATH_TO_INPUTFILE="+temp.getAbsolutePath(); - params+=EtlUtils.NEWLINE+"FORMAT=XML"; - EtlActionJob myJob=new EtlActionJob(job); //TODO:Mandantid - myJob.initJob(job,params); - returnCode= myJob.execute(""); - returntext=myJob.getSw().toString(); - - - - } - else - returntext="Übergebene TID "+tid+" entspricht nicht der XML-Datei "; - } catch (Exception e) { - returntext=e.toString(); - e.printStackTrace(); - } - - - } - return returntext; - } - -} diff --git a/src/de/superx/sxrest/JobExecutor.java b/src/de/superx/sxrest/JobExecutor.java deleted file mode 100644 index 2b10008..0000000 --- a/src/de/superx/sxrest/JobExecutor.java +++ /dev/null @@ -1,47 +0,0 @@ -package de.superx.sxrest; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Request; - -import java.sql.SQLException; - -import javax.servlet.http.HttpServletRequest; -import de.memtext.util.DateUtils; -import de.superx.common.SxUser; -import de.superx.elt.EtlActionJob; -import de.superx.servlet.SuperXManager; - -@Path("/execute") - -public class JobExecutor { - @Context - Request request; - - @GET - @Path("/{param}") - @Produces(MediaType.TEXT_PLAIN) - public String printLogs(@PathParam("param") String job, @Context HttpServletRequest request) { - String returntext = ""; - SxUser user = (SxUser) request.getSession().getAttribute("user"); - if (user == null || !user.isAdmin()) { - returntext = "Fehlende Rechte"; - } else { - EtlActionJob myJob = new EtlActionJob(job, "", ""); - try { - myJob.execute(); - } catch (Exception e) { - e.printStackTrace(); - returntext = "Fehler " + e; - - } - - - } - return returntext; - } -} diff --git a/src/de/superx/sxrest/LaunchUpgrade.java b/src/de/superx/sxrest/LaunchUpgrade.java deleted file mode 100644 index be3dd5d..0000000 --- a/src/de/superx/sxrest/LaunchUpgrade.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * de.superx.etl - a package for controlling ETL routines - * Copyright (C) 2021 Daniel Quathamer - * - * This package is licensed under the CampusSource License; - * http://www.campussource.de/org/license/ - */ -package de.superx.sxrest; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Request; -import de.memtext.util.DateUtils; -import de.superx.common.SxUser; -import de.superx.elt.EtlActionJob; -import de.superx.elt.EtlUtils; -import de.superx.servlet.SuperXManager; -import javax.servlet.http.HttpServletRequest; - - -@Path("/launchupgrade") - -public class LaunchUpgrade { - @Context - Request request; - - @GET - @Path("/{param}") - @Produces(MediaType.TEXT_PLAIN) - public String printXml(@PathParam("param") String componentName,@Context HttpServletRequest request) { - String jobOutput=""; - String jobLog=""; - int returnCode=0; - SxUser user = (SxUser) request.getSession().getAttribute("user"); - String mandantenid= (String) request.getSession().getAttribute("MandantenID"); - if(mandantenid==null || mandantenid.equals("")) - mandantenid="default"; - - if (user == null || !user.isAdmin()) { - jobLog+="Fehlende Rechte"; - returnCode=1; - } - else - { - String job=componentName+"_upgrade"; - String params=componentName.toUpperCase()+"_PFAD="+SuperXManager.getWEB_INFPfad()+EtlUtils.PATHSEP+"conf"+EtlUtils.PATHSEP+"edustore"+EtlUtils.PATHSEP+"db"+EtlUtils.PATHSEP+"module"+EtlUtils.PATHSEP+componentName; - - EtlActionJob myJob=new EtlActionJob(job); //TODO:Mandantid - try { - myJob.initJob(job,params); - } catch (Exception e) { - // TODO Auto-generated catch block - returnCode=1; - jobLog+=myJob.getActionLog().toString(); - jobLog+=e.toString(); - jobLog+=myJob.getLogoutput(); - - } - - try { - returnCode= myJob.execute(""); - jobOutput+=myJob.getSw().toString(); - jobLog+=myJob.getActionLog().toString(); - - } catch (Exception e) { - returnCode=1; - jobLog+=myJob.getActionLog().toString(); - jobLog+=e.toString(); - jobLog+=myJob.getLogoutput(); - } - } - if(returnCode==0) - return "Upgrade erfolgreich: "+EtlUtils.NEWLINE+jobLog; - else - return "Upgrade mit Fehler beendet: "+EtlUtils.NEWLINE+jobLog; - } - -} diff --git a/src/de/superx/sxrest/MaskXml.java b/src/de/superx/sxrest/MaskXml.java deleted file mode 100644 index 1fc5b46..0000000 --- a/src/de/superx/sxrest/MaskXml.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * de.superx.etl - a package for controlling ETL routines - * Copyright (C) 2021 Daniel Quathamer - * - * This package is licensed under the CampusSource License; - * http://www.campussource.de/org/license/ - */ -package de.superx.sxrest; -import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; -import javax.ws.rs.FormParam; -import javax.ws.rs.GET; -import javax.ws.rs.HEAD; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.core.Response; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; - - -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; - -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Request; -import de.memtext.util.DateUtils; -import de.superx.common.SxUser; -import de.superx.elt.EtlActionJob; -import de.superx.elt.EtlUtils; -import de.superx.servlet.SuperXManager; - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; - -import javax.servlet.http.HttpServletRequest; - - -@Path("/maskxml") - -public class MaskXml { - @Context - Request request; - - @GET - @Path("/get/{param}") - @Produces(MediaType.APPLICATION_XML) - - - public Document printXml(@PathParam("param") String tid,@Context HttpServletRequest request) { - String returntext=""; - returntext = getMaskXml(tid, request); - - return de.memtext.util.XMLUtils.buildDocumentFromString(returntext, false); - } - private String getMaskXml(String tid, HttpServletRequest request) { - String returntext; - SxUser user = (SxUser) request.getSession().getAttribute("user"); - String mandantenid= (String) request.getSession().getAttribute("MandantenID"); - if(mandantenid==null || mandantenid.equals("")) - mandantenid="default"; - - if (user == null || !user.isAdmin()) { - returntext="Fehlende Rechte"; - } - else - { - String job="sx_select_mask"; - String params="TID="+tid; - int returnCode=0; - EtlActionJob myJob=new EtlActionJob(job); //TODO:Mandantid - try { - myJob.initJob(job,params); - } catch (Exception e) { - // TODO Auto-generated catch block - - returntext=e.toString(); - returntext+=myJob.getLogoutput(); - - } - System.out.println("Job "+ job+" initialized"); - try { - returnCode= myJob.execute(""); - returntext=myJob.getSw().toString(); - - } catch (Exception e) { - // TODO Auto-generated catch block - returntext=e.toString(); - returntext+=myJob.getLogoutput(); - } - } - return returntext; - } - @GET - @Path("/download/{param}") - @Produces(MediaType.APPLICATION_XML) - public String createDownloadXml(@PathParam("param") String tid,@Context HttpServletRequest request) { - String returntext=""; - returntext = getMaskXml(tid, request); - return returntext; - //return de.memtext.util.XMLUtils.buildDocumentFromString(returntext, false); - } - /* Aktuell noch nicht genutzt: */ - @GET - @Path("/saveget/{params}") - @Produces(MediaType.TEXT_PLAIN) - - - public String saveGetXml(@QueryParam("param") String tid, - @QueryParam("Inhalt") String src, - @Context HttpServletRequest request) { - String returntext=""; - SxUser user = (SxUser) request.getSession().getAttribute("user"); - String mandantenid= (String) request.getSession().getAttribute("MandantenID"); - if(mandantenid==null || mandantenid.equals("")) - mandantenid="default"; - - if (user == null || !user.isAdmin()) { - returntext="Fehlende Rechte"; - } - else - { - returntext="tid="+tid+"-src="+src; - } - - return returntext; - } - /* Aktuell noch nicht genutzt: */ - @POST - @Path("/save") - @Consumes("application/x-www-form-urlencoded") - //@Consumes(MediaType.APPLICATION_FORM_URLENCODED) - @Produces(MediaType.TEXT_PLAIN) - - public String saveXml(@FormParam("tid") String tid, - @FormParam("Inhalt") String src, - @Context HttpServletRequest request) { - String returntext=""; - String jobuniquename="sx_select_mask"; - int returnCode=0; - tid="16000"; - SxUser user = (SxUser) request.getSession().getAttribute("user"); - String mandantenid= (String) request.getSession().getAttribute("MandantenID"); - String searchString="/etlAction[@name=\""+jobuniquename+"\"]/unload[@name=\"unload_maskeninfo\"]/rs/row/fld[@name=\"tid\"]"; - if(mandantenid==null || mandantenid.equals("")) - mandantenid="default"; - - if (user == null || !user.isAdmin()) { - returntext="Fehlende Rechte"; - - } - else - { - try { - if(de.superx.elt.EtlUtils.isNodeValueInXml(src,searchString,tid,jobuniquename)) - { - String job="sx_insert_mask"; - returntext="TID="+tid; - String params="TID="+tid; - File temp; - temp = File.createTempFile("myTempFile", ".xml"); - - BufferedWriter bw = new BufferedWriter(new FileWriter(temp)); - bw.write(src); - - bw.close(); - params+=EtlUtils.NEWLINE+"PATH_TO_INPUTFILE="+temp.getAbsolutePath(); - params+=EtlUtils.NEWLINE+"FORMAT=XML"; - EtlActionJob myJob=new EtlActionJob(job); //TODO:Mandantid - myJob.initJob(job,params); - returnCode= myJob.execute(""); - returntext=myJob.getSw().toString(); - - - - } - else - returntext="Übergebene TID "+tid+" entspricht nicht der XML-Datei "; - } catch (Exception e) { - returntext=e.toString(); - e.printStackTrace(); - } - - - } - return returntext; - } - -} diff --git a/superx/WEB-INF/lib/spring-context-indexer-6.2.19.jar b/superx/WEB-INF/lib/spring-context-indexer-6.2.19.jar new file mode 100644 index 0000000000000000000000000000000000000000..6b2bbdcc2eebd3168b05f4a89060ad825728bcfe GIT binary patch literal 27487 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 literal 0 HcmV?d00001 diff --git a/superx/WEB-INF/lib/superx-etl.jar b/superx/WEB-INF/lib/superx-etl.jar index 9e37524d770d9235fba955b4d5282ee5e0af1d34..070adf6ee89ddea39a578497b0db0d33dab2415a 100644 GIT binary patch literal 3903 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

Y~Ow^pYcIUdEs3T|C=w+?oSRM8Y8CI*;gG#4dkk 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 DltURV diff --git a/superx/edit/etl/etl_manager.jsp b/superx/edit/etl/etl_manager.jsp index 5bca3ef..127fce8 100644 --- a/superx/edit/etl/etl_manager.jsp +++ b/superx/edit/etl/etl_manager.jsp @@ -6,8 +6,7 @@ <% -String platform=de.superx.servlet.SuperXManager.isHis1?"HISinOne":"SuperX"; -String restApiPath="sxrest";// klappt noch nicht platform.equals("HISinOne")?"ds/api":"sxrest"; +String restApiPath="ds/api"; %> @@ -72,6 +71,25 @@ zs+=" response.text()) + // .then(str => new window.DOMParser().parseFromString(str, "text/xml")) + //var xmlTxt=new XMLSerializer().serializeToString(xmlDoc); + document.getElementById("Inhalt").innerHTML = xmlDoc; + } catch (error) { + document.getElementById("Inhalt").innerHTML = error.message; + } +} function getSrcAsXml(jobUniquename,jobParamName,jobParamValue) { //document.getElementById("MaskHeader").innerHTML="Masken-Quellcode laden"; @@ -91,14 +109,17 @@ var xhttp = new XMLHttpRequest(); document.getElementById("Inhalt").innerHTML="Serveranfrage Antwort... "+this.status; } }; - xhttp.open("GET", "../../"+restApiPath+"/jobetlxml/get/"+jobUniquename+"/"+jobParamName+"/view/"+jobParamValue, true); + // xhttp.open("GET", "../../ds/api/jobetlxml/get/"+jobUniquename+"/"+jobParamName+"/view/"+jobParamValue, true); + + xhttp.open("GET", "../../ds/api/jobetlxml/view/"+jobUniquename+"?jobParamName="+jobParamName+"¶m="+jobParamValue, true); xhttp.send(); } function downloadMaskSrc(jobUniquename,jobParamName,jobParamValue) { -window.open("../../"+restApiPath+"/jobetlxml/get/"+jobUniquename+"/"+jobParamName+"/download/"+jobParamValue,"_blank"); +const url="../../ds/api/jobetlxml/view/"+jobUniquename+"?jobParamName="+jobParamName+"¶m="+jobParamValue; +window.open(url,"_blank"); } function saveEtlXmlSrc(jobParamName) @@ -408,6 +429,7 @@ if(tab.equals(etlJobsArr[i].tabUniquename.toLowerCase()))

+
Wählen Sie links das Export/Import-Menü
diff --git a/superx/edit/etl/saveEtlXml.jsp b/superx/edit/etl/saveEtlXml.jsp index 4f62e57..103f3e7 100644 --- a/superx/edit/etl/saveEtlXml.jsp +++ b/superx/edit/etl/saveEtlXml.jsp @@ -6,8 +6,8 @@ <%@ page import ="java.io.File" %> <%@ page import ="java.io.FileWriter" %> <%@ page import ="java.io.IOException" %> -<%@ page import ="de.superx.elt.EtlActionJob" %> -<%@ page import ="de.superx.elt.EtlUtils" %> +<%@ page import ="de.superx.etl.EtlActionJob" %> +<%@ page import ="de.superx.etl.EtlUtils" %> <%@ page import ="de.superx.common.SxUser" %> @@ -63,7 +63,7 @@ String jobuniquename = request.getParameter("jobuniquename"); params+=EtlUtils.NEWLINE+"PATH_TO_INPUTFILE="+temp.getAbsolutePath(); params+=EtlUtils.NEWLINE+"FORMAT=XML"; EtlActionJob myJob=new EtlActionJob(jobuniquename); //TODO:Mandantid - myJob.initJob(jobuniquename,params); + myJob.initJob("etl",jobuniquename,params); returnCode= myJob.execute(""); returntext+=myJob.getActionLog().toString(); @@ -123,7 +123,7 @@ String jobuniquename = request.getParameter("jobuniquename");

Ergebnis der Ausführung

-

Status: <%="Code "+ returnCode+ "("+de.superx.elt.EtlUtils.translateReturnCode2Html(returnCode)+")"%>, Logausgabe: +

Status: <%="Code "+ returnCode+ "("+de.superx.elt.EtlUtils.translateReturnCode(returnCode)+")"%>, Logausgabe: