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

com.redhat.lightblue.util.MutablePath Maven / Gradle / Ivy

There is a newer version: 2.18.0
Show newest version
/*
 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