package com.revolsys.record.schema; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import com.revolsys.collection.map.MapEx; import com.revolsys.collection.map.Maps; import com.revolsys.geometry.model.GeometryFactory; import com.revolsys.io.PathName; import com.revolsys.jdbc.io.RecordStoreIteratorFactory; import com.revolsys.logging.Logs; import com.revolsys.properties.BaseObjectWithProperties; import com.revolsys.record.ArrayRecord; import com.revolsys.record.Record; import com.revolsys.record.RecordFactory; import com.revolsys.record.code.CodeTable; import com.revolsys.record.io.RecordStoreConnection; import com.revolsys.record.io.RecordStoreExtension; import com.revolsys.record.property.RecordDefinitionProperty; import com.revolsys.util.Property; import com.revolsys.util.UrlUtil; import com.revolsys.util.count.CategoryLabelCountMap; public abstract class AbstractRecordStore extends BaseObjectWithProperties implements RecordStore { private boolean closed = false; private Map<String, List<String>> codeTableFieldNames = new HashMap<>(); private final Map<String, CodeTable> codeTableByFieldName = new HashMap<>(); private List<RecordDefinitionProperty> commonRecordDefinitionProperties = new ArrayList<>(); private Map<String, Object> connectionProperties = new HashMap<>(); private RecordStoreConnection recordStoreConnection; private GeometryFactory geometryFactory; private RecordStoreIteratorFactory iteratorFactory = new RecordStoreIteratorFactory(); private String label; private boolean loadFullSchema = true; private RecordFactory<Record> recordFactory; private final Set<RecordStoreExtension> recordStoreExtensions = new LinkedHashSet<>(); private final RecordStoreSchema rootSchema = new RecordStoreSchema(this); private final CategoryLabelCountMap statistics = new CategoryLabelCountMap(); private final Map<String, Map<String, Object>> typeRecordDefinitionProperties = new HashMap<>(); public AbstractRecordStore() { this(ArrayRecord.FACTORY); } public AbstractRecordStore(final RecordFactory<? extends Record> recordFactory) { setRecordFactory(recordFactory); } @Override public void addCodeTable(final CodeTable codeTable) { final String idFieldName = codeTable.getIdFieldName(); addCodeTable(idFieldName, codeTable); final List<String> fieldAliases = codeTable.getFieldNameAliases(); for (final String alias : fieldAliases) { addCodeTable(alias, codeTable); } final String codeTableName = codeTable.getName(); final List<String> fieldNames = this.codeTableFieldNames.get(codeTableName); if (fieldNames != null) { for (final String fieldName : fieldNames) { addCodeTable(fieldName, codeTable); } } } public void addCodeTable(final String fieldName, final CodeTable codeTable) { if (fieldName != null && !fieldName.equalsIgnoreCase("ID")) { this.codeTableByFieldName.put(fieldName.toUpperCase(), codeTable); final RecordStoreSchema rootSchema = getRootSchema(); addCodeTableFieldNames(rootSchema, codeTable, fieldName); } } protected void addCodeTableFieldNames(final RecordStoreSchema schema, final CodeTable codeTable, final String codeTableFieldName) { if (schema.isInitialized()) { for (final RecordStoreSchema childSchema : schema.getSchemas()) { addCodeTableFieldNames(childSchema, codeTable, codeTableFieldName); } for (final RecordDefinition recordDefinition : schema.getRecordDefinitions()) { final String idFieldName = recordDefinition.getIdFieldName(); for (final FieldDefinition field : recordDefinition.getFields()) { final String fieldName = field.getName(); if (!fieldName.equals(idFieldName) && fieldName.equals(codeTableFieldName)) { field.setCodeTable(codeTable); } } } } } protected void addRecordDefinitionProperties(final RecordDefinitionImpl recordDefinition) { final String typePath = recordDefinition.getPath(); for (final RecordDefinitionProperty property : this.commonRecordDefinitionProperties) { final RecordDefinitionProperty clonedProperty = property.clone(); clonedProperty.setRecordDefinition(recordDefinition); } final Map<String, Object> properties = this.typeRecordDefinitionProperties.get(typePath); recordDefinition.setProperties(properties); } public void addRecordStoreExtension(final RecordStoreExtension extension) { if (extension != null) { try { final Map<String, Object> connectionProperties = getConnectionProperties(); extension.initialize(this, connectionProperties); this.recordStoreExtensions.add(extension); } catch (final Throwable e) { Logs.error(extension.getClass(), "Unable to initialize", e); } } } @Override @PreDestroy public void close() { this.closed = true; try { super.close(); if (this.statistics != null) { this.statistics.disconnect(); } getRootSchema().close(); } finally { this.codeTableFieldNames.clear(); this.codeTableByFieldName.clear(); this.commonRecordDefinitionProperties.clear(); this.connectionProperties.clear(); this.recordFactory = null; this.recordStoreExtensions.clear(); this.iteratorFactory = null; this.label = "deleted"; this.statistics.clear(); this.typeRecordDefinitionProperties.clear(); } } @Override public CodeTable getCodeTableByFieldName(final CharSequence fieldName) { if (fieldName == null) { return null; } else { final CodeTable codeTable = this.codeTableByFieldName.get(fieldName.toString().toUpperCase()); return codeTable; } } @Override public Map<String, CodeTable> getCodeTableByFieldNameMap() { return new HashMap<>(this.codeTableByFieldName); } public Map<String, List<String>> getCodeTableColumNames() { return this.codeTableFieldNames; } @Override public RecordStoreConnected getConnected() { return new RecordStoreConnected(this); } @Override public MapEx getConnectionProperties() { return Maps.newLinkedHashEx(this.connectionProperties); } @Override public String getConnectionTitle() { final RecordStoreConnection recordStoreConnection = getRecordStoreConnection(); if (recordStoreConnection == null) { final String url = getUrl(); if (url == null) { return null; } else { return UrlUtil.getFileName(url); } } else { return recordStoreConnection.getName(); } } @Override public GeometryFactory getGeometryFactory() { return this.geometryFactory; } @Override public RecordStoreIteratorFactory getIteratorFactory() { return this.iteratorFactory; } @Override public String getLabel() { return this.label; } @Override public RecordFactory<Record> getRecordFactory() { return this.recordFactory; } @Override public RecordStoreConnection getRecordStoreConnection() { return this.recordStoreConnection; } public Collection<RecordStoreExtension> getRecordStoreExtensions() { return this.recordStoreExtensions; } @Override public RecordStoreSchema getRootSchema() { return this.rootSchema; } @Override public CategoryLabelCountMap getStatistics() { return this.statistics; } @Override public String getUrl() { return (String)this.connectionProperties.get("url"); } @Override public String getUsername() { return (String)this.connectionProperties.get("user"); } @Override @PostConstruct public void initialize() { getStatistics().connect(); } protected void initRecordDefinition(final RecordDefinition recordDefinition) { final String idFieldName = recordDefinition.getIdFieldName(); for (final FieldDefinition field : recordDefinition.getFields()) { final String fieldName = field.getName(); if (!fieldName.equals(idFieldName)) { final CodeTable codeTable = getCodeTableByFieldName(fieldName); if (codeTable != null) { field.setCodeTable(codeTable); } } } } @Override public boolean isClosed() { return this.closed; } @Override public boolean isLoadFullSchema() { return this.loadFullSchema; } protected void obtainConnected() { } protected RecordDefinition refreshRecordDefinition(final RecordStoreSchema schema, final PathName typePath) { return null; } protected void refreshSchema() { getRootSchema().refresh(); } protected void refreshSchema(final PathName schemaName) { final RecordStoreSchema schema = getSchema(schemaName); if (schema != null) { schema.refresh(); } } protected Map<PathName, ? extends RecordStoreSchemaElement> refreshSchemaElements( final RecordStoreSchema schema) { return Collections.emptyMap(); } protected void releaseConnected() { } public void setCodeTableColumNames(final Map<String, List<String>> domainColumNames) { this.codeTableFieldNames = domainColumNames; } public void setCommonRecordDefinitionProperties( final List<RecordDefinitionProperty> commonRecordDefinitionProperties) { this.commonRecordDefinitionProperties = commonRecordDefinitionProperties; } protected void setConnectionProperties(final Map<String, ? extends Object> connectionProperties) { this.connectionProperties = Maps.newHash(connectionProperties); } public void setGeometryFactory(final GeometryFactory geometryFactory) { this.geometryFactory = geometryFactory; } public void setIteratorFactory(final RecordStoreIteratorFactory iteratorFactory) { this.iteratorFactory = iteratorFactory; } @Override public void setLabel(final String label) { this.label = label; getStatistics().setPrefix(label); } @Override public void setLoadFullSchema(final boolean loadFullSchema) { this.loadFullSchema = loadFullSchema; } @Override public void setRecordFactory(final RecordFactory<? extends Record> recordFactory) { this.recordFactory = (RecordFactory<Record>)recordFactory; } @Override public void setRecordStoreConnection(final RecordStoreConnection recordStoreConnection) { this.recordStoreConnection = recordStoreConnection; } public void setTypeRecordDefinitionProperties( final Map<String, List<RecordDefinitionProperty>> typeRecordDefinitionProperties) { for (final Entry<String, List<RecordDefinitionProperty>> typeProperties : typeRecordDefinitionProperties .entrySet()) { final String typePath = typeProperties.getKey(); Map<String, Object> currentProperties = this.typeRecordDefinitionProperties.get(typePath); if (currentProperties == null) { currentProperties = new LinkedHashMap<>(); this.typeRecordDefinitionProperties.put(typePath, currentProperties); } final List<RecordDefinitionProperty> properties = typeProperties.getValue(); for (final RecordDefinitionProperty property : properties) { final String name = property.getPropertyName(); currentProperties.put(name, property); } } } @Override public String toString() { if (Property.hasValue(this.label)) { return this.label; } else { return super.toString(); } } }