de.tsl2.nano.bean.Context Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of tsl2.nano.descriptor Show documentation
Show all versions of tsl2.nano.descriptor Show documentation
TSL2 Framework Descriptor (currency-handling, generic formatter, descriptors for beans, collections, actions and values)
/*
* File: $HeadURL$
* Id : $Id$
*
* created by: Thomas Schneider
* created on: Dec 20, 2012
*
* Copyright: (c) Thomas Schneider 2012, all rights reserved
*/
package de.tsl2.nano.bean;
import java.io.File;
import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import org.apache.commons.logging.Log;
import org.simpleframework.xml.Attribute;
import org.simpleframework.xml.Default;
import org.simpleframework.xml.DefaultType;
import org.simpleframework.xml.ElementMap;
import de.tsl2.nano.bean.def.BeanDefinition;
import de.tsl2.nano.collection.CollectionUtil;
import de.tsl2.nano.core.ENV;
import de.tsl2.nano.core.IPredicate;
import de.tsl2.nano.core.ITransformer;
import de.tsl2.nano.core.ManagedException;
import de.tsl2.nano.core.cls.AReference;
import de.tsl2.nano.core.cls.BeanClass;
import de.tsl2.nano.core.log.LogFactory;
import de.tsl2.nano.core.serialize.XmlUtil;
import de.tsl2.nano.core.util.FileUtil;
import de.tsl2.nano.core.util.StringUtil;
/**
* persistable context. avoids serializing entities (mostly having a tree of dependencies) directly - using
* {@link BReference} to reference entities through their ids.
*
* @author Thomas Schneider
* @version $Revision$
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
@Default(value = DefaultType.FIELD, required = false)
public class Context implements Serializable, Map {
/** serialVersionUID */
private static final long serialVersionUID = -5738577461481485970L;
private static final Log LOG = LogFactory.getLog(Context.class);
@Attribute
String name;
@ElementMap(entry = "property", key = "name", attribute = true, inline = true, required = false, keyType = String.class, valueType = Object.class)
private TreeMap properties;
/** if true, this context will be persisted on any change. */
transient boolean autopersist = false;
/**
* creates a new instance from file or through constructor
*
* @param name context name, used as filename on persisting to file system
* @param autoPersist whether to persist this context on each change. if name is null, no persisting will be done.
* @return new context instance
*/
public static Context create(String name, boolean autoPersist) {
Context context = null;
if (name == null) {
context = new Context();
autoPersist = false;
} else {
String fname = getFileName(name);
File file = new File(fname);
if (file.exists()) {
LOG.debug("loading Context for '" + name + "'");
context = XmlUtil.loadXml(file.getPath(), Context.class);
} else {
LOG.debug("creating new Context for '" + name + "' (file: " + fname + ")");
context = new Context(name);
}
}
context.init(autoPersist);
return context;
}
/**
* init
*
* @param context
* @param autoPersist
*/
protected void init(boolean autoPersist) {
if (properties == null)
properties = new TreeMap();
this.autopersist = autoPersist;
}
protected Context() {
this(null);
}
protected Context(String name) {
this.name = name;
}
/**
* {@inheritDoc}
*/
@Override
public int size() {
return properties.size();
}
/**
* {@inheritDoc}
*/
@Override
public boolean isEmpty() {
return properties.isEmpty();
}
/**
* {@inheritDoc}
*/
@Override
public boolean containsKey(Object key) {
return properties.containsKey(key);
}
/**
* {@inheritDoc}
*/
@Override
public boolean containsValue(Object value) {
return properties.containsValue(value);
}
/**
* {@inheritDoc}
*/
@Override
public Object get(Object key) {
return properties.get(key);
}
public Object add(Object obj) {
String k = BeanClass.getDefiningClass(obj.getClass()).getName();//String.valueOf(obj.hashCode());
put(k, obj);
return k;
}
/**
* {@inheritDoc}
*/
@Override
public Object put(Object key, Object value) {
Object result = properties.put(key, reference(value));
if (autopersist) {
try {
save();
} catch (Exception e) {
properties.remove(key);
LOG.error(key + " cannot be serialized, so will not be stored in the context " + this);
ManagedException.forward(e);
}
}
return result;
}
protected Object reference(Object value) {
return value != null && BeanContainer.instance().isPersistable(BeanClass.getDefiningClass(value.getClass()))
? new BReference(value) : value;
}
/**
* {@inheritDoc}
*/
@Override
public Object remove(Object key) {
Object result = properties.remove(key);
if (autopersist) {
save();
}
return result;
}
/**
* {@inheritDoc}
*/
@Override
public void putAll(Map m) {
properties.putAll(m);
if (autopersist) {
save();
}
}
/**
* {@inheritDoc}
*/
@Override
public Set keySet() {
return properties.keySet();
}
/**
* {@inheritDoc}
*/
@Override
public Collection values() {
return properties.values();
}
/**
* {@inheritDoc}
*/
@Override
public Set entrySet() {
return properties.entrySet();
}
/**
* resets the current environment to be empty
*/
public void clear() {
properties.clear();
if (autopersist) {
save();
}
}
/**
* if no value was found for given key, the defaultValue will be put to the map and returned
*
* @param key
* @param defaultValue
* @return map value or defaultValue
*/
public T get(String key, T defaultValue) {
T value = (T) materialize(properties.get(key));
if (value == null && defaultValue != null) {
value = defaultValue;
put(key, value);
}
return value;
}
protected Object materialize(Object obj) {
return obj instanceof AReference ? ((AReference) obj).resolve() : obj;
}
/**
* filters only values of valueType to be returned in a filtered iterator. if there are persistable entities, they
* are wrapped into {@link BReference} - so, these references can be collected giving a valueType =
* BReference.class.
*
* @param valueType any type to be collected from current context.
* @return filtered map values
*/
public Iterator get(final Class valueType) {
return CollectionUtil.getTransforming(properties.values(), new ITransformer