Possible fix for ALF-4409: Locale-independent properties can be given different locales

- 3.4 de-Hibernate problem
 - The DAO was not *ever* persisting '.default' so could give back different IDs for getOrCreateDefaultLocale().
 - Obviously, the NodeService (and all other clients) would expect the same ID for the default locale.
 - No need to change the NodeService property code - it's behaving correctly.


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@21985 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2010-08-25 08:41:22 +00:00
parent df45c7cb23
commit a82a04c9a6
3 changed files with 78 additions and 126 deletions

View File

@@ -81,21 +81,25 @@ public abstract class AbstractLocaleDAOImpl implements LocaleDAO
this.localeEntityCache = new EntityLookupCache<Long, String, String>(new LocaleEntityCallbackDAO()); this.localeEntityCache = new EntityLookupCache<Long, String, String>(new LocaleEntityCallbackDAO());
} }
/**
* {@inheritDoc}
*/
public Pair<Long, Locale> getLocalePair(Locale locale) public Pair<Long, Locale> getLocalePair(Locale locale)
{ {
if (locale == null)
{
throw new IllegalArgumentException("Locale cannot be null");
}
return getLocalePairImpl(locale); return getLocalePairImpl(locale);
} }
/**
* {@inheritDoc}
*/
public Pair<Long, Locale> getDefaultLocalePair() public Pair<Long, Locale> getDefaultLocalePair()
{ {
return getLocalePairImpl(null); return getLocalePairImpl(null);
} }
/**
* {@inheritDoc}
*/
public Pair<Long, Locale> getLocalePair(Long id) public Pair<Long, Locale> getLocalePair(Long id)
{ {
if (id == null) if (id == null)
@@ -108,42 +112,44 @@ public abstract class AbstractLocaleDAOImpl implements LocaleDAO
{ {
throw new DataIntegrityViolationException("No locale exists for ID " + id); throw new DataIntegrityViolationException("No locale exists for ID " + id);
} }
String localeStr = entityPair.getSecond();
// Convert the locale string to a locale // Convert the locale string to a locale
Locale locale = DefaultTypeConverter.INSTANCE.convert(Locale.class, entityPair.getSecond()); Locale locale = null;
if (LocaleEntity.DEFAULT_LOCALE_SUBSTITUTE.equals(localeStr))
{
locale = I18NUtil.getLocale();
}
else
{
locale = DefaultTypeConverter.INSTANCE.convert(Locale.class, entityPair.getSecond());
}
return new Pair<Long, Locale>(id, locale); return new Pair<Long, Locale>(id, locale);
} }
/**
* {@inheritDoc}
*/
public Pair<Long, Locale> getOrCreateLocalePair(Locale locale) public Pair<Long, Locale> getOrCreateLocalePair(Locale locale)
{ {
if (locale == null) return getOrCreateLocalePairImpl(locale);
{
throw new IllegalArgumentException("Locale cannot be null");
}
String localeStr = DefaultTypeConverter.INSTANCE.convert(String.class, locale);
Pair<Long, String> entityPair = localeEntityCache.getOrCreateByValue(localeStr);
if (entityPair == null)
{
throw new RuntimeException("Locale should have been created.");
}
return new Pair<Long, Locale>(entityPair.getFirst(), locale);
} }
/**
* {@inheritDoc}
*/
public Pair<Long, Locale> getOrCreateDefaultLocalePair() public Pair<Long, Locale> getOrCreateDefaultLocalePair()
{ {
Pair<Long, Locale> localePair = getDefaultLocalePair(); return getOrCreateLocalePairImpl(null);
if (localePair != null)
{
return localePair;
}
LocaleEntity localeEntity = new LocaleEntity();
localeEntity.setLocale(null);
return getOrCreateLocalePair(localeEntity.getLocale());
} }
/**
* Find the locale pair
*
* @param locale the locale to get or <tt>null</tt> to indicate the
* {@link LocaleEntity#DEFAULT_LOCALE_SUBSTITUTE default locale}.
* @return Returns the locale pair (ID, Locale) or <tt>null</tt> if not found.
*/
private Pair<Long, Locale> getLocalePairImpl(Locale locale) private Pair<Long, Locale> getLocalePairImpl(Locale locale)
{ {
// Null means look for the default // Null means look for the default
@@ -160,7 +166,7 @@ public abstract class AbstractLocaleDAOImpl implements LocaleDAO
if (localeStr == null) if (localeStr == null)
{ {
throw new IllegalArgumentException("Cannot look up entity by null ID."); throw new IllegalArgumentException("Cannot look up entity by null locale.");
} }
Pair<Long, String> entityPair = localeEntityCache.getByValue(localeStr); Pair<Long, String> entityPair = localeEntityCache.getByValue(localeStr);
@@ -174,6 +180,40 @@ public abstract class AbstractLocaleDAOImpl implements LocaleDAO
} }
} }
/**
* Find or create the locale pair
*
* @param locale the locale to get or <tt>null</tt> to indicate the
* {@link LocaleEntity#DEFAULT_LOCALE_SUBSTITUTE default locale}.
* @return Returns the locale pair (ID, Locale), never <tt>null
*/
private Pair<Long, Locale> getOrCreateLocalePairImpl(Locale locale)
{
// Null means look for the default
final String localeStr;
if (locale == null)
{
localeStr = LocaleEntity.DEFAULT_LOCALE_SUBSTITUTE;
locale = I18NUtil.getLocale();
}
else
{
localeStr = DefaultTypeConverter.INSTANCE.convert(String.class, locale);
}
if (localeStr == null)
{
throw new IllegalArgumentException("Cannot look up entity by null locale.");
}
Pair<Long, String> entityPair = localeEntityCache.getOrCreateByValue(localeStr);
if (entityPair == null)
{
throw new RuntimeException("Locale should have been created.");
}
return new Pair<Long, Locale>(entityPair.getFirst(), locale);
}
/** /**
* Callback for <b>alf_locale</b> DAO * Callback for <b>alf_locale</b> DAO
*/ */

