From a24ff559967f2e1e664ecbc83317a5adca3daee4 Mon Sep 17 00:00:00 2001 From: jensp Date: Thu, 2 Mar 2017 11:42:46 +0000 Subject: [PATCH] CCM NG/ccm-cms: Finding invalid targets for copying/moving items/folders. git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@4612 8810af33-2d31-482b-a856-94f89814c4df --- .../ui/folder/FolderBrowserController.java | 335 ++++++++++++------ .../cms/ui/folder/FolderManipulator.java | 246 +++++-------- .../ui/folder/FolderTreeModelController.java | 1 - .../main/java/org/librecms/CmsConstants.java | 3 + 4 files changed, 322 insertions(+), 263 deletions(-) diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderBrowserController.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderBrowserController.java index 79ef9a5ee..86c0113c5 100644 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderBrowserController.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderBrowserController.java @@ -43,6 +43,7 @@ import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.Objects; +import java.util.Optional; import java.util.stream.Collectors; @@ -60,6 +61,8 @@ import javax.persistence.TypedQuery; import javax.persistence.criteria.Order; import javax.persistence.criteria.Path; +import static org.librecms.CmsConstants.*; + /** * The {@code FolderBrowserController} wraps all database operations (queries) * required by the {@link FolderBrowser}, the @@ -112,7 +115,7 @@ public class FolderBrowserController { @PostConstruct private void init() { final KernelConfig kernelConfig = confManager.findConfiguration( - KernelConfig.class); + KernelConfig.class); defaultLocale = kernelConfig.getDefaultLocale(); } @@ -122,7 +125,7 @@ public class FolderBrowserController { * @param folder The folder. * * @return The number of objects (subfolders and content items) in the - * provided {@code folder}. + * provided {@code folder}. */ public long countObjects(final Folder folder) { return countObjects(folder, "%"); @@ -132,12 +135,11 @@ public class FolderBrowserController { * Count all objects (subfolders and content items) in the provided folder * which match the provided filter term. * - * @param folder The folder. + * @param folder The folder. * @param filterTerm The filter term. * * @return The number of objects (subfolders and content items) in the - * provided {@code folder} which match the provided - * {@code filterTerm}. + * provided {@code folder} which match the provided {@code filterTerm}. */ public long countObjects(final Folder folder, final String filterTerm) { @@ -171,8 +173,8 @@ public class FolderBrowserController { criteriaQuery = criteriaQuery.where(from.in(subFolders)); } else { criteriaQuery = criteriaQuery.where(builder.or( - from.in(subFolders), - from.in(items))); + from.in(subFolders), + from.in(items))); } return entityManager.createQuery(criteriaQuery).getSingleResult(); @@ -182,13 +184,13 @@ public class FolderBrowserController { * Create {@link FolderBrowserTableRow} objects for all objects in the * provided folder. * - * @param folder The folder which contains the objects. - * @param orderBy The field used to order the objects. + * @param folder The folder which contains the objects. + * @param orderBy The field used to order the objects. * @param orderDirection The direction for ordering the objects. * * @return A list with {@link FolderBrowserTableRow} objects for each object - * in the provided {@code folder} ordered by the provided field and - * in the provided direction. + * in the provided {@code folder} ordered by the provided field and in the + * provided direction. */ @Transactional(Transactional.TxType.REQUIRED) List getObjectRows(final Folder folder, @@ -201,15 +203,15 @@ public class FolderBrowserController { * Create {@link FolderBrowserTableRow} objects for all objects in the * provided folder which match provided filter term. * - * @param folder The folder which contains the objects. - * @param filterTerm The filter term. - * @param orderBy The field used to order the objects. + * @param folder The folder which contains the objects. + * @param filterTerm The filter term. + * @param orderBy The field used to order the objects. * @param orderDirection The direction for ordering the objects. * * @return A list with {@link FolderBrowserTableRow} objects for each object - * in the provided {@code folder} which matches the provided - * {@code filterTerm}, ordered by the provided field and in the - * provided direction. + * in the provided {@code folder} which matches the provided + * {@code filterTerm}, ordered by the provided field and in the provided + * direction. */ @Transactional(Transactional.TxType.REQUIRED) List getObjectRows(final Folder folder, @@ -229,17 +231,17 @@ public class FolderBrowserController { * provided folder which are in the range provided by {@code firstResult} * and {@code maxResult} * - * @param folder The folder which contains the objects. - * @param orderBy The field used to order the objects. + * @param folder The folder which contains the objects. + * @param orderBy The field used to order the objects. * @param orderDirection The direction for ordering the objects. - * @param firstResult The index of the first object to use. - * @param maxResults The maximum number of objects to retrieve. + * @param firstResult The index of the first object to use. + * @param maxResults The maximum number of objects to retrieve. * * @return A list with {@link FolderBrowserTableRow} objects for each object - * in the provided {@code folder} ordered by the provided field and - * in the provided direction. The list will start with the object - * with index provided as {@code firstResult} and contain at most - * {@code maxResults} items. + * in the provided {@code folder} ordered by the provided field and in the + * provided direction. The list will start with the object with index + * provided as {@code firstResult} and contain at most {@code maxResults} + * items. */ @Transactional(Transactional.TxType.REQUIRED) List getObjectRows(final Folder folder, @@ -260,19 +262,18 @@ public class FolderBrowserController { * provided folder which match the provided filter term and which are in the * range provided by {@code firstResult} and {@code maxResult} * - * @param folder The folder which contains the objects. - * @param filterTerm The filter term. - * @param orderBy The field used to order the objects. + * @param folder The folder which contains the objects. + * @param filterTerm The filter term. + * @param orderBy The field used to order the objects. * @param orderDirection The direction for ordering the objects. - * @param firstResult The index of the first object to use. - * @param maxResults The maximum number of objects to retrieve. + * @param firstResult The index of the first object to use. + * @param maxResults The maximum number of objects to retrieve. * * @return A list with {@link FolderBrowserTableRow} objects for each object - * in the provided {@code folder} which matches the provided - * {@code filterTerm}, ordered by the provided field and in the - * provided direction. The list will start with the object with - * index provided as {@code firstResult} and contain at most - * {@code maxResults} items. + * in the provided {@code folder} which matches the provided + * {@code filterTerm}, ordered by the provided field and in the provided + * direction. The list will start with the object with index provided as + * {@code firstResult} and contain at most {@code maxResults} items. */ @Transactional(Transactional.TxType.REQUIRED) List getObjectRows(final Folder folder, @@ -288,8 +289,8 @@ public class FolderBrowserController { firstResult, maxResults); final List subFolderRows = subFolders.stream() - .map(subFolder -> buildRow(subFolder)) - .collect(Collectors.toList()); + .map(subFolder -> buildRow(subFolder)) + .collect(Collectors.toList()); if (subFolders.size() > maxResults) { return subFolderRows; @@ -304,8 +305,8 @@ public class FolderBrowserController { firstItem, maxItems); final List itemRows = items.stream() - .map(item -> buildRow(item)) - .collect(Collectors.toList()); + .map(item -> buildRow(item)) + .collect(Collectors.toList()); final ArrayList rows = new ArrayList<>(); rows.addAll(subFolderRows); @@ -320,10 +321,10 @@ public class FolderBrowserController { * {@link Folder}. * * @param folder The {@link Folder} to use for building the - * {@link FolderBrowserTableRow}. + * {@link FolderBrowserTableRow}. * * @return A {@link FolderBrowserTableRow} containing the data needed by the - * {@link FolderBrowser} to display the provided {@code folder}. + * {@link FolderBrowser} to display the provided {@code folder}. */ private FolderBrowserTableRow buildRow(final Folder folder) { @@ -334,15 +335,15 @@ public class FolderBrowserController { row.setName(folder.getName()); row.setLanguages(Collections.emptyList()); if (folder.getTitle().hasValue(globalizationHelper - .getNegotiatedLocale())) { + .getNegotiatedLocale())) { row.setTitle(folder.getTitle().getValue(globalizationHelper - .getNegotiatedLocale())); + .getNegotiatedLocale())); } else { row.setTitle(folder.getTitle().getValue(defaultLocale)); } row.setFolder(true); row.setDeletable(!categoryManager.hasSubCategories(folder) - && !categoryManager.hasObjects(folder)); + && !categoryManager.hasObjects(folder)); return row; } @@ -352,10 +353,10 @@ public class FolderBrowserController { * {@link ContentItem}. * * @param item The {@link ContentItem} to use for building the - * {@link FolderBrowserTableRow}. + * {@link FolderBrowserTableRow}. * * @return A {@link FolderBrowserTableRow} containing the data needed by the - * {@link FolderBrowser} to display the provided {@code item}. + * {@link FolderBrowser} to display the provided {@code item}. */ private FolderBrowserTableRow buildRow(final ContentItem item) { @@ -365,20 +366,20 @@ public class FolderBrowserController { row.setObjectUuid(item.getItemUuid()); row.setName(item.getName().getValue(defaultLocale)); final List languages = new ArrayList<>(itemL10NManager - .availableLanguages(item)); + .availableLanguages(item)); languages.sort((lang1, lang2) -> lang1.toString().compareTo( - lang2.toString())); + lang2.toString())); row.setLanguages(languages); if (item.getTitle().hasValue(globalizationHelper - .getNegotiatedLocale())) { + .getNegotiatedLocale())) { row.setTitle(item.getTitle().getValue(globalizationHelper - .getNegotiatedLocale())); + .getNegotiatedLocale())); } else { row.setTitle(item.getTitle().getValue(defaultLocale)); } final ContentType type = item.getContentType(); final ContentTypeInfo typeInfo = typesManager.getContentTypeInfo( - type); + type); row.setTypeLabelBundle(typeInfo.getLabelBundle()); row.setTypeLabelKey(typeInfo.getLabelKey()); @@ -404,21 +405,21 @@ public class FolderBrowserController { if (objectId.startsWith("folder-")) { final long folderId = Long.parseLong( - objectId.substring("folder-".length())); + objectId.substring("folder-".length())); folderRepo - .findById(folderId) - .ifPresent(folderRepo::delete); + .findById(folderId) + .ifPresent(folderRepo::delete); } else if (objectId.startsWith("item-")) { final long itemId = Long.parseLong( - objectId.substring("item-".length())); + objectId.substring("item-".length())); itemRepo - .findById(itemId) - .ifPresent(itemRepo::delete); + .findById(itemId) + .ifPresent(itemRepo::delete); } else { throw new IllegalArgumentException( - "The objectId is expected to start with 'folder-' or 'item.'."); + "The objectId is expected to start with 'folder-' or 'item.'."); } } @@ -434,21 +435,20 @@ public class FolderBrowserController { * name in ascending and descending order depending on the value of * {@code orderDirection}. * - * @param folder The folder which contains the subfolders. - * @param filterTerm The filter term. - * @param orderBy Field to use for ordering. If the value is negative - * the parameter is ignored. + * @param folder The folder which contains the subfolders. + * @param filterTerm The filter term. + * @param orderBy Field to use for ordering. If the value is negative the + * parameter is ignored. * @param orderDirection Direction for ordering. If the value is negative - * the parameter is ignored. - * @param firstResult Index of the first result to retrieve. - * @param maxResults Maxium number of results to retrieve. + * the parameter is ignored. + * @param firstResult Index of the first result to retrieve. + * @param maxResults Maxium number of results to retrieve. * * * @return A list of the subfolders of the provided {@code folder} which - * match the provided {@code filterTerm}. The list is ordered as - * described above. The list will contain at most {@code maxResults} - * starting with the result with the index provided as - * {@code firstResult}. + * match the provided {@code filterTerm}. The list is ordered as described + * above. The list will contain at most {@code maxResults} starting with the + * result with the index provided as {@code firstResult}. */ private List findSubFolders(final Folder folder, final String filterTerm, @@ -457,26 +457,27 @@ public class FolderBrowserController { final int firstResult, final int maxResults) { final CriteriaBuilder builder = entityManager - .getCriteriaBuilder(); + .getCriteriaBuilder(); final CriteriaQuery criteria = builder.createQuery( - Folder.class); + Folder.class); final Root from = criteria.from(Folder.class); final Order order; if (FolderBrowser.SORT_KEY_NAME.equals(orderBy) - && FolderBrowser.SORT_ACTION_DOWN.equals(orderDirection)) { + && FolderBrowser.SORT_ACTION_DOWN.equals(orderDirection)) { order = builder.desc(from.get("name")); } else { order = builder.asc(from.get("name")); } final TypedQuery query = entityManager.createQuery( - criteria.where(builder.and( - builder.equal(from.get("parentCategory"), folder), - builder - .like(builder.lower(from.get("name")), filterTerm))) - .orderBy(order)); + criteria.where(builder.and( + builder.equal(from.get("parentCategory"), folder), + builder + .like(builder.lower(from.get("name")), + filterTerm))) + .orderBy(order)); if (firstResult >= 0) { query.setFirstResult(firstResult); @@ -491,22 +492,21 @@ public class FolderBrowserController { /** * Retrieves all items of a folder matching the provided filter term. * - * @param folder The folder which contains the subfolders. - * @param filterTerm The filter term. - * @param orderBy Field to use for ordering. If the value is negative - * the parameter is ignored. + * @param folder The folder which contains the subfolders. + * @param filterTerm The filter term. + * @param orderBy Field to use for ordering. If the value is negative the + * parameter is ignored. * @param orderDirection Direction for ordering. If the value is negative - * the parameter is ignored. - * @param firstResult Index of the first result to retrieve. - * @param maxResults Maxium number of results to retrieve. + * the parameter is ignored. + * @param firstResult Index of the first result to retrieve. + * @param maxResults Maxium number of results to retrieve. * * * @return A list of the subfolders of the provided {@code folder} which - * match the provided {@code filterTerm}. The list is ordered the - * field provided as {@code orderBy} in the direction provided by - * {@code orderDirection}. The list will contain at most - * {@code maxResults} starting with the result with the index - * provided as {@code firstResult}. + * match the provided {@code filterTerm}. The list is ordered the field + * provided as {@code orderBy} in the direction provided by + * {@code orderDirection}. The list will contain at most {@code maxResults} + * starting with the result with the index provided as {@code firstResult}. */ private List findItemsInFolder(final Folder folder, final String filterTerm, @@ -516,13 +516,13 @@ public class FolderBrowserController { final int maxResults) { final CriteriaBuilder builder = entityManager - .getCriteriaBuilder(); + .getCriteriaBuilder(); final CriteriaQuery criteria = builder.createQuery( - ContentItem.class); + ContentItem.class); final Root fromItem = criteria.from(ContentItem.class); final Join join = fromItem.join( - "categories"); + "categories"); final Path orderPath; switch (orderBy) { @@ -548,16 +548,16 @@ public class FolderBrowserController { } final TypedQuery query = entityManager.createQuery(criteria - .select(fromItem) - .where(builder.and( - builder.equal(join.get("category"), folder), - builder.equal(join.get("type"), - CmsConstants.CATEGORIZATION_TYPE_FOLDER), - builder.equal(fromItem.get("version"), - ContentItemVersion.DRAFT), - builder.like(fromItem.get("displayName"), - filterTerm))) - .orderBy(order)); + .select(fromItem) + .where(builder.and( + builder.equal(join.get("category"), folder), + builder.equal(join.get("type"), + CmsConstants.CATEGORIZATION_TYPE_FOLDER), + builder.equal(fromItem.get("version"), + ContentItemVersion.DRAFT), + builder.like(fromItem.get("displayName"), + filterTerm))) + .orderBy(order)); if (firstResult >= 0) { query.setFirstResult(firstResult); @@ -575,7 +575,7 @@ public class FolderBrowserController { * @param folder The folder to check for live items. * * @return {@code true} if the {@code folder} or on of its subfolders - * contains at least one live item, {@code false} otherwise. + * contains at least one live item, {@code false} otherwise. */ @Transactional(Transactional.TxType.REQUIRED) public boolean hasLiveItems(final Folder folder) { @@ -585,25 +585,132 @@ public class FolderBrowserController { //Ensure that we use an non detached entity. final Folder theFolder = folderRepo.findById(folder.getObjectId()) - .orElseThrow(() -> new IllegalArgumentException(String.format( - "No folder with id %s in the database. Where did that ID come from?", - folder.getObjectId()))); + .orElseThrow(() -> new IllegalArgumentException(String.format( + "No folder with id %s in the database. Where did that ID come from?", + folder.getObjectId()))); final boolean hasLiveItem = theFolder.getObjects() - .stream() - .map(categorization -> categorization.getCategorizedObject()) - .filter(object -> object instanceof ContentItem) - .map(object -> (ContentItem) object) - .filter(item -> itemManager.isLive(item)) - .anyMatch(item -> itemManager.isLive(item)); + .stream() + .map(categorization -> categorization.getCategorizedObject()) + .filter(object -> object instanceof ContentItem) + .map(object -> (ContentItem) object) + .filter(item -> itemManager.isLive(item)) + .anyMatch(item -> itemManager.isLive(item)); if (hasLiveItem) { return true; } else { return theFolder.getSubFolders() - .stream() - .anyMatch(currentFolder -> hasLiveItems(currentFolder)); + .stream() + .anyMatch(currentFolder -> hasLiveItems(currentFolder)); } } + /** + * Get the IDs of the folders invalid for copy/move actions. + * + * @param sources + * @return + */ + @Transactional(Transactional.TxType.REQUIRED) + public List createInvalidTargetsList(final List sources) { + + Objects.requireNonNull(sources); + + final List sourceFolderIds = sources + .stream() + .filter(source -> source.startsWith( + FOLDER_BROWSER_KEY_PREFIX_FOLDER)) + .collect(Collectors.toList()); + final List parentFolderIds = sourceFolderIds + .stream() + .map(sourceFolderId -> findParentFolderId(sourceFolderId)) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toList()); + final List> subFolderIds = sourceFolderIds + .stream() + .map(sourceFolderId -> findSubFolderIds(sourceFolderId)) + .collect(Collectors.toList()); + + final List invalidTargetIds = new ArrayList<>(); + invalidTargetIds.addAll(sourceFolderIds); + invalidTargetIds.addAll(parentFolderIds); + for(final List subFolderIdList : subFolderIds) { + invalidTargetIds.addAll(subFolderIdList); + } + + return invalidTargetIds; + } + + private Optional findParentFolderId(final String folderId) { + + Objects.requireNonNull(folderId); + + if (!folderId.startsWith(FOLDER_BROWSER_KEY_PREFIX_FOLDER)) { + throw new IllegalArgumentException(String.format( + "Provided string '%s' is not an ID of a folder.", + folderId)); + } + + final long objectId = Long.parseLong(folderId.substring( + FOLDER_BROWSER_KEY_PREFIX_FOLDER.length())); + final Folder folder = folderRepo.findById(objectId) + .orElseThrow(() -> new IllegalArgumentException(String.format( + "No folder with ID %d found in database. " + + "Where did that ID come form?", + objectId))); + if (folder.getParentFolder() == null) { + return Optional.empty(); + } else { + return Optional.ofNullable(String.format( + "%s%d", + FOLDER_BROWSER_KEY_PREFIX_FOLDER, + folder.getParentFolder().getObjectId())); + } + } + + private List findSubFolderIds(final String folderId) { + + Objects.requireNonNull(folderId); + + if (!folderId.startsWith(FOLDER_BROWSER_KEY_PREFIX_FOLDER)) { + throw new IllegalArgumentException(String.format( + "Provided string '%s' is not the ID of a folder.", + folderId)); + } + + final long objectId = Long.parseLong(folderId.substring( + FOLDER_BROWSER_KEY_PREFIX_FOLDER.length())); + final Folder folder = folderRepo.findById(objectId) + .orElseThrow(() -> new IllegalArgumentException(String.format( + "No folder with ID %d found in database. " + + "Where did that ID come form?", + objectId))); + return findSubFolders(folder) + .stream() + .map(subFolder -> String.format("%s%d", + FOLDER_BROWSER_KEY_PREFIX_FOLDER, + subFolder.getObjectId())) + .collect(Collectors.toList()); + } + + private List findSubFolders(final Folder folder) { + + Objects.requireNonNull(folder); + + if (folder.getSubFolders() == null + || folder.getSubFolders().isEmpty()) { + return Collections.emptyList(); + } + + final List subFolders = new ArrayList<>(); + for(final Folder subFolder : folder.getSubFolders()) { + subFolders.add(subFolder); + subFolders.addAll(findSubFolders(subFolder)); + } + + return subFolders; + } + } diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderManipulator.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderManipulator.java index eedfe8c62..01d10834f 100755 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderManipulator.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderManipulator.java @@ -55,7 +55,6 @@ import com.arsdigita.bebop.form.SingleSelect; import com.arsdigita.bebop.form.Submit; import com.arsdigita.bebop.form.TextField; import com.arsdigita.bebop.parameters.ArrayParameter; -import com.arsdigita.bebop.parameters.LongParameter; import com.arsdigita.bebop.parameters.StringParameter; import com.arsdigita.bebop.table.TableCellRenderer; import com.arsdigita.bebop.table.TableColumn; @@ -67,6 +66,8 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import org.arsdigita.cms.CMSConfig; import org.libreccm.categorization.Category; @@ -92,14 +93,14 @@ import java.util.Objects; */ @SuppressWarnings("PMD.BeanMembersShouldSerialize") public class FolderManipulator extends SimpleContainer implements - //FormProcessListener, - //FormValidationListener, - //FormSubmissionListener, - Resettable { + //FormProcessListener, + //FormValidationListener, + //FormSubmissionListener, + Resettable { //public static final String RESOURCE_BUNDLE = "com.arsdigita.cms.ui.folder.CMSFolderResources"; private static final Logger LOGGER = LogManager.getLogger( - FolderManipulator.class); + FolderManipulator.class); private static final String ATOZ_FILTER_PARAM = "aToZfilter"; private static final String ACTION_PARAM = "act"; @@ -112,9 +113,9 @@ public class FolderManipulator extends SimpleContainer implements //private static final String UNPUBLISH = "UnPublish"; private final ArrayParameter sourcesParam = new ArrayParameter( - new StringParameter(SOURCES_PARAM)); + new StringParameter(SOURCES_PARAM)); private final StringParameter actionParam - = new StringParameter(ACTION_PARAM); + = new StringParameter(ACTION_PARAM); ; /** * The folder in which the source items live. @@ -126,9 +127,9 @@ public class FolderManipulator extends SimpleContainer implements private FilterForm filterForm; private final StringParameter atozFilterParam = new StringParameter( - ATOZ_FILTER_PARAM); + ATOZ_FILTER_PARAM); private final StringParameter filterParam - = new StringParameter(FILTER_PARAM); + = new StringParameter(FILTER_PARAM); public FolderManipulator(final FolderSelectionModel folderModel) { @@ -142,9 +143,9 @@ public class FolderManipulator extends SimpleContainer implements targetSelector.addProcessListener(new TargetSelectorProcessListener()); targetSelector.addValidationListener( - new TargetSelectorValidationListener()); + new TargetSelectorValidationListener()); targetSelector.addSubmissionListener( - new TargetSelectorSubmissionListener()); + new TargetSelectorSubmissionListener()); add(targetSelector); //publishDialog.addProcessListener(new PublishDialogProcessListener()); @@ -423,7 +424,7 @@ public class FolderManipulator extends SimpleContainer implements @Override public void process(final FormSectionEvent event) - throws FormProcessException { + throws FormProcessException { final PageState state = event.getPageState(); @@ -442,7 +443,7 @@ public class FolderManipulator extends SimpleContainer implements @Override public void process(final FormSectionEvent event) throws - FormProcessException { + FormProcessException { final PageState state = event.getPageState(); @@ -498,7 +499,7 @@ public class FolderManipulator extends SimpleContainer implements @Override public void validate(final FormSectionEvent event) throws - FormProcessException { + FormProcessException { final PageState state = event.getPageState(); final FormData data = event.getFormData(); @@ -512,7 +513,7 @@ public class FolderManipulator extends SimpleContainer implements } private class TargetSelectorValidationListener implements - FormValidationListener { + FormValidationListener { public TargetSelectorValidationListener() { //Nothing @@ -520,7 +521,7 @@ public class FolderManipulator extends SimpleContainer implements @Override public void validate(final FormSectionEvent event) throws - FormProcessException { + FormProcessException { final PageState state = event.getPageState(); @@ -532,25 +533,25 @@ public class FolderManipulator extends SimpleContainer implements final FormData data = event.getFormData(); if (target == null) { data.addError(new GlobalizedMessage( - "cms.ui.folder.need_select_target_folder", - CmsConstants.CMS_FOLDER_BUNDLE)); + "cms.ui.folder.need_select_target_folder", + CmsConstants.CMS_FOLDER_BUNDLE)); //If the target is null, we can skip the rest of the checks return; } if (target.equals(sourceFolderModel.getSelectedObject(state))) { data.addError(new GlobalizedMessage( - "cms.ui.folder.not_within_same_folder", - CmsConstants.CMS_FOLDER_BUNDLE)); + "cms.ui.folder.not_within_same_folder", + CmsConstants.CMS_FOLDER_BUNDLE)); } // check create item permission final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); final Shiro shiro = cdiUtil.findBean(Shiro.class); final PermissionChecker permissionChecker = cdiUtil.findBean( - PermissionChecker.class); + PermissionChecker.class); if (!permissionChecker.isPermitted( - ItemPrivileges.CREATE_NEW, target)) { + ItemPrivileges.CREATE_NEW, target)) { data.addError("cms.ui.folder.no_permission_for_item", CmsConstants.CMS_FOLDER_BUNDLE); } @@ -572,24 +573,24 @@ public class FolderManipulator extends SimpleContainer implements final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); final FolderRepository folderRepo = cdiUtil.findBean( - FolderRepository.class); + FolderRepository.class); final ContentItemRepository itemRepo = cdiUtil.findBean( - ContentItemRepository.class); + ContentItemRepository.class); final ContentItemManager itemManager = cdiUtil.findBean( - ContentItemManager.class); + ContentItemManager.class); final FolderBrowserController controller = cdiUtil.findBean( - FolderBrowserController.class); + FolderBrowserController.class); final PermissionChecker permissionChecker = cdiUtil.findBean( - PermissionChecker.class); + PermissionChecker.class); final CcmObject object; final String name; if (objectId.startsWith("folder--")) { final long folderId = Long.parseLong(objectId.substring( - "folder--".length())); + "folder--".length())); final Folder folder = folderRepo.findById(folderId).orElseThrow( - () -> new IllegalArgumentException(String.format( - "No folder with id %d in database.", folderId))); + () -> new IllegalArgumentException(String.format( + "No folder with id %d in database.", folderId))); name = folder.getName(); @@ -602,10 +603,11 @@ public class FolderManipulator extends SimpleContainer implements } else if (objectId.startsWith("item--")) { final long itemId = Long.parseLong(objectId.substring( - "item--".length())); + "item--".length())); final ContentItem item = itemRepo.findById(itemId).orElseThrow( - () -> new IllegalArgumentException(String.format( - "No content item with id %d in database.", itemId))); + () -> new IllegalArgumentException(String.format( + "No content item with id %d in database.", + itemId))); name = item.getDisplayName(); @@ -616,9 +618,9 @@ public class FolderManipulator extends SimpleContainer implements object = item; } else { throw new IllegalArgumentException(String.format( - "Provided objectId '%s' does not start with 'folder--' " - + "or 'item--'.", - objectId)); + "Provided objectId '%s' does not start with 'folder--' " + + "or 'item--'.", + objectId)); } final long count = controller.countObjects(target, name); @@ -630,7 +632,7 @@ public class FolderManipulator extends SimpleContainer implements if (!(permissionChecker.isPermitted( ItemPrivileges.DELETE, object)) - && isMove(state)) { + && isMove(state)) { addErrorMessage(data, "cms.ui.folder.no_permission_for_item", object.getDisplayName()); @@ -659,7 +661,7 @@ public class FolderManipulator extends SimpleContainer implements // } // } private class TargetSelectorSubmissionListener implements - FormSubmissionListener { + FormSubmissionListener { public TargetSelectorSubmissionListener() { //Nothing @@ -667,15 +669,15 @@ public class FolderManipulator extends SimpleContainer implements @Override public void submitted(final FormSectionEvent event) throws - FormProcessException { + FormProcessException { final PageState state = event.getPageState(); if (targetSelector.isCancelled(state)) { reset(state); throw new FormProcessException(new GlobalizedMessage( - "cms.ui.folder.cancelled", - CmsConstants.CMS_FOLDER_BUNDLE)); + "cms.ui.folder.cancelled", + CmsConstants.CMS_FOLDER_BUNDLE)); } } @@ -719,25 +721,25 @@ public class FolderManipulator extends SimpleContainer implements final Label label = (Label) event.getTarget(); final int numberOfItems = getSources(state).length; final Category folder = (Category) sourceFolderModel. - getSelectedObject(state); + getSelectedObject(state); final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); final CategoryManager categoryManager = cdiUtil. - findBean(CategoryManager.class); + findBean(CategoryManager.class); if (isMove(state)) { label.setLabel(new GlobalizedMessage( - "cms.ui.folder.move", - CmsConstants.CMS_FOLDER_BUNDLE, - new Object[]{numberOfItems, - categoryManager.getCategoryPath( - folder)})); + "cms.ui.folder.move", + CmsConstants.CMS_FOLDER_BUNDLE, + new Object[]{numberOfItems, + categoryManager.getCategoryPath( + folder)})); } else if (isCopy(state)) { label.setLabel(new GlobalizedMessage( - "cms.ui.folder.copy", - new Object[]{numberOfItems, - categoryManager.getCategoryPath( - folder)})); + "cms.ui.folder.copy", + new Object[]{numberOfItems, + categoryManager.getCategoryPath( + folder)})); } } @@ -761,13 +763,13 @@ public class FolderManipulator extends SimpleContainer implements // Set things up the first time the selector gets visible public void expose(final PageState state) { final Category folder = (Category) sourceFolderModel. - getSelectedObject( - state); + getSelectedObject( + state); targetModel.clearSelection(state); if (folder != null) { final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); final ContentItemManager itemManager = cdiUtil.findBean( - ContentItemManager.class); + ContentItemManager.class); //ToDo // final ItemCollection items = folder.getPathInfo(true); @@ -864,15 +866,15 @@ public class FolderManipulator extends SimpleContainer implements // folderBrowser.setFilterForm(filterForm); folderBrowser.setFolderManipulator(FolderManipulator.this); paginator = new Paginator( - new FolderBrowserPaginationModelBuilder(folderBrowser), - CMSConfig.getConfig().getFolderBrowseListSize()); + new FolderBrowserPaginationModelBuilder(folderBrowser), + CMSConfig.getConfig().getFolderBrowseListSize()); folderBrowser.setPaginator(paginator); panel.add(paginator); panel.add(folderBrowser); LOGGER.debug("Adding filter form..."); filterForm = new FilterForm(new FolderBrowserFilterFormModelBuilder( - folderBrowser)); + folderBrowser)); FolderManipulator.this.add(filterForm); checkboxGroup = new CheckboxGroup(sourcesParam); @@ -884,19 +886,19 @@ public class FolderManipulator extends SimpleContainer implements group.addAction(container); container.add(new Label(new GlobalizedMessage( - "cms.ui.folder.edit_selection", - CmsConstants.CMS_FOLDER_BUNDLE))); + "cms.ui.folder.edit_selection", + CmsConstants.CMS_FOLDER_BUNDLE))); actionSelect = new SingleSelect(actionParam); actionSelect.addOption( - new Option(COPY, - new Label(new GlobalizedMessage( - "cms.ui.folder.copy.action", - CmsConstants.CMS_FOLDER_BUNDLE)))); + new Option(COPY, + new Label(new GlobalizedMessage( + "cms.ui.folder.copy.action", + CmsConstants.CMS_FOLDER_BUNDLE)))); actionSelect.addOption( - new Option(MOVE, - new Label(new GlobalizedMessage( - "cms.ui.folder.move.action", - CmsConstants.CMS_FOLDER_BUNDLE)))); + new Option(MOVE, + new Label(new GlobalizedMessage( + "cms.ui.folder.move.action", + CmsConstants.CMS_FOLDER_BUNDLE)))); //Publishing in the folder browser only works if threaded publishing is active // if (CMSConfig.getInstanceOf().getThreadedPublishing()) { // actionSelect.addOption(new Option(PUBLISH, @@ -909,8 +911,8 @@ public class FolderManipulator extends SimpleContainer implements container.add(actionSelect); submit = new Submit("Go", new GlobalizedMessage( - "cms.ui.folder.go", - CmsConstants.CMS_FOLDER_BUNDLE)); + "cms.ui.folder.go", + CmsConstants.CMS_FOLDER_BUNDLE)); container.add(submit); // Add a new first column to the table @@ -988,8 +990,8 @@ public class FolderManipulator extends SimpleContainer implements panel = new BoxPanel(BoxPanel.HORIZONTAL); final ActionLink allLink = new ActionLink( - new GlobalizedMessage("cms.ui.folder.filter.all", - CmsConstants.CMS_FOLDER_BUNDLE)); + new GlobalizedMessage("cms.ui.folder.filter.all", + CmsConstants.CMS_FOLDER_BUNDLE)); allLink.addActionListener(new ActionListener() { @Override @@ -1015,14 +1017,14 @@ public class FolderManipulator extends SimpleContainer implements // panel.add(link); // } panel.add(new Label(new GlobalizedMessage( - "cms.ui.folder.filter", - CmsConstants.CMS_FOLDER_BUNDLE))); + "cms.ui.folder.filter", + CmsConstants.CMS_FOLDER_BUNDLE))); filterField = new TextField(filterParam); panel.add(filterField); panel.add(new Submit("filterFolderSubmit", new GlobalizedMessage( - "cms.ui.folder.filter_do", - CmsConstants.CMS_FOLDER_BUNDLE))); + "cms.ui.folder.filter_do", + CmsConstants.CMS_FOLDER_BUNDLE))); add(panel); @@ -1034,28 +1036,28 @@ public class FolderManipulator extends SimpleContainer implements @Override public void process(final FormSectionEvent event) throws - FormProcessException { + FormProcessException { //Nothing } @Override public void init(final FormSectionEvent event) throws - FormProcessException { + FormProcessException { //fse.getPageState().setValue(FolderManipulator.this.m_filter, null); //filterField.setValue(fse.getPageState(), null); } @Override public void submitted(final FormSectionEvent event) throws - FormProcessException { + FormProcessException { } @Override public boolean isVisible(PageState state) { if (super.isVisible(state) - && (modelBuilder.getFolderSize(state) - >= CMSConfig.getConfig(). - getFolderAtoZShowLimit())) { + && (modelBuilder.getFolderSize(state) + >= CMSConfig.getConfig(). + getFolderAtoZShowLimit())) { return true; } else { return false; @@ -1086,7 +1088,8 @@ public class FolderManipulator extends SimpleContainer implements // } private class FolderTreeCellRenderer implements TreeCellRenderer { - private RequestLocal m_invalidFolders = new RequestLocal(); + private final RequestLocal invalidFoldersRequestLocal + = new RequestLocal(); /** * Render the folders appropriately. The selected folder is a bold @@ -1104,72 +1107,19 @@ public class FolderManipulator extends SimpleContainer implements final Object key) { // Get the list of invalid folders once per request. - @SuppressWarnings("unchecked") - ArrayList invalidFolders - = (ArrayList) m_invalidFolders.get(state); - - if (invalidFolders == null) { - // The list of invalid folders has not been set for this - // request. Setting now. - invalidFolders = new ArrayList<>(); - final String[] sources = getSources(state); - - for (final String source : sources) { - if (source.startsWith("folder--")) { - invalidFolders.addAll(source); - } - } - - - + final List invalidFolders; + if (invalidFoldersRequestLocal.get(state) == null) { + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final FolderBrowserController controller = cdiUtil.findBean( + FolderBrowserController.class); + invalidFolders = controller.createInvalidTargetsList( + Arrays.asList(getSources(state))); + invalidFoldersRequestLocal.set(state, invalidFolders); + } else { + invalidFolders = (List) invalidFoldersRequestLocal + .get(state); } -// if (invalidFolders == null) { -// // The list of invalid folders has not been set for this -// // request. Setting now. -// invalidFolders = new ArrayList(); -// -// final DataCollection collection = SessionManager.getSession(). -// retrieve( -// ContentItem.BASE_DATA_OBJECT_TYPE); -// CompoundFilter filter = collection.getFilterFactory().or(); -// // The sources themselves are not valid. -// final Long[] sources = getSources(state); -// -// for (int i = 0; i < sources.length; i++) { -// invalidFolders.add(sources[i].toString()); -// -// final Filter temp = filter.addFilter("id = :id" + i); -// temp.set("id" + i, sources[i]); -// } -// collection.addFilter(filter); -// -// final DataCollection folders = SessionManager.getSession(). -// retrieve( -// Folder.BASE_DATA_OBJECT_TYPE); -// folders.addEqualsFilter(Folder.IS_DELETED, Boolean.FALSE); -// -// filter = collection.getFilterFactory().or(); -// int count = 0; -// while (collection.next()) { -// filter.addFilter(Folder.ANCESTORS + " like :ancestors" -// + count + " || '%'"); -// filter.set("ancestors" + count, -// collection.get(ContentItem.ANCESTORS)); -// count++; -// } -// folders.addFilter(filter); -// -// while (folders.next()) { -// invalidFolders.add(folders.get(Folder.ID).toString()); -// } -// -// invalidFolders.add(sourceFolderModel.getSelectedKey(state). -// toString()); -// -// // Save the invalid folder list -// m_invalidFolders.set(state, invalidFolders); -// } final Label label = new Label(value.toString()); if (invalidFolders.contains(key.toString())) { diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderTreeModelController.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderTreeModelController.java index fe7fa02d0..2c9782137 100644 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderTreeModelController.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderTreeModelController.java @@ -26,7 +26,6 @@ import org.librecms.contentsection.Folder; import org.librecms.contentsection.FolderRepository; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.Optional; diff --git a/ccm-cms/src/main/java/org/librecms/CmsConstants.java b/ccm-cms/src/main/java/org/librecms/CmsConstants.java index 47faa26c3..7618ba8f5 100644 --- a/ccm-cms/src/main/java/org/librecms/CmsConstants.java +++ b/ccm-cms/src/main/java/org/librecms/CmsConstants.java @@ -54,6 +54,9 @@ public class CmsConstants { public static final String CATEGORIZATION_TYPE_FOLDER = "folder"; + public static final String FOLDER_BROWSER_KEY_PREFIX_FOLDER = "folder-"; + public static final String FOLDER_BROWSER_KEY_PREFIX_ITEM = "item-"; + /** * Constant string used as key for creating service package as a legacy * application.