/*
* 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.eigenbase.util;
import java.nio.*;
import java.nio.charset.*;
import java.util.List;
import org.eigenbase.sql.*;
import net.hydromatic.optiq.runtime.SqlFunctions;
import static org.eigenbase.util.Static.RESOURCE;
/**
* A string, optionally with {@link Charset character set} and {@link
* SqlCollation}. It is immutable.
*/
public class NlsString implements Comparable<NlsString> {
//~ Instance fields --------------------------------------------------------
private final String charsetName;
private final String value;
private final Charset charset;
private final SqlCollation collation;
//~ Constructors -----------------------------------------------------------
/**
* Creates a string in a specfied character set.
*
* @param value String constant, must not be null
* @param charsetName Name of the character set, may be null
* @param collation Collation, may be null
* @throws IllegalCharsetNameException If the given charset name is illegal
* @throws UnsupportedCharsetException If no support for the named charset
* is available in this instance of the Java virtual machine
* @throws RuntimeException If the given value cannot be represented in the
* given charset
*/
public NlsString(
String value,
String charsetName,
SqlCollation collation) {
assert value != null;
if (null != charsetName) {
charsetName = charsetName.toUpperCase();
this.charsetName = charsetName;
String javaCharsetName =
SqlUtil.translateCharacterSetName(charsetName);
if (javaCharsetName == null) {
throw new UnsupportedCharsetException(charsetName);
}
this.charset = Charset.forName(javaCharsetName);
CharsetEncoder encoder = charset.newEncoder();
// dry run to see if encoding hits any problems
try {
encoder.encode(CharBuffer.wrap(value));
} catch (CharacterCodingException ex) {
throw RESOURCE.charsetEncoding(value, javaCharsetName).ex();
}
} else {
this.charsetName = null;
this.charset = null;
}
this.collation = collation;
this.value = value;
}
//~ Methods ----------------------------------------------------------------
public Object clone() {
return new NlsString(value, charsetName, collation);
}
public int hashCode() {
int h = value.hashCode();
h = Util.hash(h, charsetName);
h = Util.hash(h, collation);
return h;
}
public boolean equals(Object obj) {
if (!(obj instanceof NlsString)) {
return false;
}
NlsString that = (NlsString) obj;
return Util.equal(value, that.value)
&& Util.equal(charsetName, that.charsetName)
&& Util.equal(collation, that.collation);
}
// implement Comparable
public int compareTo(NlsString other) {
// TODO jvs 18-Jan-2006: Actual collation support. This just uses
// the default collation.
return value.compareTo(other.value);
}
public String getCharsetName() {
return charsetName;
}
public Charset getCharset() {
return charset;
}
public SqlCollation getCollation() {
return collation;
}
public String getValue() {
return value;
}
/**
* Returns a string the same as this but with spaces trimmed from the
* right.
*/
public NlsString rtrim() {
String trimmed = SqlFunctions.rtrim(value);
if (!trimmed.equals(value)) {
return new NlsString(trimmed, charsetName, collation);
}
return this;
}
/**
* Returns the string quoted for SQL, for example <code>_ISO-8859-1'is it a
* plane? no it''s superman!'</code>.
*
* @param prefix if true, prefix the character set name
* @param suffix if true, suffix the collation clause
* @return the quoted string
*/
public String asSql(
boolean prefix,
boolean suffix) {
StringBuilder ret = new StringBuilder();
if (prefix && (null != charsetName)) {
ret.append("_");
ret.append(charsetName);
}
ret.append("'");
ret.append(Util.replace(value, "'", "''"));
ret.append("'");
// NOTE jvs 3-Feb-2005: see FRG-78 for why this should go away
if (false) {
if (suffix && (null != collation)) {
ret.append(" ");
ret.append(collation.toString());
}
}
return ret.toString();
}
/**
* Returns the string quoted for SQL, for example <code>_ISO-8859-1'is it a
* plane? no it''s superman!'</code>.
*/
public String toString() {
return asSql(true, true);
}
/**
* Concatenates some {@link NlsString} objects. The result has the charset
* and collation of the first element. The other elements must have matching
* (or null) charset and collation. Concatenates all at once, not pairwise,
* to avoid string copies.
*
* @param args array of {@link NlsString} to be concatenated
*/
public static NlsString concat(List<NlsString> args) {
if (args.size() < 2) {
return args.get(0);
}
String charSetName = args.get(0).charsetName;
SqlCollation collation = args.get(0).collation;
int length = args.get(0).value.length();
// sum string lengths and validate
for (int i = 1; i < args.size(); i++) {
final NlsString arg = args.get(i);
length += arg.value.length();
if (!((arg.charsetName == null)
|| arg.charsetName.equals(charSetName))) {
throw new IllegalArgumentException("mismatched charsets");
}
if (!((arg.collation == null)
|| arg.collation.equals(collation))) {
throw new IllegalArgumentException("mismatched collations");
}
}
StringBuilder sb = new StringBuilder(length);
for (NlsString arg : args) {
sb.append(arg.value);
}
return new NlsString(
sb.toString(),
charSetName,
collation);
}
/** Creates a copy of this {@code NlsString} with different content but same
* charset and collation. */
public NlsString copy(String value) {
return new NlsString(value, charsetName, collation);
}
}
// End NlsString.java