From ad84f95434e6e02d6da548e7a5a06f2edd36c66c Mon Sep 17 00:00:00 2001 From: quasi Date: Wed, 12 Oct 2011 08:30:30 +0000 Subject: [PATCH] Sprachinvariate ContentItems MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LangUtil: - supportedLanguage wird immer um "--" für die invarianten CIs erweitert, d.h. Invariante CIs werden immer unterstützt - trim() für alle LanguageStrings eingeführt, da sonst ein versehentliches Leerzeichen in der Config für die supportedLanguages das System in einen Fehler laufen läßt. iso639full.properties: - Eigentlich ist diese Datei überflüssig, aber in diesem Fall noch hilfreich, da ich den String für sprachinvariante CIs ("--") einfach eintragen konnte ContentBundle: - getInstance(String language), negotiate(...) und hasInstance(String language) so angepaßt, daß sie mit sprachunabhängigen CIs umgehen können AbstrctObjectList: - Filter in generateObjectListXML() geändert, so daß er auch auf sprachinvariante CI matched git-svn-id: https://svn.libreccm.org/ccm/trunk@1161 8810af33-2d31-482b-a856-94f89814c4df --- .../src/com/arsdigita/cms/ContentBundle.java | 295 ++++++++++-------- .../com/arsdigita/cms/util/LanguageUtil.java | 8 +- .../arsdigita/cms/util/iso639full.properties | 1 + .../navigation/ui/AbstractObjectList.java | 11 +- .../bundles/devel/cfg/project.xml | 3 +- 5 files changed, 175 insertions(+), 143 deletions(-) diff --git a/ccm-cms/src/com/arsdigita/cms/ContentBundle.java b/ccm-cms/src/com/arsdigita/cms/ContentBundle.java index 6c3a88934..af1945ef3 100755 --- a/ccm-cms/src/com/arsdigita/cms/ContentBundle.java +++ b/ccm-cms/src/com/arsdigita/cms/ContentBundle.java @@ -32,6 +32,8 @@ import com.arsdigita.kernel.permissions.PermissionService; import com.arsdigita.persistence.DataAssociation; import com.arsdigita.persistence.DataAssociationCursor; import com.arsdigita.persistence.DataObject; +import com.arsdigita.persistence.Filter; +import com.arsdigita.persistence.FilterFactory; import com.arsdigita.persistence.OID; import com.arsdigita.persistence.metadata.Property; import com.arsdigita.util.Assert; @@ -57,42 +59,37 @@ import org.apache.log4j.Logger; * @version $Id: ContentBundle.java 2140 2011-01-16 12:04:20Z pboy $ */ public class ContentBundle extends ContentItem { - - private static final Logger s_log = Logger.getLogger(ContentBundle.class); + private static final Logger s_log = Logger.getLogger(ContentBundle.class); private static DomainObjectObserver s_instancesObserver = - new AbstractDomainObjectObserver() { - public void add(DomainObject dom, String name, - DataObject dobj) { - if (INSTANCES.equals(name)) { - if (dobj != null) { - PermissionService.setContext(dobj.getOID(), dom.getOID()); + new AbstractDomainObjectObserver() { + + public void add(DomainObject dom, String name, + DataObject dobj) { + if (INSTANCES.equals(name)) { + if (dobj != null) { + PermissionService.setContext(dobj.getOID(), dom.getOID()); + } } } - } - }; - + }; /** * The base data object type of a bundle */ public static final String BASE_DATA_OBJECT_TYPE = "com.arsdigita.cms.ContentBundle"; - /** * The primary instances association */ public static final String INSTANCES = "instances"; - /** * The association to AtoZ aliases */ public static final String ATOZ_ALIASING_PROVIDERS = "atozAliasingProviders"; - /** * The default language property */ public static final String DEFAULT_LANGUAGE = "defaultLanguage"; - private boolean m_wasNew = false; /** @@ -101,7 +98,7 @@ public class ContentBundle extends ContentItem { public String getBaseDataObjectType() { return BASE_DATA_OBJECT_TYPE; } - + /** * Creates a new bundle. * @@ -109,16 +106,16 @@ public class ContentBundle extends ContentItem { */ public ContentBundle(final ContentItem primary) { super(BASE_DATA_OBJECT_TYPE); - + Assert.exists(primary, ContentItem.class); - + setDefaultLanguage(primary.getLanguage()); setContentType(primary.getContentType()); addInstance(primary); - + super.setName(primary.getName()); } - + /** * Retrieves a bundle. * @@ -127,7 +124,7 @@ public class ContentBundle extends ContentItem { public ContentBundle(final OID oid) throws DataObjectNotFoundException { super(oid); } - + /** * Retrieves a bundle. * @@ -135,10 +132,10 @@ public class ContentBundle extends ContentItem { * retrieve */ public ContentBundle(final BigDecimal id) - throws DataObjectNotFoundException { + throws DataObjectNotFoundException { this(new OID(BASE_DATA_OBJECT_TYPE, id)); } - + /** * Retrieves or creates a bundle using the DataObject * argument. @@ -149,7 +146,7 @@ public class ContentBundle extends ContentItem { public ContentBundle(final DataObject object) { super(object); } - + /** * Creates a bundle. * @@ -159,15 +156,13 @@ public class ContentBundle extends ContentItem { public ContentBundle(final String type) { super(type); } - - + protected ContentItem makeCopy() { final ContentBundle newItem = (ContentBundle) super.makeCopy(); - + final WorkflowTemplate template = - ContentTypeWorkflowTemplate.getWorkflowTemplate - (newItem.getContentSection(), newItem.getContentType()); - + ContentTypeWorkflowTemplate.getWorkflowTemplate(newItem.getContentSection(), newItem.getContentType()); + if (template != null) { s_log.debug("Setting up new workflow template"); ItemCollection instances = getInstances(); @@ -178,20 +173,20 @@ public class ContentBundle extends ContentItem { workflow.setObjectID(instance.getID()); workflow.start(Web.getContext().getUser()); workflow.save(); - + } } - + return newItem; } - + /** * Gets the default language of the bundle. */ public final String getDefaultLanguage() { return (String) get(DEFAULT_LANGUAGE); } - + /** * Sets the default language of the bundle. */ @@ -201,10 +196,10 @@ public class ContentBundle extends ContentItem { Assert.isTrue(language.length() == 2, language + " is not an ISO639 language code"); } - + set(DEFAULT_LANGUAGE, language); } - + /** * Adds a language instance to this bundle. This method will fail * if the bundle already contains a different instance for the @@ -222,22 +217,22 @@ public class ContentBundle extends ContentItem { if (s_log.isDebugEnabled()) { s_log.debug("Adding " + instance + " to bundle " + this); } - + if (Assert.isEnabled()) { Assert.exists(instance, ContentItem.class); Assert.isFalse(hasInstance(instance.getLanguage()), - "The bundle already contains an instance " + - "for the language " + instance.getLanguage()); + "The bundle already contains an instance " + + "for the language " + instance.getLanguage()); } - + instance.setParent(this); instance.setContentSection(getContentSection()); - + if (Assert.isEnabled()) { Assert.isEqual(this, instance.getParent()); } } - + /** * Removes a language instance from the bundle. This method will * fail if instance is the primary instance. @@ -256,14 +251,14 @@ public class ContentBundle extends ContentItem { Assert.isEqual(this, instance.getParent()); Assert.isNotEqual(instance, getPrimaryInstance()); } - + instance.setParent(null); - + if (Assert.isEnabled()) { Assert.isTrue(instance.getParent() == null); } } - + /** * Gets the primary instance of this bundle. * @@ -271,10 +266,10 @@ public class ContentBundle extends ContentItem { * the primary instance * @see #addInstance(ContentItem) */ - public final ContentItem getPrimaryInstance() { + public final ContentItem getPrimaryInstance() { return getInstance(getDefaultLanguage()); } - + /** * Produces a collection containing all language instances in this * bundle. @@ -284,7 +279,7 @@ public class ContentBundle extends ContentItem { public final ItemCollection getInstances() { return new ItemCollection(instances()); } - + /** * Returns a language instance for language or * null if no such instance exists. @@ -303,34 +298,49 @@ public class ContentBundle extends ContentItem { if (Assert.isEnabled()) { Assert.exists(language, String.class); Assert.isTrue(language.length() == 2, - language + " does not look like a valid language " + - "code"); + language + " does not look like a valid language " + + "code"); } - - final DataAssociationCursor instances = instances(); + + DataAssociationCursor instances = instances(); instances.addEqualsFilter(LANGUAGE, language); - + DataObject dataObject = null; - + if (instances.next()) { final DataObject data = instances.getDataObject(); - + if (Assert.isEnabled()) { //Assert.isFalse(instances.next(), // "There is more than one instance with the " + // "same language"); } - + instances.close(); - + return (ContentItem) DomainObjectFactory.newInstance(data); } else { + instances.close(); - + + // Look for language invariant version + instances = instances(); + instances.addEqualsFilter(LANGUAGE, "--"); + + if (instances.next()) { + final DataObject data = instances.getDataObject(); + + instances.close(); + + return (ContentItem) DomainObjectFactory.newInstance(data); + } else { + instances.close(); + } + return null; } } - + /** * Tells whether instance is present in the bundle. * @@ -339,13 +349,13 @@ public class ContentBundle extends ContentItem { */ public final boolean hasInstance(final ContentItem instance) { Assert.exists(instance, ContentItem.class); - + final DataAssociationCursor instances = instances(); instances.addEqualsFilter(ID, instance.getID()); - + return !instances.isEmpty(); } - + /** * Utility method to check if this bundle already contains an * instance for the given language. @@ -361,13 +371,17 @@ public class ContentBundle extends ContentItem { Assert.isTrue(language.length() == 2, language + " is not an ISO639 language code"); } - + final DataAssociationCursor instances = instances(); - instances.addEqualsFilter(LANGUAGE, language); - +// instances.addEqualsFilter(LANGUAGE, language); + FilterFactory ff = instances.getFilterFactory(); + Filter filter = ff.or(). + addFilter(ff.equals("language", language)). + addFilter(ff.equals("language", "--")); + instances.addFilter(filter); return !instances.isEmpty(); } - + /** * List all languages in which this item is available, i.e. the * language codes of all instances in this bundle. @@ -379,24 +393,24 @@ public class ContentBundle extends ContentItem { // XXX For LIVE bundles, there might be several PENDING // instances with the same language. Maybe we should filter // these out and return only one? - + final ItemCollection items = getInstances(); - + final Collection list = new ArrayList(); - + while (items.next()) { list.add(items.getLanguage()); } - + items.close(); - + if (Assert.isEnabled()) { Assert.isTrue(!list.isEmpty() || getInstances().isEmpty()); } - + return list; } - + /** * Negotiate the right language instance for this bundle and return it. * @@ -407,7 +421,6 @@ public class ContentBundle extends ContentItem { * locales * @pre locales != null */ - // Quasimodo: // Is this method ever used? Netbeans couldn't find anything. public ContentItem negotiate(Locale[] locales) { @@ -423,28 +436,36 @@ public class ContentBundle extends ContentItem { language = (String) dataObject.get(LANGUAGE); // If language is not one of the supported languages, skip this entry - if(!supportedLanguages.contains(language)) { + if (!supportedLanguages.contains(language)) { continue; } if (s_log.isDebugEnabled()) { s_log.debug("negotiate: language= " + language); } - + if (language != null) { - for (int i=0; i < locales.length; i++) { - if (language.equals(locales[i].getLanguage())) { - if (i < bestMatch || matchingInstance == null) { - bestMatch = i; - matchingInstance = dataObject; - if (s_log.isDebugEnabled()) { - s_log.debug("negotiate: " - + "bestMatch= " + i - + ", language= " + language); - } - } // else other match with less preferred language found - } - } // end for + // If the current object is languange invariant and no better + // match is already found, match it with the lowest priority + if (language.equals("--") && matchingInstance == null) { + bestMatch = locales.length; + matchingInstance = dataObject; + } else { + // In any other case + for (int i = 0; i < locales.length; i++) { + if (language.equals(locales[i].getLanguage())) { + if (i < bestMatch || matchingInstance == null) { + bestMatch = i; + matchingInstance = dataObject; + if (s_log.isDebugEnabled()) { + s_log.debug("negotiate: " + + "bestMatch= " + i + + ", language= " + language); + } + } // else other match with less preferred language found + } + } // end for + } } // end if if (bestMatch == 0 && matchingInstance != null) { s_log.debug("negotiate: best possible match found, exiting"); @@ -453,14 +474,13 @@ public class ContentBundle extends ContentItem { } instancesCursor.close(); if (matchingInstance != null) { - return (ContentItem) DomainObjectFactory.newInstance - (matchingInstance); + return (ContentItem) DomainObjectFactory.newInstance(matchingInstance); } else { s_log.info("negotiate: no match found!"); return null; } } - + /** * Negotiate the right language instance for this bundle and return it. * @@ -481,36 +501,42 @@ public class ContentBundle extends ContentItem { Locale loc = null; List languageCodes = new ArrayList(); for (int i = 0; locales.hasMoreElements(); i++) { - loc = (Locale)locales.nextElement(); + loc = (Locale) locales.nextElement(); // Quasimodo: // Only add languages to the List which are supported by cms - if(supportedLanguages.contains(loc.getLanguage())) { - languageCodes.add( loc.getLanguage()); + if (supportedLanguages.contains(loc.getLanguage())) { + languageCodes.add(loc.getLanguage()); } + if (s_log.isDebugEnabled()) { - s_log.debug("negotiate: pref " + i + ": "+ loc.getLanguage()); + s_log.debug("negotiate: pref " + i + ": " + loc.getLanguage()); } } - + + // Add unspecified language for language invariant objects + if (supportedLanguages.contains("--")) { + languageCodes.add("--"); + } + final DataAssociationCursor instances = instances(); - + DataObject dataObject = null; int bestMatch = 0; DataObject match = null; String language = null; - + while (instances.next()) { dataObject = instances.getDataObject(); language = (String) dataObject.get(LANGUAGE); - + if (s_log.isDebugEnabled()) { s_log.debug("negotiate: language= " + language); } - + if (language != null) { - for (int i=0; i < languageCodes.size(); i++) { - if (language.equals( (String)languageCodes.get(i) )) { + for (int i = 0; i < languageCodes.size(); i++) { + if (language.equals((String) languageCodes.get(i))) { if (i < bestMatch || match == null) { bestMatch = i; match = dataObject; @@ -523,58 +549,56 @@ public class ContentBundle extends ContentItem { } } // end for } // end if - + if (bestMatch == 0 && match != null) { s_log.debug("negotiate: best possible match found, exiting"); break; // exit loop when best match is found } } - + instances.close(); - + return (ContentItem) DomainObjectFactory.newInstance(match); } - + // Methods from item that bundle overrides - protected void beforeSave() { super.beforeSave(); - + final ContentItem primary = getPrimaryInstance(); - + Assert.exists(getContentType(), ContentType.class); - + if (primary != null) { primary.setContentSection(getContentSection()); } } - + protected boolean canPublishToFS() { return false; } - + protected void publishToFS() { throw new UnsupportedOperationException(); } - + public ContentItem publish(final LifecycleDefinition definition, final Date start) { throw new UnsupportedOperationException(); } - + public Lifecycle getLifecycle() { // Bundles do not have lifecycles. - + return null; } - + public void setLifecycle(final Lifecycle lifecycle) { // I'd like to do the following, but VersionCopier calls // setLifecycle. //throw new UnsupportedOperationException(); } - - + /** * Ignore the INSTANCES property for * ItemCopier.VERSION_COPY. @@ -597,57 +621,56 @@ public class ContentBundle extends ContentItem { return true; } } - + return super.copyProperty(source, property, copier); } - + public boolean copyServices(final ContentItem source) { if (s_log.isDebugEnabled()) { - s_log.debug("Copying services on bundle " + getName() + " " + - getID() + " using source " + source.getID()); + s_log.debug("Copying services on bundle " + getName() + " " + + getID() + " using source " + source.getID()); } - + // Copy categories CategoryCollection categories = source.getCategoryCollection(); - while (categories.next() ) { + while (categories.next()) { final Category category = categories.getCategory(); category.addChild(this); category.save(); // XXX remove me } categories.close(); - + return true; } - + protected void initialize() { super.initialize(); addObserver(s_instancesObserver); - + m_wasNew = isNew(); } - + protected void afterSave() { if (m_wasNew) { getPrimaryInstance().setContentSection(getContentSection()); } - + super.afterSave(); } - + // Utility methods - private DataAssociationCursor instances() { final DataAssociationCursor cursor = ((DataAssociation) super.get(INSTANCES)).cursor(); - + return cursor; } - + private DataAssociationCursor instances(final String version) { final DataAssociationCursor cursor = instances(); - + cursor.addEqualsFilter(VERSION, version); - + return cursor; } } diff --git a/ccm-cms/src/com/arsdigita/cms/util/LanguageUtil.java b/ccm-cms/src/com/arsdigita/cms/util/LanguageUtil.java index e008bf14b..254780786 100755 --- a/ccm-cms/src/com/arsdigita/cms/util/LanguageUtil.java +++ b/ccm-cms/src/com/arsdigita/cms/util/LanguageUtil.java @@ -63,7 +63,7 @@ public class LanguageUtil { * at the server startup */ public static void setSupportedLanguages(String languages) { - s_languages = languages; + s_languages = languages + ",--"; } /** Get the comma separated list of all supported languages */ @@ -80,7 +80,7 @@ public class LanguageUtil { StringTokenizer tokenizer = new StringTokenizer(allLanguages , ","); Collection langList = new LinkedList(); while (tokenizer.hasMoreElements()) { - String language = tokenizer.nextToken(); + String language = tokenizer.nextToken().trim(); langList.add(language); } return langList; @@ -95,7 +95,7 @@ public class LanguageUtil { StringTokenizer tokenizer = new StringTokenizer(allLanguages , ","); Collection langList = new LinkedList(); while (tokenizer.hasMoreElements()) { - String language = tokenizer.nextToken(); + String language = tokenizer.nextToken().trim(); langList.add(new Pair(language , getLang3LA(language))); } return langList; @@ -110,7 +110,7 @@ public class LanguageUtil { StringTokenizer tokenizer = new StringTokenizer(allLanguages , ","); Collection langList = new LinkedList(); while (tokenizer.hasMoreElements()) { - String language = tokenizer.nextToken(); + String language = tokenizer.nextToken().trim(); langList.add(new Pair(language , getLangFull(language))); } return langList; diff --git a/ccm-cms/src/com/arsdigita/cms/util/iso639full.properties b/ccm-cms/src/com/arsdigita/cms/util/iso639full.properties index dbd0f8260..56d1e2d1a 100755 --- a/ccm-cms/src/com/arsdigita/cms/util/iso639full.properties +++ b/ccm-cms/src/com/arsdigita/cms/util/iso639full.properties @@ -138,3 +138,4 @@ yo=Yoruba za=Zhuang zh=Chinese zu=Zulu +--=Undefined diff --git a/ccm-ldn-navigation/src/com/arsdigita/london/navigation/ui/AbstractObjectList.java b/ccm-ldn-navigation/src/com/arsdigita/london/navigation/ui/AbstractObjectList.java index 203ca2384..f0ddc3036 100755 --- a/ccm-ldn-navigation/src/com/arsdigita/london/navigation/ui/AbstractObjectList.java +++ b/ccm-ldn-navigation/src/com/arsdigita/london/navigation/ui/AbstractObjectList.java @@ -24,6 +24,8 @@ import com.arsdigita.london.navigation.DataCollectionRenderer; import com.arsdigita.persistence.DataCollection; +import com.arsdigita.persistence.Filter; +import com.arsdigita.persistence.FilterFactory; import com.arsdigita.util.Assert; import com.arsdigita.util.UncheckedWrapperException; @@ -94,9 +96,14 @@ public abstract class AbstractObjectList DataCollection objects = getObjects(request, response); // Quasimodo: Begin - // Limit list to objects in the negotiated language + // Limit list to objects in the negotiated language and language invariant items if (objects != null && objects.size() > 0) { - objects.addEqualsFilter("language", com.arsdigita.globalization.GlobalizationHelper.getNegotiatedLocale().getLanguage()); + FilterFactory ff = objects.getFilterFactory(); + Filter filter = ff.or(). + addFilter(ff.equals("language", com.arsdigita.globalization.GlobalizationHelper.getNegotiatedLocale().getLanguage())). + addFilter(ff.equals("language", "--")); + objects.addFilter(filter); +// objects.addEqualsFilter("language", com.arsdigita.globalization.GlobalizationHelper.getNegotiatedLocale().getLanguage()); } // Quasimodo: End diff --git a/ccm-quasi-aplaws/bundles/devel/cfg/project.xml b/ccm-quasi-aplaws/bundles/devel/cfg/project.xml index 4cdcdf6bb..b3ca1d1f0 100644 --- a/ccm-quasi-aplaws/bundles/devel/cfg/project.xml +++ b/ccm-quasi-aplaws/bundles/devel/cfg/project.xml @@ -94,7 +94,8 @@ - + +