CCM NG/ccm-cms: AssetForm including localisation for assets
git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@4663 8810af33-2d31-482b-a856-94f89814c4df
Former-commit-id: ee7280dc6b
pull/2/head
parent
65c0776a67
commit
2ece488abb
|
|
@ -18,18 +18,27 @@
|
|||
*/
|
||||
package com.arsdigita.cms.ui.assets;
|
||||
|
||||
import com.arsdigita.bebop.BoxPanel;
|
||||
import com.arsdigita.bebop.ColumnPanel;
|
||||
import com.arsdigita.bebop.Form;
|
||||
import com.arsdigita.bebop.FormProcessException;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.Page;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.SaveCancelSection;
|
||||
import com.arsdigita.bebop.SingleSelectionModel;
|
||||
import com.arsdigita.bebop.Text;
|
||||
import com.arsdigita.bebop.event.FormInitListener;
|
||||
import com.arsdigita.bebop.event.FormProcessListener;
|
||||
import com.arsdigita.bebop.event.FormSectionEvent;
|
||||
import com.arsdigita.bebop.event.FormSubmissionListener;
|
||||
import com.arsdigita.bebop.event.PrintEvent;
|
||||
import com.arsdigita.bebop.event.PrintListener;
|
||||
import com.arsdigita.bebop.form.Option;
|
||||
import com.arsdigita.bebop.form.SingleSelect;
|
||||
import com.arsdigita.bebop.form.Submit;
|
||||
import com.arsdigita.bebop.form.TextField;
|
||||
import com.arsdigita.bebop.parameters.StringParameter;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
import com.arsdigita.kernel.KernelConfig;
|
||||
|
||||
|
|
@ -39,9 +48,16 @@ import org.librecms.contentsection.Asset;
|
|||
import org.librecms.contentsection.AssetRepository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.libreccm.categorization.CategoryManager;
|
||||
import org.libreccm.core.UnexpectedErrorException;
|
||||
import org.librecms.assets.AssetL10NManager;
|
||||
import org.librecms.contentsection.Folder;
|
||||
import org.librecms.contentsection.FolderManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.TooManyListenersException;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -55,6 +71,15 @@ public abstract class AssetForm extends Form implements FormInitListener,
|
|||
|
||||
private final AssetPane assetPane;
|
||||
private final SingleSelectionModel<Long> selectionModel;
|
||||
// private final StringParameter selectedLocaleParameter;
|
||||
|
||||
private BoxPanel showLocalePanel;
|
||||
private SingleSelect showLocaleSelect;
|
||||
private Submit showLocaleSubmit;
|
||||
|
||||
private BoxPanel addLocalePanel;
|
||||
private SingleSelect addLocaleSelect;
|
||||
private Submit addLocaleSubmit;
|
||||
|
||||
private TextField title;
|
||||
private SaveCancelSection saveCancelSection;
|
||||
|
|
@ -64,11 +89,146 @@ public abstract class AssetForm extends Form implements FormInitListener,
|
|||
|
||||
this.assetPane = assetPane;
|
||||
selectionModel = assetPane.getSelectedAssetModel();
|
||||
// selectedLocaleParameter = new StringParameter("selected-locale");
|
||||
|
||||
initComponents();
|
||||
}
|
||||
|
||||
private void initComponents() {
|
||||
|
||||
showLocalePanel = new BoxPanel(BoxPanel.HORIZONTAL);
|
||||
final Label showLocaleLabel = new Label(new PrintListener() {
|
||||
|
||||
@Override
|
||||
public void prepare(final PrintEvent event) {
|
||||
final PageState state = event.getPageState();
|
||||
final Optional<Asset> selectedAsset = getSelectedAsset(state);
|
||||
final Label target = (Label) event.getTarget();
|
||||
if (selectedAsset.isPresent()) {
|
||||
target.setLabel(new GlobalizedMessage(
|
||||
"cms.ui.assest.show_locale",
|
||||
CmsConstants.CMS_BUNDLE));
|
||||
} else {
|
||||
target.setLabel(new GlobalizedMessage(
|
||||
"cms.ui.assest.initial_locale",
|
||||
CmsConstants.CMS_BUNDLE));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
);
|
||||
showLocaleSelect = new SingleSelect("selected-locale");
|
||||
try {
|
||||
showLocaleSelect.addPrintListener(new PrintListener() {
|
||||
|
||||
@Override
|
||||
public void prepare(final PrintEvent event) {
|
||||
final PageState state = event.getPageState();
|
||||
|
||||
final Optional<Asset> selectedAsset
|
||||
= getSelectedAsset(state);
|
||||
if (selectedAsset.isPresent()) {
|
||||
final SingleSelect target = (SingleSelect) event
|
||||
.getTarget();
|
||||
|
||||
target.clearOptions();;
|
||||
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final AssetL10NManager l10nManager = cdiUtil
|
||||
.findBean(AssetL10NManager.class);
|
||||
final List<Locale> availableLocales = new ArrayList<>(
|
||||
l10nManager.availableLocales(selectedAsset.get()));
|
||||
availableLocales.sort((locale1, locale2) -> {
|
||||
return locale1
|
||||
.toString()
|
||||
.compareTo(locale2.toString());
|
||||
});
|
||||
availableLocales.forEach(locale -> target.addOption(
|
||||
new Option(locale.toString(),
|
||||
new Text(locale.toString()))));
|
||||
} else {
|
||||
final SingleSelect target = (SingleSelect) event
|
||||
.getTarget();
|
||||
|
||||
target.clearOptions();
|
||||
|
||||
final List<String> langs = new ArrayList<>(
|
||||
KernelConfig.getConfig().getSupportedLanguages());
|
||||
langs.sort((lang1, lang2) -> lang1.compareTo(lang2));
|
||||
|
||||
langs.forEach(lang -> {
|
||||
target.addOption(new Option(lang, new Text(lang)));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
} catch (TooManyListenersException ex) {
|
||||
throw new UnexpectedErrorException(ex);
|
||||
}
|
||||
showLocaleSubmit = new Submit(new GlobalizedMessage(
|
||||
"cms.ui.asset.show_locale",
|
||||
CmsConstants.CMS_BUNDLE));
|
||||
showLocalePanel.add(showLocaleLabel);
|
||||
showLocalePanel.add(showLocaleSelect);
|
||||
showLocalePanel.add(showLocaleSubmit);
|
||||
add(showLocalePanel);
|
||||
|
||||
addLocalePanel = new BoxPanel(BoxPanel.HORIZONTAL) {
|
||||
|
||||
@Override
|
||||
public boolean isVisible(final PageState state) {
|
||||
return getSelectedAsset(state).isPresent();
|
||||
}
|
||||
|
||||
};
|
||||
final Label addLocaleLabel = new Label(
|
||||
new GlobalizedMessage("cms.ui.assest.add_locale",
|
||||
CmsConstants.CMS_BUNDLE));
|
||||
addLocaleSelect = new SingleSelect("add-locale-select");
|
||||
try {
|
||||
addLocaleSelect.addPrintListener(new PrintListener() {
|
||||
|
||||
@Override
|
||||
public void prepare(final PrintEvent event) {
|
||||
final PageState state = event.getPageState();
|
||||
|
||||
final Optional<Asset> selectedAsset
|
||||
= getSelectedAsset(state);
|
||||
if (selectedAsset.isPresent()) {
|
||||
final SingleSelect target = (SingleSelect) event
|
||||
.getTarget();
|
||||
|
||||
target.clearOptions();
|
||||
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final AssetL10NManager l10nManager = cdiUtil
|
||||
.findBean(AssetL10NManager.class);
|
||||
final List<Locale> creatableLocales = new ArrayList<>(
|
||||
l10nManager.creatableLocales(selectedAsset.get()));
|
||||
creatableLocales.sort((locale1, locale2) -> {
|
||||
return locale1
|
||||
.toString()
|
||||
.compareTo(locale2.toString());
|
||||
});
|
||||
creatableLocales.forEach(locale -> target.addOption(
|
||||
new Option(locale.toString(),
|
||||
new Text(locale.toString()))));
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
} catch (TooManyListenersException ex) {
|
||||
throw new UnexpectedErrorException(ex);
|
||||
}
|
||||
addLocaleSubmit = new Submit(new GlobalizedMessage(
|
||||
"cms.ui.asset.add_locale",
|
||||
CmsConstants.CMS_BUNDLE));
|
||||
addLocalePanel.add(addLocaleLabel);
|
||||
addLocalePanel.add(addLocaleSelect);
|
||||
addLocalePanel.add(addLocaleSubmit);
|
||||
add(addLocalePanel);
|
||||
|
||||
add(new Label(new GlobalizedMessage("cms.ui.asset.title",
|
||||
CmsConstants.CMS_BUNDLE)));
|
||||
title = new TextField(ASSET_TITLE);
|
||||
|
|
@ -88,6 +248,15 @@ public abstract class AssetForm extends Form implements FormInitListener,
|
|||
//Nothing here
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void register(final Page page) {
|
||||
// super.register(page);
|
||||
//
|
||||
// page.addComponentStateParam(this, selectedLocaleParameter);
|
||||
//
|
||||
// page.setVisibleDefault(showLocalePanel, true);
|
||||
// page.setVisibleDefault(addLocalePanel, true);
|
||||
// }
|
||||
protected String getTitle(final PageState state) {
|
||||
return (String) title.getValue(state);
|
||||
}
|
||||
|
|
@ -118,23 +287,78 @@ public abstract class AssetForm extends Form implements FormInitListener,
|
|||
final Optional<Asset> selectedAsset = getSelectedAsset(state);
|
||||
|
||||
if (selectedAsset.isPresent()) {
|
||||
// showLocalePanel.setVisible(state, true);
|
||||
// addLocalePanel.setVisible(state, true);
|
||||
|
||||
showLocaleSelect.setValue(state,
|
||||
KernelConfig
|
||||
.getConfig()
|
||||
.getDefaultLocale()
|
||||
.toString());
|
||||
|
||||
title.setValue(state,
|
||||
selectedAsset
|
||||
.get()
|
||||
.getTitle()
|
||||
.getValue(KernelConfig
|
||||
.getValue(getSelectedLocale(state)));
|
||||
} else {
|
||||
showLocaleSelect.setValue(state,
|
||||
KernelConfig
|
||||
.getConfig()
|
||||
.getDefaultLocale()));
|
||||
.getDefaultLocale()
|
||||
.toString());
|
||||
// showLocalePanel.setVisible(state, false);
|
||||
// addLocalePanel.setVisible(state, false);
|
||||
}
|
||||
|
||||
initForm(state, selectedAsset);
|
||||
}
|
||||
|
||||
protected Locale getSelectedLocale(final PageState state) {
|
||||
final String selected = (String) showLocaleSelect.getValue(state);
|
||||
if (selected == null) {
|
||||
return KernelConfig.getConfig().getDefaultLocale();
|
||||
} else {
|
||||
return new Locale(selected);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void initForm(final PageState state,
|
||||
final Optional<Asset> selectedAsset);
|
||||
|
||||
@Override
|
||||
public void process(final FormSectionEvent event)
|
||||
throws FormProcessException {
|
||||
|
||||
final PageState state = event.getPageState();
|
||||
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
|
||||
if (showLocaleSubmit.isSelected(state)) {
|
||||
|
||||
final Optional<Asset> selectedAsset = getSelectedAsset(state);
|
||||
|
||||
if (selectedAsset.isPresent()) {
|
||||
|
||||
title.setValue(state,
|
||||
selectedAsset
|
||||
.get()
|
||||
.getTitle()
|
||||
.getValue(getSelectedLocale(state)));
|
||||
showLocale(state);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (addLocaleSubmit.isSelected(state)) {
|
||||
final AssetL10NManager l10nManager = cdiUtil
|
||||
.findBean(AssetL10NManager.class);
|
||||
final Locale add = new Locale((String) addLocaleSelect
|
||||
.getValue(state));
|
||||
final Optional<Asset> selectedAsset = getSelectedAsset(state);
|
||||
l10nManager.addLanguage(selectedAsset.get(), add);
|
||||
}
|
||||
|
||||
if (saveCancelSection.getSaveButton().isSelected(state)) {
|
||||
final Optional<Asset> selectedAsset = getSelectedAsset(state);
|
||||
final Asset asset;
|
||||
|
|
@ -145,11 +369,9 @@ public abstract class AssetForm extends Form implements FormInitListener,
|
|||
asset = createAsset(state);
|
||||
}
|
||||
|
||||
asset.getTitle().addValue(
|
||||
KernelConfig.getConfig().getDefaultLocale(),
|
||||
asset.getTitle().addValue(getSelectedLocale(state),
|
||||
(String) title.getValue(state));
|
||||
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final AssetRepository assetRepo = cdiUtil
|
||||
.findBean(AssetRepository.class);
|
||||
assetRepo.save(asset);
|
||||
|
|
@ -175,6 +397,8 @@ public abstract class AssetForm extends Form implements FormInitListener,
|
|||
}
|
||||
}
|
||||
|
||||
protected abstract void showLocale(final PageState state);
|
||||
|
||||
protected abstract Asset createAsset(final PageState state)
|
||||
throws FormProcessException;
|
||||
|
||||
|
|
|
|||
|
|
@ -501,7 +501,7 @@ public class AssetPane extends LayoutPanel implements Resettable {
|
|||
|
||||
actionsSegment.add(newAssetForm);
|
||||
|
||||
final MetaForm editAssetForm = new MetaForm(MOVE) {
|
||||
final MetaForm editAssetForm = new MetaForm("editAsset") {
|
||||
@Override
|
||||
public Form buildForm(final PageState state) {
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ import org.librecms.contentsection.Asset;
|
|||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -88,6 +89,51 @@ public class BookmarkForm extends AssetForm {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initForm(final PageState state,
|
||||
final Optional<Asset> selectedAsset) {
|
||||
|
||||
if (selectedAsset.isPresent()) {
|
||||
|
||||
if (!(selectedAsset.get() instanceof Bookmark)) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"The provided asset must be an instanceof of class '%s' or "
|
||||
+ "an subclass but is an instanceof of class '%s'.",
|
||||
Bookmark.class.getName(),
|
||||
selectedAsset.get().getClass().getName()));
|
||||
}
|
||||
|
||||
final Bookmark bookmark = (Bookmark) selectedAsset.get();
|
||||
|
||||
description.setValue(state,
|
||||
bookmark
|
||||
.getDescription()
|
||||
.getValue(getSelectedLocale(state)));
|
||||
url.setValue(state, bookmark.getUrl());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void showLocale(final PageState state) {
|
||||
final Optional<Asset> selectedAsset = getSelectedAsset(state);
|
||||
|
||||
if (selectedAsset.isPresent()) {
|
||||
if (!(getSelectedAsset(state).get() instanceof Bookmark)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Selected asset is not a bookmark");
|
||||
}
|
||||
|
||||
final Bookmark bookmark = (Bookmark) selectedAsset.get();
|
||||
|
||||
description.setValue(state,
|
||||
bookmark
|
||||
.getDescription()
|
||||
.getValue(getSelectedLocale(state)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Asset createAsset(final PageState state)
|
||||
throws FormProcessException {
|
||||
|
|
@ -98,7 +144,7 @@ public class BookmarkForm extends AssetForm {
|
|||
|
||||
bookmark
|
||||
.getDescription()
|
||||
.addValue(KernelConfig.getConfig().getDefaultLocale(),
|
||||
.addValue(getSelectedLocale(state),
|
||||
(String) description.getValue(state));
|
||||
|
||||
bookmark.setUrl((String) url.getValue(state));
|
||||
|
|
@ -125,7 +171,7 @@ public class BookmarkForm extends AssetForm {
|
|||
|
||||
bookmark
|
||||
.getDescription()
|
||||
.addValue(KernelConfig.getConfig().getDefaultLocale(),
|
||||
.addValue(getSelectedLocale(state),
|
||||
(String) description.getValue(state));
|
||||
|
||||
bookmark.setUrl((String) url.getValue(state));
|
||||
|
|
|
|||
|
|
@ -29,10 +29,13 @@ import com.arsdigita.globalization.GlobalizedMessage;
|
|||
import com.arsdigita.kernel.KernelConfig;
|
||||
|
||||
import org.librecms.CmsConstants;
|
||||
import org.librecms.assets.Bookmark;
|
||||
import org.librecms.assets.LegalMetadata;
|
||||
import org.librecms.contentsection.Asset;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -77,6 +80,52 @@ public class LegalMetadataForm extends AssetForm {
|
|||
add(creator);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initForm(final PageState state,
|
||||
final Optional<Asset> selectedAsset) {
|
||||
|
||||
if (selectedAsset.isPresent()) {
|
||||
|
||||
if (!(selectedAsset.get() instanceof LegalMetadata)) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"The provided asset must be an instanceof of class '%s' or "
|
||||
+ "an subclass but is an instanceof of class '%s'.",
|
||||
LegalMetadata.class.getName(),
|
||||
selectedAsset.get().getClass().getName()));
|
||||
}
|
||||
|
||||
final LegalMetadata legalMetadata = (LegalMetadata) selectedAsset
|
||||
.get();
|
||||
|
||||
rightsHolder.setValue(state, legalMetadata.getRightsHolder());
|
||||
rights.setValue(state,
|
||||
legalMetadata
|
||||
.getRights()
|
||||
.getValue(getSelectedLocale(state)));
|
||||
publisher.setValue(state, legalMetadata.getPublisher());
|
||||
creator.setValue(state, legalMetadata.getCreator());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void showLocale(final PageState state) {
|
||||
final Optional<Asset> selectedAsset = getSelectedAsset(state);
|
||||
|
||||
if (selectedAsset.isPresent()) {
|
||||
if (!(getSelectedAsset(state).get() instanceof LegalMetadata)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Selected asset is not a legal metadata");
|
||||
}
|
||||
|
||||
final LegalMetadata legalMetadata = (LegalMetadata) selectedAsset.get();
|
||||
|
||||
rights.setValue(state,
|
||||
legalMetadata
|
||||
.getRights()
|
||||
.getValue(getSelectedLocale(state)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Asset createAsset(final PageState state)
|
||||
throws FormProcessException {
|
||||
|
|
@ -86,8 +135,7 @@ public class LegalMetadataForm extends AssetForm {
|
|||
final LegalMetadata legalMetadata = new LegalMetadata();
|
||||
|
||||
legalMetadata.setRightsHolder((String) rightsHolder.getValue(state));
|
||||
legalMetadata.getRights().addValue(
|
||||
KernelConfig.getConfig().getDefaultLocale(),
|
||||
legalMetadata.getRights().addValue(getSelectedLocale(state),
|
||||
(String) rights.getValue(state));
|
||||
|
||||
legalMetadata.setPublisher((String) publisher.getValue(state));
|
||||
|
|
@ -107,15 +155,15 @@ public class LegalMetadataForm extends AssetForm {
|
|||
throw new IllegalArgumentException(String.format(
|
||||
"Provided asset is not an instance of '%s' (or a sub class) "
|
||||
+ "but is an instance of class '%s'.",
|
||||
LegalMetadata.class.getName(),
|
||||
LegalMetadata.class
|
||||
.getName(),
|
||||
asset.getClass().getName()));
|
||||
}
|
||||
|
||||
final LegalMetadata legalMetadata = (LegalMetadata) asset;
|
||||
|
||||
legalMetadata.setRightsHolder((String) rightsHolder.getValue(state));
|
||||
legalMetadata.getRights().addValue(
|
||||
KernelConfig.getConfig().getDefaultLocale(),
|
||||
legalMetadata.getRights().addValue(getSelectedLocale(state),
|
||||
(String) rights.getValue(state));
|
||||
|
||||
legalMetadata.setPublisher((String) publisher.getValue(state));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,344 @@
|
|||
/*
|
||||
* Copyright (C) 2017 LibreCCM Foundation.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
package org.librecms.assets;
|
||||
|
||||
import com.arsdigita.kernel.KernelConfig;
|
||||
|
||||
import org.libreccm.configuration.ConfigurationManager;
|
||||
import org.libreccm.core.UnexpectedErrorException;
|
||||
import org.libreccm.l10n.LocalizedString;
|
||||
import org.libreccm.security.AuthorizationRequired;
|
||||
import org.libreccm.security.PermissionChecker;
|
||||
import org.libreccm.security.RequiresPrivilege;
|
||||
import org.librecms.contentsection.Asset;
|
||||
import org.librecms.contentsection.AssetRepository;
|
||||
import org.librecms.contentsection.privileges.AssetPrivileges;
|
||||
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.enterprise.context.RequestScoped;
|
||||
import javax.inject.Inject;
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
/**
|
||||
* Manages the language versions of an asset.
|
||||
*
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
@RequestScoped
|
||||
public class AssetL10NManager {
|
||||
|
||||
@Inject
|
||||
private ConfigurationManager confManager;
|
||||
|
||||
@Inject
|
||||
private AssetRepository assetRepo;
|
||||
|
||||
@Inject
|
||||
private PermissionChecker permissionChecker;
|
||||
|
||||
private Locale defaultLocale;
|
||||
private List<Locale> supportedLocales;
|
||||
|
||||
@PostConstruct
|
||||
private void init() {
|
||||
final KernelConfig kernelConfig = confManager.findConfiguration(
|
||||
KernelConfig.class);
|
||||
defaultLocale = kernelConfig.getDefaultLocale();
|
||||
supportedLocales = kernelConfig.getSupportedLanguages()
|
||||
.stream()
|
||||
.map(language -> new Locale(language))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<PropertyDescriptor> findLocalizedStringProperties(
|
||||
final Asset asset) {
|
||||
|
||||
try {
|
||||
final PropertyDescriptor[] properties = Introspector
|
||||
.getBeanInfo(asset.getClass())
|
||||
.getPropertyDescriptors();
|
||||
|
||||
return Arrays.stream(properties)
|
||||
.filter(property -> {
|
||||
return property
|
||||
.getPropertyType()
|
||||
.isAssignableFrom(LocalizedString.class);
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
} catch (IntrospectionException ex) {
|
||||
throw new UnexpectedErrorException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private LocalizedString readLocalizedString(final Asset asset,
|
||||
final Method readMethod) {
|
||||
try {
|
||||
return (LocalizedString) readMethod.invoke(asset);
|
||||
} catch (IllegalAccessException
|
||||
| IllegalArgumentException
|
||||
| InvocationTargetException ex) {
|
||||
throw new UnexpectedErrorException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private Set<Locale> collectLanguages(final Asset asset) {
|
||||
|
||||
final Set<Locale> locales = new HashSet<>();
|
||||
|
||||
findLocalizedStringProperties(asset)
|
||||
.stream()
|
||||
.map(property -> property.getReadMethod())
|
||||
.map(readMethod -> readLocalizedString(asset, readMethod))
|
||||
.forEach(str -> locales.addAll(str.getAvailableLocales()));
|
||||
|
||||
return locales;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for reading methods in this class for verifying that the
|
||||
* current user is permitted to read the item.
|
||||
*
|
||||
* @param asset The asset for which the read permission is verified
|
||||
*/
|
||||
private void checkReadPermission(final Asset asset) {
|
||||
|
||||
final String requiredPrivilege = AssetPrivileges.VIEW;
|
||||
|
||||
permissionChecker.checkPermission(requiredPrivilege, asset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all languages in which an asset is available.
|
||||
*
|
||||
* @param asset The asset.
|
||||
*
|
||||
* @return An (unmodifiable) {@link Set} containing all languages in which
|
||||
* the asset is available.
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public Set<Locale> availableLocales(final Asset asset) {
|
||||
|
||||
checkReadPermission(asset);
|
||||
return Collections.unmodifiableSet(collectLanguages(asset));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an asset has data for particular language.
|
||||
*
|
||||
* @param asset The asset to check.
|
||||
* @param locale The locale to check for.
|
||||
*
|
||||
* @return {@link true} if the item has data for the language, {@code false}
|
||||
* if not.
|
||||
*/
|
||||
@AuthorizationRequired
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public boolean hasLanguage(
|
||||
@RequiresPrivilege(AssetPrivileges.VIEW)
|
||||
final Asset asset,
|
||||
final Locale locale) {
|
||||
|
||||
Objects.requireNonNull(asset,
|
||||
"Can't check if asset null has a specific locale.");
|
||||
Objects.requireNonNull(locale, "Can't check for locale null.");
|
||||
|
||||
checkReadPermission(asset);
|
||||
|
||||
return collectLanguages(asset).contains(locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Set} containing the locales for which the asset does not
|
||||
* yet have a variant.
|
||||
*
|
||||
* @param asset The asset.
|
||||
*
|
||||
* @return A {@link Set} with the locales for which the item does not have a
|
||||
* variant.
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public Set<Locale> creatableLocales(final Asset asset) {
|
||||
checkReadPermission(asset);
|
||||
|
||||
return supportedLocales.stream()
|
||||
.filter(locale -> !hasLanguage(asset, locale))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a language to an asset. The method will retrieve all fields of the
|
||||
* type {@link LocalizedString} from the asset and add a new entry for the
|
||||
* provided locale by coping the value for the default language configured
|
||||
* in {@link KernelConfig}. If a field does not have an entry for the
|
||||
* default language the first value found is used.
|
||||
*
|
||||
* @param asset The asset to which the language variant is added.
|
||||
* @param locale The locale of the language to add.
|
||||
*/
|
||||
@AuthorizationRequired
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public void addLanguage(
|
||||
@RequiresPrivilege(AssetPrivileges.EDIT)
|
||||
final Asset asset,
|
||||
final Locale locale) {
|
||||
|
||||
Objects.requireNonNull(asset, "Can't add language to asset null.");
|
||||
Objects.requireNonNull(asset, "Cant't add language null to an asset.");
|
||||
|
||||
findLocalizedStringProperties(asset)
|
||||
.forEach(property -> addLanguage(asset, locale, property));
|
||||
|
||||
assetRepo.save(asset);
|
||||
}
|
||||
|
||||
private void addLanguage(final Asset asset,
|
||||
final Locale locale,
|
||||
final PropertyDescriptor property) {
|
||||
|
||||
final Method readMethod = property.getReadMethod();
|
||||
final LocalizedString localizedStr = readLocalizedString(asset,
|
||||
readMethod);
|
||||
addLanguage(localizedStr, locale);
|
||||
}
|
||||
|
||||
private void addLanguage(final LocalizedString localizedString,
|
||||
final Locale locale) {
|
||||
if (localizedString.hasValue(locale)) {
|
||||
//Nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
final String value;
|
||||
if (localizedString.hasValue(defaultLocale)) {
|
||||
value = localizedString.getValue(defaultLocale);
|
||||
} else {
|
||||
value = findValue(localizedString);
|
||||
}
|
||||
|
||||
localizedString.addValue(locale, value);
|
||||
}
|
||||
|
||||
private String findValue(final LocalizedString localizedStr) {
|
||||
final Optional<Locale> locale = supportedLocales
|
||||
.stream()
|
||||
.filter(current -> localizedStr.hasValue(current))
|
||||
.findAny();
|
||||
|
||||
if (locale.isPresent()) {
|
||||
return localizedStr.getValue(locale.get());
|
||||
} else {
|
||||
return "Lorem ipsum";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a language variant from an asset. This method will retrieve all
|
||||
* fields of the type {@link LocalizedString} from the asset and remove the
|
||||
* entry for the provided locale if the field has an entry for that locale.
|
||||
*
|
||||
* @param asset
|
||||
* @param locale
|
||||
*/
|
||||
@AuthorizationRequired
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public void removeLanguage(
|
||||
@RequiresPrivilege(AssetPrivileges.EDIT)
|
||||
final Asset asset,
|
||||
final Locale locale) {
|
||||
|
||||
Objects.requireNonNull(asset, "Can't remove language to asset null.");
|
||||
Objects
|
||||
.requireNonNull(asset, "Cant't remove language null to an asset.");
|
||||
|
||||
findLocalizedStringProperties(asset)
|
||||
.forEach(property -> removeLanguage(asset, locale, property));
|
||||
|
||||
assetRepo.save(asset);
|
||||
}
|
||||
|
||||
private void removeLanguage(final Asset asset,
|
||||
final Locale locale,
|
||||
final PropertyDescriptor property) {
|
||||
|
||||
final Method readMethod = property.getReadMethod();
|
||||
|
||||
final LocalizedString localizedStr = readLocalizedString(asset,
|
||||
readMethod);
|
||||
if (localizedStr.hasValue(locale)) {
|
||||
localizedStr.removeValue(locale);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method normalises the values of the fields of type
|
||||
* {@link LocalizedString} of an asset. The method will first retrieve all
|
||||
* fields of the type {@link LocalizedString} from the asset and than build
|
||||
* a set with all locales provided by any of the fields. After that the
|
||||
* method will iterate over all {@link LocalizedString} fields and check if
|
||||
* the {@link LocalizedString} has an entry for every language in the set.
|
||||
* If not an entry for the language is added.
|
||||
*
|
||||
* @param asset The asset to normalise.
|
||||
*/
|
||||
@AuthorizationRequired
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public void normalizeLanguages(
|
||||
@RequiresPrivilege(AssetPrivileges.EDIT)
|
||||
final Asset asset) {
|
||||
|
||||
Objects.requireNonNull(asset, "Can't normalise asset null");
|
||||
|
||||
final Set<Locale> languages = collectLanguages(asset);
|
||||
|
||||
findLocalizedStringProperties(asset)
|
||||
.stream()
|
||||
.map(property -> property.getReadMethod())
|
||||
.map(readMethod -> readLocalizedString(asset, readMethod))
|
||||
.forEach(str -> normalize(str, languages));
|
||||
}
|
||||
|
||||
private void normalize(final LocalizedString localizedString,
|
||||
final Set<Locale> languages) {
|
||||
|
||||
final List<Locale> missingLangs = languages.stream()
|
||||
.filter(lang -> !localizedString.hasValue(lang))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!missingLangs.isEmpty()) {
|
||||
missingLangs.stream()
|
||||
.forEach(lang -> addLanguage(localizedString, lang));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -83,11 +83,16 @@ public class ContentItemL10NManager {
|
|||
final ContentItem item) {
|
||||
|
||||
try {
|
||||
return Arrays.stream(
|
||||
Introspector.getBeanInfo(item.getClass())
|
||||
.getPropertyDescriptors())
|
||||
.filter(property -> property.getPropertyType().isAssignableFrom(
|
||||
LocalizedString.class))
|
||||
final PropertyDescriptor[] properties = Introspector
|
||||
.getBeanInfo(item.getClass())
|
||||
.getPropertyDescriptors();
|
||||
|
||||
return Arrays.stream(properties)
|
||||
.filter(property -> {
|
||||
return property
|
||||
.getPropertyType()
|
||||
.isAssignableFrom(LocalizedString.class);
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
} catch (IntrospectionException ex) {
|
||||
throw new UnexpectedErrorException(ex);
|
||||
|
|
@ -106,6 +111,7 @@ public class ContentItemL10NManager {
|
|||
}
|
||||
|
||||
private Set<Locale> collectLanguages(final ContentItem item) {
|
||||
|
||||
final Set<Locale> locales = new HashSet<>();
|
||||
|
||||
findLocalizedStringProperties(item)
|
||||
|
|
@ -146,7 +152,7 @@ public class ContentItemL10NManager {
|
|||
}
|
||||
|
||||
/**
|
||||
* Retrieves all languages in which content item is available.
|
||||
* Retrieves all languages in which a content item is available.
|
||||
*
|
||||
* @param item The item.
|
||||
*
|
||||
|
|
@ -154,8 +160,7 @@ public class ContentItemL10NManager {
|
|||
* the item is available.
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public Set<Locale> availableLanguages(
|
||||
final ContentItem item) {
|
||||
public Set<Locale> availableLanguages(final ContentItem item) {
|
||||
|
||||
checkReadPermission(item);
|
||||
return Collections.unmodifiableSet(collectLanguages(item));
|
||||
|
|
@ -205,7 +210,7 @@ public class ContentItemL10NManager {
|
|||
checkReadPermission(item);
|
||||
|
||||
return supportedLocales.stream()
|
||||
.filter(locale -> hasLanguage(item, locale))
|
||||
.filter(locale -> !hasLanguage(item, locale))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
|
|
@ -329,7 +334,7 @@ public class ContentItemL10NManager {
|
|||
}
|
||||
|
||||
findLocalizedStringProperties(item)
|
||||
.forEach(property -> ContentItemL10NManager.this.removeLanguage(item, locale, property));
|
||||
.forEach(property -> removeLanguage(item, locale, property));
|
||||
|
||||
itemRepo.save(item);
|
||||
}
|
||||
|
|
@ -357,13 +362,13 @@ public class ContentItemL10NManager {
|
|||
* not an entry for the language is added.
|
||||
*
|
||||
* @param item The item to normalise. The item <strong>must be</strong> the
|
||||
* <strong>draft version</strong> of the item! If a <em>live
|
||||
* version</em> or a <em>pending version</em> is provided the
|
||||
* method will throw an {@link IllegalArgumentException}!
|
||||
* <strong>draft version</strong> of the item! If a <em>live version</em> or
|
||||
* a <em>pending version</em> is provided the method will throw an
|
||||
* {@link IllegalArgumentException}!
|
||||
*/
|
||||
@AuthorizationRequired
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public void normalizedLanguages(
|
||||
public void normalizeLanguages(
|
||||
@RequiresPrivilege(ItemPrivileges.EDIT)
|
||||
final ContentItem item) {
|
||||
|
||||
|
|
|
|||
|
|
@ -392,7 +392,7 @@ public class ContentItemL10NManagerTest {
|
|||
|
||||
/**
|
||||
* Tries to normalise the languages of a content item by using
|
||||
* {@link ContentItemL10NManager#normalizedLanguages(org.librecms.contentsection.ContentItem)}
|
||||
* {@link ContentItemL10NManager#normalizeLanguages(org.librecms.contentsection.ContentItem)}
|
||||
*/
|
||||
@Test
|
||||
@InSequence(120)
|
||||
|
|
@ -406,12 +406,12 @@ public class ContentItemL10NManagerTest {
|
|||
final Optional<ContentItem> item = itemRepo.findById(-10200L);
|
||||
assertThat(item.isPresent(), is(true));
|
||||
|
||||
l10nManager.normalizedLanguages(item.get());
|
||||
l10nManager.normalizeLanguages(item.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that calling
|
||||
* {@link ContentItemL10NManager#normalizedLanguages(org.librecms.contentsection.ContentItem)}
|
||||
* {@link ContentItemL10NManager#normalizeLanguages(org.librecms.contentsection.ContentItem)}
|
||||
* for already normalised item has not effect.
|
||||
*/
|
||||
@Test
|
||||
|
|
@ -425,13 +425,13 @@ public class ContentItemL10NManagerTest {
|
|||
final Optional<ContentItem> item = itemRepo.findById(-10100L);
|
||||
assertThat(item.isPresent(), is(true));
|
||||
|
||||
l10nManager.normalizedLanguages(item.get());
|
||||
l10nManager.normalizeLanguages(item.get());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that
|
||||
* {@link ContentItemL10NManager#normalizedLanguages(org.librecms.contentsection.ContentItem)}
|
||||
* {@link ContentItemL10NManager#normalizeLanguages(org.librecms.contentsection.ContentItem)}
|
||||
* throws an {@link IllegalArgumentException} if called with {@code null}
|
||||
* for the item.
|
||||
*/
|
||||
|
|
@ -446,7 +446,7 @@ public class ContentItemL10NManagerTest {
|
|||
public void normalizeItemNull() {
|
||||
final ContentItem item = null;
|
||||
|
||||
l10nManager.normalizedLanguages(item);
|
||||
l10nManager.normalizeLanguages(item);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue