CCM NG/ccm-cms: Optimised ContentItemManger#publish

git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@4429 8810af33-2d31-482b-a856-94f89814c4df
pull/2/head
jensp 2016-11-03 11:58:59 +00:00
parent 48588b8a1f
commit aa95d07092
4 changed files with 508 additions and 426 deletions

View File

@ -135,6 +135,11 @@ public class AssetManager {
* {@code false if not}. * {@code false if not}.
*/ */
public boolean isShared(final Asset asset) { public boolean isShared(final Asset asset) {
if (asset == null) {
throw new IllegalArgumentException(
"Can't determine if null is a shared asset.");
}
return getAssetFolder(asset).isPresent(); return getAssetFolder(asset).isPresent();
} }
@ -149,8 +154,8 @@ public class AssetManager {
final List<Asset> orphaned = assets.stream() final List<Asset> orphaned = assets.stream()
.filter(asset -> asset.getCategories().isEmpty() .filter(asset -> asset.getCategories().isEmpty()
&& asset.getItemAttachments().isEmpty()) && asset.getItemAttachments().isEmpty()).
.collect(Collectors.toList()); collect(Collectors.toList());
orphaned.forEach(orphan -> assetRepo.delete(orphan)); orphaned.forEach(orphan -> assetRepo.delete(orphan));
} }
@ -394,6 +399,10 @@ public class AssetManager {
*/ */
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public boolean isAssetInUse(final Asset asset) { public boolean isAssetInUse(final Asset asset) {
if (asset == null) {
throw new IllegalArgumentException("Can't verify if null is in use.");
}
return !asset.getItemAttachments().isEmpty(); return !asset.getItemAttachments().isEmpty();
} }
@ -416,8 +425,7 @@ public class AssetManager {
/** /**
* Returns the path of an item as String. * Returns the path of an item as String.
* *
* @param asset The {@link Asset} for which the path is * @param asset The {@link Asset} for which the path is generated.
* generated.
* @param withContentSection Whether to include the content section into the * @param withContentSection Whether to include the content section into the
* path or not. * path or not.
* *
@ -521,6 +529,15 @@ public class AssetManager {
* shared asset an empty {@link Optional} is returned. * shared asset an empty {@link Optional} is returned.
*/ */
public Optional<Folder> getAssetFolder(final Asset asset) { public Optional<Folder> getAssetFolder(final Asset asset) {
if (asset == null) {
throw new IllegalArgumentException(
"Can't retrieve the folder for asset null.");
}
if (asset.getCategories() == null) {
return Optional.empty();
}
return asset.getCategories().stream() return asset.getCategories().stream()
.filter(categorization -> { .filter(categorization -> {
return CATEGORIZATION_TYPE_FOLDER.equals( return CATEGORIZATION_TYPE_FOLDER.equals(

View File

@ -64,7 +64,6 @@ import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.logging.Level;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.TypedQuery; import javax.persistence.TypedQuery;
@ -170,8 +169,7 @@ public class ContentItemManager {
* *
* @param <T> The type of the content item. * @param <T> The type of the content item.
* @param name The name (URL stub) of the new content item. * @param name The name (URL stub) of the new content item.
* @param section The content section in which the item is * @param section The content section in which the item is generated.
* generated.
* @param folder The folder in which in the item is stored. * @param folder The folder in which in the item is stored.
* @param workflowTemplate The template for the workflow to apply to the new * @param workflowTemplate The template for the workflow to apply to the new
* item. * item.
@ -321,9 +319,8 @@ public class ContentItemManager {
* *
* @param item The item to copy. * @param item The item to copy.
* @param targetFolder The folder in which the copy is created. If the * @param targetFolder The folder in which the copy is created. If the
* target folder is the same folder as the folder of the * target folder is the same folder as the folder of the original item an
* original item an index is appended to the name of the * index is appended to the name of the item.
* item.
* *
* @return The copy of the item * @return The copy of the item
*/ */
@ -447,9 +444,7 @@ public class ContentItemManager {
throw new RuntimeException(ex); throw new RuntimeException(ex);
} }
source.getAvailableLocales().forEach( copyLocalizedString(source, target);
locale -> target.addValue(locale,
source.getValue(locale)));
} else if (propType != null } else if (propType != null
&& propType.isAssignableFrom(ContentItem.class)) { && propType.isAssignableFrom(ContentItem.class)) {
@ -564,25 +559,19 @@ public class ContentItemManager {
return result; return result;
} }
private void copyAttachmentList(final AttachmentList list, private void copyAttachmentList(final AttachmentList sourceList,
final ContentItem target) { final ContentItem target) {
final AttachmentList targetList = new AttachmentList(); final AttachmentList targetList = new AttachmentList();
for (final Locale locale : list.getDescription().getAvailableLocales()) { copyLocalizedString(sourceList.getDescription(), targetList.getDescription());
targetList.getDescription().addValue(
locale, list.getDescription().getValue(locale));
}
targetList.setItem(target); targetList.setItem(target);
targetList.setName(list.getName()); targetList.setName(sourceList.getName());
targetList.setOrder(list.getOrder()); targetList.setOrder(sourceList.getOrder());
for (Map.Entry<Locale, String> title : list.getTitle().getValues() copyLocalizedString(sourceList.getTitle(), targetList.getTitle());
.entrySet()) {
targetList.getTitle().addValue(title.getKey(), title.getValue());
}
targetList.setUuid(UUID.randomUUID().toString()); targetList.setUuid(UUID.randomUUID().toString());
entityManager.persist(list); entityManager.persist(sourceList);
for (ItemAttachment<?> attachment : list.getAttachments()) { for (ItemAttachment<?> attachment : sourceList.getAttachments()) {
if (assetManager.isShared(attachment.getAsset())) { if (assetManager.isShared(attachment.getAsset())) {
copySharedAssetAttachment(attachment, targetList); copySharedAssetAttachment(attachment, targetList);
} else { } else {
@ -590,7 +579,7 @@ public class ContentItemManager {
} }
} }
entityManager.merge(list); entityManager.merge(sourceList);
} }
private void copySharedAssetAttachment(final ItemAttachment<?> attachment, private void copySharedAssetAttachment(final ItemAttachment<?> attachment,
@ -616,6 +605,39 @@ public class ContentItemManager {
throw new UncheckedWrapperException(ex); throw new UncheckedWrapperException(ex);
} }
copyAsset(source, target);
entityManager.persist(target);
final ItemAttachment<Asset> targetAttachment = new ItemAttachment<>();
targetAttachment.setAsset(target);
targetAttachment.setSortKey(attachment.getSortKey());
targetAttachment.setUuid(UUID.randomUUID().toString());
entityManager.persist(targetAttachment);
targetAttachment.setAttachmentList(targetList);
targetList.addAttachment(targetAttachment);
entityManager.merge(targetAttachment);
}
public void copyAsset(final Asset source, final Asset target) {
if (source == null) {
throw new IllegalArgumentException("Source Asset can't be null.");
}
if (target == null) {
throw new IllegalArgumentException("Target Asset can't be null.");
}
if (!source.getClass().equals(target.getClass())) {
throw new IllegalArgumentException(String.format(
"Asset belong to different classes. source is instance of "
+ "\"%s\", target is instance of \"%s\". It is not "
+ "possible to use assets of diffierent classes "
+ "with this method",
source.getClass().getName(),
target.getClass().getName()));
}
final BeanInfo beanInfo; final BeanInfo beanInfo;
try { try {
beanInfo = Introspector.getBeanInfo(source.getClass()); beanInfo = Introspector.getBeanInfo(source.getClass());
@ -623,8 +645,8 @@ public class ContentItemManager {
throw new UncheckedWrapperException(ex); throw new UncheckedWrapperException(ex);
} }
for (final PropertyDescriptor propertyDescriptor : beanInfo for (final PropertyDescriptor propertyDescriptor : beanInfo.
.getPropertyDescriptors()) { getPropertyDescriptors()) {
final String propertyName = propertyDescriptor.getName(); final String propertyName = propertyDescriptor.getName();
if ("objectId".equals(propertyName) if ("objectId".equals(propertyName)
|| "uuid".equals(propertyName) || "uuid".equals(propertyName)
@ -653,9 +675,7 @@ public class ContentItemManager {
throw new UncheckedWrapperException(ex); throw new UncheckedWrapperException(ex);
} }
sourceStr.getAvailableLocales().forEach( copyLocalizedString(sourceStr, targetStr);
locale -> targetStr.addValue(locale,
sourceStr.getValue(locale)));
} else { } else {
final Object value; final Object value;
try { try {
@ -669,18 +689,16 @@ public class ContentItemManager {
} }
} }
if (target.getUuid() == null || target.getUuid().isEmpty()) {
target.setUuid(UUID.randomUUID().toString()); target.setUuid(UUID.randomUUID().toString());
}
}
entityManager.persist(target); private void copyLocalizedString(final LocalizedString source,
final ItemAttachment<Asset> targetAttachment = new ItemAttachment<>(); final LocalizedString target) {
targetAttachment.setAsset(target); for (final Locale locale : source.getAvailableLocales()) {
targetAttachment.setSortKey(attachment.getSortKey()); target.addValue(locale, source.getValue(locale));
targetAttachment.setUuid(UUID.randomUUID().toString()); }
entityManager.persist(targetAttachment);
targetAttachment.setAttachmentList(targetList);
targetList.addAttachment(targetAttachment);
entityManager.merge(targetAttachment);
} }
/** /**
@ -726,6 +744,7 @@ public class ContentItemManager {
@RequiresPrivilege(ItemPrivileges.PUBLISH) @RequiresPrivilege(ItemPrivileges.PUBLISH)
final ContentItem item, final ContentItem item,
final LifecycleDefinition lifecycleDefinition) { final LifecycleDefinition lifecycleDefinition) {
if (item == null) { if (item == null) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"The item to publish can't be null."); "The item to publish can't be null.");
@ -741,17 +760,15 @@ public class ContentItemManager {
final ContentItem liveItem; final ContentItem liveItem;
if (isLive(item)) { if (isLive(item)) {
final ContentItem oldLiveItem = getLiveVersion( liveItem = getLiveVersion(item, ContentItem.class).get();
item, ContentItem.class).get(); // unpublish(oldLiveItem);
unpublish(oldLiveItem); } else {
}
// else {
try { try {
liveItem = draftItem.getClass().newInstance(); liveItem = draftItem.getClass().newInstance();
} catch (InstantiationException | IllegalAccessException ex) { } catch (InstantiationException | IllegalAccessException ex) {
throw new RuntimeException(ex); throw new RuntimeException(ex);
} }
// } }
liveItem.setVersion(ContentItemVersion.PUBLISHING); liveItem.setVersion(ContentItemVersion.PUBLISHING);
liveItem.setItemUuid(draftItem.getItemUuid()); liveItem.setItemUuid(draftItem.getItemUuid());
@ -781,10 +798,78 @@ public class ContentItemManager {
categorization.getCategory(), categorization.getCategory(),
categorization.getType())); categorization.getType()));
for (AttachmentList attachmentList : item.getAttachments()) { for (int i = 0; i < draftItem.getAttachments().size(); i++) {
copyAttachmentList(attachmentList, liveItem); final AttachmentList sourceList = draftItem.getAttachments().get(i);
final AttachmentList targetList;
if (liveItem.getAttachments().size() < i + 1) {
targetList = new AttachmentList();
copyLocalizedString(sourceList.getDescription(),
targetList.getDescription());
targetList.setItem(liveItem);
liveItem.addAttachmentList(targetList);
targetList.setName(sourceList.getName());
copyLocalizedString(sourceList.getTitle(),
targetList.getTitle());
targetList.setOrder(sourceList.getOrder());
targetList.setUuid(UUID.randomUUID().toString());
} else {
targetList = liveItem.getAttachments().get(i);
} }
for (int j = 0; j < sourceList.getAttachments().size(); j++) {
final ItemAttachment<?> sourceAttachment = sourceList.
getAttachments().get(j);
final ItemAttachment<Asset> targetAttachment;
if (targetList.getAttachments().size() < j + 1) {
targetAttachment = new ItemAttachment<>();
} else {
targetAttachment = (ItemAttachment<Asset>) targetList.
getAttachments().get(j);
}
if (!sourceAttachment.getAsset().equals(targetAttachment)) {
final Asset oldTargetAsset = targetAttachment.getAsset();
if (oldTargetAsset != null
&& !assetManager.isShared(oldTargetAsset)) {
targetAttachment.setAsset(null);
oldTargetAsset.removeItemAttachment(targetAttachment);
entityManager.remove(oldTargetAsset);
}
final Asset sourceAsset = sourceAttachment.getAsset();
final Asset targetAsset;
if (assetManager.isShared(sourceAttachment.getAsset())) {
targetAsset = sourceAttachment.getAsset();
} else {
try {
targetAsset = sourceAttachment.getAsset().getClass().
newInstance();
} catch (InstantiationException | IllegalAccessException ex) {
throw new UncheckedWrapperException(ex);
}
copyAsset(sourceAsset, targetAsset);
entityManager.persist(targetAsset);
}
targetAttachment.setAsset(targetAsset);
targetAttachment.setAttachmentList(targetList);
targetAttachment.setSortKey(sourceAttachment.getSortKey());
targetAttachment.setUuid(UUID.randomUUID().toString());
}
targetList.addAttachment(targetAttachment);
entityManager.persist(targetAttachment);
entityManager.merge(targetList);
}
}
// for (AttachmentList attachmentList : item.getAttachments()) {
// copyAttachmentList(attachmentList, liveItem);
// }
final BeanInfo beanInfo; final BeanInfo beanInfo;
try { try {
beanInfo = Introspector.getBeanInfo(item.getClass()); beanInfo = Introspector.getBeanInfo(item.getClass());
@ -819,9 +904,7 @@ public class ContentItemManager {
throw new RuntimeException(ex); throw new RuntimeException(ex);
} }
source.getAvailableLocales().forEach( copyLocalizedString(source, target);
locale -> target.addValue(locale, source.
getValue(locale)));
} else if (propType != null } else if (propType != null
&& propType.isAssignableFrom(ContentItem.class)) { && propType.isAssignableFrom(ContentItem.class)) {
final ContentItem linkedItem; final ContentItem linkedItem;
@ -1060,9 +1143,9 @@ public class ContentItemManager {
* @param type Type of the content item. * @param type Type of the content item.
* *
* @return The live version of an item. If the item provided is already the * @return The live version of an item. If the item provided is already the
* live version the provided item is returned, otherwise the live * live version the provided item is returned, otherwise the live version is
* version is returned. If there is no live version an empty * returned. If there is no live version an empty {@link Optional} is
* {@link Optional} is returned. * returned.
*/ */
@AuthorizationRequired @AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
@ -1120,10 +1203,10 @@ public class ContentItemManager {
* @param type Type of the item. * @param type Type of the item.
* *
* @return The draft version of the provided content item. If the provided * @return The draft version of the provided content item. If the provided
* item is the draft version the provided item is simply returned. * item is the draft version the provided item is simply returned. Otherwise
* Otherwise the draft version is retrieved from the database and is * the draft version is retrieved from the database and is returned. Each
* returned. Each content item has a draft version (otherwise * content item has a draft version (otherwise something is seriously wrong
* something is seriously wrong with the database) this method will * with the database) this method will
* <b>never</b> return {@code null}. * <b>never</b> return {@code null}.
*/ */
@AuthorizationRequired @AuthorizationRequired

View File

@ -157,12 +157,12 @@
<ccm_core.ccm_objects_aud object_id="-10200" <ccm_core.ccm_objects_aud object_id="-10200"
rev="0" rev="0"
revtype="0" revtype="0"
revend="6" revend="5"
display_name="article2" /> display_name="article2" />
<ccm_core.ccm_objects_aud object_id="-99200" <ccm_core.ccm_objects_aud object_id="-99200"
rev="0" rev="0"
revtype="0" revtype="0"
revend="6" revend="5"
display_name="article2" /> display_name="article2" />
<ccm_core.ccm_objects_aud object_id="-10300" <ccm_core.ccm_objects_aud object_id="-10300"
rev="0" rev="0"
@ -173,16 +173,13 @@
revtype="0" revtype="0"
display_name="news1" /> display_name="news1" />
<ccm_core.ccm_objects_aud object_id="-10200" <ccm_core.ccm_objects_aud object_id="-10200"
rev="6" rev="5"
revtype="1" revtype="1"
display_name="article2" /> display_name="article2" />
<ccm_core.ccm_objects_aud object_id="-99300"
rev="6"
revtype="0"
display_name="article2" />
<ccm_core.ccm_objects_aud object_id="-99200" <ccm_core.ccm_objects_aud object_id="-99200"
rev="6" rev="5"
revtype="2" /> revtype="1"
display_name="article2" />
<ccm_core.ccm_objects_aud object_id="-11100" <ccm_core.ccm_objects_aud object_id="-11100"
rev="0" rev="0"
revtype="0" revtype="0"
@ -387,14 +384,12 @@
version="DRAFT" version="DRAFT"
content_type_id="-20200"/> content_type_id="-20200"/>
<ccm_cms.content_items_aud object_id="-10200" <ccm_cms.content_items_aud object_id="-10200"
rev="6" rev="5"
item_uuid="acae860f-2ffa-450d-b486-054292f0dae6" item_uuid="acae860f-2ffa-450d-b486-054292f0dae6"
version="DRAFT" version="DRAFT"
content_type_id="-20100"/> content_type_id="-20100"/>
<ccm_cms.content_items_aud object_id="-99200" <ccm_cms.content_items_aud object_id="-99200"
rev="6" /> rev="5"
<ccm_cms.content_items_aud object_id="-99300"
rev="6"
item_uuid="00000000-0000-0000-0000-000000000000" item_uuid="00000000-0000-0000-0000-000000000000"
version="LIVE" version="LIVE"
content_type_id="-20100"/> content_type_id="-20100"/>
@ -424,7 +419,7 @@
object_id="-10200" object_id="-10200"
localized_value="article2" localized_value="article2"
locale="en" locale="en"
revend="6" revend="5"
revtype="0" /> revtype="0" />
<ccm_cms.content_item_names_aud rev="0" <ccm_cms.content_item_names_aud rev="0"
object_id="-10300" object_id="-10300"
@ -441,23 +436,23 @@
localized_value="article2" localized_value="article2"
locale="en" locale="en"
revtype="0" revtype="0"
revend="6"/> revend="5"/>
<ccm_cms.content_item_names_aud rev="6" <ccm_cms.content_item_names_aud rev="5"
object_id="-10200" object_id="-10200"
localized_value="article2-edited" localized_value="article2-edited"
locale="en" locale="en"
revtype="0" /> revtype="0" />
<ccm_cms.content_item_names_aud rev="6" <ccm_cms.content_item_names_aud rev="5"
object_id="-10200" object_id="-10200"
localized_value="article2" localized_value="article2"
locale="en" locale="en"
revtype="2" /> revtype="2" />
<ccm_cms.content_item_names_aud rev="6" <ccm_cms.content_item_names_aud rev="5"
object_id="-99300" object_id="-99300"
localized_value="article2-edited" localized_value="article2-edited"
locale="en" locale="en"
revtype="0" /> revtype="0" />
<ccm_cms.content_item_names_aud rev="6" <ccm_cms.content_item_names_aud rev="5"
object_id="-99200" object_id="-99200"
localized_value="article2" localized_value="article2"
locale="en" locale="en"
@ -504,22 +499,22 @@
localized_value="Article 2 Title" localized_value="Article 2 Title"
locale="en" locale="en"
revtype="0" /> revtype="0" />
<ccm_cms.content_item_titles_aud rev="6" <ccm_cms.content_item_titles_aud rev="5"
object_id="-10200" object_id="-10200"
localized_value="Article has been edited" localized_value="Article has been edited"
locale="en" locale="en"
revtype="0" /> revtype="0" />
<ccm_cms.content_item_titles_aud rev="6" <ccm_cms.content_item_titles_aud rev="5"
object_id="-10200" object_id="-10200"
localized_value="Article 2" localized_value="Article 2"
locale="en" locale="en"
revtype="2" /> revtype="2" />
<ccm_cms.content_item_titles_aud rev="6" <ccm_cms.content_item_titles_aud rev="5"
object_id="-99300" object_id="-99300"
localized_value="Article has been edited" localized_value="Article has been edited"
locale="en" locale="en"
revtype="0" /> revtype="0" />
<ccm_cms.content_item_titles_aud rev="6" <ccm_cms.content_item_titles_aud rev="5"
object_id="-99200" object_id="-99200"
localized_value="Article 2 Title" localized_value="Article 2 Title"
locale="en" locale="en"
@ -568,29 +563,16 @@
revtype="0" /> revtype="0" />
<ccm_cms.article_texts_aud <ccm_cms.article_texts_aud
rev="0" rev="0"
revend="6"
object_id="-99200" object_id="-99200"
localized_value="Duis quis tincidunt elit. In pharetra justo sit amet ipsum dictum, at." localized_value="Duis quis tincidunt elit. In pharetra justo sit amet ipsum dictum, at."
locale="en" locale="en"
revtype="0" /> revtype="0" />
<ccm_cms.article_texts_aud
rev="6"
object_id="-99200"
localized_value="Duis quis tincidunt elit. In pharetra justo sit amet ipsum dictum, at."
locale="en"
revtype="2" />
<ccm_cms.article_texts_aud <ccm_cms.article_texts_aud
rev="0" rev="0"
object_id="-10300" object_id="-10300"
localized_value="Etiam euismod lacus laoreet sodales ultricies. Pellentesque non elit vitae purus sagittis." localized_value="Etiam euismod lacus laoreet sodales ultricies. Pellentesque non elit vitae purus sagittis."
locale="en" locale="en"
revtype="0" /> revtype="0" />
<ccm_cms.article_texts_aud
rev="6"
object_id="-99300"
localized_value="Duis quis tincidunt elit. In pharetra justo sit amet ipsum dictum, at."
locale="en"
revtype="0" />
<ccm_cms.news object_id="-10400" <ccm_cms.news object_id="-10400"
news_date="2016-08-08" news_date="2016-08-08"