| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.jackrabbit.oak.plugins.nodetype; |
| |
| import static com.google.common.base.Preconditions.checkState; |
| import static com.google.common.collect.Lists.newArrayList; |
| import static com.google.common.collect.Maps.newTreeMap; |
| import static java.util.Collections.emptyList; |
| import static org.apache.jackrabbit.JcrConstants.JCR_HASORDERABLECHILDNODES; |
| import static org.apache.jackrabbit.JcrConstants.JCR_ISMIXIN; |
| import static org.apache.jackrabbit.JcrConstants.JCR_MIXINTYPES; |
| import static org.apache.jackrabbit.JcrConstants.JCR_NODETYPENAME; |
| import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYITEMNAME; |
| import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE; |
| import static org.apache.jackrabbit.JcrConstants.JCR_SUPERTYPES; |
| import static org.apache.jackrabbit.JcrConstants.JCR_UUID; |
| import static org.apache.jackrabbit.JcrConstants.NT_CHILDNODEDEFINITION; |
| import static org.apache.jackrabbit.JcrConstants.NT_PROPERTYDEFINITION; |
| import static org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants.JCR_IS_ABSTRACT; |
| import static org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants.JCR_IS_QUERYABLE; |
| import static org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants.REP_DECLARING_NODE_TYPE; |
| import static org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants.REP_MIXIN_TYPES; |
| import static org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants.REP_NAMED_CHILD_NODE_DEFINITIONS; |
| import static org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants.REP_NAMED_PROPERTY_DEFINITIONS; |
| import static org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants.REP_PRIMARY_TYPE; |
| import static org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants.REP_RESIDUAL_CHILD_NODE_DEFINITIONS; |
| import static org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants.REP_RESIDUAL_PROPERTY_DEFINITIONS; |
| import static org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants.REP_UUID; |
| import static org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants.RESIDUAL_NAME; |
| |
| import java.io.IOException; |
| import java.io.StringWriter; |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import javax.jcr.PropertyType; |
| import javax.jcr.RepositoryException; |
| import javax.jcr.Value; |
| import javax.jcr.nodetype.ItemDefinition; |
| import javax.jcr.nodetype.NoSuchNodeTypeException; |
| import javax.jcr.nodetype.NodeDefinition; |
| import javax.jcr.nodetype.NodeType; |
| import javax.jcr.nodetype.NodeTypeDefinition; |
| import javax.jcr.nodetype.NodeTypeIterator; |
| import javax.jcr.nodetype.PropertyDefinition; |
| |
| import com.google.common.base.Predicate; |
| import com.google.common.collect.Iterables; |
| import com.google.common.collect.Lists; |
| import com.google.common.collect.Maps; |
| import com.google.common.collect.Sets; |
| import org.apache.jackrabbit.commons.cnd.CompactNodeTypeDefWriter; |
| import org.apache.jackrabbit.commons.iterator.NodeTypeIteratorAdapter; |
| import org.apache.jackrabbit.oak.api.PropertyState; |
| import org.apache.jackrabbit.oak.api.Tree; |
| import org.apache.jackrabbit.oak.api.Type; |
| import org.apache.jackrabbit.oak.commons.UUIDUtils; |
| import org.apache.jackrabbit.oak.namepath.JcrNameParser; |
| import org.apache.jackrabbit.oak.namepath.JcrPathParser; |
| import org.apache.jackrabbit.oak.namepath.NamePathMapper; |
| import org.apache.jackrabbit.oak.plugins.nodetype.constraint.Constraints; |
| import org.apache.jackrabbit.oak.plugins.tree.TreeUtil; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| /** |
| * <pre> |
| * [nt:nodeType] |
| * - jcr:nodeTypeName (NAME) protected mandatory |
| * - jcr:supertypes (NAME) protected multiple |
| * - jcr:isAbstract (BOOLEAN) protected mandatory |
| * - jcr:isQueryable (BOOLEAN) protected mandatory |
| * - jcr:isMixin (BOOLEAN) protected mandatory |
| * - jcr:hasOrderableChildNodes (BOOLEAN) protected mandatory |
| * - jcr:primaryItemName (NAME) protected |
| * + jcr:propertyDefinition (nt:propertyDefinition) = nt:propertyDefinition protected sns |
| * + jcr:childNodeDefinition (nt:childNodeDefinition) = nt:childNodeDefinition protected sns |
| * </pre> |
| */ |
| class NodeTypeImpl extends AbstractTypeDefinition implements NodeType { |
| |
| private static final Logger log = LoggerFactory.getLogger(NodeTypeImpl.class); |
| |
| private static final PropertyDefinition[] NO_PROPERTY_DEFINITIONS = |
| new PropertyDefinition[0]; |
| |
| private static final NodeDefinition[] NO_NODE_DEFINITIONS = |
| new NodeDefinition[0]; |
| |
| private static final NodeType[] NO_NODE_TYPES = new NodeType[0]; |
| |
| private static final String[] NO_NAMES = new String[0]; |
| |
| NodeTypeImpl(Tree type, NamePathMapper mapper) { |
| super(type, mapper); |
| } |
| |
| private String getOakName() { |
| return getOakName(definition); |
| } |
| |
| private String getOakName(Tree tree) { |
| PropertyState property = tree.getProperty(JCR_NODETYPENAME); |
| if (property != null) { |
| return property.getValue(Type.NAME); |
| } else { |
| return tree.getName(); |
| } |
| } |
| |
| //-----------------------------------------------------------< NodeType >--- |
| |
| @Override |
| public String getName() { |
| return mapper.getJcrName(getOakName()); |
| } |
| |
| @Override |
| public String[] getDeclaredSupertypeNames() { |
| String[] names = getNames(JCR_SUPERTYPES); |
| if (names != null) { |
| for (int i = 0; i < names.length; i++) { |
| names[i] = mapper.getJcrName(names[i]); |
| } |
| } else { |
| names = NO_NAMES; |
| } |
| return names; |
| } |
| |
| @Override |
| public boolean isAbstract() { |
| return getBoolean(JCR_IS_ABSTRACT); |
| } |
| |
| @Override |
| public boolean isMixin() { |
| return getBoolean(JCR_ISMIXIN); |
| } |
| |
| @Override |
| public boolean hasOrderableChildNodes() { |
| return getBoolean(JCR_HASORDERABLECHILDNODES); |
| } |
| |
| @Override |
| public boolean isQueryable() { |
| return getBoolean(JCR_IS_QUERYABLE); |
| } |
| |
| @Override |
| public String getPrimaryItemName() { |
| String oakName = getName(JCR_PRIMARYITEMNAME); |
| if (oakName != null) { |
| return mapper.getJcrName(oakName); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Returns the declared property definitions in their original order. |
| * |
| * @return declared property definitions |
| */ |
| @Override @NotNull |
| public PropertyDefinition[] getDeclaredPropertyDefinitions() { |
| Map<Integer, PropertyDefinition> definitions = newTreeMap(); |
| for (Tree child : Iterables.filter(definition.getChildren(), PrimaryTypePredicate.PROPERTY_DEF_PREDICATE)) { |
| definitions.put(getIndex(child), new PropertyDefinitionImpl(child, this, mapper)); |
| } |
| return definitions.values().toArray(NO_PROPERTY_DEFINITIONS); |
| } |
| |
| /** |
| * Returns the declared child node definitions in their original order. |
| * |
| * @return declared child node definitions |
| */ |
| @Override @NotNull |
| public NodeDefinition[] getDeclaredChildNodeDefinitions() { |
| Map<Integer, NodeDefinition> definitions = newTreeMap(); |
| for (Tree child : Iterables.filter(definition.getChildren(), PrimaryTypePredicate.CHILDNODE_DEF_PREDICATE)) { |
| definitions.put(getIndex(child), new NodeDefinitionImpl(child, this, mapper)); |
| } |
| return definitions.values().toArray(NO_NODE_DEFINITIONS); |
| } |
| |
| @Override |
| public NodeType[] getSupertypes() { |
| Map<String, NodeType> supertypes = Maps.newLinkedHashMap(); |
| addSupertypes(definition, supertypes); |
| return supertypes.values().toArray(NO_NODE_TYPES); |
| } |
| |
| private void addSupertypes(Tree type, Map<String, NodeType> supertypes) { |
| PropertyState property = type.getProperty(JCR_SUPERTYPES); |
| if (property != null) { |
| Tree root = definition.getParent(); |
| for (String oakName : property.getValue(Type.NAMES)) { |
| if (!supertypes.containsKey(oakName)) { |
| Tree supertype = root.getChild(oakName); |
| checkState(supertype.exists()); |
| supertypes.put( |
| oakName, new NodeTypeImpl(supertype, mapper)); |
| addSupertypes(supertype, supertypes); |
| } |
| } |
| } |
| } |
| |
| @Override |
| public NodeType[] getDeclaredSupertypes() { |
| NodeType[] supertypes = NO_NODE_TYPES; |
| String[] oakNames = getNames(JCR_SUPERTYPES); |
| if (oakNames != null && oakNames.length > 0) { |
| supertypes = new NodeType[oakNames.length]; |
| Tree root = definition.getParent(); |
| for (int i = 0; i < oakNames.length; i++) { |
| Tree type = root.getChild(oakNames[i]); |
| checkState(type.exists()); |
| supertypes[i] = new NodeTypeImpl(type, mapper); |
| } |
| } |
| return supertypes; |
| } |
| |
| @Override |
| public NodeTypeIterator getSubtypes() { |
| Map<String, Set<String>> inheritance = Maps.newHashMap(); |
| |
| Tree root = definition.getParent(); |
| for (Tree child : root.getChildren()) { |
| String oakName = getOakName(child); |
| PropertyState supertypes = child.getProperty(JCR_SUPERTYPES); |
| if (supertypes != null) { |
| for (String supername : supertypes.getValue(Type.NAMES)) { |
| Set<String> subtypes = inheritance.get(supername); |
| if (subtypes == null) { |
| subtypes = Sets.newHashSet(); |
| inheritance.put(supername, subtypes); |
| } |
| subtypes.add(oakName); |
| } |
| } |
| } |
| |
| Map<String, NodeType> subtypes = Maps.newHashMap(); |
| addSubtypes(getOakName(), subtypes, root, inheritance); |
| return new NodeTypeIteratorAdapter(subtypes.values()); |
| } |
| |
| private void addSubtypes( |
| String typeName, Map<String, NodeType> subtypes, |
| Tree root, Map<String, Set<String>> inheritance) { |
| Set<String> subnames = inheritance.get(typeName); |
| if (subnames != null) { |
| for (String subname : subnames) { |
| if (!subtypes.containsKey(subname)) { |
| Tree tree = root.getChild(subname); |
| subtypes.put(subname, new NodeTypeImpl(tree, mapper)); |
| } |
| } |
| } |
| } |
| |
| @Override |
| public NodeTypeIterator getDeclaredSubtypes() { |
| List<NodeType> subtypes = Lists.newArrayList(); |
| |
| String oakName = getOakName(); |
| Tree root = definition.getParent(); |
| for (Tree child : root.getChildren()) { |
| PropertyState supertypes = child.getProperty(JCR_SUPERTYPES); |
| if (supertypes != null) { |
| for (String name : supertypes.getValue(Type.NAMES)) { |
| if (oakName.equals(name)) { |
| subtypes.add(new NodeTypeImpl(child, mapper)); |
| break; |
| } |
| } |
| } |
| } |
| |
| return new NodeTypeIteratorAdapter(subtypes); |
| } |
| |
| @Override |
| public boolean isNodeType(String nodeTypeName) { |
| String oakName = mapper.getOakNameOrNull(nodeTypeName); |
| return internalIsNodeType(oakName); |
| } |
| |
| @Override |
| public PropertyDefinition[] getPropertyDefinitions() { |
| Collection<PropertyDefinition> definitions = internalGetPropertyDefinitions(); |
| return definitions.toArray(new PropertyDefinition[definitions.size()]); |
| } |
| |
| @Override |
| public NodeDefinition[] getChildNodeDefinitions() { |
| Collection<NodeDefinition> definitions = internalGetChildDefinitions(); |
| return definitions.toArray(new NodeDefinition[definitions.size()]); |
| } |
| |
| @Override |
| public boolean canSetProperty(String propertyName, Value value) { |
| if (value == null) { |
| return canRemoveProperty(propertyName); |
| } |
| |
| try { |
| EffectiveNodeTypeImpl effective = |
| new EffectiveNodeTypeImpl(this, getManager()); |
| PropertyDefinition def = effective.getPropertyDefinition( |
| propertyName, false, value.getType(), false); |
| return !def.isProtected() && |
| meetsTypeConstraints(value, def.getRequiredType()) && |
| meetsValueConstraints(value, def.getValueConstraints()); |
| } catch (RepositoryException e) { // TODO don't use exceptions for flow control. Use internal method in ReadOnlyNodeTypeManager instead. |
| log.debug(e.getMessage()); |
| return false; |
| } |
| } |
| |
| @Override |
| public boolean canSetProperty(String propertyName, Value[] values) { |
| if (values == null) { |
| return canRemoveProperty(propertyName); |
| } |
| |
| try { |
| int type = (values.length == 0) ? PropertyType.STRING : values[0].getType(); |
| EffectiveNodeTypeImpl effective = |
| new EffectiveNodeTypeImpl(this, getManager()); |
| PropertyDefinition def = effective.getPropertyDefinition( |
| propertyName, true, type, false); |
| return !def.isProtected() && |
| meetsTypeConstraints(values, def.getRequiredType()) && |
| meetsValueConstraints(values, def.getValueConstraints()); |
| } catch (RepositoryException e) { // TODO don't use exceptions for flow control. Use internal method in ReadOnlyNodeTypeManager instead. |
| log.debug(e.getMessage()); |
| return false; |
| } |
| } |
| |
| @Override |
| public boolean canAddChildNode(String childNodeName) { |
| // FIXME: properly calculate matching definition |
| for (NodeDefinition definition : getChildNodeDefinitions()) { |
| String name = definition.getName(); |
| if (matches(childNodeName, name) || RESIDUAL_NAME.equals(name)) { |
| return !definition.isProtected() && definition.getDefaultPrimaryType() != null; |
| } |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean canAddChildNode(String childNodeName, String nodeTypeName) { |
| NodeType type; |
| try { |
| type = getManager().getNodeType(nodeTypeName); |
| if (type.isAbstract()) { |
| return false; |
| } |
| } catch (NoSuchNodeTypeException e) { |
| return false; |
| } catch (RepositoryException e) { |
| log.warn("Unable to access node type " + nodeTypeName, e); |
| return false; |
| } |
| // FIXME: properly calculate matching definition |
| for (NodeDefinition definition : getChildNodeDefinitions()) { |
| String name = definition.getName(); |
| if (matches(childNodeName, name) || RESIDUAL_NAME.equals(name)) { |
| if (definition.isProtected()) { |
| return false; |
| } |
| for (String required : definition.getRequiredPrimaryTypeNames()) { |
| if (type.isNodeType(required)) { |
| return true; |
| } |
| } |
| } |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean canRemoveItem(String itemName) { |
| List<ItemDefinition> definitions = Lists.newArrayList(); |
| definitions.addAll(Arrays.asList(getChildNodeDefinitions())); |
| definitions.addAll(Arrays.asList(getPropertyDefinitions())); |
| return internalCanRemoveItem(itemName, definitions); |
| } |
| |
| @Override |
| public boolean canRemoveNode(String nodeName) { |
| return internalCanRemoveItem(nodeName, Arrays.asList(getChildNodeDefinitions())); |
| } |
| |
| @Override |
| public boolean canRemoveProperty(String propertyName) { |
| return internalCanRemoveItem(propertyName, Arrays.asList(getPropertyDefinitions())); |
| } |
| |
| /** |
| * Returns the namespace neutral CND of the given node type definition. |
| * @param def the node type definition |
| * @return the CND |
| */ |
| private static String getCnd(NodeTypeDefinition def) { |
| StringWriter out = new StringWriter(); |
| CompactNodeTypeDefWriter cndWriter = new CompactNodeTypeDefWriter(out, new CompactNodeTypeDefWriter.NamespaceMapping(){ |
| @Override |
| public String getNamespaceURI(String s) { |
| return s; |
| } |
| }, false); |
| try { |
| cndWriter.write(def); |
| } catch (IOException e) { |
| // should never occur |
| log.error("Error generating CND of " + def, e); |
| throw new IllegalStateException(e); |
| } |
| return out.toString(); |
| } |
| |
| //-------------------------------------------------------------< Object >--- |
| @Override |
| public String toString() { |
| return getName(); |
| } |
| |
| @Override |
| public boolean equals(Object o) { |
| return this == o || o instanceof NodeType && getCnd(this).equals(getCnd((NodeType) o)); |
| } |
| |
| @Override |
| public int hashCode() { |
| return getCnd(this).hashCode(); |
| } |
| |
| //-----------------------------------------------------------< internal >--- |
| |
| private boolean internalCanRemoveItem(String itemName, |
| Iterable<? extends ItemDefinition> definitions) { |
| // FIXME: should properly calculate matching definition taking residual definitions into account. |
| for (ItemDefinition definition : definitions) { |
| String name = definition.getName(); |
| if (matches(itemName, name)) { |
| if (definition.isMandatory() || definition.isProtected()) { |
| return false; |
| } |
| } |
| } |
| return definitions.iterator().hasNext(); |
| } |
| |
| private ReadOnlyNodeTypeManager getManager() { |
| final Tree types = definition.getParent(); |
| return new ReadOnlyNodeTypeManager() { |
| @Override @Nullable |
| protected Tree getTypes() { |
| return types; |
| } |
| }; |
| } |
| |
| boolean internalIsNodeType(String oakName) { |
| if (getOakName().equals(oakName)) { |
| return true; |
| } |
| for (NodeType type : getDeclaredSupertypes()) { |
| if (((NodeTypeImpl) type).internalIsNodeType(oakName)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| Collection<NodeDefinition> internalGetChildDefinitions() { |
| // TODO distinguish between additive and overriding node definitions. See 3.7.6.8 Item Definitions in Subtypes |
| Collection<NodeDefinition> definitions = new ArrayList<NodeDefinition>(); |
| definitions.addAll(Arrays.asList(getDeclaredChildNodeDefinitions())); |
| for (NodeType type : getSupertypes()) { |
| definitions.addAll(Arrays.asList(type.getDeclaredChildNodeDefinitions())); |
| } |
| return definitions; |
| } |
| |
| Collection<PropertyDefinition> internalGetPropertyDefinitions() { |
| // TODO distinguish between additive and overriding property definitions. See 3.7.6.8 Item Definitions in Subtypes |
| Collection<PropertyDefinition> definitions = new ArrayList<PropertyDefinition>(); |
| definitions.addAll(Arrays.asList(getDeclaredPropertyDefinitions())); |
| for (NodeType type : getSupertypes()) { |
| definitions.addAll(Arrays.asList(type.getDeclaredPropertyDefinitions())); |
| } |
| return definitions; |
| } |
| |
| List<PropertyDefinition> getDeclaredNamedPropertyDefinitions(String oakName) { |
| String escapedName = oakName; |
| if (JCR_PRIMARYTYPE.equals(oakName)) { |
| escapedName = REP_PRIMARY_TYPE; |
| } else if (JCR_MIXINTYPES.equals(oakName)) { |
| escapedName = REP_MIXIN_TYPES; |
| } else if (JCR_UUID.equals(oakName)) { |
| escapedName = REP_UUID; |
| } |
| return getDeclaredPropertyDefs(definition |
| .getChild(REP_NAMED_PROPERTY_DEFINITIONS) |
| .getChild(escapedName)); |
| } |
| |
| List<PropertyDefinition> getDeclaredResidualPropertyDefinitions() { |
| return getDeclaredPropertyDefs(definition |
| .getChild(REP_RESIDUAL_PROPERTY_DEFINITIONS)); |
| } |
| |
| List<NodeDefinition> getDeclaredNamedNodeDefinitions(String oakName) { |
| return getDeclaredNodeDefs(definition |
| .getChild(REP_NAMED_CHILD_NODE_DEFINITIONS) |
| .getChild(oakName)); |
| } |
| |
| List<NodeDefinition> getDeclaredResidualNodeDefinitions() { |
| return getDeclaredNodeDefs(definition |
| .getChild(REP_RESIDUAL_CHILD_NODE_DEFINITIONS)); |
| } |
| |
| private List<PropertyDefinition> getDeclaredPropertyDefs(Tree definitions) { |
| if (definitions.exists()) { |
| List<PropertyDefinition> list = newArrayList(); |
| String typeName = getOakName(); |
| for (Tree def : definitions.getChildren()) { |
| String declaringTypeName = |
| TreeUtil.getName(def, REP_DECLARING_NODE_TYPE); |
| if (typeName.equals(declaringTypeName)) { |
| list.add(new PropertyDefinitionImpl(def, this, mapper)); |
| } |
| } |
| return list; |
| } else { |
| return emptyList(); |
| } |
| } |
| |
| private List<NodeDefinition> getDeclaredNodeDefs(Tree defs) { |
| if (defs.exists()) { |
| List<NodeDefinition> list = newArrayList(); |
| String typeName = getOakName(); |
| for (Tree def : defs.getChildren()) { |
| String declaringTypeName = |
| TreeUtil.getName(def, REP_DECLARING_NODE_TYPE); |
| if (typeName.equals(declaringTypeName)) { |
| list.add(new NodeDefinitionImpl(def, this, mapper)); |
| } |
| } |
| return list; |
| } else { |
| return emptyList(); |
| } |
| } |
| |
| //-------------------------------------------------------------------------- |
| private static boolean meetsTypeConstraints(Value value, int requiredType) { |
| try { |
| switch (requiredType) { |
| case PropertyType.STRING: |
| value.getString(); |
| return true; |
| case PropertyType.BINARY: |
| value.getBinary(); |
| return true; |
| case PropertyType.LONG: |
| value.getLong(); |
| return true; |
| case PropertyType.DOUBLE: |
| value.getDouble(); |
| return true; |
| case PropertyType.DATE: |
| value.getDate(); |
| return true; |
| case PropertyType.BOOLEAN: |
| value.getBoolean(); |
| return true; |
| case PropertyType.NAME: { |
| int type = value.getType(); |
| return type != PropertyType.DOUBLE && |
| type != PropertyType.LONG && |
| type != PropertyType.BOOLEAN && |
| JcrNameParser.validate(value.getString()); |
| } |
| case PropertyType.PATH: { |
| int type = value.getType(); |
| return type != PropertyType.DOUBLE && |
| type != PropertyType.LONG && |
| type != PropertyType.BOOLEAN && |
| JcrPathParser.validate(value.getString()); |
| } |
| case PropertyType.REFERENCE: |
| case PropertyType.WEAKREFERENCE: |
| return UUIDUtils.isValidUUID(value.getString()); |
| case PropertyType.URI: |
| new URI(value.getString()); |
| return true; |
| case PropertyType.DECIMAL: |
| value.getDecimal(); |
| return true; |
| case PropertyType.UNDEFINED: |
| return true; |
| default: |
| log.warn("Invalid property type value: " + requiredType); |
| return false; |
| } |
| } catch (RepositoryException e) { |
| return false; |
| } catch (URISyntaxException e) { |
| return false; |
| } |
| } |
| |
| private static boolean meetsTypeConstraints(Value[] values, int requiredType) { |
| // Constraints must be met by all values |
| for (Value value : values) { |
| if (!meetsTypeConstraints(value, requiredType)) { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| private static boolean meetsValueConstraints(Value value, String[] constraints) { |
| if (constraints == null || constraints.length == 0) { |
| return true; |
| } |
| |
| // Any of the constraints must be met |
| for (String constraint : constraints) { |
| if (Constraints.valueConstraint(value.getType(), constraint).apply(value)) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| private static boolean meetsValueConstraints(Value[] values, String[] constraints) { |
| if (constraints == null || constraints.length == 0) { |
| return true; |
| } |
| |
| // Constraints must be met by all values |
| for (Value value : values) { |
| if (!meetsValueConstraints(value, constraints)) { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| private static int getIndex(@NotNull Tree tree) { |
| String name = tree.getName(); |
| int i = name.lastIndexOf('['); |
| return (i == -1) ? 1 : Integer.valueOf(name.substring(i+1, name.lastIndexOf(']'))); |
| } |
| |
| private boolean matches(String childNodeName, String name) { |
| String oakChildName = mapper.getOakNameOrNull(childNodeName); |
| String oakName = mapper.getOakNameOrNull(name); |
| // TODO need a better way to handle SNS |
| return oakChildName != null && oakChildName.startsWith(oakName); |
| } |
| |
| private static final class PrimaryTypePredicate implements Predicate<Tree> { |
| |
| private static final PrimaryTypePredicate PROPERTY_DEF_PREDICATE = new PrimaryTypePredicate(NT_PROPERTYDEFINITION); |
| private static final PrimaryTypePredicate CHILDNODE_DEF_PREDICATE = new PrimaryTypePredicate(NT_CHILDNODEDEFINITION); |
| |
| private final String primaryTypeName; |
| |
| private PrimaryTypePredicate(@NotNull String primaryTypeName) { |
| this.primaryTypeName = primaryTypeName; |
| } |
| |
| @Override |
| public boolean apply(Tree tree) { |
| return primaryTypeName.equals(TreeUtil.getPrimaryTypeName(tree)); |
| } |
| } |
| } |