/*
* $Id: IWResourceBundle.java,v 1.55 2009/05/27 09:45:29 laddi Exp $
*
* Copyright (C) 2001-2005 Idega hf. All Rights Reserved.
*
* This software is the proprietary information of Idega hf. Use is subject to
* license terms.
*
*/
package com.idega.idegaweb;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.MissingResourceException;
import java.util.Properties;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.logging.Level;
import javax.naming.OperationNotSupportedException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import com.idega.exception.IWBundleDoesNotExist;
import com.idega.presentation.IWContext;
import com.idega.presentation.Image;
import com.idega.util.CoreConstants;
import com.idega.util.CoreUtil;
import com.idega.util.EnumerationIteratorWrapper;
import com.idega.util.FileUtil;
import com.idega.util.SortedProperties;
import com.idega.util.StringHandler;
import com.idega.util.messages.MessageResource;
import com.idega.util.messages.MessageResourceImportanceLevel;
/**
* <p>
* This is an idegaWeb representation of a localization folder/file for each
* locale in an idegaWeb Bundle.<br/> There is an instance of this class for
* each localization file (e.g.
* com.idega.core.bundle/en.locale/Localized.strings) and is an extension to the
* standard Java ResourceBundle.
* </p>
* Last modified: $Date: 2009/05/27 09:45:29 $ by $Author: laddi $<br/>
*
* @author <a href="mailto:tryggvil@idega.com">Tryggvi Larusson</a>
* @version $Revision: 1.55 $
*/
@Service
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class IWResourceBundle extends ResourceBundle implements MessageResource, Serializable {
private static final long serialVersionUID = 2495736573750344100L;
public static final String RESOURCE_IDENTIFIER = "bundle_resource";
// ==================privates====================
private Map<String, String> lookup;
private Properties properties;
private Locale locale;
private File file;
private IWBundle iwBundleParent;
private String resourcesURL;
private String identifier;
private Level usagePriorityLevel;
private boolean autoInsert;
private String bundleIdentifier;
/**
* Empty constructor for use in extending classes
*
*/
public IWResourceBundle() {
initProperities();
}
/**
* Creates a IWResourceBundle for a specific Locale
*
* @param file
* file to read from.
* @param parent
* Parent IWBundle to instanciate from
* @param locale
* Locale to create from
*/
public IWResourceBundle(IWBundle parent, File file, Locale locale) throws IOException {
this();
initialize(parent, new FileInputStream(file), file, locale);
}
public IWResourceBundle(IWBundle parent, InputStream stream, Locale locale) throws IOException {
this();
initialize(parent,stream,null,locale);
}
/**
* <p>
* This constructor is used for locale variants, and the parent resourceBundle
* includes the default localizations.
* </p>
*/
public IWResourceBundle(IWResourceBundle parent, File file, Locale locale) throws IOException {
this(parent.getIWBundleParent(), file, locale);
setParent(parent);
}
/**
* <p>
* This constructor is used for locale variants, and the parent resourceBundle
* includes the default localizations.
* </p>
*/
public IWResourceBundle(IWResourceBundle parent, InputStream inputStream, Locale locale) throws IOException {
this(parent.getIWBundleParent(), inputStream, locale);
setParent(parent);
}
protected void initProperities() {
setIdentifier(RESOURCE_IDENTIFIER);
setLevel(MessageResourceImportanceLevel.LAST_ORDER);
setAutoInsert(false);
}
/**
* <p>
* TODO tryggvil describe method initialize
* </p>
* @param parent
* @param file
* @param locale
* @throws IOException
*/
protected void initialize(IWBundle parent, InputStream streamForRead, File file, Locale locale) throws IOException {
setIWBundleParent(parent);
setLocale(locale);
this.file = file;
try {
this.properties = new SortedProperties();
this.properties.load(streamForRead);
}
catch (FileNotFoundException e) {
// System.err.println("IWResourceBundle: File Not
// Found:"+file.getAbsolutePath());
}
this.lookup = new TreeMap<String, String>();
for (Entry<Object, Object> entry: this.properties.entrySet()) {
lookup.put(entry.getKey().toString(), entry.getValue().toString());
}
setResourcesURL(parent.getResourcesVirtualPath() + "/" + locale.toString() + ".locale");
}
public void initialize(String bundleIdentifier, Locale newLocale) throws IOException, OperationNotSupportedException {
if(bundleIdentifier == null || bundleIdentifier.equals(MessageResource.NO_BUNDLE)) {
throw new OperationNotSupportedException("Empty bundle is not supported supported");
} else {
setBundleIdentifier(bundleIdentifier);
IWContext iwc = IWContext.getCurrentInstance();
if(newLocale == null)
newLocale = iwc.getCurrentLocale();
IWBundle bundle = getIWMainApplication().getBundle(bundleIdentifier);
if (IWMainApplicationSettings.isAutoCreateStringsActive()) {
file = FileUtil.getFileAndCreateIfNotExists(bundle.getResourcesRealPath(newLocale), getLocalizedStringsFileName());
}
else {
file = new File(bundle.getResourcesRealPath(newLocale), getLocalizedStringsFileName());
}
// setAutoInsert(iwc.getApplicationSettings().getBoolean(AUTO_INSERT_PROPERTY, false));
initialize(bundle, new FileInputStream(file), file, newLocale);
}
}
/**
* Override of ResourceBundle, same semantics
*/
@Override
public Object handleGetObject(String key) {
if (this.lookup != null) {
Object obj = this.lookup.get(key);
return obj; // once serialization is in place, you can do non-strings
}
else {
IWBundle parent = getIWBundleParent();
if (parent != null) {
throw new IWBundleDoesNotExist(parent.getBundleIdentifier());
}
else {
throw new IWBundleDoesNotExist();
}
}
}
/**
* Implementation of ResourceBundle.getKeys.
*/
@Override
public Enumeration<String> getKeys() {
Enumeration<String> result = null;
if (this.parent != null) {
Iterator<String> iter = this.lookup.keySet().iterator();
final Enumeration<String> myKeys = new EnumerationIteratorWrapper<String>(iter);
final Enumeration<String> parentKeys = this.parent.getKeys();
result = new Enumeration<String>() {
public boolean hasMoreElements() {
if (this.temp == null) {
nextElement();
}
return this.temp != null;
}
public String nextElement() {
String returnVal = this.temp;
if (myKeys.hasMoreElements()) {
this.temp = myKeys.nextElement();
}
else {
this.temp = null;
while (this.temp == null && parentKeys.hasMoreElements()) {
this.temp = parentKeys.nextElement();
if (IWResourceBundle.this.lookup.containsKey(this.temp)) {
this.temp = null;
}
}
}
return returnVal;
}
String temp = null;
};
}
else {
Iterator<String> iter = this.lookup.keySet().iterator();
result = new EnumerationIteratorWrapper<String>(iter);
}
return result;
}
@Override
public Locale getLocale() {
return this.locale;
}
protected void setLocale(Locale locale) {
this.locale = locale;
}
public synchronized void storeState() {
if(file!=null){
try {
this.properties.clear();
if (this.lookup != null) {
for (String key: this.lookup.keySet()) {
if (key != null) {
Object value = this.lookup.get(key);
if (value != null) {
this.properties.put(key, value);
}
}
}
if (!this.file.exists()) {
this.file.createNewFile();
System.out.println("IWResourceBundle: Created new file: " + this.file.getAbsolutePath());
}
FileOutputStream fos = new FileOutputStream(this.file);
this.properties.store(fos, null);
fos.close();
}
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException ex) {
ex.printStackTrace();
}
}
else{
System.out.println("IWResourceBundle: Cannot save, was nat read from file ");
}
}
/**
* Uses factory to get localisedMessage from all available message resources
* @deprecated IWMainApplication.getLocalisedStringMessage should be used instead
* @param key
* @return found string
*/
@Deprecated
public String getLocalizedString(String key) {
String bundleIdentifier = getIWBundleParent().getBundleIdentifier();
Locale locale = CoreUtil.getIWContext().getCurrentLocale();
return getIWBundleParent().getApplication().getLocalisedStringMessage(key, null, bundleIdentifier, locale);
}
/**
* Uses getString but returns null if resource is not found
*
* @param key
* @return
*/
protected String getBundleLocalizedString(String key) {
try {
return super.getString(key);
}
catch (MissingResourceException e) {
return null;
}
}
/**
* Gets a localized string value and sets the value as returnValueIfNotFound if it is previously not found and returns it. <br/>
* However if e.g. an english version does not exist for the english local the value from Localizable.strings is used, unless it is null or empty then returnValueIfNotFound is used<br/>
*
* @param key
* @param returnValueIfNotFound
* @return a string localized in the IWRB locale or the default value from Localizable.strings or the returnValueIfNotFound if that is null or empty.
*/
public String getLocalizedString(String key, String returnValueIfNotFound) {
return getLocalizedString(locale == null ? CoreUtil.getIWContext().getCurrentLocale() : locale, key, returnValueIfNotFound);
}
public String getLocalizedString(Locale locale, String key, String returnValueIfNotFound) {
String bundleIdentifier = getIWBundleParent().getBundleIdentifier();
IWMainApplication iwma = IWMainApplication.defaultIWMainApplication;
return iwma.getLocalisedStringMessage(key, returnValueIfNotFound, bundleIdentifier, locale);
}
/**
* Gets a localized string value and sets the value as returnValueIfNotFound if it is previously not found and returns it. <br/>
* However if e.g. an english version does not exist for the english local the value from Localizable.strings is used, unless it is null or empty then returnValueIfNotFound is used<br/>
*
* @param key
* @param returnValueIfNotFound
* @return a string localized in the IWRB locale or the default value from Localizable.strings or the returnValueIfNotFound if that is null or empty.
*/
private String getBundleLocalizedString(String key, String returnValueIfNotFound) {
String returnString = getBundleLocalizedString(key);
if (((returnString == null) || StringHandler.EMPTY_STRING.equals(returnString))) {
IWBundle bundle = getIWBundleParent();
String value = bundle.getLocalizableStringDefaultValue(key);
if( value==null || ("".equals(value) && (returnValueIfNotFound!=null)) ){
return returnValueIfNotFound;
}
else{
return value;
}
} else {
return returnString;
}
}
/**
* * Gets a localized stringvalue and sets the value as returnValueIfNotFound
* if it is previously not found and <br>
* THEN formats the string using
* java.text.MessageFormat.format(thestring,arrayofvariables).<br>
* The variables in the array then replace varibles in the localized string
* <br>
* For example: the localized string : "Hello my name is {0}" and the array
* contains object that implements the toString() method.<br>
* When we call java.text.MessageFormat.format(thestring,arrayofvariables) the
* variable {0} is then replaced with the arrayofvariables[0].toString() item
* of the array.<br>
*
* @param key
* @param returnValueIfNotFound
* @param messageFormatVariables
* an Object array of .toString() implementing objects
* @return the string localized and formatted
*/
public String getLocalizedAndFormattedString(String key, String returnValueIfNotFound, Object[] messageFormatVariables) {
String localizedAndFormatted = getLocalizedString(key, returnValueIfNotFound);
if (messageFormatVariables != null) {
localizedAndFormatted = MessageFormat.format(localizedAndFormatted, messageFormatVariables);
}
return localizedAndFormatted;
}
/**
* Uses getLocalizedString but returns null if resource is not found
*/
public Image getLocalizedImageButton(String key) {
try {
String text = getLocalizedString(key);
return this.iwBundleParent.getApplication().getImageFactory().createButton(text, this.iwBundleParent, getLocale());
}
catch (MissingResourceException e) {
return null;
}
}
public Image getLocalizedImageButton(String key, String returnValueIfNull) {
String text = getLocalizedString(key, returnValueIfNull);
return this.iwBundleParent.getApplication().getImageFactory().createButton(text, this.iwBundleParent, getLocale());
}
/**
* Uses getLocalizedString but returns null if resource is not found
*/
public Image getLocalizedImageTab(String key, boolean flip) {
try {
String text = getLocalizedString(key);
return this.iwBundleParent.getApplication().getImageFactory().createTab(text, this.iwBundleParent, getLocale(), flip);
}
catch (MissingResourceException e) {
return null;
}
}
public Image getLocalizedImageTab(String key, String returnValueIfNull, boolean flip) {
String text = getLocalizedString(key, returnValueIfNull);
return this.iwBundleParent.getApplication().getImageFactory().createTab(text, this.iwBundleParent, getLocale(), flip);
}
/**
* Sets a value of a string key in this ResourceBundle. Stores the files
* implicitly (storeState()) to the diskafter a call to this method.
*
* @param key
* a String key
* @param value
* a value to the key
*/
public void setString(String key, String value) {
this.lookup.put(key, value);
checkBundleLocalizedString(key, value);
storeState();
}
public void setStrings(Map<String, String> values) {
for(String key : values.keySet()) {
this.lookup.put(key, values.get(key));
checkBundleLocalizedString(key, values.get(key));
}
storeState();
}
public boolean removeString(String key) {
if (this.lookup.remove(key) != null) {
storeState();
return true;
}
return false;
}
private void setIWBundleParent(IWBundle parent) {
this.iwBundleParent = parent;
}
public IWBundle getIWBundleParent() {
return this.iwBundleParent;
}
/*
* Returns the Resource URI for the image with the internal url urlInBundle
* inside the resource bundle
*/
public String getImageURI(String urlInBundle) {
StringBuffer buf = new StringBuffer(getResourcesURL());
if(!urlInBundle.startsWith(CoreConstants.SLASH)){
buf.append(CoreConstants.SLASH);
}
buf.append(urlInBundle);
return buf.toString();
}
public Image getImage(String urlInBundle) {
return new Image(getImageURI(urlInBundle));
}
public Image getImage(String urlInBundle, int width, int height) {
return getImage(urlInBundle, "", width, height);
}
public Image getImage(String urlInBundle, String name, int width, int height) {
return new Image(getResourcesURL() + CoreConstants.SLASH + urlInBundle, name, width, height);
}
public Image getImage(String urlInBundle, String overUrlInBundle, String imageName, String overImageName) {
return new Image(imageName, getResourcesURL() + CoreConstants.SLASH + urlInBundle, getResourcesURL() + CoreConstants.SLASH + overUrlInBundle);
}
public Image getImage(String urlInBundle, String overUrlInBundle, String name, int width, int height) {
Image returnImage = new Image(name, getResourcesURL() + CoreConstants.SLASH + urlInBundle, getResourcesURL() + CoreConstants.SLASH + overUrlInBundle);
returnImage.setWidth(width);
returnImage.setHeight(height);
return returnImage;
}
public Image getImage(String urlInBundle, String name) {
return new Image(getResourcesURL() + CoreConstants.SLASH + urlInBundle, name);
}
public Image getImage(String urlInBundle, String key, String defaultKeyValue) {
return new Image(getResourcesURL() + CoreConstants.SLASH + urlInBundle, getLocalizedString(key, defaultKeyValue));
}
private void setResourcesURL(String url) {
this.resourcesURL = url;
}
public String getResourcesURL() {
return this.resourcesURL;
}
public void setLocalizedString(String key, String value) {
this.setString(key, value);
}
protected boolean checkBundleLocalizedString(String key, String value) {
IWBundle bundle = getIWBundleParent();
if (!bundle.containsLocalizedString(key)) {
bundle.addLocalizableString(key, value);
try {
((DefaultIWBundle) bundle).storeLocalizableStrings();
}
catch (ClassCastException ce) {
System.err.println("Cant store LocalizableStrings becauase bundle " + bundle.getBundleIdentifier() + " is not subclass of DefaultIWBundle");
ce.printStackTrace();
}
return true;
}
return false;
}
@Override
public String toString() {
IWBundle bundleParent = this.getIWBundleParent();
if (bundleParent != null) {
return bundleParent + CoreConstants.SLASH + this.locale;
}
else {
return this.locale.toString();
}
}
/**
* @return the parentResourceBundle
*/
public IWResourceBundle getParentResourceBundle() {
return (IWResourceBundle) this.parent;
}
/**
* @param parentResourceBundle
* the parentResourceBundle to set
*/
public void setParentResourceBundle(IWResourceBundle parentResourceBundle) {
super.setParent(parentResourceBundle);
}
protected Map<String, String> getLookup() {
return lookup;
}
protected void setLookup(Map<String, String> lookup) {
this.lookup = lookup;
}
protected Properties getProperties() {
return properties;
}
/**
* @return object that was found in resource or null if nothing is found
*/
public Object getMessage(Object key) {
return getBundleLocalizedString(String.valueOf(key), null);
}
/**
* @return object that was set or null if there was a failure setting object
*/
public Object setMessage(Object key, Object value) {
try {
setString(String.valueOf(key), String.valueOf(value));
return value;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public void setMessages(Map<Object, Object> values) {
try {
Map<String, String> stringMap = new HashMap<String, String>();
for(Object key : values.keySet()) {
stringMap.put(String.valueOf(key), String.valueOf(values.get(key)));
}
setStrings(stringMap);
} catch (Exception e) {
e.printStackTrace();
}
}
//TODO use IWBundle class method
private String getLocalizedStringsFileName(){
return "Localized.strings";
}
@SuppressWarnings("unchecked")
public Set<String> getAllLocalisedKeys() {
if(getBundleIdentifier() != null && !getBundleIdentifier().equals(MessageResource.NO_BUNDLE)) {
IWBundle bundle = getIWMainApplication().getBundle(getBundleIdentifier());
String[] str = bundle.getLocalizableStrings();
return new TreeSet<String>(Arrays.asList(str));
} else {
return getLookup().keySet();
}
}
public void removeMessage(Object key) {
getLookup().remove(key);
this.storeState();
}
private IWMainApplication getIWMainApplication() {
IWContext iwc = IWContext.getCurrentInstance();
IWMainApplication iwma = iwc == null ? IWMainApplication.getDefaultIWMainApplication() : iwc.getApplicationContext().getIWMainApplication();
return iwma;
}
public String getIdentifier() {
return identifier;
}
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
public Level getLevel() {
return usagePriorityLevel;
}
public boolean isAutoInsert() {
return autoInsert;
}
public void setAutoInsert(boolean value) {
autoInsert = value;
}
public void setLevel(Level priorityLevel) {
usagePriorityLevel = priorityLevel;
}
public String getBundleIdentifier() {
return bundleIdentifier;
}
public void setBundleIdentifier(String bundleIdentifier) {
this.bundleIdentifier = bundleIdentifier;
}
private void writeObject(ObjectOutputStream out) throws IOException {
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
}
}