/* * DBeaver - Universal Database Manager * Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org) * * 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 org.jkiss.dbeaver.model.virtual; import org.jkiss.code.NotNull; import org.jkiss.code.Nullable; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.model.*; import org.jkiss.dbeaver.model.data.DBDAttributeBinding; import org.jkiss.dbeaver.model.exec.DBCLogicalOperator; import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor; import org.jkiss.dbeaver.model.struct.*; import org.jkiss.utils.CommonUtils; import java.util.*; /** * Dictionary descriptor */ public class DBVEntity extends DBVObject implements DBSEntity, DBPQualifiedObject { private static final String[] DESC_COLUMN_PATTERNS = { "title", "name", "label", "display", "displayname", "description", "comment", "remark", "information", "email", }; private static final int MIN_DESC_COLUMN_LENGTH = 4; private static final int MAX_DESC_COLUMN_LENGTH = 1000; private final DBVContainer container; private String name; private String description; private String descriptionColumnNames; List<DBVEntityConstraint> entityConstraints; List<DBVEntityAttribute> entityAttributes; Map<String, String> properties; List<DBVColorOverride> colorOverrides; public DBVEntity(DBVContainer container, String name, String descriptionColumnNames) { this.container = container; this.name = name; this.descriptionColumnNames = descriptionColumnNames; } // Copy constructor public DBVEntity(DBVContainer container, DBVEntity copy) { this.container = container; this.name = copy.name; this.descriptionColumnNames = copy.descriptionColumnNames; if (!CommonUtils.isEmpty(copy.entityConstraints)) { this.entityConstraints = new ArrayList<>(copy.entityConstraints.size()); for (DBVEntityConstraint c : copy.entityConstraints) { this.entityConstraints.add(new DBVEntityConstraint(this, c)); } } if (!CommonUtils.isEmpty(copy.entityAttributes)) { this.entityAttributes = new ArrayList<>(copy.entityAttributes.size()); for (DBVEntityAttribute attribute : copy.entityAttributes) { this.entityAttributes.add(new DBVEntityAttribute(this, null, attribute)); } } if (!CommonUtils.isEmpty(copy.properties)) { this.properties = new LinkedHashMap<>(copy.properties); } } @Nullable public DBSEntity getRealEntity(DBRProgressMonitor monitor) throws DBException { DBSObjectContainer realContainer = container.getRealContainer(monitor); if (realContainer == null) { return null; } DBSObject realObject = realContainer.getChild(monitor, name); if (realObject instanceof DBSEntity) { return (DBSEntity) realObject; } log.warn("Entity '" + name + "' not found in '" + realContainer.getName() + "'"); return null; } @NotNull @Override public String getName() { return name; } @Nullable @Override public String getDescription() { return description; } @Override public DBVContainer getParentObject() { return container; } @NotNull @Override public DBPDataSource getDataSource() { return container.getDataSource(); } public void setDescription(String description) { this.description = description; } @Override public boolean isPersisted() { return true; } @NotNull @Override public DBSEntityType getEntityType() { return DBSEntityType.VIRTUAL_ENTITY; } @Nullable public String getProperty(String name) { return CommonUtils.isEmpty(properties) ? null : properties.get(name); } public void setProperty(String name, @Nullable String value) { if (properties == null) { properties = new LinkedHashMap<>(); } if (value == null) { properties.remove(name); } else { properties.put(name, value); } } @NotNull @Override public Collection<? extends DBSEntityAttribute> getAttributes(@NotNull DBRProgressMonitor monitor) throws DBException { DBSEntity realEntity = getRealEntity(monitor); if (realEntity != null) { final Collection<? extends DBSEntityAttribute> realAttributes = realEntity.getAttributes(monitor); if (!CommonUtils.isEmpty(realAttributes)) { return realAttributes; } } return Collections.emptyList(); /* // Merge with virtual attributes for (DBVEntityAttribute va : entityAttributes) { boolean found = false; for (int i = 0; i < attributes.size(); i++) { DBSEntityAttribute attr = attributes.get(i); if (va.getName().equals(attr.getName())) { attributes.set(i, va); found = true; break; } } if (!found) { attributes.add(va); } } return attributes; */ } @Nullable @Override public DBSEntityAttribute getAttribute(@NotNull DBRProgressMonitor monitor, @NotNull String attributeName) { try { return DBUtils.findObject(getAttributes(monitor), attributeName); } catch (DBException e) { log.error("Can't obtain real entity's attributes", e); return null; } } @Nullable public DBVEntityAttribute getVirtualAttribute(DBDAttributeBinding binding, boolean create) { if (entityAttributes != null || create) { if (entityAttributes == null) { entityAttributes = new ArrayList<>(); } DBSObject[] path = DBUtils.getObjectPath(binding, true); DBVEntityAttribute topAttribute = DBUtils.findObject(entityAttributes, path[0].getName()); if (topAttribute == null && create) { topAttribute = new DBVEntityAttribute(this, null, path[0].getName()); entityAttributes.add(topAttribute); } if (topAttribute != null) { for (int i = 1; i < path.length; i++) { DBVEntityAttribute nextAttribute = topAttribute.getChild(path[i].getName()); if (nextAttribute == null) { if (create) { nextAttribute = new DBVEntityAttribute(this, topAttribute, path[i].getName()); } else { log.debug("Can't find hierarchical attribute '" + binding + "'"); return null; } } topAttribute = nextAttribute; } } return topAttribute; } return null; } void addVirtualAttribute(DBVEntityAttribute attribute) { if (entityAttributes == null) { entityAttributes = new ArrayList<>(); } entityAttributes.add(attribute); } void resetVirtualAttribute(DBVEntityAttribute attribute) { entityAttributes.remove(attribute); } @Nullable @Override public Collection<? extends DBVEntityConstraint> getConstraints(@NotNull DBRProgressMonitor monitor) throws DBException { return entityConstraints; } public DBVEntityConstraint getBestIdentifier() { if (entityConstraints == null) { entityConstraints = new ArrayList<>(); } if (entityConstraints.isEmpty()) { entityConstraints.add(new DBVEntityConstraint(this, DBSEntityConstraintType.VIRTUAL_KEY, "PRIMARY")); } for (DBVEntityConstraint constraint : entityConstraints) { if (constraint.getConstraintType().isUnique()) { return constraint; } } return entityConstraints.get(0); } void addConstraint(DBVEntityConstraint constraint) { if (entityConstraints == null) { entityConstraints = new ArrayList<>(); } entityConstraints.add(constraint); } @Nullable @Override public Collection<? extends DBSEntityAssociation> getAssociations(@NotNull DBRProgressMonitor monitor) throws DBException { return null; } @Nullable @Override public Collection<? extends DBSEntityAssociation> getReferences(@NotNull DBRProgressMonitor monitor) throws DBException { return null; } public String getDescriptionColumnNames() { return descriptionColumnNames; } public void setDescriptionColumnNames(String descriptionColumnNames) { this.descriptionColumnNames = descriptionColumnNames; } public Collection<DBSEntityAttribute> getDescriptionColumns(DBRProgressMonitor monitor, DBSEntity entity) throws DBException { return getDescriptionColumns(monitor, entity, descriptionColumnNames); } public static Collection<DBSEntityAttribute> getDescriptionColumns(DBRProgressMonitor monitor, DBSEntity entity, String descColumns) throws DBException { if (CommonUtils.isEmpty(descColumns)) { return Collections.emptyList(); } List<DBSEntityAttribute> result = new ArrayList<>(); Collection<? extends DBSEntityAttribute> attributes = entity.getAttributes(monitor); if (!CommonUtils.isEmpty(attributes)) { StringTokenizer st = new StringTokenizer(descColumns, ","); while (st.hasMoreTokens()) { String colName = st.nextToken(); for (DBSEntityAttribute attr : attributes) { if (colName.equalsIgnoreCase(attr.getName())) { result.add(attr); } } } } return result; } public static String getDefaultDescriptionColumn(DBRProgressMonitor monitor, DBSEntityAttribute keyColumn) throws DBException { assert keyColumn.getParentObject() != null; Collection<? extends DBSEntityAttribute> allColumns = keyColumn.getParentObject().getAttributes(monitor); if (allColumns == null || allColumns.isEmpty()) { return null; } if (allColumns.size() == 1) { return DBUtils.getQuotedIdentifier(keyColumn); } // Find all string columns Map<String, DBSEntityAttribute> stringColumns = new TreeMap<>(); for (DBSEntityAttribute column : allColumns) { if (column != keyColumn && column.getDataKind() == DBPDataKind.STRING && column.getMaxLength() < MAX_DESC_COLUMN_LENGTH && column.getMaxLength() >= MIN_DESC_COLUMN_LENGTH) { stringColumns.put(column.getName(), column); } } if (stringColumns.isEmpty()) { return DBUtils.getQuotedIdentifier(keyColumn); } if (stringColumns.size() > 1) { // Make some tests for (String pattern : DESC_COLUMN_PATTERNS) { for (String columnName : stringColumns.keySet()) { if (columnName.toLowerCase(Locale.ENGLISH).contains(pattern)) { return DBUtils.getQuotedIdentifier(stringColumns.get(columnName)); } } } } // No columns match pattern return DBUtils.getQuotedIdentifier(stringColumns.values().iterator().next()); } public List<DBVColorOverride> getColorOverrides() { return colorOverrides; } public void setColorOverrides(List<DBVColorOverride> colorOverrides) { this.colorOverrides = colorOverrides; } public void setColorOverride(DBDAttributeBinding attribute, Object value, String foreground, String background) { final String attrName = attribute.getName(); final DBVColorOverride co = new DBVColorOverride( attrName, DBCLogicalOperator.EQUALS, new Object[] { value }, foreground, background); if (colorOverrides == null) { colorOverrides = new ArrayList<>(); } else { for (Iterator<DBVColorOverride> iterator = colorOverrides.iterator(); iterator.hasNext(); ) { DBVColorOverride c = iterator.next(); if (c.matches(attrName, DBCLogicalOperator.EQUALS, co.getAttributeValues())) { iterator.remove(); } } } colorOverrides.add(co); } public void addColorOverride(DBVColorOverride color) { if (colorOverrides == null) { colorOverrides = new ArrayList<>(); } colorOverrides.add(color); } public void removeColorOverride(DBDAttributeBinding attribute) { if (colorOverrides == null) { return; } final String attrName = attribute.getName(); for (Iterator<DBVColorOverride> iterator = colorOverrides.iterator(); iterator.hasNext(); ) { DBVColorOverride c = iterator.next(); if (c.getAttributeName().equals(attrName)) { iterator.remove(); } } } @Override public boolean hasValuableData() { if (!CommonUtils.isEmpty(descriptionColumnNames) || !CommonUtils.isEmpty(properties)) { return true; } if (!CommonUtils.isEmpty(entityConstraints)) { for (DBVEntityConstraint c : entityConstraints) { if (c.hasAttributes()) { return true; } } } if (!CommonUtils.isEmpty(entityAttributes)) { for (DBVEntityAttribute attr : entityAttributes) { if (attr.hasValuableData()) { return true; } } } if (!CommonUtils.isEmpty(colorOverrides)) { return true; } return false; } @NotNull @Override public String getFullyQualifiedName(DBPEvaluationContext context) { return DBUtils.getFullQualifiedName(getDataSource(), container, this); } @Override public String toString() { return name; } }