diff --git a/admin/oss/jailer-engine.pom b/admin/oss/jailer-engine.pom
index 599952e22..06a823f14 100644
--- a/admin/oss/jailer-engine.pom
+++ b/admin/oss/jailer-engine.pom
@@ -48,7 +48,7 @@
com.h2database
h2
- 2.2.224
+ 2.3.230
org.apache.logging.log4j
diff --git a/docs/api.html b/docs/api.html
index 5efbf7013..d90a64d9e 100644
--- a/docs/api.html
+++ b/docs/api.html
@@ -150,7 +150,7 @@
new BasicDataSource(
"org.h2.Driver", "jdbc:h2:" + new File(baseFolder, "demo-scott-h2").getAbsolutePath(), "sa", "",
POOL_SIZE,
- new File(baseFolder, "lib/h2-2.2.224.jar")),
+ new File(baseFolder, "lib/h2-2.3.230.jar")),
null,
new File(baseFolder, "datamodel/Demo-Scott"),
new File(baseFolder, "extractionmodel/Demo-Scott.jm"),
@@ -162,7 +162,7 @@
new BasicDataSource(
"org.h2.Driver", "jdbc:h2:" + new File(baseFolder, "demo-scott-h2-subset").getAbsolutePath(), "sa", "",
POOL_SIZE,
- new File(baseFolder, "lib/h2-2.2.224.jar")));
+ new File(baseFolder, "lib/h2-2.3.230.jar")));
/**
* Exports data related with employee "SCOTT"
diff --git a/lib/h2-2.2.224.jar b/lib/h2-2.2.224.jar
deleted file mode 100644
index ff1997a23..000000000
Binary files a/lib/h2-2.2.224.jar and /dev/null differ
diff --git a/lib/h2-2.3.230.jar b/lib/h2-2.3.230.jar
new file mode 100644
index 000000000..3a8f7f277
Binary files /dev/null and b/lib/h2-2.3.230.jar differ
diff --git a/src/main/engine/net/sf/jailer/api_example/APIExample.java b/src/main/engine/net/sf/jailer/api_example/APIExample.java
index a809a7fd8..0049c0bee 100644
--- a/src/main/engine/net/sf/jailer/api_example/APIExample.java
+++ b/src/main/engine/net/sf/jailer/api_example/APIExample.java
@@ -45,7 +45,7 @@ public class APIExample {
new BasicDataSource(
"org.h2.Driver", "jdbc:h2:" + new File(baseFolder, "demo-scott-h2").getAbsolutePath(), "sa", "",
POOL_SIZE,
- new File(baseFolder, "lib/h2-2.2.224.jar")),
+ new File(baseFolder, "lib/h2-2.3.230.jar")),
null,
new File(baseFolder, "datamodel/Demo-Scott"),
new File(baseFolder, "extractionmodel/Demo-Scott.jm"),
@@ -57,7 +57,7 @@ public class APIExample {
new BasicDataSource(
"org.h2.Driver", "jdbc:h2:" + new File(baseFolder, "demo-scott-h2-subset").getAbsolutePath(), "sa", "",
POOL_SIZE,
- new File(baseFolder, "lib/h2-2.2.224.jar")));
+ new File(baseFolder, "lib/h2-2.3.230.jar")));
/**
* Exports data related with employee "SCOTT"
diff --git a/src/main/engine/net/sf/jailer/configuration/LocalDatabaseConfiguration.java b/src/main/engine/net/sf/jailer/configuration/LocalDatabaseConfiguration.java
index 42c3b5b57..773437d00 100644
--- a/src/main/engine/net/sf/jailer/configuration/LocalDatabaseConfiguration.java
+++ b/src/main/engine/net/sf/jailer/configuration/LocalDatabaseConfiguration.java
@@ -35,7 +35,7 @@ public class LocalDatabaseConfiguration {
private String password = "";
private String driver = "org.h2.Driver";
- private String lib = "lib/h2-2.2.224.jar";
+ private String lib = "lib/h2-2.3.230.jar";
/**
* @return the localPKType
diff --git a/src/main/engine/net/sf/jailer/configuration/jailer.json b/src/main/engine/net/sf/jailer/configuration/jailer.json
index 6d3ea2b5b..87ca7b995 100644
--- a/src/main/engine/net/sf/jailer/configuration/jailer.json
+++ b/src/main/engine/net/sf/jailer/configuration/jailer.json
@@ -8,7 +8,7 @@
"user": "",
"password": "",
"driver": "org.h2.Driver",
- "lib": "lib/h2-2.2.224.jar"
+ "lib": "lib/h2-2.3.230.jar"
},
"commentNullColumnPlaceholder": "For DBUnit flat XML files, null columns can carry a placeholder value which can later be replaced using a ReplacementDataSet. In Flat XML files the first row of a table defines the metadata. If a null column is omitted, none of the following rows can have this column! This is the default behaviour of Jailer. Thus, define a null placeholder and replace it with a null value when you load the data set with DBUnit.",
diff --git a/src/main/engine/net/sf/jailer/datamodel/Association.java b/src/main/engine/net/sf/jailer/datamodel/Association.java
index fe9e004cd..71ca9af61 100644
--- a/src/main/engine/net/sf/jailer/datamodel/Association.java
+++ b/src/main/engine/net/sf/jailer/datamodel/Association.java
@@ -434,7 +434,9 @@ public class Association extends ModelElement {
String tag;
Set otherNames = null;
if (aggregationTagName == null) {
- otherNames = source.associations.stream().map(a -> a.aggregationTagName).filter(t -> t != null).collect(Collectors.toSet());
+ otherNames = new HashSet<>();
+ otherNames.addAll(source.associations.stream().map(a -> a.aggregationTagName).filter(t -> t != null).collect(Collectors.toSet()));
+ otherNames.addAll(source.getColumns().stream().map(c -> c.name.toLowerCase()).collect(Collectors.toSet()));
tag = destination.getUnqualifiedName().toLowerCase(Locale.ENGLISH);
} else {
tag = aggregationTagName;
diff --git a/src/main/engine/net/sf/jailer/datamodel/Table.java b/src/main/engine/net/sf/jailer/datamodel/Table.java
index 0dad4a76b..9f15e89e9 100644
--- a/src/main/engine/net/sf/jailer/datamodel/Table.java
+++ b/src/main/engine/net/sf/jailer/datamodel/Table.java
@@ -405,10 +405,6 @@ public class Table extends ModelElement implements Comparable {
// TODO should use " as quot-char in GUI
// TODO whatabout MySQL/MariaBD? Requoting? How?
// TODO default-quoting("/caseIns.) + heuristic re-quoting in XmlRowWriter: if content like 'SQL:T."xy"' -> 'SQL:T. {
/**
* Gets template for XML exports as DOM.
*/
- private Document getXmlTemplateAsDocument(String xmlTemplate, Quoting quoting) throws ParserConfigurationException, SAXException, IOException {
+ public Document getXmlTemplateAsDocument(String xmlTemplate, Quoting quoting) throws ParserConfigurationException, SAXException, IOException {
Document template;
if (xmlTemplate == null) {
template = createInitialXmlTemplate(quoting);
diff --git a/src/main/engine/net/sf/jailer/subsetting/ObjectNotationOutputException.java b/src/main/engine/net/sf/jailer/subsetting/ObjectNotationOutputException.java
new file mode 100644
index 000000000..d3005dda1
--- /dev/null
+++ b/src/main/engine/net/sf/jailer/subsetting/ObjectNotationOutputException.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2007 - 2024 Ralf Wisser.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.sf.jailer.subsetting;
+
+/**
+ * Thrown if something goes wrong when exporting to an XML/JSON/YAML file.
+ *
+ * @author Ralf Wisser
+ */
+public class ObjectNotationOutputException extends RuntimeException {
+
+ private static final long serialVersionUID = -3712636626146836549L;
+
+ public ObjectNotationOutputException(String message) {
+ super(message);
+ }
+
+}
diff --git a/src/main/engine/net/sf/jailer/subsetting/RowLimitExceededException.java b/src/main/engine/net/sf/jailer/subsetting/RowLimitExceededException.java
index f87810a1a..a3a336a41 100644
--- a/src/main/engine/net/sf/jailer/subsetting/RowLimitExceededException.java
+++ b/src/main/engine/net/sf/jailer/subsetting/RowLimitExceededException.java
@@ -16,7 +16,7 @@
package net.sf.jailer.subsetting;
/**
- * Throws if row limit is exceeded.
+ * Thrown if row limit is exceeded.
*
* @author Ralf Wisser
*/
diff --git a/src/main/engine/net/sf/jailer/subsetting/SubsettingEngine.java b/src/main/engine/net/sf/jailer/subsetting/SubsettingEngine.java
index 3d237d7dd..c1d60462c 100644
--- a/src/main/engine/net/sf/jailer/subsetting/SubsettingEngine.java
+++ b/src/main/engine/net/sf/jailer/subsetting/SubsettingEngine.java
@@ -1228,6 +1228,21 @@ public class SubsettingEngine {
} catch (TransformerConfigurationException e) {
throw new RuntimeException(e);
}
+
+ sortedTables.sort(new Comparator() {
+ @Override
+ public int compare(Table t1, Table t2) {
+ boolean s1 = subjects.contains(t1);
+ boolean s2 = subjects.contains(t2);
+ if (s1 && !s2) {
+ return -1;
+ }
+ if (!s1 && s2) {
+ return 1;
+ }
+ return 0;
+ }
+ });
for (Table table: sortedTables) {
entityGraph.markRoots(table);
@@ -1235,6 +1250,10 @@ public class SubsettingEngine {
for (Table table: sortedTables) {
_log.info("exporting table " + datamodel.getDisplayName(table));
reader.setTable(table);
+ reader.setTableIsSubject(subjects.contains(table));
+ if (executionContext.isIgnoreNonAggregated() && !subjects.contains(table)) {
+ continue;
+ }
entityGraph.readMarkedEntities(table, reader, reader.getTableMapping(table).selectionSchema, reader.getTableMapping(table).originalPKAliasPrefix, true);
}
reader.endDocument();
@@ -1697,7 +1716,7 @@ public class SubsettingEngine {
datamodel.transpose();
}
- if (scriptFile != null && scriptFormat != ScriptFormat.XML && exportStatistic.getTotal() != exportedCount) {
+ if (scriptFile != null && !scriptFormat.isObjectNotation() && exportStatistic.getTotal() != exportedCount) {
String message =
"The number of rows collected (" + exportStatistic.getTotal() + ") differs from that of the exported ones (" + exportedCount + ").\n" +
"This may have been caused by an invalid primary key definition.\nPlease note that each primary key must be unique.\n" +
diff --git a/src/main/engine/net/sf/jailer/xml/JSONWriter.java b/src/main/engine/net/sf/jailer/xml/JSONWriter.java
new file mode 100644
index 000000000..56ce7882b
--- /dev/null
+++ b/src/main/engine/net/sf/jailer/xml/JSONWriter.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2007 - 2024 Ralf Wisser.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.sf.jailer.xml;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+
+import net.sf.jailer.xml.XmlUtil.ObjectNotationWriter;
+
+/**
+ * A writer for JSON.
+ *
+ * @author Ralf Wisser
+ */
+public class JSONWriter implements ObjectNotationWriter {
+ private final JsonGenerator jGen;
+
+ public JSONWriter(Writer out) throws IOException {
+ JsonFactory jfactory = new JsonFactory();
+ this.jGen = jfactory.createGenerator(out);
+ this.jGen.useDefaultPrettyPrinter();
+ }
+
+ @Override
+ public void writeStartObject() throws IOException {
+ this.jGen.writeStartObject();
+ }
+
+ @Override
+ public void writeStartArray() throws IOException {
+ this.jGen.writeStartArray();;
+ }
+
+ @Override
+ public void writeEndObject() throws IOException {
+ this.jGen.writeEndObject();;
+ }
+
+ @Override
+ public void writeEndArray() throws IOException {
+ this.jGen.writeEndArray();
+ }
+
+ @Override
+ public void flush() throws IOException {
+ this.jGen.flush();
+ }
+
+ @Override
+ public void writeFieldName(String qName) throws IOException {
+ this.jGen.writeFieldName(qName);
+ }
+
+ @Override
+ public void writeArrayFieldStart(String qName) throws IOException {
+ this.jGen.writeArrayFieldStart(qName);
+ }
+
+ @Override
+ public void writeNull() throws IOException {
+ this.jGen.writeNull();
+ }
+
+ @Override
+ public void writeBinary(byte[] content) throws IOException {
+ this.jGen.writeBinary(content);
+ }
+
+ @Override
+ public void writeBoolean(Boolean content) throws IOException {
+ this.jGen.writeBoolean(content);
+ }
+
+ @Override
+ public void writeNumber(BigInteger content) throws IOException {
+ this.jGen.writeNumber(content);
+ }
+
+ @Override
+ public void writeNumber(BigDecimal content) throws IOException {
+ this.jGen.writeNumber(content);
+ }
+
+ @Override
+ public void writeNumber(Double content) throws IOException {
+ this.jGen.writeNumber(content);
+ }
+
+ @Override
+ public void writeNumber(Float content) throws IOException {
+ this.jGen.writeNumber(content);
+ }
+
+ @Override
+ public void writeNumber(Integer content) throws IOException {
+ this.jGen.writeNumber(content);
+ }
+
+ @Override
+ public void writeNumber(Long content) throws IOException {
+ this.jGen.writeNumber(content);
+ }
+
+ @Override
+ public void writeNumber(Short content) throws IOException {
+ this.jGen.writeNumber(content);
+ }
+
+ @Override
+ public void writeString(String string) throws IOException {
+ this.jGen.writeString(string);
+ }
+
+ @Override
+ public void writeComment(String comment) throws IOException {
+ try {
+ jGen.writeStringField("j:comment", comment + " /j:comment");
+ } catch (Exception e) {
+ e.printStackTrace();
+ // ignore
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/engine/net/sf/jailer/xml/XmlExportTransformer.java b/src/main/engine/net/sf/jailer/xml/XmlExportTransformer.java
index ab62e740a..2f733c294 100644
--- a/src/main/engine/net/sf/jailer/xml/XmlExportTransformer.java
+++ b/src/main/engine/net/sf/jailer/xml/XmlExportTransformer.java
@@ -44,6 +44,7 @@ import net.sf.jailer.datamodel.Column;
import net.sf.jailer.datamodel.RowIdSupport;
import net.sf.jailer.datamodel.Table;
import net.sf.jailer.entitygraph.EntityGraph;
+import net.sf.jailer.subsetting.ObjectNotationOutputException;
import net.sf.jailer.subsetting.ScriptFormat;
import net.sf.jailer.util.CellContentConverter;
import net.sf.jailer.util.Quoting;
@@ -59,7 +60,12 @@ public class XmlExportTransformer extends AbstractResultSetReader {
* The table to read from.
*/
private Table table;
-
+
+ /**
+ * true iff table is subject.
+ */
+ private boolean tableIsSubject;
+
/**
* For writing rows as xml.
*/
@@ -114,9 +120,13 @@ public class XmlExportTransformer extends AbstractResultSetReader {
* {@link RowIdSupport}.
*/
private final RowIdSupport rowIdSupport;
+
+ private final ExecutionContext executionContext;
private final Quoting quoting;
-
+
+ private ScriptFormat scriptFormat;
+
/**
* Constructor.
*
@@ -133,21 +143,33 @@ public class XmlExportTransformer extends AbstractResultSetReader {
public XmlExportTransformer(OutputStream out, String commentHeader,
EntityGraph entityGraph, Set totalProgress, Set cyclicAggregatedTables,
String rootTag, String datePattern, String timestampPattern, Session session, ScriptFormat scriptFormat, Charset charset, ExecutionContext executionContext) throws TransformerConfigurationException, SAXException, SQLException {
- this.xmlRowWriter = new XmlRowWriter(out, commentHeader, rootTag, datePattern, timestampPattern, scriptFormat, charset);
+ this.xmlRowWriter = new XmlRowWriter(out, commentHeader, rootTag, datePattern, timestampPattern, scriptFormat, charset, executionContext);
this.entityGraph = entityGraph;
+ this.scriptFormat = scriptFormat;
this.totalProgress = totalProgress;
this.cyclicAggregatedTables = cyclicAggregatedTables;
this.session = session;
this.quoting = Quoting.getQuoting(session);
this.rowIdSupport = new RowIdSupport(entityGraph.getDatamodel(), session.dbms, executionContext);
+ this.executionContext = executionContext;
}
+ private int rootCount = 0;
+
/**
* Reads result-set and writes into export-script.
*/
@Override
public void readCurrentRow(ResultSet resultSet) throws SQLException {
try {
+ if (executionContext.isDisallowNonAggregated() && !tableIsSubject) {
+ throw new ObjectNotationOutputException("Non-aggregated objects (\"" + table.getName() + "\") are disallowed at root level.\n(" + scriptFormat + ")");
+ }
+ if (++rootCount > 1) {
+ if (executionContext.isSingleRoot()) {
+ throw new ObjectNotationOutputException("Multiple root objects are not allowed. (\"" + table.getName() + "\")\n(" + scriptFormat + ")");
+ }
+ }
writeEntity(table, null, resultSet, new ArrayList(), getCellContentConverter(resultSet, session, session.dbms));
} catch (SAXException e) {
throw new RuntimeException(e);
@@ -225,7 +247,7 @@ public class XmlExportTransformer extends AbstractResultSetReader {
}
};
try {
- xmlRowWriter.startList(sa);
+ xmlRowWriter.startList(sa, name);
entityGraph.readDependentEntities(sa.destination, sa, resultSet, getMetaData(resultSet), reader, getTypeCache(sa.destination), getTableMapping(sa.destination).selectionSchema, getTableMapping(sa.destination).originalPKAliasPrefix);
if (cyclicAggregatedTables.contains(sa.destination)) {
entityGraph.markDependentEntitiesAsTraversed(sa, resultSet, getMetaData(resultSet), getTypeCache(sa.destination));
@@ -265,6 +287,13 @@ public class XmlExportTransformer extends AbstractResultSetReader {
this.table = table;
}
+ /**
+ * @param tableIsSubject true iff table is subject
+ */
+ public void setTableIsSubject(boolean tableIsSubject) {
+ this.tableIsSubject = tableIsSubject;
+ }
+
/**
* Closes the XML document.
*/
diff --git a/src/main/engine/net/sf/jailer/xml/XmlRowWriter.java b/src/main/engine/net/sf/jailer/xml/XmlRowWriter.java
index 91abeca78..92dc79c54 100644
--- a/src/main/engine/net/sf/jailer/xml/XmlRowWriter.java
+++ b/src/main/engine/net/sf/jailer/xml/XmlRowWriter.java
@@ -30,6 +30,7 @@ import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
+import java.util.Stack;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.sax.TransformerHandler;
@@ -38,6 +39,7 @@ import javax.xml.transform.stream.StreamResult;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
+import net.sf.jailer.ExecutionContext;
import net.sf.jailer.configuration.DBMS;
import net.sf.jailer.database.Session;
import net.sf.jailer.datamodel.AggregationSchema;
@@ -50,7 +52,7 @@ import net.sf.jailer.util.SqlUtil;
/**
- * Writes rows into XML file.
+ * Writes rows into XML/JSON/YAML file.
*
* @author Ralf Wisser
*/
@@ -86,6 +88,13 @@ public class XmlRowWriter {
*/
private final Map> typeCachesForStringKey = new HashMap>();
+ protected boolean forSketch = false;
+
+ /**
+ * Execution context.
+ */
+ private final ExecutionContext executionContext;
+
/**
* Constructor.
*
@@ -95,41 +104,72 @@ public class XmlRowWriter {
* @param datePattern pattern for dates
* @param timestampPattern pattern for time-stamps
* @param scriptFormat
+ * @param executionContext
*/
- public XmlRowWriter(OutputStream out, String commentHeader, String rootTag, String datePattern, String timestampPattern, ScriptFormat scriptFormat, Charset charset) throws SAXException, TransformerConfigurationException {
+ public XmlRowWriter(OutputStream out, String commentHeader, String rootTag, String datePattern, String timestampPattern, ScriptFormat scriptFormat, Charset charset, ExecutionContext executionContext) throws SAXException, TransformerConfigurationException {
this.rootTag = rootTag;
- this.datePattern = new SimpleDateFormat(datePattern, Locale.ENGLISH);
- this.timestampPattern = new SimpleDateFormat(timestampPattern, Locale.ENGLISH);
+ this.executionContext = executionContext;
+ this.datePattern = datePattern == null? new SimpleDateFormat() : new SimpleDateFormat(datePattern, Locale.ENGLISH);
+ this.timestampPattern = timestampPattern == null? new SimpleDateFormat() : new SimpleDateFormat(timestampPattern, Locale.ENGLISH);
StreamResult streamResult = new StreamResult(new OutputStreamWriter(out, charset));
transformerHandler = scriptFormat == ScriptFormat.JSON
- ? XmlUtil.createJSONTransformerHandler(commentHeader, rootTag, streamResult, charset)
- : XmlUtil.createTransformerHandler(commentHeader, rootTag, streamResult, charset);
+ ? XmlUtil.createObjectNotationTransformerHandler(commentHeader, executionContext.isSingleRoot()? "" : rootTag, streamResult.getWriter(), false, scriptFormat, executionContext)
+ : XmlUtil.createTransformerHandler(commentHeader, executionContext.isSingleRoot()? "" : rootTag, streamResult, charset);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param out output stream to write the xml into
+ * @param commentHeader comment at top of document
+ * @param rootTag root tag name
+ * @param datePattern pattern for dates
+ * @param timestampPattern pattern for time-stamps
+ * @param scriptFormat
+ * @param executionContext
+ */
+ public XmlRowWriter(OutputStream out, String commentHeader, String rootTag, String datePattern, String timestampPattern, ScriptFormat scriptFormat, Charset charset, TransformerHandler transformerHandler, ExecutionContext executionContext) throws SAXException, TransformerConfigurationException {
+ this.rootTag = rootTag;
+ this.executionContext = executionContext;
+ this.datePattern = datePattern == null? new SimpleDateFormat() : new SimpleDateFormat(datePattern, Locale.ENGLISH);
+ this.timestampPattern = timestampPattern == null? new SimpleDateFormat() : new SimpleDateFormat(timestampPattern, Locale.ENGLISH);
+ forSketch = true;
+ this.transformerHandler = transformerHandler;
}
/**
* Closes the writer.
*/
public void close() throws SAXException {
- // TODO
- // TODO rootTag is never empty. multipleObject attribute
- if (rootTag.length() > 0 && !(transformerHandler instanceof ObjectFormatTransformer)) {
+ if (!executionContext.isSingleRoot() && !(transformerHandler instanceof ObjectFormatTransformer)) {
transformerHandler.endElement("", "", rootTag);
}
transformerHandler.endDocument();
}
-
+
+ private Map> associationTempAggregationTagName = new HashMap<>();
+
/**
* Writes start element for a list of rows.
*
* @param association association describing the list
+ * @param name
*/
- public void startList(Association association) throws SAXException {
+ public void startList(Association association, String name) throws SAXException {
+ if (association != null) {
+ Stack stack = associationTempAggregationTagName.get(association);
+ if (stack == null) {
+ stack = new Stack<>();
+ associationTempAggregationTagName.put(association, stack);
+ }
+ stack.push(name);
+ }
if (association != null && getAggregationSchema(association) == AggregationSchema.EXPLICIT_LIST) {
if (ifLevel == 0) {
if (transformerHandler instanceof ObjectFormatTransformer) {
((ObjectFormatTransformer) transformerHandler).startArray();
}
- transformerHandler.startElement(null, null, association.getAggregationTagName(), null);
+ transformerHandler.startElement(null, null, name != null? name : association.getAggregationTagName(), null);
}
}
}
@@ -148,6 +188,12 @@ public class XmlRowWriter {
}
}
}
+ if (association != null) {
+ Stack stack = associationTempAggregationTagName.get(association);
+ if (stack != null && !stack.isEmpty()) {
+ stack.pop();
+ }
+ }
}
private AggregationSchema getAggregationSchema(Association association) {
@@ -200,6 +246,8 @@ public class XmlRowWriter {
*/
protected final CellContentConverter cellContentConverter;
+ private String lastElementName;
+
/**
* Constructor.
*
@@ -211,7 +259,7 @@ public class XmlRowWriter {
this.table = table;
this.association = association;
this.session = session;
- this.cellContentConverter = new CellContentConverter(resultSetMetaData, session, session.dbms);
+ this.cellContentConverter = session == null? null : new CellContentConverter(resultSetMetaData, session, session.dbms);
}
/**
@@ -221,7 +269,7 @@ public class XmlRowWriter {
* @param returnNull if true, return null instead of empty string if sql-result is null
* @return the xml to write out
*/
- private Object toContent(String text, boolean returnNull) {
+ protected Object toContent(String text, boolean returnNull) {
if (text != null && text.startsWith(XmlUtil.SQL_PREFIX)) {
String columnName = "C" + nr++;
int type;
@@ -231,45 +279,52 @@ public class XmlRowWriter {
typeCache = new HashMap();
typeCachesForStringKey.put(table, typeCache);
}
- type = SqlUtil.getColumnType(resultSet, resultSetMetaData, columnName, typeCache);
- if ((type == Types.BLOB || type == Types.CLOB|| type == Types.NCLOB) && !DBMS.SQLITE.equals(session.dbms)) {
- Object object = resultSet.getObject(columnName);
- if (returnNull && (object == null || resultSet.wasNull())) {
- return null;
- }
- if (object instanceof Blob) {
- Blob blob = (Blob) object;
- byte[] blobValue = blob.getBytes(1, (int) blob.length());
- return Base64.encodeBytes(blobValue);
- }
+ try {
+ type = SqlUtil.getColumnType(resultSet, resultSetMetaData, columnName, typeCache);
+ if ((type == Types.BLOB || type == Types.CLOB || type == Types.NCLOB)
+ && !DBMS.SQLITE.equals(session.dbms)) {
+ Object object = resultSet.getObject(columnName);
+ if (returnNull && (object == null || resultSet.wasNull())) {
+ return null;
+ }
+ if (object instanceof Blob) {
+ Blob blob = (Blob) object;
+ byte[] blobValue = blob.getBytes(1, (int) blob.length());
+ return Base64.encodeBytes(blobValue);
+ }
- if (object instanceof Clob) {
- Clob clobValue = (Clob) object;
- int length = (int) clobValue.length();
- if (length > 0) {
- return clobValue.getSubString(1, length);
+ if (object instanceof Clob) {
+ Clob clobValue = (Clob) object;
+ int length = (int) clobValue.length();
+ if (length > 0) {
+ return clobValue.getSubString(1, length);
+ }
+ return "";
}
- return "";
- }
- } else {
- Object o = cellContentConverter.getObject(resultSet, columnName);
- if (returnNull && (o == null || resultSet.wasNull())) {
- return null;
- }
- if (o != null) {
- Object value;
-
- if (o instanceof Timestamp) {
- value = timestampPattern.format((Timestamp) o);
- } else if (o instanceof Date) {
- value = datePattern.format((Date) o);
- } else {
- value = o;
+ } else {
+ Object o = cellContentConverter.getObject(resultSet, columnName);
+ if (returnNull && (o == null || resultSet.wasNull())) {
+ return null;
+ }
+ if (o != null) {
+ Object value;
+
+ if (o instanceof Timestamp) {
+ value = timestampPattern.format((Timestamp) o);
+ } else if (o instanceof Date) {
+ value = datePattern.format((Date) o);
+ } else {
+ value = o;
+ }
+ return value;
}
- return value;
}
+ return null;
+ } catch (OutOfMemoryError e) {
+ throw new OutOfMemoryError("Out of Memory. \nNot enough memory to read field "
+ + (table == null ? "" : ("\"" + table.getName() + "\".")) + " \"" + lastElementName
+ + "\"");
}
- return null;
} catch (SQLException e) {
throw new RuntimeException(e);
}
@@ -280,7 +335,7 @@ public class XmlRowWriter {
@Override
public void visitComment(String comment) {
try {
- if (ifLevel == 0) {
+ if (ifLevel == 0 && forSketch) {
transformerHandler.comment(comment.toCharArray(), 0, comment.length());
}
} catch (SAXException e) {
@@ -308,6 +363,7 @@ public class XmlRowWriter {
@Override
public void visitElementStart(String elementName, boolean isRoot, String[] aNames, String[] aValues) {
+ lastElementName = elementName;
if (ifLevel > 0) {
++ifLevel;
}
@@ -332,8 +388,6 @@ public class XmlRowWriter {
} else if (!aNames[i].equals(jailerNamespaceDeclaration)) {
Object content = toContent(aValues[i], false);
attr.addAttribute("", "", aNames[i], "CDATA", content == null? "" : content.toString());
- // TODO
- // TODO if instanceof ObjectFormatTransformer then startElement(); content(); endElement();
}
}
}
@@ -342,7 +396,19 @@ public class XmlRowWriter {
++ifLevel;
} else {
if (!isRoot || association == null || getAggregationSchema(association) != AggregationSchema.FLAT) {
- String tagName = isRoot && association != null && getAggregationSchema(association) != AggregationSchema.EXPLICIT_LIST? association.getAggregationTagName() : elementName;
+ String tagName;
+ if (isRoot && association != null && getAggregationSchema(association) != AggregationSchema.EXPLICIT_LIST) {
+ tagName = null;
+ Stack stack = associationTempAggregationTagName.get(association);
+ if (stack != null && !stack.isEmpty()) {
+ tagName = stack.peek();
+ }
+ if (tagName == null) {
+ tagName = association.getAggregationTagName();
+ }
+ } else {
+ tagName = elementName;
+ }
transformerHandler.startElement("", "", tagName, attr);
}
}
@@ -375,21 +441,14 @@ public class XmlRowWriter {
}
-// TODO
-// TODO Sketch also in JSON
-// TODO no Sketch-view in ExMoEd, only in template-editor
-// TODO "Sketch" dann in "Template"-Dialog (fuer beide Tabellen der Asoziation?)
-
-// TODO
-// TODO template-editor (GUI):
-// TODO add sketch view (JScrollPane)
-// TODO make it bigger
-
// TODO
// TODO docu about "j:if-not-null"/"j:is-null" in template dialog
+// TODO 1
+// TODO JSON/YAML/XML
+// TODO "unformatted" export. in XMLSettingsDialog+CLI+SubesstingEngine(Facade)
+
// TODO
-// TODO warn if "singleObject" and "incudeNonAggr" and later exists. "dont warn again" button (transient)
-
+// TODO new maven dep, testen
diff --git a/src/main/engine/net/sf/jailer/xml/XmlUtil.java b/src/main/engine/net/sf/jailer/xml/XmlUtil.java
index 93b6e68fa..ac08e3f46 100644
--- a/src/main/engine/net/sf/jailer/xml/XmlUtil.java
+++ b/src/main/engine/net/sf/jailer/xml/XmlUtil.java
@@ -22,6 +22,7 @@ import java.io.Writer;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.charset.Charset;
+import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
@@ -39,7 +40,6 @@ import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;
-import org.apache.commons.collections4.map.HashedMap;
import org.w3c.dom.Attr;
import org.w3c.dom.Comment;
import org.w3c.dom.Document;
@@ -53,9 +53,9 @@ import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
-import com.fasterxml.jackson.core.JsonFactory;
-import com.fasterxml.jackson.core.JsonGenerator;
-
+import net.sf.jailer.ExecutionContext;
+import net.sf.jailer.datamodel.Association;
+import net.sf.jailer.subsetting.ScriptFormat;
import net.sf.jailer.util.PrintUtil;
import net.sf.jailer.xml.XmlRowWriter.ObjectFormatTransformer;
@@ -65,15 +65,41 @@ import net.sf.jailer.xml.XmlRowWriter.ObjectFormatTransformer;
* @author Ralf Wisser
*/
public class XmlUtil {
+
+ public static interface ObjectNotationWriter {
+ public void writeStartObject() throws IOException;
+ public void writeStartArray() throws IOException;
+ public void writeEndObject() throws IOException;
+ public void writeEndArray() throws IOException;
+ public void flush() throws IOException;
+ public void writeFieldName(String qName) throws IOException;
+ public void writeArrayFieldStart(String qName) throws IOException;
+ public void writeNull() throws IOException;
+ public void writeBinary(byte[] content) throws IOException;
+ public void writeBoolean(Boolean content) throws IOException;
+ public void writeNumber(BigInteger content) throws IOException;
+ public void writeNumber(BigDecimal content) throws IOException;
+ public void writeNumber(Double content) throws IOException;
+ public void writeNumber(Float content) throws IOException;
+ public void writeNumber(Integer content) throws IOException;
+ public void writeNumber(Long content) throws IOException;
+ public void writeNumber(Short content) throws IOException;
+ public void writeString(String string) throws IOException;
+ public void writeComment(String comment) throws IOException;
+ }
- private static class JSONTransformerHandler implements TransformerHandler, ObjectFormatTransformer {
+ public static class ObjectNotationTransformerHandler implements TransformerHandler, ObjectFormatTransformer {
private final Writer out;
- private final JsonGenerator jGenerator;
+ private final ObjectNotationWriter jGenerator;
+ private final ExecutionContext executionContext;
+ private final boolean forSketch;
Stack states = new Stack<>();
-
- private JSONTransformerHandler(Writer out, JsonGenerator jGenerator) {
+
+ private ObjectNotationTransformerHandler(Writer out, ObjectNotationWriter jGenerator, boolean forSketch, ExecutionContext executionContext) {
this.out = out;
this.jGenerator = jGenerator;
+ this.forSketch = forSketch;
+ this.executionContext = executionContext;
}
@Override
@@ -83,8 +109,13 @@ public class XmlUtil {
@Override
public void startDocument() throws SAXException {
try {
- jGenerator.writeStartObject();
- states.push('{');
+ if (forSketch || executionContext.isSingleRoot()) {
+ jGenerator.writeStartObject();
+ states.push('R');
+ } else {
+ jGenerator.writeStartArray();
+ states.push('M');
+ }
} catch (IOException e) {
throw new RuntimeException(e);
}
@@ -93,8 +124,12 @@ public class XmlUtil {
@Override
public void endDocument() throws SAXException {
try {
- jGenerator.writeEndObject();
- states.pop();
+ Character c = states.pop();
+ if (c == 'R') {
+ jGenerator.writeEndObject();
+ } else if (c == 'M') {
+ jGenerator.writeEndArray();
+ }
jGenerator.flush();
} catch (IOException e) {
try {
@@ -124,12 +159,17 @@ public class XmlUtil {
jGenerator.writeStartObject();
states.push('=');
jGenerator.writeFieldName(qName);
+ } else if (states.peek() == 'M') {
+ jGenerator.writeStartObject();
+ states.push('m');
} else if (states.peek() == '[') {
jGenerator.writeArrayFieldStart(qName);
states.push('-');
} else if (states.peek() == '-') {
jGenerator.writeStartObject();
states.push('{');
+ } else if (states.peek() == 'R') {
+ states.push('r');
} else {
states.push('=');
jGenerator.writeFieldName(qName);
@@ -155,6 +195,9 @@ public class XmlUtil {
if (pop == '{') {
jGenerator.writeEndObject();
}
+ if (pop == 'm') {
+ jGenerator.writeEndObject();
+ }
if (pop == '-') {
jGenerator.writeEndArray();
}
@@ -163,7 +206,7 @@ public class XmlUtil {
}
}
- private Map constants = new HashedMap<>();
+ private Map constants = new HashMap<>();
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
@@ -242,6 +285,14 @@ public class XmlUtil {
@Override
public void comment(char[] ch, int start, int length) throws SAXException {
+ try {
+ String comment = new String(ch, start, length).trim();
+ if (!comment.isEmpty()) {
+ jGenerator.writeComment(comment);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
}
@Override
@@ -312,12 +363,56 @@ public class XmlUtil {
@Override
public void startArray() {
- states.push('[');
+ try {
+ if (states.peek() == '=') {
+ jGenerator.writeStartObject();
+ states.push('[');
+ } else {
+ states.push('[');
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
}
@Override
public void endArray() {
- states.pop();
+ try {
+ states.pop();
+ if (states.peek() == '=') {
+ jGenerator.writeEndObject();
+ states.pop();
+ states.push('?');
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void associationSketch(Association a, String associationName, String name) {
+ try {
+ if (states.peek() != '=') {
+ jGenerator.writeFieldName(name);
+ } else {
+ jGenerator.writeStartObject();
+ states.pop();
+ states.push('?');
+ associationSketch(a, associationName, name);
+ jGenerator.writeEndObject();
+ return;
+ }
+ boolean isArray = !a.isInsertDestinationBeforeSource();
+
+ if (isArray) {
+ jGenerator.writeStartArray();
+ jGenerator.writeEndArray();
+ } else {
+ jGenerator.writeStartObject();
+ jGenerator.writeEndObject();
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
}
}
@@ -538,35 +633,38 @@ public class XmlUtil {
return transformerHandler;
}
- public static TransformerHandler createJSONTransformerHandler(String commentHeader, String rootTag,
- StreamResult streamResult, Charset charset) {
+ public static ObjectNotationTransformerHandler createObjectNotationTransformerHandler(String commentHeader, String rootTag,
+ Writer out, boolean forSketch, ScriptFormat scriptFormat, ExecutionContext executionContext) {
- Writer out = streamResult.getWriter();
- JsonFactory jfactory = new JsonFactory();
- JsonGenerator jGenerator;
+ ObjectNotationWriter jGenerator;
try {
- jGenerator = jfactory
- .createGenerator(out);
- jGenerator.useDefaultPrettyPrinter();
+ if (scriptFormat == ScriptFormat.JSON) {
+ jGenerator = new JSONWriter(out);
+ } else if (scriptFormat == ScriptFormat.YAML) {
+ // TODO
+ jGenerator = new YAMLWriter(out);
+ } else {
+ throw new RuntimeException("unknown script format: " + scriptFormat);
+ }
} catch (IOException e) {
throw new RuntimeException(e);
}
- // TODO
- // TODO c|blob: size-limit (editable). As watch-dog (error if exceeded) (show path of field on error)
-
// TODO
// TODO count XML/JSON/YMAML exports (s16-19)
-
- // TODO
- // TODO ? default in XML/JSON/... Settings: dont allow arrays. max straenge. dann in der Fehlermeldung auf Mögl. Array zuzulassen aufmerksam machen?
- // TODO ? gute gruende, das gegenteil zu machen. im fehlerfall nur warnen.
- TransformerHandler th = new JSONTransformerHandler(out, jGenerator);
+
+ ObjectNotationTransformerHandler th = new ObjectNotationTransformerHandler(out, jGenerator, forSketch, executionContext);
try {
th.startDocument();
- } catch (SAXException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
+ if (commentHeader != null && !commentHeader.isEmpty()) {
+ // TODO
+ // TODO nicht bei JSON, noch testen
+ if (!(jGenerator instanceof JSONWriter)) {
+ jGenerator.writeComment(commentHeader);
+ }
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
}
return th;
}
diff --git a/src/main/engine/net/sf/jailer/xml/YAMLWriter.java b/src/main/engine/net/sf/jailer/xml/YAMLWriter.java
new file mode 100644
index 000000000..5882c7738
--- /dev/null
+++ b/src/main/engine/net/sf/jailer/xml/YAMLWriter.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2007 - 2024 Ralf Wisser.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.sf.jailer.xml;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+
+import net.sf.jailer.xml.XmlUtil.ObjectNotationWriter;
+
+/**
+ * A writer for JSON.
+ *
+ * @author Ralf Wisser
+ */
+public class YAMLWriter implements ObjectNotationWriter {
+ private final JsonGenerator jGen;
+
+ public YAMLWriter(Writer out) throws IOException {
+ // TODO
+ // TODO implement using SnakeYaml
+ JsonFactory jfactory = new JsonFactory();
+ this.jGen = jfactory.createGenerator(out);
+ this.jGen.useDefaultPrettyPrinter();
+ }
+
+ @Override
+ public void writeStartObject() throws IOException {
+ this.jGen.writeStartObject();
+ }
+
+ @Override
+ public void writeStartArray() throws IOException {
+ this.jGen.writeStartArray();;
+ }
+
+ @Override
+ public void writeEndObject() throws IOException {
+ this.jGen.writeEndObject();;
+ }
+
+ @Override
+ public void writeEndArray() throws IOException {
+ this.jGen.writeEndArray();
+ }
+
+ @Override
+ public void flush() throws IOException {
+ this.jGen.flush();
+ }
+
+ @Override
+ public void writeFieldName(String qName) throws IOException {
+ this.jGen.writeFieldName(qName);
+ }
+
+ @Override
+ public void writeArrayFieldStart(String qName) throws IOException {
+ this.jGen.writeArrayFieldStart(qName);
+ }
+
+ @Override
+ public void writeNull() throws IOException {
+ this.jGen.writeNull();
+ }
+
+ @Override
+ public void writeBinary(byte[] content) throws IOException {
+ this.jGen.writeBinary(content);
+ }
+
+ @Override
+ public void writeBoolean(Boolean content) throws IOException {
+ this.jGen.writeBoolean(content);
+ }
+
+ @Override
+ public void writeNumber(BigInteger content) throws IOException {
+ this.jGen.writeNumber(content);
+ }
+
+ @Override
+ public void writeNumber(BigDecimal content) throws IOException {
+ this.jGen.writeNumber(content);
+ }
+
+ @Override
+ public void writeNumber(Double content) throws IOException {
+ this.jGen.writeNumber(content);
+ }
+
+ @Override
+ public void writeNumber(Float content) throws IOException {
+ this.jGen.writeNumber(content);
+ }
+
+ @Override
+ public void writeNumber(Integer content) throws IOException {
+ this.jGen.writeNumber(content);
+ }
+
+ @Override
+ public void writeNumber(Long content) throws IOException {
+ this.jGen.writeNumber(content);
+ }
+
+ @Override
+ public void writeNumber(Short content) throws IOException {
+ this.jGen.writeNumber(content);
+ }
+
+ @Override
+ public void writeString(String string) throws IOException {
+ this.jGen.writeString(string);
+ }
+
+ @Override
+ public void writeComment(String comment) throws IOException {
+ try {
+ jGen.writeStringField("j:comment", comment + " /j:comment");
+ } catch (Exception e) {
+ e.printStackTrace();
+ // ignore
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/gui/net/sf/jailer/ui/ColumnMapperDialog.form b/src/main/gui/net/sf/jailer/ui/ColumnMapperDialog.form
index 10ae1e2b3..e40616bf2 100644
--- a/src/main/gui/net/sf/jailer/ui/ColumnMapperDialog.form
+++ b/src/main/gui/net/sf/jailer/ui/ColumnMapperDialog.form
@@ -22,53 +22,129 @@
-
+
-
+
+
+
+
+
+
-
-
-
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -128,20 +204,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/main/gui/net/sf/jailer/ui/ColumnMapperDialog.java b/src/main/gui/net/sf/jailer/ui/ColumnMapperDialog.java
index 433f0ec8a..446bcdac8 100644
--- a/src/main/gui/net/sf/jailer/ui/ColumnMapperDialog.java
+++ b/src/main/gui/net/sf/jailer/ui/ColumnMapperDialog.java
@@ -15,10 +15,13 @@
*/
package net.sf.jailer.ui;
+import java.awt.Container;
import java.awt.GridBagConstraints;
import java.awt.event.ActionListener;
import java.util.Collections;
import java.util.Vector;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import javax.swing.DefaultComboBoxModel;
import javax.swing.ImageIcon;
@@ -28,8 +31,10 @@ import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
import org.w3c.dom.Document;
+import net.sf.jailer.ExecutionContext;
import net.sf.jailer.datamodel.DataModel;
import net.sf.jailer.datamodel.Table;
+import net.sf.jailer.subsetting.ScriptFormat;
import net.sf.jailer.ui.syntaxtextarea.RSyntaxTextAreaWithTheme;
import net.sf.jailer.xml.XmlUtil;
@@ -43,13 +48,16 @@ public class ColumnMapperDialog extends javax.swing.JDialog {
private final java.awt.Frame parent;
private Table table;
private DataModel dataModel;
+ private ScriptFormat scriptFormat;
private boolean ok;
private ParameterSelector parameterSelector;
private String initialTemplate = "";
+ private ExecutionContext executionContext;
/** Creates new form ColumnMapperDialog */
- public ColumnMapperDialog(java.awt.Frame parent, ParameterSelector.ParametersGetter parametersGetter) {
+ public ColumnMapperDialog(java.awt.Frame parent, ParameterSelector.ParametersGetter parametersGetter, ExecutionContext executionContext) {
super(parent, true);
+ this.executionContext = executionContext;
this.parent = parent;
this.mappingField = new RSyntaxTextAreaWithTheme();
mappingField.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_XML);
@@ -70,20 +78,42 @@ public class ColumnMapperDialog extends javax.swing.JDialog {
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.insets = new java.awt.Insets(4, 4, 0, 4);
- jPanel1.add(jScrollPane2, gridBagConstraints);
+ jPanel4.add(jScrollPane2, gridBagConstraints);
jScrollPane2.setViewportView(mappingField);
- AutoCompletion.enable(tableCombobox);
+ JScrollPane tab = new JScrollPane();
+ xmlSketch = new RSyntaxTextAreaWithTheme();
+
+ xmlSketch.setEditable(false);
+ tab.setViewportView(xmlSketch);
+ xmlSketch.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_XML);
+ xmlSketch.setCodeFoldingEnabled(true);
+
+ xmlSketch.setText("");
+ xmlSketch.setCaretPosition(0);
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 1;
+ gridBagConstraints.gridy = 2;
+ gridBagConstraints.weightx = 1;
+ gridBagConstraints.weighty = 1;
+ gridBagConstraints.fill = GridBagConstraints.BOTH;
+ gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
+ gridBagConstraints.insets = new java.awt.Insets(4, 0, 0, 0);
+ jPanel5.add(tab, gridBagConstraints);
+
+ AutoCompletion.enable(tableCombobox);
paramPanel.add(parameterSelector = new ParameterSelector(this, mappingField, parametersGetter));
tableCombobox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(java.awt.event.ActionEvent e) {
try {
- if (table != null) {
- table = dataModel.getTableByDisplayName((String) tableCombobox.getSelectedItem());
+ Table t = dataModel.getTableByDisplayName((String) tableCombobox.getSelectedItem());
+ if (t != null) {
+ table = t;
setMappingFieldText(XmlUtil.build(table.getXmlTemplateAsDocument(null)));
mappingField.discardAllEdits();
+ updateSketch(table);
}
} catch (Exception ex) {
UIUtil.showException(ColumnMapperDialog.this.parent, "Error", ex);
@@ -98,9 +128,11 @@ public class ColumnMapperDialog extends javax.swing.JDialog {
* @param dataModel the data model
* @param table the table
*/
- public boolean edit(DataModel dataModel, Table table) {
+ public boolean edit(DataModel dataModel, Table table, ScriptFormat scriptFormat) {
+ this.table = table;
+ this.dataModel = dataModel;
+ this.scriptFormat = scriptFormat;
parameterSelector.updateParameters();
- this.table = null;
Vector tableNames = new Vector();
for (Table t: dataModel.getTables()) {
tableNames.add(dataModel.getDisplayName(t));
@@ -109,11 +141,13 @@ public class ColumnMapperDialog extends javax.swing.JDialog {
tableCombobox.setModel(new DefaultComboBoxModel(tableNames));
tableCombobox.setMaximumRowCount(40);
tableCombobox.setSelectedItem(dataModel.getDisplayName(table));
- int w = 600, h = 600;
+ int w = 1200, h = 600;
setSize(w, h);
setLocation(Math.max(0, parent.getX() + parent.getWidth() / 2 - w / 2),
Math.max(0, parent.getY() + parent.getHeight() / 2 - h / 2));
+ jSplitPane1.setDividerLocation((int) (w * 0.66));
invalidate();
+ updateSketch(table);
try {
setMappingFieldText(XmlUtil.build(table.getXmlTemplateAsDocument(null)));
initialTemplate = mappingField.getText();
@@ -130,12 +164,53 @@ public class ColumnMapperDialog extends javax.swing.JDialog {
}
mappingField.discardAllEdits();
ok = false;
- this.table = table;
- this.dataModel = dataModel;
setVisible(true);
return ok;
}
+ private RSyntaxTextArea xmlSketch;
+
+ /**
+ * Adds a tab to the sketch-tabbedpane for a given table.
+ *
+ * @param table the table
+ */
+ private void updateSketch(Table table) {
+ String sketch = "";
+ try {
+ sketch = XmlSketchBuilder.buildSketch(table, 1, scriptFormat, executionContext);
+ if (scriptFormat == ScriptFormat.JSON) {
+ Pattern pattern = Pattern.compile("\"j\\:comment\"\\s*\\:\\s*\"(.*)/j\\:comment\"(?:\\,)?");
+ Matcher matcher = pattern.matcher(sketch);
+ boolean result = matcher.find();
+ StringBuffer sb = new StringBuffer();
+ if (result) {
+ do {
+ String comment = matcher.group(1);
+ matcher.appendReplacement(sb, "// " + Matcher.quoteReplacement(comment.replace("\\\"", "\f").replace("\"", "").replace("\f", "\"")));
+ result = matcher.find();
+ } while (result);
+ }
+ matcher.appendTail(sb);
+ sketch = sb.toString();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ sketch = e.getMessage();
+ }
+ if (scriptFormat == ScriptFormat.XML) {
+ xmlSketch.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_XML);
+ }
+ if (scriptFormat == ScriptFormat.JSON) {
+ xmlSketch.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JSON_WITH_COMMENTS);
+ }
+ if (scriptFormat == ScriptFormat.YAML) {
+ xmlSketch.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_YAML);
+ }
+ Container sParent = xmlSketch.getParent();
+ xmlSketch.setText(sketch);
+ }
+
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
@@ -145,20 +220,27 @@ public class ColumnMapperDialog extends javax.swing.JDialog {
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
+ jPanel3 = new javax.swing.JPanel();
jPanel1 = new javax.swing.JPanel();
jLabel1 = new javax.swing.JLabel();
tableCombobox = new JComboBox2();
+ jSplitPane1 = new javax.swing.JSplitPane();
+ jPanel4 = new javax.swing.JPanel();
jLabel2 = new javax.swing.JLabel();
+ paramPanel = new javax.swing.JPanel();
+ jPanel5 = new javax.swing.JPanel();
+ jLabel3 = new javax.swing.JLabel();
jPanel2 = new javax.swing.JPanel();
formatButton = new javax.swing.JButton();
resetButton = new javax.swing.JButton();
okButton = new javax.swing.JButton();
cancelButton = new javax.swing.JButton();
- paramPanel = new javax.swing.JPanel();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setTitle("XML Column Mapping");
- getContentPane().setLayout(new javax.swing.BoxLayout(getContentPane(), javax.swing.BoxLayout.LINE_AXIS));
+ getContentPane().setLayout(new java.awt.GridBagLayout());
+
+ jPanel3.setLayout(new java.awt.GridBagLayout());
jPanel1.setLayout(new java.awt.GridBagLayout());
@@ -178,13 +260,54 @@ public class ColumnMapperDialog extends javax.swing.JDialog {
gridBagConstraints.insets = new java.awt.Insets(4, 0, 0, 0);
jPanel1.add(tableCombobox, gridBagConstraints);
+ jSplitPane1.setDividerLocation(300);
+
+ jPanel4.setLayout(new java.awt.GridBagLayout());
+
jLabel2.setText(" Mapping ");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 10;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.insets = new java.awt.Insets(2, 0, 0, 0);
- jPanel1.add(jLabel2, gridBagConstraints);
+ jPanel4.add(jLabel2, gridBagConstraints);
+
+ paramPanel.setMinimumSize(new java.awt.Dimension(150, 0));
+ paramPanel.setLayout(new javax.swing.BoxLayout(paramPanel, javax.swing.BoxLayout.LINE_AXIS));
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 3;
+ gridBagConstraints.gridy = 20;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
+ jPanel4.add(paramPanel, gridBagConstraints);
+
+ jSplitPane1.setLeftComponent(jPanel4);
+
+ jPanel5.setLayout(new java.awt.GridBagLayout());
+
+ jLabel3.setText("Sketch");
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 1;
+ gridBagConstraints.gridy = 1;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
+ gridBagConstraints.insets = new java.awt.Insets(0, 2, 0, 0);
+ jPanel5.add(jLabel3, gridBagConstraints);
+
+ jSplitPane1.setRightComponent(jPanel5);
+
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 1;
+ gridBagConstraints.gridy = 10;
+ gridBagConstraints.gridwidth = 2;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
+ gridBagConstraints.weightx = 1.0;
+ gridBagConstraints.weighty = 1.0;
+ jPanel1.add(jSplitPane1, gridBagConstraints);
+
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
+ gridBagConstraints.weightx = 1.0;
+ gridBagConstraints.weighty = 1.0;
+ jPanel3.add(jPanel1, gridBagConstraints);
jPanel2.setLayout(new java.awt.GridBagLayout());
@@ -229,23 +352,19 @@ public class ColumnMapperDialog extends javax.swing.JDialog {
jPanel2.add(cancelButton, new java.awt.GridBagConstraints());
gridBagConstraints = new java.awt.GridBagConstraints();
- gridBagConstraints.gridx = 1;
+ gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 30;
gridBagConstraints.gridwidth = 3;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4);
- jPanel1.add(jPanel2, gridBagConstraints);
+ jPanel3.add(jPanel2, gridBagConstraints);
- paramPanel.setMinimumSize(new java.awt.Dimension(150, 0));
- paramPanel.setLayout(new javax.swing.BoxLayout(paramPanel, javax.swing.BoxLayout.LINE_AXIS));
gridBagConstraints = new java.awt.GridBagConstraints();
- gridBagConstraints.gridx = 3;
- gridBagConstraints.gridy = 20;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
- jPanel1.add(paramPanel, gridBagConstraints);
-
- getContentPane().add(jPanel1);
+ gridBagConstraints.weightx = 1.0;
+ gridBagConstraints.weighty = 1.0;
+ getContentPane().add(jPanel3, gridBagConstraints);
pack();
}// //GEN-END:initComponents
@@ -253,7 +372,7 @@ public class ColumnMapperDialog extends javax.swing.JDialog {
private void resetButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_resetButtonActionPerformed
try {
mappingField.beginAtomicEdit();
- setMappingFieldText(XmlUtil.build(table.getXmlTemplateAsDocument(null)));
+ setMappingFieldText(XmlUtil.build(table.getXmlTemplateAsDocument(XmlUtil.build(table.getDefaultXmlTemplate(null)), null)));
mappingField.endAtomicEdit();
mappingField.grabFocus();
} catch (Exception e) {
@@ -299,13 +418,18 @@ public class ColumnMapperDialog extends javax.swing.JDialog {
mappingField.setCaretPosition(0);
}
- // Variables declaration - do not modify//GEN-BEGIN:variables
+ // Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton cancelButton;
private javax.swing.JButton formatButton;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
+ private javax.swing.JLabel jLabel3;
private javax.swing.JPanel jPanel1;
private javax.swing.JPanel jPanel2;
+ private javax.swing.JPanel jPanel3;
+ private javax.swing.JPanel jPanel4;
+ private javax.swing.JPanel jPanel5;
+ private javax.swing.JSplitPane jSplitPane1;
private javax.swing.JButton okButton;
private javax.swing.JPanel paramPanel;
private javax.swing.JButton resetButton;
@@ -326,6 +450,20 @@ public class ColumnMapperDialog extends javax.swing.JDialog {
private static final long serialVersionUID = -5437578641818236294L;
}
+// TODO
+// TODO parameter panel:
+// TODO docu? grundsaetzlich, as link to docu?
+
+// TODO
+// TODO doku: "tutorial"/"preparation": too(ooooo) old!
+
+// TODO
+// TODO H2, Demo DB, somtimes tables get empty- (H2-Bug?)
+// TODO !!! 2.3.230 !!!
+// TODO find work-around
+// TODO symptom: all tables are empty but still exists
+// TODO f.e.: copy demo-db before connecting. Check if demo-db is valid ("select count(*) from Employee" > 0, same with sakila)
+
// TODO
// TODO no timer. "auto update" checkbox + "update" button in dialog. + stale-indication. initially check checkbox iff template is small (heuristically, maybe if size < 10000 char?)
// TODO was: show sketch. use timer for preventing lags bcof expensive sketch creation (1000+ column templates f.e.)
diff --git a/src/main/gui/net/sf/jailer/ui/DbConnectionDialog.java b/src/main/gui/net/sf/jailer/ui/DbConnectionDialog.java
index 062549183..13a7a4d23 100644
--- a/src/main/gui/net/sf/jailer/ui/DbConnectionDialog.java
+++ b/src/main/gui/net/sf/jailer/ui/DbConnectionDialog.java
@@ -891,7 +891,7 @@ public class DbConnectionDialog extends javax.swing.JDialog {
ConnectionInfo ci = new ConnectionInfo(executionContext);
ci.alias = "Demo Scott";
ci.driverClass = "org.h2.Driver";
- ci.jar1 = "lib" + File.separator + "h2-2.2.224.jar";
+ ci.jar1 = "lib" + File.separator + "h2-2.3.230.jar";
ci.url = "jdbc:h2:" + Environment.newFile("demo-scott-h2").getAbsolutePath();
ci.user = "sa";
ci.password = "";
@@ -901,7 +901,7 @@ public class DbConnectionDialog extends javax.swing.JDialog {
ci = new ConnectionInfo(executionContext);
ci.alias = "Demo Sakila";
ci.driverClass = "org.h2.Driver";
- ci.jar1 = "lib" + File.separator + "h2-2.2.224.jar";
+ ci.jar1 = "lib" + File.separator + "h2-2.3.230.jar";
ci.url = "jdbc:h2:" + Environment.newFile("demo-sakila-h2").getAbsolutePath();
ci.user = "sa";
ci.password = "";
diff --git a/src/main/gui/net/sf/jailer/ui/ExtractionModelEditor.form b/src/main/gui/net/sf/jailer/ui/ExtractionModelEditor.form
index 1d114a47e..9180e0150 100644
--- a/src/main/gui/net/sf/jailer/ui/ExtractionModelEditor.form
+++ b/src/main/gui/net/sf/jailer/ui/ExtractionModelEditor.form
@@ -593,7 +593,7 @@
-
+
diff --git a/src/main/gui/net/sf/jailer/ui/ExtractionModelEditor.java b/src/main/gui/net/sf/jailer/ui/ExtractionModelEditor.java
index 011bed43f..785ebc64e 100644
--- a/src/main/gui/net/sf/jailer/ui/ExtractionModelEditor.java
+++ b/src/main/gui/net/sf/jailer/ui/ExtractionModelEditor.java
@@ -48,6 +48,7 @@ import java.io.PrintWriter;
import java.sql.SQLException;
import java.util.ArrayDeque;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
@@ -71,8 +72,6 @@ import javax.swing.DefaultListCellRenderer;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
-import javax.swing.JCheckBox;
-import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
@@ -112,12 +111,6 @@ import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
-import org.apache.commons.lang3.stream.Streams;
-import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
-import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
-
-import com.fasterxml.jackson.annotation.JsonTypeInfo.None;
-
import net.sf.jailer.ExecutionContext;
import net.sf.jailer.database.BasicDataSource;
import net.sf.jailer.database.Session;
@@ -146,7 +139,6 @@ import net.sf.jailer.ui.graphical_view.GraphicalDataModelView;
import net.sf.jailer.ui.scrollmenu.JScrollPopupMenu;
import net.sf.jailer.ui.syntaxtextarea.DataModelBasedSQLCompletionProvider;
import net.sf.jailer.ui.syntaxtextarea.RSyntaxTextAreaWithSQLSyntaxStyle;
-import net.sf.jailer.ui.syntaxtextarea.RSyntaxTextAreaWithTheme;
import net.sf.jailer.ui.syntaxtextarea.SQLCompletionProvider;
import net.sf.jailer.ui.undo.CompensationAction;
import net.sf.jailer.ui.undo.UndoManager;
@@ -300,7 +292,7 @@ public class ExtractionModelEditor extends javax.swing.JPanel implements PlafAwa
return dataModel.getParameters(condition.getText(), extractionModel.additionalSubjects);
}
};
- columnMapperDialog = new ColumnMapperDialog(extractionModelFrame, parametersGetter);
+ columnMapperDialog = new ColumnMapperDialog(extractionModelFrame, parametersGetter, executionContext);
boolean isNew;
if (extractionModelFile == null || !new File(extractionModelFile).exists()) {
needsSave = extractionModelFile != null;
@@ -945,7 +937,7 @@ public class ExtractionModelEditor extends javax.swing.JPanel implements PlafAwa
}
DefaultComboBoxModel formatComboBoxModel = new DefaultComboBoxModel();
- Streams.of(ScriptFormat.values()).forEach(sf -> {
+ Arrays.stream(ScriptFormat.values()).forEach(sf -> {
formatComboBoxModel.addElement(sf);
if (sf.separatorFollowed) {
formatComboBoxModel.addElement(null);
@@ -1459,14 +1451,38 @@ public class ExtractionModelEditor extends javax.swing.JPanel implements PlafAwa
((GridLayout) editorPanel.getLayout()).setVgap(1);
((GridLayout) editorPanel.getLayout()).setColumns(1);
if (false && scriptFormat.isObjectNotation()) { // TODO
- gridBagConstraints = new java.awt.GridBagConstraints();
+
+ JPanel sketchPanel = new JPanel();
+ sketchPanel.setLayout(new java.awt.GridBagLayout());
+
+ jLabel12.setFont(jLabel12.getFont().deriveFont(jLabel12.getFont().getStyle() | java.awt.Font.BOLD));
+ jLabel12.setText(" " + scriptFormat + " Sketches");
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 0;
+ gridBagConstraints.gridwidth = 5;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
+ gridBagConstraints.insets = new java.awt.Insets(8, 0, 4, 0);
+ sketchPanel.add(jLabel12, gridBagConstraints);
+
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 1;
+ gridBagConstraints.gridy = 11;
+ gridBagConstraints.gridwidth = 2;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
+ gridBagConstraints.weightx = 1.0;
+ gridBagConstraints.weighty = 1.0;
+ gridBagConstraints.insets = new java.awt.Insets(0, 8, 0, 0);
+ sketchPanel.add(sketchTabbedPane, gridBagConstraints);
+
+ gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 3;
gridBagConstraints.weightx = 1;
gridBagConstraints.weighty = 0.6;
gridBagConstraints.fill = GridBagConstraints.BOTH;
gridBagConstraints.insets = new Insets(0, 0, 0, 0);
- panel2.add(xmlMappingPanel, gridBagConstraints);
+ panel2.add(sketchPanel, gridBagConstraints);
// editorPanel.add(xmlMappingPanel);
((GridLayout) editorPanel.getLayout()).setRows(1);
} else {
@@ -1559,7 +1575,7 @@ public class ExtractionModelEditor extends javax.swing.JPanel implements PlafAwa
jPanel8 = new javax.swing.JPanel();
jLabel7 = new javax.swing.JLabel();
jPanel10 = new javax.swing.JPanel();
- exportFormat = new javax.swing.JComboBox();
+ exportFormat = new JComboBox2();
exportButton = new javax.swing.JButton();
openXmlSettings = new javax.swing.JButton();
jLabel10 = new javax.swing.JLabel();
@@ -1581,7 +1597,7 @@ public class ExtractionModelEditor extends javax.swing.JPanel implements PlafAwa
jLabel1 = new javax.swing.JLabel();
jLabel2 = new javax.swing.JLabel();
jLabel3 = new javax.swing.JLabel();
- aggregationCombobox = new javax.swing.JComboBox();
+ aggregationCombobox = new JComboBox2();
tagField = new javax.swing.JTextField();
jPanel5 = new javax.swing.JPanel();
xmlTagApply = new javax.swing.JButton();
@@ -1714,7 +1730,7 @@ public class ExtractionModelEditor extends javax.swing.JPanel implements PlafAwa
layeredPane.setLayer(focusPanel, javax.swing.JLayeredPane.PALETTE_LAYER);
layeredPane.add(focusPanel);
- focusPanel.setBounds(0, 0, 359, 32);
+ focusPanel.setBounds(0, 0, 345, 32);
rightBorderPanel.setOpaque(false);
rightBorderPanel.setLayout(new java.awt.GridBagLayout());
@@ -1851,11 +1867,7 @@ public class ExtractionModelEditor extends javax.swing.JPanel implements PlafAwa
exportFormat.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
exportFormat.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
- if (exportFormat.getSelectedItem() == null) {
- UIUtil.invokeLater(() -> exportFormat.setSelectedItem(scriptFormat));
- } else {
- onExportModusChanged(evt);
- }
+ onExportModusChanged(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
@@ -1960,7 +1972,7 @@ public class ExtractionModelEditor extends javax.swing.JPanel implements PlafAwa
gridBagConstraints.gridy = 7;
gridBagConstraints.gridwidth = 4;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
- gridBagConstraints.insets = new java.awt.Insets(4, 0, 4, 0);
+ gridBagConstraints.insets = new java.awt.Insets(4, 0, 6, 0);
jPanel3.add(jPanel16, gridBagConstraints);
jPanel17.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.CENTER, 5, 8));
@@ -2976,46 +2988,23 @@ public class ExtractionModelEditor extends javax.swing.JPanel implements PlafAwa
* Updates the XML sketch component.
*/
private void updateSketch() {
- try {
- sketchTabbedPane.removeAll();
-
- if (currentAssociation != null) {
- addSketchTab(currentAssociation.source);
- if (currentAssociation.source != currentAssociation.destination) {
- addSketchTab(currentAssociation.destination);
- }
- sketchTabbedPane.setSelectedIndex(0);
- } else {
- if (root != null) {
- addSketchTab(root);
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- /**
- * Adds a tab to the sketch-tabbedpane for a given table.
- *
- * @param table the table
- */
- private void addSketchTab(Table table) throws Exception {
- JScrollPane tab = new JScrollPane();
- RSyntaxTextArea xmlSketch = new RSyntaxTextAreaWithTheme();
-
- xmlSketch.setEditable(false);
- tab.setViewportView(xmlSketch);
- xmlSketch.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_XML);
- xmlSketch.setCodeFoldingEnabled(true);
-
- String tabName = null;
- String sketch = "";
- tabName = dataModel.getDisplayName(table);
- sketch = XmlSketchBuilder.buildSketch(table, 1);
- xmlSketch.setText(sketch);
- xmlSketch.setCaretPosition(0);
- sketchTabbedPane.addTab(tabName, tab);
+// try {
+// sketchTabbedPane.removeAll();
+//
+// if (currentAssociation != null) {
+// addSketchTab(currentAssociation.source);
+// if (currentAssociation.source != currentAssociation.destination) {
+// addSketchTab(currentAssociation.destination);
+// }
+// sketchTabbedPane.setSelectedIndex(0);
+// } else {
+// if (root != null) {
+// addSketchTab(root);
+// }
+// }
+// } catch (Exception e) {
+// e.printStackTrace();
+// }
}
/**
@@ -3925,7 +3914,7 @@ public class ExtractionModelEditor extends javax.swing.JPanel implements PlafAwa
public void openColumnMapper(Table table) {
String old = table.getXmlTemplate();
columnMapperDialog.setTitle(scriptFormat + " Column Mapping");
- if (columnMapperDialog.edit(dataModel, table)) {
+ if (columnMapperDialog.edit(dataModel, table, scriptFormat)) {
String template = table.getXmlTemplate();
table.setXmlTemplate(old);
changeXmlTemplate(table, template);
@@ -4161,7 +4150,7 @@ public class ExtractionModelEditor extends javax.swing.JPanel implements PlafAwa
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton activateDesictionPendingButton;
private javax.swing.JButton additionalSubjectsButton;
- private javax.swing.JComboBox aggregationCombobox;
+ private JComboBox2 aggregationCombobox;
private javax.swing.JLabel assocStatsLabel;
private javax.swing.JLabel associatedWith;
javax.swing.JTextField condition;
@@ -4169,7 +4158,7 @@ public class ExtractionModelEditor extends javax.swing.JPanel implements PlafAwa
private javax.swing.JLabel dependsOn;
private javax.swing.JPanel editorPanel;
public javax.swing.JButton exportButton;
- private javax.swing.JComboBox exportFormat;
+ private JComboBox2 exportFormat;
private javax.swing.JPanel focusLabelPanel;
javax.swing.JPanel focusPanel;
private javax.swing.JPanel graphContainer;
diff --git a/src/main/gui/net/sf/jailer/ui/UIUtil.java b/src/main/gui/net/sf/jailer/ui/UIUtil.java
index f9699ec5d..4150f8ec7 100644
--- a/src/main/gui/net/sf/jailer/ui/UIUtil.java
+++ b/src/main/gui/net/sf/jailer/ui/UIUtil.java
@@ -152,6 +152,7 @@ import net.sf.jailer.datamodel.DataModel;
import net.sf.jailer.datamodel.Table;
import net.sf.jailer.ddl.DDLCreator;
import net.sf.jailer.progress.ProgressListener;
+import net.sf.jailer.subsetting.ObjectNotationOutputException;
import net.sf.jailer.subsetting.RowLimitExceededException;
import net.sf.jailer.ui.databrowser.DetailsView;
import net.sf.jailer.ui.databrowser.Row;
@@ -864,7 +865,7 @@ public class UIUtil {
if (t instanceof DataModel.NoPrimaryKeyException || t instanceof CycleFinder.CycleFoundException) {
context = EXCEPTION_CONTEXT_USER_ERROR;
}
- if (t instanceof RowLimitExceededException) {
+ if (t instanceof RowLimitExceededException || t instanceof ObjectNotationOutputException) {
context = EXCEPTION_CONTEXT_USER_WARNING;
}
if (t instanceof SqlException) {
diff --git a/src/main/gui/net/sf/jailer/ui/XmlSettingsDialog.form b/src/main/gui/net/sf/jailer/ui/XmlSettingsDialog.form
index 23c3bffa2..c79ba5b55 100644
--- a/src/main/gui/net/sf/jailer/ui/XmlSettingsDialog.form
+++ b/src/main/gui/net/sf/jailer/ui/XmlSettingsDialog.form
@@ -147,13 +147,14 @@
-
+
-
+
+
@@ -208,13 +209,13 @@
-
+
-
+
diff --git a/src/main/gui/net/sf/jailer/ui/XmlSettingsDialog.java b/src/main/gui/net/sf/jailer/ui/XmlSettingsDialog.java
index 770f7c0ba..c445da43b 100644
--- a/src/main/gui/net/sf/jailer/ui/XmlSettingsDialog.java
+++ b/src/main/gui/net/sf/jailer/ui/XmlSettingsDialog.java
@@ -42,8 +42,8 @@ public class XmlSettingsDialog extends javax.swing.JDialog {
setModal(true);
ButtonGroup buttonGroup = new ButtonGroup();
- buttonGroup.add(singleRoot);
buttonGroup.add(multipleRoots);
+ buttonGroup.add(singleRoot);
buttonGroup = new ButtonGroup();
buttonGroup.add(include);
@@ -91,8 +91,8 @@ public class XmlSettingsDialog extends javax.swing.JDialog {
rootTag.setVisible(scriptFormat == ScriptFormat.XML);
xmlRootTagLabel.setVisible(scriptFormat == ScriptFormat.XML);
- multipleRoots.setSelected(!xmlSettings.singleRoot);
singleRoot.setSelected(xmlSettings.singleRoot);
+ multipleRoots.setSelected(!xmlSettings.singleRoot);
ignore.setSelected(xmlSettings.ignoreNonAggregated);
include.setSelected(xmlSettings.includeNonAggregated);
disallow.setSelected(xmlSettings.disallowNonAggregated);
@@ -226,12 +226,12 @@ public class XmlSettingsDialog extends javax.swing.JDialog {
rootTag = new javax.swing.JTextField();
dateExample = new javax.swing.JLabel();
timestampExample = new javax.swing.JLabel();
- multipleRoots = new javax.swing.JCheckBox();
+ singleRoot = new javax.swing.JCheckBox();
jPanel2 = new javax.swing.JPanel();
Ok = new javax.swing.JButton();
cancelButton = new javax.swing.JButton();
xmlRootTagLabel1 = new javax.swing.JLabel();
- singleRoot = new javax.swing.JCheckBox();
+ multipleRoots = new javax.swing.JCheckBox();
include = new javax.swing.JCheckBox();
xmlRootTagLabel2 = new javax.swing.JLabel();
xmlRootTagLabel3 = new javax.swing.JLabel();
@@ -343,11 +343,16 @@ public class XmlSettingsDialog extends javax.swing.JDialog {
gridBagConstraints.insets = new java.awt.Insets(0, 8, 0, 8);
jPanel3.add(timestampExample, gridBagConstraints);
- multipleRoots.setText("Single Object");
- multipleRoots.setToolTipText("Writes a single root/subject object with all its aggregated sub-objects.
The export process fails if more than one such object exists.");
- multipleRoots.addItemListener(new java.awt.event.ItemListener() {
+ singleRoot.setText("Single Object");
+ singleRoot.setToolTipText("Writes a single root/subject object with all its aggregated sub-objects.
The export process fails if more than one such object exists.");
+ singleRoot.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
- multipleRootsItemStateChanged(evt);
+ singleRootItemStateChanged(evt);
+ }
+ });
+ singleRoot.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ singleRootActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
@@ -355,7 +360,7 @@ public class XmlSettingsDialog extends javax.swing.JDialog {
gridBagConstraints.gridy = 20;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.insets = new java.awt.Insets(8, 0, 0, 0);
- jPanel3.add(multipleRoots, gridBagConstraints);
+ jPanel3.add(singleRoot, gridBagConstraints);
jPanel2.setLayout(new java.awt.GridBagLayout());
@@ -403,18 +408,18 @@ public class XmlSettingsDialog extends javax.swing.JDialog {
gridBagConstraints.insets = new java.awt.Insets(8, 0, 0, 0);
jPanel3.add(xmlRootTagLabel1, gridBagConstraints);
- singleRoot.setText("Multiple Objects (Array)");
- singleRoot.setToolTipText("Writes an array/collection of all root/subject objects with all their aggregated sub-objects.");
- singleRoot.addItemListener(new java.awt.event.ItemListener() {
+ multipleRoots.setText("Multiple Objects (Array)");
+ multipleRoots.setToolTipText("Writes an array/collection of all root/subject objects with all their aggregated sub-objects.");
+ multipleRoots.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
- singleRootItemStateChanged(evt);
+ multipleRootsItemStateChanged(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 10;
gridBagConstraints.gridy = 22;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
- jPanel3.add(singleRoot, gridBagConstraints);
+ jPanel3.add(multipleRoots, gridBagConstraints);
include.setText("Include");
include.setToolTipText("Write out all objects that are not aggregated in any other object at root level.");
@@ -508,14 +513,14 @@ public class XmlSettingsDialog extends javax.swing.JDialog {
dispose();
}//GEN-LAST:event_cancelButtonActionPerformed
- private void multipleRootsItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_multipleRootsItemStateChanged
- rootTag.setEditable(!multipleRoots.isSelected());
- }//GEN-LAST:event_multipleRootsItemStateChanged
-
private void singleRootItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_singleRootItemStateChanged
- // TODO add your handling code here:
+ rootTag.setEditable(!multipleRoots.isSelected());
}//GEN-LAST:event_singleRootItemStateChanged
+ private void multipleRootsItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_multipleRootsItemStateChanged
+ rootTag.setEditable(!multipleRoots.isSelected());
+ }//GEN-LAST:event_multipleRootsItemStateChanged
+
private void includeItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_includeItemStateChanged
// TODO add your handling code here:
}//GEN-LAST:event_includeItemStateChanged
@@ -527,6 +532,10 @@ public class XmlSettingsDialog extends javax.swing.JDialog {
private void disallowItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_disallowItemStateChanged
// TODO add your handling code here:
}//GEN-LAST:event_disallowItemStateChanged
+
+ private void singleRootActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_singleRootActionPerformed
+ // TODO add your handling code here:
+ }//GEN-LAST:event_singleRootActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton Ok;
diff --git a/src/main/gui/net/sf/jailer/ui/XmlSketchBuilder.java b/src/main/gui/net/sf/jailer/ui/XmlSketchBuilder.java
index 28b352bd6..b341cf6df 100644
--- a/src/main/gui/net/sf/jailer/ui/XmlSketchBuilder.java
+++ b/src/main/gui/net/sf/jailer/ui/XmlSketchBuilder.java
@@ -15,7 +15,11 @@
*/
package net.sf.jailer.ui;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -31,11 +35,15 @@ import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
+import net.sf.jailer.ExecutionContext;
import net.sf.jailer.datamodel.AggregationSchema;
import net.sf.jailer.datamodel.Association;
import net.sf.jailer.datamodel.Cardinality;
import net.sf.jailer.datamodel.Table;
+import net.sf.jailer.subsetting.ScriptFormat;
+import net.sf.jailer.xml.XmlRowWriter;
import net.sf.jailer.xml.XmlUtil;
+import net.sf.jailer.xml.XmlUtil.ObjectNotationTransformerHandler;
/**
* Builds XML sketches.
@@ -50,19 +58,53 @@ public class XmlSketchBuilder {
* @param table the table
* @return xml sketch for table
*/
- public static String buildSketch(Table table, int depth) throws Exception {
+ public static String buildSketch(Table table, int depth, ScriptFormat scriptFormat, ExecutionContext executionContext) throws Exception {
if (table == null) {
return "";
}
Document sketch = table.getXmlTemplateAsDocument(null);
if (sketch.getChildNodes().getLength() > 0 && sketch.getChildNodes().item(0) instanceof Element) {
- insertAssociationSketch(sketch.getChildNodes().item(0), table, sketch, depth);
+ insertAssociationSketch(sketch.getChildNodes().item(0), table, sketch, scriptFormat, depth);
}
- return XmlUtil.buildOmitDeclaration(sketch);
+ String result = XmlUtil.buildOmitDeclaration(sketch);
+ if (scriptFormat != ScriptFormat.XML) {
+ OutputStream out = new ByteArrayOutputStream();
+ ObjectNotationTransformerHandler th = XmlUtil.createObjectNotationTransformerHandler("", "", new OutputStreamWriter(out, Charset.defaultCharset()), true, scriptFormat, executionContext);
+ XmlRowWriter xmlRowWriter = new XmlRowWriter(out, null, null, null, null, scriptFormat, Charset.defaultCharset(), th, executionContext);
+ XmlUtil.visitDocumentNodes(XmlUtil.parse(result), xmlRowWriter.new XmlWritingNodeVisitor(null, null, table, null, null) {
+ @Override
+ protected Object toContent(String text, boolean returnNull) {
+ return "...";
+ }
+ @Override
+ public void visitAssociationElement(String associationName, String name) {
+ if (name != null) {
+ table.associations.stream().filter(a -> associationName.equals(a.getName())).findAny()
+ .ifPresent(a -> {
+ th.associationSketch(a, associationName, name);
+ });
+ }
+ }
+ });
+ th.endDocument();
+ result = out.toString();
+ }
+ return result;
}
- private static void insertAssociationSketch(Node node, Table table, Document doc, int depth) throws DOMException, ParserConfigurationException, SAXException, IOException {
+ private static void insertAssociationSketch(Node node, Table table, Document doc, ScriptFormat scriptFormat, int depth) throws DOMException, ParserConfigurationException, SAXException, IOException {
NodeList children = node.getChildNodes();
+ if (node instanceof Element) {
+ Node a0 = ((Element) node).getAttributes().item(0);
+ if (a0 != null && a0.getNodeName() != null && a0.getNodeName().startsWith("j:")) {
+ ((Element) node).removeAttribute(a0.getNodeName());
+ }
+ Node ch = ((Element) node).getFirstChild();
+ if (ch != null && ch.getTextContent().trim().startsWith("SQL:")) {
+ ((Element) node).removeChild(ch);
+ ((Element) node).appendChild(doc.createTextNode("..."));
+ }
+ }
int i = 0;
while (i < children.getLength()) {
if (children.item(i) instanceof Element) {
@@ -77,17 +119,22 @@ public class XmlSketchBuilder {
}
}
}
- if (association != null && depth < 3) {
- Node[] ae = insertAssociationSketch(association, doc, depth + 1);
+ if (association != null && depth < 5) {
+ Node[] ae = insertAssociationSketch(association, doc, scriptFormat, depth + 1);
if (ae != null) {
for (Node n: ae) {
node.insertBefore(doc.importNode(n, true), e);
++i;
}
}
- }
- node.removeChild(e);
+ }
+ if (scriptFormat == ScriptFormat.XML) {
+ node.removeChild(e);
+ } else {
+ ++i;
+ }
} else {
+ insertAssociationSketch(e, table, doc, scriptFormat, depth + 1);
++i;
}
} else {
@@ -96,37 +143,39 @@ public class XmlSketchBuilder {
}
}
- private static Node[] insertAssociationSketch(Association association, Document doc, int depth) throws ParserConfigurationException, SAXException, IOException {
- if (association.getAggregationSchema() == AggregationSchema.EXPLICIT_LIST) {
- Element e1 = doc.createElement(association.getAggregationTagName());
- Element e2 = doc.createElement(association.destination.getUnqualifiedName().toLowerCase(Locale.ENGLISH));
- e1.appendChild(e2);
- if (association.getCardinality() != Cardinality.MANY_TO_ONE && association.getCardinality() != Cardinality.ONE_TO_ONE) {
- e1.appendChild(doc.createComment("..."));
+ private static Node[] insertAssociationSketch(Association association, Document doc, ScriptFormat scriptFormat, int depth) throws ParserConfigurationException, SAXException, IOException {
+ if (scriptFormat == ScriptFormat.XML) {
+ if (association.getAggregationSchema() == AggregationSchema.EXPLICIT_LIST) {
+ Element e1 = doc.createElement(association.getAggregationTagName());
+ Element e2 = doc.createElement(association.destination.getUnqualifiedName().toLowerCase(Locale.ENGLISH));
+ e1.appendChild(e2);
+ // if (association.getCardinality() != Cardinality.MANY_TO_ONE && association.getCardinality() != Cardinality.ONE_TO_ONE) {
+ e1.appendChild(doc.createTextNode("..."));
+ // }
+ return new Node[] { e1 };
}
- return new Node[] { e1 };
- }
- else if (association.getAggregationSchema() == AggregationSchema.IMPLICIT_LIST) {
- Element e1 = doc.createElement(association.getAggregationTagName());
- if (association.getCardinality() != Cardinality.MANY_TO_ONE && association.getCardinality() != Cardinality.ONE_TO_ONE) {
- Node c = doc.createComment("...");
- return new Node[] { e1, c };
+ else if (association.getAggregationSchema() == AggregationSchema.IMPLICIT_LIST) {
+ Element e1 = doc.createElement(association.getAggregationTagName());
+ // if (association.getCardinality() != Cardinality.MANY_TO_ONE && association.getCardinality() != Cardinality.ONE_TO_ONE) {
+ e1.appendChild(doc.createTextNode("..."));
+ return new Node[] { e1 };
+ // }
+ // return new Node[] { e1 };
+ } else if (association.getAggregationSchema() == AggregationSchema.FLAT) {
+ Document sketch = association.destination.getXmlTemplateAsDocument(null);
+ List nodes = new ArrayList();
+ if (sketch.getChildNodes().getLength() > 0 && sketch.getChildNodes().item(0) instanceof Element) {
+ insertAssociationSketch(sketch.getChildNodes().item(0), association.destination, sketch, scriptFormat, depth + 1);
+ }
+ NodeList children = sketch.getChildNodes().item(0).getChildNodes();
+ for (int i = 0; i < children.getLength(); ++i) {
+ nodes.add(children.item(i));
+ }
+ // if (association.getCardinality() != Cardinality.MANY_TO_ONE && association.getCardinality() != Cardinality.ONE_TO_ONE) {
+ // nodes.add(sketch.createTextNode("..."));
+ // }
+ return nodes.toArray(new Node[nodes.size()]);
}
- return new Node[] { e1 };
- } else if (association.getAggregationSchema() == AggregationSchema.FLAT) {
- Document sketch = association.destination.getXmlTemplateAsDocument(null);
- List nodes = new ArrayList();
- if (sketch.getChildNodes().getLength() > 0 && sketch.getChildNodes().item(0) instanceof Element) {
- insertAssociationSketch(sketch.getChildNodes().item(0), association.destination, sketch, depth + 1);
- }
- NodeList children = sketch.getChildNodes().item(0).getChildNodes();
- for (int i = 0; i < children.getLength(); ++i) {
- nodes.add(children.item(i));
- }
- if (association.getCardinality() != Cardinality.MANY_TO_ONE && association.getCardinality() != Cardinality.ONE_TO_ONE) {
- nodes.add(sketch.createComment("..."));
- }
- return nodes.toArray(new Node[nodes.size()]);
}
return null;
}