Java tutorial
/* * AndFHEM - Open Source Android application to control a FHEM home automation * server. * * Copyright (c) 2011, Matthias Klass or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are * distributed under license by Red Hat Inc. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU GENERAL PUBLIC LICENSE, as published by the Free Software Foundation. * * This program 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 this distribution; if not, write to: * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ package li.klass.fhem.service.graph.gplot; import com.google.common.base.Charsets; import com.google.common.base.Optional; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Range; import com.google.common.io.Resources; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import java.net.JarURLConnection; import java.net.URISyntaxException; import java.net.URL; import java.util.Enumeration; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Queue; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.inject.Inject; import javax.inject.Singleton; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Maps.newHashMap; import static java.util.Collections.emptyMap; @Singleton public class GPlotParser { public static final Pattern SETS_PATTERN = Pattern.compile("set ([a-zA-Z0-9]+) [\"'\\[]([^\"^\']+)[\"'\\]]"); public static final Pattern AXIS_PATTERN = Pattern.compile("axes x1y([12])"); public static final Pattern TITLE_PATTERN = Pattern.compile("title '([^']*)'"); public static final Pattern TYPE_PATTERN = Pattern.compile("with ([a-zA-Z]+)"); public static final Pattern SERIES_TYPE_PATTERN = Pattern.compile("(l[0-9])((dot|fill(_stripe|_gyr)?)?)"); public static final Pattern LINE_WIDTH_PATTERN = Pattern.compile("lw ([0-9]+(\\.[0-9]+)?)"); private static final Logger LOGGER = LoggerFactory.getLogger(GPlotParser.class); public static final FilenameFilter GPLOT_FILTER = new FilenameFilter() { @Override public boolean accept(File dir, String filename) { return filename != null && filename.endsWith(".gplot"); } }; private ImmutableMap<String, GPlotSeries.SeriesColor> TO_COLOR = ImmutableMap.<String, GPlotSeries.SeriesColor>builder() .put("l0", GPlotSeries.SeriesColor.RED).put("l1", GPlotSeries.SeriesColor.GREEN) .put("l2", GPlotSeries.SeriesColor.BLUE).put("l3", GPlotSeries.SeriesColor.MAGENTA) .put("l4", GPlotSeries.SeriesColor.BROWN).put("l5", GPlotSeries.SeriesColor.WHITE) .put("l6", GPlotSeries.SeriesColor.OLIVE).put("l7", GPlotSeries.SeriesColor.GRAY) .put("l8", GPlotSeries.SeriesColor.YELLOW).build(); @Inject public GPlotParser() { } public Optional<GPlotDefinition> parseSafe(String content) { try { return Optional.of(parse(content)); } catch (Exception e) { LOGGER.info("parseSafe() - cannot parse: \r\n" + content, e); return Optional.absent(); } } public GPlotDefinition parse(String content) { List<String> lines = newArrayList(content.split("[\\r\\n]")); Map<String, String> setsDeclarations = extractSetsFrom(lines); GPlotDefinition definition = new GPlotDefinition(); definition.setLeftAxis(createAxis(setsDeclarations, "y")); definition.setRightAxis(createAxis(setsDeclarations, "y2")); List<GPlotSeries> series = extractSeriesFrom(lines); for (GPlotSeries s : series) { (s.getAxis() == GPlotSeries.Axis.LEFT ? definition.getLeftAxis() : definition.getRightAxis()) .addSeries(s); } return definition; } private GPlotAxis createAxis(Map<String, String> setsDeclarations, String prefix) { String labelKey = prefix + "label"; String rightLabel = setsDeclarations.containsKey(labelKey) ? setsDeclarations.get(labelKey) : ""; String rangeKey = prefix + "range"; Optional<Range<Double>> optRange = Optional.absent(); if (setsDeclarations.containsKey(rangeKey)) { String rangeValue = setsDeclarations.get(rangeKey); String[] parts = rangeValue.split(":"); Range<Double> range; if (rangeValue.startsWith(":")) { range = Range.atMost(Double.parseDouble(parts[0])); } else if (rangeValue.endsWith(":")) { range = Range.atLeast(Double.parseDouble(parts[0])); } else { range = Range.closed(Double.parseDouble(parts[0]), Double.parseDouble(parts[1])); } optRange = Optional.of(range); } return new GPlotAxis(rightLabel, optRange); } @SuppressWarnings("ConstantConditions") private List<GPlotSeries> extractSeriesFrom(List<String> lines) { List<GPlotSeries> result = newArrayList(); Queue<GPlotSeries.Builder> builders = new LinkedList<>(); boolean plotFound = false; for (String line : lines) { line = line.trim(); if (line.startsWith("plot")) { plotFound = true; } if (line.startsWith("#FileLog") || line.startsWith("#Log.") || line.startsWith("#logProxy")) { builders.add(new GPlotSeries.Builder().withFileLogDef(line.split(" ")[1])); } else if (line.startsWith("#DbLog")) { builders.add(new GPlotSeries.Builder().withDbLogDef(line.split(" ")[1])); } else if (plotFound) { GPlotSeries.Builder builder = builders.peek(); if (builder == null) { break; } boolean attributeFound = handleAxis(line, builder); attributeFound = handleTitle(line, builder) | attributeFound; attributeFound = handleLineType(line, builder) | attributeFound; attributeFound = handleSeriesType(line, builder) | attributeFound; attributeFound = handleLineWidth(line, builder) | attributeFound; if (attributeFound) { result.add(builder.build()); builders.remove(); } } } return result; } private boolean handleLineWidth(String line, GPlotSeries.Builder builder) { Matcher matcher = LINE_WIDTH_PATTERN.matcher(line); if (matcher.find()) { float lineWidth = Float.parseFloat(matcher.group(1)); builder.withLineWith(lineWidth); return true; } return false; } private boolean handleSeriesType(String line, GPlotSeries.Builder builder) { Matcher matcher = SERIES_TYPE_PATTERN.matcher(line); if (matcher.find()) { String colorDesc = matcher.group(1); String fillDesc = matcher.group(2); GPlotSeries.SeriesType seriesType = GPlotSeries.SeriesType.DEFAULT; if (fillDesc.contains("fill")) { seriesType = GPlotSeries.SeriesType.FILL; } else if (fillDesc.contains("dot")) { seriesType = GPlotSeries.SeriesType.DOT; } builder.withColor(TO_COLOR.get(colorDesc)); builder.withSeriesType(seriesType); return true; } return false; } private boolean handleLineType(String line, GPlotSeries.Builder builder) { Matcher typeMatcher = TYPE_PATTERN.matcher(line); if (typeMatcher.find()) { try { builder.withLineType( GPlotSeries.LineType.valueOf(typeMatcher.group(1).toUpperCase(Locale.getDefault()))); return true; } catch (IllegalArgumentException e) { LOGGER.debug("cannot find type for {}", typeMatcher.group(1)); } } return false; } private boolean handleTitle(String line, GPlotSeries.Builder builder) { Matcher titleMatcher = TITLE_PATTERN.matcher(line); if (titleMatcher.find()) { builder.withTitle(titleMatcher.group(1)); return true; } return false; } private boolean handleAxis(String line, GPlotSeries.Builder builder) { Matcher axesMatcher = AXIS_PATTERN.matcher(line); if (axesMatcher.find()) { String axis = axesMatcher.group(1); switch (axis) { case "1": builder.withAxis(GPlotSeries.Axis.LEFT); break; case "2": builder.withAxis(GPlotSeries.Axis.RIGHT); break; } return true; } else { builder.withAxis(GPlotSeries.Axis.LEFT); return false; } } private Map<String, String> extractSetsFrom(List<String> lines) { Map<String, String> out = newHashMap(); for (String line : lines) { Matcher matcher = SETS_PATTERN.matcher(line); if (!matcher.matches()) { continue; } out.put(matcher.group(1), matcher.group(2)); } return out; } public Map<String, GPlotDefinition> getDefaultGPlotFiles() { try { URL url = GPlotParser.class.getResource("dummy.txt"); String scheme = url.getProtocol(); checkArgument(scheme.equals("jar")); return readDefinitionsFromJar(url); } catch (Exception e) { LOGGER.error("loadDefaultGPlotFiles() - cannot load default files", e); } return emptyMap(); } private Map<String, GPlotDefinition> readDefinitionsFromJar(URL url) throws IOException, URISyntaxException { Map<String, GPlotDefinition> result = newHashMap(); JarURLConnection con = (JarURLConnection) url.openConnection(); JarFile archive = con.getJarFile(); Enumeration<JarEntry> entries = archive.entries(); while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); if (entry.getName().endsWith(".gplot")) { String filename = entry.getName().substring(entry.getName().lastIndexOf("/") + 1); String plotName = filename.substring(0, filename.indexOf(".")); URL resource = GPlotParser.class.getResource(filename); result.put(plotName, parse(Resources.toString(resource, Charsets.UTF_8))); } } return result; } }