Java tutorial
/** * ========================================================================================== * = JAHIA'S DUAL LICENSING - IMPORTANT INFORMATION = * ========================================================================================== * * http://www.jahia.com * * Copyright (C) 2002-2016 Jahia Solutions Group SA. All rights reserved. * * THIS FILE IS AVAILABLE UNDER TWO DIFFERENT LICENSES: * 1/GPL OR 2/JSEL * * 1/ GPL * ================================================================================== * * IF YOU DECIDE TO CHOOSE THE GPL LICENSE, YOU MUST COMPLY WITH THE FOLLOWING TERMS: * * 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 <http://www.gnu.org/licenses/>. * * * 2/ JSEL - Commercial and Supported Versions of the program * =================================================================================== * * IF YOU DECIDE TO CHOOSE THE JSEL LICENSE, YOU MUST COMPLY WITH THE FOLLOWING TERMS: * * Alternatively, commercial and supported versions of the program - also known as * Enterprise Distributions - must be used in accordance with the terms and conditions * contained in a separate written agreement between you and Jahia Solutions Group SA. * * If you are unsure which license is appropriate for your use, * please contact the sales department at sales@jahia.com. */ package org.jahia.modules.external; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.jackrabbit.util.ChildrenCollectorFilter; import org.apache.jackrabbit.value.BinaryImpl; import org.jahia.modules.external.acl.ExternalDataAce; import org.jahia.modules.external.acl.ExternalDataAcl; import org.jahia.services.content.nodetypes.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.jcr.*; import javax.jcr.lock.Lock; import javax.jcr.lock.LockException; import javax.jcr.nodetype.*; import javax.jcr.version.Version; import javax.jcr.version.VersionException; import javax.jcr.version.VersionHistory; import java.io.IOException; import java.io.InputStream; import java.math.BigDecimal; import java.util.*; /** * Implementation of the {@link javax.jcr.Node} for the {@link org.jahia.modules.external.ExternalData}. * * @author Thomas Draier */ public class ExternalNodeImpl extends ExternalItemImpl implements Node { public static final String MATCH_ALL_PATTERN = "*"; private static final Logger logger = LoggerFactory.getLogger(ExternalNodeImpl.class); private static final String J_TRANSLATION = "j:translation_"; private ExternalData data; private List<String> externalChildren; private Map<String, ExternalPropertyImpl> properties = null; private String uuid; public ExternalNodeImpl(ExternalData data, ExternalSessionImpl session) throws RepositoryException { super(session); this.data = data; this.properties = new HashMap<String, ExternalPropertyImpl>(); for (Map.Entry<String, String[]> entry : data.getProperties().entrySet()) { ExtendedPropertyDefinition definition = getPropertyDefinition(entry.getKey()); if (definition != null && definition.getName().equals(MATCH_ALL_PATTERN) && data.getType() != null && data.getType().equals("jnt:translation")) { definition = ((ExternalNodeImpl) getParent()).getPropertyDefinition(entry.getKey()); } if (definition != null) { int requiredType = definition.getRequiredType(); if (definition.isMultiple()) { Value[] values = new Value[entry.getValue().length]; for (int i = 0; i < entry.getValue().length; i++) { values[i] = session.getValueFactory().createValue(entry.getValue()[i], requiredType); } properties.put(entry.getKey(), new ExternalPropertyImpl( new Name(entry.getKey(), NodeTypeRegistry.getInstance().getNamespaces()), this, session, values)); } else { properties.put(entry.getKey(), new ExternalPropertyImpl( new Name(entry.getKey(), NodeTypeRegistry.getInstance().getNamespaces()), this, session, session.getValueFactory().createValue( entry.getValue().length > 0 ? entry.getValue()[0] : null, requiredType))); } } } if (data.getBinaryProperties() != null) { for (Map.Entry<String, Binary[]> entry : data.getBinaryProperties().entrySet()) { ExtendedPropertyDefinition definition = getPropertyDefinition(entry.getKey()); if (definition != null && definition.getRequiredType() == PropertyType.BINARY) { if (definition.isMultiple()) { Value[] values = new Value[entry.getValue().length]; for (int i = 0; i < entry.getValue().length; i++) { values[i] = session.getValueFactory().createValue(entry.getValue()[i]); } properties.put(entry.getKey(), new ExternalPropertyImpl( new Name(entry.getKey(), NodeTypeRegistry.getInstance().getNamespaces()), this, session, values)); } else { properties.put(entry.getKey(), new ExternalPropertyImpl( new Name(entry.getKey(), NodeTypeRegistry.getInstance().getNamespaces()), this, session, session.getValueFactory().createValue(entry.getValue()[0]))); } } } } properties.put("jcr:uuid", new ExternalPropertyImpl(new Name("jcr:uuid", NodeTypeRegistry.getInstance().getNamespaces()), this, session, session.getValueFactory().createValue(getIdentifier()))); properties.put("jcr:primaryType", new ExternalPropertyImpl( new Name("jcr:primaryType", NodeTypeRegistry.getInstance().getNamespaces()), this, session, session.getValueFactory().createValue(data.getType(), PropertyType.NAME))); ExtendedNodeType[] values = getMixinNodeTypes(); if (values.length > 0) { List<Value> mixins = new ArrayList<Value>(); for (ExtendedNodeType value : values) { mixins.add(session.getValueFactory().createValue(value.getName(), PropertyType.NAME)); } properties.put("jcr:mixinTypes", new ExternalPropertyImpl( new Name("jcr:mixinTypes", NodeTypeRegistry.getInstance().getNamespaces()), this, session, mixins.toArray(new Value[mixins.size()]))); } } private NodeDefinition getChildNodeDefinition(String name, String childType) throws RepositoryException { Map<String, ExtendedNodeDefinition> nodeDefinitionsAsMap = getExtendedPrimaryNodeType() .getChildNodeDefinitionsAsMap(); if (nodeDefinitionsAsMap.containsKey(name)) { return nodeDefinitionsAsMap.get(name); } ExtendedNodeType childTypeNT = NodeTypeRegistry.getInstance().getNodeType(childType); for (NodeType nodeType : getMixinNodeTypes()) { nodeDefinitionsAsMap = ((ExtendedNodeType) nodeType).getChildNodeDefinitionsAsMap(); if (nodeDefinitionsAsMap.containsKey(name)) { return nodeDefinitionsAsMap.get(name); } for (Map.Entry<String, ExtendedNodeDefinition> entry : ((ExtendedNodeType) nodeType) .getUnstructuredChildNodeDefinitions().entrySet()) { if (childTypeNT.isNodeType(entry.getKey())) { return entry.getValue(); } } } for (Map.Entry<String, ExtendedNodeDefinition> entry : getExtendedPrimaryNodeType() .getUnstructuredChildNodeDefinitions().entrySet()) { if (childTypeNT.isNodeType(entry.getKey())) { return entry.getValue(); } } Node extensionNode = getExtensionNode(false); if (extensionNode != null && extensionNode.isNodeType("jnt:externalProviderExtension")) { return extensionNode.getDefinition(); } return null; } public ExtendedPropertyDefinition getPropertyDefinition(String name) throws RepositoryException { Map<String, ExtendedPropertyDefinition> propertyDefinitionsAsMap = getExtendedPrimaryNodeType() .getPropertyDefinitionsAsMap(); if (propertyDefinitionsAsMap.containsKey(name)) { return propertyDefinitionsAsMap.get(name); } for (NodeType nodeType : getMixinNodeTypes(false)) { propertyDefinitionsAsMap = ((ExtendedNodeType) nodeType).getPropertyDefinitionsAsMap(); if (propertyDefinitionsAsMap.containsKey(name)) { return propertyDefinitionsAsMap.get(name); } } if (getExtensionNode(false) != null) { for (NodeType nodeType : getExtensionNode(false).getMixinNodeTypes()) { nodeType = NodeTypeRegistry.getInstance().getNodeType(nodeType.getName()); propertyDefinitionsAsMap = ((ExtendedNodeType) nodeType).getPropertyDefinitionsAsMap(); if (propertyDefinitionsAsMap.containsKey(name)) { return propertyDefinitionsAsMap.get(name); } } } if (!getExtendedPrimaryNodeType().getUnstructuredPropertyDefinitions().isEmpty()) { return getExtendedPrimaryNodeType().getUnstructuredPropertyDefinitions().values().iterator().next(); } return null; } public ExternalData getData() { return data; } /** * {@inheritDoc} */ @Override public String getPath() throws RepositoryException { return data.getPath(); } /** * {@inheritDoc} */ @Override public String getName() throws RepositoryException { return data.getName(); } /** * {@inheritDoc} */ @Override public Node getParent() throws ItemNotFoundException, AccessDeniedException, RepositoryException { if (data.getPath().equals("/")) { throw new ItemNotFoundException(); } String path = StringUtils.substringBeforeLast(data.getPath(), "/"); try { controlManager.checkRead(path.isEmpty() ? "/" : path); } catch (PathNotFoundException e) { throw new AccessDeniedException(path); } return session.getNode(path.isEmpty() ? "/" : path); } public List<String> getExternalChildren() throws RepositoryException { if (externalChildren == null) { if (isNew) { externalChildren = new ArrayList<String>(); } else { ExternalContentStoreProvider.setCurrentSession(session); try { final ExternalDataSource dataSource = session.getRepository().getDataSource(); if (dataSource instanceof ExternalDataSource.CanLoadChildrenInBatch) { ExternalDataSource.CanLoadChildrenInBatch childrenLoader = (ExternalDataSource.CanLoadChildrenInBatch) dataSource; final List<ExternalData> childrenNodes = childrenLoader.getChildrenNodes(getPath()); if (externalChildren == null) { externalChildren = new ArrayList<String>(childrenNodes.size()); } for (ExternalData child : childrenNodes) { String parentPath = StringUtils.substringBeforeLast(child.getPath(), "/"); if (parentPath.equals("")) { parentPath = "/"; } if (parentPath.equals(getPath())) { externalChildren.add(child.getName()); } final ExternalNodeImpl node = new ExternalNodeImpl(child, session); session.registerNode(node); } } else { externalChildren = new ArrayList<String>(dataSource.getChildren(getPath())); } } finally { ExternalContentStoreProvider.removeCurrentSession(); } } } return externalChildren; } /** * {@inheritDoc} */ @Override public boolean isNode() { return true; } @Override void setNew(boolean isNew) throws RepositoryException { super.setNew(isNew); if (!isNew) { if (!data.getTmpId().equals(data.getId())) { getSession().getRepository().getStoreProvider().getExternalProviderInitializerService() .updateExternalIdentifier(data.getTmpId(), data.getId(), getSession().getRepository().getProviderKey(), false); } data.markSaved(); } } /** * {@inheritDoc} */ @Override public void remove() throws VersionException, LockException, ConstraintViolationException, RepositoryException { if (!(session.getRepository().getDataSource() instanceof ExternalDataSource.Writable)) { throw new UnsupportedRepositoryOperationException(); } if (!canRemoveNode()) { throw new AccessDeniedException(getPath()); } if (!data.getPath().equals("/")) { ((ExternalNodeImpl) getParent()).getExternalChildren().remove(getName()); } session.getDeletedData().put(getPath(), data); session.unregisterNode(this); Node extensionNode = getExtensionNode(false); if (extensionNode != null) { extensionNode.remove(); } } protected void removeProperty(String name) throws RepositoryException { if (!(session.getRepository().getDataSource() instanceof ExternalDataSource.Writable)) { throw new UnsupportedRepositoryOperationException(); } checkModify(); boolean hasProperty = false; if (data.getBinaryProperties() != null && data.getBinaryProperties().containsKey(name)) { hasProperty = true; data.getBinaryProperties().remove(name); properties.remove(name); } if (data.getProperties() != null && data.getProperties().containsKey(name)) { hasProperty = true; data.getProperties().remove(name); properties.remove(name); } if (data.getLazyBinaryProperties() != null && data.getLazyBinaryProperties().contains(name)) { hasProperty = true; data.getLazyBinaryProperties().remove(name); } if (data.getLazyProperties() != null && data.getLazyProperties().contains(name)) { hasProperty = true; data.getLazyProperties().remove(name); } if (hasProperty) { session.getChangedData().put(getPath(), data); } } /** * {@inheritDoc} */ @Override public Node addNode(String relPath) throws ItemExistsException, PathNotFoundException, VersionException, ConstraintViolationException, LockException, RepositoryException { return addNode(relPath, null); } /** * {@inheritDoc} */ @Override public Node addNode(String relPath, String primaryNodeTypeName) throws ItemExistsException, PathNotFoundException, NoSuchNodeTypeException, LockException, VersionException, ConstraintViolationException, RepositoryException { checkAddChildNodes(); if (canItemBeExtended(relPath, primaryNodeTypeName)) { if ((StringUtils.equals(primaryNodeTypeName, ExternalDataAcl.ACL_NODE_TYPE) || StringUtils.equals(primaryNodeTypeName, ExternalDataAce.ACE_NODE_TYPE)) && session.getRepository().getDataSource() instanceof ExternalDataSource.AccessControllable) { throw new UnsupportedRepositoryOperationException("Acl and Ace are handle by DataSource"); } Node extendedNode = getExtensionNode(true); if (extendedNode != null) { Node n = extendedNode.addNode(relPath, primaryNodeTypeName); n.addMixin("jmix:externalProviderExtension"); List<Value> values = ExtensionNode.createNodeTypeValues(session.getValueFactory(), primaryNodeTypeName); n.setProperty("j:extendedType", values.toArray(new Value[values.size()])); n.setProperty("j:isExternalProviderRoot", false); String localPath = (getPath().equals("/") ? "/" : getPath() + "/") + relPath; return new ExtensionNode(n, localPath, getSession()); } } if (!(session.getRepository().getDataSource() instanceof ExternalDataSource.Writable)) { throw new UnsupportedRepositoryOperationException(); } String separator = StringUtils.equals(this.data.getId(), "/") ? "" : "/"; ExternalData subNodeData = new ExternalData(this.data.getId() + separator + relPath, getPath() + (getPath().equals("/") ? "" : "/") + relPath, primaryNodeTypeName, new HashMap<String, String[]>(), true); final ExternalNodeImpl newNode = new ExternalNodeImpl(subNodeData, session); session.registerNode(newNode); session.getChangedData().put(subNodeData.getPath(), subNodeData); session.setNewItem(newNode); getExternalChildren().add(relPath); return newNode; } /** * {@inheritDoc} */ @Override public void orderBefore(String srcChildRelPath, String destChildRelPath) throws UnsupportedRepositoryOperationException, VersionException, ConstraintViolationException, ItemNotFoundException, LockException, RepositoryException { if (srcChildRelPath.equals(destChildRelPath)) { return; } List<String> children = getExternalChildren(); children.remove(srcChildRelPath); if (destChildRelPath == null || !children.contains(destChildRelPath)) { // put scrChildNode at the end of the list children.add(srcChildRelPath); } else { children.add(children.indexOf(destChildRelPath), srcChildRelPath); } session.getOrderedData().put(getPath(), children); } /** * {@inheritDoc} */ @Override public Property setProperty(String name, Value value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { checkModify(); if (canItemBeExtended(getPropertyDefinition(name))) { final Node extensionNode = getExtensionNode(true); if (extensionNode != null) { return new ExtensionProperty(extensionNode.setProperty(name, value), getPath() + "/" + name, session, this); } } if (!(session.getRepository().getDataSource() instanceof ExternalDataSource.Writable)) { throw new UnsupportedRepositoryOperationException(); } if (value == null) { if (hasProperty(name)) { removeProperty(name); } return null; } ExtendedPropertyDefinition epd = getPropertyDefinition(name); if (!hasProperty(name) || (hasProperty(name) && !getProperty(name).getValue().equals(value))) { if (epd.getRequiredType() == PropertyType.BINARY) { if (data.getBinaryProperties() == null) { data.setBinaryProperties(new HashMap<String, Binary[]>()); } data.getBinaryProperties().put(name, new Binary[] { value.getBinary() }); } else if (epd.isInternationalized()) { Map<String, String[]> valMap = new HashMap<String, String[]>(); if (getName().startsWith(J_TRANSLATION)) { String lang = StringUtils.substringAfter(getName(), "_"); valMap.put(lang, new String[] { value.getString() }); data.getI18nProperties().put(name, valMap); } else { throw new ConstraintViolationException("Property " + name + " is internationalized"); } } else { data.getProperties().put(name, new String[] { value.getString() }); } final ExternalPropertyImpl newProperty = new ExternalPropertyImpl( new Name(name, NodeTypeRegistry.getInstance().getNamespaces()), this, session, value); properties.put(name, newProperty); session.setNewItem(newProperty); session.getChangedData().put(getPath(), data); } return getProperty(name); } /** * {@inheritDoc} */ @Override public Property setProperty(String name, Value value, int type) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { return setProperty(name, value); } /** * {@inheritDoc} */ @Override public Property setProperty(String name, Value[] values) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { checkModify(); if (canItemBeExtended(getPropertyDefinition(name))) { final Node extensionNode = getExtensionNode(true); if (extensionNode != null) { return new ExtensionProperty(extensionNode.setProperty(name, values), getPath() + "/" + name, session, this); } } if (!(session.getRepository().getDataSource() instanceof ExternalDataSource.Writable)) { throw new UnsupportedRepositoryOperationException(); } if (values == null) { if (hasProperty(name)) { removeProperty(name); } return null; } ExtendedPropertyDefinition epd = getPropertyDefinition(name); if (!hasProperty(name) || (hasProperty(name) && !Arrays.equals(getProperty(name).getValues(), values))) { if (epd.getRequiredType() == PropertyType.BINARY) { if (data.getBinaryProperties() == null) { data.setBinaryProperties(new HashMap<String, Binary[]>()); } Binary[] b = new Binary[values.length]; for (int i = 0; i < values.length; i++) { b[i] = values[i] != null ? values[i].getBinary() : null; } data.getBinaryProperties().put(name, b); } else { String[] s = new String[values.length]; for (int i = 0; i < values.length; i++) { s[i] = values[i] != null ? values[i].getString() : null; } if (epd.isInternationalized()) { Map<String, String[]> valMap = new HashMap<String, String[]>(); if (getName().startsWith(J_TRANSLATION)) { String lang = StringUtils.substringAfter(getName(), "_"); valMap.put(lang, s); data.getI18nProperties().put(name, valMap); } else { throw new ConstraintViolationException("Property " + name + " is internationalized"); } } else { data.getProperties().put(name, s); } } final ExternalPropertyImpl newProperty = new ExternalPropertyImpl( new Name(name, NodeTypeRegistry.getInstance().getNamespaces()), this, session, values); properties.put(name, newProperty); session.setNewItem(newProperty); session.getChangedData().put(getPath(), data); } return getProperty(name); } /** * {@inheritDoc} */ @Override public Property setProperty(String name, Value[] values, int type) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { return setProperty(name, values); } /** * {@inheritDoc} */ @Override public Property setProperty(String name, String[] values) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { Value[] v = null; if (values != null) { v = new Value[values.length]; for (int i = 0; i < values.length; i++) { v[i] = values[i] != null ? getSession().getValueFactory().createValue(values[i]) : null; } } return setProperty(name, v); } /** * {@inheritDoc} */ @Override public Property setProperty(String name, String[] values, int type) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { return setProperty(name, values); } /** * {@inheritDoc} */ @Override public Property setProperty(String name, String value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { Value v = null; if (value != null) { v = getSession().getValueFactory().createValue(value); } return setProperty(name, v); } /** * {@inheritDoc} */ @Override public Property setProperty(String name, String value, int type) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { return setProperty(name, value); } /** * {@inheritDoc} */ @Override @SuppressWarnings("deprecation") public Property setProperty(String name, InputStream value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { checkModify(); if (canItemBeExtended(getPropertyDefinition(name))) { final Node extensionNode = getExtensionNode(true); if (extensionNode != null) { return new ExtensionProperty(extensionNode.setProperty(name, value), getPath() + "/" + name, session, this); } } if (!(session.getRepository().getDataSource() instanceof ExternalDataSource.Writable)) { throw new UnsupportedRepositoryOperationException(); } if (value == null) { if (hasProperty(name)) { removeProperty(name); } return null; } Value v = null; Binary binary = null; try { binary = new BinaryImpl(value); Binary[] b = { binary }; if (data.getBinaryProperties() == null) { data.setBinaryProperties(new HashMap<String, Binary[]>()); } data.getBinaryProperties().put(name, b); v = getSession().getValueFactory().createValue(binary); session.registerTemporaryBinary(binary); } catch (IOException e) { throw new RepositoryException(e); } return setProperty(name, v); } /** * {@inheritDoc} */ @Override public Property setProperty(String name, boolean value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { Value v = getSession().getValueFactory().createValue(value); return setProperty(name, v); } /** * {@inheritDoc} */ @Override public Property setProperty(String name, double value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { Value v = getSession().getValueFactory().createValue(value); return setProperty(name, v); } /** * {@inheritDoc} */ @Override public Property setProperty(String name, long value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { Value v = getSession().getValueFactory().createValue(value); return setProperty(name, v); } /** * {@inheritDoc} */ @Override public Property setProperty(String name, Calendar value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { Value v = null; if (value != null) { v = getSession().getValueFactory().createValue(value); } return setProperty(name, v); } /** * {@inheritDoc} */ @Override public Property setProperty(String name, Node value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { Value v = null; if (value != null) { v = getSession().getValueFactory().createValue(value); } return setProperty(name, v); } /** * {@inheritDoc} */ @Override public Node getNode(String s) throws RepositoryException { Node n = session.getNode(getPath().endsWith("/") ? getPath() + s : getPath() + "/" + s); if (n != null) { return n; } n = getExtensionNode(false); if (n != null) { return new ExtensionNode(n.getNode(s), getPath() + "/" + s, getSession()); } throw new PathNotFoundException(); } /** * {@inheritDoc} */ @Override public NodeIterator getNodes() throws RepositoryException { return getNodes(MATCH_ALL_PATTERN); } /** * {@inheritDoc} */ @Override public NodeIterator getNodes(String namePattern) throws RepositoryException { List<String> filteredList = new ArrayList<>(); final boolean matchAll = MATCH_ALL_PATTERN.equals(namePattern); final ExternalDataSource dataSource = session.getRepository().getDataSource(); if (ExternalDataAcl.ACL_NODE_NAME.equals(data.getName()) && ExternalDataAcl.ACL_NODE_TYPE.equals(data.getType()) && data.getId().startsWith(ExternalDataAcl.ACL_NODE_NAME) && dataSource instanceof ExternalDataSource.AccessControllable) { // get list of ace ExternalNodeImpl parent = (ExternalNodeImpl) getParent(); if (parent.data.getExternalDataAcl() != null && parent.data.getExternalDataAcl().getAcl() != null && parent.data.getExternalDataAcl().getAcl().size() > 0) { for (ExternalDataAce ace : parent.data.getExternalDataAcl().getAcl()) { String aceNodeName = ace.toString(); if (matchAll || ChildrenCollectorFilter.matches(aceNodeName, namePattern)) { filteredList.add(aceNodeName); } } } return new ExternalNodeIterator(filteredList); } final List<String> externalChildren = getExternalChildren(); if (!externalChildren.isEmpty()) { if (!namePattern.equals("j:translation*") && !data.isNew()) { if (!matchAll) { for (String path : externalChildren) { if (ChildrenCollectorFilter.matches(path, namePattern)) { filteredList.add(path); } } } else { filteredList.addAll(externalChildren); } } } Set<String> languages = new HashSet<>(); if (data.getI18nProperties() != null) { languages.addAll(data.getI18nProperties().keySet()); } if (data.getLazyI18nProperties() != null) { languages.addAll(data.getLazyI18nProperties().keySet()); } for (String lang : languages) { if (matchAll || ChildrenCollectorFilter.matches(J_TRANSLATION + lang, namePattern)) { filteredList.add(J_TRANSLATION + lang); } } // handle acl if (data.getExternalDataAcl() != null && dataSource instanceof ExternalDataSource.AccessControllable && (matchAll || ChildrenCollectorFilter.matches(ExternalDataAcl.ACL_NODE_NAME, namePattern))) { filteredList.add(ExternalDataAcl.ACL_NODE_NAME); } Node n = getExtensionNode(false); if (n != null) { return new ExternalNodeIterator(filteredList, matchAll ? n.getNodes() : n.getNodes(namePattern)); } return new ExternalNodeIterator(filteredList); } /** * {@inheritDoc} */ @Override public NodeIterator getNodes(String[] nameGlobs) throws RepositoryException { final List<String> filteredList = new ArrayList<String>(); final ExternalDataSource dataSource = session.getRepository().getDataSource(); if (ExternalDataAcl.ACL_NODE_NAME.equals(data.getName()) && ExternalDataAcl.ACL_NODE_TYPE.equals(data.getType()) && data.getId().startsWith(ExternalDataAcl.ACL_NODE_NAME) && dataSource instanceof ExternalDataSource.AccessControllable) { // get list of ace ExternalNodeImpl parent = (ExternalNodeImpl) getParent(); if (parent.data.getExternalDataAcl() != null && parent.data.getExternalDataAcl().getAcl() != null && parent.data.getExternalDataAcl().getAcl().size() > 0) { for (ExternalDataAce ace : parent.data.getExternalDataAcl().getAcl()) { String aceNodeName = ace.toString(); if (ChildrenCollectorFilter.matches(aceNodeName, nameGlobs)) { filteredList.add(aceNodeName); } } } return new ExternalNodeIterator(filteredList); } for (String path : getExternalChildren()) { if (ChildrenCollectorFilter.matches(path, nameGlobs)) { filteredList.add(path); } } Set<String> languages = new HashSet<String>(); if (data.getI18nProperties() != null) { languages.addAll(data.getI18nProperties().keySet()); } if (data.getLazyI18nProperties() != null) { languages.addAll(data.getLazyI18nProperties().keySet()); } for (String lang : languages) { if (ChildrenCollectorFilter.matches(J_TRANSLATION + lang, nameGlobs)) { filteredList.add(J_TRANSLATION + lang); } } // handle acl if (data.getExternalDataAcl() != null && dataSource instanceof ExternalDataSource.AccessControllable && ChildrenCollectorFilter.matches(ExternalDataAcl.ACL_NODE_NAME, nameGlobs)) { filteredList.add(ExternalDataAcl.ACL_NODE_NAME); } Node n = getExtensionNode(false); if (n != null) { return new ExternalNodeIterator(filteredList, n.getNodes(nameGlobs)); } return new ExternalNodeIterator(filteredList); } /** * {@inheritDoc} */ @Override public Property getProperty(String s) throws PathNotFoundException, RepositoryException { Node n = getExtensionNode(false); if (n != null && n.hasProperty(s) && getPropertyDefinition(s) != null && canItemBeExtended(getPropertyDefinition(s))) { return new ExtensionProperty(n.getProperty(s), getPath() + "/" + s, session, this); } Property property = properties.get(s); if (property == null) { if (data.getLazyProperties() != null && data.getLazyProperties().contains(s)) { String[] values; if (properties.containsKey("jcr:language")) { values = session.getI18nPropertyValues(data, properties.get("jcr:language").getString(), s); } else { values = session.getPropertyValues(data, s); } data.getProperties().put(s, values); data.getLazyProperties().remove(s); ExternalPropertyImpl p = new ExternalPropertyImpl( new Name(s, NodeTypeRegistry.getInstance().getNamespaces()), this, session); ExtendedPropertyDefinition definition = getPropertyDefinition(s); if (definition != null && definition.getName().equals(MATCH_ALL_PATTERN) && data != null && data.getType() != null && data.getType().equals("jnt:translation")) { definition = ((ExternalNodeImpl) getParent()).getPropertyDefinition(s); } if (definition != null && definition.isMultiple()) { p.setValue(values); } else if (values != null && values.length > 0) { p.setValue(values[0]); } properties.put(s, p); return p; } else if (data.getLazyBinaryProperties() != null && data.getLazyBinaryProperties().contains(s)) { Binary[] values = session.getBinaryPropertyValues(data, s); data.getBinaryProperties().put(s, values); data.getLazyBinaryProperties().remove(s); ExternalPropertyImpl p = new ExternalPropertyImpl( new Name(s, NodeTypeRegistry.getInstance().getNamespaces()), this, session); if (getPropertyDefinition(s).isMultiple()) { p.setValue(values); } else if (values != null && values.length > 0) { p.setValue(values[0]); } properties.put(s, p); return p; } else { throw new PathNotFoundException(s); } } return property; } /** * {@inheritDoc} */ @Override public PropertyIterator getProperties() throws RepositoryException { Node n = getExtensionNode(false); if (n != null) { return new ExternalPropertyIterator(properties, n.getProperties(), data.getLazyProperties(), data.getLazyBinaryProperties(), this); } return new ExternalPropertyIterator(properties, data.getLazyProperties(), data.getLazyBinaryProperties(), this); } /** * {@inheritDoc} */ @Override public PropertyIterator getProperties(String namePattern) throws RepositoryException { final Map<String, ExternalPropertyImpl> filteredList = new HashMap<String, ExternalPropertyImpl>(); for (Map.Entry<String, ExternalPropertyImpl> entry : properties.entrySet()) { if (ChildrenCollectorFilter.matches(entry.getKey(), namePattern)) { filteredList.put(entry.getKey(), entry.getValue()); } } Set<String> lazyProperties = null; if (data.getLazyProperties() != null) { lazyProperties = new HashSet<String>(); for (String propertyName : data.getLazyProperties()) { if (ChildrenCollectorFilter.matches(propertyName, namePattern)) { lazyProperties.add(propertyName); } } } Set<String> lazyBinaryProperties = null; if (data.getLazyBinaryProperties() != null) { lazyBinaryProperties = new HashSet<String>(); for (String propertyName : data.getLazyBinaryProperties()) { if (ChildrenCollectorFilter.matches(propertyName, namePattern)) { lazyBinaryProperties.add(propertyName); } } } Node n = getExtensionNode(false); if (n != null) { return new ExternalPropertyIterator(filteredList, n.getProperties(namePattern), lazyProperties, lazyBinaryProperties, this); } return new ExternalPropertyIterator(filteredList, lazyProperties, lazyBinaryProperties, this); } /** * {@inheritDoc} */ @Override public Item getPrimaryItem() throws ItemNotFoundException, RepositoryException { throw new ItemNotFoundException("External node does not support getPrimaryItem"); } /** * {@inheritDoc} */ @Override public String getUUID() throws UnsupportedRepositoryOperationException, RepositoryException { return getIdentifier(); } /** * {@inheritDoc} */ @Override public int getIndex() throws RepositoryException { return 1; } /** * {@inheritDoc} */ @Override public PropertyIterator getReferences() throws RepositoryException { throw new UnsupportedRepositoryOperationException(); } /** * {@inheritDoc} */ @Override public boolean hasNode(String s) throws RepositoryException { return session.itemExists(getPath().endsWith("/") ? getPath() + s : getPath() + "/" + s); } /** * {@inheritDoc} */ @Override public boolean hasProperty(String relPath) throws RepositoryException { return properties.containsKey(relPath) || (data.getLazyProperties() != null && data.getLazyProperties().contains(relPath)) || (data.getLazyBinaryProperties() != null && data.getLazyBinaryProperties().contains(relPath)) || (getExtensionNode(false) != null && getPropertyDefinition(relPath) != null && canItemBeExtended(getPropertyDefinition(relPath)) && getExtensionNode(false).hasProperty(relPath)); } /** * {@inheritDoc} */ @Override public boolean hasNodes() throws RepositoryException { return getNodes().hasNext(); } /** * {@inheritDoc} */ @Override public boolean hasProperties() throws RepositoryException { return (!properties.isEmpty() || (data.getLazyProperties() != null && !data.getLazyProperties().isEmpty()) || (data.getLazyBinaryProperties() != null && !data.getLazyBinaryProperties().isEmpty()) || getProperties().hasNext()); } /** * {@inheritDoc} */ @Override public ExtendedNodeType getPrimaryNodeType() throws RepositoryException { return getExtendedPrimaryNodeType(); } public ExtendedNodeType getExtendedPrimaryNodeType() throws RepositoryException { return NodeTypeRegistry.getInstance().getNodeType(data.getType()); } /** * {@inheritDoc} */ @Override public ExtendedNodeType[] getMixinNodeTypes() throws RepositoryException { return getMixinNodeTypes(true); } private ExtendedNodeType[] getMixinNodeTypes(boolean withExtension) throws RepositoryException { List<ExtendedNodeType> nt = new ArrayList<ExtendedNodeType>(); if (data.getMixin() != null) { for (String s : data.getMixin()) { nt.add(NodeTypeRegistry.getInstance().getNodeType(s)); } } if (data.getExternalDataAcl() != null && data.getExternalDataAcl().getAcl().size() > 0 && session.getRepository().getDataSource() instanceof ExternalDataSource.AccessControllable) { nt.add(NodeTypeRegistry.getInstance().getNodeType("jmix:accessControlled")); } if (withExtension) { Node extensionNode = getExtensionNode(false); if (extensionNode != null) { for (NodeType type : extensionNode.getMixinNodeTypes()) { if (!type.isNodeType("jmix:externalProviderExtension")) { nt.add(NodeTypeRegistry.getInstance().getNodeType(type.getName())); } } } } return nt.toArray(new ExtendedNodeType[nt.size()]); } /** * {@inheritDoc} */ @Override public boolean isNodeType(String nodeTypeName) throws RepositoryException { return isNodeType(nodeTypeName, true); } public boolean isNodeType(String nodeTypeName, boolean withExtension) throws RepositoryException { if (getPrimaryNodeType().isNodeType(nodeTypeName)) { return true; } for (NodeType nodeType : getMixinNodeTypes(withExtension)) { if (nodeType.isNodeType(nodeTypeName)) { return true; } } return false; } /** * {@inheritDoc} */ @Override public void addMixin(String mixinName) throws NoSuchNodeTypeException, VersionException, ConstraintViolationException, LockException, RepositoryException { if (isNodeType(mixinName) || !canManageNodeTypes()) { return; } if (getSession().getExtensionForbiddenMixins().contains(mixinName) && !(data.getMixin() != null && data.getMixin().contains(mixinName))) { List<String> mixins = data.getMixin() == null ? new ArrayList<String>() : new ArrayList<>(data.getMixin()); mixins.add(mixinName); data.setMixin(mixins); return; } Node extensionNode = getExtensionNode(true); if (extensionNode != null) { extensionNode.addMixin(mixinName); return; } throw new UnsupportedRepositoryOperationException(); } /** * {@inheritDoc} */ @Override public void removeMixin(String mixinName) throws NoSuchNodeTypeException, VersionException, ConstraintViolationException, LockException, RepositoryException { if (!canManageNodeTypes()) { return; } if (getSession().getExtensionForbiddenMixins().contains(mixinName) && data.getMixin() != null && data.getMixin().contains(mixinName)) { List<String> mixins = new ArrayList<>(data.getMixin()); mixins.remove(mixinName); data.setMixin(mixins); return; } Node extensionNode = getExtensionNode(false); if (extensionNode != null) { extensionNode.removeMixin(mixinName); // remove child node and properties brought by the mixin PropertyIterator pi = getProperties(); while (pi.hasNext()) { Property extensionProperty = pi.nextProperty(); List<NodeType> nodeTypes = new ArrayList<NodeType>(); nodeTypes.addAll(Arrays.asList(getMixinNodeTypes(true))); nodeTypes.add(NodeTypeRegistry.getInstance().getNodeType("jmix:externalProviderExtension")); boolean canSetProperty = extensionProperty.isMultiple() ? getPrimaryNodeType().canSetProperty(extensionProperty.getName(), extensionProperty.getValues()) : getPrimaryNodeType().canSetProperty(extensionProperty.getName(), extensionProperty.getValue()); for (PropertyDefinition propertyDefinition : getPrimaryNodeType().getPropertyDefinitions()) { if (propertyDefinition.getName().equals(extensionProperty.getName()) && propertyDefinition.getRequiredType() == extensionProperty.getType()) { canSetProperty = true; break; } } if (!canSetProperty) { for (NodeType mixinType : nodeTypes) { if (!StringUtils.equals(mixinType.getName(), mixinName)) { if (extensionProperty.isMultiple()) { if (mixinType.canSetProperty(extensionProperty.getName(), extensionProperty.getValues())) { canSetProperty = true; break; } } else { if (mixinType.canSetProperty(extensionProperty.getName(), extensionProperty.getValue())) { canSetProperty = true; break; } } } } if (!canSetProperty) { extensionProperty.remove(); } } } NodeIterator ni = extensionNode.getNodes(); while (ni.hasNext()) { Node extensionChildNode = ni.nextNode(); boolean canAddChildNode = getPrimaryNodeType().canAddChildNode(extensionChildNode.getName(), getPrimaryNodeType().getName()); if (!canAddChildNode) { for (NodeType mixinType : getMixinNodeTypes(true)) { if (!StringUtils.equals(mixinType.getName(), mixinName)) { if (mixinType.canAddChildNode(extensionChildNode.getName(), getPrimaryNodeType().getName())) { canAddChildNode = true; break; } } } if (!canAddChildNode) { extensionChildNode.remove(); } } } return; } if (!isNodeType(mixinName)) { throw new NoSuchNodeTypeException("Mixin " + mixinName + " not included in node " + getPath()); } throw new UnsupportedRepositoryOperationException(); } /** * {@inheritDoc} */ @Override public boolean canAddMixin(String mixinName) throws NoSuchNodeTypeException, RepositoryException { if (getSession().getExtensionForbiddenMixins().contains(mixinName) && canManageNodeTypes()) { return true; } Node extensionNode = getExtensionNode(true); return extensionNode != null && extensionNode.canAddMixin(mixinName); } /** * {@inheritDoc} */ @Override public NodeDefinition getDefinition() throws RepositoryException { ExternalNodeImpl parentNode; try { parentNode = (ExternalNodeImpl) getParent(); } catch (ItemNotFoundException e) { return null; } ExtendedNodeType parentNodeType = parentNode.getExtendedPrimaryNodeType(); ExtendedNodeDefinition nodeDefinition = parentNodeType.getChildNodeDefinitionsAsMap().get(getName()); if (nodeDefinition != null) { return nodeDefinition; } for (Map.Entry<String, ExtendedNodeDefinition> entry : parentNodeType.getUnstructuredChildNodeDefinitions() .entrySet()) { if (isNodeType(entry.getKey())) { return entry.getValue(); } } return null; } /** * {@inheritDoc} */ @Override public Version checkin() throws VersionException, UnsupportedRepositoryOperationException, InvalidItemStateException, LockException, RepositoryException { throw new UnsupportedRepositoryOperationException(); } /** * {@inheritDoc} */ @Override public void checkout() throws UnsupportedRepositoryOperationException, LockException, RepositoryException { } /** * {@inheritDoc} */ @Override public void doneMerge(Version version) throws VersionException, InvalidItemStateException, UnsupportedRepositoryOperationException, RepositoryException { throw new UnsupportedRepositoryOperationException(); } /** * {@inheritDoc} */ @Override public void cancelMerge(Version version) throws VersionException, InvalidItemStateException, UnsupportedRepositoryOperationException, RepositoryException { throw new UnsupportedRepositoryOperationException(); } /** * {@inheritDoc} */ @Override public void update(String s) throws NoSuchWorkspaceException, AccessDeniedException, LockException, InvalidItemStateException, RepositoryException { throw new UnsupportedRepositoryOperationException(); } /** * {@inheritDoc} */ @Override public NodeIterator merge(String s, boolean b) throws NoSuchWorkspaceException, AccessDeniedException, MergeException, LockException, InvalidItemStateException, RepositoryException { throw new UnsupportedRepositoryOperationException(); } /** * {@inheritDoc} */ @Override public String getCorrespondingNodePath(String workspaceName) throws ItemNotFoundException, NoSuchWorkspaceException, AccessDeniedException, RepositoryException { return getPath(); } /** * {@inheritDoc} */ @Override public boolean isCheckedOut() throws RepositoryException { return true; } /** * {@inheritDoc} */ @Override public void restore(String s, boolean b) throws VersionException, ItemExistsException, UnsupportedRepositoryOperationException, LockException, InvalidItemStateException, RepositoryException { throw new UnsupportedRepositoryOperationException(); } /** * {@inheritDoc} */ @Override public void restore(Version version, boolean b) throws VersionException, ItemExistsException, UnsupportedRepositoryOperationException, LockException, RepositoryException { throw new UnsupportedRepositoryOperationException(); } /** * {@inheritDoc} */ @Override public void restore(Version version, String s, boolean b) throws PathNotFoundException, ItemExistsException, VersionException, ConstraintViolationException, UnsupportedRepositoryOperationException, LockException, InvalidItemStateException, RepositoryException { throw new UnsupportedRepositoryOperationException(); } /** * {@inheritDoc} */ @Override public void restoreByLabel(String s, boolean b) throws VersionException, ItemExistsException, UnsupportedRepositoryOperationException, LockException, InvalidItemStateException, RepositoryException { throw new UnsupportedRepositoryOperationException(); } /** * {@inheritDoc} */ @Override public VersionHistory getVersionHistory() throws UnsupportedRepositoryOperationException, RepositoryException { throw new UnsupportedRepositoryOperationException(); } /** * {@inheritDoc} */ @Override public Version getBaseVersion() throws UnsupportedRepositoryOperationException, RepositoryException { throw new UnsupportedRepositoryOperationException(); } /** * {@inheritDoc} */ @Override public Lock lock(boolean b, boolean b1) throws UnsupportedRepositoryOperationException, LockException, AccessDeniedException, InvalidItemStateException, RepositoryException { return session.getWorkspace().getLockManager().lock(getPath(), b, b1, Long.MAX_VALUE, null); } /** * {@inheritDoc} */ @Override public Lock getLock() throws UnsupportedRepositoryOperationException, LockException, AccessDeniedException, RepositoryException { return session.getWorkspace().getLockManager() != null ? session.getWorkspace().getLockManager().getLock(getPath()) : null; } /** * {@inheritDoc} */ @Override public void unlock() throws UnsupportedRepositoryOperationException, LockException, AccessDeniedException, InvalidItemStateException, RepositoryException { if (session.getWorkspace().getLockManager() != null) { session.getWorkspace().getLockManager().unlock(getPath()); } } /** * {@inheritDoc} */ @Override public boolean holdsLock() throws RepositoryException { return session.getWorkspace().getLockManager() != null && session.getWorkspace().getLockManager().getLock(getPath()) != null; } /** * {@inheritDoc} */ @Override public boolean isLocked() throws RepositoryException { return session.getWorkspace().getLockManager() != null && session.getWorkspace().getLockManager().isLocked(getPath()); } /** * {@inheritDoc} */ @Override public Property setProperty(String name, Binary value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { Value v = null; if (value != null) { InputStream stream = value.getStream(); try { return setProperty(name, stream); } finally { IOUtils.closeQuietly(stream); } } return setProperty(name, v); } /** * {@inheritDoc} */ @Override public Property setProperty(String name, BigDecimal value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException { Value v = null; if (value != null) { v = getSession().getValueFactory().createValue(value); } return setProperty(name, v); } /** * {@inheritDoc} */ @Override public PropertyIterator getProperties(String[] nameGlobs) throws RepositoryException { final Map<String, ExternalPropertyImpl> filteredList = new HashMap<String, ExternalPropertyImpl>(); for (Map.Entry<String, ExternalPropertyImpl> entry : properties.entrySet()) { if (ChildrenCollectorFilter.matches(entry.getKey(), nameGlobs)) { filteredList.put(entry.getKey(), entry.getValue()); } } Set<String> lazyProperties = null; if (data.getLazyProperties() != null) { lazyProperties = new HashSet<String>(); for (String propertyName : data.getLazyProperties()) { if (ChildrenCollectorFilter.matches(propertyName, nameGlobs)) { lazyProperties.add(propertyName); } } } Set<String> lazyBinaryProperties = null; if (data.getLazyBinaryProperties() != null) { lazyBinaryProperties = new HashSet<String>(); for (String propertyName : data.getLazyBinaryProperties()) { if (ChildrenCollectorFilter.matches(propertyName, nameGlobs)) { lazyBinaryProperties.add(propertyName); } } } Node n = getExtensionNode(false); if (n != null) { return new ExternalPropertyIterator(filteredList, n.getProperties(nameGlobs), lazyProperties, lazyBinaryProperties, this); } return new ExternalPropertyIterator(filteredList, lazyProperties, lazyBinaryProperties, this); } /** * {@inheritDoc} */ @Override public final String getIdentifier() throws RepositoryException { if (uuid == null) { if (!session.getRepository().getDataSource().isSupportsUuid() || data.getId().startsWith(ExternalSessionImpl.TRANSLATION_PREFIX)) { uuid = getStoreProvider().getOrCreateInternalIdentifier(data.getId()); } else { uuid = data.getId(); } } return uuid; } /** * {@inheritDoc} */ @Override public PropertyIterator getReferences(String name) throws RepositoryException { throw new UnsupportedRepositoryOperationException(); } /** * {@inheritDoc} */ @Override public PropertyIterator getWeakReferences() throws RepositoryException { throw new UnsupportedRepositoryOperationException(); } /** * {@inheritDoc} */ @Override public PropertyIterator getWeakReferences(String name) throws RepositoryException { throw new UnsupportedRepositoryOperationException(); } /** * {@inheritDoc} */ @Override public void setPrimaryType(String nodeTypeName) throws NoSuchNodeTypeException, VersionException, ConstraintViolationException, LockException, RepositoryException { throw new UnsupportedRepositoryOperationException(); } /** * {@inheritDoc} */ @Override public NodeIterator getSharedSet() throws RepositoryException { return new ExternalNodeIterator(new ArrayList<String>()); } /** * {@inheritDoc} */ @Override public void removeSharedSet() throws VersionException, LockException, ConstraintViolationException, RepositoryException { throw new UnsupportedRepositoryOperationException(); } /** * {@inheritDoc} */ @Override public void removeShare() throws VersionException, LockException, ConstraintViolationException, RepositoryException { throw new UnsupportedRepositoryOperationException(); } /** * {@inheritDoc} */ @Override public void followLifecycleTransition(String transition) throws UnsupportedRepositoryOperationException, InvalidLifecycleTransitionException, RepositoryException { throw new UnsupportedRepositoryOperationException(); } /** * {@inheritDoc} */ @Override public String[] getAllowedLifecycleTransistions() throws UnsupportedRepositoryOperationException, RepositoryException { return new String[0]; } public Node getExtensionNode(boolean create) throws RepositoryException { Session extensionSession = getSession().getExtensionSession(); if (extensionSession == null) { return null; } List<String> extensionAllowedTypes = getSession().getExtensionAllowedTypes(); boolean allowed = false; if (extensionAllowedTypes != null) { for (String type : extensionAllowedTypes) { if (isNodeType(type, false)) { allowed = true; break; } } } if (!allowed) { return null; } String path = getPath(); boolean isRoot = path.equals("/"); String mountPoint = getStoreProvider().getMountPoint(); String globalPath = mountPoint + (isRoot ? "" : path); if (!extensionSession.itemExists(globalPath)) { if (!create) { return null; } else { // create extension nodes if needed String[] splittedPath = StringUtils.split(path, "/"); StringBuilder currentExtensionPath = new StringBuilder(mountPoint); StringBuilder currentExternalPath = new StringBuilder(); // create extension node on the mountpoint if needed if (!extensionSession.nodeExists(mountPoint)) { String parent = StringUtils.substringBeforeLast(mountPoint, "/"); if (parent.equals("")) { parent = "/"; } final Node extParent = extensionSession.getNode(parent); takeLockToken(extParent); extParent.addMixin("jmix:hasExternalProviderExtension"); Node n = extParent.addNode(StringUtils.substringAfterLast(mountPoint, "/"), "jnt:externalProviderExtension"); n.addMixin("jmix:externalProviderExtension"); n.setProperty("j:isExternalProviderRoot", true); Node externalNode = (Node) session.getItemWithNoCheck("/"); n.setProperty("j:externalNodeIdentifier", externalNode.getIdentifier()); List<Value> values = ExtensionNode.createNodeTypeValues(session.getValueFactory(), externalNode.getPrimaryNodeType().getName()); n.setProperty("j:extendedType", values.toArray(new Value[values.size()])); } for (String p : splittedPath) { currentExtensionPath.append("/").append(p); currentExternalPath.append("/").append(p); if (!extensionSession.nodeExists(currentExtensionPath.toString())) { final Node extParent = extensionSession .getNode(StringUtils.substringBeforeLast(currentExtensionPath.toString(), "/")); takeLockToken(extParent); Node n = extParent.addNode(p, "jnt:externalProviderExtension"); Node externalNode = (Node) session.getItemWithNoCheck(currentExternalPath.toString()); List<Value> values = ExtensionNode.createNodeTypeValues(session.getValueFactory(), externalNode.getPrimaryNodeType().getName()); n.setProperty("j:extendedType", values.toArray(new Value[values.size()])); n.addMixin("jmix:externalProviderExtension"); n.setProperty("j:isExternalProviderRoot", false); n.setProperty("j:externalNodeIdentifier", externalNode.getIdentifier()); } } } } Node node = extensionSession.getNode(globalPath); if (create && isRoot && !node.isNodeType("jmix:hasExternalProviderExtension")) { node.addMixin("jmix:hasExternalProviderExtension"); } if (!node.isNodeType("jmix:externalProviderExtension")) { node.addMixin("jmix:externalProviderExtension"); } return node; } public void takeLockToken(Node parentNode) throws RepositoryException { if (parentNode.isLocked() && parentNode.hasProperty("j:locktoken")) { parentNode.getSession().addLockToken(parentNode.getProperty("j:locktoken").getString()); } } public boolean canItemBeExtended(String relPath, String primaryNodeTypeName) throws RepositoryException { return canItemBeExtended(getChildNodeDefinition(relPath, primaryNodeTypeName)); } public boolean canItemBeExtended(ItemDefinition definition) throws RepositoryException { if (definition == null) { throw new ConstraintViolationException(); } NodeType type = definition.getDeclaringNodeType(); Map<String, List<String>> overridableProperties = getSession().getOverridableProperties(); Map<String, List<String>> nonOverridableProperties = getSession().getNonOverridableProperties(); for (Map.Entry<String, List<String>> entry : overridableProperties.entrySet()) { if ((entry.getKey().equals(MATCH_ALL_PATTERN) || type.getName().equals(entry.getKey())) && (entry.getValue().contains(MATCH_ALL_PATTERN) || entry.getValue().contains(definition.getName())) && !(nonOverridableProperties.containsKey(MATCH_ALL_PATTERN) && nonOverridableProperties.get(MATCH_ALL_PATTERN).contains(definition.getName())) && !(nonOverridableProperties.containsKey(type.getName()) && nonOverridableProperties.get(type.getName()).contains(definition.getName()))) { return true; } } if (type.isMixin()) { Node ext = getExtensionNode(false); if (ext != null) { for (NodeType assignedMixin : ext.getMixinNodeTypes()) { if (assignedMixin.isNodeType(type.getName())) { return true; } } } } return false; } @Override public String toString() { return "external node " + data.getPath(); } /** * Property iterator implementation */ private class ExternalPropertyIterator implements PropertyIterator { private int pos = 0; private Iterator<ExternalPropertyImpl> it; private PropertyIterator extensionPropertiesIterator; private Property nextProperty = null; private Map<String, ExternalPropertyImpl> externalProperties; private Set<String> lazyProperties; private Iterator<String> lazyPropertiesIterator; private ExternalNodeImpl node; ExternalPropertyIterator(Map<String, ExternalPropertyImpl> externalPropertyMap, Set<String> lazyProperties, Set<String> lazyBinaryProperties, ExternalNodeImpl node) { this(externalPropertyMap, null, lazyProperties, lazyBinaryProperties, node); } ExternalPropertyIterator(Map<String, ExternalPropertyImpl> externalPropertyMap, PropertyIterator extensionPropertiesIterator, Set<String> lazyProperties, Set<String> lazyBinaryProperties, ExternalNodeImpl node) { this.extensionPropertiesIterator = extensionPropertiesIterator; this.externalProperties = new HashMap<String, ExternalPropertyImpl>(externalPropertyMap); this.lazyProperties = new HashSet<String>(); if (lazyProperties != null) { this.lazyProperties.addAll(lazyProperties); } if (lazyBinaryProperties != null) { this.lazyProperties.addAll(lazyBinaryProperties); } this.node = node; fetchNext(); } private void fetchNext() { nextProperty = null; if (extensionPropertiesIterator != null) { while (extensionPropertiesIterator.hasNext()) { Property next = extensionPropertiesIterator.nextProperty(); try { final ExtendedPropertyDefinition propertyDefinition = getPropertyDefinition(next.getName()); if (propertyDefinition != null && canItemBeExtended(propertyDefinition)) { nextProperty = new ExtensionProperty(next, getPath() + "/" + next.getName(), node.getSession(), ExternalNodeImpl.this); externalProperties.remove(next.getName()); lazyProperties.remove(next.getName()); return; } } catch (RepositoryException e) { logger.error("Cannot get property", e); } } } if (it == null) { it = externalProperties.values().iterator(); } if (it.hasNext()) { nextProperty = it.next(); return; } if (lazyPropertiesIterator == null && lazyProperties != null) { lazyPropertiesIterator = lazyProperties.iterator(); } if (lazyPropertiesIterator != null && lazyPropertiesIterator.hasNext()) { String propertyName = lazyPropertiesIterator.next(); try { nextProperty = getProperty(propertyName); } catch (RepositoryException e) { logger.error(e.getMessage(), e); logger.error(e.getMessage(), e); } } } @Override public Property nextProperty() { if (nextProperty == null) { throw new NoSuchElementException(); } Property next = nextProperty; fetchNext(); pos++; return next; } @Override public void skip(long skipNum) { for (int i = 0; i < skipNum; i++) { nextProperty(); } } @Override public long getSize() { return externalProperties.size() + (extensionPropertiesIterator != null ? extensionPropertiesIterator.getSize() : 0); } @Override public long getPosition() { return pos; } @Override public boolean hasNext() { return nextProperty != null; } @Override public Object next() { return nextProperty(); } @Override public void remove() { throw new UnsupportedOperationException("remove"); } } /** * Node iterator implementation */ private class ExternalNodeIterator implements NodeIterator { private int pos = 0; private Iterator<String> it; private final List<String> list; private NodeIterator extensionNodeIterator; private Node nextNode; public ExternalNodeIterator(List<String> list) { this(list, null); } public ExternalNodeIterator(List<String> list, NodeIterator extensionNodeIterator) { this.extensionNodeIterator = extensionNodeIterator; this.list = list; this.it = list.iterator(); fetchNext(); } private Node fetchNext() { nextNode = null; if (it.hasNext()) { Node next = null; do { try { next = getNode(it.next()); } catch (RepositoryException e) { next = null; logger.debug(e.getMessage(), e); } } while (next == null && hasNext()); nextNode = next; return nextNode; } if (extensionNodeIterator != null) { while (extensionNodeIterator.hasNext()) { Node n = extensionNodeIterator.nextNode(); try { if (!list.contains(n.getName())) { String path = getPath(); if (!path.endsWith("/")) { path += "/"; } path += n.getName(); try { nextNode = session.getNode(path); } catch (PathNotFoundException e) { logger.debug("Cannot find node " + path, e); } return nextNode; } } catch (RepositoryException e) { logger.error(e.getMessage(), e); } } } return null; } @Override public Node nextNode() { if (nextNode == null) { throw new NoSuchElementException(); } Node next = nextNode; fetchNext(); pos++; return next; } @Override public void skip(long skipNum) { for (int i = 0; i < skipNum; i++) { nextNode(); } } @Override public long getSize() { return list.size() + (extensionNodeIterator != null ? extensionNodeIterator.getSize() : 0); } @Override public long getPosition() { return pos; } @Override public boolean hasNext() { return nextNode != null; } @Override public Object next() { return nextNode(); } @Override public void remove() { throw new UnsupportedOperationException(); } } }