/* Copyright (C) 2009 Mobile Sorcery AB
This program is free software; you can redistribute it and/or modify it
under the terms of the Eclipse Public License v1.0.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the Eclipse Public License v1.0 for
more details.
You should have received a copy of the Eclipse Public License v1.0 along
with this program. It is also available at http://www.eclipse.org/legal/epl-v10.html
*/
package com.mobilesorcery.sdk.core;
import java.util.Map;
import java.util.TreeMap;
/**
* <p>A 'namespace' property owner, where all property keys are suffixed
* with a namespace using the / character.<p>
* <p>Namespaces have a natural
* hierarchy - the value for key <code>property/overridden</code>
* will first be found using the exact key, <code>property/overridden</code>.
* If no value is found, <code>property</code> will be used as a key. If
* still no value is found, the same procedure is repeated with default values.
* </p>
* <p>
* Likewise, the key <code>property/overridden/overriddenagain</code> will
* potentially use an additional lookup.
* <emph>TODO: Use something like CascadingProperties instead, much less bookkeeping!!</emph>
* @author Mattias Bybro
*
*/
public class NameSpacePropertyOwner extends PropertyOwnerBase implements IPropertyOwner {
private final IPropertyOwner parent;
private final String[] namespace;
private final int levels;
private final String fullNamespace;
public NameSpacePropertyOwner(IPropertyOwner parent, String namespace) {
this.parent = parent;
this.namespace = namespace.split("/");
this.fullNamespace = namespace;
this.levels = this.namespace.length;
}
public String getNamespace() {
return fullNamespace;
}
private String assembleFullKey(String key, int level) {
return assembleFullKeys(key)[level];
}
private String[] assembleFullKeys(String key) {
String[] result = new String[levels + 1];
StringBuffer buffer = new StringBuffer(key);
result[0] = buffer.toString();
for (int i = 0; i < levels; i++) {
buffer.append('/');
buffer.append(namespace[i]);
result[i + 1] = buffer.toString();
}
return result;
}
@Override
public String getContext() {
return parent.getContext();
}
@Override
public String getDefaultProperty(String key) {
String[] fullKeys = assembleFullKeys(key);
for (int i = 0; i < levels + 1; i++) {
String prop = parent.getDefaultProperty(fullKeys[levels - i]);
if (prop != null) {
return prop;
}
}
return null;
}
@Override
public String getProperty(String key) {
String[] fullKeys = assembleFullKeys(key);
for (int i = 0; i < levels + 1; i++) {
String prop = parent.getProperty(fullKeys[levels - i]);
if (prop != null) {
return prop;
}
}
return null;
}
@Override
public void initProperty(String key, String value) {
parent.initProperty(assembleFullKey(key, levels), value);
}
@Override
public boolean setProperty(String key, String value) {
if (equals(getProperty(key), value)) {
return false;
} else {
return parent.setProperty(assembleFullKey(key, levels), value);
}
}
public static boolean equals(String oldValue, String value) {
if (oldValue == null) {
return value == null;
}
return oldValue.equals(value);
}
/**
* Returns the key part of a namespaced key
* @param key
* @param fullKey
* @return
*/
public static String getKey(String key) {
String[] parts = key.split("/", 2);
if (parts.length == 0) {
return "";
} else {
return parts[0];
}
}
public static String[] getNamespace(String key) {
String[] parts = key.split("/");
if (parts.length == 1) {
return new String[] { "" };
} else {
String[] result = new String[parts.length - 1];
System.arraycopy(parts, 1, result, 0, result.length);
return result;
}
}
public static String getFullNamespace(String key) {
String[] parts = key.split("/", 2);
if (parts.length == 1) {
return "";
} else {
return parts[1];
}
}
public Map<String, String> getProperties(String fullNamespace) {
TreeMap<String, String> result = new TreeMap<String, String>();
Map<String, String> parentProperties = parent.getProperties();
for (String key : parentProperties.keySet()) {
if (fullNamespace.equals(getFullNamespace(key))) {
result.put(getKey(key), parentProperties.get(key));
}
}
return result;
}
@Override
public Map<String, String> getProperties() {
Map<String, String> result = parent.getProperties();
result.putAll(getProperties(fullNamespace));
return result;
}
/**
* Clears all properties with this namespace from the parent.
*/
public void clear() {
// A tad slow, but this method is rarely used.
Map<String, String> properties = getProperties(fullNamespace);
for (String key : properties.keySet()) {
setProperty(key, null);
}
}
@Override
public boolean isDefault(String key) {
String[] fullKeys = assembleFullKeys(key);
for (int i = 0; i < levels + 1; i++) {
boolean isDefault = parent.isDefault(fullKeys[levels - i]);
if (!isDefault) {
return false;
}
}
return true;
}
}