/* * Copyright 2009 Google 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 com.google.jstestdriver; import com.google.jstestdriver.hooks.FileInfoScheme; import com.google.jstestdriver.model.HandlerPathPrefix; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.util.LinkedList; import java.util.List; import java.util.Set; /** * Represents a test resource. The filePath is considered the canonical identifier * for a resource. * * @author jeremiele@google.com (Jeremie Lenfant-Engelmann) */ public class FileInfo implements Cloneable { private static final Logger logger = LoggerFactory.getLogger(FileInfo.class); private String filePath; private Long timestamp; private transient boolean isPatch; private boolean serveOnly; private List<FileInfo> patches; private String data; private long length; private String displayPath; public FileInfo() { } public FileInfo(String filePath, long timestamp, long length, boolean isPatch, boolean serveOnly, String data, String displayPath) { this.filePath = filePath; this.timestamp = timestamp; this.length = length; this.isPatch = isPatch; this.serveOnly = serveOnly; this.data = data; this.displayPath = displayPath; } public String getData() { return data == null ? "" : data; } public void setData(String data) { this.data = data; } public List<FileInfo> getPatches() { if (patches != null) { return new LinkedList<FileInfo>(patches); } return new LinkedList<FileInfo>(); } public void addPatch(FileInfo patch) { if (patches == null) { patches = new LinkedList<FileInfo>(); } this.patches.add(patch); } public long getLength() { return length; } public boolean isServeOnly() { return serveOnly; } /** Gets the path of a file. The path may be relative. */ public String getFilePath() { return filePath; } public long getTimestamp() { return timestamp; } public void setTimestamp(long timestamp) { this.timestamp = timestamp; } public boolean isPatch() { return isPatch; } public boolean isWebAddress() { return filePath.startsWith("http://") || filePath.startsWith("https://"); } public boolean canLoad() { return !isWebAddress(); } public boolean isLoaded() { return data != null; } public File toFile() { return new File(filePath); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((filePath == null) ? 0 : filePath.hashCode()); return result; } @Override public boolean equals(Object obj) { if (!(obj instanceof FileInfo)) { return false; } FileInfo other = (FileInfo) obj; if (filePath == null) { if (other.filePath != null){ return false; } } if (!filePath.equals(other.filePath)){ return false; } return true; } public FileInfo load(String data, long timestamp) { return new FileInfo(filePath, timestamp, length, isPatch, serveOnly, data, displayPath); } /** Translates the FileInfo into a lightweight FileSrc object. */ public FileSource toFileSource(HandlerPathPrefix prefix, Set<FileInfoScheme> schemes) { for (FileInfoScheme scheme : schemes) { if (scheme.matches(filePath)) { return new FileSource(displayPath, filePath, this.getTimestamp(), length); } } return new FileSource(prefix.prefixPath("/test/" + this.getDisplayPath()), filePath, this.getTimestamp(), length); } @Override public String toString() { if (logger.isDebugEnabled() || logger.isTraceEnabled()) { return "\n\tFileInfo [filePath=" + filePath + ", length=" + length + ", patches=" + patches + ", serveOnly=" + serveOnly + ", timestamp=" + timestamp + "]"; } return "\n\tFileInfo[" + this.getDisplayPath() + "]"; } /** * @param resolvedPath The resolved absolute path of the file. * @param displayPath The path to send to the browser for debugging and display. * @param timestamp The timestamp of the file. * @return An updated FileInfo. */ public FileInfo fromResolvedPath(String resolvedPath, String displayPath, long timestamp) { return new FileInfo(resolvedPath, timestamp, length, isPatch, serveOnly, data, displayPath); } /** * Provides a unique identifier to reference this FileInfo in the browser. */ public String getDisplayPath() { // remove relative path markers, as they won't resolve properly in the browser. return displayPath; } /** * Loads a file from the file system using a reader. * @param reader The file reader to pull from the file system. * @return The loaded file info. */ public FileInfo loadFile(FileReader reader) { if (!this.canLoad()) { return this; } StringBuilder fileContent = new StringBuilder(); fileContent.append(reader.readFile(filePath)); List<FileInfo> patches = this.getPatches(); if (patches != null) { for (FileInfo patch : patches) { fileContent.append(reader.readFile(patch.getFilePath())); } } return load(fileContent.toString(), timestamp); } @Override protected Object clone() throws CloneNotSupportedException { return new FileInfo(filePath, timestamp, length, isPatch, serveOnly, data, displayPath); } /** * Tests to see if a file is a proper replacement: different timestamp, length. * Also returns false if the paths don't match. */ public boolean shouldReplaceWith(FileInfo file) { if (!filePath.equals(file.getFilePath())) { logger.trace("paths not equal {} {}", getDisplayPath(), file.getDisplayPath()); return false; } if (getTimestamp() != file.getTimestamp()) { logger.trace("replace {} because {} != {}", new Object[]{getDisplayPath(), getTimestamp(), file.getTimestamp()}); return true; } /*if (getLength() != file.getLength()) { logger.trace("replace {} because {} != {}", new Object[]{getDisplayPath(), getLength(), file.getLength()}); return true; }*/ return false; } }