| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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 com.epam.dlab.backendapi.domain; |
| |
| import com.epam.dlab.backendapi.resources.dto.LibraryAutoCompleteDTO; |
| import com.epam.dlab.backendapi.resources.dto.LibraryDTO; |
| import com.epam.dlab.exceptions.DlabException; |
| import com.fasterxml.jackson.databind.ObjectMapper; |
| import com.google.common.base.MoreObjects; |
| import io.dropwizard.util.Duration; |
| import lombok.extern.slf4j.Slf4j; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.TreeMap; |
| import java.util.stream.Collectors; |
| |
| /** |
| * Class to store the info about libraries. |
| */ |
| @Slf4j |
| public class ExploratoryLibList { |
| |
| /** |
| * Timeout in milliseconds when the info is out of date. |
| */ |
| private static final long EXPIRED_TIMEOUT_MILLIS = Duration.hours(2).toMilliseconds(); |
| |
| /** |
| * Timeout in milliseconds until the is out of date. |
| */ |
| private static final long UPDATE_TIMEOUT_MILLIS = Duration.minutes(30).toMilliseconds(); |
| |
| /** |
| * Timeout in milliseconds for request to update lib. |
| */ |
| protected static final long UPDATE_REQUEST_TIMEOUT_MILLIS = Duration.minutes(15).toMilliseconds(); |
| |
| /** |
| * Group name. |
| */ |
| private String group; |
| |
| /** |
| * List of libraries group:libraries:version. |
| */ |
| private Map<String, Map<String, String>> libs = new HashMap<>(); |
| |
| /** |
| * Time in milliseconds when the info is out of date. |
| */ |
| private long expiredTimeMillis = 0; |
| |
| /** |
| * Last access time in milliseconds to the info. |
| */ |
| private long accessTimeMillis = 0; |
| |
| /** |
| * Update start time in milliseconds. |
| */ |
| private long updateStartTimeMillis = 0; |
| |
| /** |
| * Update in progress. |
| */ |
| private boolean updating = false; |
| |
| |
| /** |
| * Instantiate the list of libraries. |
| * |
| * @param group the name of docker's image. |
| * @param content JSON string. |
| */ |
| ExploratoryLibList(String group, String content) { |
| this.group = group; |
| if (content != null) { |
| setLibs(content); |
| } |
| } |
| |
| /** |
| * Return the list of all groups. |
| */ |
| public List<String> getGroupList() { |
| List<String> list = new ArrayList<>(libs.keySet()); |
| Collections.sort(list); |
| return list; |
| } |
| |
| /** |
| * Return the name of docker image; |
| */ |
| public String getGroup() { |
| return group; |
| } |
| |
| /** |
| * Return the full list of libraries for group. |
| * |
| * @param group the name of group. |
| */ |
| public Map<String, String> getLibs(String group) { |
| return libs.get(group); |
| } |
| |
| /** |
| * Return the full list of libraries for group. |
| * |
| * @param content JSON string. |
| */ |
| private void setLibs(String content) { |
| ObjectMapper mapper = new ObjectMapper(); |
| try { |
| synchronized (this) { |
| @SuppressWarnings("unchecked") |
| Map<String, Map<String, String>> map = mapper.readValue(content, Map.class); |
| for (Map.Entry<String, Map<String, String>> entry : map.entrySet()) { |
| Map<String, String> group = entry.getValue(); |
| String groupName = entry.getKey(); |
| libs.remove(groupName); |
| log.info("Update {} group with lib group {} with {} libraries", this.group, groupName, (group != null) ? group.size() : null); |
| libs.put(groupName, new TreeMap<>(group)); |
| } |
| setExpiredTime(); |
| updating = false; |
| } |
| } catch (IOException e) { |
| throw new DlabException("Cannot deserialize the list of libraries. " + e.getLocalizedMessage(), e); |
| } |
| } |
| |
| public void setExpiredTime() { |
| expiredTimeMillis = System.currentTimeMillis() + EXPIRED_TIMEOUT_MILLIS; |
| accessTimeMillis = System.currentTimeMillis(); |
| } |
| |
| /** |
| * Search and return the list of libraries for name's prefix <b>startWith</b>. |
| * |
| * @param group the name of group. |
| * @param startWith the prefix for library name. |
| * @return LibraryAutoCompleteDTO dto |
| */ |
| public LibraryAutoCompleteDTO getLibs(String group, String startWith) { |
| final String startsWithLower = startWith.toLowerCase(); |
| Map<String, String> libMap = getLibs(group); |
| if (libMap == null) { |
| return LibraryAutoCompleteDTO.builder() |
| .autoComplete(isUpdating() ? AutoCompleteEnum.UPDATING : AutoCompleteEnum.NONE) |
| .libraries(Collections.emptyList()) |
| .build(); |
| } |
| List<LibraryDTO> libraries = libMap.entrySet() |
| .stream() |
| .filter(e -> e.getKey().toLowerCase().startsWith(startsWithLower)) |
| .map(e -> new LibraryDTO(e.getKey(), e.getValue())) |
| .collect(Collectors.toList()); |
| |
| return LibraryAutoCompleteDTO.builder() |
| .autoComplete(AutoCompleteEnum.ENABLED) |
| .libraries(libraries) |
| .build(); |
| } |
| |
| /** |
| * Set last access time. |
| */ |
| private void touch() { |
| accessTimeMillis = System.currentTimeMillis(); |
| } |
| |
| /** |
| * Return <b>true</b> if the info is out of date. |
| */ |
| public boolean isExpired() { |
| touch(); |
| return (expiredTimeMillis < System.currentTimeMillis()); |
| } |
| |
| /** |
| * Return <b>true</b> if the info needs to update. |
| */ |
| public boolean isUpdateNeeded() { |
| touch(); |
| return (accessTimeMillis > expiredTimeMillis - UPDATE_TIMEOUT_MILLIS); |
| } |
| |
| /** |
| * Set updating in progress. |
| */ |
| public void setUpdating() { |
| updateStartTimeMillis = System.currentTimeMillis(); |
| updating = true; |
| } |
| |
| /** |
| * Set updating to false. |
| */ |
| public void setNotUpdating() { |
| updating = Boolean.FALSE; |
| } |
| |
| /** |
| * Return <b>true</b> if the update in progress. |
| */ |
| public boolean isUpdating() { |
| if (updating && |
| updateStartTimeMillis + UPDATE_REQUEST_TIMEOUT_MILLIS < System.currentTimeMillis()) { |
| updating = false; |
| } |
| return updating; |
| } |
| |
| |
| @Override |
| public String toString() { |
| return MoreObjects.toStringHelper(this) |
| .add("group", group) |
| .add("expiredTimeMillis", expiredTimeMillis) |
| .add("accessTimeMillis", accessTimeMillis) |
| .add("updateStartTimeMillis", updateStartTimeMillis) |
| .add("isUpdating", updating) |
| .add("libs", (libs == null ? "null" : "...")) |
| .toString(); |
| } |
| } |