blob: 1bc8d8f8541fe657c19d6c3ff6e5249f1cec59b4 [file] [log] [blame]
/*
* 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.document.bundlor;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants;
import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.jetbrains.annotations.Nullable;
import static org.apache.jackrabbit.oak.api.Type.STRINGS;
import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
import static org.apache.jackrabbit.oak.plugins.memory.PropertyStates.createProperty;
public class BundledTypesRegistry {
public static BundledTypesRegistry NOOP = BundledTypesRegistry.from(EMPTY_NODE);
private final Map<String, DocumentBundlor> bundlors;
public BundledTypesRegistry(Map<String, DocumentBundlor> bundlors) {
this.bundlors = ImmutableMap.copyOf(bundlors);
}
public static BundledTypesRegistry from(NodeState configParentState){
Map<String, DocumentBundlor> bundlors = Maps.newHashMap();
for (ChildNodeEntry e : configParentState.getChildNodeEntries()){
NodeState config = e.getNodeState();
if (config.getBoolean(DocumentBundlor.PROP_DISABLED)){
continue;
}
bundlors.put(e.getName(), DocumentBundlor.from(config));
}
return new BundledTypesRegistry(bundlors);
}
@Nullable
public DocumentBundlor getBundlor(NodeState state) {
if (isVersionedNode(state)){
return getBundlorForVersionedNode(state);
}
//Prefer mixin (as they are more specific) over primaryType
for (String mixin : getMixinNames(state, JcrConstants.JCR_MIXINTYPES)){
DocumentBundlor bundlor = bundlors.get(mixin);
if (bundlor != null){
return bundlor;
}
}
return bundlors.get(getPrimaryTypeName(state, JcrConstants.JCR_PRIMARYTYPE));
}
private DocumentBundlor getBundlorForVersionedNode(NodeState state) {
//Prefer mixin (as they are more specific) over primaryType
for (String mixin : getMixinNames(state, JcrConstants.JCR_FROZENMIXINTYPES)){
DocumentBundlor bundlor = bundlors.get(mixin);
if (bundlor != null){
return bundlor;
}
}
return bundlors.get(getPrimaryTypeName(state, JcrConstants.JCR_FROZENPRIMARYTYPE));
}
Map<String, DocumentBundlor> getBundlors() {
return bundlors;
}
private static boolean isVersionedNode(NodeState state) {
return JcrConstants.NT_FROZENNODE.equals(getPrimaryTypeName(state, JcrConstants.JCR_PRIMARYTYPE));
}
private static String getPrimaryTypeName(NodeState nodeState, String typePropName) {
PropertyState ps = nodeState.getProperty(typePropName);
return (ps == null) ? JcrConstants.NT_BASE : ps.getValue(Type.NAME);
}
private static Iterable<String> getMixinNames(NodeState nodeState, String typePropName) {
PropertyState ps = nodeState.getProperty(typePropName);
return (ps == null) ? Collections.<String>emptyList() : ps.getValue(Type.NAMES);
}
//~--------------------------------------------< Builder >
public static BundledTypesRegistryBuilder builder(){
return new BundledTypesRegistryBuilder(EMPTY_NODE.builder());
}
public static class BundledTypesRegistryBuilder {
private final NodeBuilder builder;
public BundledTypesRegistryBuilder(NodeBuilder builder) {
this.builder = builder;
}
public TypeBuilder forType(String typeName){
NodeBuilder child = builder.child(typeName);
child.setProperty(JcrConstants.JCR_PRIMARYTYPE, NodeTypeConstants.NT_OAK_UNSTRUCTURED, Type.NAME);
return new TypeBuilder(this, child);
}
public TypeBuilder forType(String typeName, String ... includes){
TypeBuilder typeBuilder = forType(typeName);
for (String include : includes){
typeBuilder.include(include);
}
return typeBuilder;
}
public BundledTypesRegistry buildRegistry() {
return BundledTypesRegistry.from(builder.getNodeState());
}
public NodeState build(){
return builder.getNodeState();
}
public static class TypeBuilder {
private final BundledTypesRegistryBuilder parent;
private final NodeBuilder typeBuilder;
private final Set<String> patterns = Sets.newHashSet();
private TypeBuilder(BundledTypesRegistryBuilder parent, NodeBuilder typeBuilder) {
this.parent = parent;
this.typeBuilder = typeBuilder;
}
public TypeBuilder include(String pattern){
patterns.add(pattern);
return this;
}
public BundledTypesRegistry buildRegistry(){
setupPatternProp();
return parent.buildRegistry();
}
public BundledTypesRegistryBuilder registry(){
setupPatternProp();
return parent;
}
public NodeState build(){
setupPatternProp();
return parent.build();
}
private void setupPatternProp() {
typeBuilder.setProperty(createProperty(DocumentBundlor.PROP_PATTERN, patterns, STRINGS));
}
}
}
}