| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.openjpa.lib.identifier; |
| |
| import java.util.ArrayList; |
| import java.util.Locale; |
| |
| import org.apache.openjpa.lib.conf.Configurable; |
| import org.apache.openjpa.lib.conf.Configuration; |
| import org.apache.openjpa.lib.util.Localizer; |
| import org.apache.openjpa.lib.util.StringUtil; |
| |
| /** |
| * Implementation class for the base identifier impl. |
| * |
| */ |
| public class IdentifierUtilImpl implements IdentifierUtil, Configurable { |
| |
| private static final Localizer _loc = Localizer.forPackage |
| (IdentifierUtilImpl.class); |
| |
| private IdentifierConfiguration _config = null; |
| |
| public IdentifierUtilImpl() { |
| |
| } |
| |
| public IdentifierUtilImpl(IdentifierConfiguration config) { |
| _config = config; |
| } |
| |
| @Override |
| public void setIdentifierConfiguration(IdentifierConfiguration config) { |
| _config = config; |
| } |
| |
| @Override |
| public IdentifierConfiguration getIdentifierConfiguration() { |
| return _config; |
| } |
| |
| @Override |
| public String combineNames(String rule, String name1, String name2) { |
| return combineNames(getNamingRule(rule), name1, name2); |
| } |
| |
| @Override |
| public String combineNames(String rule, String[] names) { |
| return combineNames(getNamingRule(rule), names); |
| } |
| |
| public String combineNames(IdentifierConfiguration config, String rule, String[] names) { |
| return combineNames(config, getNamingRule(rule), names); |
| } |
| |
| @Override |
| public String combineNames(IdentifierRule rule, |
| IdentifierRule[] rules, String[] names) { |
| return combineNames(_config, rule, rules, names); |
| } |
| |
| public String combineNames(IdentifierConfiguration config, IdentifierRule rule, |
| IdentifierRule[] rules, String[] names) { |
| boolean delimited = false; |
| String combined = null; |
| for (int i = 0; i < names.length; i++) { |
| String name = names[i]; |
| if (isDelimited(rules[i], name)) { |
| delimited = true; |
| name = removeDelimiters(config, rules[i], name); |
| } |
| if (i == 0) { |
| combined = name; |
| } |
| else { |
| combined = combined + config.getIdentifierConcatenator() + name; |
| } |
| } |
| |
| if (delimited) { |
| combined = delimit(config, rule, combined); |
| } |
| |
| return combined; |
| } |
| |
| public String combineNames(IdentifierConfiguration config, IdentifierRule rule, String name1, String name2) { |
| boolean delimit = false; |
| if (isDelimited(rule, name1)) { |
| name1 = removeDelimiters(config, rule, name1); |
| delimit = true; |
| } |
| if (isDelimited(rule, name2)) { |
| name2 = removeDelimiters(config, rule, name2); |
| delimit = true; |
| } |
| String name = name1 + config.getIdentifierConcatenator() + name2; |
| return delimit(config, rule, name, delimit); |
| } |
| |
| public String combineNames(IdentifierConfiguration config, IdentifierRule namingRule, String[] names) { |
| boolean delimited = false; |
| String combined = null; |
| for (int i = 0; i < names.length; i++) { |
| String name = names[i]; |
| if (isDelimited(config, namingRule, name)) { |
| delimited = true; |
| name = removeDelimiters(config, namingRule, name); |
| } |
| if (i == 0) { |
| combined = name; |
| } |
| else { |
| combined = combined + config.getIdentifierConcatenator() + name; |
| } |
| } |
| if (delimited) { |
| combined = delimit(config, namingRule, combined); |
| } |
| |
| return combined; |
| } |
| |
| @Override |
| public String appendNames(IdentifierRule rule, String name1, String name2) { |
| if (isDelimited(rule, name1)) { |
| name1 = removeDelimiters(rule, name1); |
| } |
| if (isDelimited(rule, name2)) { |
| name2 = removeDelimiters(rule, name2); |
| } |
| if (name1 == null) { |
| name1 = IdentifierUtil.EMPTY; |
| } |
| if (name2 == null) { |
| name2 = IdentifierUtil.EMPTY; |
| } |
| String name = name1 + name2; |
| return delimit(rule, name); |
| } |
| |
| /** |
| * Joins multiple names together using the standard delimiting rules |
| * ex. ( {"s", "t", "c"} --> "s"."t"."c" } |
| */ |
| @Override |
| public String joinNames(IdentifierRule[] rules, String[] names) { |
| |
| if (names == null || names.length == 0) { |
| return null; |
| } |
| StringBuilder combinedName = new StringBuilder(); |
| for (int i = 0; i < names.length; i++) { |
| combinedName.append(delimit(rules[i], names[i])); |
| if (i < (names.length -1)) { |
| combinedName.append(_config.getIdentifierDelimiter()); |
| } |
| } |
| return combinedName.toString(); |
| } |
| |
| @Override |
| public String joinNames(String rule, String[] names) { |
| return joinNames(_config, getNamingRule(rule), names, _config.getIdentifierDelimiter()); |
| } |
| |
| @Override |
| public String joinNames(IdentifierRule rule, String[] names) { |
| return joinNames(_config, rule, names, _config.getIdentifierDelimiter()); |
| } |
| |
| @Override |
| public String joinNames(IdentifierRule rule, String[] names, String delimiter) { |
| return joinNames(_config, rule, names, delimiter); |
| } |
| |
| @Override |
| public String joinNames(String rule, String[] names, String delimiter) { |
| return joinNames(_config, getNamingRule(rule), names, delimiter); |
| } |
| |
| /** |
| * Join names using a single naming rule and specified delimiter |
| * @param rule |
| * @param names |
| */ |
| public String joinNames(IdentifierConfiguration config, IdentifierRule rule, String[] names, String delimiter) { |
| |
| if (names == null || names.length == 0) { |
| return null; |
| } |
| StringBuilder combinedName = new StringBuilder(); |
| for (int i = 0; i < names.length; i++) { |
| if (names[i] != null) { |
| combinedName.append(delimit(config, rule, names[i], false)); |
| if (i < (names.length -1)) { |
| combinedName.append(delimiter); |
| } |
| } |
| } |
| return combinedName.toString(); |
| } |
| |
| public String[] splitName(IdentifierConfiguration config, IdentifierRule nrule, String name) { |
| return splitName(nrule, name, config.getIdentifierDelimiter()); |
| } |
| |
| @Override |
| public String[] splitName(IdentifierRule nrule, String name) { |
| return splitName(nrule, name, _config.getIdentifierDelimiter()); |
| } |
| |
| |
| /** |
| * Splits names using single naming rule and appropriate separators |
| * @param name the multi-value name |
| * @return individual components of the name |
| * ex. schema.table --> { schema, table } |
| */ |
| @Override |
| public String[] splitName(IdentifierRule nrule, String name, String nameDelim) { |
| if (!canSplit(nrule, name, nameDelim) || StringUtil.isEmpty(name)) { |
| return new String[] {name}; |
| } |
| // "schema"."table" |
| // "sch.ma"."table" |
| // "sch""ma".table |
| |
| // Split names by object delimiter not between name delimiters |
| ArrayList<String> names = new ArrayList<>(2); |
| String pname = name; |
| |
| // for each name |
| int ndLen = nameDelim.length(); |
| while (!StringUtil.isEmpty(name)) { |
| pname = splitNameCharDelimiters(name, nameDelim); |
| names.add(pname); |
| if ((pname.length() + ndLen) >= name.length()) { |
| break; |
| } |
| name = name.substring(pname.length() + ndLen); |
| } |
| return names.toArray(new String[names.size()]); |
| } |
| |
| /** |
| * Gets the first part of a name when single character delimiters are |
| * in use. |
| * @param pname |
| */ |
| private String splitNameCharDelimiters(String name, String nameDelim) { |
| StringBuilder sname = new StringBuilder(""); |
| char ld = _config.getLeadingDelimiter().charAt(0); |
| char td = _config.getTrailingDelimiter().charAt(0); |
| char nd = nameDelim.charAt(0); |
| int dlvl = 0; |
| boolean wasLd = false; |
| for (int i = 0; i < name.length(); i++) { |
| char c = name.charAt(i); |
| if (c == ld) { |
| // Handle case where delimiters are the same |
| if (td == ld && wasLd) { |
| dlvl--; |
| wasLd = false; |
| } else { |
| wasLd = true; |
| dlvl++; |
| } |
| } else if (c == td) { |
| dlvl--; |
| } else if (c == nd) { |
| if (dlvl == 0 && sname.length() > 0) { |
| return sname.toString(); |
| } |
| } |
| sname.append(c); |
| } |
| return sname.toString(); |
| } |
| |
| /** |
| * Returns whether a name is double quoted |
| */ |
| public static boolean isDoubleQuoted(String name) { |
| if (name == null || name.length() < 3) { |
| return false; |
| } |
| return name.startsWith(DOUBLE_QUOTE) && |
| name.endsWith(DOUBLE_QUOTE); |
| } |
| |
| public String delimit(IdentifierConfiguration config, IdentifierRule rule, String name) { |
| return delimit(config, rule, name, false); |
| } |
| |
| |
| @Override |
| public String delimit(IdentifierRule rule, String name) { |
| return delimit(_config, rule, name, false); |
| } |
| |
| @Override |
| public String delimit(IdentifierRule rule, String name, boolean force) { |
| return delimit(_config, rule, name, force); |
| } |
| |
| public String delimit(IdentifierConfiguration config, IdentifierRule rule, String name, boolean force) { |
| if (!rule.getCanDelimit() || StringUtil.isEmpty(name)) { |
| return name; |
| } |
| |
| if ((force && !isDelimited(config, rule, name)) || requiresDelimiters(config, rule, name)) { |
| return config.getLeadingDelimiter() + name + config.getTrailingDelimiter(); |
| } |
| return name; |
| } |
| |
| @Override |
| public boolean isDelimited(IdentifierRule rule, String name) { |
| return isDelimited(_config, rule, name); |
| } |
| |
| public boolean isDelimited(IdentifierConfiguration config, IdentifierRule rule, String name) { |
| if (name == null || name.length() < 3) { |
| return false; |
| } |
| return name.startsWith(config.getLeadingDelimiter()) && |
| name.endsWith(config.getTrailingDelimiter()); |
| } |
| |
| @Override |
| public String removeDelimiters(IdentifierConfiguration config, String rule, |
| String name) { |
| return removeDelimiters(_config, getNamingRule(rule), name, _config.getLeadingDelimiter(), |
| _config.getTrailingDelimiter()); |
| } |
| |
| @Override |
| public String removeDelimiters(IdentifierRule rule, String name) { |
| return removeDelimiters(_config, rule, name, _config.getLeadingDelimiter(), |
| _config.getTrailingDelimiter()); |
| } |
| |
| public String removeDelimiters(IdentifierConfiguration config, IdentifierRule rule, String name) { |
| return removeDelimiters(config, rule, name, _config.getLeadingDelimiter(), |
| _config.getTrailingDelimiter()); |
| } |
| |
| @Override |
| public boolean requiresDelimiters(IdentifierRule rule, String name) { |
| return requiresDelimiters(_config, rule, name); |
| } |
| |
| public boolean requiresDelimiters(IdentifierConfiguration config, IdentifierRule rule, String name) { |
| if (rule == null) { |
| throw new IllegalArgumentException(_loc.get("no-rules-provided").getMessage()); |
| } |
| if (rule.getCanDelimit() && !isDelimited(config, rule, name) && rule.requiresDelimiters(name)) { |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Returns whether a name is considered a reserved word. |
| */ |
| @Override |
| public boolean isReservedWord(IdentifierRule rule, String name) { |
| if (rule == null) { |
| throw new IllegalArgumentException("Naming rule is null!"); |
| } |
| if (rule.getReservedWords() == null) { |
| return false; |
| } |
| if (!isDelimited(rule, name)) { |
| name = name.toUpperCase(Locale.ENGLISH); |
| } |
| return rule.getReservedWords().contains(name); |
| } |
| |
| @Override |
| public boolean isReservedWord(String rule, String name) { |
| return isReservedWord(_config.getIdentifierRule(rule), name); |
| } |
| |
| |
| protected String removeDelimiters(IdentifierConfiguration config, IdentifierRule rule, String name, String leading, |
| String trailing) { |
| if (name == null) { |
| return null; |
| } |
| if (isDelimited(config, rule, name)) { |
| String id = name.substring(leading.length(), |
| (name.length() - trailing.length())); |
| return id; |
| } |
| return name; |
| } |
| |
| @Override |
| public String combineNames(String rule, String[] rules, String[] names) { |
| return combineNames(getNamingRule(rule), getNamingRules(rules), names); |
| } |
| |
| @Override |
| public String truncateName(String rule, String name, int length) { |
| return truncateName(getNamingRule(rule), name, length); |
| } |
| |
| @Override |
| public String truncateName(IdentifierRule namingRule, String name, int length) { |
| String tName = name; |
| boolean delimited = isDelimited(namingRule, name); |
| if (delimited) { |
| tName = removeDelimiters(namingRule, name); |
| } |
| if (tName.length() <= length) { |
| return name; |
| } |
| tName = tName.substring(0, tName.length() - length); |
| if (delimited) { |
| tName = delimit(namingRule, tName); |
| } |
| return tName; |
| } |
| |
| @Override |
| public String delimit(String rule, String name) { |
| return delimit(getNamingRule(rule), name); |
| } |
| |
| @Override |
| public String delimit(String rule, String name, boolean force) { |
| return delimit(getNamingRule(rule), name, force); |
| } |
| |
| @Override |
| public boolean isDelimited(String rule, String name) { |
| return isDelimited(getNamingRule(rule), name); |
| } |
| |
| @Override |
| public String removeDelimiters(String rule, String name) { |
| return removeDelimiters(getNamingRule(rule), name); |
| } |
| |
| @Override |
| public boolean requiresDelimiters(String rule, String name) { |
| return requiresDelimiters(getNamingRule(rule), name); |
| } |
| |
| public String[] splitName(IdentifierConfiguration config, String rule, String name) { |
| return splitName(config, getNamingRule(rule), name); |
| } |
| |
| @Override |
| public String[] splitName(String rule, String name) { |
| return splitName(_config, getNamingRule(rule), name); |
| } |
| |
| @Override |
| public String joinNames(String[] rules, String[] names) { |
| return joinNames(getNamingRules(rules), names); |
| } |
| |
| private IdentifierRule getNamingRule(String rule) { |
| return _config.getIdentifierRule(rule); |
| } |
| |
| @Override |
| public String appendNames(String rule, String name1, String name2) { |
| return appendNames(getNamingRule(rule), name1, name2); |
| } |
| |
| @Override |
| public String removeHungarianNotation(IdentifierRule rule, String name) { |
| boolean delimited = isDelimited(rule, name); |
| if (delimited) { |
| name = removeDelimiters(rule, name); |
| } |
| char[] chname = name.toCharArray(); |
| int newStart = 0; |
| |
| for (int i = 0; i < chname.length; i++) { |
| if (Character.isUpperCase(chname[i])) |
| { |
| newStart = i; |
| break; |
| } |
| } |
| |
| name = name.substring(newStart); |
| if (delimited) { |
| name = delimit(rule, name); |
| } |
| return name; |
| } |
| |
| @Override |
| public String removeHungarianNotation(String rule, String name) { |
| return removeHungarianNotation(getNamingRule(rule), name); |
| } |
| |
| @Override |
| public String[] splitName(String nrule, String name, String nameDelim) { |
| return splitName(getNamingRule(nrule), name, nameDelim); |
| } |
| |
| @Override |
| public String convert(IdentifierConfiguration config, String rule, String name) { |
| // Already using same delimiter, no need to convert |
| if (!needsConversion(config)) { |
| return name; |
| } |
| // Otherwise, remove delimiters and add appropriate delimiters |
| IdentifierRule orule = getIdentifierConfiguration().getIdentifierRule(rule); |
| IdentifierRule nrule = config.getIdentifierRule(rule); |
| boolean delimit = isDelimited(config, orule, name); |
| if (delimit) { |
| name = removeDelimiters(config, orule, name, config.getLeadingDelimiter(), |
| config.getTrailingDelimiter()); |
| return delimit(getIdentifierConfiguration(), nrule, name, delimit); |
| } |
| return name; |
| } |
| |
| @Override |
| public String convertFull(IdentifierConfiguration config, String rule, String fullName) { |
| if (!needsConversion(config)) { |
| return fullName; |
| } |
| // Split |
| String[] names = splitName(config, rule, fullName); |
| // Convert |
| for (int i = 0; i < names.length; i++) { |
| names[i] = convert(config, rule, names[i]); |
| } |
| // If a single part name, return it. |
| if (names.length == 1) { |
| return names[0]; |
| } |
| // Join if multiple names |
| return joinNames(getIdentifierConfiguration(), config.getIdentifierRule(rule), names, |
| getIdentifierConfiguration().getIdentifierDelimiter()); |
| } |
| |
| public String combineFull(IdentifierConfiguration config, String rule, String fullName) { |
| if (!needsConversion(config)) { |
| return fullName; |
| } |
| // Split |
| String[] names = splitName(config, rule, fullName); |
| // Convert |
| for (int i = 0; i < names.length; i++) { |
| names[i] = convert(config, rule, names[i]); |
| } |
| // Join |
| return joinNames(config, config.getIdentifierRule(rule), names, config.getIdentifierDelimiter()); |
| } |
| |
| |
| protected boolean needsConversion(IdentifierConfiguration config) { |
| return (config != getIdentifierConfiguration()) |
| && !(config.getConversionKey().equals(getIdentifierConfiguration().getConversionKey())); |
| } |
| |
| private IdentifierRule[] getNamingRules(String[] rules) { |
| IdentifierRule[] nrules = new IdentifierRule[rules.length]; |
| for (int i = 0; i < rules.length; i++) { |
| nrules[i] = _config.getIdentifierRule(rules[i]); |
| } |
| return nrules; |
| } |
| |
| @Override |
| public void endConfiguration() { |
| } |
| |
| @Override |
| public void setConfiguration(Configuration conf) { |
| } |
| |
| @Override |
| public void startConfiguration() { |
| } |
| |
| @Override |
| public boolean canSplit(String rule, String name) { |
| return canSplit(getNamingRule(rule), name, _config.getIdentifierDelimiter()); |
| } |
| |
| @Override |
| public boolean canSplit(IdentifierRule rule, String name) { |
| return canSplit(rule, name, _config.getIdentifierDelimiter()); |
| } |
| |
| @Override |
| public boolean canSplit(String rule, String name, String delim) { |
| return canSplit(getNamingRule(rule), name); |
| } |
| |
| @Override |
| public boolean canSplit(IdentifierRule rule, String name, String delim) { |
| if (name == null || name.length() == 0) { |
| return false; |
| } |
| return name.contains(delim); |
| } |
| |
| @Override |
| public String combineNames(IdentifierRule rule, String[] names) { |
| return combineNames(_config, rule, names); |
| } |
| |
| @Override |
| public String combineNames(IdentifierRule rule, String name1, String name2) { |
| return combineNames(_config, rule, name1, name2); |
| } |
| } |