/* * Copyright 2013 Eediom Inc. * * Licensed 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 org.araqne.log.api; import java.io.BufferedReader; import java.io.Closeable; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.text.ParseException; import java.text.ParsePosition; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class LastPositionHelper { private LastPositionHelper() { } public static Map<String, LastPosition> deserialize(Map<String, Object> state) { Map<String, LastPosition> positions = new HashMap<String, LastPosition>(); SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ"); for (String key : state.keySet()) { @SuppressWarnings("unchecked") Map<String, Object> m = (Map<String, Object>) state.get(key); String path = (String) m.get("path"); // position type can be integer or long, so requires normalization long position = Long.valueOf(m.get("position").toString()); String s = (String) m.get("last_seen"); Date lastSeen = null; if (s != null) lastSeen = df.parse(s, new ParsePosition(0)); LastPosition p = new LastPosition(path, position, lastSeen); positions.put(key, p); } return positions; } public static Map<String, Object> serialize(Map<String, LastPosition> positions) { SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ"); Map<String, Object> state = new HashMap<String, Object>(); for (String key : positions.keySet()) { LastPosition p = positions.get(key); Map<String, Object> m = new HashMap<String, Object>(); m.put("path", p.getPath()); m.put("position", p.getPosition()); m.put("last_seen", p.getLastSeen() == null ? null : df.format(p.getLastSeen())); state.put(key, m); } return state; } public static Map<String, LastPosition> readLastPositions(File f) { List<String> lines = readAllLine(f); return readLastPosition(lines); } public static Map<String, LastPosition> readLastPosition(List<String> lines) { SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHH:mm:ss"); Map<String, LastPosition> lastPositions = new HashMap<String, LastPosition>(); if (lines == null || lines.isEmpty()) return lastPositions; int startIndex = 0; int endIndex = lines.size() - 1; int version = 1; if (lines.get(0).equals("ARAQNE_LAST_POS_VER2")) { version = 2; startIndex++; endIndex--; } for (; startIndex <= endIndex; startIndex++) { String line = lines.get(startIndex); LastPosition inform = parseLine(version, line, sdf); if (inform == null) continue; File file = new File(inform.getPath()); if (inform.getLastSeen() == null && !file.exists()) inform.setLastSeen(new Date()); if (inform.getLastSeen() != null && file.exists()) inform.setLastSeen(null); lastPositions.put(inform.getPath(), inform); } return lastPositions; } public static List<String> parseV2Lines(Map<String, LastPosition> lastPositions) { List<String> lines = new ArrayList<String>(); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHH:mm:ss"); lines.add("ARAQNE_LAST_POS_VER2"); long currentTime = new Date().getTime(); for (String path : lastPositions.keySet()) { LastPosition inform = lastPositions.get(path); String position = Long.toString(inform.getPosition()); String line = path + " " + position; if (inform.getLastSeen() != null) { long limitTime = inform.getLastSeen().getTime() + 3600000L; if (limitTime <= currentTime) continue; line += " " + sdf.format(inform.getLastSeen()); } else line += " -"; lines.add(line); } lines.add("END_FILE"); return lines; } public static void updateLastPositionFile(File f, Map<String, LastPosition> lastPositions) { Logger logger = LoggerFactory.getLogger(LastPositionHelper.class); // write last positions FileOutputStream os = null; try { os = new FileOutputStream(f); List<String> lines = parseV2Lines(lastPositions); for (String line : lines) { if (!line.equals("END_FILE")) line += "\n"; os.write(line.getBytes("utf-8")); } } catch (IOException e) { logger.error("araqne log api: cannot write last position file", e); } finally { if (os != null) { try { os.close(); } catch (IOException e) { } } } } private static List<String> readAllLine(File f) { Logger logger = LoggerFactory.getLogger(LastPositionHelper.class); try { if (f.exists()) { List<String> lines = new ArrayList<String>(); FileInputStream is = null; BufferedReader br = null; try { is = new FileInputStream(f); br = new BufferedReader(new InputStreamReader(is, "utf-8")); while (true) { String line = br.readLine(); if (line == null) break; if (line.trim().isEmpty()) continue; lines.add(line.trim()); } } finally { ensureClose(is); ensureClose(br); } return lines; } } catch (IOException e) { logger.error("araqne log api: apache logger cannot read last positions", e); } return null; } private static LastPosition parseLine(int version, String line, SimpleDateFormat sdf) { String path = null; long pos = 0; Date lastSeen = null; String posString = null; if (version == 1) { int p = line.lastIndexOf(" ", line.length()); path = line.substring(0, p); posString = line.substring(p + 1); pos = posString.trim().isEmpty() ? 0 : Long.parseLong(posString); return new LastPosition(path, pos, null); } else if (version == 2) { int startDate = line.lastIndexOf(" ", line.length()); String date = line.substring(startDate + 1); if (!date.equals("-")) { try { lastSeen = sdf.parse(line.substring(startDate + 1)); } catch (ParseException e) { } } int startPos = line.lastIndexOf(" ", startDate - 1); pos = Long.parseLong(line.substring(startPos + 1, startDate)); path = line.substring(0, startPos); return new LastPosition(path, pos, lastSeen); } return null; } private static void ensureClose(Closeable c) { try { if (c != null) c.close(); } catch (IOException e) { } } }