001/* 002 * Copyright 2019 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.cms.data; 017 018import java.util.ArrayList; 019import java.util.Arrays; 020import java.util.Collection; 021import java.util.HashMap; 022import java.util.List; 023import java.util.Map; 024import java.util.stream.Collectors; 025 026import org.apache.commons.lang3.StringUtils; 027import org.apache.jackrabbit.util.Text; 028 029import org.ametys.cms.data.type.ResourceElementTypeHelper; 030import org.ametys.plugins.repository.RepositoryConstants; 031import org.ametys.plugins.repository.data.repositorydata.RepositoryData; 032 033/** 034 * CLass representing a rich text 035 */ 036public class RichText extends Resource 037{ 038 private static final String __ATTACHMENT_CONTENT_IDENTIFIER = "content"; 039 040 private static final String __RICH_TEXT_MIME_TYPE = "text/xml"; 041 private static final String __RICH_TEXT_ENCODING = "UTF-8"; 042 043 /** the rich text's annotations */ 044 protected Map<String, List<String>> _annotations = new HashMap<>(); 045 046 /** The resource's repository data */ 047 protected RepositoryData _folderData; 048 049 /** the files contained in the rich text */ 050 protected Map<String, NamedResource> _attachments = new HashMap<>(); 051 052 /** the files contained in the rich text */ 053 protected Map<String, NamedResource> _addedAttachments = new HashMap<>(); 054 055 /** the files contained in the rich text */ 056 protected Collection<String> _removedAttachments = new ArrayList<>(); 057 058 /** 059 * Default constructor 060 */ 061 public RichText() 062 { 063 // Empty contructor 064 } 065 066 /** 067 * Constructor to use when reading the rich text from the repository 068 * @param richTextData the repository data containing the rich text's data 069 * @param folderData the repository data containing the folder's data 070 */ 071 public RichText(RepositoryData richTextData, RepositoryData folderData) 072 { 073 super(richTextData); 074 _folderData = folderData; 075 } 076 077 @Override 078 public String getMimeType() 079 { 080 return __RICH_TEXT_MIME_TYPE; 081 } 082 083 @Override 084 public void setMimeType(String mimeType) 085 { 086 if (__RICH_TEXT_MIME_TYPE.equals(mimeType)) 087 { 088 super.setMimeType(mimeType); 089 } 090 else 091 { 092 throw new IllegalArgumentException("The mime type '" + mimeType + "' is not authorized for rich texts. The only authorized mime type is '" + __RICH_TEXT_MIME_TYPE + "'."); 093 } 094 } 095 096 @Override 097 public String getEncoding() 098 { 099 return __RICH_TEXT_ENCODING; 100 } 101 102 @Override 103 public void setEncoding(String encoding) 104 { 105 if (__RICH_TEXT_ENCODING.equals(encoding)) 106 { 107 super.setEncoding(encoding); 108 } 109 else 110 { 111 throw new IllegalArgumentException("The encoding '" + encoding + "' is not authorized for rich texts. The only authorized encoding is '" + __RICH_TEXT_ENCODING + "'."); 112 } 113 } 114 115 /** 116 * Retrieves the rich text's annotations 117 * @return the rich text's annotations 118 */ 119 public Map<String, List<String>> getAllAnnotations() 120 { 121 return _annotations; 122 } 123 124 /** 125 * Retrieves the rich text's annotations of the given name 126 * @param name the name of the annotations to retrieve 127 * @return the rich text's annotations of the given name 128 */ 129 public List<String> getAnnotations(String name) 130 { 131 return _annotations.containsKey(name) ? _annotations.get(name) : new ArrayList<>(); 132 } 133 134 /** 135 * Add annotations to the rich text 136 * @param name the name of the annotations to add 137 * @param values annotations to add 138 */ 139 public void addAnnotations(String name, String... values) 140 { 141 List<String> allValues = new ArrayList<>(); 142 if (_annotations.containsKey(name)) 143 { 144 allValues.addAll(_annotations.get(name)); 145 } 146 147 allValues.addAll(Arrays.asList(values)); 148 _annotations.put(name, allValues); 149 } 150 151 /** 152 * Removes all rich text's annotations 153 */ 154 public void removeAllAnnotations() 155 { 156 _annotations = new HashMap<>(); 157 } 158 159 /** 160 * Removes the rich text's annotations of the given name 161 * @param name the name of the annotations to remove 162 */ 163 public void removeAnnotations(String name) 164 { 165 _annotations.remove(name); 166 } 167 168 /** 169 * Retrieves the names of the rich text's attachments 170 * @return the names of the rich text's attachments 171 */ 172 public Collection<String> getAttachmentNames() 173 { 174 if (_folderData != null) 175 { 176 return _folderData.getDataNames(StringUtils.EMPTY).stream() 177 .map(Text::unescapeIllegalJcrChars) 178 .collect(Collectors.toSet()); 179 } 180 else 181 { 182 return _attachments.keySet(); 183 } 184 } 185 186 /** 187 * Retrieves the rich text's attachments 188 * @return the rich text's attachments 189 */ 190 public Collection<NamedResource> getAttachments() 191 { 192 if (_folderData != null) 193 { 194 return _getAttachmentsFromFolderData(); 195 } 196 else 197 { 198 return _attachments.values(); 199 } 200 } 201 202 private List<NamedResource> _getAttachmentsFromFolderData() 203 { 204 List<NamedResource> attachments = new ArrayList<>(); 205 206 for (String escapedFileName : _folderData.getDataNames(StringUtils.EMPTY)) 207 { 208 NamedResource file = _getAttachmentFromFolderData(Text.unescapeIllegalJcrChars(escapedFileName)); 209 210 attachments.add(file); 211 } 212 213 return attachments; 214 } 215 216 /** 217 * Retrieves the attachments that have been added to the rich text 218 * @return the added attachments 219 */ 220 public Collection<NamedResource> getAddedAttachments() 221 { 222 return _addedAttachments.values(); 223 } 224 225 /** 226 * Retrieves the names of the removed attachments of the rich text 227 * @return the names of the removed attachments 228 */ 229 public Collection<String> getRemovedAttachments() 230 { 231 return _removedAttachments; 232 } 233 234 /** 235 * Checks if the rich text has an attachment with the given name 236 * @param filename the name of the attachment 237 * @return <code>true</code> if the rich text has an attachment with the given name, <code>false</code> otherwise 238 */ 239 public boolean hasAttachment(String filename) 240 { 241 if (_folderData != null) 242 { 243 return _folderData.hasValue(Text.escapeIllegalJcrChars(filename), StringUtils.EMPTY); 244 } 245 else 246 { 247 return _attachments.containsKey(filename); 248 } 249 } 250 251 /** 252 * Retrieves the rich text's attachment with the given name, or <code>null</code> if there is no such attachment 253 * @param filename the name of the attachment to retrieve 254 * @return the rich text's attachment with the given name 255 */ 256 public NamedResource getAttachment(String filename) 257 { 258 if (_folderData != null) 259 { 260 return _getAttachmentFromFolderData(filename); 261 } 262 else 263 { 264 return _attachments.get(filename); 265 } 266 } 267 268 private NamedResource _getAttachmentFromFolderData(String filename) 269 { 270 String escapedFilename = Text.escapeIllegalJcrChars(filename); 271 RepositoryData attachmentData = ResourceElementTypeHelper.getRepositoryData(_folderData, RepositoryConstants.FILE_NODETYPE, escapedFilename, StringUtils.EMPTY); 272 RepositoryData resourceData = ResourceElementTypeHelper.getRepositoryData(attachmentData, RepositoryConstants.RESOURCE_NODETYPE, __ATTACHMENT_CONTENT_IDENTIFIER, ResourceElementTypeHelper.METADATA_PREFIX); 273 274 NamedResource attachment = new NamedResource(resourceData); 275 ResourceElementTypeHelper.readResourceData(resourceData, attachment); 276 attachment.setFilename(filename); 277 278 return attachment; 279 } 280 281 /** 282 * Adds an attachment to the rich text 283 * @param attachment the attachment to add 284 */ 285 public void addAttachment(NamedResource attachment) 286 { 287 String filename = attachment.getFilename(); 288 289 _addedAttachments.put(filename, attachment); 290 _attachments.put(filename, attachment); 291 292 if (_removedAttachments.contains(filename)) 293 { 294 _removedAttachments.remove(filename); 295 } 296 297 _folderData = null; 298 } 299 300 /** 301 * Remove an attachment from the rich text 302 * @param filename the name of the attachment to remove 303 */ 304 public void removeAttachment(String filename) 305 { 306 if (_attachments.containsKey(filename)) 307 { 308 _removedAttachments.add(filename); 309 _attachments.remove(filename); 310 311 if (_addedAttachments.containsKey(filename)) 312 { 313 _addedAttachments.remove(filename); 314 } 315 316 _folderData = null; 317 } 318 } 319 320 /** 321 * Remove all the attachments from the rich text 322 */ 323 public void removeAttachments() 324 { 325 _removedAttachments.addAll(_attachments.keySet()); 326 _attachments = new HashMap<>(); 327 _addedAttachments = new HashMap<>(); 328 _folderData = null; 329 } 330}