package com.revolsys.record;
import java.util.HashMap;
import java.util.Map;
import com.revolsys.collection.map.ThreadSharedProperties;
import com.revolsys.datatype.DataType;
import com.revolsys.datatype.DataTypes;
import com.revolsys.geometry.model.Geometry;
import com.revolsys.io.BaseCloseable;
import com.revolsys.io.PathName;
import com.revolsys.io.PathUtil;
import com.revolsys.io.Writer;
import com.revolsys.logging.Logs;
import com.revolsys.record.schema.FieldDefinition;
import com.revolsys.record.schema.RecordDefinition;
import com.revolsys.record.schema.RecordDefinitionImpl;
public class RecordLog implements BaseCloseable {
private static final String LOG_MESSAGE = "LOG_MESSAGE";
private static final String LOG_LOCALITY = "LOG_LOCALITY";
private static final String KEY = RecordLog.class.getName();
public static void error(final Class<?> logCategory, final String message, final Record record) {
final RecordLog recordLog = getForThread();
if (record == null) {
Logs.error(logCategory, message + "\tnull");
} else if (recordLog == null) {
final RecordDefinition recordDefinition = record.getRecordDefinition();
Logs.error(logCategory, message + "\t" + recordDefinition.getPath() + record.getIdentifier());
} else {
recordLog.error(message, record);
}
}
public static RecordLog getForThread() {
final RecordLog recordLog = ThreadSharedProperties.getProperty(KEY);
return recordLog;
}
public static RecordLog recordLog() {
RecordLog recordLog = getForThread();
if (recordLog == null) {
recordLog = new RecordLog();
ThreadSharedProperties.setProperty(KEY, recordLog);
}
return recordLog;
}
private final Map<RecordDefinition, RecordDefinitionImpl> logRecordDefinitionMap = new HashMap<>();
private Writer<Record> writer;
private boolean usesLocality;
public RecordLog() {
}
public RecordLog(final boolean usesLocality) {
this.usesLocality = usesLocality;
}
public RecordLog(final Writer<Record> writer) {
this.writer = writer;
}
@Override
public void close() {
final Writer<Record> writer = this.writer;
if (writer != null) {
writer.flush();
writer.close();
}
this.logRecordDefinitionMap.clear();
}
public synchronized void error(final Object message, final Record record) {
log(null, message, record, null);
}
public synchronized void error(final Object message, final Record record,
final Geometry geometry) {
log(null, message, record, geometry);
}
public synchronized void error(final String localityName, final Object message,
final Record record) {
log(localityName, message, record, null);
}
public synchronized void error(final String localityName, final Object message,
final Record record, final Geometry geometry) {
log(localityName, message, record, geometry);
}
public RecordDefinition getLogRecordDefinition(final Record record) {
final RecordDefinition recordDefinition = record.getRecordDefinition();
final RecordDefinition logRecordDefinition = getLogRecordDefinition(recordDefinition);
return logRecordDefinition;
}
public RecordDefinition getLogRecordDefinition(final RecordDefinition recordDefinition) {
RecordDefinitionImpl logRecordDefinition = this.logRecordDefinitionMap.get(recordDefinition);
if (logRecordDefinition == null) {
final String path = recordDefinition.getPath();
final String parentPath = PathUtil.getPath(path);
final String tableName = PathUtil.getName(path);
final String logTableName;
if (tableName.toUpperCase().equals(tableName)) {
logTableName = tableName + "_LOG";
} else {
logTableName = tableName + "_log";
}
final PathName logTypeName = PathName.newPathName(PathUtil.toPath(parentPath, logTableName));
logRecordDefinition = new RecordDefinitionImpl(logTypeName);
if (this.usesLocality) {
logRecordDefinition.addField(LOG_LOCALITY, DataTypes.STRING, 255, false);
}
logRecordDefinition.addField(LOG_MESSAGE, DataTypes.STRING, 255, true);
for (final FieldDefinition fieldDefinition : recordDefinition.getFields()) {
final FieldDefinition logFieldDefinition = new FieldDefinition(fieldDefinition);
final DataType dataType = logFieldDefinition.getDataType();
if (recordDefinition.getGeometryField() == fieldDefinition) {
logRecordDefinition.addField("GEOMETRY", dataType);
} else {
logRecordDefinition.addField(new FieldDefinition(fieldDefinition));
}
}
logRecordDefinition.setGeometryFactory(recordDefinition.getGeometryFactory());
this.logRecordDefinitionMap.put(recordDefinition, logRecordDefinition);
}
return logRecordDefinition;
}
public Writer<Record> getWriter() {
return this.writer;
}
private void log(final Object localityName, final Object message, final Record record,
Geometry geometry) {
final Writer<Record> writer = this.writer;
if (writer != null) {
final RecordDefinition logRecordDefinition = getLogRecordDefinition(record);
final Record logRecord = new ArrayRecord(logRecordDefinition, record);
if (geometry == null) {
geometry = record.getGeometry();
}
logRecord.setGeometryValue(geometry);
logRecord.setValue(LOG_LOCALITY, localityName);
logRecord.setValue(LOG_MESSAGE, message);
synchronized (writer) {
writer.write(logRecord);
}
}
}
public void setWriter(final Writer<Record> writer) {
this.writer = writer;
}
@Override
public String toString() {
if (this.writer == null) {
return super.toString();
} else {
return this.writer.toString();
}
}
}