Java tutorial
/* * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License, version 2 as published by the Free Software * Foundation. * * You should have received a copy of the GNU General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/gpl-2.0.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * 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. * * * Copyright 2006 - 2013 Pentaho Corporation. All rights reserved. */ package org.pentaho.platform.repository2.unified.jcr; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Properties; import java.util.regex.Pattern; import javax.jcr.Item; import javax.jcr.ItemNotFoundException; import javax.jcr.Node; import javax.jcr.NodeIterator; import javax.jcr.PathNotFoundException; import javax.jcr.Property; import javax.jcr.PropertyIterator; import javax.jcr.PropertyType; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.UnsupportedRepositoryOperationException; import javax.jcr.lock.Lock; import javax.jcr.version.Version; import javax.jcr.version.VersionHistory; import javax.jcr.version.VersionManager; import org.apache.commons.lang.mutable.MutableBoolean; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.jackrabbit.JcrConstants; import org.apache.jackrabbit.core.VersionManagerImpl; import org.pentaho.platform.api.engine.IPentahoSession; import org.pentaho.platform.api.locale.IPentahoLocale; import org.pentaho.platform.api.repository2.unified.IRepositoryAccessVoterManager; import org.pentaho.platform.api.repository2.unified.IRepositoryFileData; import org.pentaho.platform.api.repository2.unified.IRepositoryVersionManager; import org.pentaho.platform.api.repository2.unified.RepositoryFile; import org.pentaho.platform.api.repository2.unified.RepositoryFileAcl; import org.pentaho.platform.api.repository2.unified.RepositoryFilePermission; import org.pentaho.platform.api.repository2.unified.RepositoryFileSid; import org.pentaho.platform.api.repository2.unified.RepositoryFileTree; import org.pentaho.platform.api.repository2.unified.RepositoryRequest; import org.pentaho.platform.api.repository2.unified.VersionSummary; import org.pentaho.platform.engine.core.system.PentahoSessionHolder; import org.pentaho.platform.engine.core.system.PentahoSystem; import org.pentaho.platform.repository2.locale.PentahoLocale; import org.pentaho.platform.repository2.messages.Messages; import org.pentaho.platform.repository2.unified.exception.RepositoryFileDaoMalformedNameException; import org.pentaho.platform.repository2.unified.jcr.sejcr.CredentialsStrategySessionFactory; import org.pentaho.platform.util.messages.LocaleHelper; import org.springframework.util.Assert; import org.springframework.util.StringUtils; /** * Class of static methods where the real JCR work takes place. * * @author mlowery */ public class JcrRepositoryFileUtils { private static final Log logger = LogFactory.getLog(JcrRepositoryFileUtils.class); /** * See section 4.6 "Path Syntax" of JCR 1.0 spec. Note that this list is only characters that can never appear in a * "simplename". It does not include '.' because, while "." and ".." are illegal, any other string containing '.' is * legal. It is up to this implementation to prohibit permutations of legal characters. */ // private static final List<Character> reservedChars = Collections.unmodifiableList( Arrays.asList( new Character[] { // '/', ':', '[', ']', '*', '\'', '"', '|', '\t', '\r', '\n' } ) ); // This list will drive what characters are not allowed on the client as well as the server private static List<Character> reservedChars = Collections .unmodifiableList(Arrays.asList(new Character[] { '/', '\\', '\t', '\r', '\n' })); private static IRepositoryVersionManager repositoryVersionManager = null; /** * Try to get parameters from PentahoSystem, otherwise use default */ static { List<Character> newOverrideReservedChars = PentahoSystem.get(ArrayList.class, "reservedChars", PentahoSessionHolder.getSession()); if (newOverrideReservedChars != null) { reservedChars = newOverrideReservedChars; } } private static Pattern makePattern(List<Character> list) { // escape all reserved characters as they may have special meaning to regex engine StringBuilder buf = new StringBuilder(); buf.append(".*"); //$NON-NLS-1$ buf.append("["); //$NON-NLS-1$ for (Character ch : list) { buf.append("\\"); //$NON-NLS-1$ buf.append(ch); } buf.append("]"); //$NON-NLS-1$ buf.append("+"); //$NON-NLS-1$ buf.append(".*"); //$NON-NLS-1$ return Pattern.compile(buf.toString()); } public static RepositoryFile getFileById(final Session session, final PentahoJcrConstants pentahoJcrConstants, final IPathConversionHelper pathConversionHelper, final ILockHelper lockHelper, final Serializable fileId) throws RepositoryException { Node fileNode = session.getNodeByIdentifier(fileId.toString()); Assert.notNull(fileNode); return nodeToFile(session, pentahoJcrConstants, pathConversionHelper, lockHelper, fileNode); } public static RepositoryFile nodeToFile(final Session session, final PentahoJcrConstants pentahoJcrConstants, final IPathConversionHelper pathConversionHelper, final ILockHelper lockHelper, final Node node) throws RepositoryException { return nodeToFile(session, pentahoJcrConstants, pathConversionHelper, lockHelper, node, false, null); } private static RepositoryFile getRootFolder(final Session session) throws RepositoryException { Node node = session.getRootNode(); RepositoryFile file = new RepositoryFile.Builder(node.getIdentifier(), "").folder(true).versioned(false) //$NON-NLS-1$ .path(JcrStringHelper.pathDecode(node.getPath())) .build(); return file; } public static RepositoryFile nodeToFileOld(final Session session, final PentahoJcrConstants pentahoJcrConstants, final IPathConversionHelper pathConversionHelper, final ILockHelper lockHelper, final Node node, final boolean loadMaps, IPentahoLocale pentahoLocale) throws RepositoryException { if (session.getRootNode().isSame(node)) { return getRootFolder(session); } Serializable id = null; String name = null; String path = null; long fileSize = 0; Date created = null; String creatorId = null; Boolean hidden = false; Date lastModified = null; boolean folder = false; boolean versioned = false; Serializable versionId = null; boolean locked = false; String lockOwner = null; Date lockDate = null; String lockMessage = null; String title = null; String description = null; Boolean aclNode = false; Map<String, Properties> localePropertiesMap = null; id = getNodeId(session, pentahoJcrConstants, node); if (logger.isDebugEnabled()) { logger.debug(String.format("reading file with id '%s' and path '%s'", id, node.getPath())); //$NON-NLS-1$ } path = pathConversionHelper.absToRel((getAbsolutePath(session, pentahoJcrConstants, node))); // if the rel path is / then name the folder empty string instead of its true name (this hides the tenant name) name = RepositoryFile.SEPARATOR.equals(path) ? "" : getNodeName(session, pentahoJcrConstants, node); //$NON-NLS-1$ if (isPentahoFolder(pentahoJcrConstants, node)) { folder = true; } // jcr:created nodes have OnParentVersion values of INITIALIZE if (node.hasProperty(pentahoJcrConstants.getJCR_CREATED())) { Calendar tmpCal = node.getProperty(pentahoJcrConstants.getJCR_CREATED()).getDate(); if (tmpCal != null) { created = tmpCal.getTime(); } } // Expensive Map<String, Serializable> metadata = getFileMetadata(session, id); creatorId = (String) metadata.get(PentahoJcrConstants.PHO_CONTENTCREATOR); if (node.hasProperty(pentahoJcrConstants.getPHO_HIDDEN())) { hidden = node.getProperty(pentahoJcrConstants.getPHO_HIDDEN()).getBoolean(); } if (node.hasProperty(pentahoJcrConstants.getPHO_FILESIZE())) { fileSize = node.getProperty(pentahoJcrConstants.getPHO_FILESIZE()).getLong(); } if (node.hasProperty(pentahoJcrConstants.getPHO_ACLNODE())) { aclNode = node.getProperty(pentahoJcrConstants.getPHO_ACLNODE()).getBoolean(); } if (isPentahoFile(pentahoJcrConstants, node)) { // pho:lastModified nodes have OnParentVersion values of IGNORE; i.e. they don't exist in frozen nodes if (!node.isNodeType(pentahoJcrConstants.getNT_FROZENNODE())) { Calendar tmpCal = node.getProperty(pentahoJcrConstants.getPHO_LASTMODIFIED()).getDate(); if (tmpCal != null) { lastModified = tmpCal.getTime(); } } } // Get default locale if null if (pentahoLocale == null) { Locale currentLocale = LocaleHelper.getLocale(); if (currentLocale != null) { pentahoLocale = new PentahoLocale(currentLocale); } else { pentahoLocale = new PentahoLocale(); } } // Not needed for content generators and the like if (isPentahoHierarchyNode(session, pentahoJcrConstants, node)) { if (node.hasNode(pentahoJcrConstants.getPHO_LOCALES())) { // Expensive localePropertiesMap = getLocalePropertiesMap(session, pentahoJcrConstants, node.getNode(pentahoJcrConstants.getPHO_LOCALES())); // [BISERVER-8337] localize title and description LocalePropertyResolver lpr = new LocalePropertyResolver(name); LocalizationUtil localizationUtil = new LocalizationUtil(localePropertiesMap, pentahoLocale.getLocale()); title = localizationUtil.resolveLocalizedString(lpr.resolveDefaultTitleKey(), null); if (org.apache.commons.lang.StringUtils.isBlank(title)) { title = localizationUtil.resolveLocalizedString(lpr.resolveTitleKey(), null); if (org.apache.commons.lang.StringUtils.isBlank(title)) { title = localizationUtil.resolveLocalizedString(lpr.resolveNameKey(), title); } } description = localizationUtil.resolveLocalizedString(lpr.resolveDefaultDescriptionKey(), null); if (org.apache.commons.lang.StringUtils.isBlank(description)) { description = localizationUtil.resolveLocalizedString(lpr.resolveDescriptionKey(), description); } } // BISERVER-8609 - Backwards compatibility. Fallback to the old data structure if title/description are not // found if (title == null && node.hasNode(pentahoJcrConstants.getPHO_TITLE())) { title = getLocalizedString(session, pentahoJcrConstants, node.getNode(pentahoJcrConstants.getPHO_TITLE()), pentahoLocale); } if (description == null && node.hasNode(pentahoJcrConstants.getPHO_DESCRIPTION())) { description = getLocalizedString(session, pentahoJcrConstants, node.getNode(pentahoJcrConstants.getPHO_DESCRIPTION()), pentahoLocale); } } if (!loadMaps) { localePropertiesMap = null; // remove reference, allow garbage collection } versioned = isVersioned(session, pentahoJcrConstants, node); if (versioned) { versionId = getVersionId(session, pentahoJcrConstants, node); } locked = isLocked(pentahoJcrConstants, node); if (locked) { Lock lock = session.getWorkspace().getLockManager().getLock(node.getPath()); lockOwner = lockHelper.getLockOwner(session, pentahoJcrConstants, lock); lockDate = lockHelper.getLockDate(session, pentahoJcrConstants, lock); lockMessage = lockHelper.getLockMessage(session, pentahoJcrConstants, lock); } RepositoryFile file = new RepositoryFile.Builder(id, name).createdDate(created).creatorId(creatorId) .lastModificationDate(lastModified).folder(folder).versioned(versioned).path(path) .versionId(versionId).fileSize(fileSize).locked(locked).lockDate(lockDate).hidden(hidden) .lockMessage(lockMessage).lockOwner(lockOwner).title(title).description(description) .locale(pentahoLocale.toString()).localePropertiesMap(localePropertiesMap).aclNode(aclNode).build(); return file; } public static RepositoryFile nodeToFile(final Session session, final PentahoJcrConstants pentahoJcrConstants, final IPathConversionHelper pathConversionHelper, final ILockHelper lockHelper, final Node node, final boolean loadMaps, IPentahoLocale pentahoLocale) throws RepositoryException { if (session.getRootNode().isSame(node)) { return getRootFolder(session); } // Get default locale if null if (pentahoLocale == null) { Locale currentLocale = LocaleHelper.getLocale(); if (currentLocale != null) { pentahoLocale = new PentahoLocale(currentLocale); } else { pentahoLocale = new PentahoLocale(); } } return getRepositoryFileProxyFactory().getProxy(node, pentahoLocale); } private static RepositoryFileProxyFactory fileProxyFactory; private static RepositoryFileProxyFactory getRepositoryFileProxyFactory() { if (fileProxyFactory == null) { fileProxyFactory = PentahoSystem.get(RepositoryFileProxyFactory.class); } return fileProxyFactory; } public static String getLocalizedString(final Session session, final PentahoJcrConstants pentahoJcrConstants, final Node localizedStringNode, IPentahoLocale pentahoLocale) throws RepositoryException { Assert.isTrue(isLocalizedString(session, pentahoJcrConstants, localizedStringNode)); boolean isLocaleNull = pentahoLocale == null; if (pentahoLocale == null) { pentahoLocale = new PentahoLocale(); } Locale locale = pentahoLocale.getLocale(); final String UNDERSCORE = "_"; //$NON-NLS-1$ final String COLON = ":"; //$NON-NLS-1$ boolean hasLanguage = StringUtils.hasText(locale.getLanguage()); boolean hasCountry = StringUtils.hasText(locale.getCountry()); boolean hasVariant = StringUtils.hasText(locale.getVariant()); List<String> candidatePropertyNames = new ArrayList<String>(3); if (hasVariant) { candidatePropertyNames.add( locale.getLanguage() + UNDERSCORE + locale.getCountry() + UNDERSCORE + locale.getVariant()); } if (hasCountry) { candidatePropertyNames.add(locale.getLanguage() + UNDERSCORE + locale.getCountry()); } if (hasLanguage) { candidatePropertyNames.add(locale.getLanguage()); } for (String propertyName : candidatePropertyNames) { if (localizedStringNode.hasProperty(propertyName)) { return localizedStringNode.getProperty(propertyName).getString(); } } String prefix = session.getNamespacePrefix(PentahoJcrConstants.PHO_NS); Assert.hasText(prefix); String propertyStr = isLocaleNull ? pentahoJcrConstants.getPHO_ROOTLOCALE() : prefix + COLON + locale.getLanguage(); return localizedStringNode.getProperty(propertyStr).getString(); } public static Map<String, Properties> getLocalePropertiesMap(final Session session, final PentahoJcrConstants pentahoJcrConstants, final Node localesNode) throws RepositoryException { String prefix = session.getNamespacePrefix(PentahoJcrConstants.PHO_NS); Assert.hasText(prefix); Map<String, Properties> localePropertiesMap = new HashMap<String, Properties>(); NodeIterator nodeItr = localesNode.getNodes(); while (nodeItr.hasNext()) { Node node = nodeItr.nextNode(); String locale = node.getName(); Properties properties = new Properties(); PropertyIterator propertyIterator = node.getProperties(); while (propertyIterator.hasNext()) { Property property = propertyIterator.nextProperty(); if (!property.isMultiple()) { properties.put(property.getName(), property.getValue().getString()); } } localePropertiesMap.put(locale, properties); } return localePropertiesMap; } private static void setLocalePropertiesMap(final Session session, final PentahoJcrConstants pentahoJcrConstants, final Node localeRootNode, final Map<String, Properties> localePropertiesMap) throws RepositoryException { String prefix = session.getNamespacePrefix(PentahoJcrConstants.PHO_NS); Assert.hasText(prefix); if (localePropertiesMap != null && !localePropertiesMap.isEmpty()) { for (String locale : localePropertiesMap.keySet()) { Properties properties = localePropertiesMap.get(locale); if (properties != null) { // create node and set properties for each locale Node localeNode; if (!NodeHelper.checkHasNode(localeRootNode, locale)) { localeNode = localeRootNode.addNode(locale, pentahoJcrConstants.getNT_UNSTRUCTURED()); } else { localeNode = NodeHelper.checkGetNode(localeRootNode, locale); } for (String propertyName : properties.stringPropertyNames()) { try { localeNode.setProperty(propertyName, properties.getProperty(propertyName)); } catch (Throwable th) { // Continue setting other properties continue; } } } } } } private static Map<String, String> getLocalizedStringMap(final Session session, final PentahoJcrConstants pentahoJcrConstants, final Node localizedStringNode) throws RepositoryException { Assert.isTrue(isLocalizedString(session, pentahoJcrConstants, localizedStringNode)); String prefix = session.getNamespacePrefix(PentahoJcrConstants.PHO_NS); Assert.hasText(prefix); Map<String, String> localizedStringMap = new HashMap<String, String>(); PropertyIterator propertyIter = localizedStringNode.getProperties(); // Loop through properties and append the appropriate values in the map while (propertyIter.hasNext()) { Property property = propertyIter.nextProperty(); String propertyKey = property.getName().substring(prefix.length() + 1); localizedStringMap.put(propertyKey, property.getString()); } return localizedStringMap; } /** * Sets localized string. */ private static void setLocalizedStringMap(final Session session, final PentahoJcrConstants pentahoJcrConstants, final Node localizedStringNode, final Map<String, String> map) throws RepositoryException { Assert.isTrue(isLocalizedString(session, pentahoJcrConstants, localizedStringNode)); String prefix = session.getNamespacePrefix(PentahoJcrConstants.PHO_NS); Assert.hasText(prefix); PropertyIterator propertyIter = localizedStringNode.getProperties(); while (propertyIter.hasNext()) { Property prop = propertyIter.nextProperty(); if (prop.getName().startsWith(prefix)) { prop.remove(); } } for (Map.Entry<String, String> entry : map.entrySet()) { localizedStringNode.setProperty(prefix + ":" + entry.getKey(), entry.getValue()); //$NON-NLS-1$ } } public static String getAbsolutePath(final Session session, final PentahoJcrConstants pentahoJcrConstants, final Node node) throws RepositoryException { if (node.isNodeType(pentahoJcrConstants.getNT_FROZENNODE())) { return JcrStringHelper.pathDecode(session .getNodeByIdentifier(node.getProperty(pentahoJcrConstants.getJCR_FROZENUUID()).getString()) .getPath()); } return JcrStringHelper.pathDecode(node.getPath()); } public static Serializable getNodeId(final Session session, final PentahoJcrConstants pentahoJcrConstants, final Node node) throws RepositoryException { if (node.isNodeType(pentahoJcrConstants.getNT_FROZENNODE())) { return node.getProperty(pentahoJcrConstants.getJCR_FROZENUUID()).getString(); } return node.getIdentifier(); } public static String getNodeName(final Session session, final PentahoJcrConstants pentahoJcrConstants, final Node node) throws RepositoryException { if (node.isNodeType(pentahoJcrConstants.getNT_FROZENNODE())) { return JcrStringHelper.fileNameDecode(session .getNodeByIdentifier(node.getProperty(pentahoJcrConstants.getJCR_FROZENUUID()).getString()) .getName()); } return JcrStringHelper.fileNameDecode(node.getName()); } public static String getVersionId(final Session session, final PentahoJcrConstants pentahoJcrConstants, final Node node) throws RepositoryException { if (node.isNodeType(pentahoJcrConstants.getNT_FROZENNODE())) { return JcrStringHelper.fileNameDecode(node.getParent().getName()); } Version version = getBaseVersion(session, node); return version != null ? JcrStringHelper.fileNameDecode(version.getName()) : null; } /** * Getting base version of the node. In the case of getting NullPointerException from Jackrabbit Content Repository * (see https://issues.apache.org/jira/browse/JCR-2382), catching it, logging the error and returning null * * @param node * @return version of the node or null * @throws UnsupportedRepositoryOperationException * @throws RepositoryException */ private static Version getBaseVersion(final Session session, final Node node) throws UnsupportedRepositoryOperationException, RepositoryException { Version version = null; VersionManager versionManager = session.getWorkspace().getVersionManager(); try { version = versionManager.getBaseVersion(node.getPath()); } catch (NullPointerException ex) { logger.warn(Messages.getInstance().getString("JcrRepositoryFileUtils.WARN_0001_NPE_FROM_CR"), ex); } return version; } public static Node createFolderNode(final Session session, final PentahoJcrConstants pentahoJcrConstants, final Serializable parentFolderId, final RepositoryFile folder) throws RepositoryException { // Not need to check the name if we encoded it // checkName( folder.getName() ); Node parentFolderNode; if (parentFolderId != null) { parentFolderNode = session.getNodeByIdentifier(parentFolderId.toString()); } else { parentFolderNode = session.getRootNode(); } // guard against using a file retrieved from a more lenient session inside a more strict session Assert.notNull(parentFolderNode); String encodedfolderName = JcrStringHelper.fileNameEncode(folder.getName()); Node folderNode = parentFolderNode.addNode(encodedfolderName, pentahoJcrConstants.getPHO_NT_PENTAHOFOLDER()); folderNode.setProperty(pentahoJcrConstants.getPHO_HIDDEN(), folder.isHidden()); folderNode.setProperty(pentahoJcrConstants.getPHO_ACLNODE(), folder.isAclNode()); // folderNode.setProperty(pentahoJcrConstants.getPHO_TITLE(), folder.getTitle()); Node localeNodes = null; if (folder.getTitle() != folder.getName()) { // Title is different from the name localeNodes = folderNode.addNode(pentahoJcrConstants.getPHO_LOCALES(), pentahoJcrConstants.getPHO_NT_LOCALE()); Map<String, Properties> localPropertiesMap = new HashMap<String, Properties>(); String defaultLocale = LocaleHelper.getLocale().toString(); Properties titleProps = new Properties(); titleProps.put("file.title", folder.getTitle()); localPropertiesMap.put(defaultLocale, titleProps); setLocalePropertiesMap(session, pentahoJcrConstants, localeNodes, localPropertiesMap); } if (folder.isVersioned()) { // folderNode.setProperty(addPentahoPrefix(session, PentahoJcrConstants.PENTAHO_VERSIONED), true); folderNode.addMixin(pentahoJcrConstants.getPHO_MIX_VERSIONABLE()); } folderNode.addNode(pentahoJcrConstants.getPHO_METADATA(), JcrConstants.NT_UNSTRUCTURED); folderNode.addMixin(pentahoJcrConstants.getMIX_REFERENCEABLE()); return folderNode; } public static Node createFileNode(final Session session, final PentahoJcrConstants pentahoJcrConstants, final Serializable parentFolderId, final RepositoryFile file, final IRepositoryFileData content, final ITransformer<IRepositoryFileData> transformer) throws RepositoryException { // Not need to check the name if we encoded it // checkName( file.getName() ); String encodedFileName = JcrStringHelper.fileNameEncode(file.getName()); Node parentFolderNode; if (parentFolderId != null) { parentFolderNode = session.getNodeByIdentifier(parentFolderId.toString()); } else { parentFolderNode = session.getRootNode(); } // guard against using a file retrieved from a more lenient session inside a more strict session Assert.notNull(parentFolderNode); Node fileNode = parentFolderNode.addNode(encodedFileName, pentahoJcrConstants.getPHO_NT_PENTAHOFILE()); fileNode.setProperty(pentahoJcrConstants.getPHO_CONTENTTYPE(), transformer.getContentType()); fileNode.setProperty(pentahoJcrConstants.getPHO_LASTMODIFIED(), Calendar.getInstance()); fileNode.setProperty(pentahoJcrConstants.getPHO_HIDDEN(), file.isHidden()); fileNode.setProperty(pentahoJcrConstants.getPHO_FILESIZE(), content.getDataSize()); fileNode.setProperty(pentahoJcrConstants.getPHO_ACLNODE(), file.isAclNode()); if (file.getLocalePropertiesMap() != null && !file.getLocalePropertiesMap().isEmpty()) { Node localeNodes = fileNode.addNode(pentahoJcrConstants.getPHO_LOCALES(), pentahoJcrConstants.getPHO_NT_LOCALE()); setLocalePropertiesMap(session, pentahoJcrConstants, localeNodes, file.getLocalePropertiesMap()); } Node metaNode = fileNode.addNode(pentahoJcrConstants.getPHO_METADATA(), JcrConstants.NT_UNSTRUCTURED); setMetadataItemForFile(session, PentahoJcrConstants.PHO_CONTENTCREATOR, file.getCreatorId(), metaNode); fileNode.addMixin(pentahoJcrConstants.getMIX_LOCKABLE()); fileNode.addMixin(pentahoJcrConstants.getMIX_REFERENCEABLE()); if (file.isVersioned()) { // fileNode.setProperty(addPentahoPrefix(session, PentahoJcrConstants.PENTAHO_VERSIONED), true); fileNode.addMixin(pentahoJcrConstants.getPHO_MIX_VERSIONABLE()); } transformer.createContentNode(session, pentahoJcrConstants, content, fileNode); return fileNode; } private static void preventLostUpdate(final Session session, final PentahoJcrConstants pentahoJcrConstants, final RepositoryFile file) throws RepositoryException { Node fileNode = session.getNodeByIdentifier(file.getId().toString()); // guard against using a file retrieved from a more lenient session inside a more strict session Assert.notNull(fileNode); if (isVersioned(session, pentahoJcrConstants, fileNode)) { Assert.notNull(file.getVersionId(), "updating a versioned file requires a non-null version id"); //$NON-NLS-1$ Assert.state( session.getWorkspace().getVersionManager().getBaseVersion(fileNode.getPath()).getName() .equals(file.getVersionId().toString()), "update to this file has occurred since its last read"); //$NON-NLS-1$ } } public static Node updateFileNode(final Session session, final PentahoJcrConstants pentahoJcrConstants, final RepositoryFile file, final IRepositoryFileData content, final ITransformer<IRepositoryFileData> transformer) throws RepositoryException { Node fileNode = session.getNodeByIdentifier(file.getId().toString()); // guard against using a file retrieved from a more lenient session inside a more strict session Assert.notNull(fileNode); preventLostUpdate(session, pentahoJcrConstants, file); fileNode.setProperty(pentahoJcrConstants.getPHO_CONTENTTYPE(), transformer.getContentType()); fileNode.setProperty(pentahoJcrConstants.getPHO_LASTMODIFIED(), Calendar.getInstance()); fileNode.setProperty(pentahoJcrConstants.getPHO_HIDDEN(), file.isHidden()); fileNode.setProperty(pentahoJcrConstants.getPHO_FILESIZE(), content.getDataSize()); fileNode.setProperty(pentahoJcrConstants.getPHO_ACLNODE(), file.isAclNode()); if (file.getLocalePropertiesMap() != null && !file.getLocalePropertiesMap().isEmpty()) { Node localePropertiesMapNode = null; if (!fileNode.hasNode(pentahoJcrConstants.getPHO_LOCALES())) { localePropertiesMapNode = fileNode.addNode(pentahoJcrConstants.getPHO_LOCALES(), pentahoJcrConstants.getPHO_NT_LOCALE()); } else { localePropertiesMapNode = fileNode.getNode(pentahoJcrConstants.getPHO_LOCALES()); } setLocalePropertiesMap(session, pentahoJcrConstants, localePropertiesMapNode, file.getLocalePropertiesMap()); } if (file.getCreatorId() != null) { Node metadataNode = null; if (!fileNode.hasNode(pentahoJcrConstants.getPHO_METADATA())) { metadataNode = fileNode.addNode(pentahoJcrConstants.getPHO_METADATA(), JcrConstants.NT_UNSTRUCTURED); } else { metadataNode = fileNode.getNode(pentahoJcrConstants.getPHO_METADATA()); } setMetadataItemForFile(session, PentahoJcrConstants.PHO_CONTENTCREATOR, file.getCreatorId(), metadataNode); } transformer.updateContentNode(session, pentahoJcrConstants, content, fileNode); return fileNode; } public static Node updateFolderNode(final Session session, final PentahoJcrConstants pentahoJcrConstants, final RepositoryFile folder) throws RepositoryException { Node folderNode = session.getNodeByIdentifier(folder.getId().toString()); // guard against using a file retrieved from a more lenient session inside a more strict session Assert.notNull(folderNode); preventLostUpdate(session, pentahoJcrConstants, folder); folderNode.setProperty(pentahoJcrConstants.getPHO_HIDDEN(), folder.isHidden()); folderNode.setProperty(pentahoJcrConstants.getPHO_ACLNODE(), folder.isAclNode()); if (folder.getLocalePropertiesMap() != null && !folder.getLocalePropertiesMap().isEmpty()) { Node localePropertiesMapNode = null; if (!folderNode.hasNode(pentahoJcrConstants.getPHO_LOCALES())) { localePropertiesMapNode = folderNode.addNode(pentahoJcrConstants.getPHO_LOCALES(), pentahoJcrConstants.getPHO_NT_LOCALE()); } else { localePropertiesMapNode = folderNode.getNode(pentahoJcrConstants.getPHO_LOCALES()); } setLocalePropertiesMap(session, pentahoJcrConstants, localePropertiesMapNode, folder.getLocalePropertiesMap()); } return folderNode; } public static IRepositoryFileData getContent(final Session session, final PentahoJcrConstants pentahoJcrConstants, final Serializable fileId, final Serializable versionId, final ITransformer<IRepositoryFileData> transformer) throws RepositoryException { Node fileNode = session.getNodeByIdentifier(fileId.toString()); if (isVersioned(session, pentahoJcrConstants, fileNode)) { VersionManager vMgr = session.getWorkspace().getVersionManager(); Version version = null; if (versionId != null) { version = vMgr.getVersionHistory(fileNode.getPath()).getVersion(versionId.toString()); } else { version = vMgr.getBaseVersion(fileNode.getPath()); } fileNode = getNodeAtVersion(pentahoJcrConstants, version); } Assert.isTrue(!isPentahoFolder(pentahoJcrConstants, fileNode)); return transformer.fromContentNode(session, pentahoJcrConstants, fileNode); } public static List<RepositoryFile> getChildren(final Session session, final PentahoJcrConstants pentahoJcrConstants, final IPathConversionHelper pathConversionHelper, final ILockHelper lockHelper, final RepositoryRequest repositoryRequest) throws RepositoryException { Node folderNode = session.getNodeByIdentifier(JcrStringHelper.idEncode(repositoryRequest.getPath())); Assert.isTrue(isPentahoFolder(pentahoJcrConstants, folderNode)); List<RepositoryFile> children = new ArrayList<RepositoryFile>(); // get all immediate child nodes that are of type PHO_NT_PENTAHOFOLDER or PHO_NT_PENTAHOFILE NodeIterator nodeIterator = null; if (repositoryRequest.getChildNodeFilter() != null) { nodeIterator = folderNode.getNodes(repositoryRequest.getChildNodeFilter()); } else { nodeIterator = folderNode.getNodes(); } while (nodeIterator.hasNext()) { Node node = nodeIterator.nextNode(); if (isSupportedNodeType(pentahoJcrConstants, node)) { RepositoryFile file = nodeToFile(session, pentahoJcrConstants, pathConversionHelper, lockHelper, node); if (!file.isAclNode() && (!file.isHidden() || repositoryRequest.isShowHidden())) { children.add(file); } } } Collections.sort(children); return children; } @Deprecated public static List<RepositoryFile> getChildren(final Session session, final PentahoJcrConstants pentahoJcrConstants, final IPathConversionHelper pathConversionHelper, final ILockHelper lockHelper, final Serializable folderId, final String filter) throws RepositoryException { return getChildren(session, pentahoJcrConstants, pathConversionHelper, lockHelper, folderId, filter, null); } @Deprecated public static List<RepositoryFile> getChildren(final Session session, final PentahoJcrConstants pentahoJcrConstants, final IPathConversionHelper pathConversionHelper, final ILockHelper lockHelper, final Serializable folderId, final String filter, Boolean showHiddenFiles) throws RepositoryException { RepositoryRequest repositoryRequest = new RepositoryRequest(folderId.toString(), showHiddenFiles, 0, filter); return getChildren(session, pentahoJcrConstants, pathConversionHelper, lockHelper, repositoryRequest); } public static boolean isPentahoFolder(final PentahoJcrConstants pentahoJcrConstants, final Node node) throws RepositoryException { Assert.notNull(node); if (node.isNodeType(pentahoJcrConstants.getNT_FROZENNODE())) { String nodeTypeName = node.getProperty(pentahoJcrConstants.getJCR_FROZENPRIMARYTYPE()).getString(); return pentahoJcrConstants.getPHO_NT_PENTAHOFOLDER().equals(nodeTypeName); } return node.isNodeType(pentahoJcrConstants.getPHO_NT_PENTAHOFOLDER()); } public static boolean isPentahoHierarchyNode(final Session session, final PentahoJcrConstants pentahoJcrConstants, final Node node) throws RepositoryException { Assert.notNull(node); if (node.isNodeType(pentahoJcrConstants.getNT_FROZENNODE())) { String nodeTypeName = node.getProperty(pentahoJcrConstants.getJCR_FROZENPRIMARYTYPE()).getString(); // TODO mlowery add PENTAHOLINKEDFILE here when it is available return pentahoJcrConstants.getPHO_NT_PENTAHOFOLDER().equals(nodeTypeName) || pentahoJcrConstants.getPHO_NT_PENTAHOFILE().equals(nodeTypeName); } return node.isNodeType(pentahoJcrConstants.getPHO_NT_PENTAHOHIERARCHYNODE()); } public static boolean isLocked(final PentahoJcrConstants pentahoJcrConstants, final Node node) throws RepositoryException { Assert.notNull(node); if (node.isNodeType(pentahoJcrConstants.getNT_FROZENNODE())) { // frozen nodes are never locked return false; } boolean locked = node.isLocked(); if (locked) { Assert.isTrue(node.isNodeType(pentahoJcrConstants.getMIX_LOCKABLE())); } return locked; } public static boolean isPentahoFile(final PentahoJcrConstants pentahoJcrConstants, final Node node) throws RepositoryException { Assert.notNull(node); if (node.isNodeType(pentahoJcrConstants.getNT_FROZENNODE())) { String primaryTypeName = node.getProperty(pentahoJcrConstants.getJCR_FROZENPRIMARYTYPE()).getString(); if (pentahoJcrConstants.getPHO_NT_PENTAHOFILE().equals(primaryTypeName)) { return true; } return false; } return node.isNodeType(pentahoJcrConstants.getPHO_NT_PENTAHOFILE()); } private static boolean isLocalizedString(final Session session, final PentahoJcrConstants pentahoJcrConstants, final Node node) throws RepositoryException { Assert.notNull(node); if (node.isNodeType(pentahoJcrConstants.getNT_FROZENNODE())) { String frozenPrimaryType = node.getProperty(pentahoJcrConstants.getJCR_FROZENPRIMARYTYPE()).getString(); if (pentahoJcrConstants.getPHO_NT_LOCALIZEDSTRING().equals(frozenPrimaryType)) { return true; } return false; } return node.isNodeType(pentahoJcrConstants.getPHO_NT_LOCALIZEDSTRING()); } public static boolean isVersioned(final Session session, final PentahoJcrConstants pentahoJcrConstants, final Node node) throws RepositoryException { Assert.notNull(node); if (node.isNodeType(pentahoJcrConstants.getNT_FROZENNODE())) { // frozen nodes represent the nodes at a particular version; so yes, they are versioned! return true; } return node.isNodeType(pentahoJcrConstants.getPHO_MIX_VERSIONABLE()); } public static boolean isSupportedNodeType(final PentahoJcrConstants pentahoJcrConstants, final Node node) throws RepositoryException { Assert.notNull(node); if (node.isNodeType(pentahoJcrConstants.getNT_FROZENNODE())) { String nodeTypeName = node.getProperty(pentahoJcrConstants.getJCR_FROZENPRIMARYTYPE()).getString(); return pentahoJcrConstants.getPHO_NT_PENTAHOFILE().equals(nodeTypeName) || pentahoJcrConstants.getPHO_NT_PENTAHOFOLDER().equals(nodeTypeName); } return node.isNodeType(pentahoJcrConstants.getPHO_NT_PENTAHOFILE()) || node.isNodeType(pentahoJcrConstants.getPHO_NT_PENTAHOFOLDER()); } /** * Conditionally checks out node representing file if node is versionable. */ public static void checkoutNearestVersionableFileIfNecessary(final Session session, final PentahoJcrConstants pentahoJcrConstants, final Serializable fileId) throws RepositoryException { // file could be null meaning the caller is using null as the parent folder; that's OK; in this case the node // in // question would be the repository root node and that is never versioned if (fileId != null) { Node node = session.getNodeByIdentifier(fileId.toString()); checkoutNearestVersionableNodeIfNecessary(session, pentahoJcrConstants, node); } } /** * Conditionally checks out node if node is versionable. */ public static void checkoutNearestVersionableNodeIfNecessary(final Session session, final PentahoJcrConstants pentahoJcrConstants, final Node node) throws RepositoryException { Assert.notNull(node); Node versionableNode = findNearestVersionableNode(session, pentahoJcrConstants, node); if (versionableNode != null) { session.getWorkspace().getVersionManager().checkout(versionableNode.getPath()); } } public static void checkinNearestVersionableFileIfNecessary(final Session session, final PentahoJcrConstants pentahoJcrConstants, final Serializable fileId, final String versionMessage) throws RepositoryException { checkinNearestVersionableFileIfNecessary(session, pentahoJcrConstants, fileId, versionMessage, null, false); } /** * Conditionally checks in node representing file if node is versionable. */ public static void checkinNearestVersionableFileIfNecessary(final Session session, final PentahoJcrConstants pentahoJcrConstants, final Serializable fileId, final String versionMessage, final Date versionDate, final boolean aclOnlyChange) throws RepositoryException { // file could be null meaning the caller is using null as the parent folder; that's OK; in this case the node // in // question would be the repository root node and that is never versioned if (fileId != null) { Node node = session.getNodeByIdentifier(fileId.toString()); checkinNearestVersionableNodeIfNecessary(session, pentahoJcrConstants, node, versionMessage, versionDate, aclOnlyChange); } } public static void checkinNearestVersionableNodeIfNecessary(final Session session, final PentahoJcrConstants pentahoJcrConstants, final Node node, final String versionMessage) throws RepositoryException { checkinNearestVersionableNodeIfNecessary(session, pentahoJcrConstants, node, versionMessage, null, false); } /** * Conditionally checks in node if node is versionable. * <p/> * TODO mlowery move commented out version labeling to its own method */ public static void checkinNearestVersionableNodeIfNecessary(final Session session, final PentahoJcrConstants pentahoJcrConstants, final Node node, final String versionMessage, Date versionDate, final boolean aclOnlyChange) throws RepositoryException { Assert.notNull(node); session.save(); /* * session.save must be called inside the versionable node block and outside to ensure user changes are made when a * file is not versioned. */ Node versionableNode = findNearestVersionableNode(session, pentahoJcrConstants, node); if (versionableNode != null) { versionableNode.setProperty(pentahoJcrConstants.getPHO_VERSIONAUTHOR(), getUsername()); if (StringUtils.hasText(versionMessage)) { versionableNode.setProperty(pentahoJcrConstants.getPHO_VERSIONMESSAGE(), versionMessage); } else { // TODO mlowery why do I need to check for hasProperty here? in JR 1.6, I didn't need to if (versionableNode.hasProperty(pentahoJcrConstants.getPHO_VERSIONMESSAGE())) { versionableNode.setProperty(pentahoJcrConstants.getPHO_VERSIONMESSAGE(), (String) null); } } if (aclOnlyChange) { versionableNode.setProperty(pentahoJcrConstants.getPHO_ACLONLYCHANGE(), true); } else { // TODO mlowery why do I need to check for hasProperty here? in JR 1.6, I didn't need to if (versionableNode.hasProperty(pentahoJcrConstants.getPHO_ACLONLYCHANGE())) { versionableNode.getProperty(pentahoJcrConstants.getPHO_ACLONLYCHANGE()).remove(); } } session.save(); // required before checkin since we set some properties above Calendar cal = Calendar.getInstance(); if (versionDate != null) { cal.setTime(versionDate); } else { cal.setTime(new Date()); } ((VersionManagerImpl) session.getWorkspace().getVersionManager()).checkin(versionableNode.getPath(), cal); // if we're not versioning, delete only the previous version to // prevent the number of versions from increasing. We still need a versioned node if (!getRepositoryVersionManager().isVersioningEnabled(versionableNode.getPath())) { List<VersionSummary> versionSummaries = (List<VersionSummary>) getVersionSummaries(session, pentahoJcrConstants, versionableNode.getIdentifier(), Boolean.TRUE); if ((versionSummaries != null) && (versionSummaries.size() > 1)) { VersionSummary versionSummary = (VersionSummary) versionSummaries .toArray()[versionSummaries.size() - 2]; if (versionSummary != null) { String versionId = (String) versionSummary.getId(); session.getWorkspace().getVersionManager().getVersionHistory(versionableNode.getPath()) .removeVersion(versionId); session.save(); } } } } } private static String getUsername() { IPentahoSession pentahoSession = PentahoSessionHolder.getSession(); Assert.state(pentahoSession != null); return pentahoSession.getName(); } /** * Returns the nearest versionable node (possibly the node itself) or {@code null} if the root is reached. */ private static Node findNearestVersionableNode(final Session session, final PentahoJcrConstants pentahoJcrConstants, final Node node) throws RepositoryException { Node currentNode = node; while (!currentNode.isNodeType(pentahoJcrConstants.getPHO_MIX_VERSIONABLE())) { try { currentNode = currentNode.getParent(); } catch (ItemNotFoundException e) { // at the root return null; } } return currentNode; } public static void deleteFile(final Session session, final PentahoJcrConstants pentahoJcrConstants, final Serializable fileId, final ILockHelper lockTokenHelper) throws RepositoryException { Node fileNode = session.getNodeByIdentifier(fileId.toString()); // guard against using a file retrieved from a more lenient session inside a more strict session Assert.notNull(fileNode); // technically, the node can be locked when it is deleted; however, we want to avoid an orphaned lock token; // delete // it first if (fileNode.isLocked()) { Lock lock = session.getWorkspace().getLockManager().getLock(fileNode.getPath()); // don't need lock token anymore lockTokenHelper.removeLockToken(session, pentahoJcrConstants, lock); } fileNode.remove(); } public static RepositoryFile nodeIdToFile(final Session session, final PentahoJcrConstants pentahoJcrConstants, final IPathConversionHelper pathConversionHelper, final ILockHelper lockHelper, final Serializable fileId) throws RepositoryException { Node fileNode = session.getNodeByIdentifier(fileId.toString()); return nodeToFile(session, pentahoJcrConstants, pathConversionHelper, lockHelper, fileNode); } public static Object getVersionSummaries(final Session session, final PentahoJcrConstants pentahoJcrConstants, final Serializable fileId, final boolean includeAclOnlyChanges) throws RepositoryException { Node fileNode = session.getNodeByIdentifier(fileId.toString()); VersionHistory versionHistory = session.getWorkspace().getVersionManager() .getVersionHistory(fileNode.getPath()); // get root version but don't include it in version summaries; from JSR-170 specification section 8.2.5: // [root version] is a dummy version that serves as the starting point of the version graph. Like all version // nodes, // it has a subnode called jcr:frozenNode. But, in this case that frozen node does not contain any state // information // about N Version version = versionHistory.getRootVersion(); Version[] successors = version.getSuccessors(); List<VersionSummary> versionSummaries = new ArrayList<VersionSummary>(); while (successors != null && successors.length > 0) { version = successors[0]; // branching not supported VersionSummary sum = toVersionSummary(pentahoJcrConstants, versionHistory, version); if (!sum.isAclOnlyChange() || (includeAclOnlyChanges && sum.isAclOnlyChange())) { versionSummaries.add(sum); } successors = version.getSuccessors(); } return versionSummaries; } private static VersionSummary toVersionSummary(final PentahoJcrConstants pentahoJcrConstants, final VersionHistory versionHistory, final Version version) throws RepositoryException { List<String> labels = Arrays.asList(versionHistory.getVersionLabels(version)); // get custom Pentaho properties (i.e. author and message) Node nodeAtVersion = getNodeAtVersion(pentahoJcrConstants, version); String author = "BASE_VERSION"; if (nodeAtVersion.hasProperty(pentahoJcrConstants.getPHO_VERSIONAUTHOR())) { author = nodeAtVersion.getProperty(pentahoJcrConstants.getPHO_VERSIONAUTHOR()).getString(); } String message = null; if (nodeAtVersion.hasProperty(pentahoJcrConstants.getPHO_VERSIONMESSAGE())) { message = nodeAtVersion.getProperty(pentahoJcrConstants.getPHO_VERSIONMESSAGE()).getString(); } boolean aclOnlyChange = false; if (nodeAtVersion.hasProperty(pentahoJcrConstants.getPHO_ACLONLYCHANGE()) && nodeAtVersion.getProperty(pentahoJcrConstants.getPHO_ACLONLYCHANGE()).getBoolean()) { aclOnlyChange = true; } return new VersionSummary(version.getName(), versionHistory.getVersionableIdentifier(), aclOnlyChange, version.getCreated().getTime(), author, message, labels); } /** * Returns the node as it was at the given version. * * @param version * version to get * @return node at version */ private static Node getNodeAtVersion(final PentahoJcrConstants pentahoJcrConstants, final Version version) throws RepositoryException { return version.getNode(pentahoJcrConstants.getJCR_FROZENNODE()); } public static RepositoryFile getFileAtVersion(final Session session, final PentahoJcrConstants pentahoJcrConstants, final IPathConversionHelper pathConversionHelper, final ILockHelper lockHelper, final Serializable fileId, final Serializable versionId) throws RepositoryException { Node fileNode = session.getNodeByIdentifier(fileId.toString()); Version version = session.getWorkspace().getVersionManager().getVersionHistory(fileNode.getPath()) .getVersion(versionId.toString()); return nodeToFile(session, pentahoJcrConstants, pathConversionHelper, lockHelper, getNodeAtVersion(pentahoJcrConstants, version)); } /** * Returns the metadata regarding that identifies what transformer wrote this file's data. */ public static String getFileContentType(final Session session, final PentahoJcrConstants pentahoJcrConstants, final Serializable fileId, final Serializable versionId) throws RepositoryException { Assert.notNull(fileId); Node fileNode = session.getNodeByIdentifier(fileId.toString()); if (versionId != null) { Version version = session.getWorkspace().getVersionManager().getVersionHistory(fileNode.getPath()) .getVersion(versionId.toString()); Node nodeAtVersion = getNodeAtVersion(pentahoJcrConstants, version); return nodeAtVersion.getProperty(pentahoJcrConstants.getPHO_CONTENTTYPE()).getString(); } return fileNode.getProperty(pentahoJcrConstants.getPHO_CONTENTTYPE()).getString(); } public static Serializable getParentId(final Session session, final Serializable fileId) throws RepositoryException { Node node = session.getNodeByIdentifier(fileId.toString()); return node.getParent().getIdentifier(); } public static Serializable getBaseVersionId(final Session session, final Serializable fileId) throws RepositoryException { Node node = session.getNodeByIdentifier(fileId.toString()); return session.getWorkspace().getVersionManager().getBaseVersion(node.getPath()).getName(); } public static Object getVersionSummary(final Session session, final PentahoJcrConstants pentahoJcrConstants, final Serializable fileId, final Serializable versionId) throws RepositoryException { VersionManager vMgr = session.getWorkspace().getVersionManager(); Node fileNode = session.getNodeByIdentifier(fileId.toString()); VersionHistory versionHistory = vMgr.getVersionHistory(fileNode.getPath()); Version version = null; if (versionId != null) { version = versionHistory.getVersion(versionId.toString()); } else { version = vMgr.getBaseVersion(fileNode.getPath()); } return toVersionSummary(pentahoJcrConstants, versionHistory, version); } public static RepositoryFileTree getTree(final Session session, final PentahoJcrConstants pentahoJcrConstants, final IPathConversionHelper pathConversionHelper, final ILockHelper lockHelper, final String absPath, final RepositoryRequest repositoryRequest, IRepositoryAccessVoterManager accessVoterManager) throws RepositoryException { Item fileItem = session.getItem(JcrStringHelper.pathEncode(absPath)); // items are nodes or properties; this must be a node Assert.isTrue(fileItem.isNode()); Node fileNode = (Node) fileItem; return getTreeByNode(session, pentahoJcrConstants, pathConversionHelper, lockHelper, fileNode, repositoryRequest.getDepth(), repositoryRequest.getChildNodeFilter(), repositoryRequest.isShowHidden(), accessVoterManager, repositoryRequest.getTypes(), new MutableBoolean(false)); } /** * Returns a RepositoryFileTree for a given node. This method will be called recursively for each folder it processes. * The childNodeFilter is a filter used directly by the JCR jar to filter node names. Since JCR does not know a folder * from a file (that is our construct), it is not capable of filtering out filenames but not folder names. Therefore, * this logic will create two sets of children nodes. The <code>filteredChildrenSet</code> keeps the child nodes that * satisfied the childNodeFilter. The <code> childrenFolderSet</code> keeps a set of all child folder nodes regardless * of the value of the filter. We use the <code>childrenFolderSet</code> to know what folders to traverse, but we use * the <code>filteredChildrenSet </code> to determine what actual files to include in the returned tree. * <p> * Just because we process a folder node does not necessarily mean the folder will be reported in the tree. It must * first find a file that satisfies the criteria of the <code>childNodeFilter</code> mask. A file meeting the criteria * may be any number of folders down the repository structure, so the <code>foundFiltered</code> MutableBoolean tells * the caller if a file was found, at any level, meeting that criteria. * * @param session * The current session in progress * @param pentahoJcrConstants * @param pathConversionHelper * @param lockHelper * @param fileNode * The node which will serve as the root of the tree * @param depth * how many levels do we go down. * @param childNodeFilter * The filter sent to JCR to retrieve defining which files are in scope * @param showHidden * Whether to return hidden files * @param accessVoterManager * See IRepositoryAccessVoterManager * @param types * <code>FILE_TYPE_FILTERS</code> Types of files to return including FILES, FOLDERS, FILES_FOLDERS * @param foundFiltered * This <code>MutableBoolean</code> will tell the caller if there was a file encountered, (at any level up to * the depth), that was compliant with the childNodeFilter. This will determine if this node, (and its * children), should be discarded because there are no relevant files. * @return A RepositoryFileTree representing the entire tree at and below the given node that complies with file * filtering and other parameters of the tree request. * @throws RepositoryException */ private static RepositoryFileTree getTreeByNode(final Session session, final PentahoJcrConstants pentahoJcrConstants, final IPathConversionHelper pathConversionHelper, final ILockHelper lockHelper, final Node fileNode, final int depth, final String childNodeFilter, final boolean showHidden, IRepositoryAccessVoterManager accessVoterManager, RepositoryRequest.FILES_TYPE_FILTER types, MutableBoolean foundFiltered) throws RepositoryException { RepositoryFile rootFile = nodeToFile(session, pentahoJcrConstants, pathConversionHelper, lockHelper, fileNode, false, null); if ((!showHidden && rootFile.isHidden()) || rootFile.isAclNode() || (!accessVoterManager.hasAccess(rootFile, RepositoryFilePermission.READ, JcrRepositoryFileAclUtils.getAcl(session, pentahoJcrConstants, rootFile.getId()), PentahoSessionHolder.getSession()))) { return null; } List<RepositoryFileTree> children; HashSet<Node> childrenFolderSet; // if depth is neither negative (indicating unlimited depth) nor positive (indicating at least one more level // to go) if (depth != 0) { children = new ArrayList<RepositoryFileTree>(); int numberOfPasses = childNodeFilter != null && !childNodeFilter.equals("*") ? 2 : 1; // get Filtered Children set HashSet<Node> filteredChildrenSet; filteredChildrenSet = new HashSet<Node>(); NodeIterator childNodes = fileNode.getNodes(childNodeFilter); while (childNodes.hasNext()) { Node childNode = childNodes.nextNode(); boolean pentahoFolder = isPentahoFolder(pentahoJcrConstants, childNode); if (!(!pentahoFolder && types == RepositoryRequest.FILES_TYPE_FILTER.FOLDERS || pentahoFolder && types == RepositoryRequest.FILES_TYPE_FILTER.FILES)) { filteredChildrenSet.add(childNode); } } // Now get the unfiltered folder set not already in Filtered Set childrenFolderSet = new HashSet<Node>(); if (numberOfPasses == 2) { if (isPentahoFolder(pentahoJcrConstants, fileNode)) { childNodes = fileNode.getNodes(); while (childNodes.hasNext()) { Node childNode = childNodes.nextNode(); boolean pentahoFolder = isPentahoFolder(pentahoJcrConstants, childNode); if (pentahoFolder) { childrenFolderSet.add(childNode); } } } } // Now work on the unfiltered set of folders, if any, add them only if file have been found somewhere down the // tree for (Node childNode : childrenFolderSet) { checkNodeForTree(childNode, children, session, pentahoJcrConstants, pathConversionHelper, childNodeFilter, lockHelper, depth, showHidden, accessVoterManager, types, foundFiltered, false); } // And finally, add Children in filtered for (Node childNode : filteredChildrenSet) { foundFiltered.setValue(true); checkNodeForTree(childNode, children, session, pentahoJcrConstants, pathConversionHelper, childNodeFilter, lockHelper, depth, showHidden, accessVoterManager, types, foundFiltered, true); } Collections.sort(children); } else { children = null; } return new RepositoryFileTree(rootFile, children); } /** * This method is called twice by <code>getTreeNode</code>. It's job is to determine whether the current child node * should be added to the list of children for the node being processed. It is a separate method simply because it is * too much code to appear twice in the above <code>getTreeNode</code> method. It also makes the recursive call back * to getTreeByNode to process the next lower level of folder node (it must process the lower levels to know if the * folder should be added). Finally, it returns the foundFiltered boolean to let the caller know if a file was found * that satisfied the childNodeFilter. */ private static void checkNodeForTree(final Node childNode, List<RepositoryFileTree> children, final Session session, final PentahoJcrConstants pentahoJcrConstants, final IPathConversionHelper pathConversionHelper, final String childNodeFilter, final ILockHelper lockHelper, final int depth, final boolean showHidden, final IRepositoryAccessVoterManager accessVoterManager, RepositoryRequest.FILES_TYPE_FILTER types, MutableBoolean foundFiltered, boolean isRootFiltered) throws RepositoryException { RepositoryFile file = nodeToFile(session, pentahoJcrConstants, pathConversionHelper, lockHelper, childNode); if (isSupportedNodeType(pentahoJcrConstants, childNode) && (accessVoterManager.hasAccess(file, RepositoryFilePermission.READ, JcrRepositoryFileAclUtils.getAcl(session, pentahoJcrConstants, file.getId()), PentahoSessionHolder.getSession()))) { MutableBoolean foundFilteredAtomic = new MutableBoolean( !isPentahoFolder(pentahoJcrConstants, childNode)); RepositoryFileTree repositoryFileTree = getTreeByNode(session, pentahoJcrConstants, pathConversionHelper, lockHelper, childNode, depth - 1, childNodeFilter, showHidden, accessVoterManager, types, foundFilteredAtomic); if (repositoryFileTree != null && (foundFilteredAtomic.booleanValue() || isRootFiltered)) { foundFiltered.setValue(true); children.add(repositoryFileTree); } } } public static Node updateFileLocaleProperties(final Session session, final Serializable fileId, String locale, Properties properties) throws RepositoryException { PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session); Node fileNode = session.getNodeByIdentifier(fileId.toString()); String prefix = session.getNamespacePrefix(PentahoJcrConstants.PHO_NS); Assert.hasText(prefix); Node localesNode = null; if (!fileNode.hasNode(pentahoJcrConstants.getPHO_LOCALES())) { // Auto-create pho:locales node if doesn't exist localesNode = fileNode.addNode(pentahoJcrConstants.getPHO_LOCALES(), pentahoJcrConstants.getPHO_NT_LOCALE()); } else { localesNode = fileNode.getNode(pentahoJcrConstants.getPHO_LOCALES()); } try { Node localeNode = NodeHelper.checkGetNode(localesNode, locale); for (String propertyName : properties.stringPropertyNames()) { localeNode.setProperty(propertyName, properties.getProperty(propertyName)); } } catch (PathNotFoundException pnfe) { // locale doesn't exist, create a new locale node Map<String, Properties> propertiesMap = new HashMap<String, Properties>(); propertiesMap.put(locale, properties); setLocalePropertiesMap(session, pentahoJcrConstants, localesNode, propertiesMap); } return fileNode; } public static Node deleteFileLocaleProperties(final Session session, final Serializable fileId, String locale) throws RepositoryException { PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session); Node fileNode = session.getNodeByIdentifier(fileId.toString()); String prefix = session.getNamespacePrefix(PentahoJcrConstants.PHO_NS); Assert.hasText(prefix); Node localesNode = fileNode.getNode(pentahoJcrConstants.getPHO_LOCALES()); Assert.notNull(localesNode); try { // remove locale node Node localeNode = NodeHelper.checkGetNode(localesNode, locale); localeNode.remove(); } catch (PathNotFoundException pnfe) { // nothing to delete } return fileNode; } public static void setFileMetadata(final Session session, final Serializable fileId, Map<String, Serializable> metadataMap) throws ItemNotFoundException, RepositoryException { PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session); Node fileNode = session.getNodeByIdentifier(fileId.toString()); String prefix = session.getNamespacePrefix(PentahoJcrConstants.PHO_NS); Assert.hasText(prefix); Node metadataNode = fileNode.getNode(pentahoJcrConstants.getPHO_METADATA()); checkoutNearestVersionableNodeIfNecessary(session, pentahoJcrConstants, metadataNode); PropertyIterator propertyIter = metadataNode.getProperties(prefix + ":*"); //$NON-NLS-1$ while (propertyIter.hasNext()) { propertyIter.nextProperty().remove(); } for (String key : metadataMap.keySet()) { setMetadataItemForFile(session, key, metadataMap.get(key), metadataNode); } checkinNearestVersionableNodeIfNecessary(session, pentahoJcrConstants, metadataNode, null); } private static void setMetadataItemForFile(final Session session, final String metadataKey, final Serializable metadataObj, final Node metadataNode) throws ItemNotFoundException, RepositoryException { checkName(metadataKey); Assert.notNull(metadataNode); String prefix = session.getNamespacePrefix(PentahoJcrConstants.PHO_NS); Assert.hasText(prefix); if (metadataObj instanceof String) { metadataNode.setProperty(prefix + ":" + metadataKey, (String) metadataObj); //$NON-NLS-1$ } else if (metadataObj instanceof Calendar) { metadataNode.setProperty(prefix + ":" + metadataKey, (Calendar) metadataObj); //$NON-NLS-1$ } else if (metadataObj instanceof Double) { metadataNode.setProperty(prefix + ":" + metadataKey, (Double) metadataObj); //$NON-NLS-1$ } else if (metadataObj instanceof Long) { metadataNode.setProperty(prefix + ":" + metadataKey, (Long) metadataObj); //$NON-NLS-1$ } else if (metadataObj instanceof Boolean) { metadataNode.setProperty(prefix + ":" + metadataKey, (Boolean) metadataObj); //$NON-NLS-1$ } } public static Map<String, Serializable> getFileMetadata(final Session session, final Serializable fileId) throws ItemNotFoundException, RepositoryException { Map<String, Serializable> values = new HashMap<String, Serializable>(); String prefix = session.getNamespacePrefix(PentahoJcrConstants.PHO_NS); Node fileNode = session.getNodeByIdentifier(fileId.toString()); PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session); String metadataNodeName = pentahoJcrConstants.getPHO_METADATA(); Node metadataNode = null; try { metadataNode = NodeHelper.checkGetNode(fileNode, metadataNodeName); } catch (PathNotFoundException pathNotFound) { // No meta on this return an empty Map return values; } PropertyIterator iter = metadataNode.getProperties(prefix + ":*"); //$NON-NLS-1$ while (iter.hasNext()) { Property property = iter.nextProperty(); String key = property.getName().substring(property.getName().indexOf(':') + 1); Serializable value = null; switch (property.getType()) { case PropertyType.STRING: value = property.getString(); break; case PropertyType.DATE: value = property.getDate(); break; case PropertyType.DOUBLE: value = property.getDouble(); break; case PropertyType.LONG: value = property.getLong(); break; case PropertyType.BOOLEAN: value = property.getBoolean(); break; } if (value != null) { values.put(key, value); } } return values; } /** * Use override list from PentahoSystem if it exists * * @return */ public static List<Character> getReservedChars() { return reservedChars; } /** * Checks for presence of black listed chars as well as illegal permutations of legal chars. */ public static void checkName(final String name) { Pattern containsReservedCharsPattern = makePattern(getReservedChars()); if (!StringUtils.hasLength(name) || // not null, not empty, and not all whitespace !name.trim().equals(name) || // no leading or trailing whitespace containsReservedCharsPattern.matcher(name).matches() || // no reserved characters ".".equals(name) || // no . //$NON-NLS-1$ "..".equals(name)) { // no .. //$NON-NLS-1$ throw new RepositoryFileDaoMalformedNameException(name); } } public static RepositoryFile createFolder(final Session session, final CredentialsStrategySessionFactory sessionFactory, final RepositoryFile parentFolder, final RepositoryFile folder, final boolean inheritAces, final RepositoryFileSid ownerSid, final IPathConversionHelper pathConversionHelper, final String versionMessage) throws RepositoryException { Serializable parentFolderId = parentFolder == null ? null : parentFolder.getId(); PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session); JcrRepositoryFileUtils.checkoutNearestVersionableFileIfNecessary(session, pentahoJcrConstants, parentFolderId); Node folderNode = createFolderNode(session, pentahoJcrConstants, parentFolderId, folder); session.save(); JcrRepositoryFileAclUtils.createAcl(session, pentahoJcrConstants, folderNode.getIdentifier(), new RepositoryFileAcl.Builder(ownerSid).entriesInheriting(inheritAces).build()); session.save(); if (folder.isVersioned()) { JcrRepositoryFileUtils.checkinNearestVersionableNodeIfNecessary(session, pentahoJcrConstants, folderNode, versionMessage); } JcrRepositoryFileUtils.checkinNearestVersionableFileIfNecessary(session, pentahoJcrConstants, parentFolderId, Messages.getInstance().getString("JcrRepositoryFileDao.USER_0001_VER_COMMENT_ADD_FOLDER", folder.getName(), (parentFolderId == null ? "root" : parentFolderId.toString()))); //$NON-NLS-1$ //$NON-NLS-2$ return JcrRepositoryFileUtils.getFileById(session, pentahoJcrConstants, pathConversionHelper, null, folderNode.getIdentifier()); } public static RepositoryFile getFileByAbsolutePath(final Session session, final String absPath, final IPathConversionHelper pathConversionHelper, final ILockHelper lockHelper, final boolean loadMaps, final IPentahoLocale locale) throws RepositoryException { PentahoJcrConstants pentahoJcrConstants = new PentahoJcrConstants(session); Item fileNode; try { fileNode = session.getItem(JcrStringHelper.pathEncode(absPath)); // items are nodes or properties; this must be a node Assert.isTrue(fileNode.isNode()); } catch (PathNotFoundException e) { fileNode = null; } return fileNode != null ? nodeToFile(session, pentahoJcrConstants, pathConversionHelper, lockHelper, (Node) fileNode, loadMaps, locale) : null; } public static IRepositoryVersionManager getRepositoryVersionManager() { if (repositoryVersionManager == null) { repositoryVersionManager = PentahoSystem.get(IRepositoryVersionManager.class); } return repositoryVersionManager; } //User for unit tests public static void setRepositoryVersionManager(IRepositoryVersionManager repositoryVersionManager) { JcrRepositoryFileUtils.repositoryVersionManager = repositoryVersionManager; } }