com.crashnote.external.config.impl.Path Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of crashnote-appengine Show documentation
Show all versions of crashnote-appengine Show documentation
Reports exceptions from Java apps on Appengine to crashnote.com
/**
* Copyright (C) 2011-2012 Typesafe Inc.
*/
package com.crashnote.external.config.impl;
import java.util.Iterator;
import java.util.List;
import com.crashnote.external.config.ConfigException;
final class Path {
final private String first;
final private Path remainder;
Path(final String first, final Path remainder) {
this.first = first;
this.remainder = remainder;
}
Path(final String... elements) {
if (elements.length == 0)
throw new ConfigException.BugOrBroken("empty path");
this.first = elements[0];
if (elements.length > 1) {
final PathBuilder pb = new PathBuilder();
for (int i = 1; i < elements.length; ++i) {
pb.appendKey(elements[i]);
}
this.remainder = pb.result();
} else {
this.remainder = null;
}
}
// append all the paths in the list together into one path
Path(final List pathsToConcat) {
if (pathsToConcat.isEmpty())
throw new ConfigException.BugOrBroken("empty path");
final Iterator i = pathsToConcat.iterator();
final Path firstPath = i.next();
this.first = firstPath.first;
final PathBuilder pb = new PathBuilder();
if (firstPath.remainder != null) {
pb.appendPath(firstPath.remainder);
}
while (i.hasNext()) {
pb.appendPath(i.next());
}
this.remainder = pb.result();
}
String first() {
return first;
}
/**
*
* @return path minus the first element or null if no more elements
*/
Path remainder() {
return remainder;
}
/**
*
* @return path minus the last element or null if we have just one element
*/
Path parent() {
if (remainder == null)
return null;
final PathBuilder pb = new PathBuilder();
Path p = this;
while (p.remainder != null) {
pb.appendKey(p.first);
p = p.remainder;
}
return pb.result();
}
/**
*
* @return last element in the path
*/
String last() {
Path p = this;
while (p.remainder != null) {
p = p.remainder;
}
return p.first;
}
Path prepend(final Path toPrepend) {
final PathBuilder pb = new PathBuilder();
pb.appendPath(toPrepend);
pb.appendPath(this);
return pb.result();
}
int length() {
int count = 1;
Path p = remainder;
while (p != null) {
count += 1;
p = p.remainder;
}
return count;
}
Path subPath(final int removeFromFront) {
int count = removeFromFront;
Path p = this;
while (p != null && count > 0) {
count -= 1;
p = p.remainder;
}
return p;
}
Path subPath(final int firstIndex, final int lastIndex) {
if (lastIndex < firstIndex)
throw new ConfigException.BugOrBroken("bad call to subPath");
Path from = subPath(firstIndex);
final PathBuilder pb = new PathBuilder();
int count = lastIndex - firstIndex;
while (count > 0) {
count -= 1;
pb.appendKey(from.first());
from = from.remainder();
if (from == null)
throw new ConfigException.BugOrBroken("subPath lastIndex out of range " + lastIndex);
}
return pb.result();
}
@Override
public boolean equals(final Object other) {
if (other instanceof Path) {
final Path that = (Path) other;
return this.first.equals(that.first)
&& ConfigImplUtil.equalsHandlingNull(this.remainder,
that.remainder);
} else {
return false;
}
}
@Override
public int hashCode() {
return 41 * (41 + first.hashCode())
+ (remainder == null ? 0 : remainder.hashCode());
}
// this doesn't have a very precise meaning, just to reduce
// noise from quotes in the rendered path for average cases
static boolean hasFunkyChars(final String s) {
final int length = s.length();
if (length == 0)
return false;
// if the path starts with something that could be a number,
// we need to quote it because the number could be invalid,
// for example it could be a hyphen with no digit afterward
// or the exponent "e" notation could be mangled.
final char first = s.charAt(0);
if (!(Character.isLetter(first)))
return true;
for (int i = 1; i < length; ++i) {
final char c = s.charAt(i);
if (Character.isLetterOrDigit(c) || c == '-' || c == '_')
continue;
else
return true;
}
return false;
}
private void appendToStringBuilder(final StringBuilder sb) {
if (hasFunkyChars(first) || first.isEmpty())
sb.append(ConfigImplUtil.renderJsonString(first));
else
sb.append(first);
if (remainder != null) {
sb.append(".");
remainder.appendToStringBuilder(sb);
}
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("Path(");
appendToStringBuilder(sb);
sb.append(")");
return sb.toString();
}
/**
* toString() is a debugging-oriented version while this is an
* error-message-oriented human-readable one.
*/
String render() {
final StringBuilder sb = new StringBuilder();
appendToStringBuilder(sb);
return sb.toString();
}
static Path newKey(final String key) {
return new Path(key, null);
}
static Path newPath(final String path) {
return Parser.parsePath(path);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy