/*******************************************************************************
* 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.ArrayList;
import java.util.List;
import java.util.regex.MatchResult;
import org.eclipse.skalli.commons.ComparatorUtils;
import org.eclipse.skalli.commons.Link;
import org.eclipse.skalli.commons.LinkMapping;
import org.eclipse.skalli.model.EntityBase;
/**
* Utility that maps an input string, e.g. a source location, to a list of {@link Link links} by
* comparing it to given regular expressions and generating links from associated templates that
* may contain placeholders. For example, one might generate various links for a source location,
* such as a link to a repository viewer or a link to an associated code review system.
*/
public class LinkMapper<T extends LinkMapping> {
protected final String[] purposes;
/**
* Constant to accept mappings of any purpose
* (see {@link #getMappedLinks(String, List, String, EntityBase, String...)}).
*/
public static final String[] ALL_PURPOSES = new String[] { "*" }; //$NON-NLS-1$
/**
* Creates a link mapper for a collection of purposes. The purpose of a link mapping
* determines in which situations a certain link mapping is relevant.
*
* @param purposes the purposes to accept when evaluating link mappings. A mapping that doesn't match
* any of the given purposes is skipped. {@link #ALL_PURPOSE} and <code>"*"</code> match any purpose.
* An empty array excludes all purposes.
*/
public LinkMapper(String... purposes) {
this.purposes = purposes != null? purposes : new String[] { null };
}
/**
* Maps a given string to a collection of links by matching the string with a given collection of
* {@link LinkMapping#getPattern() regular expressions} and, in case of a successful match,
* by converting the string into a link based on a {@link LinkMapping#getTemplate() template}
* associated with the regular expression. The template may contain placeholders that are
* resolved during the link generation.
* <br>
* If specified, the <code>userId</code> parameter is mapped to the placeholder <tt>${userId}</tt>.
* The properties of the entity, if specified, are mapped to placeholders of the form <tt>${propertyName}</tt>.
* Properties of extensions of the entity, if any, are mapped to placeholders of the form
* <tt>${extension.propertyName}</tt>. The placeholders <tt>${1},${2},...</tt> provide the
* {@link MatchResult#group(int) groups} of the match result.
*
* @param s the string to match to the given mappings and to convert to links in case
* of successful matches.
* @param mappings the mappings, each comprising a regular expression to compare the string with,
* a template with optional placeholders from which to generate a link, and a purpose to exclude
* certain mappings that are not relevant.
* @param userId the unique identifier of a user.
* @param entity any (probably extensible) entity.
*
* @return a list of links, or an empty list.
*/
public List<Link> getMappedLinks(String s, List<T> mappings, String userId, EntityBase entity) {
List<Link> links = new ArrayList<Link>();
if (mappings != null) {
for (T mapping : mappings) {
if (accept(mapping)) {
String url = PropertyMapper.convert(s, mapping.getPattern(), mapping.getTemplate(),
entity, userId);
if (url != null) {
Link location = new Link(url, mapping.getName());
links.add(location);
}
}
}
}
return links;
}
/**
* Filters a given collection of link mappings and returns only those that
* pass {@link #accept(LinkMapping)}.
*
* @param mappings the collection of link mappings to filter.
*
* @return a list of link mappings, or an empty list.
*/
public List<T> filter(List<T> mappings) {
List<T> filteredMappings = new ArrayList<T>();
if (mappings != null) {
for (T mapping : mappings) {
if (mapping != null && accept(mapping)) {
filteredMappings.add(mapping);
}
}
}
return filteredMappings;
}
/**
* Returns <code>true</code> if the given mapping should be taken into account for
* the link generation. This implementation checks only that the purpose of the mapping
* matches any of the purposes provided in the constructor and may be overwritten to conduct
* more sophisticated checks.
*
* @param mapping the mapping to check.
* @return <code>true</code>, if the mapping is accepted.
*/
protected boolean accept(T mapping) {
for (String purpose : purposes) {
if (ALL_PURPOSES[0].equals(purpose) || ComparatorUtils.equals(purpose, mapping.getPurpose())) {
return true;
}
}
return false;
}
}