/* * 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.InternalQName; import org.exoplatform.services.jcr.datamodel.QPath; import org.exoplatform.services.jcr.datamodel.QPathEntry; import org.exoplatform.services.jcr.impl.xml.XMLChar; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; import java.lang.ref.WeakReference; import javax.jcr.RepositoryException; /** * Created by The eXo Platform SAS.<br> * Helper for creating namespace mapping dependent entities like JCR path, name, * uuid * * @author Gennady Azarenkov * @version $Id: LocationFactory.java 11907 2008-03-13 15:36:21Z ksm $ */ public class LocationFactory { protected static Log log = ExoLogger.getLogger("exo.jcr.component.core.LocationFactory"); private final NamespaceAccessor namespaces; private final WeakReference<? extends NamespaceAccessor> weakAccessor; public LocationFactory(NamespaceAccessor namespaces) { this.namespaces = namespaces; this.weakAccessor = null; } public LocationFactory(WeakReference<? extends NamespaceAccessor> weakAccessor) { this.namespaces = null; this.weakAccessor = weakAccessor; } private NamespaceAccessor getNamespaceAccessor() { if (namespaces != null) { return namespaces; } NamespaceAccessor na = weakAccessor.get(); if (na == null) { throw new IllegalStateException("The namespace accessor cannot be found probably because" + " the corresponding eXo container has been removed"); } return na; } public JCRPath createRootLocation() throws RepositoryException { return parseNames(JCRPath.ROOT_PATH, true); } /** * Creates JCRPath from parent path and relPath * * @param parentLoc parent path * @param relPath related path * @return * @throws RepositoryException */ public JCRPath createJCRPath(JCRPath parentLoc, String relPath) throws RepositoryException { JCRPath addPath = parseNames(relPath, false); return parentLoc.add(addPath); } /** * Parses absolute JCR path from string (JCR format /ns:name[index]/etc) * * @param absPath * @return * @throws RepositoryException */ public JCRPath parseAbsPath(String absPath) throws RepositoryException { return parseNames(absPath, true); } public JCRPath parseRelPath(String relPath) throws RepositoryException { return parseNames(relPath, false); } /** * creates abs(if convertable to abs path) or rel(otherwice) JCRPath * * @param path * @return JCRPath * @throws RepositoryException */ public JCRPath parseJCRPath(String path) throws RepositoryException { if (isAbsPathParseable(path)) { return parseAbsPath(path); } else { return parseRelPath(path); } } /** * Creates JCRPath by internalQPath * * @param qPath * @return * @throws RepositoryException */ public JCRPath createJCRPath(QPath qPath) throws RepositoryException { return JCRPath.createJCRPath(getNamespaceAccessor(), qPath); } public JCRName createJCRName(InternalQName qname) throws RepositoryException { String prefix = getNamespaceAccessor().getNamespacePrefixByURI(qname.getNamespace()); return new JCRName(qname, prefix); } public String formatPathElement(QPathEntry qe) throws RepositoryException { String prefix = getNamespaceAccessor().getNamespacePrefixByURI(qe.getNamespace()); JCRPath p = JCRPath.createJCRPath(); p = p.addEntry(qe.getNamespace(), qe.getName(), prefix, qe.getIndex()); return p.getEntry(0).getAsString(false); } /** * Parses absolute JCR name from string (JCR format ns:name[index]) * * @param name * @return * @throws RepositoryException */ public JCRName parseJCRName(String name) throws RepositoryException { JCRPath path = parsePathEntry(JCRPath.createJCRPath(), name); JCRPath.PathElement entry = path.getName(); return new JCRName(entry); } public JCRPath.PathElement[] createRelPath(QPathEntry[] relPath) throws RepositoryException { return JCRPath.createJCRPath(getNamespaceAccessor(), relPath).getEntries(); } private JCRPath parsePathEntry(JCRPath path, String name) throws RepositoryException { // should be reset here (if there is explicit index) or // in JCRPath.Entry() (with index == 1) int index = -1; if (name == null) { throw new RepositoryException("Name can not be null"); } int delim = name.indexOf(":"); int endOfName = name.length(); int indexStart = name.indexOf("["); if (indexStart > 0) { int indexEnd = name.indexOf("]"); if ((indexEnd <= indexStart + 1) || (indexEnd != name.length() - 1)) { throw new RepositoryException("Invalid path entry: \"" + name + "\""); } index = Integer.parseInt(name.substring(indexStart + 1, indexEnd)); if (index <= 0) { throw new RepositoryException("Invalid path entry: \"" + name + "\""); } endOfName = indexStart; } try { String prefix; if (delim <= 0) { prefix = ""; } else { // prefix validation prefix = name.substring(0, delim); if (!XMLChar.isValidName(prefix)) { throw new RepositoryException("Illegal path entry: \"" + name + "\""); } } // name validation String someName = name.substring(delim + 1, endOfName); if (!isValidName(someName, !prefix.equals(""))) { throw new RepositoryException("Illegal path entry: \"" + name + "\""); } path = path.addEntry(getNamespaceAccessor().getNamespaceURIByPrefix(prefix), someName, prefix, index); return path; } catch (Exception e) { throw new RepositoryException(e.getMessage(), e); } } private JCRPath parseNames(String path, boolean absolute) throws RepositoryException { if ((path == null) || (path.equals(""))) { throw new RepositoryException("Illegal relPath: \"" + path + "\""); } JCRPath jcrPath = JCRPath.createJCRPath(); int start = 0; if (!absolute) { start = -1; } if (isAbsPathParseable(path)) { if (!absolute) { throw new RepositoryException("Illegal relPath: \"" + path + "\""); } jcrPath = jcrPath.addEntry(getNamespaceAccessor().getNamespaceURIByPrefix(""), "", "", -1); } else { if (absolute) { throw new RepositoryException("Illegal absPath: \"" + path + "\""); } } int end = 0; while (end >= 0) { end = path.indexOf('/', start + 1); String qname = path.substring(start + 1, end == -1 ? path.length() : end); if (start + 1 != path.length()) { jcrPath = parsePathEntry(jcrPath, qname); } else { // jcrPath.addEntry(getNamespaceAccessor().getNamespaceURIByPrefix(""), "", "", -1); return jcrPath; } start = end; } return jcrPath; } private static boolean isAbsPathParseable(String str) { return str.startsWith("/"); } // Some functions for JCRPath Validation private boolean isNonspace(String str, char ch) throws RepositoryException { if (ch == '|') { throw new RepositoryException("Illegal absPath: \"" + str + "\": The path entry contains an illegal char: \"" + ch + "\""); } return !((ch == '\t') || (ch == '\n') || (ch == '\f') || (ch == '\r') || (ch == ' ') || (ch == '/') || (ch == ':') || (ch == '[') || (ch == ']') || (ch == '*')); } private boolean isSimpleString(String str) throws RepositoryException { char ch; for (int i = 0; i < str.length(); i++) { ch = str.charAt(i); if (!isNonspace(str, ch) && (ch != ' ')) { return false; } } return true; } private boolean isLocalName(String str) throws RepositoryException { int strLen = str.length(); switch (strLen) { case 0 : return false; case 1 : char ch = str.charAt(0); return (isNonspace(str, ch) && (ch != '.')); case 2 : char ch0 = str.charAt(0); char ch1 = str.charAt(1); return (((ch0 == '.') && (isNonspace(str, ch1) && (ch1 != '.'))) || ((isNonspace(str, ch0) && (ch0 != '.')) && (ch1 == '.')) || ((isNonspace(str, ch0) && (ch0 != '.')) && (isNonspace(str, ch1) && (ch1 != '.')))); default : return isNonspace(str, str.charAt(0)) && isSimpleString(str.substring(1, strLen - 1)) && isNonspace(str, str.charAt(strLen - 1)); } } private boolean isSimpleName(String str) throws RepositoryException { int strLen = str.length(); switch (strLen) { case 0 : return false; case 1 : return isNonspace(str, str.charAt(0)); case 2 : return isNonspace(str, str.charAt(0)) && isNonspace(str, str.charAt(1)); default : return isNonspace(str, str.charAt(0)) && isSimpleString(str.substring(1, strLen - 1)) && isNonspace(str, str.charAt(strLen - 1)); } } private boolean isValidName(String str, boolean prefixed) throws RepositoryException { return (prefixed ? isLocalName(str) : isSimpleName(str) || str.equals(JCRPath.THIS_RELPATH) || str.equals(JCRPath.PARENT_RELPATH) || str.equals("*")); } }