/*
* Copyright 2017 Hewlett Packard Enterprise Development Company, L.P.
* Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
*/
package com.hp.autonomy.frontend.find.idol.savedsearches.snapshot;
import com.autonomy.aci.client.services.AciErrorException;
import com.hp.autonomy.frontend.configuration.ConfigService;
import com.hp.autonomy.frontend.find.core.beanconfiguration.BiConfiguration;
import com.hp.autonomy.frontend.find.core.savedsearches.EmbeddableIndex;
import com.hp.autonomy.frontend.find.core.savedsearches.FieldTextParser;
import com.hp.autonomy.frontend.find.core.savedsearches.SavedSearchService;
import com.hp.autonomy.frontend.find.core.savedsearches.SavedSearchType;
import com.hp.autonomy.frontend.find.core.savedsearches.snapshot.SavedSnapshot;
import com.hp.autonomy.frontend.find.core.savedsearches.snapshot.SavedSnapshot.Builder;
import com.hp.autonomy.frontend.find.idol.dashboards.IdolDashboardConfig;
import com.hp.autonomy.frontend.find.idol.dashboards.widgets.DatasourceDependentWidget;
import com.hp.autonomy.frontend.find.idol.dashboards.widgets.datasources.SavedSearchDatasource;
import com.hp.autonomy.searchcomponents.core.search.StateTokenAndResultCount;
import com.hp.autonomy.searchcomponents.core.search.TypedStateToken;
import com.hp.autonomy.searchcomponents.idol.search.IdolDocumentsService;
import com.hp.autonomy.searchcomponents.idol.search.IdolQueryRestrictions;
import com.hp.autonomy.searchcomponents.idol.search.IdolQueryRestrictionsBuilder;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@RestController
@RequestMapping(SavedSnapshotController.PATH)
@ConditionalOnProperty(BiConfiguration.BI_PROPERTY)
class SavedSnapshotController {
static final String PATH = "/api/bi/saved-snapshot";
private static final Integer STATE_TOKEN_MAX_RESULTS = Integer.MAX_VALUE;
private final IdolDocumentsService documentsService;
private final SavedSearchService<SavedSnapshot, Builder> service;
private final FieldTextParser fieldTextParser;
private final ObjectFactory<IdolQueryRestrictionsBuilder> queryRestrictionsBuilderFactory;
private final ConfigService<IdolDashboardConfig> dashboardConfigService;
@SuppressWarnings("TypeMayBeWeakened")
@Autowired
public SavedSnapshotController(final IdolDocumentsService documentsService,
final SavedSearchService<SavedSnapshot, Builder> service,
final FieldTextParser fieldTextParser,
final ObjectFactory<IdolQueryRestrictionsBuilder> queryRestrictionsBuilderFactory,
final ConfigService<IdolDashboardConfig> dashboardConfigService) {
this.documentsService = documentsService;
this.service = service;
this.fieldTextParser = fieldTextParser;
this.queryRestrictionsBuilderFactory = queryRestrictionsBuilderFactory;
this.dashboardConfigService = dashboardConfigService;
}
private Collection<Long> getValidIds() {
return dashboardConfigService.getConfig().getDashboards().stream()
.flatMap(dashboard -> dashboard.getWidgets().stream()
.filter(widget -> widget instanceof DatasourceDependentWidget)
.map(widget -> (DatasourceDependentWidget) widget)
.filter(widget -> widget.getDatasource() instanceof SavedSearchDatasource)
.map(widget -> (SavedSearchDatasource) widget.getDatasource())
.filter(datasource -> datasource.getConfig().getType() == SavedSearchType.SNAPSHOT)
.map(datasource -> datasource.getConfig().getId()))
.collect(Collectors.toSet());
}
@RequestMapping(method = RequestMethod.GET)
public Set<SavedSnapshot> getAll() {
return service.getAll();
}
@RequestMapping(method = RequestMethod.POST)
public SavedSnapshot create(
@RequestBody final SavedSnapshot snapshot
) throws AciErrorException {
final List<StateTokenAndResultCount> stateTokensList = Arrays.asList(
getStateTokenAndResultCount(snapshot, false),
getStateTokenAndResultCount(snapshot, true)
);
final Set<TypedStateToken> stateTokens = new HashSet<>();
for(final StateTokenAndResultCount listToken : stateTokensList) {
final TypedStateToken token = listToken.getTypedStateToken();
stateTokens.add(token);
}
// use result count from the query without promotions
final long resultCount = stateTokensList.get(0).getResultCount();
return service.create(
new Builder(snapshot)
.setStateTokens(stateTokens)
.setResultCount(resultCount)
.build()
);
}
@RequestMapping(value = "{id}", method = RequestMethod.PUT)
public SavedSnapshot update(
@PathVariable("id") final long id,
@RequestBody final SavedSnapshot snapshot
) throws AciErrorException {
// It is only possible to update a snapshot's title
return service.update(
new Builder()
.setId(id)
.setTitle(snapshot.getTitle())
.build()
);
}
@RequestMapping(value = "{id}", method = RequestMethod.DELETE)
public void delete(
@PathVariable("id") final long id
) {
service.deleteById(id);
}
private StateTokenAndResultCount getStateTokenAndResultCount(final SavedSnapshot snapshot, final boolean promotions) throws AciErrorException {
final List<String> indexes;
if(snapshot.getIndexes() == null) {
indexes = null;
} else {
indexes = new ArrayList<>();
indexes.addAll(snapshot.getIndexes().stream().map(EmbeddableIndex::getName).collect(Collectors.toList()));
}
final IdolQueryRestrictions restrictions = queryRestrictionsBuilderFactory.getObject()
.databases(indexes)
.queryText(snapshot.toQueryText())
.fieldText(fieldTextParser.toFieldText(snapshot))
.maxDate(snapshot.getMaxDate())
.minDate(snapshot.getMinDate())
.minScore(snapshot.getMinScore())
.build();
return documentsService.getStateTokenAndResultCount(restrictions, STATE_TOKEN_MAX_RESULTS, promotions);
}
@RequestMapping(method = RequestMethod.GET, value = "/{id}")
public SavedSnapshot get(@PathVariable("id") final long id) {
if(getValidIds().contains(id)) {
return Optional.ofNullable(service.getDashboardSearch(id))
.orElseThrow(() -> new IllegalArgumentException("Configured ID " + id + " does not match any known Saved Snapshot"));
} else {
throw new IllegalArgumentException("Saved Snapshot ID " + id + " is not in the dashboards configuration file");
}
}
}