blob: 1cf5c79c55595c1b9746134730f36bc1e5d03d6d [file] [log] [blame]
/*
* Copyright (c) 2015, 2016 Eike Stepper (Berlin, Germany) 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:
* Eike Stepper - initial API and implementation
*/
package org.eclipse.oomph.setup.internal.core;
import org.eclipse.oomph.preferences.util.PreferencesUtil;
import org.eclipse.oomph.preferences.util.PreferencesUtil.PreferenceProperty;
import org.eclipse.oomph.setup.util.StringExpander;
import org.eclipse.oomph.util.IOUtil;
import org.eclipse.oomph.util.StringUtil;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.URIConverter;
import org.eclipse.emf.ecore.xml.type.XMLTypeFactory;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.Platform;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Eike Stepper
*/
public class StringFilterRegistry
{
public static final StringFilterRegistry INSTANCE = new StringFilterRegistry();
private static final Pattern CAMEL_PATTERN = Pattern.compile("(?:[^\\p{Alnum}]+|^)(\\p{Lower})?");
private final Map<String, StringFilter> filters = new HashMap<String, StringFilter>();
private StringFilterRegistry()
{
registerFilter(new DocumentedStringFilter()
{
public String getName()
{
return "file";
}
@Override
public String getDescription()
{
return "Converts a file: URI to an OS-specific file system path.";
}
public String filter(String value)
{
return URI.createURI(value).toFileString();
}
});
registerFilter(new DocumentedStringFilter()
{
public String getName()
{
return "uri";
}
@Override
public String getDescription()
{
return "Converts a file system path to a file: URI.";
}
public String filter(String value)
{
return URI.createFileURI(value).toString();
}
});
registerFilter(new DocumentedStringFilter()
{
public String getName()
{
return "uriLastSegment";
}
@Override
public String getDescription()
{
return "Extracts the last path segment from a hierarchical URI or the authority from an opaque URI.";
}
public String filter(String value)
{
URI uri = URI.createURI(value);
if (!uri.isHierarchical())
{
uri = URI.createURI(uri.opaquePart());
}
return URI.decode(uri.lastSegment());
}
});
registerFilter(new DocumentedStringFilter()
{
public String getName()
{
return "gitRepository";
}
@Override
public String getDescription()
{
return "Extracts the name of the repository from a Git URI (excluding a possible .git suffix).";
}
public String filter(String value)
{
URI uri = URI.createURI(value);
if (!uri.isHierarchical())
{
uri = URI.createURI(uri.opaquePart());
}
String result = URI.decode(uri.lastSegment());
if (result != null && result.endsWith(".git"))
{
result = result.substring(0, result.length() - 4);
}
return result;
}
});
registerFilter(new DocumentedStringFilter()
{
public String getName()
{
return "username";
}
@Override
public String getDescription()
{
return "Escapes all \"at\" symbols (@) of a String value, so that the result can be used in URI that contain a username.";
}
public String filter(String value)
{
return URI.encodeSegment(value, false).replace(":", "%3A").replace("@", "%40");
}
});
registerFilter(new DocumentedStringFilter()
{
public String getName()
{
return "canonical";
}
@Override
public String getDescription()
{
return "Canonicalizes a file system path.";
}
public String filter(String value)
{
// Don't canonicalize the value if it contains a unexpanded variable reference.
if (StringExpander.STRING_EXPANSION_PATTERN.matcher(value).find())
{
return value;
}
File file = new File(value).getAbsoluteFile();
try
{
return file.getCanonicalPath();
}
catch (IOException ex)
{
return file.getAbsolutePath();
}
}
});
registerFilter(new DocumentedStringFilter()
{
public String getName()
{
return "preferenceNode";
}
@Override
public String getDescription()
{
return "Escapes all forward slashes (/) of a String value, so that the result can be used as a value in preference nodes.";
}
public String filter(String value)
{
return value.replaceAll("/", "\\\\2f");
}
});
registerFilter(new DocumentedStringFilter()
{
public String getName()
{
return "length";
}
@Override
public String getDescription()
{
return "Converts a String to a String that contains the alpha-numerical representation of the length of the original String.";
}
public String filter(String value)
{
return Integer.toString(value.length());
}
});
registerFilter(new DocumentedStringFilter()
{
public String getName()
{
return "trim";
}
@Override
public String getDescription()
{
return "Removes all whitespace from the beginning and the end of a String.";
}
public String filter(String value)
{
return value.trim();
}
});
registerFilter(new DocumentedStringFilter()
{
public String getName()
{
return "trimLeft";
}
@Override
public String getDescription()
{
return "Removes all whitespace from the beginning of a String.";
}
public String filter(String value)
{
return StringUtil.trimLeft(value);
}
});
registerFilter(new DocumentedStringFilter()
{
public String getName()
{
return "trimRight";
}
@Override
public String getDescription()
{
return "Removes all whitespace from the end of a String.";
}
public String filter(String value)
{
return StringUtil.trimRight(value);
}
});
registerFilter(new DocumentedStringFilter()
{
public String getName()
{
return "trimTrailingSlashes";
}
@Override
public String getDescription()
{
return "Removes all slashes and backslashes from the end of a String.";
}
public String filter(String value)
{
return StringUtil.trimTrailingSlashes(value);
}
});
registerFilter(new DocumentedStringFilter()
{
public String getName()
{
return "upper";
}
@Override
public String getDescription()
{
return "Converts all characters of a String value to upper-case.";
}
public String filter(String value)
{
return value.toUpperCase();
}
});
registerFilter(new DocumentedStringFilter()
{
public String getName()
{
return "lower";
}
@Override
public String getDescription()
{
return "Converts all characters of a String value to lower-case.";
}
public String filter(String value)
{
return value.toLowerCase();
}
});
registerFilter(new DocumentedStringFilter()
{
public String getName()
{
return "cap";
}
@Override
public String getDescription()
{
return "Capitalizes the first word of a String value.";
}
public String filter(String value)
{
return StringUtil.cap(value);
}
});
registerFilter(new DocumentedStringFilter()
{
public String getName()
{
return "capAll";
}
@Override
public String getDescription()
{
return "Capitalizes all words of a String value.";
}
@Override
public String[] getDeprecations()
{
return new String[] { "allCap" };
}
public String filter(String value)
{
return StringUtil.capAll(value);
}
});
registerFilter(new DocumentedStringFilter()
{
public String getName()
{
return "qualifiedName";
}
@Override
public String getDescription()
{
return "Converts a camel case String value name to a qualified name.";
}
public String filter(String value)
{
return value.trim().replaceAll("[^\\p{Alnum}]+", ".").toLowerCase();
}
});
registerFilter(new DocumentedStringFilter()
{
public String getName()
{
return "camel";
}
@Override
public String getDescription()
{
return "Converts a qualified name to camel case notation.";
}
public String filter(String value)
{
Matcher matcher = CAMEL_PATTERN.matcher(value);
StringBuffer result = new StringBuffer();
while (matcher.find())
{
String group = matcher.group(1);
matcher.appendReplacement(result, group == null ? "" : group.toUpperCase());
}
matcher.appendTail(result);
return result.toString();
}
});
registerFilter(new DocumentedStringFilter()
{
public String getName()
{
return "property";
}
@Override
public String getDescription()
{
return "Escapes all double back slashes (\\\\) of a String value, so that the result can be used as a value in properties.";
}
public String filter(String value)
{
return value.replaceAll("\\\\", "\\\\\\\\");
}
});
registerFilter(new DocumentedStringFilter()
{
public String getName()
{
return "path";
}
@Override
public String getDescription()
{
return "Extracts the path segments from a URI.";
}
public String filter(String value)
{
return value.replaceAll("\\\\", "/");
}
});
registerFilter(new DocumentedStringFilter()
{
public String getName()
{
return "basePath";
}
@Override
public String getDescription()
{
return "Removes the last segment from a file system path.";
}
public String filter(String value)
{
value = value.replaceAll("\\\\", "/");
int pos = value.lastIndexOf('/');
if (pos == -1)
{
return "";
}
return value.substring(0, pos);
}
});
registerFilter(new DocumentedStringFilter()
{
public String getName()
{
return "lastSegment";
}
@Override
public String getDescription()
{
return "Extracts the last segment from a file system path.";
}
public String filter(String value)
{
int pos = Math.max(value.lastIndexOf('/'), value.lastIndexOf('\\'));
if (pos == -1)
{
return value;
}
return value.substring(pos + 1);
}
});
registerFilter(new DocumentedStringFilter()
{
public String getName()
{
return "fileExtension";
}
@Override
public String getDescription()
{
return "Extracts the file extension from a URI or a file system path.";
}
public String filter(String value)
{
int pos = value.lastIndexOf('.');
if (pos == -1)
{
return "";
}
return value.substring(pos + 1);
}
});
registerFilter(new DocumentedStringFilter()
{
public String getName()
{
return "pathEncode";
}
@Override
public String getDescription()
{
return "Converts a file system path to a String value that can be used as a file name.";
}
public String filter(String value)
{
return IOUtil.encodeFileName(value);
}
});
registerFilter(new DocumentedStringFilter()
{
public String getName()
{
return "urlEncode";
}
@Override
public String getDescription()
{
return "URL-encodes a String value.";
}
public String filter(String value)
{
try
{
return URLEncoder.encode(value, "UTF-8");
}
catch (UnsupportedEncodingException ex)
{
// Should not happen.
return value;
}
}
});
registerFilter(new DocumentedStringFilter()
{
public String getName()
{
return "urlDecode";
}
@Override
public String getDescription()
{
return "Decodes a URL.";
}
public String filter(String value)
{
try
{
return URLDecoder.decode(value, "UTF-8");
}
catch (UnsupportedEncodingException ex)
{
// Should not happen.
return value;
}
}
});
registerFilter(new DocumentedStringFilter()
{
public String getName()
{
return "slashEncode";
}
@Override
public String getDescription()
{
return "Encodes all slashes and backslashes of a String value.";
}
@SuppressWarnings("restriction")
public String filter(String value)
{
try
{
return org.eclipse.equinox.internal.security.storage.SlashEncode.encode(value);
}
catch (Throwable ex)
{
// Should not happen.
return value;
}
}
});
registerFilter(new DocumentedStringFilter()
{
public String getName()
{
return "slashDecode";
}
@Override
public String getDescription()
{
return "Decodes a slashEncoded String value.";
}
@SuppressWarnings("restriction")
public String filter(String value)
{
try
{
return org.eclipse.equinox.internal.security.storage.SlashEncode.decode(value);
}
catch (Throwable ex)
{
// Should not happen.
return value;
}
}
});
registerFilter(new DocumentedStringFilter()
{
public String getName()
{
return "propertyValue";
}
@Override
public String getDescription()
{
return "Interprets the String value as a preference property path and returns the value of that property.";
}
public String filter(String value)
{
PreferenceProperty preferenceProperty = new PreferencesUtil.PreferenceProperty(value);
String result = preferenceProperty.get(null);
return result == null ? "" : result;
}
});
registerFilter("base64", new ParameterizedStringFilter()
{
public String filter(String value)
{
return filter(value, null);
}
public String filter(String value, String argument)
{
try
{
Charset charset;
if (value.startsWith("<?xml"))
{
String xmlEncoding = URIConverter.ReadableInputStream.getEncoding(value);
charset = Charset.forName(xmlEncoding == null ? "UTF-8" : xmlEncoding);
}
else if (argument != null)
{
charset = Charset.forName(argument.toUpperCase());
}
else
{
charset = Charset.defaultCharset();
}
return XMLTypeFactory.eINSTANCE.convertBase64Binary(value.getBytes(charset));
}
catch (Exception ex)
{
return value;
}
}
});
}
public static void main(String[] args) throws UnsupportedEncodingException
{
List<Map.Entry<String, StringFilter>> entries = new ArrayList<Map.Entry<String, StringFilter>>(INSTANCE.filters.entrySet());
Collections.sort(entries, new Comparator<Map.Entry<String, StringFilter>>()
{
public int compare(Map.Entry<String, StringFilter> e1, Map.Entry<String, StringFilter> e2)
{
return e1.getKey().compareTo(e2.getKey());
}
});
System.out.println("{| class=\"wikitable\"");
boolean first = true;
for (Map.Entry<String, StringFilter> entry : entries)
{
String name;
String description;
StringFilter filter = entry.getValue();
if (filter instanceof DocumentedStringFilter)
{
name = ((DocumentedStringFilter)filter).getName();
description = ((DocumentedStringFilter)filter).getDescription();
boolean deprecated = !name.toLowerCase().equals(entry.getKey().toLowerCase());
if (deprecated)
{
continue;
}
}
else
{
name = entry.getKey();
description = "";
}
if (first)
{
first = false;
}
else
{
System.out.println("|-");
}
System.out.println("| '''" + name + "''' || " + description);
}
System.out.println("|}");
}
public String filter(String value, String filterName)
{
StringFilter filter = filters.get(filterName.toLowerCase());
if (filter == null)
{
int argumentIndex = filterName.indexOf('.');
if (argumentIndex != -1)
{
filter = filters.get(filterName.substring(0, argumentIndex).toLowerCase());
if (filter instanceof ParameterizedStringFilter)
{
ParameterizedStringFilter parameterizedStringFilter = (ParameterizedStringFilter)filter;
return parameterizedStringFilter.filter(value, filterName.substring(argumentIndex + 1));
}
}
return value;
}
return filter.filter(value);
}
void initContributions()
{
if (SetupCorePlugin.INSTANCE.isOSGiRunning())
{
try
{
IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry();
for (IConfigurationElement configurationElement : extensionRegistry.getConfigurationElementsFor("org.eclipse.oomph.setup.core.stringFilters"))
{
String filterName = configurationElement.getAttribute("name");
if (!filters.containsKey(filterName))
{
try
{
StringFilter filter = (StringFilter)configurationElement.createExecutableExtension("class");
registerFilter(filterName, filter);
}
catch (Exception ex)
{
SetupCorePlugin.INSTANCE.log(ex);
}
}
}
}
catch (Exception ex)
{
SetupCorePlugin.INSTANCE.log(ex);
}
}
}
private void registerFilter(String filterName, StringFilter filter)
{
filters.put(filterName.toLowerCase(), filter);
}
private void registerFilter(DocumentedStringFilter filter)
{
String name = filter.getName().toLowerCase();
filters.put(name, filter);
String[] deprecations = filter.getDeprecations();
if (deprecations != null)
{
for (String deprecatedName : deprecations)
{
filters.put(deprecatedName.toLowerCase(), filter);
}
}
}
/**
* @author Eike Stepper
*/
public static abstract class DocumentedStringFilter implements StringFilter, StringFilterDocumentation
{
public String getDescription()
{
return null;
}
public String[] getDeprecations()
{
return null;
}
}
}