View File

@@ -26,8 +26,8 @@ package org.alfresco.repo.domain.locale;
import java.util.Locale; import java.util.Locale;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.util.Pair; import org.alfresco.util.Pair;
import org.springframework.dao.DataIntegrityViolationException;
/** /**
* Data abstraction layer for Locale entities. * Data abstraction layer for Locale entities.
@@ -39,8 +39,8 @@ public interface LocaleDAO
{ {
/** /**
* @param id the unique ID of the entity * @param id the unique ID of the entity
* @return the locale (never null) * @return the locale pair (never null)
* @throws AlfrescoRuntimeException if the ID provided is invalid * @throws DataIntegrityViolationException if the ID provided is invalid
*/ */
Pair<Long, Locale> getLocalePair(Long id); Pair<Long, Locale> getLocalePair(Long id);
@@ -62,8 +62,7 @@ public interface LocaleDAO
* Gets the locale ID for an existing instance or creates a new entity if * Gets the locale ID for an existing instance or creates a new entity if
* one doesn't exist. * one doesn't exist.
* *
* @param id the locale to fetch or <tt>null</tt> to get or create the default * @param locale the locale to fetch or <tt>null</tt> to get or create the default locale.
* locale.
* @return the locale - never <tt>null</tt> * @return the locale - never <tt>null</tt>
*/ */
Pair<Long, Locale> getOrCreateLocalePair(Locale locale); Pair<Long, Locale> getOrCreateLocalePair(Locale locale);

View File

@@ -24,13 +24,7 @@
*/ */
package org.alfresco.repo.domain.locale; package org.alfresco.repo.domain.locale;
import java.util.Locale; import org.alfresco.util.EqualsHelper;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.springframework.extensions.surf.util.I18NUtil;
/** /**
@@ -49,15 +43,8 @@ public class LocaleEntity
private Long version; private Long version;
private String localeStr; private String localeStr;
private transient ReadLock refReadLock;
private transient WriteLock refWriteLock;
private transient Locale locale;
public LocaleEntity() public LocaleEntity()
{ {
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
refReadLock = lock.readLock();
refWriteLock = lock.writeLock();
} }
@Override @Override
@@ -95,16 +82,7 @@ public class LocaleEntity
} }
public void setLocaleStr(String localeStr) public void setLocaleStr(String localeStr)
{ {
refWriteLock.lock(); this.localeStr = localeStr;
try
{
this.localeStr = localeStr;
this.locale = null;
}
finally
{
refWriteLock.unlock();
}
} }
@Override @Override
@@ -123,77 +101,12 @@ public class LocaleEntity
return false; return false;
} }
LocaleEntity that = (LocaleEntity) obj; LocaleEntity that = (LocaleEntity) obj;
return (this.getLocale().equals(that.getLocale())); return EqualsHelper.nullSafeEquals(this.localeStr, that.localeStr);
} }
@Override @Override
public int hashCode() public int hashCode()
{ {
return getLocale().hashCode(); return localeStr == null ? 0 : localeStr.hashCode();
}
/**
* Lazily constructs a <code>Locale</code> instance referencing this entity
*/
public Locale getLocale()
{
// The default locale cannot be cached as it depends on the running thread's locale
if (localeStr == null || localeStr.equals(DEFAULT_LOCALE_SUBSTITUTE))
{
return I18NUtil.getLocale();
}
// first check if it is available
refReadLock.lock();
try
{
if (locale != null)
{
return locale;
}
}
finally
{
refReadLock.unlock();
}
// get write lock
refWriteLock.lock();
try
{
// double check
if (locale == null )
{
locale = DefaultTypeConverter.INSTANCE.convert(Locale.class, localeStr);
}
return locale;
}
finally
{
refWriteLock.unlock();
}
}
/**
* @param locale the locale to set or <tt>null</tt> to represent the default locale
*/
public void setLocale(Locale locale)
{
refWriteLock.lock();
try
{
if (locale == null)
{
this.localeStr = DEFAULT_LOCALE_SUBSTITUTE;
this.locale = null;
}
else
{
this.localeStr = DefaultTypeConverter.INSTANCE.convert(String.class, locale);
this.locale = locale;
}
}
finally
{
refWriteLock.unlock();
}
} }
} }