/*
* The MIT License
*
* Copyright 2013 Oleg Nenashev, Synopsys Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.synopsys.arc.jenkins.plugins.rolestrategy;
import com.michelin.cio.hudson.plugins.rolestrategy.Role;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Arrays;
import javax.annotation.Nonnull;
/**
* Macro representation for roles and users.
* Implements following format:
* {@code @macroId[:index][(parameter1, parameter2, ...)]},
* <ul>
* <li>macroId - name of the macro. Supports alphanumeric symbols</li>
* <li>index - optional integer, which allow to duplicate macro calls</li>
* <li>parameters - optional set of strings. each parameter should be string without quotes</li>
* </ul>
*
* TODO: Macro parameters (ex, multiple usage of macro)
* @since 2.1.0
* @author Oleg Nenashev, Synopsys Inc.
*/
public class Macro {
public final static String MACRO_PREFIX = "@";
private final static String PARAMS_LEFT_BORDER = "(";
private final static String PARAMS_RIGHT_BORDER = ")";
private final static String PARAMS_DELIMITER = "\\\"*,\\\"*";
private final static String INDEX_DELIMITER = ":";
private final static int DEFAULT_MACRO_ID = Integer.MIN_VALUE;
private final String name;
private final String dispName;
private final int index;
//TODO: rework to list/set?
@Nonnull
private final String[] parameters;
public Macro(String name, Integer index, String[] parameters) {
this.name = name;
this.dispName = MACRO_PREFIX + name;
this.index = (index == null) ? DEFAULT_MACRO_ID : index;
this.parameters = parameters != null ? Arrays.copyOf(parameters, parameters.length) : new String[0];
}
/**
* Get name of the macro.
* @return Name of the macro (without prefix)
*/
public String getName() {
return name;
}
public String getDisplayName() {
return dispName;
}
public int getIndex() {
return index;
}
public boolean hasIndex() {
return index != DEFAULT_MACRO_ID;
}
public String[] getParameters() {
return Arrays.copyOf(parameters, parameters.length);
}
public boolean hasParameters() {
return parameters.length != 0;
}
@Override
public String toString() {
StringBuilder bldr = new StringBuilder(dispName);
if (hasIndex()) {
bldr.append(":");
bldr.append(index);
}
if (hasParameters()) {
bldr.append("(");
bldr.append(parameters[0]);
for (int i=1;i<parameters.length;i++) {
bldr.append(",");
bldr.append(parameters[i]);
}
bldr.append(")");
}
return bldr.toString();
}
/**
* Check if role is a macro.
* @param role Role to be checked
* @return true if role meets macro criteria
*/
public static boolean isMacro(Role role) {
return isMacro(role.getName());
}
public static boolean isMacro(String macroString) {
return macroString.startsWith(MACRO_PREFIX);
}
/**
* @deprecated Use {@link #parse(java.lang.String)}
*/
@Deprecated
@SuppressFBWarnings(value = "NM_METHOD_NAMING_CONVENTION", justification = "deprecated, just for API compatibility")
public static Macro Parse(String macroString) throws MacroException {
return parse(macroString);
}
/**
* Parse macro from string
* @param macroString - macro string
* @return Macro instance
* @throws MacroException - Parse error
* @since TODO
*/
public static Macro parse(String macroString) throws MacroException {
if (!isMacro(macroString)) {
throw new MacroException(MacroExceptionCode.Not_Macro,
"Can't parse macro: Macro String should start from " + MACRO_PREFIX);
}
int leftBorder = macroString.indexOf(PARAMS_LEFT_BORDER);
int rightBorder = macroString.lastIndexOf(PARAMS_RIGHT_BORDER);
boolean hasParams = checkBorders(macroString, leftBorder, rightBorder);
// Get macroName and id
String macroIdStr = hasParams ? macroString.substring(0, leftBorder) : macroString;
String[] macroIdItems = macroIdStr.split(INDEX_DELIMITER);
if (macroIdItems.length > 2) {
throw new MacroException(MacroExceptionCode.WrongFormat,
"Macro string should contain only one '"+INDEX_DELIMITER+"' delimiter");
}
// Macro name
String macroName = macroIdItems[0].substring(MACRO_PREFIX.length());
if (macroName.isEmpty()) {
throw new MacroException(MacroExceptionCode.WrongFormat, "Macro name is empty");
}
// Macro id
int macroId = DEFAULT_MACRO_ID;
if (macroIdItems.length == 2) {
try {
macroId = Integer.parseInt(macroIdItems[1]);
}
catch(NumberFormatException ex) {
throw new MacroException(MacroExceptionCode.WrongFormat,
"Can't parse int from "+macroIdItems[1]+": "+ex.getMessage());
}
}
// Parse parameters
String[] params = null;
if (hasParams) {
String paramsStr = macroString.substring(leftBorder+1, rightBorder);
params = paramsStr.split(PARAMS_DELIMITER);
}
return new Macro(macroName, macroId, params);
}
private static boolean checkBorders(String macroStr, int leftBorder, int rightBorder)
throws MacroException
{
if (leftBorder==-1 || rightBorder==-1)
{
if (leftBorder == rightBorder) {
return false; // no borders
}
String missingBorder = (leftBorder == -1) ? "left" : "right";
throw new MacroException(MacroExceptionCode.WrongFormat, "Missing border: "+missingBorder);
}
// Check ending
if (rightBorder != -1 && !macroStr.endsWith(PARAMS_RIGHT_BORDER))
{
throw new MacroException(MacroExceptionCode.WrongFormat,
"Parametrized Macro should end with '"+PARAMS_RIGHT_BORDER+"'");
}
// Check duplicated borders
if (leftBorder != macroStr.lastIndexOf(PARAMS_LEFT_BORDER)) {
throw new MacroException(MacroExceptionCode.WrongFormat,
"Duplicated left border ('"+PARAMS_LEFT_BORDER+"' symbol)");
}
if (rightBorder != macroStr.indexOf(PARAMS_RIGHT_BORDER)) {
throw new MacroException(MacroExceptionCode.WrongFormat,
"Duplicated right border ('"+PARAMS_RIGHT_BORDER+"' symbol)");
}
// Check quatas
if (macroStr.contains("\"")) {
throw new MacroException(MacroExceptionCode.WrongFormat,
"Double quotes aren't supported");
}
if (macroStr.contains("'")) {
throw new MacroException(MacroExceptionCode.WrongFormat,
"Single quotes aren't supported");
}
return true;
}
}