blob: 43364564a0bb48d002657bc7066c0132d73cf01d [file] [log] [blame]
/*
* 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.olingo.server.api;
import java.util.Arrays;
import java.util.Formatter;
import java.util.Locale;
import java.util.MissingFormatArgumentException;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import org.apache.olingo.commons.api.ODataException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Abstract superclass of all translatable server exceptions.
*/
public abstract class ODataTranslatedException extends ODataException {
private static final long serialVersionUID = -1210541002198287561L;
private static final Logger LOG = LoggerFactory.getLogger(ODataTranslatedException.class);
private static final Locale DEFAULT_LOCALE = Locale.ENGLISH;
protected static final String DEFAULT_SERVER_BUNDLE_NAME = "server-core-exceptions-i18n";
/** Key for the exception text in the resource bundle. */
public static interface MessageKey {
/** Gets this key. */
public String getKey();
}
private MessageKey messageKey;
private Object[] parameters;
protected ODataTranslatedException(String developmentMessage, MessageKey messageKey, String... parameters) {
super(developmentMessage);
this.messageKey = messageKey;
this.parameters = parameters;
}
protected ODataTranslatedException(String developmentMessage, Throwable cause, MessageKey messageKey,
String... parameters) {
super(developmentMessage, cause);
this.messageKey = messageKey;
this.parameters = parameters;
}
@Override
public String getLocalizedMessage() {
return getTranslatedMessage(DEFAULT_LOCALE).getMessage();
}
@Override
public String toString() {
return getMessage();
}
/** Gets the message key. */
public MessageKey getMessageKey() {
return messageKey;
}
/**
* Gets the translated message text for a given locale (or the default locale if not available),
* returning the developer message text if none is found.
* @param locale the preferred {@link Locale}
* @return the error message
*/
public ODataErrorMessage getTranslatedMessage(final Locale locale) {
if (messageKey == null) {
return new ODataErrorMessage(getMessage(), DEFAULT_LOCALE);
}
ResourceBundle bundle = createResourceBundle(locale);
if (bundle == null) {
return new ODataErrorMessage(getMessage(), DEFAULT_LOCALE);
}
return buildMessage(bundle, locale);
}
/**
* <p>Gets the name of the {@link ResourceBundle} containing the exception texts.</p>
* <p>The key for an exception text is the concatenation of the exception-class name and
* the {@link MessageKey}, separated by a dot.</p>
* @return the name of the resource bundle
*/
protected abstract String getBundleName();
private ResourceBundle createResourceBundle(final Locale locale) {
try {
return ResourceBundle.getBundle(getBundleName(), locale == null ? DEFAULT_LOCALE : locale);
} catch (final MissingResourceException e) {
LOG.error(e.getMessage(), e);
return null;
}
}
private ODataErrorMessage buildMessage(ResourceBundle bundle, Locale locale) {
String message = null;
try {
message = bundle.getString(getClass().getSimpleName() + '.' + messageKey.getKey());
StringBuilder builder = new StringBuilder();
Formatter f = new Formatter(builder, locale);
f.format(message, parameters);
f.close();
Locale usedLocale = bundle.getLocale();
if (Locale.ROOT.equals(usedLocale)) {
usedLocale = DEFAULT_LOCALE;
}
return new ODataErrorMessage(builder.toString(), usedLocale);
} catch (MissingResourceException e) {
return new ODataErrorMessage("Missing message for key '" + messageKey.getKey() + "'!", DEFAULT_LOCALE);
} catch (MissingFormatArgumentException e) {
return new ODataErrorMessage("Missing replacement for place holder in message '" + message +
"' for following arguments '" + Arrays.toString(parameters) + "'!", DEFAULT_LOCALE);
}
}
/** Error message text and {@link Locale} used for it. */
public class ODataErrorMessage {
String message;
Locale locale;
public ODataErrorMessage(final String message, final Locale usedLocale) {
this.message = message;
this.locale = usedLocale;
}
/** Gets the message text. */
public String getMessage() {
return message;
}
/** Gets the {@link Locale} used for this message. */
public Locale getLocale() {
return locale;
}
}
}