/* * Copyright (C) 2009 eXo Platform SAS. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.exoplatform.services.jcr.impl.core; import org.exoplatform.services.jcr.core.NamespaceAccessor; import org.exoplatform.services.jcr.datamodel.QPath; import org.exoplatform.services.jcr.datamodel.QPathEntry; import org.exoplatform.services.jcr.impl.Constants; import javax.jcr.RepositoryException; /** * Created by The eXo Platform SAS. * * @author <a href="mailto:geaz@users.sourceforge.net">Gennady Azarenkov </a> * @version $Id$ */ public class JCRPathExt extends JCRPath { private static PathElement[] EMPTY_PATH = new PathElement[0]; private static final PathElement THIS_ELEMENT = new PathElement(Constants.NS_DEFAULT_URI, THIS_RELPATH, Constants.NS_EMPTY_PREFIX, -1); private static final PathElement MOVE_UP_ELEMENT = new PathElement(Constants.NS_DEFAULT_URI, PARENT_RELPATH, Constants.NS_EMPTY_PREFIX, -1); protected final PathElement[] names; protected final int size; protected String cachedToString; protected String cachedToStringShowIndex; protected QPath cachedInternalQPath; public final static JCRPathExt ROOT = new JCRPathExt(); private JCRPathExt() { this(EMPTY_PATH); } JCRPathExt(NamespaceAccessor namespaces, QPathEntry[] path) throws RepositoryException { PathElement[] names = new PathElement[path.length]; int size = 0; for (QPathEntry entry : path) { String prefix = namespaces.getNamespacePrefixByURI(entry.getNamespace()); PathElement element = element(entry.getNamespace(), entry.getName(), prefix, entry.getIndex()); size = addEntry(names, size, element); } // this.names = names; this.size = size; } JCRPathExt(JCRPathExt that, PathElement[] addedEntries, int addedSize) { PathElement[] names = new PathElement[that.size + addedSize]; int size = 0; for (int i = 0;i < that.size;i++) { size = addEntry(names, size, that.names[i]); } for (int i = 0;i < addedSize;i++) { size = addEntry(names, size, addedEntries[i]); } // this.names = names; this.size = size; } JCRPathExt(PathElement[] names) { this(names, names.length); } JCRPathExt(PathElement[] names, int size) { if (size < 0) { throw new AssertionError("Size value is negative: " + size); } if (size > names.length) { throw new AssertionError("Size value is too large: " + size + " instead of max: " + names.length); } // this.names = names; this.size = size; } public boolean isAbsolute() { if (size > 0) { PathElement first = names[0]; if (first.getName().equals(ROOT_NAME)) { return true; } } return false; } @Override JCRPath add(JCRPath path) { return new JCRPathExt(this, ((JCRPathExt)path).names, ((JCRPathExt)path).size); } @Override JCRPath addEntries(PathElement... entries) { return new JCRPathExt(this, entries, entries.length); } JCRPathExt addEntry(String namespace, String name, String prefix, int index) { return addEntry(element(namespace, name, prefix, index)); } public JCRPathExt makeAncestorPath(int relativeDegree) { return new JCRPathExt(names, size - relativeDegree); } JCRPathExt addEntry(PathElement entry) { return new JCRPathExt(this, new PathElement[]{entry}, 1); } private static PathElement element(String namespace, String name, String prefix, int index) { if (name.equals(THIS_RELPATH)) { return THIS_ELEMENT; } else if (name.equals(PARENT_RELPATH)) { return MOVE_UP_ELEMENT; } else { return new PathElement(namespace, name, prefix, index); } } private static int addEntry(PathElement[] entries, int size, PathElement entry) { if (entry == THIS_ELEMENT) // NOSONAR { return size; } if (size > 0 && entry == MOVE_UP_ELEMENT && !(entries[size - 1] == MOVE_UP_ELEMENT)) // NOSONAR { if (size <= 0) { LOG.warn("Wrong relative path. Can't move up in path hierarhy."); return 0; } return size - 1; } // entries[size] = entry; // return size + 1; } public JCRPathExt makeParentPath() { return makeAncestorPath(1); } @Override public int getLength() { return size; } @Override public PathElement getEntry(int index) { if (index > size) { throw new ArrayIndexOutOfBoundsException(); } return names[index]; } public PathElement[] getRelPath(int relativeDegree) { PathElement[] relPath = new PathElement[relativeDegree]; System.arraycopy(names, size - relativeDegree, relPath, 0, relativeDegree); return relPath; } public QPath getInternalPath() { if (cachedInternalQPath == null) { QPathEntry[] entries = new QPathEntry[size]; for (int i = 0; i < size; i++) entries[i] = new QPathEntry(names[i].getNamespace(), names[i].getName(), names[i].getIndex()); cachedInternalQPath = new QPath(entries); } return cachedInternalQPath; } public String getAsString(boolean showIndex) { if (showIndex) { if (cachedToStringShowIndex != null) { return cachedToStringShowIndex; } } else { if (cachedToString != null) { return cachedToString; } } // [PN] 27.06.07 String path; if (isAbsolute()) { if (size == 1) { path = "/"; } else { StringBuilder builder = new StringBuilder(); for (int i = 1; i < size; i++) { builder.append("/").append(names[i].getAsString(showIndex)); } path = builder.toString(); } } else { // relative StringBuilder builder = new StringBuilder(); for (int i = 0; i < size; i++) { if (i > 0) { builder.append("/"); } else { } builder.append(names[i].getAsString(showIndex)); } path = builder.toString(); } // if (showIndex) { cachedToStringShowIndex = path; } else { cachedToString = path; } // return path; } public int getDepth() { return size - 1; } public boolean isDescendantOf(JCRPath ancestorLocation, boolean childOnly) { return isDescendantOf((JCRPathExt)ancestorLocation, childOnly); } public boolean isDescendantOf(JCRPathExt ancestorLocation, boolean childOnly) { int depthDiff = getDepth() - ancestorLocation.getDepth(); if (depthDiff <= 0 || (childOnly && depthDiff != 1)) return false; JCRPathExt.PathElement[] anotherNames = ancestorLocation.names; for (int i = 0; i < ancestorLocation.size; i++) { boolean result = anotherNames[i].equals(names[i]); if (!result) return false; } return true; } public boolean isAncestorOf(JCRPath descendantLocation, boolean childOnly) { return descendantLocation.isDescendantOf(this, childOnly); } public PathElement getName() { if (size > 0) return names[size - 1]; return THIS_ELEMENT; } public int getIndex() { return names[size - 1].getIndex(); } public boolean isIndexSetExplicitly() { return names[size - 1].isIndexSetExplicitly(); } public boolean isSameNameSibling(JCRPath anotherPath) { return isSameNameSibling((JCRPathExt)anotherPath); } public boolean isSameNameSibling(JCRPathExt anotherPath) { JCRName[] anotherNames = anotherPath.names; for (int i = 0; i < anotherPath.size - 1; i++) { boolean result = anotherNames[i].equals(names[i]); if (!result) return false; } return getName().getName().equals(anotherPath.getName().getName()) && this.getName().getPrefix().equals(anotherPath.getName().getPrefix()); } public boolean equals(Object obj) { if (this == obj) { return true; } if (obj instanceof JCRPathExt) { JCRPathExt other = (JCRPathExt)obj; return this.getInternalPath().equals(other.getInternalPath()); } return false; } public PathElement[] getEntries() { return names.clone(); } }