/*******************************************************************************
* Copyright (c) 2010-2014 SAP AG 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:
* SAP AG - initial API and implementation
*******************************************************************************/
package org.eclipse.skalli.services.extension;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.text.StrLookup;
import org.eclipse.skalli.commons.CollectionUtils;
import org.eclipse.skalli.model.EntityBase;
import org.eclipse.skalli.model.ExtensibleEntityBase;
import org.eclipse.skalli.model.ExtensionEntityBase;
import org.eclipse.skalli.model.Project;
import org.eclipse.skalli.model.PropertyName;
/**
* A {@link StrLookup} implementation that reflectively scans a given
* {@link EntityBase entity}, e.g. a project, for properties.
* <p>
* Maps property values to the respective property names declared with
* {@link PropertyName} annotations in the entity.
* For {@link ExtensibleEntityBase extensible entities}, properties of
* extensions are mapped to keys of the form <tt>extensionName.propertyName</tt>,
* where <tt>extensionName</tt> is the {@link ExtensionService#getShortName() short name}
* of the extension. Properties of the extensible entity itself are mapped to
* simple <tt>propertyName</tt>.
*/
public class PropertyLookup extends StrLookup {
private final HashMap<String, Object> properties = new HashMap<String, Object>();
/**
* Creates a property lookup instance from a given property map.
* The given properties are mapped to placeholders by their respective keys.
*
* @param @param customProperties optional custom properties, or <code>null</code>.
*/
public PropertyLookup(Map<String, ?> customProperties) {
this(null, customProperties);
}
/**
* Creates a property lookup instance for a given entity, e.g. a {@link Project}.
* Properties of the entity are scanned and provided as placeholders for the lookup.
*
* @param entity the entity, for which to create a property lookup.
*/
public PropertyLookup(EntityBase entity) {
this(entity, null);
}
/**
* Creates a property lookup instance for a given entity, e.g. a {@link Project}.
* Properties of the entity are scanned and provided as placeholders for the lookup.
* If the entity is {@link ExtensibleEntityBase extensible}, extensions are scanned,
* too, and added as placeholders of the form <tt>${extensionName.propertyName}</tt>.
* The given custom properties are mapped to placeholders by their respective keys
* and provided for the lookup as well.
*
* @param entity the entity, for which to create a property lookup.
* @param customProperties optional custom properties, or <code>null</code>.
*/
public PropertyLookup(EntityBase entity, Map<String, ?> customProperties) {
if (entity != null) {
putAllProperties(entity, ""); //$NON-NLS-1$
}
if (customProperties != null) {
properties.putAll(customProperties);
}
}
/**
* Adds all properties of the given entity to this property lookup.
* Property names of the entity are scanned and provided as placeholders of the form
* <tt>${prefix.propertyName}</tt> for the lookup. If the prefix is blank, placeholders
* of the form <tt>${propertyName}</tt> are used.
* Extensions of the entity are scanned, too, and added as placeholders of the form
* <tt>${prefix.extensionName.propertyName}</tt>. If the prefix is blank, placeholders are
* named <tt>${extensionName.propertyName}</tt>, respectively.
*
* @param entity the entity to add to this property lookup.
* @param prefix the prefix for building placeholders.
*/
public void putAllProperties(EntityBase entity, String prefix) {
prefix = StringUtils.removeEnd(prefix, "."); //$NON-NLS-1$
if (entity instanceof ExtensibleEntityBase) {
putAllProperties((ExtensibleEntityBase) entity, prefix);
}
for (String propertyName : entity.getPropertyNames()) {
properties.put(concat(prefix, propertyName), entity.getProperty(propertyName));
}
}
private void putAllProperties(ExtensibleEntityBase extensible, String prefix) {
for (ExtensionEntityBase extension : extensible.getAllExtensions()) {
ExtensionService<?> extensionService = ExtensionServices.getByExtensionClass(extension.getClass());
if (extensionService != null) {
putAllProperties(extension, concat(prefix, extensionService.getShortName()));
}
}
}
private String concat(String prefix, String s) {
StringBuilder sb = new StringBuilder(prefix);
if (sb.length() > 0) {
sb.append('.');
}
sb.append(s);
return sb.toString();
}
/**
* Returns the properties available for lookup as map.
*/
public Map<String, Object> asMap() {
return properties;
}
/**
* Returns the number of properties available for the lookup.
*/
public int size() {
return properties.size();
}
/**
* Returns <tt>true</tt> if this lookup contains no properties at all.
*/
public boolean isEmpty() {
return properties.isEmpty();
}
/**
* Returns <tt>true</tt> if this lookup contains a property with the given key.
*
* @param key the key of the property (without the surrounding
* <tt>${...}</tt> of the placeholder).
*/
public boolean containsKey(String key) {
return properties.containsKey(key);
}
/**
* Returns <tt>true</tt> if this lookup contains a given property value.
*
* @param value the property value to search for.
*/
public boolean containsValue(Object value) {
return properties.containsValue(value);
}
/**
* Returns all known property keys
*
* @return a set of keys (equivalent to the placeholders, but without the surrounding
* <tt>${...}</tt>), or an empty set.
*/
public Set<String> keySet() {
return properties.keySet();
}
/**
* Returns the property for the given key.
*
* @param key the key of the property to return (equivalent to the placeholder,
* but without the surrounding <tt>${...}</tt>).
*
* @return the value of the property, or <code>nully</code> if there is no property
* with the given key.
*/
public Object get(String key) {
return properties.get(key);
}
/**
* Returns a collection of all property values.
* @return the collection of property values, or an empty collection.
*/
public Collection<Object> values() {
return properties.values();
}
/**
* Returns an entry set of all properties.
* @return an entry set of properties, or an empty set.
*/
public Set<Map.Entry<String, Object>> entrySet() {
return properties.entrySet();
}
@Override
public String lookup(String key) {
if (StringUtils.isBlank(key)) {
return null;
}
Object o = properties.get(key);
if (o == null) {
return null;
}
if (o instanceof Collection) {
return CollectionUtils.toString((Collection<?>) o, ',');
}
return o.toString();
}
}