/* This file is part of RouteConverter. RouteConverter is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. RouteConverter is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with RouteConverter; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Copyright (C) 2007 Christian Pesch. All Rights Reserved. */ package slash.navigation.feedback.domain; import slash.navigation.datasources.DataSource; import slash.navigation.datasources.Downloadable; import slash.navigation.datasources.File; import slash.navigation.datasources.Fragment; import slash.navigation.datasources.Theme; import slash.navigation.datasources.binding.DatasourceType; import slash.navigation.datasources.binding.FileType; import slash.navigation.datasources.binding.FragmentType; import slash.navigation.datasources.binding.MapType; import slash.navigation.datasources.binding.ThemeType; import slash.navigation.datasources.helpers.DataSourcesUtil; import slash.navigation.download.FileAndChecksum; import slash.navigation.rest.Credentials; import slash.navigation.rest.Delete; import slash.navigation.rest.Post; import slash.navigation.rest.Put; import slash.navigation.rest.exception.ForbiddenException; import slash.navigation.rest.exception.UnAuthorizedException; import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.logging.Logger; import static java.lang.String.format; import static java.lang.String.valueOf; import static java.util.Locale.getDefault; import static slash.common.io.Transfer.UTF8_ENCODING; import static slash.navigation.datasources.DataSourceManager.DATASOURCES_URI; import static slash.navigation.datasources.DataSourceManager.V1; import static slash.navigation.datasources.helpers.DataSourcesUtil.asChecksums; import static slash.navigation.datasources.helpers.DataSourcesUtil.asDatasourceType; import static slash.navigation.datasources.helpers.DataSourcesUtil.asMetaDataComparablePath; import static slash.navigation.datasources.helpers.DataSourcesUtil.createFileType; import static slash.navigation.datasources.helpers.DataSourcesUtil.createFragmentType; import static slash.navigation.datasources.helpers.DataSourcesUtil.createMapType; import static slash.navigation.datasources.helpers.DataSourcesUtil.createThemeType; import static slash.navigation.rest.HttpRequest.APPLICATION_JSON; /** * Encapsulates REST access to the RouteFeedback service of RouteConverter. * * @author Christian Pesch */ public class RouteFeedback { private static final Logger log = Logger.getLogger(RouteFeedback.class.getName()); private static final String ERROR_REPORT_URI = "error-report/"; private static final String UPDATE_CHECK_URI = "update-check/"; static final String USER_URI = V1 + "users/"; private final String rootUrl; private final String apiUrl; private final Credentials credentials; public RouteFeedback(String rootUrl, String apiUrl, Credentials credentials) { this.rootUrl = rootUrl; this.apiUrl = apiUrl; this.credentials = credentials; } public String addUser(String userName, String password, String firstName, String lastName, String email) throws IOException { log.info("Adding user " + userName + "," + firstName + "," + lastName + "," + email); Post request = new Post(apiUrl + USER_URI); request.setAccept(APPLICATION_JSON); request.addString("username", userName); request.addString("password", password); request.addString("first_name", firstName); request.addString("last_name", lastName); request.addString("email", email); String result = request.executeAsString(); if (request.isBadRequest()) throw new ForbiddenException("Cannot add user: " + result, apiUrl + USER_URI); if (request.isForbidden()) throw new ForbiddenException("Cannot add user: " + result, apiUrl + USER_URI); if (!request.isSuccessful()) throw new IOException("POST on " + (apiUrl + USER_URI) + " with payload " + userName + "," + firstName + "," + lastName + "," + email + " not successful: " + result); return request.getLocation(); } void deleteUser(String userUrl) throws IOException { log.info("Deleting user " + userUrl); Delete request = new Delete(userUrl, credentials); request.setAccept(APPLICATION_JSON); String result = request.executeAsString(); if (request.isBadRequest()) throw new ForbiddenException("Not authorized to delete user", userUrl); if (!request.isSuccessful()) throw new IOException("DELETE on " + userUrl + " not successful: " + result); } private String getErrorReportUrl() { return rootUrl + ERROR_REPORT_URI; } public String sendErrorReport(String logOutput, String description, java.io.File file) throws IOException { log.fine("Sending error report with log \"" + logOutput + "\", description \"" + description + "\"" + (file != null ? ", file " + file.getAbsolutePath() : "")); Post request = new Post(getErrorReportUrl(), credentials); request.addString("log", logOutput); request.addString("description", description); if (file != null) request.addFile("file", file); String result = request.executeAsString(); if (request.isUnAuthorized()) throw new UnAuthorizedException("Cannot send error report " + (file != null ? ", file " + file.getAbsolutePath() : ""), getErrorReportUrl()); if (!request.isSuccessful()) throw new IOException("POST on " + getErrorReportUrl() + " with log " + logOutput.length() + " characters" + ", description \"" + description + "\", file " + file + " not successful: " + result); return request.getLocation(); } public String checkForUpdate(String routeConverterVersion, String routeConverterBits, long startCount, String javaVersion, String javaBits, String osName, String osVersion, String osArch, String webstartVersion, long startTime) throws IOException { log.fine("Checking for update for version " + routeConverterVersion); Post request = new Post(rootUrl + UPDATE_CHECK_URI, credentials); request.addString("id", valueOf(startTime)); request.addString("javaBits", javaBits); request.addString("javaVersion", javaVersion); request.addString("locale", getDefault().getLanguage()); request.addString("osArch", osArch); request.addString("osName", osName); request.addString("osVersion", osVersion); request.addString("rcStartCount", Long.toString(startCount)); request.addString("rcVersion", routeConverterVersion); request.addString("rcBits", routeConverterBits); if (webstartVersion != null) request.addString("webstartVersion", webstartVersion); return request.executeAsString().replace("\"", ""); } private boolean contains(String[] array, String name) { for (String anArray : array) { if (name.equals(anArray)) return true; } return false; } private Set<FileAndChecksum> findFile(Fragment fragment, java.util.Map<FileAndChecksum, List<FileAndChecksum>> fileAndChecksumMap) throws IOException { Set<FileAndChecksum> result = new HashSet<>(); for (List<FileAndChecksum> fileAndChecksums : fileAndChecksumMap.values()) { for (FileAndChecksum fileAndChecksum : fileAndChecksums) { String filePath = asMetaDataComparablePath(fileAndChecksum.getFile()); if (filePath.contains(fragment.getKey())) result.add(fileAndChecksum); } } return result; } private List<FragmentType> createFragmentTypes(List<Fragment<Downloadable>> fragments, java.util.Map<FileAndChecksum, List<FileAndChecksum>> fileAndChecksums) throws IOException { if (fragments == null) return null; List<FragmentType> fragmentTypes = new ArrayList<>(); for (Fragment fragment : fragments) fragmentTypes.add(createFragmentType(fragment, findFile(fragment, fileAndChecksums))); return fragmentTypes; } private String toXml(DataSource dataSource, java.util.Map<FileAndChecksum, List<FileAndChecksum>> fileToFragments, String... filterUrls) throws IOException { DatasourceType datasourceType = asDatasourceType(dataSource); for (File aFile : dataSource.getFiles()) { if (!contains(filterUrls, dataSource.getBaseUrl() + aFile.getUri())) continue; FileType fileType = createFileType(aFile.getUri(), asChecksums(fileToFragments.keySet()), aFile.getBoundingBox()); List<FragmentType> fragmentTypes = createFragmentTypes(aFile.getFragments(), fileToFragments); if (fragmentTypes != null) fileType.getFragment().addAll(fragmentTypes); datasourceType.getFile().add(fileType); } for (slash.navigation.datasources.Map map : dataSource.getMaps()) { if (!contains(filterUrls, dataSource.getBaseUrl() + map.getUri())) continue; MapType mapType = createMapType(map.getUri(), asChecksums(fileToFragments.keySet()), map.getBoundingBox()); List<FragmentType> fragmentTypes = createFragmentTypes(map.getFragments(), fileToFragments); if (fragmentTypes != null) mapType.getFragment().addAll(fragmentTypes); datasourceType.getMap().add(mapType); } for (Theme theme : dataSource.getThemes()) { if (!contains(filterUrls, dataSource.getBaseUrl() + theme.getUri())) continue; ThemeType themeType = createThemeType(theme.getUri(), asChecksums(fileToFragments.keySet()), theme.getImageUrl()); List<FragmentType> fragmentTypes = createFragmentTypes(theme.getFragments(), fileToFragments); if (fragmentTypes != null) themeType.getFragment().addAll(fragmentTypes); datasourceType.getTheme().add(themeType); } return DataSourcesUtil.toXml(datasourceType); } private String getDataSourcesUrl(String dataSourceId) { return apiUrl + DATASOURCES_URI + dataSourceId + "/"; } public String sendChecksums(DataSource dataSource, java.util.Map<FileAndChecksum, List<FileAndChecksum>> fileToFragments, String filterUrl) throws IOException { String xml = toXml(dataSource, fileToFragments, filterUrl); log.info(format("Sending checksums for %s filtered with %s:%n%s", fileToFragments, filterUrl, xml)); String dataSourcesUrl = getDataSourcesUrl(dataSource.getId()); Put request = new Put(dataSourcesUrl, credentials); request.setAccept(APPLICATION_JSON); request.addFile("file", xml.getBytes(UTF8_ENCODING)); String result = request.executeAsString(); if (request.isUnAuthorized()) throw new UnAuthorizedException("Cannot send checksums", dataSourcesUrl); if (!request.isSuccessful()) throw new IOException("PUT on " + dataSourcesUrl + " for data source " + dataSource + " not successful: " + result); log.info(format("Sent checksum for %s filtered with %s with result:%n%s", fileToFragments, filterUrl, result)); return result; } }