package org.etk.orm.plugins.mapper.property;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import javax.jcr.Property;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import org.etk.orm.api.UndeclaredRepositoryException;
import org.etk.orm.core.EntityContext;
import org.etk.orm.core.ListType;
import org.etk.orm.plugins.bean.ValueKind;
import org.etk.orm.plugins.common.JCR;
import org.etk.orm.plugins.common.collection.AbstractFilterIterator;
class PropertyMap extends AbstractMap<String, Object> {
/** . */
private final JCRPropertyDetypedPropertyMapper mapper;
/** . */
private final EntityContext ctx;
/** . */
private SetImpl set;
PropertyMap(JCRPropertyDetypedPropertyMapper mapper, EntityContext ctx) {
this.ctx = ctx;
this.mapper = mapper;
this.set = null;
}
public Set<Entry<String, Object>> entrySet() {
if (set == null) {
set = new SetImpl();
}
return set;
}
@Override
public Object get(Object key) {
String s = validateKey(key);
if (s != null) {
try {
if (mapper.valueKind == ValueKind.SINGLE) {
return ctx.getPropertyValue(s, null);
} else {
return ctx.getPropertyValues(s, null, ListType.LIST);
}
}
catch (RepositoryException e) {
throw new UndeclaredRepositoryException(e);
}
} else {
return null;
}
}
@Override
public Object remove(Object key) {
String s = validateKey(key);
if (s != null) {
return put(s, null);
} else {
return null;
}
}
@Override
public Object put(String key, Object value) {
String s = validateKey(key);
if (s != null) {
return update(key, value);
} else {
throw new IllegalArgumentException("Invalid key " + key + " should being with the prefix " + mapper.namePrefix);
}
}
private String validateKey(Object key) {
if (key == null) {
throw new NullPointerException("Key cannot be null");
}
if (key instanceof String) {
String s = (String)key;
if (mapper.namePrefix != null) {
return mapper.namePrefix + s;
} else {
return s;
}
} else {
throw new ClassCastException("Key must be instance of String instead of " + key.getClass().getName());
}
}
private Object update(String key, Object value) {
try {
Object previous;
if (mapper.valueKind == ValueKind.SINGLE) {
previous = ctx.getPropertyValue(key, null);
ctx.setPropertyValue(key, null, value);
} else {
List<?> list = (List<?>)value;
previous = ctx.getPropertyValues(key, null, ListType.LIST);
ctx.setPropertyValues(key, null, ListType.LIST, list);
}
return previous;
}
catch (RepositoryException e) {
throw new UndeclaredRepositoryException(e);
}
}
private class SetImpl extends AbstractSet<Map.Entry<String, Object>> {
public Iterator<Map.Entry<String, Object>> iterator() {
try {
Iterator<Property> i;
if (mapper.namePattern == null) {
i = JCR.adapt(ctx.getNode().getProperties());
} else {
i = JCR.adapt(ctx.getNode().getProperties(mapper.namePattern));
}
//
return new AbstractFilterIterator<Entry<String, Object>, Property>(i) {
@Override
protected Entry<String, Object> adapt(Property internal) {
try {
// todo : that does not respect the encoding of property names but
// that is not much important for now as it is an unsupported feature
// todo : support for default values is not done because
// we pass null as the SimpleValueInfo type parameter
//
final String key = internal.getName();
//
final String name = mapper.namePrefix != null ? key.substring(mapper.namePrefix.length()) : key;
//
if ("*".equals(internal.getDefinition().getName())) {
switch (internal.getType()) {
case PropertyType.STRING:
case PropertyType.NAME:
case PropertyType.LONG:
case PropertyType.BOOLEAN:
{
return new Entry<String, Object>() {
public String getKey() {
return name;
}
public Object getValue() {
return get(key);
}
public Object setValue(Object value) {
throw new UnsupportedOperationException();
}
};
}
}
}
//
return null;
}
catch (RepositoryException e) {
throw new UndeclaredRepositoryException(e);
}
}
};
}
catch (RepositoryException e) {
throw new UndeclaredRepositoryException(e);
}
}
public int size() {
int count = 0;
Iterator<Map.Entry<String, Object>> iterator = iterator();
while (iterator.hasNext()) {
iterator.next();
count++;
}
return count;
}
}
}