• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

HotelsDotCom / waggle-dance / #489

25 Jun 2026 01:07AM UTC coverage: 69.255% (-0.01%) from 69.269%
#489

push

web-flow
Merge e9de2a718 into bbd99ea37

7 of 10 new or added lines in 5 files covered. (70.0%)

2631 of 3799 relevant lines covered (69.26%)

0.69 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.12
/waggle-dance-core/src/main/java/com/hotels/bdp/waggledance/mapping/model/MetaStoreMappingImpl.java
1
/**
2
 * Copyright (C) 2016-2026 Expedia, Inc.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 * http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package com.hotels.bdp.waggledance.mapping.model;
17

18
import java.io.IOException;
19
import java.util.Collections;
20
import java.util.List;
21
import java.util.Locale;
22
import java.util.concurrent.CompletableFuture;
23
import java.util.concurrent.ExecutionException;
24
import java.util.concurrent.ExecutorService;
25
import java.util.concurrent.Executors;
26
import java.util.concurrent.Future;
27
import java.util.concurrent.TimeUnit;
28
import java.util.concurrent.TimeoutException;
29

30
import org.apache.hadoop.hive.metastore.MetaStoreFilterHook;
31
import org.apache.hadoop.hive.metastore.api.AlreadyExistsException;
32
import org.apache.hadoop.hive.metastore.api.Database;
33
import org.apache.hadoop.hive.metastore.api.InvalidObjectException;
34
import org.apache.hadoop.hive.metastore.api.MetaException;
35
import org.apache.hadoop.hive.metastore.api.ThriftHiveMetastore;
36
import org.apache.thrift.TException;
37
import org.slf4j.Logger;
38
import org.slf4j.LoggerFactory;
39

40
import com.hotels.bdp.waggledance.api.model.ConnectionType;
41
import com.hotels.bdp.waggledance.client.CloseableThriftHiveMetastoreIface;
42
import com.hotels.bdp.waggledance.server.security.AccessControlHandler;
43
import com.hotels.bdp.waggledance.server.security.NotAllowedException;
44

45

46
class MetaStoreMappingImpl implements MetaStoreMapping {
47

48
  private final static Logger log = LoggerFactory.getLogger(MetaStoreMappingImpl.class);
1✔
49

50
  // MilliSeconds
51
  static final long DEFAULT_AVAILABILITY_TIMEOUT = 2000;
52

53
  private final String databasePrefix;
54
  private final String name;
55
  private final CloseableThriftHiveMetastoreIface client;
56
  private final AccessControlHandler accessControlHandler;
57
  private final ConnectionType connectionType;
58
  private final long latency;
59
  private final MetaStoreFilterHook metastoreFilter;
60
  private final boolean glueBackend;
61
  private final ExecutorService executor = Executors.newSingleThreadExecutor();
1✔
62

63
  MetaStoreMappingImpl(
64
      String databasePrefix,
65
      String name,
66
      CloseableThriftHiveMetastoreIface client,
67
      AccessControlHandler accessControlHandler,
68
      ConnectionType connectionType,
69
      long latency,
70
      MetaStoreFilterHook metastoreFilter,
71
      boolean glueBackend) {
1✔
72
    this.databasePrefix = databasePrefix;
1✔
73
    this.name = name;
1✔
74
    this.client = client;
1✔
75
    this.accessControlHandler = accessControlHandler;
1✔
76
    this.connectionType = connectionType;
1✔
77
    this.latency = latency;
1✔
78
    this.metastoreFilter = metastoreFilter;
1✔
79
    this.glueBackend = glueBackend;
1✔
80
  }
1✔
81

82
  @Override
83
  public String transformOutboundDatabaseName(String databaseName) {
84
    return databaseName.toLowerCase(Locale.ROOT);
1✔
85
  }
86

87
  @Override
88
  public List<String> transformOutboundDatabaseNameMultiple(String databaseName) {
89
    return Collections.singletonList(transformInboundDatabaseName(databaseName));
1✔
90
  }
91

92
  @Override
93
  public ThriftHiveMetastore.Iface getClient() {
94
    return client;
1✔
95
  }
96

97
  @Override
98
  public MetaStoreFilterHook getMetastoreFilter() {
99
    return metastoreFilter;
1✔
100
  }
101

102
  @Override
103
  public Database transformOutboundDatabase(Database database) {
104
    database.setName(transformOutboundDatabaseName(database.getName()));
1✔
105
    return database;
1✔
106
  }
107

108
  @Override
109
  public String transformInboundDatabaseName(String databaseName) {
110
    return databaseName.toLowerCase(Locale.ROOT);
1✔
111
  }
112

113
  @Override
114
  public String getDatabasePrefix() {
115
    return databasePrefix;
1✔
116
  }
117

118
  @Override
119
  public void close() throws IOException {
120
    client.close();
1✔
121
    executor.shutdownNow();
1✔
122
  }
1✔
123

124
  /**
125
   * This is potentially slow so a best effort is made and false is returned after a timeout.
126
   */
127
  @Override
128
  public boolean isAvailable() {
129
    Future<Boolean> future = CompletableFuture.supplyAsync(() -> {
1✔
130
      try {
131
        boolean isOpen = client.isOpen();
1✔
132
        if (isOpen && connectionType == ConnectionType.TUNNELED) {
1✔
133
          client.getStatus();
1✔
134
        }
135
        return isOpen;
1✔
136
      } catch (Exception e) {
1✔
137
        log.error("Metastore Mapping {} unavailable", name, e);
1✔
138
        return false;
1✔
139
      }
140
    }, executor);
141
    long timeout = DEFAULT_AVAILABILITY_TIMEOUT + getLatency();
1✔
142
    try {
143
      return future.get(timeout, TimeUnit.MILLISECONDS);
1✔
144
    } catch (TimeoutException e) {
1✔
145
      log.info("Took too long (>" + timeout + "ms) to check availability of '" + name + "', assuming unavailable");
1✔
146
      future.cancel(true);
1✔
147
    } catch (InterruptedException | ExecutionException e) {
×
148
      log.error("Error while checking availability '" + name + "', assuming unavailable");
×
149
    }
1✔
150
    return false;
1✔
151
  }
152

153
  @Override
154
  public MetaStoreMapping checkWritePermissions(String databaseName) {
155
    if (!accessControlHandler.hasWritePermission(databaseName)) {
1✔
156
      throw new NotAllowedException(
1✔
157
          "You cannot perform this operation on the virtual database '" + databaseName + "'.");
158
    }
159
    return this;
1✔
160
  }
161

162
  @Override
163
  public void createDatabase(Database database)
164
    throws AlreadyExistsException, InvalidObjectException, MetaException, TException {
165
    if (accessControlHandler.hasCreatePermission()) {
1✔
166
      getClient().create_database(database);
1✔
167
      accessControlHandler.databaseCreatedNotification(database.getName());
1✔
168
    } else {
169
      throw new NotAllowedException("You cannot create the database '" + database.getName() + "'.");
1✔
170
    }
171
  }
1✔
172

173
  @Override
174
  public String getMetastoreMappingName() {
175
    return name;
1✔
176
  }
177

178
  @Override
179
  public long getLatency() {
180
    return latency;
1✔
181
  }
182

183
  @Override
184
  public boolean isGlueBackend() {
NEW
185
    return glueBackend;
×
186
  }
187

188
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc