All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gxp.compiler.fs..svn.text-base.FileRef.svn-base Maven / Gradle / Ivy

Go to download

Google XML Pages (GXP) is a templating system used to generate XML/SGML markup (most often HTML).

The newest version!
/*
 * Copyright (C) 2008 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.gxp.compiler.fs;

import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.io.ByteStreams;
import com.google.common.io.CharStreams;

import java.io.*;
import java.net.URI;
import java.nio.charset.Charset;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.Adler32;

import javax.tools.FileObject;
import javax.tools.JavaFileObject.Kind;

/**
 * A value object that refers to a file in some {@code FileSystem}s.
 *
 * 

A {@code FileRef}'s "name" consists of a leading slash ("/") followed by * a sequence of zero or more slash separated components. Only the canonical * name "/" may end in a slash. Adjacent slashes are collapsed into a single * slash. Sample legal names are: "/" and "/a/b", but not "/a/" or "/a//b". * (The latter two names will be normalized into "/a" and "/a/b".) This * abstracts away from the system's notion of what a filename looks like, * whether it's "C:\windows\foo.txt" or "/usr/include/linux/stddef.h". * *

FileRef doesn't have any support for special filenames like "." or "..", * but some implementations of {@link FileSystem#parseFilename(String)} * will resolve these when parsing. * *

Note that there is no such thing as a relative {@code FileRef}; {@code * FileRef}s are always absolute. The {@link FileRef#join(String)} method may * be used to create {@code FileRef}s relative to existing {@code FileRef}s. * *

You can convert between the types of filenames the user is used to * seeing, "filenames", and {@code FileRef} objects using {@link * FileSystem#parseFilename(String)} and {@link * FileRef#toFilename()}. */ public final class FileRef implements FileObject { private final FileStore store; private final String name; // regex that matches 0 or more legal extension characters private static final String EXTENSION_CHARS = "[^\\./]*"; private static final Pattern SUFFIX_CHARS_PATTERN = Pattern.compile("^[^\\/]*"); private static final Pattern EXTENSION_PATTERN = Pattern.compile("\\.(" + EXTENSION_CHARS + ")$"); public FileRef(FileStore store, String name) { this.store = Preconditions.checkNotNull(store); this.name = normalize(Preconditions.checkNotNull(name)); } public String getName() { return name; } public URI toUri() { return store.toUri(this); } /** * Returns the time that the file was last modified, measured in milliseconds * since the epoch. */ public long getLastModified() { return store.getLastModified(this); } /** * @return a {@code Adler32} checksum of the file contents or 0 if the file * cannot be read. */ public long getChecksum() { try { Adler32 checksum = new Adler32(); InputStream is = openInputStream(); checksum.update(ByteStreams.toByteArray(is)); is.close(); return checksum.getValue(); } catch (IOException e) { return 0; } } /** * Delete this file */ public boolean delete() { return store.delete(this); } /** * Opens this filename for writing text. * *

The {@code Writer} returned will throw a {@link * java.nio.charset.UnmappableCharacterException} if unmappable characters * (ie: characters that do not exist in the specified encoding) are written * to it. */ public Writer openWriter(Charset encoding) throws IOException { return new OutputStreamWriter(openOutputStream(), encoding.newEncoder()); } public Writer openWriter() throws IOException { return openWriter(store.getDefaultCharset()); } /** * Opens this filename for reading text. * * TODO(harryh): the below note makes this not properly implement FileObject * but I'm intentionally leaving it this way for now, because I think this * is better. Might have to revisit this decision later. * *

The {@code Writer} returned will throw a {@link * java.nio.charset.UnmappableCharacterException} if unmappable characters * (ie: characters that do not exist in the specified encoding) are written * to it. */ public Reader openReader(Charset encoding) throws IOException { return new InputStreamReader(openInputStream(), encoding.newDecoder()); } public Reader openReader(boolean ignoreEncodingErrors) throws IOException { return openReader(store.getDefaultCharset()); } /** * Opens this filename for reading bytes. */ public InputStream openInputStream() throws IOException { return store.openInputStream(this); } /** * Opens this filename for writing bytes. */ public OutputStream openOutputStream() throws IOException { return store.openOutputStream(this); } public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { return CharStreams.toString(openReader(ignoreEncodingErrors)); } /** * @return a new FileRef where the final extension has been removed. * If the filename has no suffx, return this. */ public FileRef removeExtension() { Matcher m = EXTENSION_PATTERN.matcher(name); return m.find() ? new FileRef(this.store, name.substring(0, m.start())) : this; } public Kind getKind() { Matcher m = EXTENSION_PATTERN.matcher(name); if (m.find()) { String extension = name.substring(m.start()); for (Kind kind : Kind.values()) { if (extension.equals(kind.extension)) { return kind; } } } return Kind.OTHER; } /** * @return a new FileRef with an additional suffix. Note that the suffix * includes the dot. */ public FileRef addSuffix(String suffix) { if (!SUFFIX_CHARS_PATTERN.matcher(suffix).matches()) { throw new IllegalArgumentException("Illegal characters in suffix," + " \"" + suffix + "\"."); } return new FileRef(this.store, name + suffix); } public String toFilename() { return store.toFilename(this); } public String toRelativeFilename() { return store.toRelativeFilename(this); } /** * Joins a path suffix onto this FileRef creating a new FileRef which is * effectively 'suffix' relative to 'this'. * eg: new FileRef("/a/b").join("/x/y") is new FileRef("/a/b/x/y") */ public FileRef join(String suffix) { return new FileRef(this.store, this.name + "/" + suffix); } /** * @return whether this filename is an ancestor of the specified FileRef, * "that". */ public boolean isAncestorOf(FileRef that) { return store.equals(that.store) && ("/".equals(name) || that.name.startsWith(name + "/")); } /** * @return a String representation of this FileRef for debugging purposes. */ @Override public String toString() { return getClass().getSimpleName() + "(\"" + store + ":" + name + "\")"; } @Override public int hashCode() { return Objects.hashCode(store, name); } @Override public boolean equals(Object that) { return this == that || (that instanceof FileRef && this.equals((FileRef) that)); } public boolean equals(FileRef that) { return this.store.equals(that.store) && this.name.equals(that.name); } private static final Pattern NORMAL_PATTERN = Pattern.compile("/([^/]+(/[^/]+)*)?"); private static final Pattern MULTIPLE_SLASH_PATTERN = Pattern.compile("//+"); private static String normalize(String name) { if (NORMAL_PATTERN.matcher(name).matches()) { // short-circuit if string already appears to be normalized return name; } String newName = MULTIPLE_SLASH_PATTERN.matcher("/" + name).replaceAll("/"); if ((newName.length() > 1) && newName.endsWith("/")) { return newName.substring(0, newName.length() - 1); } return newName; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy