/*******************************************************************************
* Copyright (c) 2015 ARM Ltd. and others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* ARM Ltd and ARM Germany GmbH - Initial API and implementation
*******************************************************************************/
package com.arm.cmsis.pack.generic;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import com.arm.cmsis.pack.common.CmsisConstants;
import com.arm.cmsis.pack.utils.WildCards;
/**
* Default implementation of IAttributes interface
*/
public class Attributes implements IAttributes {
protected Map<String, String> fAttributes = null;
/**
* Default constructor
*/
public Attributes() {
}
/**
* Copy constructor
* @param copyFrom
*/
public Attributes(final IAttributes copyFrom) {
setAttributes(copyFrom.getAttributesAsMap());
}
@Override
synchronized public boolean hasAttribute(String key) {
return fAttributes != null && fAttributes.containsKey(key);
}
@Override
synchronized public String getAttribute(String key) {
if(fAttributes != null) {
return fAttributes.get(key);
}
return null;
}
@Override
synchronized public String getAttribute(String key, String defaultValue) {
String value = getAttribute(key);
if(value != null) {
return value;
}
return defaultValue;
}
@Override
public int getAttributeAsInt(String key, int nDefault) {
String value = getAttribute(key);
if(value != null && !value.isEmpty()) {
try {
return Integer.decode(value);
} catch (NumberFormatException e) {
// do nothing, return default
}
}
return nDefault;
}
@Override
public long getAttributeAsLong(String key, long nDefault) {
String value = getAttribute(key);
if(value != null && !value.isEmpty()) {
try {
return Long.decode(value);
} catch (NumberFormatException e) {
// do nothing, return default
}
}
return nDefault;
}
@Override
public boolean getAttributeAsBoolean(String key, boolean bDefault) {
String value = getAttribute(key);
if(value != null && !value.isEmpty()) {
if(value.equals("1") || value.toLowerCase().equals("true")) { //$NON-NLS-1$ //$NON-NLS-2$
return true;
}
return false;
}
return bDefault;
}
@Override
synchronized public void setAttribute(String key, String value) {
if(key == null) {
return;
}
if(fAttributes == null) {
fAttributes = new TreeMap<String, String>(); // use natural sorting to get consistent string representation
}
if(value != null) {
fAttributes.put(key, value);
} else if(fAttributes != null) {
fAttributes.remove(key);
}
}
@Override
public void setAttribute(String key, boolean value) {
setAttribute(key, value ? "1" : "0"); //$NON-NLS-1$ //$NON-NLS-2$
}
@Override
public void setAttribute(String key, int value) {
setAttribute(key, Integer.toString(value));
}
@Override
synchronized public void removeAttribute(String key) {
if(fAttributes != null ) {
fAttributes.remove(key);
}
}
@Override
synchronized public void mergeAttribute(String key, String value) {
if(!hasAttribute(key)) {
setAttribute(key, value);
}
}
@Override
synchronized public boolean hasAttributes() {
return fAttributes != null && !fAttributes.isEmpty();
}
@Override
synchronized public Map<String, String> getAttributesAsMap() {
return fAttributes;
}
@Override
synchronized public void setAttributes(Map<String, String> attributes) {
if(attributes == null) {
fAttributes = null;
} else {
// make copy
fAttributes = new TreeMap<String, String>();
fAttributes.putAll(attributes);
}
}
@Override
public void setAttributes(String attributesString) {
fAttributes = splitString(attributesString);
}
@Override
synchronized public void setAttributes(IAttributes attributes) {
if(attributes != null && attributes.hasAttributes()) {
setAttributes(attributes.getAttributesAsMap());
} else {
fAttributes = null;
}
}
@Override
synchronized public void mergeAttributes(final IAttributes attributes) {
if(attributes == null || !attributes.hasAttributes()) {
return; // nothing to merge
}
Map<String, String> attributesMap = attributes.getAttributesAsMap();
if(fAttributes == null) {
setAttributes(attributesMap);
}
for(Entry<String, String> e: attributesMap.entrySet()) {
mergeAttribute(e.getKey(), e.getValue());
}
}
@Override
synchronized public void mergeAttributes(final IAttributes attributes, final String prefix) {
if(attributes == null || !attributes.hasAttributes()) {
return; // nothing to merge
}
Map<String, String> attributesMap = attributes.getAttributesAsMap();
for(Entry<String, String> e: attributesMap.entrySet()) {
String key = e.getKey();
if(key.startsWith(prefix)) {
mergeAttribute(key, e.getValue());
}
}
}
@Override
synchronized public boolean containsAttribute(String pattern) {
if(fAttributes == null) {
return false;
}
for(String key : fAttributes.keySet()){
if(WildCards.match(pattern, key)) {
return true;
}
}
return false;
}
@Override
public boolean matchAttributes(final IAttributes attributes) {
return matchAttributes(attributes, null, false);
}
@Override
public boolean matchAttributes(final IAttributes attributes, String prefix) {
return matchAttributes(attributes, prefix, false);
}
@Override
public boolean matchCommonAttributes(final IAttributes attributes) {
return matchAttributes(attributes, null, true);
}
@Override
public boolean matchCommonAttributes(final IAttributes attributes, String prefix) {
return matchAttributes(attributes, prefix, true);
}
/**
* Checks if attributes found in this element and supplied map match
* using wild card match
* @param attributes to match to
* @param prefix if not null or empty - match only attributes with that prefix
* @param bCommon match mode: true - compare only attributes found in both maps, false - match all
* @return true if matches, false otherwise
*/
protected boolean matchAttributes(final IAttributes attributes, String prefix, boolean bCommon){
if(attributes == null) {
return fAttributes == null || fAttributes.isEmpty();
}
for(Entry<String, String> e : fAttributes.entrySet()){
String key = e.getKey();
if(prefix != null && !prefix.isEmpty()) {
if(!key.startsWith(prefix)) {
continue;
}
}
String val = e.getValue();
String pattern = attributes.getAttribute(key);
if(pattern == null) {
if(bCommon) {
continue;
}
return false;
}
if(!matchAttribute(key, val, pattern)) {
return false;
}
}
return true;
}
@Override
public boolean matchAttribute(String key, String value, String pattern) {
return WildCards.match(pattern, value);
}
@Override
public boolean containsValue(String value) {
if(fAttributes == null || fAttributes.isEmpty()) {
return false;
}
return fAttributes.containsValue(value);
}
@Override
public boolean containsValuePattern(String pattern) {
if(pattern == null || fAttributes == null || fAttributes.isEmpty()) {
return false;
}
for(Entry<String, String> e : fAttributes.entrySet()){
String key = e.getKey();
String val = e.getValue();
if(matchAttribute(key, val, pattern)) {
return true;
}
}
return false;
}
@Override
public String getUrl() {
return getAttribute(CmsisConstants.URL);
}
@Override
public String getDoc() {
return getAttribute(CmsisConstants.DOC);
}
@Override
public boolean equals(Object obj) {
if(obj instanceof IAttributes) {
IAttributes other = (IAttributes)obj;
return other.toString().equals(toString());
}
return super.equals(obj);
}
@Override
public int hashCode() {
return toString().hashCode();
}
@Override
public String toString() {
return getAttributesAsString();
}
/**
* Returns string containing all attributes in the form "key0"="value0", "key1"=value1,...
* @return string containing keys and values of all attributes
*/
synchronized public String getAttributesAsString() {
String s = CmsisConstants.EMPTY_STRING;
if(hasAttributes()) {
for(Entry<String, String> e : fAttributes.entrySet()){
if(!s.isEmpty())
{
s += ", "; //$NON-NLS-1$
}
s += e.getKey();
s += "=\""; //$NON-NLS-1$
s += e.getValue();
s += "\""; //$NON-NLS-1$
}
}
return s;
}
/**
* Splits given string into key-value pairs
* @return string containing keys and values in the form <code>key1="value1", key2="vaule2", ...</code>
*/
static public Map<String, String> splitString(String attributesString) {
if (attributesString == null || attributesString.isEmpty()) {
return null;
}
String[] pairs = attributesString.split("\\\","); //$NON-NLS-1$
if (pairs == null || pairs.length == 0) {
return null;
}
Map<String, String> attributes = new TreeMap<String, String>();
for (String p : pairs) {
String[] pair = p.split("=\\\""); //$NON-NLS-1$
if (pair == null || pair.length != 2) {
continue;
}
String key = pair[0].trim();
String val = pair[1].trim();
if (val.endsWith("\"")) { //$NON-NLS-1$
val = val.substring(0, val.length() - 1);
}
attributes.put(key, val);
}
return attributes;
}
}