Java tutorial
/** * Copyright 2012 meltmedia * * 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 com.meltmedia.cadmium.core.history; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; import com.meltmedia.cadmium.core.ApplicationContentRoot; import com.meltmedia.cadmium.core.FileSystemManager; import com.meltmedia.cadmium.core.commands.GitLocation; import com.meltmedia.cadmium.core.history.loggly.EventQueue; import com.meltmedia.cadmium.core.history.loggly.HistoryEvent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.inject.Inject; import javax.inject.Singleton; import java.io.Closeable; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.concurrent.ExecutorService; @Singleton public class HistoryManager implements Closeable { public static final String HISTORY_FILE_NAME = "history.json"; private final Logger log = LoggerFactory.getLogger(getClass()); private List<HistoryEntry> history = new ArrayList<HistoryEntry>(); private String contentRoot; @Inject private ExecutorService pool; @Inject private EventQueue eventQueue; @Inject public HistoryManager(@ApplicationContentRoot String contentRoot) throws Exception { this.contentRoot = contentRoot; readHistoryFile(); } public HistoryManager(String contentRoot, ExecutorService pool) throws Exception { this.contentRoot = contentRoot; this.pool = pool; readHistoryFile(); } public HistoryManager(String contentRoot, ExecutorService pool, EventQueue queue) throws Exception { this.contentRoot = contentRoot; this.pool = pool; this.eventQueue = queue; readHistoryFile(); } public void logEvent(boolean maint, String openId, String comment) { logEvent(HistoryEntry.EntryType.MAINT, null, openId, "", "", comment, maint, false, false, true); } public void logEvent(HistoryEntry.EntryType type, GitLocation gitPointer, String openId, String directory, String uuid, String comment, boolean revertible, boolean finished) { logEvent(type, gitPointer, openId, directory, uuid, comment, false, revertible, false, finished); } public void logEvent(HistoryEntry.EntryType type, GitLocation gitPointer, String openId, String directory, String uuid, String comment, boolean maint, boolean revertible, boolean failed, boolean finished) { HistoryEntry lastEntry = history.size() > 0 ? history.get(0) : null; if (uuid != null && lastEntry != null && lastEntry.getUuid() != null && uuid.trim().length() > 0 && uuid.equals(lastEntry.getUuid())) { log.debug("Last history entry was a dup."); return; } HistoryEntry newEntry = new HistoryEntry(); newEntry.setTimestamp(new Date()); if (lastEntry != null) { newEntry.setIndex(lastEntry.getIndex() + 1); } int index = 1; while (lastEntry != null && (lastEntry.isRevertible() != revertible)) { if (history.size() > index) { lastEntry = history.get(index); index++; } else { lastEntry = null; break; } } if (lastEntry != null && lastEntry.getTimestamp() != null) { lastEntry.setTimeLive(newEntry.getTimestamp().getTime() - lastEntry.getTimestamp().getTime()); log.debug("The last history event lived [{}ms]", lastEntry.getTimeLive()); } // the git pointer was not added to the HistoryEntry yet, to avoid changes to the message format. String repository = gitPointer != null && gitPointer.getRepository() != null ? gitPointer.getRepository() : ""; String branch = gitPointer != null && gitPointer.getBranch() != null ? gitPointer.getBranch() : ""; String revision = gitPointer != null && gitPointer.getRevision() != null ? gitPointer.getRevision() : ""; newEntry.setType(type); newEntry.setRepoUrl(repository); newEntry.setBranch(branch); newEntry.setRevision(revision); newEntry.setOpenId(openId); newEntry.setServedDirectory(directory); newEntry.setUuid(uuid); newEntry.setComment(comment); newEntry.setMaintenance(maint); newEntry.setRevertible(revertible); newEntry.setFailed(failed); newEntry.setFinished(finished); log.info( "Logging new {} History Event: repoUrl[{}], branch[{}], sha[{}], openId[{}], directory[{}], uuid[{}], revertible[{}], maint[{}], failed[{}], comment[{}]", new Object[] { type, repository, branch, revision, openId, directory, uuid, revertible, maint, failed, comment }); history.add(0, newEntry); if (newEntry.isFinished() || newEntry.isFailed()) { eventQueue.log(new HistoryEvent(newEntry)); } pool.execute(historyWriter); } public List<HistoryEntry> getHistory(Integer limit, boolean filter) { List<HistoryEntry> filteredHistory = new ArrayList<HistoryEntry>(); if (limit == null || limit <= 0) { limit = history.size() + 1; } log.info("Limit={}, filter={}", limit, filter); for (HistoryEntry entry : history) { if (!filter || entry.isRevertible()) { filteredHistory.add(entry); } if (filteredHistory.size() >= limit) { break; } } log.info("History size {}, filtered history size {}", history.size(), filteredHistory.size()); return filteredHistory; } public void markHistoryEntryAsFinished(String uuid) { for (HistoryEntry entry : history) { if (!entry.isFinished() && entry.getUuid() != null && entry.getUuid().equals(uuid) && entry.isRevertible()) { entry.setFinished(true); eventQueue.log(new HistoryEvent(entry)); log.debug("Marked {} as finished.", entry); pool.execute(historyWriter); break; } } } public HistoryEntry getLatestHistoryEntryByUUID(String uuid, Date since) { for (HistoryEntry entry : history) { if ((since == null || entry.getTimestamp().after(since)) && entry.getUuid() != null && entry.getUuid().equals(uuid)) { log.debug("Got latest entry for {}, {}", uuid, entry); return entry; } } return null; } private void readHistoryFile() throws Exception { if (contentRoot != null) { String path = FileSystemManager.getFileIfCanRead(contentRoot, HISTORY_FILE_NAME); if (path != null) { Gson gson = new Gson(); JsonReader reader = null; try { reader = new JsonReader(new FileReader(path)); reader.setLenient(true); List<HistoryEntry> entries = gson.fromJson(reader, new TypeToken<List<HistoryEntry>>() { }.getType()); if (entries != null) { history.addAll(entries); } } finally { log.info("Read in {} history entries", history.size()); if (reader != null) { reader.close(); } } } } } private Runnable historyWriter = new Runnable() { public void run() { if (contentRoot != null) { File path = new File(contentRoot, HISTORY_FILE_NAME); if (path.canWrite() || !path.exists()) { FileWriter writer = null; try { writer = new FileWriter(path, false); Gson gson = new Gson(); gson.toJson(history, new TypeToken<List<HistoryEntry>>() { }.getType(), writer); } catch (Exception e) { log.warn("Failed to write history", e); } finally { if (writer != null) { try { writer.close(); } catch (Exception e) { log.error("Failed to close history file", e); } } } } } } }; public List<HistoryEntry> getHistory() { return this.history; } @Override public void close() throws IOException { if (pool != null) { try { pool.shutdownNow(); } catch (Throwable t) { } pool = null; } } }