Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

594 lines
24 KiB
Java
Raw Normal View History

2021-08-01 14:27:44 -07:00
/*
* Copyright 2021 Collate
* 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
2021-08-01 14:27:44 -07:00
* 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.openmetadata.service;
2021-08-01 14:27:44 -07:00
import static org.openmetadata.common.utils.CommonUtil.listOf;
import static org.openmetadata.common.utils.CommonUtil.listOrEmpty;
import static org.openmetadata.service.resources.tags.TagLabelUtil.addDerivedTags;
import static org.openmetadata.service.util.EntityUtil.getFlattenedEntityField;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import io.github.classgraph.ClassGraph;
import io.github.classgraph.ClassInfoList;
import io.github.classgraph.ScanResult;
import java.lang.reflect.Modifier;
2021-11-09 13:25:08 -08:00
import java.net.URI;
2022-03-20 18:01:51 -07:00
import java.util.ArrayList;
import java.util.Arrays;
2021-11-09 13:25:08 -08:00
import java.util.Collections;
2023-07-10 16:50:49 -07:00
import java.util.EnumMap;
2021-11-09 13:25:08 -08:00
import java.util.HashMap;
import java.util.HashSet;
2021-11-09 13:25:08 -08:00
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
2021-11-09 13:25:08 -08:00
import java.util.UUID;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.core.UriInfo;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.jdbi.v3.core.Jdbi;
import org.openmetadata.schema.EntityInterface;
import org.openmetadata.schema.EntityTimeSeriesInterface;
import org.openmetadata.schema.FieldInterface;
import org.openmetadata.schema.entity.services.ServiceType;
import org.openmetadata.schema.type.EntityReference;
import org.openmetadata.schema.type.Include;
import org.openmetadata.schema.type.MetadataOperation;
import org.openmetadata.schema.type.TagLabel;
import org.openmetadata.service.exception.CatalogExceptionMessage;
import org.openmetadata.service.exception.EntityNotFoundException;
import org.openmetadata.service.jdbi3.ChangeEventRepository;
import org.openmetadata.service.jdbi3.CollectionDAO;
import org.openmetadata.service.jdbi3.EntityRepository;
import org.openmetadata.service.jdbi3.EntityTimeSeriesRepository;
import org.openmetadata.service.jdbi3.FeedRepository;
import org.openmetadata.service.jdbi3.LineageRepository;
import org.openmetadata.service.jdbi3.PolicyRepository;
import org.openmetadata.service.jdbi3.Repository;
import org.openmetadata.service.jdbi3.RoleRepository;
Fix #14786: Suggestions API (#14821) * Fix #14786: Suggestions API * Handle suggestions in ometa * Minor: Optimise Databricks Client (#14776) * MINOR - Fix SP topology context & Looker usage context (#14816) * MINOR - Fix SP topology context & Looker usage context * MINOR - Fix SP topology context & Looker usage context * Fix tests * Fixes #14598: Fix Tags / Labels ingestion on includeTags as False (#14782) * fix(ui): password error message for char limits (#14808) * fix(ui): password error message for char limits * fix java side code * Fixes #13556: Support for Salesforce table description ingestion (#14733) * ISSUE-13556: Add suport for Salesforce table description ingestion * ISSUE-13556: Remove unnecessary blank line * ISSUE-13556: Fix to get description for each table --------- Co-authored-by: Teddy <teddy.crepineau@gmail.com> * MINOR - Better handling of Ingestion Pipeline Status (#14792) * MINOR - Better handling of Ingestion Pipeline Status * format * format * MINOR: Added table validation for cost analysis data (#14793) * Added validation for cost analysis source * centralized life cycle logic * CYPRESS: simplify side navigation click in cypress (#14818) * simplify side navigation click in cypress * make sidbar item uses common enum * fix cypress failure of outside import * fix(#14326): tier dropdown is not working in advance search (#14780) * improvement in advance search based on custom property * fix a reading undefined property issue * wip: advance search based on tier * some code cleanup and improvement * some fixes * fix: ui flicker when advanceSearched is apply and refresh the page * some cleanup * no need to call customproperty api call, if entity not suppport customProperties * minor change * fix: autocomplete not working in tier search option in advance search modal * added unit test for advance search provider component * some cleanup * added testcase for open modal * added testcase for resetAllFilters method * removed unwanted code * added e2e test for testing tier advance search * fix: e2e search flow for single field * fix: string field not working after giving listValues in TierSearch * fix: group query e2e test fix * used asyncFetch way to get the tierOptions synchronously * some cleanup * remove unwanted lines * some cleanup * fix: selected option show option value instead of option title * fix(minor): update skip icon for executions (#14809) * Fixes #14803: ignore capitalization when confirming deletes (#14804) * ignore case when confirming deletes * Test confirmation of deletes works when case differs Added test case for 'delete' as the confirmation text. * minor(config): update openmetadata-ui code reviewers (#14823) * Add Tests * Add list/accept/reject apis * initial ui changes * localisation * show suggestion for empty description * ui feedbacks * Fix permission check for entities without owner * Fix entityLink and add tests * Add update suggestion WIP * Fix test * Fix PUT and Pagination * Fix styling * update test * Update status * add OM server connection in apps * add permissions check * Fix CI * Remove TODO * Fix feedResourceTest * fix unit tests * add private configs for apps * add private configs for apps * fix update application icons * minor center align icon * add private configs for apps * Format * Fix pydantic gen * Remove token * Update name * Rework private conf * Fix apps * Fix apps * Format * Format * show metapilot only if its installed --------- Co-authored-by: Pere Miquel Brull <peremiquelbrull@gmail.com> Co-authored-by: Mayur Singal <39544459+ulixius9@users.noreply.github.com> Co-authored-by: Ayush Shah <ayush@getcollate.io> Co-authored-by: Chirag Madlani <12962843+chirag-madlani@users.noreply.github.com> Co-authored-by: kwgdaig <18678754+kwgdaig@users.noreply.github.com> Co-authored-by: Teddy <teddy.crepineau@gmail.com> Co-authored-by: Onkar Ravgan <onkar.10r@gmail.com> Co-authored-by: Ashish Gupta <ashish@getcollate.io> Co-authored-by: Abhishek Porwal <80886271+Abhishek332@users.noreply.github.com> Co-authored-by: Carlo Q <carlo@machina.bio> Co-authored-by: karanh37 <karanh37@gmail.com>
2024-01-31 18:51:09 -08:00
import org.openmetadata.service.jdbi3.SuggestionRepository;
import org.openmetadata.service.jdbi3.SystemRepository;
import org.openmetadata.service.jdbi3.TokenRepository;
import org.openmetadata.service.jdbi3.UsageRepository;
import org.openmetadata.service.resources.feeds.MessageParser.EntityLink;
Search refactor (#13397) * Refactor Search * Refactor Search * Fix propgation bugs * Fix propgation bugs * Fix glossary term search * Fix glossary term search * Only issue search requests if the client is configured properly * Only issue search requests if the client is configured properly * Fix glossary index * add documentation for sharded tables (#13361) * Cost analysis agg (#13408) * feat: updated DI workflow to inherit from BaseWorkflow + split processor and producer classes * feat: __init__.py files creation * feat: updated workflow import classes in code and doc * feat: moved kpi runner from runner to processor folder * fix: skip failure on list entities * feat: deleted unused files * feat: updated status reporter * feat: ran linting * feat: fix test error with typing and fqn * feat: updated test dependencies * feat: ran linting * feat: move execution order up * feat: updated cost analysis report to align with new workflow * feat: fix entity already exists for pipeline entity status * feat: ran python linting * feat: move skip_on_failure to method * feat: added unusedReport to DI * feat: added aggregated unused report * feat: ran linting * feat: reverted compose file changes --------- Co-authored-by: Sriharsha Chintalapani <harshach@users.noreply.github.com> * Add Java 17 support (#12895) * Add Java 17 support * Change Test HTTP client provider * Create Tests HTTP Client once * Create Tests HTTP Client once * fix(CI): Update CI to use jdk 17 and dockerfiles as well --------- Co-authored-by: Akash-Jain <Akash.J@deuexsolutions.com> * Refactor Search * Refactor Search * Fix propgation bugs * Fix propgation bugs * Fix glossary term search * Fix glossary term search * Only issue search requests if the client is configured properly * Only issue search requests if the client is configured properly * Fix glossary index * Merge main * fix style * deleted field propagation * Fix style * close the test client * Changing to jersey connector * Fix Authentication Exception headers --------- Co-authored-by: Pere Miquel Brull <peremiquelbrull@gmail.com> Co-authored-by: Ayush Shah <ayush@getcollate.io> Co-authored-by: Teddy <teddy.crepineau@gmail.com> Co-authored-by: Akash-Jain <Akash.J@deuexsolutions.com>
2023-10-03 14:56:53 -07:00
import org.openmetadata.service.search.SearchRepository;
import org.openmetadata.service.search.indexes.SearchIndex;
import org.openmetadata.service.util.EntityUtil.Fields;
import org.openmetadata.service.util.FullyQualifiedName;
2021-11-09 13:25:08 -08:00
@Slf4j
2021-08-01 14:27:44 -07:00
public final class Entity {
private static volatile boolean initializedRepositories = false;
@Getter @Setter private static CollectionDAO collectionDAO;
public static final String SEPARATOR = "."; // Fully qualified name separator
// Canonical entity name to corresponding EntityRepository map
private static final Map<String, EntityRepository<? extends EntityInterface>>
ENTITY_REPOSITORY_MAP = new HashMap<>();
private static final Map<String, EntityTimeSeriesRepository<? extends EntityTimeSeriesInterface>>
ENTITY_TS_REPOSITORY_MAP = new HashMap<>();
@Getter @Setter private static TokenRepository tokenRepository;
@Getter @Setter private static PolicyRepository policyRepository;
@Getter @Setter private static RoleRepository roleRepository;
@Getter @Setter private static FeedRepository feedRepository;
@Getter @Setter private static LineageRepository lineageRepository;
@Getter @Setter private static UsageRepository usageRepository;
@Getter @Setter private static SystemRepository systemRepository;
@Getter @Setter private static ChangeEventRepository changeEventRepository;
Search refactor (#13397) * Refactor Search * Refactor Search * Fix propgation bugs * Fix propgation bugs * Fix glossary term search * Fix glossary term search * Only issue search requests if the client is configured properly * Only issue search requests if the client is configured properly * Fix glossary index * add documentation for sharded tables (#13361) * Cost analysis agg (#13408) * feat: updated DI workflow to inherit from BaseWorkflow + split processor and producer classes * feat: __init__.py files creation * feat: updated workflow import classes in code and doc * feat: moved kpi runner from runner to processor folder * fix: skip failure on list entities * feat: deleted unused files * feat: updated status reporter * feat: ran linting * feat: fix test error with typing and fqn * feat: updated test dependencies * feat: ran linting * feat: move execution order up * feat: updated cost analysis report to align with new workflow * feat: fix entity already exists for pipeline entity status * feat: ran python linting * feat: move skip_on_failure to method * feat: added unusedReport to DI * feat: added aggregated unused report * feat: ran linting * feat: reverted compose file changes --------- Co-authored-by: Sriharsha Chintalapani <harshach@users.noreply.github.com> * Add Java 17 support (#12895) * Add Java 17 support * Change Test HTTP client provider * Create Tests HTTP Client once * Create Tests HTTP Client once * fix(CI): Update CI to use jdk 17 and dockerfiles as well --------- Co-authored-by: Akash-Jain <Akash.J@deuexsolutions.com> * Refactor Search * Refactor Search * Fix propgation bugs * Fix propgation bugs * Fix glossary term search * Fix glossary term search * Only issue search requests if the client is configured properly * Only issue search requests if the client is configured properly * Fix glossary index * Merge main * fix style * deleted field propagation * Fix style * close the test client * Changing to jersey connector * Fix Authentication Exception headers --------- Co-authored-by: Pere Miquel Brull <peremiquelbrull@gmail.com> Co-authored-by: Ayush Shah <ayush@getcollate.io> Co-authored-by: Teddy <teddy.crepineau@gmail.com> Co-authored-by: Akash-Jain <Akash.J@deuexsolutions.com>
2023-10-03 14:56:53 -07:00
@Getter @Setter private static SearchRepository searchRepository;
Fix #14786: Suggestions API (#14821) * Fix #14786: Suggestions API * Handle suggestions in ometa * Minor: Optimise Databricks Client (#14776) * MINOR - Fix SP topology context & Looker usage context (#14816) * MINOR - Fix SP topology context & Looker usage context * MINOR - Fix SP topology context & Looker usage context * Fix tests * Fixes #14598: Fix Tags / Labels ingestion on includeTags as False (#14782) * fix(ui): password error message for char limits (#14808) * fix(ui): password error message for char limits * fix java side code * Fixes #13556: Support for Salesforce table description ingestion (#14733) * ISSUE-13556: Add suport for Salesforce table description ingestion * ISSUE-13556: Remove unnecessary blank line * ISSUE-13556: Fix to get description for each table --------- Co-authored-by: Teddy <teddy.crepineau@gmail.com> * MINOR - Better handling of Ingestion Pipeline Status (#14792) * MINOR - Better handling of Ingestion Pipeline Status * format * format * MINOR: Added table validation for cost analysis data (#14793) * Added validation for cost analysis source * centralized life cycle logic * CYPRESS: simplify side navigation click in cypress (#14818) * simplify side navigation click in cypress * make sidbar item uses common enum * fix cypress failure of outside import * fix(#14326): tier dropdown is not working in advance search (#14780) * improvement in advance search based on custom property * fix a reading undefined property issue * wip: advance search based on tier * some code cleanup and improvement * some fixes * fix: ui flicker when advanceSearched is apply and refresh the page * some cleanup * no need to call customproperty api call, if entity not suppport customProperties * minor change * fix: autocomplete not working in tier search option in advance search modal * added unit test for advance search provider component * some cleanup * added testcase for open modal * added testcase for resetAllFilters method * removed unwanted code * added e2e test for testing tier advance search * fix: e2e search flow for single field * fix: string field not working after giving listValues in TierSearch * fix: group query e2e test fix * used asyncFetch way to get the tierOptions synchronously * some cleanup * remove unwanted lines * some cleanup * fix: selected option show option value instead of option title * fix(minor): update skip icon for executions (#14809) * Fixes #14803: ignore capitalization when confirming deletes (#14804) * ignore case when confirming deletes * Test confirmation of deletes works when case differs Added test case for 'delete' as the confirmation text. * minor(config): update openmetadata-ui code reviewers (#14823) * Add Tests * Add list/accept/reject apis * initial ui changes * localisation * show suggestion for empty description * ui feedbacks * Fix permission check for entities without owner * Fix entityLink and add tests * Add update suggestion WIP * Fix test * Fix PUT and Pagination * Fix styling * update test * Update status * add OM server connection in apps * add permissions check * Fix CI * Remove TODO * Fix feedResourceTest * fix unit tests * add private configs for apps * add private configs for apps * fix update application icons * minor center align icon * add private configs for apps * Format * Fix pydantic gen * Remove token * Update name * Rework private conf * Fix apps * Fix apps * Format * Format * show metapilot only if its installed --------- Co-authored-by: Pere Miquel Brull <peremiquelbrull@gmail.com> Co-authored-by: Mayur Singal <39544459+ulixius9@users.noreply.github.com> Co-authored-by: Ayush Shah <ayush@getcollate.io> Co-authored-by: Chirag Madlani <12962843+chirag-madlani@users.noreply.github.com> Co-authored-by: kwgdaig <18678754+kwgdaig@users.noreply.github.com> Co-authored-by: Teddy <teddy.crepineau@gmail.com> Co-authored-by: Onkar Ravgan <onkar.10r@gmail.com> Co-authored-by: Ashish Gupta <ashish@getcollate.io> Co-authored-by: Abhishek Porwal <80886271+Abhishek332@users.noreply.github.com> Co-authored-by: Carlo Q <carlo@machina.bio> Co-authored-by: karanh37 <karanh37@gmail.com>
2024-01-31 18:51:09 -08:00
@Getter @Setter private static SuggestionRepository suggestionRepository;
// List of all the entities
private static final Set<String> ENTITY_LIST = new TreeSet<>();
// Common field names
public static final String FIELD_OWNER = "owner";
2022-04-22 18:57:08 -07:00
public static final String FIELD_NAME = "name";
public static final String FIELD_DESCRIPTION = "description";
public static final String FIELD_FOLLOWERS = "followers";
public static final String FIELD_VOTES = "votes";
public static final String FIELD_TAGS = "tags";
public static final String FIELD_DELETED = "deleted";
public static final String FIELD_PIPELINE_STATUS = "pipelineStatus";
2022-04-22 18:57:08 -07:00
public static final String FIELD_DISPLAY_NAME = "displayName";
public static final String FIELD_EXTENSION = "extension";
public static final String FIELD_USAGE_SUMMARY = "usageSummary";
public static final String FIELD_CHILDREN = "children";
public static final String FIELD_PARENT = "parent";
public static final String FIELD_REVIEWERS = "reviewers";
public static final String FIELD_EXPERTS = "experts";
public static final String FIELD_DOMAIN = "domain";
public static final String FIELD_DATA_PRODUCTS = "dataProducts";
public static final String FIELD_ASSETS = "assets";
public static final String FIELD_STYLE = "style";
public static final String FIELD_LIFE_CYCLE = "lifeCycle";
public static final String FIELD_DISABLED = "disabled";
2021-11-09 13:25:08 -08:00
//
// Service entities
2021-11-09 13:25:08 -08:00
//
2021-08-01 14:27:44 -07:00
public static final String DATABASE_SERVICE = "databaseService";
public static final String MESSAGING_SERVICE = "messagingService";
public static final String DASHBOARD_SERVICE = "dashboardService";
2021-09-24 08:54:04 -07:00
public static final String PIPELINE_SERVICE = "pipelineService";
public static final String STORAGE_SERVICE = "storageService";
public static final String MLMODEL_SERVICE = "mlmodelService";
public static final String METADATA_SERVICE = "metadataService";
public static final String SEARCH_SERVICE = "searchService";
2021-11-09 13:25:08 -08:00
//
// Data asset entities
2021-11-09 13:25:08 -08:00
//
2021-08-01 14:27:44 -07:00
public static final String TABLE = "table";
public static final String STORED_PROCEDURE = "storedProcedure";
2021-08-01 14:27:44 -07:00
public static final String DATABASE = "database";
public static final String DATABASE_SCHEMA = "databaseSchema";
2021-08-01 14:27:44 -07:00
public static final String METRICS = "metrics";
public static final String DASHBOARD = "dashboard";
public static final String DASHBOARD_DATA_MODEL = "dashboardDataModel";
2021-09-24 08:54:04 -07:00
public static final String PIPELINE = "pipeline";
public static final String TASK = "task";
public static final String CHART = "chart";
public static final String APPLICATION = "app";
public static final String APP_MARKET_PLACE_DEF = "appMarketPlaceDefinition";
2021-08-01 14:27:44 -07:00
public static final String REPORT = "report";
public static final String TOPIC = "topic";
public static final String SEARCH_INDEX = "searchIndex";
public static final String MLMODEL = "mlmodel";
public static final String CONTAINER = "container";
Query as entity (#10449) * added query as an entity * changed name of the variables and methods * Added Resource Descriptors * testcase bug fix * addressing comments * added script for table query migration * added script for table query migration postgresql * bug fix * db change for script test * added current timestamp * change db config from postgresql to mysql * added extension to use fucntion gen_random_uuid() * solving maven ci * added queryUsage and change is migration script * addressing comments * addressing comments * added queryUsage relation and testcase * added api to insert queries in bulk * . * fix a test case which was failing due to latest changes * Ingestion Changes for Query as Entity * move query changes to latest sqls * added tags and owner * update PR for Query as Entity * update type * fixed pagination * fix path param * fix TestCases * add validation criteria * removed exisitng query apis * checkstyle fix * remove vote from put * remove vote from put * Query As Entity Ingestion Changes * Remove unused func * update Review Comments * update Review Comments * remove previous changes for Query and Update Tests * moved Checksum to Query Util Class * update python api * fix python checkstyle * Fixed Tests * Fix pytest * remove space changes * remove space changes * Fixed put_addFollowerDeleteEntity_200 * Fix usage ingestion * Update Python SDK and tests * pylint fix --------- Co-authored-by: Himank Mehta <himankmehta@Himanks-MacBook-Air.local> Co-authored-by: ulixius9 <mayursingal9@gmail.com> Co-authored-by: Mayur Singal <39544459+ulixius9@users.noreply.github.com>
2023-03-16 09:25:30 +05:30
public static final String QUERY = "query";
public static final String GLOSSARY = "glossary";
public static final String GLOSSARY_TERM = "glossaryTerm";
public static final String TAG = "tag";
public static final String CLASSIFICATION = "classification";
public static final String TYPE = "type";
public static final String TEST_DEFINITION = "testDefinition";
public static final String TEST_CONNECTION_DEFINITION = "testConnectionDefinition";
public static final String TEST_SUITE = "testSuite";
public static final String KPI = "kpi";
public static final String TEST_CASE = "testCase";
public static final String WEB_ANALYTIC_EVENT = "webAnalyticEvent";
public static final String DATA_INSIGHT_CHART = "dataInsightChart";
2021-08-01 14:27:44 -07:00
2021-11-09 13:25:08 -08:00
//
// Policy entity
2021-11-09 13:25:08 -08:00
//
public static final String POLICY = "policy";
public static final String POLICIES = "policies";
2021-11-09 13:25:08 -08:00
//
// Role, team and user entities
2021-11-09 13:25:08 -08:00
//
2021-12-30 08:30:12 -08:00
public static final String ROLE = "role";
2021-08-01 14:27:44 -07:00
public static final String USER = "user";
public static final String TEAM = "team";
public static final String PERSONA = "persona";
public static final String BOT = "bot";
2021-08-01 14:27:44 -07:00
//
// Operation related entities
//
public static final String INGESTION_PIPELINE = "ingestionPipeline";
//
// Domain related entities
//
public static final String DOMAIN = "domain";
public static final String DATA_PRODUCT = "dataProduct";
//
// Other entities
public static final String EVENT_SUBSCRIPTION = "eventsubscription";
public static final String THREAD = "THREAD";
Fix #14786: Suggestions API (#14821) * Fix #14786: Suggestions API * Handle suggestions in ometa * Minor: Optimise Databricks Client (#14776) * MINOR - Fix SP topology context & Looker usage context (#14816) * MINOR - Fix SP topology context & Looker usage context * MINOR - Fix SP topology context & Looker usage context * Fix tests * Fixes #14598: Fix Tags / Labels ingestion on includeTags as False (#14782) * fix(ui): password error message for char limits (#14808) * fix(ui): password error message for char limits * fix java side code * Fixes #13556: Support for Salesforce table description ingestion (#14733) * ISSUE-13556: Add suport for Salesforce table description ingestion * ISSUE-13556: Remove unnecessary blank line * ISSUE-13556: Fix to get description for each table --------- Co-authored-by: Teddy <teddy.crepineau@gmail.com> * MINOR - Better handling of Ingestion Pipeline Status (#14792) * MINOR - Better handling of Ingestion Pipeline Status * format * format * MINOR: Added table validation for cost analysis data (#14793) * Added validation for cost analysis source * centralized life cycle logic * CYPRESS: simplify side navigation click in cypress (#14818) * simplify side navigation click in cypress * make sidbar item uses common enum * fix cypress failure of outside import * fix(#14326): tier dropdown is not working in advance search (#14780) * improvement in advance search based on custom property * fix a reading undefined property issue * wip: advance search based on tier * some code cleanup and improvement * some fixes * fix: ui flicker when advanceSearched is apply and refresh the page * some cleanup * no need to call customproperty api call, if entity not suppport customProperties * minor change * fix: autocomplete not working in tier search option in advance search modal * added unit test for advance search provider component * some cleanup * added testcase for open modal * added testcase for resetAllFilters method * removed unwanted code * added e2e test for testing tier advance search * fix: e2e search flow for single field * fix: string field not working after giving listValues in TierSearch * fix: group query e2e test fix * used asyncFetch way to get the tierOptions synchronously * some cleanup * remove unwanted lines * some cleanup * fix: selected option show option value instead of option title * fix(minor): update skip icon for executions (#14809) * Fixes #14803: ignore capitalization when confirming deletes (#14804) * ignore case when confirming deletes * Test confirmation of deletes works when case differs Added test case for 'delete' as the confirmation text. * minor(config): update openmetadata-ui code reviewers (#14823) * Add Tests * Add list/accept/reject apis * initial ui changes * localisation * show suggestion for empty description * ui feedbacks * Fix permission check for entities without owner * Fix entityLink and add tests * Add update suggestion WIP * Fix test * Fix PUT and Pagination * Fix styling * update test * Update status * add OM server connection in apps * add permissions check * Fix CI * Remove TODO * Fix feedResourceTest * fix unit tests * add private configs for apps * add private configs for apps * fix update application icons * minor center align icon * add private configs for apps * Format * Fix pydantic gen * Remove token * Update name * Rework private conf * Fix apps * Fix apps * Format * Format * show metapilot only if its installed --------- Co-authored-by: Pere Miquel Brull <peremiquelbrull@gmail.com> Co-authored-by: Mayur Singal <39544459+ulixius9@users.noreply.github.com> Co-authored-by: Ayush Shah <ayush@getcollate.io> Co-authored-by: Chirag Madlani <12962843+chirag-madlani@users.noreply.github.com> Co-authored-by: kwgdaig <18678754+kwgdaig@users.noreply.github.com> Co-authored-by: Teddy <teddy.crepineau@gmail.com> Co-authored-by: Onkar Ravgan <onkar.10r@gmail.com> Co-authored-by: Ashish Gupta <ashish@getcollate.io> Co-authored-by: Abhishek Porwal <80886271+Abhishek332@users.noreply.github.com> Co-authored-by: Carlo Q <carlo@machina.bio> Co-authored-by: karanh37 <karanh37@gmail.com>
2024-01-31 18:51:09 -08:00
public static final String SUGGESTION = "SUGGESTION";
public static final String WORKFLOW = "workflow";
//
// Time series entities
public static final String ENTITY_REPORT_DATA = "entityReportData";
public static final String TEST_CASE_RESOLUTION_STATUS = "testCaseResolutionStatus";
public static final String WEB_ANALYTIC_ENTITY_VIEW_REPORT_DATA =
"webAnalyticEntityViewReportData";
public static final String WEB_ANALYTIC_USER_ACTIVITY_REPORT_DATA =
"webAnalyticUserActivityReportData";
public static final String RAW_COST_ANALYSIS_REPORT_DATA = "rawCostAnalysisReportData";
public static final String AGGREGATED_COST_ANALYSIS_REPORT_DATA =
"aggregatedCostAnalysisReportData";
//
// Reserved names in OpenMetadata
//
public static final String ADMIN_ROLE = "Admin";
public static final String ADMIN_USER_NAME = "admin";
public static final String ORGANIZATION_NAME = "Organization";
public static final String ORGANIZATION_POLICY_NAME = "OrganizationPolicy";
public static final String INGESTION_BOT_NAME = "ingestion-bot";
public static final String INGESTION_BOT_ROLE = "IngestionBotRole";
public static final String PROFILER_BOT_NAME = "profiler-bot";
public static final String PROFILER_BOT_ROLE = "ProfilerBotRole";
public static final String QUALITY_BOT_NAME = "quality-bot";
public static final String QUALITY_BOT_ROLE = "QualityBotRole";
public static final String ALL_RESOURCES = "All";
public static final String DOCUMENT = "document";
// ServiceType - Service Entity name map
2023-07-10 16:50:49 -07:00
static final Map<ServiceType, String> SERVICE_TYPE_ENTITY_MAP = new EnumMap<>(ServiceType.class);
static {
SERVICE_TYPE_ENTITY_MAP.put(ServiceType.DATABASE, DATABASE_SERVICE);
SERVICE_TYPE_ENTITY_MAP.put(ServiceType.MESSAGING, MESSAGING_SERVICE);
SERVICE_TYPE_ENTITY_MAP.put(ServiceType.DASHBOARD, DASHBOARD_SERVICE);
SERVICE_TYPE_ENTITY_MAP.put(ServiceType.PIPELINE, PIPELINE_SERVICE);
SERVICE_TYPE_ENTITY_MAP.put(ServiceType.ML_MODEL, MLMODEL_SERVICE);
SERVICE_TYPE_ENTITY_MAP.put(ServiceType.METADATA, METADATA_SERVICE);
SERVICE_TYPE_ENTITY_MAP.put(ServiceType.STORAGE, STORAGE_SERVICE);
SERVICE_TYPE_ENTITY_MAP.put(ServiceType.SEARCH, SEARCH_SERVICE);
2023-07-10 16:50:49 -07:00
}
private Entity() {}
2021-11-09 13:25:08 -08:00
public static void initializeRepositories(OpenMetadataApplicationConfig config, Jdbi jdbi) {
if (!initializedRepositories) {
tokenRepository = new TokenRepository();
policyRepository = new PolicyRepository();
roleRepository = new RoleRepository();
List<Class<?>> repositories = getRepositories();
for (Class<?> clz : repositories) {
if (Modifier.isAbstract(clz.getModifiers())) {
continue; // Don't instantiate abstract classes
}
try {
clz.getDeclaredConstructor().newInstance();
} catch (Exception e) {
try {
clz.getDeclaredConstructor(OpenMetadataApplicationConfig.class).newInstance(config);
} catch (Exception ex) {
try {
clz.getDeclaredConstructor(Jdbi.class).newInstance(jdbi);
} catch (Exception exception) {
LOG.warn("Exception encountered", exception);
}
}
}
}
initializedRepositories = true;
}
}
public static void cleanup() {
initializedRepositories = false;
collectionDAO = null;
searchRepository = null;
ENTITY_REPOSITORY_MAP.clear();
}
public static <T extends EntityInterface> void registerEntity(
Class<T> clazz, String entity, EntityRepository<T> entityRepository) {
2021-11-10 16:07:06 -08:00
ENTITY_REPOSITORY_MAP.put(entity, entityRepository);
EntityInterface.CANONICAL_ENTITY_NAME_MAP.put(entity.toLowerCase(Locale.ROOT), entity);
EntityInterface.ENTITY_TYPE_TO_CLASS_MAP.put(entity.toLowerCase(Locale.ROOT), clazz);
ENTITY_LIST.add(entity);
LOG.debug("Registering entity {} {}", clazz, entity);
2021-11-09 13:25:08 -08:00
}
public static <T extends EntityTimeSeriesInterface> void registerEntity(
Class<T> clazz, String entity, EntityTimeSeriesRepository<T> entityRepository) {
ENTITY_TS_REPOSITORY_MAP.put(entity, entityRepository);
EntityTimeSeriesInterface.CANONICAL_ENTITY_NAME_MAP.put(
entity.toLowerCase(Locale.ROOT), entity);
EntityTimeSeriesInterface.ENTITY_TYPE_TO_CLASS_MAP.put(entity.toLowerCase(Locale.ROOT), clazz);
ENTITY_LIST.add(entity);
LOG.debug("Registering entity time series {} {}", clazz, entity);
}
public static void registerResourcePermissions(
String entity, List<MetadataOperation> entitySpecificOperations) {
// Set up entity operations for permissions
Class<?> clazz = getEntityClassFromType(entity);
ResourceRegistry.addResource(entity, entitySpecificOperations, getEntityFields(clazz));
}
public static void registerTimeSeriesResourcePermissions(String entity) {
// Set up entity operations for permissions
Class<?> clazz = getEntityTimeSeriesClassFromType(entity);
ResourceRegistry.addResource(entity, null, getEntityFields(clazz));
}
public static Set<String> getEntityList() {
return Collections.unmodifiableSet(ENTITY_LIST);
}
public static EntityReference getEntityReference(EntityReference ref, Include include) {
if (ref == null) {
return null;
}
return ref.getId() != null
? getEntityReferenceById(ref.getType(), ref.getId(), include)
: getEntityReferenceByName(ref.getType(), ref.getFullyQualifiedName(), include);
}
public static EntityReference getEntityReferenceById(
@NonNull String entityType, @NonNull UUID id, Include include) {
EntityRepository<? extends EntityInterface> repository = getEntityRepository(entityType);
include = repository.supportsSoftDelete ? Include.ALL : include;
return repository.getReference(id, include);
}
2023-07-10 16:50:49 -07:00
public static EntityReference getEntityReferenceByName(
@NonNull String entityType, String fqn, Include include) {
if (fqn == null) {
return null;
}
EntityRepository<? extends EntityInterface> repository = getEntityRepository(entityType);
return repository.getReferenceByName(fqn, include);
}
public static EntityReference getOwner(@NonNull EntityReference reference) {
EntityRepository<?> repository = getEntityRepository(reference.getType());
return repository.getOwner(reference);
2021-11-09 13:25:08 -08:00
}
public static void withHref(UriInfo uriInfo, List<EntityReference> list) {
listOrEmpty(list).forEach(ref -> withHref(uriInfo, ref));
2021-11-09 13:25:08 -08:00
}
public static void withHref(UriInfo uriInfo, EntityReference ref) {
2021-11-09 13:25:08 -08:00
if (ref == null) {
return;
2021-11-09 13:25:08 -08:00
}
String entityType = ref.getType();
EntityRepository<?> entityRepository = getEntityRepository(entityType);
2021-11-09 13:25:08 -08:00
URI href = entityRepository.getHref(uriInfo, ref.getId());
ref.withHref(href);
2021-11-09 13:25:08 -08:00
}
2021-08-01 14:27:44 -07:00
public static Fields getFields(String entityType, List<String> fields) {
EntityRepository<?> entityRepository = Entity.getEntityRepository(entityType);
return entityRepository.getFields(String.join(",", fields));
}
public static <T> T getEntity(EntityReference ref, String fields, Include include) {
return ref.getId() != null
? getEntity(ref.getType(), ref.getId(), fields, include)
: getEntityByName(ref.getType(), ref.getFullyQualifiedName(), fields, include);
}
public static <T> T getEntityOrNull(
EntityReference entityReference, String field, Include include) {
if (entityReference == null) return null;
return Entity.getEntity(entityReference, field, include);
}
public static <T> T getEntity(EntityLink link, String fields, Include include) {
return getEntityByName(link.getEntityType(), link.getEntityFQN(), fields, include);
}
/** Retrieve the entity using id from given entity reference and fields */
public static <T> T getEntity(
String entityType, UUID id, String fields, Include include, boolean fromCache) {
EntityRepository<?> entityRepository = Entity.getEntityRepository(entityType);
@SuppressWarnings("unchecked")
T entity =
(T) entityRepository.get(null, id, entityRepository.getFields(fields), include, fromCache);
return entity;
}
public static <T> T getEntity(String entityType, UUID id, String fields, Include include) {
return getEntity(entityType, id, fields, include, true);
}
2022-03-20 18:01:51 -07:00
/** Retrieve the entity using id from given entity reference and fields */
public static <T> T getEntityByName(
String entityType, String fqn, String fields, Include include, boolean fromCache) {
2022-03-20 18:01:51 -07:00
EntityRepository<?> entityRepository = Entity.getEntityRepository(entityType);
@SuppressWarnings("unchecked")
T entity =
(T)
entityRepository.getByName(
null, fqn, entityRepository.getFields(fields), include, fromCache);
return entity;
}
public static <T> T getEntityByName(
String entityType, String fqn, String fields, Include include) {
return getEntityByName(entityType, fqn, fields, include, true);
}
/** Retrieve the corresponding entity repository for a given entity name. */
public static EntityRepository<? extends EntityInterface> getEntityRepository(
@NonNull String entityType) {
EntityRepository<? extends EntityInterface> entityRepository =
ENTITY_REPOSITORY_MAP.get(entityType);
2021-11-09 13:25:08 -08:00
if (entityRepository == null) {
throw EntityNotFoundException.byMessage(
CatalogExceptionMessage.entityRepositoryNotFound(entityType));
2021-11-09 13:25:08 -08:00
}
return entityRepository;
2021-08-01 14:27:44 -07:00
}
public static EntityTimeSeriesRepository<? extends EntityTimeSeriesInterface>
getEntityTimeSeriesRepository(@NonNull String entityType) {
EntityTimeSeriesRepository<? extends EntityTimeSeriesInterface> entityTimeSeriesRepository =
ENTITY_TS_REPOSITORY_MAP.get(entityType);
if (entityTimeSeriesRepository == null) {
throw EntityNotFoundException.byMessage(
CatalogExceptionMessage.entityTypeNotFound(entityType));
}
return entityTimeSeriesRepository;
}
/** Retrieve the corresponding entity repository for a given entity name. */
public static EntityRepository<? extends EntityInterface> getServiceEntityRepository(
@NonNull ServiceType serviceType) {
EntityRepository<? extends EntityInterface> entityRepository =
ENTITY_REPOSITORY_MAP.get(SERVICE_TYPE_ENTITY_MAP.get(serviceType));
if (entityRepository == null) {
throw EntityNotFoundException.byMessage(
CatalogExceptionMessage.entityTypeNotFound(serviceType.value()));
}
return entityRepository;
}
public static List<TagLabel> getEntityTags(String entityType, EntityInterface entity) {
EntityRepository<? extends EntityInterface> entityRepository = getEntityRepository(entityType);
return listOrEmpty(entityRepository.getAllTags(entity));
}
2022-03-20 18:01:51 -07:00
public static void deleteEntity(
String updatedBy, String entityType, UUID entityId, boolean recursive, boolean hardDelete) {
EntityRepository<?> dao = getEntityRepository(entityType);
try {
dao.find(entityId, Include.ALL);
dao.delete(updatedBy, entityId, recursive, hardDelete);
} catch (EntityNotFoundException e) {
LOG.warn("Entity {} is already deleted.", entityId);
}
}
public static void restoreEntity(String updatedBy, String entityType, UUID entityId) {
EntityRepository<?> dao = getEntityRepository(entityType);
dao.restoreEntity(updatedBy, entityType, entityId);
}
public static <T> String getEntityTypeFromClass(Class<T> clz) {
return EntityInterface.CANONICAL_ENTITY_NAME_MAP.get(
clz.getSimpleName().toLowerCase(Locale.ROOT));
}
public static String getEntityTypeFromObject(Object object) {
return EntityInterface.CANONICAL_ENTITY_NAME_MAP.get(
object.getClass().getSimpleName().toLowerCase(Locale.ROOT));
}
public static Class<? extends EntityInterface> getEntityClassFromType(String entityType) {
return EntityInterface.ENTITY_TYPE_TO_CLASS_MAP.get(entityType.toLowerCase(Locale.ROOT));
}
public static Class<? extends EntityTimeSeriesInterface> getEntityTimeSeriesClassFromType(
String entityType) {
return EntityTimeSeriesInterface.ENTITY_TYPE_TO_CLASS_MAP.get(
entityType.toLowerCase(Locale.ROOT));
}
/**
* Get list of all the entity field names from JsonPropertyOrder annotation from generated java class from entity.json
*/
public static <T> Set<String> getEntityFields(Class<T> clz) {
JsonPropertyOrder propertyOrder = clz.getAnnotation(JsonPropertyOrder.class);
return new HashSet<>(Arrays.asList(propertyOrder.value()));
}
/** Returns true if the entity supports activity feeds, announcement, and tasks */
public static boolean supportsFeed(String entityType) {
return listOf(
TABLE,
DATABASE,
DATABASE_SCHEMA,
METRICS,
DASHBOARD,
DASHBOARD_DATA_MODEL,
PIPELINE,
CHART,
REPORT,
TOPIC,
MLMODEL,
CONTAINER,
QUERY,
GLOSSARY,
GLOSSARY_TERM,
TAG,
CLASSIFICATION)
.contains(entityType);
}
/** Class for getting validated entity list from a queryParam with list of entities. */
public static class EntityList {
private EntityList() {}
public static List<String> getEntityList(String name, String entitiesParam) {
if (entitiesParam == null) {
return Collections.emptyList();
}
entitiesParam = entitiesParam.replace(" ", "");
if (entitiesParam.equals("*")) {
return List.of("*");
}
List<String> list = Arrays.asList(entitiesParam.split(","));
validateEntities(name, list);
return list;
}
private static void validateEntities(String name, List<String> list) {
for (String entity : list) {
if (ENTITY_REPOSITORY_MAP.get(entity) == null) {
throw new IllegalArgumentException(
String.format("Invalid entity %s in query param %s", entity, name));
}
}
}
}
/** Compile a list of REST collections based on Resource classes marked with {@code Repository} annotation */
private static List<Class<?>> getRepositories() {
try (ScanResult scanResult = new ClassGraph().enableAnnotationInfo().scan()) {
ClassInfoList classList = scanResult.getClassesWithAnnotation(Repository.class);
return classList.loadClasses();
}
}
public static <T extends FieldInterface> void populateEntityFieldTags(
String entityType, List<T> fields, String fqnPrefix, boolean setTags) {
EntityRepository<?> repository = Entity.getEntityRepository(entityType);
// Get Flattened Fields
List<T> flattenedFields = getFlattenedEntityField(fields);
// Fetch All tags belonging to Prefix
Map<String, List<TagLabel>> allTags = repository.getTagsByPrefix(fqnPrefix, ".%");
for (T c : listOrEmpty(flattenedFields)) {
if (setTags) {
List<TagLabel> columnTag =
allTags.get(FullyQualifiedName.buildHash(c.getFullyQualifiedName()));
if (columnTag == null) {
c.setTags(new ArrayList<>());
} else {
c.setTags(addDerivedTags(columnTag));
}
} else {
c.setTags(c.getTags());
}
}
}
public static SearchIndex buildSearchIndex(String entityType, Object entity) {
if (searchRepository != null) {
return searchRepository.getSearchIndexFactory().buildIndex(entityType, entity);
}
throw new BadRequestException("searchrepository not initialized");
}
public static <T> T getDao() {
return (T) collectionDAO;
}
2021-08-01 14:27:44 -07:00
}