All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
de.julielab.xmlData.config.FieldConfig Maven / Gradle / Ivy
/**
* FieldDefinition.java
*
* Copyright (c) 2011, JULIE Lab.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
*
* Author: faessler
*
* Current version: 1.0
* Since version: 1.0
*
* Creation date: 11.03.2011
**/
package de.julielab.xmlData.config;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ximpleware.AutoPilot;
import com.ximpleware.EOFException;
import com.ximpleware.EncodingException;
import com.ximpleware.EntityException;
import com.ximpleware.NavException;
import com.ximpleware.ParseException;
import com.ximpleware.PilotException;
import com.ximpleware.VTDException;
import com.ximpleware.VTDGen;
import com.ximpleware.VTDNav;
import com.ximpleware.XPathEvalException;
import com.ximpleware.XPathParseException;
import de.julielab.xml.JulieXMLConstants;
import de.julielab.xml.JulieXMLTools;
import de.julielab.xmlData.Constants;
/**
* This class holds the definition of fields for the database table to work
* with. The definition was read from the configuration XML file.
*
* @author faessler
*/
public class FieldConfig extends ConfigBase {
private final static Logger log = LoggerFactory.getLogger(FieldConfig.class);
private static final String XPATH_CONF_SCHEMA_INFO = "//DBSchemaInformation";
private static final String XPATH_CONF_SCHEMES = XPATH_CONF_SCHEMA_INFO + "/tableSchemas";
private static final String XPATH_CONF_SCHEME = XPATH_CONF_SCHEMES + "/tableSchema";
private static final String XPATH_CONF_FIELD_TEMPLATE = XPATH_CONF_SCHEME
+ "[@name='%s']/field";
private static final String XPATH_CONF_ACTIVE_SCHEME_TEMPLATE = XPATH_CONF_SCHEME
+ "[@name='%s']";
private List> fields;
private Map> fieldNameMap;
private String forEachXPath;
private String[] primaryKey;
private String[] columns;
private String[] columnsToRetrieve;
private String timestampFieldName = null;
private List primaryKeyFieldNumbers = null;
private byte[] configData;
/**
* @return the name
*/
public String getName() {
return name;
}
public FieldConfig(byte[] configData, String schemaName) throws VTDException {
this.configData = configData;
this.name = schemaName;
buildFields(configData, schemaName);
}
public FieldConfig(List> fields, String forEachXPath, String schemaName) {
this.forEachXPath = forEachXPath;
this.name = schemaName;
this.fields = fields;
fieldNameMap = new HashMap<>();
for (Map field : fields) {
String name = field.get(JulieXMLConstants.NAME);
if (name == null)
throw new IllegalArgumentException("The passed field configuration contains the field \"" + field + "\" " +
"that does specify the required \"" + JulieXMLConstants.NAME + "\" property");
if (field.get(JulieXMLConstants.TYPE) == null)
throw new IllegalArgumentException("The passed field configuration contains the field \"" + field + "\" " +
"that does specify the required \"" + JulieXMLConstants.TYPE + "\" property");
fieldNameMap.put(name, field);
if (field.get(JulieXMLConstants.TIMESTAMP) != null && Boolean.parseBoolean(field.get(JulieXMLConstants.TIMESTAMP)))
timestampFieldName = name;
}
primaryKey = fields.stream().
filter(field -> Boolean.parseBoolean((field.get(JulieXMLConstants.PRIMARY_KEY)))).
map(field -> field.get(JulieXMLConstants.NAME)).
toArray(String[]::new);
columns = fields.stream().
map(field -> field.get(JulieXMLConstants.NAME)).
toArray(String[]::new);
columnsToRetrieve = fields.stream().
filter(field -> Boolean.parseBoolean((field.get(JulieXMLConstants.RETRIEVE)))).
map(field -> field.get(JulieXMLConstants.NAME)).
toArray(String[]::new);
primaryKeyFieldNumbers = new ArrayList<>();
for (int i = 0; i < fields.size(); i++) {
Map field = fields.get(i);
if (Boolean.parseBoolean((field.get(JulieXMLConstants.PRIMARY_KEY))))
primaryKeyFieldNumbers.add(i);
}
}
private void buildFields(byte[] mergedConfData, String activeSchemeName)
throws EncodingException, EOFException, EntityException, ParseException,
XPathParseException, XPathEvalException, NavException, PilotException {
VTDGen vg = new VTDGen();
vg.setDoc(mergedConfData);
vg.parse(true);
VTDNav vn = vg.getNav();
AutoPilot ap = new AutoPilot(vn);
ap.selectXPath(String.format(XPATH_CONF_ACTIVE_SCHEME_TEMPLATE, activeSchemeName));
if (ap.evalXPath() != -1) {
int attrIndex = vn.getAttrVal(JulieXMLConstants.FOR_EACH);
if (attrIndex != -1)
forEachXPath = vn.toString(attrIndex);
}
ap.selectXPath(String.format(XPATH_CONF_FIELD_TEMPLATE, activeSchemeName));
AutoPilot ap2 = new AutoPilot(vn);
fields = new ArrayList>();
fieldNameMap = new HashMap>();
boolean xPathFound = false;
while (ap.evalXPath() != -1) {
xPathFound = true;
Map field = new LinkedHashMap();
String fieldName = null;
int i = -1;
ap2.selectAttr("*");
while ((i = ap2.iterateAttr()) != -1) {
String attrName = vn.toString(i);
String attrValue = vn.toRawString(i + 1);
// I actually don't know if there still are unsupported types since in the DataBaseConnector we just set objects
if (attrName.equals(JulieXMLConstants.TYPE))
if (!isKnownType(attrValue))
throw new IllegalArgumentException("Type \"" + attrValue
+ "\" is not supported by this tool.");
field.put(attrName, attrValue);
if (attrName.equals(JulieXMLConstants.NAME))
fieldName = attrValue;
if (attrName.equals(JulieXMLConstants.TIMESTAMP) && Boolean.parseBoolean(attrValue))
timestampFieldName = fieldName;
}
// These fields potentially still contain field
// definitions which do not rely on the XML document
// itself but e.g. on the file name. These fields
// are treated in the "prepare" method.
fields.add(field);
fieldNameMap.put(fieldName, field);
}
if (!xPathFound)
throw new TableSchemaDoesNotExistException("No field schema with name \""
+ activeSchemeName + "\" was found.");
}
public List> getFields() {
return fields;
}
public Map getField(String fieldName) {
return fieldNameMap.get(fieldName);
}
public String getForEachXPath() {
return forEachXPath;
}
public void setForEachXPath(String forEachXPath) {
this.forEachXPath = forEachXPath;
}
public static boolean isKnownType(String type) {
return isStringType(type) || isTimestampWithoutTZType(type) || isStringTypeArray(type)
|| isIntegerType(type) || isBooleanType(type) || isBinaryDataType(type) || isXmlType(type);
}
public static boolean isBinaryDataType(String type) {
return type.equals(Constants.TYPE_BINARY_DATA);
}
/**
* @param type
* @return
*/
public static boolean isStringTypeArray(String type) {
return type.equals(Constants.TYPE_TEXT_ARRAY) || type.equals(Constants.TYPE_VARCHAR_ARRAY);
}
public static boolean isXmlType(String type) {
return type.equals(Constants.TYPE_XML);}
/**
* @param type
* @return
*/
public static boolean isBooleanType(String type) {
return type.equals(Constants.TYPE_BOOLEAN);
}
/**
* Returns true if the string type
equals the SQL
* "timestamp without time zone" type.
*
* @param type
* String to test.
* @return True if type
denotes a timestamp type without
* timezone information.
*/
public static boolean isTimestampWithoutTZType(String type) {
return type.equals(Constants.TYPE_TIMESTAMP_WITHOUT_TIMEZONE);
}
public boolean isOfTimestampWithoutTZType(String fieldName) {
return isTimestampWithoutTZType(fieldNameMap.get(fieldName).get(JulieXMLConstants.TYPE));
}
public static boolean isStringType(String type) {
return type.equals(Constants.TYPE_TEXT);
}
/**
* @param type
* @return
*/
public static boolean isIntegerType(String type) {
return type.equals(Constants.TYPE_INTEGER);
}
public boolean isOfStringType(String fieldName) {
return isStringType(fieldNameMap.get(fieldName).get(JulieXMLConstants.TYPE));
}
public boolean isOfStringType(Map field) {
return isStringType(field.get(JulieXMLConstants.TYPE));
}
public boolean isOfIntegerType(Map field) {
return isIntegerType(field.get(JulieXMLConstants.TYPE));
}
public boolean isOfBinaryDataType(Map field) {
return isBinaryDataType(field.get(JulieXMLConstants.TYPE));
}
/**
*
* @return - An Array with the names off all primary keys
*/
public String[] getPrimaryKey() {
if (primaryKey == null) {
primaryKey = getPrimaryKeyFields().
map(field -> field.get(JulieXMLConstants.NAME)).
toArray(String[]::new);
}
return primaryKey;
}
public Stream> getPrimaryKeyFields() {
return fields.stream().filter(field -> Boolean.parseBoolean(field.get(JulieXMLConstants.PRIMARY_KEY)));
}
/**
*
* @return - The indices of those fields which are primary keys, beginning
* with 0
*/
public List getPrimaryKeyFieldNumbers() {
if (primaryKeyFieldNumbers == null) {
List fieldNumbers = new ArrayList();
int i = 0;
for (Map field : fields) {
if (Boolean.parseBoolean(field.get(JulieXMLConstants.PRIMARY_KEY)))
fieldNumbers.add(i);
++i;
}
primaryKeyFieldNumbers = fieldNumbers;
}
return primaryKeyFieldNumbers;
}
public String[] getColumnsToRetrieve() {
if (columnsToRetrieve == null) {
List retrieveColumnNames = new ArrayList();
for (Map field : fields) {
if (Boolean.parseBoolean(field.get(JulieXMLConstants.RETRIEVE)))
retrieveColumnNames.add(field.get(JulieXMLConstants.NAME));
}
columnsToRetrieve = new String[retrieveColumnNames.size()];
retrieveColumnNames.toArray(columnsToRetrieve);
}
return columnsToRetrieve;
}
public List> getFieldsToRetrieve() {
List> fieldsToRetrieve = new ArrayList>();
for (Map field : fields) {
if (Boolean.parseBoolean(field.get(JulieXMLConstants.RETRIEVE)))
fieldsToRetrieve.add(field);
}
return fieldsToRetrieve;
}
/**
* Returns the names of the columns forming the primary key in a CSV format.
*
* This method calls {@link #getPrimaryKey()} to obtain the list of primary
* key column names. It then builds a string consisting of these names
* separated by commas and returns this string.
*
* Example: If the primary key columns are "pmid" and "systemID", the string
* returned would be "pmid,systemID".
*
* @return A comma separated list of the column names which form the primary
* key in this table scheme.
*/
public String getPrimaryKeyString() {
return StringUtils.join(getPrimaryKey(), ",");
}
/**
* Takes an array of format strings according to {@link String#format(String, Object...)} with a single %s symbol.
* The number of format
* string must be equal to the number of primary key elements of this table schema definition. Then, for the
* i
th format string, the i
th primary key element is applied.
* @param fmtStrs The format string to fill with primary key elements, one format string per primary key element.
* @return An array of strings corresponding to the format strings filled with the primary key elements.
* @see {@link String#format(String, Object...)}
*/
public String[] expandPKNames(String[] fmtStrs) {
return JulieXMLTools.expandArrayEntries(getPrimaryKey(), fmtStrs);
}
/**
* Applies each primary key element to the format string and returns the results as array. Each result element
* corresponds to one primary key element applied to the format string.
* @param fmtStr The format string to be filled with the primary key elements.
* @return All results corresponding to applying each primary key element once to the given format string.
*/
public String[] expandPKNames(String fmtStr) {
return JulieXMLTools.expandArrayEntries(getPrimaryKey(), fmtStr);
}
public String getTimestampFieldName() {
return timestampFieldName;
}
@Override
public String toString() {
List strList = new ArrayList();
strList.add("Schema configuration for \"" + name + "\":");
for (Map field : fields) {
strList.add("\n");
strList.add("Field \"" + field.get(JulieXMLConstants.NAME) + "\":");
for (String attr : field.keySet()) {
strList.add(attr + "=\"" + field.get(attr) + "\"");
}
}
return StringUtils.join(strList, "\n");
}
public String getConfigText() {
if (configData != null)
return new String(configData);
return "";
}
private final String name;
public String[] getColumns() {
if (columns == null) {
List columnNames = new ArrayList();
for (Map field : fields) {
columnNames.add(field.get(JulieXMLConstants.NAME));
}
columns = new String[columnNames.size()];
columnNames.toArray(columns);
}
return columns;
}
public static Map createField(String... configuration) {
if (configuration.length % 2 == 1)
throw new IllegalArgumentException("An even number of arguments is required. The even indexes " +
"are field property keys, the odd indexes are the values to the previous key.");
Map field = new HashMap<>();
for (int i = 0; i < configuration.length; i = i + 2) {
String s = configuration[i];
field.put(s, configuration[i + 1]);
}
return field;
}
}