diff --git a/ccm-cms/src/main/java/org/librecms/assets/AssetManager.java b/ccm-cms/src/main/java/org/librecms/assets/AssetManager.java index 817315ea8..a61d61e31 100644 --- a/ccm-cms/src/main/java/org/librecms/assets/AssetManager.java +++ b/ccm-cms/src/main/java/org/librecms/assets/AssetManager.java @@ -50,8 +50,18 @@ import org.librecms.contentsection.privileges.AssetPrivileges; import java.util.Objects; import org.libreccm.categorization.ObjectNotAssignedToCategoryException; +import org.libreccm.l10n.LocalizedString; import org.librecms.contentsection.FolderType; +import java.beans.BeanInfo; +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.Map; +import java.util.Set; + import static org.librecms.CmsConstants.*; /** @@ -165,33 +175,33 @@ public class AssetManager { final Asset asset, @RequiresPrivilege(AssetPrivileges.CREATE_NEW) final Folder targetFolder) { - + if (asset == null) { throw new IllegalArgumentException("No asset to move provided."); } - + if (targetFolder == null) { throw new IllegalArgumentException("No target folder specified."); } - + if (targetFolder.getType() != FolderType.ASSETS_FOLDER) { throw new IllegalArgumentException(String.format( "The provided target folder %s is not an asset folder.", Objects.toString(targetFolder))); } - + final Optional currentFolder = getAssetFolder(asset); - + if (currentFolder.isPresent()) { try { - categoryManager.removeObjectFromCategory(asset, + categoryManager.removeObjectFromCategory(asset, currentFolder.get()); - } catch(ObjectNotAssignedToCategoryException ex) { + } catch (ObjectNotAssignedToCategoryException ex) { throw new UncheckedWrapperException(ex); } } - - categoryManager.addObjectToCategory(asset, + + categoryManager.addObjectToCategory(asset, targetFolder, CATEGORIZATION_TYPE_FOLDER); } @@ -201,13 +211,182 @@ public class AssetManager { * * @param asset The {@link Asset} to copy. * @param targetFolder The folder to which the {@link Asset} is copied. + * + * @return The copy of the {@code asset}. */ @Transactional(Transactional.TxType.REQUIRED) @AuthorizationRequired - public void copy(final Asset asset, - @RequiresPrivilege(AssetPrivileges.CREATE_NEW) - final Folder targetFolder) { - throw new UnsupportedOperationException("Not implemented yet."); + @SuppressWarnings("unchecked") + public Asset copy(final Asset asset, + @RequiresPrivilege(AssetPrivileges.CREATE_NEW) + final Folder targetFolder) { + + if (asset == null) { + throw new IllegalArgumentException("No asset to copy."); + } + + if (targetFolder == null) { + throw new IllegalArgumentException("No target folder provided."); + } + + if (targetFolder.getType() != FolderType.ASSETS_FOLDER) { + throw new IllegalArgumentException(String.format( + "The provided target folder %s is not an asset folder.", + Objects.toString(targetFolder))); + } + + final Asset copy; + try { + copy = asset.getClass().newInstance(); + } catch (InstantiationException | IllegalAccessException ex) { + throw new UncheckedWrapperException(ex); + } + + final BeanInfo beanInfo; + try { + beanInfo = Introspector.getBeanInfo(asset.getClass()); + } catch (IntrospectionException ex) { + throw new UncheckedWrapperException(ex); + } + + for (final PropertyDescriptor propertyDescriptor : beanInfo + .getPropertyDescriptors()) { + if (propertyIsExcluded(propertyDescriptor.getName())) { + continue; + } + + final Class propType = propertyDescriptor.getPropertyType(); + final Method readMethod = propertyDescriptor.getReadMethod(); + final Method writeMethod = propertyDescriptor.getWriteMethod(); + + if (writeMethod == null) { + continue; + } + + if (LocalizedString.class.equals(propType)) { + final LocalizedString source; + final LocalizedString target; + try { + source = (LocalizedString) readMethod.invoke(asset); + target = (LocalizedString) readMethod.invoke(copy); + } catch (IllegalAccessException + | IllegalArgumentException + | InvocationTargetException ex) { + throw new RuntimeException(ex); + } + + source.getAvailableLocales().forEach( + locale -> target.addValue(locale, + source.getValue(locale))); + } else if (propType != null + && propType.isAssignableFrom(Asset.class)) { + + final Asset linkedAsset; + try { + linkedAsset = (Asset) readMethod.invoke(asset); + } catch (IllegalAccessException + | IllegalArgumentException + | InvocationTargetException ex) { + throw new UncheckedWrapperException(ex); + } + + try { + writeMethod.invoke(copy, linkedAsset); + } catch (IllegalAccessException + | IllegalArgumentException + | InvocationTargetException ex) { + throw new UncheckedWrapperException(ex); + } + } else if (propType != null + && propType.isAssignableFrom(List.class)) { + final List source; + final List target; + try { + source = (List) readMethod.invoke(asset); + target = (List) readMethod.invoke(copy); + } catch (IllegalAccessException + | IllegalArgumentException + | InvocationTargetException ex) { + throw new UncheckedWrapperException(ex); + } + + target.addAll(source); + } else if (propType != null + && propType.isAssignableFrom(Map.class)) { + final Map source; + final Map target; + + try { + source = (Map) readMethod.invoke(asset); + target = (Map) readMethod.invoke(copy); + } catch (IllegalAccessException + | IllegalArgumentException + | InvocationTargetException ex) { + throw new RuntimeException(ex); + } + + source.forEach((key, value) -> target.put(key, value)); + } else if (propType != null + && propType.isAssignableFrom(Set.class)) { + final Set source; + final Set target; + + try { + source = (Set) readMethod.invoke(asset); + target = (Set) readMethod.invoke(copy); + } catch (IllegalAccessException + | IllegalArgumentException + | InvocationTargetException ex) { + throw new RuntimeException(ex); + } + + target.addAll(source); + } else { + final Object value; + try { + value = readMethod.invoke(asset); + writeMethod.invoke(copy, value); + } catch (IllegalAccessException + | IllegalArgumentException + | InvocationTargetException ex) { + throw new UncheckedWrapperException(ex); + } + } + } + + if (targetFolder.equals(getAssetFolder(asset).orElse(null))) { + final long number = assetRepo.countFilterByFolderAndName( + targetFolder, String.format("%s_copy", + asset.getDisplayName())); + final long index = number + 1; + copy.setDisplayName(String.format("%s_copy%d", + copy.getDisplayName(), + index)); + } + + assetRepo.save(asset); + + categoryManager.addObjectToCategory(copy, + targetFolder, + CATEGORIZATION_TYPE_FOLDER); + + return asset; + } + + private boolean propertyIsExcluded(final String name) { + final String[] excluded = new String[]{"objectId", + "uuid", + "categories", + "itemAttachments"}; + + boolean result = false; + for (final String current : excluded) { + if (current.equals(name)) { + result = true; + } + } + + return result; } /** diff --git a/ccm-cms/src/main/java/org/librecms/assets/BinaryAsset.java b/ccm-cms/src/main/java/org/librecms/assets/BinaryAsset.java index 4af597560..2804567a6 100644 --- a/ccm-cms/src/main/java/org/librecms/assets/BinaryAsset.java +++ b/ccm-cms/src/main/java/org/librecms/assets/BinaryAsset.java @@ -44,7 +44,7 @@ import static org.librecms.CmsConstants.*; /** * Base class for all assets storing binary information, like videos. - * + * * @author Jens Pelzetter */ @Entity @@ -56,13 +56,13 @@ public class BinaryAsset extends Asset implements Serializable { @Embedded @AssociationOverride( - name = "values", - joinTable = @JoinTable(name = "BINARY_ASSET_DESCRIPTIONS", - schema = DB_SCHEMA, - joinColumns = { - @JoinColumn(name = "ASSET_ID") - } - ) + name = "values", + joinTable = @JoinTable(name = "BINARY_ASSET_DESCRIPTIONS", + schema = DB_SCHEMA, + joinColumns = { + @JoinColumn(name = "ASSET_ID") + } + ) ) private LocalizedString description; @@ -85,6 +85,7 @@ public class BinaryAsset extends Asset implements Serializable { public BinaryAsset() { super(); description = new LocalizedString(); + data = new byte[]{}; } public LocalizedString getDescription() { @@ -112,12 +113,21 @@ public class BinaryAsset extends Asset implements Serializable { } public byte[] getData() { - return Arrays.copyOf(data, data.length); + if (data == null) { + return new byte[]{}; + } else { + return Arrays.copyOf(data, data.length); + } } public void setData(final byte[] data) { - this.data = Arrays.copyOf(data, data.length); - size = data.length; + if (data == null) { + this.data = new byte[]{}; + size = this.data.length; + } else { + this.data = Arrays.copyOf(data, data.length); + size = data.length; + } } public long getSize() { @@ -181,13 +191,14 @@ public class BinaryAsset extends Asset implements Serializable { @Override public String toString(final String data) { return super.toString(String.format(", description = %s, " - + "fileName = \"%s\", " - + "mimeType = \"%s\", " - + "size = %d%s", + + "fileName = \"%s\", " + + "mimeType = \"%s\", " + + "size = %d%s", Objects.toString(description), fileName, Objects.toString(mimeType), size, data)); } + } diff --git a/ccm-cms/src/main/java/org/librecms/contentsection/ContentItemManager.java b/ccm-cms/src/main/java/org/librecms/contentsection/ContentItemManager.java index 9f6faa606..6bbf6817d 100644 --- a/ccm-cms/src/main/java/org/librecms/contentsection/ContentItemManager.java +++ b/ccm-cms/src/main/java/org/librecms/contentsection/ContentItemManager.java @@ -325,6 +325,7 @@ public class ContentItemManager { final ContentItem item, @RequiresPrivilege(ItemPrivileges.CREATE_NEW) final Folder targetFolder) { + if (item == null) { throw new IllegalArgumentException("The item to copy can't be null."); } @@ -511,7 +512,7 @@ public class ContentItemManager { } else { final Object value; try { - value = readMethod.invoke(item); + value = readMethod.invoke(draftItem); writeMethod.invoke(copy, value); } catch (IllegalAccessException | IllegalArgumentException diff --git a/ccm-cms/src/test/java/org/librecms/assets/AssetManagerTest.java b/ccm-cms/src/test/java/org/librecms/assets/AssetManagerTest.java index cbc01c48b..fc15f3121 100644 --- a/ccm-cms/src/test/java/org/librecms/assets/AssetManagerTest.java +++ b/ccm-cms/src/test/java/org/librecms/assets/AssetManagerTest.java @@ -319,10 +319,10 @@ public class AssetManagerTest { public void moveAssetToOtherFolder() { final Asset asset = assetRepo.findById(-900L); assertThat(asset, is(not(nullValue()))); - + final Folder folder = folderRepo.findById(-410L); assertThat(folder, is(not(nullValue()))); - + assetManager.move(asset, folder); } @@ -344,10 +344,10 @@ public class AssetManagerTest { public void moveAssetToFolderInOtherContentSection() { final Asset asset = assetRepo.findById(-900L); assertThat(asset, is(not(nullValue()))); - + final Folder folder = folderRepo.findById(-1600L); assertThat(folder, is(not(nullValue()))); - + assetManager.move(asset, folder); } @@ -363,10 +363,12 @@ public class AssetManagerTest { @ShouldMatchDataSet("datasets/org/librecms/assets/AssetManagerTest/data.xml") @ShouldThrowException(IllegalArgumentException.class) public void moveAssetNull() { + final Asset asset = null; + final Folder folder = folderRepo.findById(-410L); assertThat(folder, is(not(nullValue()))); - - assetManager.move(null, folder); + + assetManager.move(asset, folder); } /** @@ -383,8 +385,10 @@ public class AssetManagerTest { public void moveAssetTargetFolderIsNull() { final Asset asset = assetRepo.findById(-900L); assertThat(asset, is(not(nullValue()))); - - assetManager.move(asset, null); + + final Folder targetFolder = null; + + assetManager.move(asset, targetFolder); } /** @@ -401,10 +405,10 @@ public class AssetManagerTest { public void moveAssetTargetFolderIsNotAssetFolder() { final Asset asset = assetRepo.findById(-900L); assertThat(asset, is(not(nullValue()))); - + final Folder folder = folderRepo.findById(-200L); assertThat(folder, is(not(nullValue()))); - + assetManager.move(asset, folder); } @@ -419,9 +423,21 @@ public class AssetManagerTest { value = "datasets/org/librecms/assets/AssetManagerTest/" + "after-copy-to-other-folder.xml", excludeColumns = {"object_id", - "uuid"}) + "uuid", + "asset_id", + "id", + "timestamp", + "rev", + "categorization_id", + "object_order"}) public void copyAssetToOtherFolder() { - fail(); + final Asset asset = assetRepo.findById(-1100L); + assertThat(asset, is(not(nullValue()))); + + final Folder targetFolder = folderRepo.findById(-400L); + assertThat(targetFolder, is(not(nullValue()))); + + assetManager.copy(asset, targetFolder); } /** @@ -435,9 +451,22 @@ public class AssetManagerTest { value = "datasets/org/librecms/assets/AssetManagerTest/" + "after-copy-to-same-folder.xml", excludeColumns = {"object_id", - "uuid"}) + "uuid", + "asset_id", + "id", + "timestamp", + "rev", + "categorization_id", + "object_order"}) public void copyAssetToSameFolder() { - fail(); + final Asset asset = assetRepo.findById(-1100L); + assertThat(asset, is(not(nullValue()))); + + final Folder targetFolder = folderRepo.findById(-420L); + assertThat(targetFolder, is(not(nullValue()))); + + assetManager.copy(asset, targetFolder); + assetManager.copy(asset, targetFolder); } /** @@ -452,9 +481,21 @@ public class AssetManagerTest { value = "datasets/org/librecms/assets/AssetManagerTest/" + "after-copy-to-other-contentsection.xml", excludeColumns = {"object_id", - "uuid"}) + "uuid", + "asset_id", + "id", + "timestamp", + "rev", + "categorization_id", + "object_order"}) public void copyAssetToOtherContentSection() { - fail(); + final Asset asset = assetRepo.findById(-1100L); + assertThat(asset, is(not(nullValue()))); + + final Folder targetFolder = folderRepo.findById(-1600L); + assertThat(targetFolder, is(not(nullValue()))); + + assetManager.copy(asset, targetFolder); } /** @@ -469,7 +510,12 @@ public class AssetManagerTest { @ShouldMatchDataSet("datasets/org/librecms/assets/AssetManagerTest/data.xml") @ShouldThrowException(IllegalArgumentException.class) public void copyAssetNull() { - fail(); + final Asset asset = null; + + final Folder targetFolder = folderRepo.findById(-420L); + assertThat(targetFolder, is(not(nullValue()))); + + assetManager.copy(asset, targetFolder); } /** @@ -484,7 +530,12 @@ public class AssetManagerTest { @ShouldMatchDataSet("datasets/org/librecms/assets/AssetManagerTest/data.xml") @ShouldThrowException(IllegalArgumentException.class) public void copyAssetTargetFolderIsNull() { - fail(); + final Asset asset = assetRepo.findById(-1100L); + assertThat(asset, is(not(nullValue()))); + + final Folder targetFolder = null; + + assetManager.copy(asset, targetFolder); } /** @@ -499,7 +550,13 @@ public class AssetManagerTest { @ShouldMatchDataSet("datasets/org/librecms/assets/AssetManagerTest/data.xml") @ShouldThrowException(IllegalArgumentException.class) public void copyAssetTargetFolderIsNotAssetFolder() { - fail(); + final Asset asset = assetRepo.findById(-1100L); + assertThat(asset, is(not(nullValue()))); + + final Folder targetFolder = folderRepo.findById(-200L); + assertThat(targetFolder, is(not(nullValue()))); + + assetManager.copy(asset, targetFolder); } /** diff --git a/ccm-cms/src/test/resources/datasets/org/librecms/assets/AssetManagerTest/after-copy-to-other-contentsection.xml b/ccm-cms/src/test/resources/datasets/org/librecms/assets/AssetManagerTest/after-copy-to-other-contentsection.xml index ffc0a3b5a..502f93033 100644 --- a/ccm-cms/src/test/resources/datasets/org/librecms/assets/AssetManagerTest/after-copy-to-other-contentsection.xml +++ b/ccm-cms/src/test/resources/datasets/org/librecms/assets/AssetManagerTest/after-copy-to-other-contentsection.xml @@ -10,6 +10,8 @@ + + + @@ -65,6 +73,9 @@ + + + + + + @@ -196,6 +237,10 @@ type="ASSETS_FOLDER" /> + + + + + @@ -261,6 +311,8 @@ rev="0" /> + + + + data_size="0" /> + + + + + - + + + + @@ -65,6 +73,9 @@ + + + + + + @@ -196,6 +237,10 @@ type="ASSETS_FOLDER" /> + + + + + @@ -261,6 +311,8 @@ rev="0" /> + + + + data_size="0" /> + + + + + - + + + + @@ -65,6 +73,12 @@ + + + + + + + + @@ -196,6 +244,10 @@ type="ASSETS_FOLDER" /> + + + + + + @@ -261,6 +319,10 @@ rev="0" /> + + + + + + + data_size="0" /> + + + + + + + + + - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -