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

@ -68,7 +68,7 @@ import static org.librecms.CmsConstants.*;
public class AssetManager { public class AssetManager {
private static final Logger LOGGER = LogManager. private static final Logger LOGGER = LogManager.
getLogger(AssetManager.class); getLogger(AssetManager.class);
@Inject @Inject
private EntityManager entityManager; private EntityManager entityManager;
@ -94,15 +94,15 @@ public class AssetManager {
* thrown. * thrown.
* *
* *
* @param asset The {@link Asset} to share. * @param asset The {@link Asset} to share.
* @param folder The {@link Folder} in which the {@link Asset} is created. * @param folder The {@link Folder} in which the {@link Asset} is created.
*/ */
@AuthorizationRequired @AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public void shareAsset( public void shareAsset(
final Asset asset, final Asset asset,
@RequiresPrivilege(AssetPrivileges.CREATE_NEW) @RequiresPrivilege(AssetPrivileges.CREATE_NEW)
final Folder folder) { final Folder folder) {
if (asset == null) { if (asset == null) {
throw new IllegalArgumentException("Can't share asset null."); throw new IllegalArgumentException("Can't share asset null.");
@ -114,14 +114,14 @@ public class AssetManager {
if (isShared(asset)) { if (isShared(asset)) {
throw new IllegalArgumentException(String.format( throw new IllegalArgumentException(String.format(
"The asset %s is already shared.", "The asset %s is already shared.",
Objects.toString(asset))); Objects.toString(asset)));
} }
categoryManager.addObjectToCategory( categoryManager.addObjectToCategory(
asset, asset,
folder, folder,
CmsConstants.CATEGORIZATION_TYPE_FOLDER); CmsConstants.CATEGORIZATION_TYPE_FOLDER);
} }
/** /**
@ -132,9 +132,14 @@ public class AssetManager {
* @param asset The asset the check. * @param asset The asset the check.
* *
* @return {@code true} is the {@link Asset} is shared, * @return {@code true} is the {@link Asset} is shared,
* {@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();
} }
@ -148,9 +153,9 @@ public class AssetManager {
final List<Asset> assets = assetRepo.findAll(); final List<Asset> assets = assetRepo.findAll();
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));
} }
@ -158,17 +163,17 @@ public class AssetManager {
/** /**
* Moves an {@link Asset} to an folder. * Moves an {@link Asset} to an folder.
* *
* @param asset The {@link Asset} to move. * @param asset The {@link Asset} to move.
* @param targetFolder The folder to which the {@link Asset} is moved. Must * @param targetFolder The folder to which the {@link Asset} is moved. Must
* be an asset folder. * be an asset folder.
*/ */
@AuthorizationRequired @AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public void move( public void move(
@RequiresPrivilege(AssetPrivileges.EDIT) @RequiresPrivilege(AssetPrivileges.EDIT)
final Asset asset, final Asset asset,
@RequiresPrivilege(AssetPrivileges.CREATE_NEW) @RequiresPrivilege(AssetPrivileges.CREATE_NEW)
final Folder targetFolder) { final Folder targetFolder) {
if (asset == null) { if (asset == null) {
throw new IllegalArgumentException("No asset to move provided."); throw new IllegalArgumentException("No asset to move provided.");
@ -180,8 +185,8 @@ public class AssetManager {
if (targetFolder.getType() != FolderType.ASSETS_FOLDER) { if (targetFolder.getType() != FolderType.ASSETS_FOLDER) {
throw new IllegalArgumentException(String.format( throw new IllegalArgumentException(String.format(
"The provided target folder %s is not an asset folder.", "The provided target folder %s is not an asset folder.",
Objects.toString(targetFolder))); Objects.toString(targetFolder)));
} }
final Optional<Folder> currentFolder = getAssetFolder(asset); final Optional<Folder> currentFolder = getAssetFolder(asset);
@ -203,7 +208,7 @@ public class AssetManager {
/** /**
* Copies an {@link Asset}. * Copies an {@link Asset}.
* *
* @param asset The {@link Asset} to copy. * @param asset The {@link Asset} to copy.
* @param targetFolder The folder to which the {@link Asset} is copied. * @param targetFolder The folder to which the {@link Asset} is copied.
* *
* @return The copy of the {@code asset}. * @return The copy of the {@code asset}.
@ -225,8 +230,8 @@ public class AssetManager {
if (targetFolder.getType() != FolderType.ASSETS_FOLDER) { if (targetFolder.getType() != FolderType.ASSETS_FOLDER) {
throw new IllegalArgumentException(String.format( throw new IllegalArgumentException(String.format(
"The provided target folder %s is not an asset folder.", "The provided target folder %s is not an asset folder.",
Objects.toString(targetFolder))); Objects.toString(targetFolder)));
} }
final Asset copy; final Asset copy;
@ -244,7 +249,7 @@ public class AssetManager {
} }
for (final PropertyDescriptor propertyDescriptor : beanInfo for (final PropertyDescriptor propertyDescriptor : beanInfo
.getPropertyDescriptors()) { .getPropertyDescriptors()) {
if (propertyIsExcluded(propertyDescriptor.getName())) { if (propertyIsExcluded(propertyDescriptor.getName())) {
continue; continue;
} }
@ -264,49 +269,49 @@ public class AssetManager {
source = (LocalizedString) readMethod.invoke(asset); source = (LocalizedString) readMethod.invoke(asset);
target = (LocalizedString) readMethod.invoke(copy); target = (LocalizedString) readMethod.invoke(copy);
} catch (IllegalAccessException } catch (IllegalAccessException
| IllegalArgumentException | IllegalArgumentException
| InvocationTargetException ex) { | InvocationTargetException ex) {
throw new RuntimeException(ex); throw new RuntimeException(ex);
} }
source.getAvailableLocales().forEach( source.getAvailableLocales().forEach(
locale -> target.addValue(locale, locale -> target.addValue(locale,
source.getValue(locale))); source.getValue(locale)));
} else if (propType != null } else if (propType != null
&& propType.isAssignableFrom(Asset.class)) { && propType.isAssignableFrom(Asset.class)) {
final Asset linkedAsset; final Asset linkedAsset;
try { try {
linkedAsset = (Asset) readMethod.invoke(asset); linkedAsset = (Asset) readMethod.invoke(asset);
} catch (IllegalAccessException } catch (IllegalAccessException
| IllegalArgumentException | IllegalArgumentException
| InvocationTargetException ex) { | InvocationTargetException ex) {
throw new UncheckedWrapperException(ex); throw new UncheckedWrapperException(ex);
} }
try { try {
writeMethod.invoke(copy, linkedAsset); writeMethod.invoke(copy, linkedAsset);
} catch (IllegalAccessException } catch (IllegalAccessException
| IllegalArgumentException | IllegalArgumentException
| InvocationTargetException ex) { | InvocationTargetException ex) {
throw new UncheckedWrapperException(ex); throw new UncheckedWrapperException(ex);
} }
} else if (propType != null } else if (propType != null
&& propType.isAssignableFrom(List.class)) { && propType.isAssignableFrom(List.class)) {
final List<Object> source; final List<Object> source;
final List<Object> target; final List<Object> target;
try { try {
source = (List<Object>) readMethod.invoke(asset); source = (List<Object>) readMethod.invoke(asset);
target = (List<Object>) readMethod.invoke(copy); target = (List<Object>) readMethod.invoke(copy);
} catch (IllegalAccessException } catch (IllegalAccessException
| IllegalArgumentException | IllegalArgumentException
| InvocationTargetException ex) { | InvocationTargetException ex) {
throw new UncheckedWrapperException(ex); throw new UncheckedWrapperException(ex);
} }
target.addAll(source); target.addAll(source);
} else if (propType != null } else if (propType != null
&& propType.isAssignableFrom(Map.class)) { && propType.isAssignableFrom(Map.class)) {
final Map<Object, Object> source; final Map<Object, Object> source;
final Map<Object, Object> target; final Map<Object, Object> target;
@ -314,14 +319,14 @@ public class AssetManager {
source = (Map<Object, Object>) readMethod.invoke(asset); source = (Map<Object, Object>) readMethod.invoke(asset);
target = (Map<Object, Object>) readMethod.invoke(copy); target = (Map<Object, Object>) readMethod.invoke(copy);
} catch (IllegalAccessException } catch (IllegalAccessException
| IllegalArgumentException | IllegalArgumentException
| InvocationTargetException ex) { | InvocationTargetException ex) {
throw new RuntimeException(ex); throw new RuntimeException(ex);
} }
source.forEach((key, value) -> target.put(key, value)); source.forEach((key, value) -> target.put(key, value));
} else if (propType != null } else if (propType != null
&& propType.isAssignableFrom(Set.class)) { && propType.isAssignableFrom(Set.class)) {
final Set<Object> source; final Set<Object> source;
final Set<Object> target; final Set<Object> target;
@ -329,8 +334,8 @@ public class AssetManager {
source = (Set<Object>) readMethod.invoke(asset); source = (Set<Object>) readMethod.invoke(asset);
target = (Set<Object>) readMethod.invoke(copy); target = (Set<Object>) readMethod.invoke(copy);
} catch (IllegalAccessException } catch (IllegalAccessException
| IllegalArgumentException | IllegalArgumentException
| InvocationTargetException ex) { | InvocationTargetException ex) {
throw new RuntimeException(ex); throw new RuntimeException(ex);
} }
@ -341,8 +346,8 @@ public class AssetManager {
value = readMethod.invoke(asset); value = readMethod.invoke(asset);
writeMethod.invoke(copy, value); writeMethod.invoke(copy, value);
} catch (IllegalAccessException } catch (IllegalAccessException
| IllegalArgumentException | IllegalArgumentException
| InvocationTargetException ex) { | InvocationTargetException ex) {
throw new UncheckedWrapperException(ex); throw new UncheckedWrapperException(ex);
} }
} }
@ -350,8 +355,8 @@ public class AssetManager {
if (targetFolder.equals(getAssetFolder(asset).orElse(null))) { if (targetFolder.equals(getAssetFolder(asset).orElse(null))) {
final long number = assetRepo.countFilterByFolderAndName( final long number = assetRepo.countFilterByFolderAndName(
targetFolder, String.format("%s_copy", targetFolder, String.format("%s_copy",
asset.getDisplayName())); asset.getDisplayName()));
final long index = number + 1; final long index = number + 1;
copy.setDisplayName(String.format("%s_copy%d", copy.setDisplayName(String.format("%s_copy%d",
copy.getDisplayName(), copy.getDisplayName(),
@ -390,10 +395,14 @@ public class AssetManager {
* @param asset The {@link Asset} to check for usage. * @param asset The {@link Asset} to check for usage.
* *
* @return {@code true} if the {@link Asset} is in use, {@link false} if * @return {@code true} if the {@link Asset} is in use, {@link false} if
* not. * not.
*/ */
@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();
} }
@ -405,7 +414,7 @@ public class AssetManager {
* @param asset The {@link Assset} for which the path is generated. * @param asset The {@link Assset} for which the path is generated.
* *
* @return The path of the {@link Asset}. If the {@link Asset} is a non * @return The path of the {@link Asset}. If the {@link Asset} is a non
* shared asset the path is empty. * shared asset the path is empty.
* *
* @see #getAssetPath(org.librecms.assets.Asset, boolean) * @see #getAssetPath(org.librecms.assets.Asset, boolean)
*/ */
@ -416,24 +425,23 @@ 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.
* *
* @return The path of the asset. For non shared assets this is an empty * @return The path of the asset. For non shared assets this is an empty
* string. * string.
* *
* @see #getAssetPath(org.librecms.assets.Asset) * @see #getAssetPath(org.librecms.assets.Asset)
*/ */
public String getAssetPath(final Asset asset, public String getAssetPath(final Asset asset,
final boolean withContentSection) { final boolean withContentSection) {
final List<Categorization> result = asset.getCategories().stream() final List<Categorization> result = asset.getCategories().stream()
.filter(categorization -> { .filter(categorization -> {
return CATEGORIZATION_TYPE_FOLDER.equals( return CATEGORIZATION_TYPE_FOLDER.equals(
categorization.getType()); categorization.getType());
}) })
.collect(Collectors.toList()); .collect(Collectors.toList());
if (result.isEmpty()) { if (result.isEmpty()) {
return ""; return "";
@ -452,8 +460,8 @@ public class AssetManager {
if (withContentSection) { if (withContentSection) {
final String sectionName final String sectionName
= ((Folder) result.get(0).getCategory()). = ((Folder) result.get(0).getCategory()).
getSection().getDisplayName(); getSection().getDisplayName();
return String.format("%s:/%s", sectionName, path); return String.format("%s:/%s", sectionName, path);
} else { } else {
return String.format("/%s", path); return String.format("/%s", path);
@ -467,15 +475,15 @@ public class AssetManager {
* @param asset * @param asset
* *
* @return A list of the folders which form the path of the asset. For non * @return A list of the folders which form the path of the asset. For non
* shared assets an empty list is returned. * shared assets an empty list is returned.
*/ */
public List<Folder> getAssetFolders(final Asset asset) { public List<Folder> getAssetFolders(final Asset asset) {
final List<Categorization> result = asset.getCategories().stream() final List<Categorization> result = asset.getCategories().stream()
.filter(categorization -> { .filter(categorization -> {
return CATEGORIZATION_TYPE_FOLDER.equals(categorization return CATEGORIZATION_TYPE_FOLDER.equals(categorization
.getType()); .getType());
}) })
.collect(Collectors.toList()); .collect(Collectors.toList());
final List<Folder> folders = new ArrayList<>(); final List<Folder> folders = new ArrayList<>();
if (!result.isEmpty()) { if (!result.isEmpty()) {
@ -484,12 +492,12 @@ public class AssetManager {
folders.add((Folder) current); folders.add((Folder) current);
} else { } else {
throw new IllegalArgumentException(String.format( throw new IllegalArgumentException(String.format(
"The asset %s is assigned to the category %s with the" "The asset %s is assigned to the category %s with the"
+ "categorization type \"%s\", but the Category is not" + "categorization type \"%s\", but the Category is not"
+ "a folder. This is no supported.", + "a folder. This is no supported.",
asset.getUuid(), asset.getUuid(),
current.getUuid(), current.getUuid(),
CATEGORIZATION_TYPE_FOLDER)); CATEGORIZATION_TYPE_FOLDER));
} }
while (current.getParentCategory() != null) { while (current.getParentCategory() != null) {
@ -498,12 +506,12 @@ public class AssetManager {
folders.add((Folder) current); folders.add((Folder) current);
} else { } else {
throw new IllegalArgumentException(String.format( throw new IllegalArgumentException(String.format(
"The asset %s is assigned to the category %s with the" "The asset %s is assigned to the category %s with the"
+ "categorization type \"%s\", but the Category is not" + "categorization type \"%s\", but the Category is not"
+ "a folder. This is no supported.", + "a folder. This is no supported.",
asset.getUuid(), asset.getUuid(),
current.getUuid(), current.getUuid(),
CATEGORIZATION_TYPE_FOLDER)); CATEGORIZATION_TYPE_FOLDER));
} }
} }
} }
@ -518,18 +526,27 @@ public class AssetManager {
* @param asset The asset. * @param asset The asset.
* *
* @return The folder in which the asset is placed. If the asset is a non * @return The folder in which the asset is placed. If the asset is a non
* 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(
categorization.getType()); categorization.getType());
}) })
.map(categorization -> { .map(categorization -> {
return (Folder) categorization.getCategory(); return (Folder) categorization.getCategory();
}) })
.findFirst(); .findFirst();
} }
} }

View File

@ -152,8 +152,8 @@
display_name="org.librecms.contenttypes.Article" display_name="org.librecms.contenttypes.Article"
uuid="bd061ab6-9c4f-45ff-ab69-f521008eeac3" /> uuid="bd061ab6-9c4f-45ff-ab69-f521008eeac3" />
<ccm_core.ccm_objects object_id="-11300" <ccm_core.ccm_objects object_id="-11300"
display_name="nonSharedAsset" display_name="nonSharedAsset"
uuid="00000000-0000-0000-0000-000000000000" /> uuid="00000000-0000-0000-0000-000000000000" />
<ccm_core.ccm_objects_aud object_id="-10100" <ccm_core.ccm_objects_aud object_id="-10100"
rev="0" rev="0"
@ -188,7 +188,7 @@
rev="10" rev="10"
revtype="0" revtype="0"
display_name="article1" /> display_name="article1" />
<ccm_core.ccm_objects_aud object_id="-11100" <ccm_core.ccm_objects_aud object_id="-11100"
rev="10" rev="10"
revtype="1" revtype="1"
display_name="sharedAsset" /> display_name="sharedAsset" />

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"