package com.shootoff.util; import static java.net.URLEncoder.encode; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.Optional; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import oshi.SystemInfo; public class HardwareData { private static final Logger logger = LoggerFactory.getLogger(HardwareData.class); private static final SystemInfo si = new SystemInfo(); private static final long BYTES_IN_MEGABYTE = 1048576; public static String getCpuName() { // Remove (R) and (TM) because they make the processor harder to search // for as most databases don't include them return si.getHardware().getProcessor().getName().replaceAll("\\(R\\)", "").replaceAll("\\(TM\\)", ""); } public static long getMegabytesOfRam() { return si.getHardware().getMemory().getTotal() / BYTES_IN_MEGABYTE; } public static Optional<Integer> getCpuScore() { final String cpuResult = searchCpuByName(getCpuName()); if ("Connection to the search engine failed.".equals(cpuResult) || cpuResult.startsWith("No results found")) return Optional.empty(); final String cpuData = getCpuByUrl(cpuResult); if (logger.isTraceEnabled()) logger.trace("CPU score data: {}", cpuData); final JSONParser parser = new JSONParser(); try { final JSONObject jsonObject = (JSONObject) parser.parse(cpuData); final JSONObject scoreData = (JSONObject) jsonObject.values().toArray()[0]; return Optional.of(Integer.parseInt((String) scoreData.get("Score"))); } catch (final ParseException e) { return Optional.empty(); } } /* * Copyright (c) 2015 yakka34 Permission is hereby granted, free of charge, * to any person obtaining a copy of this software and associated * documentation files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies of the * Software, and to permit persons to whom the Software is furnished to do * so, subject to the following conditions: The above copyright notice and * this permission notice shall be included in all copies or substantial * portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT * WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH * THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ private static String getCpuByUrl(String url) { final String jsonString = getCpuInfo(url); return jsonString; } // Uses cpubenchmark.net's zoom zearch and returns cpu's // benhmark/information url. private static String searchCpuByName(String cpuName) { final String encodedName = encodeToUrl(cpuName); Document html = null; String url = null; try { // Connects to zoom's search engine and looks for given cpu from // benhmarks section. html = Jsoup.connect("https://www.passmark.com/search/zoomsearch.php?zoom_sort=0&zoom_query=" + encodedName + "&zoom_cat%5B%5D=5").get(); } catch (final IOException e) { logger.warn("Connection throws an exception: " + e); } // Regex check is used to validate correct search result. if (html != null) { Elements links = html.select("div.results"); links = links.select("a[href~=^(https?:\\/\\/www.cpubenchmark.net/cpu.php\\?)]"); url = links.attr("href"); if (url.isEmpty()) { return "No results found for: " + cpuName; } } // message for connection issues. else { return "Connection to the search engine failed."; } return url; } // getCpuInfo calls various methods to construct a complete Json formated // string from given url. private static String getCpuInfo(String url) { Document html = null; String infoString; String jsonString; String infoArray[]; try { html = Jsoup.connect(url).get(); } catch (final IOException e) { logger.warn("Connection to: " + url + " ,throws an exception: " + e); } if (html != null) { // Attributes in the infoString are seperated by commas and data by // semicolons. infoString = parseHtmlForInfo(html); // infoString needs to be split into array for further processing. infoArray = parseStringToArray(infoString); // Array is used to create JSONString. jsonString = convertArrayToJsonString(infoArray); } else { logger.warn("No CPU data html value assigned returning null!"); return null; } return jsonString; } // Parses given html file. Data parsing is hardcoded because lack of id // tagging on cpubenchmark.net behalf. private static String parseHtmlForInfo(Document html) { // Instead of parsing the the whole html page everytime, only useful // table section is used. final Element table = html.select("table.desc").first(); // <span> containing the name is clearly labeled as cpuname. final String cpuName = table.select("span.cpuname").text(); // Score is the last one to use <span> tag and will be parsed to int. final int cpuScore = Integer.parseInt(table.select("span").last().text()); // There are 2 <em> tags containing information. First one has // description and second one has "Other names" eg.alternative name. final String description = table.select("em").first().text(); final String altName = table.select("em").last().text(); // Name -> Score -> possible description -> AltName. final String infoString = cpuName + ",Score:" + cpuScore + "," + description + ",AltName:" + altName; return infoString; } // Splits the infoString into array by using regex split. private static String[] parseStringToArray(String infoString) { // Splits the String everytime it founds comma or semicolon. final String[] infoArray = infoString.split("[,:]"); return infoArray; } // Data from array is read and placed into json object which will be parsed // into String. @SuppressWarnings("unchecked") private static String convertArrayToJsonString(String[] infoArray) { // Depending on prefered formating, use of temp is not necessary. final JSONObject temp = new JSONObject(); final JSONObject jObj = new JSONObject(); final int length = infoArray.length; for (int i = 1; i < length - 1; i += 2) { final int y = i + 1; temp.put(infoArray[i].trim(), infoArray[y].trim()); } // Name of the cpu is always located first in the array. jObj.put(infoArray[0], temp); return jObj.toString(); } private static String encodeToUrl(String string) { String encodedUrl = null; try { encodedUrl = encode(string, "UTF-8"); } catch (final UnsupportedEncodingException e) { logger.warn("Encoding not supported: " + e); } return encodedUrl; } }