org.apache.jackrabbit.spi.commons.ItemInfoBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.apache.sling.feature.analyser Show documentation
Show all versions of org.apache.sling.feature.analyser Show documentation
A feature describes an OSGi system
/*
* 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.spi.commons;
import static org.apache.jackrabbit.spi.commons.iterator.Iterators.filterIterator;
import static org.apache.jackrabbit.spi.commons.iterator.Iterators.transformIterator;
import org.apache.jackrabbit.spi.ChildInfo;
import org.apache.jackrabbit.spi.ItemInfo;
import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.spi.NodeId;
import org.apache.jackrabbit.spi.NodeInfo;
import org.apache.jackrabbit.spi.Path;
import org.apache.jackrabbit.spi.PropertyId;
import org.apache.jackrabbit.spi.PropertyInfo;
import org.apache.jackrabbit.spi.QValue;
import org.apache.jackrabbit.spi.commons.identifier.IdFactoryImpl;
import org.apache.jackrabbit.spi.commons.iterator.Iterators;
import org.apache.jackrabbit.spi.commons.iterator.Predicate;
import org.apache.jackrabbit.spi.commons.iterator.Transformer;
import org.apache.jackrabbit.spi.commons.name.NameConstants;
import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
import org.apache.jackrabbit.spi.commons.name.PathFactoryImpl;
import org.apache.jackrabbit.spi.commons.value.QValueFactoryImpl;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.URI;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;
/**
* Utility class providing a {@link NodeInfoBuilder} for building {@link NodeInfo}.
* Example usage:
*
* ItemInfoBuilder.nodeInfoBuilder()
* .createNodeInfo("node1")
* .createPropertyInfo("prop1", "value1").build()
* .createPropertyInfo("prop2")
* .addValue(1.2)
* .addValue(2.3)
* .build()
* .build()
* .createNodeInfo("node2")
* .setPrimaryType(NameConstants.NT_BASE)
* .addMixin(NameConstants.MIX_LOCKABLE)
* .createPropertyInfo("prop3")
* .setType(PropertyType.BINARY)
* .build()
* .build()
* .build();
*
*/
public final class ItemInfoBuilder {
private ItemInfoBuilder() {
super();
}
/**
* Same as nodeInfoBuilder("", listener)
* @param listener
* @return
*/
public static NodeInfoBuilder nodeInfoBuilder(Listener listener) {
return nodeInfoBuilder("", listener);
}
/**
* Same as nodeInfoBuilder("", null)
* @return
*/
public static NodeInfoBuilder nodeInfoBuilder() {
return nodeInfoBuilder("", null);
}
/**
* Same as nodeInfoBuilder(localName, null)
* @param localName
* @return
*/
public static NodeInfoBuilder nodeInfoBuilder(String localName) {
return nodeInfoBuilder(localName, null);
}
/**
* Return a {@link NodeInfoBuilder} for a node with a given localName
.
* @param localName localName of the node
* @param listener {@link Listener} to receive notifications about {@link NodeInfo}s,
* {@link PropertyInfo}s and {@link ChildInfo}s built.
* @return
*/
public static NodeInfoBuilder nodeInfoBuilder(String localName, Listener listener) {
return new NodeInfoBuilder(null, localName, listener);
}
/**
* Return a {@link NodeInfoBuilder} for a node with a given name
.
* @param name name of the node
* @param listener {@link Listener} to receive notifications about {@link NodeInfo}s,
* {@link PropertyInfo}s and {@link ChildInfo}s built.
* @return
*/
public static NodeInfoBuilder nodeInfoBuilder(Name name, Listener listener) {
return new NodeInfoBuilder(null, name, listener);
}
/**
* A listener for receiving notifications about items built by the builders in this class.
*/
public interface Listener {
/**
* Notification that a new {@link NodeInfo} has been built.
* @param nodeInfo
*/
void createNodeInfo(NodeInfo nodeInfo);
/**
* Notification that new {@link ChildInfo}s have been built.
* @param id Id of the parent to which the childInfos
belong
* @param childInfos
*/
void createChildInfos(NodeId id, Iterator childInfos);
/**
* Notification that a new {@link PropertyInfo} has been built.
* @param propertyInfo
*/
void createPropertyInfo(PropertyInfo propertyInfo);
}
/**
* Builder for {@link NodeInfo}s. Use one of the {@link ItemInfoBuilder#nodeInfoBuilder()}
* methods to create instances of this class.
*/
public static class NodeInfoBuilder {
private final NodeInfoBuilder parent;
private final Listener listener;
private Path parentPath;
private String localName;
private String namespace;
private Name name;
private int index = Path.INDEX_DEFAULT;
private String uuid;
private Name primaryTypeName = NameConstants.NT_UNSTRUCTURED;
private final List mixins = new ArrayList();
private boolean includeChildInfos = true;
private boolean stale;
private final List itemInfos = new ArrayList();
private NodeInfo nodeInfo;
private NodeInfoBuilder(NodeInfoBuilder nodeInfoBuilder, String localName, Listener listener) {
super();
parent = nodeInfoBuilder;
this.localName = localName;
this.listener = listener;
}
private NodeInfoBuilder(NodeInfoBuilder nodeInfoBuilder, Name name, Listener listener) {
super();
parent = nodeInfoBuilder;
this.name = name;
this.listener = listener;
}
/**
* Create a new child {@link PropertyInfo} with a given localName
and a given
* value
of type String
on this {@link NodeInfo}.
*
* @param localName
* @param value
* @return this
* @throws RepositoryException
*/
public PropertyInfoBuilder createPropertyInfo(String localName, String value) throws RepositoryException {
PropertyInfoBuilder pBuilder = new PropertyInfoBuilder(this, localName, listener);
pBuilder.addValue(value);
return pBuilder;
}
/**
* Create a new child {@link PropertyInfo} with a given
* localName
on this {@link NodeInfo}.
*
* @param localName
* @return this
*/
public PropertyInfoBuilder createPropertyInfo(String localName) {
return new PropertyInfoBuilder(this, localName, listener);
}
/**
* Create a new child {@link PropertyInfo} on this {@link NodeInfo}.
*
* @return this
*/
public PropertyInfoBuilder createPropertyInfo() {
return new PropertyInfoBuilder(this, null, listener);
}
/**
* Create a new child {@link NodeInfo} on this NodeInfo with a given localName
.
* @param localName
* @return this
*/
public NodeInfoBuilder createNodeInfo(String localName) {
return new NodeInfoBuilder(this, localName, listener);
}
/**
* Create a new child {@link NodeInfo} on this NodeInfo.
* @return this
*/
public NodeInfoBuilder createNodeInfo() {
return new NodeInfoBuilder(this, (String) null, listener);
}
/**
* Set the name
of the node
*
* @param name
* @return
*/
public NodeInfoBuilder setName(Name name) {
this.name = name;
return this;
}
/**
* Set the localName
of the node
*
* @param localName
* @return
*/
public NodeInfoBuilder setName(String localName) {
this.localName = localName;
return this;
}
/**
* Set the namespace
*
* @param namespace
* @return
*/
public NodeInfoBuilder setNamespace(String namespace) {
this.namespace = namespace;
return this;
}
/**
* Set the index.
* @see NodeInfo#getIndex()
*
* @param index
* @return
*/
public NodeInfoBuilder setIndex(int index) {
this.index = index;
return this;
}
/**
* Set the uuid
*
* @param uuid
* @return
*/
public NodeInfoBuilder setUUID(String uuid) {
this.uuid = uuid;
return this;
}
/**
* Set the parent's path of the node
*
* @param parentPath
* @return
*/
public NodeInfoBuilder setParentPath(Path parentPath) {
this.parentPath = parentPath;
return this;
}
/**
* Set the name of the primary type.
* @param name
* @see NodeInfo#getNodetype()
*
* @return
*/
public NodeInfoBuilder setPrimaryType(Name name) {
primaryTypeName = name;
return this;
}
/**
* Add a mixin type
* @see NodeInfo#getMixins()
*
* @param name
* @return
*/
public NodeInfoBuilder addMixin(Name name) {
mixins.add(name);
return this;
}
/**
* Whether the {@link ChildInfo}s should be included or not.
* @see NodeInfo#getChildInfos()
*
* @param include
* @return
*/
public NodeInfoBuilder includeChildInfos(boolean include) {
includeChildInfos = include;
return this;
}
/**
* Build the {@link NodeInfo}. If a {@link Listener} is associated with this
* instance, then its {@link Listener#createChildInfos(NodeId, Iterator)} and
* its {@link Listener#createNodeInfo(NodeInfo)} methods are called.
*
* @return the parent builder of this builder
* @throws RepositoryException
* @throws IllegalStateException if build has been called before
*/
public NodeInfoBuilder build() throws RepositoryException {
if (stale) {
throw new IllegalStateException("Builder is stale");
}
else {
stale = true;
NodeId id = getId();
nodeInfo = new NodeInfoImpl(getPath(), id, index, primaryTypeName,
mixins.toArray(new Name[mixins.size()]), Iterators.empty(),
getPropertyIds(), includeChildInfos ? getChildInfos() : null);
if (listener != null) {
listener.createNodeInfo(nodeInfo);
listener.createChildInfos(id, getChildInfos());
}
if (parent == null) {
return this;
}
else {
parent.addNodeInfo(nodeInfo);
return parent;
}
}
}
/**
* @return the parent builder of this builder
*/
public NodeInfoBuilder getParent() {
return parent;
}
/**
* Returns the {@link NodeInfo} which has been built by this builder.
*
* @return
* @throws IllegalStateException if {@link #build()} has not been called before.
*/
public NodeInfo getNodeInfo() {
if (!stale) {
throw new IllegalStateException("NodeInfo not built yet");
}
return nodeInfo;
}
/**
* Add a {@link PropertyInfo}
*
* @param propertyInfo
* @return this
*/
public NodeInfoBuilder addPropertyInfo(PropertyInfo propertyInfo) {
itemInfos.add(propertyInfo);
return this;
}
/**
* Add a {@link NodeInfo}
*
* @param nodeInfo
* @return this
*/
public NodeInfoBuilder addNodeInfo(NodeInfo nodeInfo) {
itemInfos.add(nodeInfo);
return this;
}
private NodeId getId() throws RepositoryException {
if (uuid == null) {
return IdFactoryImpl.getInstance().createNodeId((String) null, getPath());
}
else {
return IdFactoryImpl.getInstance().createNodeId(uuid);
}
}
private Path getPath() throws RepositoryException {
if (localName == null && name == null) {
throw new IllegalStateException("Name not set");
}
if (parent == null && parentPath == null) {
return PathFactoryImpl.getInstance().getRootPath();
}
else {
Path path = parentPath == null ? parent.getPath() : parentPath;
if (name == null) {
String ns = namespace == null ? Name.NS_DEFAULT_URI : namespace;
name = NameFactoryImpl.getInstance().create(ns, localName);
}
return PathFactoryImpl.getInstance().create(path, name, true);
}
}
private Iterator getChildInfos() {
return transformIterator(filterIterator(itemInfos.iterator(),
new Predicate(){
public boolean evaluate(ItemInfo info) {
return info.denotesNode();
}
}),
new Transformer(){
public ChildInfo transform(ItemInfo info) {
return new ChildInfoImpl(
info.getPath().getName(), null,
Path.INDEX_DEFAULT);
}
});
}
private Iterator getPropertyIds() {
return transformIterator(filterIterator(itemInfos.iterator(),
new Predicate(){
public boolean evaluate(ItemInfo info) {
return !info.denotesNode();
}
}),
new Transformer(){
public PropertyId transform(ItemInfo info) {
return (PropertyId) info.getId();
}
});
}
}
/**
* Builder for {@link PropertyInfo}s. Use {@link NodeInfoBuilder#createPropertyInfo(String)}
* to create an instance of this class.
*/
public static class PropertyInfoBuilder {
private final NodeInfoBuilder parent;
private final Listener listener;
private Name name;
private String localName;
private String namespace;
private final List values = new ArrayList();
private int type = PropertyType.UNDEFINED;
private boolean isMultivalued = true;
private boolean stale;
private PropertyInfo propertyInfo;
private PropertyInfoBuilder(NodeInfoBuilder nodeInfoBuilder, String localName, Listener listener) {
super();
parent = nodeInfoBuilder;
this.localName = localName;
this.listener = listener;
}
/**
* Set the name
of this property
*
* @param name
* @return
*/
public PropertyInfoBuilder setName(Name name) {
this.name = name;
return this;
}
/**
* Set the localName
of this property
*
* @param localName
* @return
*/
public PropertyInfoBuilder setName(String localName) {
this.localName = localName;
return this;
}
/**
* Set the namespace
*
* @param namespace
* @return
*/
public PropertyInfoBuilder setNamespace(String namespace) {
this.namespace = namespace;
return this;
}
/**
* Set the {@link PropertyType type}
of this property
*
* @param type
* @return this
* @throws IllegalStateException if a property of a different type has been added before.
*/
public PropertyInfoBuilder setType(int type) {
if (values.size() > 0 && type != values.get(0).getType()) {
throw new IllegalStateException("Type mismatch. " +
"Required " + PropertyType.nameFromValue(values.get(0).getType()) +
" found " + PropertyType.nameFromValue(type));
}
this.type = type;
return this;
}
/**
* Add a value
to this property. Sets this property to single valued if
* this is the first value. Otherwise sets this property to multi-valued.
*
* @param value
* @return this
* @throws IllegalStateException if the type of the value does not match the type of this property
*/
public PropertyInfoBuilder addValue(QValue value) {
int actualType = value.getType();
if (type != PropertyType.UNDEFINED && type != actualType) {
throw new IllegalStateException("Type mismatch. " +
"Required " + PropertyType.nameFromValue(type) +
" found " + PropertyType.nameFromValue(value.getType()));
}
values.add(value);
type = actualType;
isMultivalued = values.size() != 1;
return this;
}
/**
* Add a {@link PropertyType#STRING} value to this property.
*
* @param value
* @return this
* @throws RepositoryException
* @throws IllegalStateException if the type of the value does not match the type of this property
*/
public PropertyInfoBuilder addValue(String value) throws RepositoryException {
return addValue(QValueFactoryImpl.getInstance().create(value, PropertyType.STRING));
}
/**
* Add a {@link PropertyType#DATE} value to this property.
*
* @param value
* @return this
* @throws RepositoryException
* @throws IllegalStateException if the type of the value does not match the type of this property
*/
public PropertyInfoBuilder addValue(Calendar value) throws RepositoryException {
return addValue(QValueFactoryImpl.getInstance().create(value));
}
/**
* Add a {@link PropertyType#DOUBLE} value to this property.
*
* @param value
* @return this
* @throws RepositoryException
* @throws IllegalStateException if the type of the value does not match the type of this property
*/
public PropertyInfoBuilder addValue(double value) throws RepositoryException {
return addValue(QValueFactoryImpl.getInstance().create(value));
}
/**
* Add a {@link PropertyType#LONG} value to this property.
*
* @param value
* @return this
* @throws RepositoryException
* @throws IllegalStateException if the type of the value does not match the type of this property
*/
public PropertyInfoBuilder addValue(long value) throws RepositoryException {
return addValue(QValueFactoryImpl.getInstance().create(value));
}
/**
* Add a {@link PropertyType#BOOLEAN} value to this property.
*
* @param value
* @return this
* @throws RepositoryException
* @throws IllegalStateException if the type of the value does not match the type of this property
*/
public PropertyInfoBuilder addValue(boolean value) throws RepositoryException {
return addValue(QValueFactoryImpl.getInstance().create(value));
}
/**
* Add a {@link PropertyType#NAME} value to this property.
*
* @param value
* @return this
* @throws RepositoryException
* @throws IllegalStateException if the type of the value does not match the type of this property
*/
public PropertyInfoBuilder addValue(Name value) throws RepositoryException {
return addValue(QValueFactoryImpl.getInstance().create(value));
}
/**
* Add a {@link PropertyType#PATH} value to this property.
*
* @param value
* @return this
* @throws RepositoryException
* @throws IllegalStateException if the type of the value does not match the type of this property
*/
public PropertyInfoBuilder addValue(Path value) throws RepositoryException {
return addValue(QValueFactoryImpl.getInstance().create(value));
}
/**
* Add a {@link PropertyType#DECIMAL} value to this property.
*
* @param value
* @return this
* @throws RepositoryException
* @throws IllegalStateException if the type of the value does not match the type of this property
*/
public PropertyInfoBuilder addValue(BigDecimal value) throws RepositoryException {
return addValue(QValueFactoryImpl.getInstance().create(value));
}
/**
* Add a {@link PropertyType#URI} value to this property.
*
* @param value
* @return this
* @throws RepositoryException
* @throws IllegalStateException if the type of the value does not match the type of this property
*/
public PropertyInfoBuilder addValue(URI value) throws RepositoryException {
return addValue(QValueFactoryImpl.getInstance().create(value));
}
/**
* Add a {@link PropertyType#BINARY} value to this property.
*
* @param value
* @return this
* @throws RepositoryException
* @throws IllegalStateException if the type of the value does not match the type of this property
*/
public PropertyInfoBuilder addValue(byte[] value) throws RepositoryException {
return addValue(QValueFactoryImpl.getInstance().create(value));
}
/**
* Add a {@link PropertyType#BINARY} value to this property.
*
* @param value
* @return this
* @throws RepositoryException
* @throws IllegalStateException if the type of the value does not match the type of this property
*/
public PropertyInfoBuilder addValue(InputStream value) throws RepositoryException, IOException {
return addValue(QValueFactoryImpl.getInstance().create(value));
}
/**
* Add a {@link PropertyType#BINARY} value to this property.
*
* @param value
* @return this
* @throws RepositoryException
* @throws IllegalStateException if the type of the value does not match the type of this property
*/
public PropertyInfoBuilder addValue(File value) throws RepositoryException, IOException {
return addValue(QValueFactoryImpl.getInstance().create(value));
}
/**
* Set this property to multi-values.
*
* @param on
* @return this
* @throws IllegalStateException if this property does not contain exactly on value
*/
public PropertyInfoBuilder setMultivalued(boolean on) {
if (!on && values.size() != 1) {
throw new IllegalStateException(
"Cannot create single valued property when multiple values are present");
}
isMultivalued = true;
return this;
}
/**
* Build the {@link PropertyInfo}. If a {@link Listener} is associated with this
* instance, then its {@link Listener#createPropertyInfo(PropertyInfo)} methods
* is called.
*
* @return the parent builder of this builder
* @throws RepositoryException
* @throws IllegalStateException if build has been called before
* @throws IllegalStateException if the type is not set
*/
public NodeInfoBuilder build() throws RepositoryException {
if (stale) {
throw new IllegalStateException("Builder is stale");
}
else if (type == PropertyType.UNDEFINED) {
throw new IllegalStateException("Type not set");
}
else if (localName == null && name == null) {
throw new IllegalStateException("Name not set");
}
else {
stale = true;
NodeId parentId = parent.getId();
if (name == null) {
String ns = namespace == null ? Name.NS_DEFAULT_URI : namespace;
name = NameFactoryImpl.getInstance().create(ns, localName);
}
Path path = PathFactoryImpl.getInstance().create(parent.getPath(), name, true);
PropertyId id = IdFactoryImpl.getInstance().createPropertyId(parentId, name);
propertyInfo = new PropertyInfoImpl(path, id, type, isMultivalued,
values.toArray(new QValue[values.size()]));
if (listener != null) {
listener.createPropertyInfo(propertyInfo);
}
return parent.addPropertyInfo(propertyInfo);
}
}
/**
* @return the parent builder of this builder
*/
public NodeInfoBuilder getParent() {
return parent;
}
/**
* Returns the {@link PropertyInfo} which has been built by this builder.
*
* @return
* @throws IllegalStateException if {@link #build()} has not been called before.
*/
public PropertyInfo getPropertyInfo() {
if (!stale) {
throw new IllegalStateException("PropertyInfo not built yet");
}
return propertyInfo;
}
}
}