
com.redhat.lightblue.util.MutablePath Maven / Gradle / Ivy
/*
Copyright 2013 Red Hat, Inc. and/or its affiliates.
This file is part of lightblue.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
package com.redhat.lightblue.util;
import java.util.List;
/**
* A Path that can be modified. Uses copy-on-write semantics to prevent
* unnecessary copies.
*/
public class MutablePath extends Path {
private static final long serialVersionUID = 1L;
/**
* If true, this MutablePath is the only Path with a reference to the path
* data. If false, path data is referenced by other Paths and a deep copy
* will only be made if data is modified.
*/
private boolean pathOwned;
public MutablePath() {
pathOwned = true;
}
/**
* Shallow copy of the input Path that is converted to a deep copy on first
* update.
*
* @param x
*/
public MutablePath(Path x) {
super(x);
pathOwned = false;
}
public MutablePath(MutablePath x) {
setData(new PathRep(x.getData()));
pathOwned = true;
}
/**
* Create a mutable path as a prefix of the given path
*
* @param x Source path
* @param pfix If positive, the new path is a prefix of x containing pfix
* elements. If negative, the new path is a prefix of x with last -pfix
* elements removed.
*/
public MutablePath(Path x, int pfix) {
setData(new PathRep(x.getData(), pfix));
pathOwned = true;
}
public MutablePath(String x) {
super(x);
pathOwned = true;
}
@Override
public MutablePath copy() {
return new MutablePath(this);
}
@Override
public Path immutableCopy() {
Path p = new Path();
p.setData(new PathRep(getData()));
return p;
}
/**
* Appends the given path to the current path segments.
*
* @param x the new path segments
* @return the updated path
*/
public MutablePath push(String x) {
if (x == null) {
throw new IllegalArgumentException(UtilConstants.ERR_NULL_VALUE_PASSED_TO_PUSH);
}
List s = parse(x);
if (s != null && !s.isEmpty()) {
own();
getData().append(s);
}
return this;
}
/**
* Appends x to the end of this
*/
public MutablePath push(Path x) {
if (x == null) {
throw new IllegalArgumentException(UtilConstants.ERR_NULL_VALUE_PASSED_TO_PUSH);
}
own();
getData().append(x.getData());
return this;
}
/**
* Appends the given integer (array index) to the current path segments.
*
* @param x the array index
* @return the updated path
*/
public MutablePath push(int x) {
return push(Integer.toString(x));
}
/**
* Remove the last path segment from this path.
*
* @return the updated path
*/
public MutablePath pop() {
try {
own();
getData().remove(getData().size() - 1);
} catch (IndexOutOfBoundsException e) {
throw new IllegalStateException(UtilConstants.ERR_CANT_POP_EMPTY_PATH);
}
return this;
}
/**
* Replace the last path segment with the path supplied.
*
* @param x the new end of the path
* @return the updated path
*/
public Path setLast(String x) {
try {
own();
getData().remove(getData().size() - 1);
getData().append(parse(x));
return this;
} catch (IndexOutOfBoundsException e) {
throw new IllegalStateException(UtilConstants.ERR_CANT_SET_LAST_SEGMENT_ON_EMPTY_PATH);
}
}
/**
* Replace the last path segment with the given integer (array index).
*
* @param x the array index
* @return the updated path
*/
public Path setLast(int x) {
return setLast(String.valueOf(x));
}
public Path set(int i, String x) {
own();
getData().set(i, x);
return this;
}
public Path set(int i, int value) {
return set(i, Integer.toString(value));
}
/**
* Reduces the length of the path to the given length
*/
public MutablePath cut(int length) {
own();
int l = getData().size();
while (l > length) {
getData().remove(--l);
}
return this;
}
/**
* Sets the path to empty path
*/
public MutablePath clear() {
own();
getData().clear();
return this;
}
/**
* Sets this path to p
*/
public MutablePath set(Path p) {
return clear().push(p);
}
/**
* If the path is not owned by this instance does a deep copy and marks the
* path as owned.
*/
private void own() {
if (!pathOwned) {
setData(new PathRep(getData()));
pathOwned = true;
}
}
@Override
public boolean equals(Object x) {
if (x instanceof Path) {
return ((Path) x).getData().equals(getData());
} else {
return false;
}
}
@Override
public int hashCode() {
return getData().hashCode();
}
/**
* Rewrites the array indexes in the prefix of this path that is common with
* fullPath, based on the array indexes in that shared prefix
*
* @param fullPath A path
*
* If
* fullPath= x.y.1.w.2.k
* thisPath = x.y.*.w.*.k.*
*
* Then:
*
* thisPath.rewriteIndexes(fullPath) -> x.y.1.w.2.k.*
*
*
* This is useful when interpreting an absolute path derived from metadata
* in the context of a definite absolute path with no ANYs
*
* @return this
*/
public MutablePath rewriteIndexes(Path fullPath) {
PathRep thisData = getData();
PathRep fpData = fullPath.getData();
int thisSize = thisData.size();
int fpSize = fpData.size();
for (int index = 0; index < thisSize && index < fpSize; index++) {
String thisSeg = thisData.get(index);
String fpSeg = fpData.get(index);
if (Path.ANY.equals(thisSeg)) {
own();
thisData = getData();
thisData.set(index, fpSeg);
} else if (!thisSeg.equals(fpSeg)) {
break;
}
}
return this;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy