/**
* $Id: $
* $Date: $
*
*/
package org.xmlsh.types.xtypes;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.xmlsh.core.InvalidArgumentException;
import org.xmlsh.core.XStringLookup;
import org.xmlsh.core.XStringSubstituter;
import org.xmlsh.core.XValue;
import org.xmlsh.types.TypeFamily;
/*
*
* Generic Properties
* A set of Name/Value pairs to any object
*/
public class XValueProperties extends XValueMap {
public XValueProperties(Map<?, ?> map) throws InvalidArgumentException {
for (Map.Entry<?, ?> e : map.entrySet()) {
super.put(e.getKey().toString(), XValue.newXValue(e.getValue()));
}
}
public XValueProperties() {
super();
}
public XValueProperties(XValueProperty prop) {
super();
add(prop);
}
public XValueProperties(List<XValueProperty> list) {
for (XValueProperty p : list)
add(p);
}
public static XValueProperties fromMap(Map<?, ?> map) throws InvalidArgumentException {
return new XValueProperties(map);
};
public static XValueProperties fromJavaProperties(Properties props) {
final XValueProperties xp = new XValueProperties();
props.stringPropertyNames().forEach( (s) -> xp.put( s , props.getProperty(s) ));
return xp;
};
public static XValueProperties fromProperty(XValueProperty prop) {
return new XValueProperties(prop);
}
public static XValueProperties fromPropertyList(List<XValueProperty> list) {
return new XValueProperties(list);
}
@Override
public XValue asXValue() throws InvalidArgumentException {
return XValue.newXValue(TypeFamily.XTYPE, this);
}
/*
* Expand properties to set of nested properties based on a delimiter
public XValueProperties expandTree(String delim) throws InvalidArgumentException {
XValueProperties tree = new XValueProperties();
Set<String> keySet = keySet();
Set<String> nested = nestedKeys(keySet, delim);
if (nested.isEmpty()) {
tree.addAll(this);
return tree;
}
List<String> rootKeys = topLevelKeys(keySet, delim);
for (String key : rootKeys)
tree.put(key, get(key));
for (String key : nested) {
XValueProperties nestedProps = nestedProperties(keySet, key, delim);
if (nestedProps != null)
tree.put(key, nestedProps);
}
return tree;
}
// Create a new property with only keys nested under the parent
private XValueProperties nestedProperties(Set<String> keySet, String parent, String delim) throws InvalidArgumentException {
System.out.println("nestedProperties: parent: " + parent);
// Create a new Properties object by filtering out only keys starting with parent.
XValueProperties nested = new XValueProperties();
String parentKey = parent + delim;
int parentLen = parentKey.length();
for (String key : keySet) {
if (key.startsWith(parentKey)) {
String childKey = key.substring(parentLen);
XValue value = get(key);
nested.put(childKey, value);
if (childKey.contains(delim)) {
XValueProperties childProps = nestedProperties(keySet, childKey, delim);
if (childProps != null)
nested.put(childKey, childProps.asXValue());
} else
nested.put(childKey, value);
}
}
if (nested.isEmpty())
return null;
return nested.expandTree(delim);
}
// Return all unique keys that start with a common prefix , stripping off any child suffexes
private static Set<String> nestedKeys(Set<String> keys, String delim) {
Set<String> nestedKeys = new HashSet<String>();
for (String key : keys) {
// many identical prefixes allowed one key per name so dont need to find dups
int dpos = key.indexOf(delim);
if (dpos > 0)
nestedKeys.add(key.substring(0, dpos));
}
return nestedKeys;
}
private static List<String> topLevelKeys(Set<String> keys, String delim) {
List<String> topKeys = new ArrayList<String>();
for (String key : keys) {
// only alllowed one key per name so dont need to find dups
if (!key.contains(delim))
topKeys.add(key);
}
return topKeys;
}
****/
/*
* Merge these properties with that, recursively
* return a merged set where any property in that overwrites the property in this
*/
public XValueProperties merge(XValueProperties that) throws InvalidArgumentException {
if (isEmpty())
return that;
// Copy this to merged
XValueProperties merged = new XValueProperties(this);
Set<java.util.Map.Entry<String, XValue>> entries = that.entrySet();
for (java.util.Map.Entry<String, XValue> e : entries) {
XValue thatx = e.getValue();
// Nothing in this - put it in
String key = e.getKey();
if (!merged.containsKey(key))
merged.put(e);
else {
XValue thisx = get(key);
assert (thisx != null);
// Both are nested properties, merge
if (thisx.isInstanceOf(XValueProperties.class) && thatx.isInstanceOf(XValueProperties.class)) {
XValueProperties thatp = thatx.asInstanceOf(XValueProperties.class);
XValueProperties thisp = thisx.asInstanceOf(XValueProperties.class);
merged.put(key, thisp.merge(thatp));
} else
merged.put(key, thatx);
}
}
return merged;
}
public static class XPropertiesLookup extends XStringLookup {
XValueProperties mProps ;
/**
* @param xValueProperties
* @param lookup
*/
public XPropertiesLookup(XValueProperties props, XStringLookup parent) {
super(parent);
mProps = props;
}
@Override
protected XValue lookupXValue(String value) {
return mProps.get( value );
}
}
public XValueProperties replaceVariables(final XStringLookup lookup) {
XStringSubstituter subst = new XStringSubstituter(getLookup(lookup));
XValueProperties that = new XValueProperties();
for (java.util.Map.Entry<String, XValue> e : entrySet()) {
XValue v = e.getValue();
XValue vnew = v.substitute(subst);
that.put( e.getKey() , vnew );
}
return that ;
}
public XPropertiesLookup getLookup(final XStringLookup lookup) {
return new XPropertiesLookup(this, lookup);
}
public static XValueProperties fromXValue(XValue xv) throws InvalidArgumentException {
return fromXValues(Collections.singletonList(xv));
}
public static XValueProperties fromXValues(List<XValue> args) throws InvalidArgumentException {
XValueProperties props = null;
for (XValue xarg : args) {
for (XValue arg : xarg) {
if (props == null) {
if (arg.isInstanceOf(XValueProperties.class))
props = arg.asInstanceOf(XValueProperties.class);
else if (arg.isInstanceOf(Map.class))
props = fromMap(arg.asInstanceOf(Map.class));
else if (arg.isInstanceOf(XValueProperty.class))
props = new XValueProperties(arg.asInstanceOf(XValueProperty.class));
else if (arg.isInstanceOf(IXValueMap.class)) {
props = new XValueProperties((Map<?, ?>) arg.asInstanceOf(IXValueMap.class));
}
} else {
if (arg.isInstanceOf(XValueProperties.class))
props = props.merge(arg.asInstanceOf(XValueProperties.class));
else if (arg.isInstanceOf(Map.class))
props = props.merge(fromMap(arg.asInstanceOf(Map.class)));
else if (arg.isInstanceOf(XValueProperty.class))
props.add(arg.asInstanceOf(XValueProperty.class));
else if (arg.isInstanceOf(IXValueMap.class)) {
props = props.merge(fromMap((Map<?, ?>) arg.asInstanceOf(IXValueMap.class)));
} else {
}
}
}
}
return props;
}
public XValue getProperty(String name) {
return get( name );
}
}
/*
* Copyright (C) 2008-2012 David A. Lee.
*
* The contents of this file are subject to the "Simplified BSD License" (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.opensource.org/licenses/bsd-license.php
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights and limitations under the License.
*
* The Original Code is: all this file.
*
* The Initial Developer of the Original Code is David A. Lee
*
* Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
*
* Contributor(s): David A. Lee
*/