001    /*
002     * JBoss DNA (http://www.jboss.org/dna)
003     * See the COPYRIGHT.txt file distributed with this work for information
004     * regarding copyright ownership.  Some portions may be licensed
005     * to Red Hat, Inc. under one or more contributor license agreements.
006    * See the AUTHORS.txt file in the distribution for a full listing of 
007    * individual contributors.
008     *
009     * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
010     * is licensed to you under the terms of the GNU Lesser General Public License as
011     * published by the Free Software Foundation; either version 2.1 of
012     * the License, or (at your option) any later version.
013     *
014     * JBoss DNA is distributed in the hope that it will be useful,
015     * but WITHOUT ANY WARRANTY; without even the implied warranty of
016     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017     * Lesser General Public License for more details.
018     *
019     * You should have received a copy of the GNU Lesser General Public
020     * License along with this software; if not, write to the Free
021     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
022     * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
023     */
024    package org.jboss.dna.graph.property.basic;
025    
026    import java.util.Collections;
027    import java.util.Iterator;
028    import java.util.List;
029    import net.jcip.annotations.Immutable;
030    import org.jboss.dna.common.text.Inflector;
031    import org.jboss.dna.common.util.CheckArg;
032    import org.jboss.dna.graph.GraphI18n;
033    import org.jboss.dna.graph.property.InvalidPathException;
034    import org.jboss.dna.graph.property.Path;
035    
036    /**
037     * A basic implementation of {@link Path}.
038     * 
039     * @author Randall Hauch
040     * @author John Verhaeg
041     */
042    @Immutable
043    public class BasicPath extends AbstractPath {
044    
045        /**
046         * The initial serializable version. Version {@value}
047         */
048        private static final long serialVersionUID = 1L;
049    
050        private static final List<Segment> EMPTY_SEGMENTS = Collections.emptyList();
051    
052        public static final Path EMPTY_RELATIVE = new BasicPath(EMPTY_SEGMENTS, false);
053    
054        public static final Path SELF_PATH = new BasicPath(Collections.singletonList(Path.SELF_SEGMENT), false);
055    
056        public static final Path PARENT_PATH = new BasicPath(Collections.singletonList(Path.PARENT_SEGMENT), false);
057    
058        private final List<Segment> segments;
059        private final boolean absolute;
060        private final boolean normalized;
061    
062        /**
063         * @param segments the segments
064         * @param absolute true if this path is absolute, or false otherwise
065         */
066        public BasicPath( List<Segment> segments,
067                          boolean absolute ) {
068            assert segments != null;
069            this.segments = Collections.unmodifiableList(segments);
070            this.absolute = absolute;
071            this.normalized = isNormalized(this.segments);
072        }
073    
074        /**
075         * {@inheritDoc}
076         */
077        public Path getAncestor( int degree ) {
078            CheckArg.isNonNegative(degree, "degree");
079            if (degree == 0) return this;
080            int endIndex = this.segments.size() - degree;
081            if (endIndex == 0) return this.isAbsolute() ? RootPath.INSTANCE : null;
082            if (endIndex < 0) {
083                String msg = GraphI18n.pathAncestorDegreeIsInvalid.text(this.getString(), Inflector.getInstance().ordinalize(degree));
084                throw new InvalidPathException(msg);
085            }
086            return subpath(0, endIndex);
087        }
088    
089        /**
090         * {@inheritDoc}
091         * 
092         * @see org.jboss.dna.graph.property.basic.AbstractPath#getSegmentsOfParent()
093         */
094        @Override
095        protected Iterator<Segment> getSegmentsOfParent() {
096            int size = this.segments.size();
097            if (size == 1) return EMPTY_PATH_ITERATOR;
098            return this.segments.subList(0, size - 1).iterator();
099        }
100    
101        /**
102         * {@inheritDoc}
103         */
104        public List<Segment> getSegmentsList() {
105            return this.segments;
106        }
107    
108        /**
109         * {@inheritDoc}
110         */
111        public boolean isAbsolute() {
112            return this.absolute;
113        }
114    
115        /**
116         * {@inheritDoc}
117         */
118        public boolean isNormalized() {
119            return this.normalized;
120        }
121    
122        /**
123         * {@inheritDoc}
124         */
125        public boolean isRoot() {
126            return false;
127        }
128    
129        /**
130         * {@inheritDoc}
131         */
132        public int size() {
133            return this.segments.size();
134        }
135    
136    }