blob: 9eb4fc6d81c81fd5287c266585eee0d9f6ee88df [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.sling.jcr.resource;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import org.apache.sling.api.resource.PersistableValueMap;
import org.apache.sling.api.resource.PersistenceException;
import org.apache.sling.jcr.resource.internal.NodeUtil;
import org.apache.sling.jcr.resource.internal.helper.JcrPropertyMapCacheEntry;
import org.slf4j.LoggerFactory;
/**
* This implementation of the value map allows to change
* the properties and save them later on.
*
* @deprecated Resources should be adapted to a modifiable value map instead
*/
@SuppressWarnings("deprecation")
@Deprecated
public final class JcrModifiablePropertyMap
extends JcrPropertyMap
implements PersistableValueMap {
private static volatile boolean LOG_DEPRECATED = true;
/** Set of removed and changed properties. */
private Set<String> changedProperties;
/**
* Constructor
* @param node The underlying node.
*/
public JcrModifiablePropertyMap(final Node node) {
super(node);
if ( LOG_DEPRECATED ) {
LOG_DEPRECATED = false;
LoggerFactory.getLogger(this.getClass()).warn("DEPRECATION WARNING: JcrModifiablePropertyMap is deprecated. Please switch to resource API.");
}
}
/**
* Constructor
* @param node The underlying node.
* @param dynamicCL Dynamic class loader for loading serialized objects.
* @since 2.0.6
*/
public JcrModifiablePropertyMap(final Node node, final ClassLoader dynamicCL) {
super(node, dynamicCL);
if ( LOG_DEPRECATED ) {
LOG_DEPRECATED = false;
LoggerFactory.getLogger(this.getClass()).warn("DEPRECATION WARNING: JcrModifiablePropertyMap is deprecated. Please switch to resource API.");
}
}
// ---------- Map
/**
* @see java.util.Map#clear()
*/
@Override
public void clear() {
// we have to read all properties first
this.readFully();
if ( this.changedProperties == null ) {
this.changedProperties = new HashSet<String>();
}
this.changedProperties.addAll(this.cache.keySet());
this.cache.clear();
this.valueCache.clear();
}
/**
* @see java.util.Map#put(java.lang.Object, java.lang.Object)
*/
@Override
public Object put(String aKey, Object value) {
final String key = checkKey(aKey);
if ( key.indexOf('/') != -1 ) {
throw new IllegalArgumentException("Invalid key: " + key);
}
if ( value == null ) {
throw new NullPointerException("Value should not be null (key = " + key + ")");
}
readFully();
final Object oldValue = this.get(key);
try {
this.cache.put(key, new JcrPropertyMapCacheEntry(value, this.getNode()));
} catch (final RepositoryException re) {
throw new IllegalArgumentException("Value for key " + key + " can't be put into node: " + value, re);
}
this.valueCache.put(key, value);
if ( this.changedProperties == null ) {
this.changedProperties = new HashSet<String>();
}
this.changedProperties.add(key);
return oldValue;
}
/**
* @see java.util.Map#putAll(java.util.Map)
*/
@Override
public void putAll(Map<? extends String, ? extends Object> t) {
readFully();
if ( t != null ) {
final Iterator<?> i = t.entrySet().iterator();
while (i.hasNext() ) {
@SuppressWarnings("unchecked")
final Map.Entry<? extends String, ? extends Object> entry = (Map.Entry<? extends String, ? extends Object>) i.next();
put(entry.getKey(), entry.getValue());
}
}
}
/**
* @see java.util.Map#remove(java.lang.Object)
*/
@Override
public Object remove(Object aKey) {
final String key = checkKey(aKey.toString());
readFully();
final Object oldValue = this.cache.remove(key);
this.valueCache.remove(key);
if ( this.changedProperties == null ) {
this.changedProperties = new HashSet<String>();
}
this.changedProperties.add(key);
return oldValue;
}
/**
* @see org.apache.sling.api.resource.PersistableValueMap#reset()
*/
@Override
public void reset() {
if ( this.changedProperties != null ) {
this.changedProperties = null;
}
this.cache.clear();
this.valueCache.clear();
this.fullyRead = false;
}
/**
* @see org.apache.sling.api.resource.PersistableValueMap#save()
*/
@Override
@SuppressWarnings("javadoc")
public void save() throws PersistenceException {
if ( this.changedProperties == null || this.changedProperties.size() == 0 ) {
// nothing has changed
return;
}
try {
final Node node = getNode();
// check for mixin types
if ( this.changedProperties.contains(NodeUtil.MIXIN_TYPES) ) {
if ( cache.containsKey(NodeUtil.MIXIN_TYPES) ) {
final JcrPropertyMapCacheEntry entry = cache.get(NodeUtil.MIXIN_TYPES);
NodeUtil.handleMixinTypes(node, entry.convertToType(String[].class, node, getDynamicClassLoader()));
} else {
// remove all mixin types!
NodeUtil.handleMixinTypes(node, null);
}
}
for(final String key : this.changedProperties) {
final String name = escapeKeyName(key);
if ( !NodeUtil.MIXIN_TYPES.equals(name) ) {
if ( cache.containsKey(key) ) {
final JcrPropertyMapCacheEntry entry = cache.get(key);
if ( entry.isArray() ) {
node.setProperty(name, entry.convertToType(Value[].class, node, getDynamicClassLoader()));
} else {
node.setProperty(name, entry.convertToType(Value.class, node, getDynamicClassLoader()));
}
} else {
if ( node.hasProperty(name) ) {
node.getProperty(name).remove();
}
}
}
}
node.getSession().save();
this.reset();
} catch (final RepositoryException re) {
throw new PersistenceException("Unable to persist changes.", re, getPath(), null);
}
}
}