/**
* Copyright (C) 2014 Stratio (http://stratio.com)
*
* 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 com.stratio.ingestion.sink.jdbc;
import com.google.common.base.*;
import org.apache.flume.Event;
import org.jooq.*;
import org.jooq.impl.DefaultDataType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class TemplateQueryGenerator implements QueryGenerator {
private static final Logger log = LoggerFactory.getLogger(TemplateQueryGenerator.class);
private static final Pattern PARAMETER_PATTERN = Pattern.compile("\\$\\{(?<part>[^\\s.{}]+)(?:\\.(?<header>[^\\s.{}]+))?:(?<type>[^\\s.{}]+)\\}");
private static final String BODY = "BODY";
private static final String HEADER = "HEADER";
private final List<Parameter> parameters;
final String sql;
public TemplateQueryGenerator(final SQLDialect sqlDialect, final String sql) {
final Matcher m = PARAMETER_PATTERN.matcher(sql);
parameters = new ArrayList<Parameter>();
while (m.find()) {
final String part = m.group("part").toUpperCase(Locale.ENGLISH);
final String header = m.group("header");
final String type = m.group("type").toUpperCase(Locale.ENGLISH);
DataType<?> dataType = DefaultDataType.getDataType(sqlDialect, type);
if (BODY.equals(part)) {
if (header != null) {
throw new IllegalArgumentException("BODY parameter must have no header name specifier (${body:" + type + "}, not (${body." + header + ":" + type + "}");
}
}
final Parameter parameter = new Parameter(header, dataType);
parameters.add(parameter);
log.trace("Parameter: {}", parameter);
}
this.sql = m.replaceAll("?");
log.debug("Generated SQL: {}", this.sql);
}
public boolean executeQuery(final DSLContext dslContext, final List<Event> events) {
List<Query> queries = new ArrayList<Query>();
for (int i = 0; i < events.size(); i++) {
final Object[] bindings = new Object[this.parameters.size()];
for (int j = 0; j < this.parameters.size(); j++) {
bindings[j] = this.parameters.get(j).binding(events.get(i));
}
queries.add(dslContext.query(this.sql, bindings));
}
dslContext.batch(queries).execute();
return true;
}
private static class Parameter {
private final String header;
private final DataType<?> dataType;
public Parameter(final String header, final DataType<?> dataType) {
this.header = header;
this.dataType = dataType;
}
public Object binding(final Event event) {
if (header == null) {
final byte body[] = event.getBody();
return dataType.convert(new String(body, Charsets.UTF_8));
} else {
final Map<String, String> headers = event.getHeaders();
for (final Map.Entry<String, String> entry : headers.entrySet()) {
if (entry.getKey().equals(header)) {
return dataType.convert(entry.getValue());
}
}
}
log.trace("No bindable field found for {}", this);
return null;
}
@Override
public String toString() {
return com.google.common.base.Objects.toStringHelper(Parameter.class)
.add("header", header).add("dataType", dataType).toString();
}
}
}