001/* 002 * Copyright 2012 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.repository; 017 018import java.time.ZonedDateTime; 019import java.util.Calendar; 020import java.util.List; 021import java.util.Locale; 022import java.util.Map; 023 024import javax.jcr.Node; 025import javax.jcr.RepositoryException; 026 027import org.apache.avalon.framework.component.Component; 028 029import org.ametys.cms.content.references.OutgoingReferences; 030import org.ametys.cms.data.type.ModelItemTypeConstants; 031import org.ametys.core.user.UserIdentity; 032import org.ametys.core.util.DateUtils; 033import org.ametys.plugins.repository.AmetysRepositoryException; 034import org.ametys.plugins.repository.RepositoryConstants; 035import org.ametys.plugins.repository.data.repositorydata.ModifiableRepositoryData; 036import org.ametys.plugins.repository.data.repositorydata.impl.JCRRepositoryData; 037import org.ametys.runtime.model.ElementDefinition; 038import org.ametys.runtime.model.ModelItem; 039 040 041/** 042 * Provides helper methods to use the {@link ModifiableContent} API on {@link DefaultContent}s. 043 */ 044public class ModifiableContentHelper implements Component 045{ 046 /** The Avalon role */ 047 public static final String ROLE = ModifiableContentHelper.class.getName(); 048 049 /** 050 * Set a {@link DefaultContent} title for the given locale. 051 * @param content the {@link DefaultContent} to set. 052 * @param title the title to set. 053 * @param locale The locale. Can be null if the content is not a multilingual content. 054 * @throws AmetysRepositoryException if an error occurs. 055 */ 056 public void setTitle(DefaultContent content, String title, Locale locale) throws AmetysRepositoryException 057 { 058 ModelItem titleDefinition = content.getDefinition(Content.ATTRIBUTE_TITLE); 059 ModifiableRepositoryData repositoryData = new JCRRepositoryData(content.getNode()); 060 if (titleDefinition instanceof ElementDefinition && ModelItemTypeConstants.MULTILINGUAL_STRING_ELEMENT_TYPE_ID.equals(((ElementDefinition) titleDefinition).getType().getId())) 061 { 062 if (locale == null) 063 { 064 throw new IllegalArgumentException("Cannot set a title with null locale on a multilingual title"); 065 } 066 067 ModifiableRepositoryData titleRepositoryData; 068 if (repositoryData.hasValue(Content.ATTRIBUTE_TITLE)) 069 { 070 titleRepositoryData = repositoryData.getRepositoryData(Content.ATTRIBUTE_TITLE); 071 } 072 else 073 { 074 titleRepositoryData = repositoryData.addRepositoryData(Content.ATTRIBUTE_TITLE, RepositoryConstants.MULTILINGUAL_STRING_METADATA_NODETYPE); 075 } 076 titleRepositoryData.setValue(locale.toString(), title); 077 } 078 else 079 { 080 repositoryData.setValue(Content.ATTRIBUTE_TITLE, title); 081 } 082 } 083 084 /** 085 * Set the title of non-multilingual {@link DefaultContent}. 086 * Be careful! Use only if content's title is not a multilingual string. If not sure use {@link #setTitle(DefaultContent, String, Locale)} instead. 087 * @param content the {@link DefaultContent} to set. 088 * @param title the title to set. 089 * @throws AmetysRepositoryException if an error occurs. 090 */ 091 public void setTitle(DefaultContent content, String title) throws AmetysRepositoryException 092 { 093 setTitle(content, title, null); 094 } 095 096 /** 097 * Copy the title of the source content to the target content 098 * @param srcContent The source content 099 * @param targetContent The target content 100 * @throws AmetysRepositoryException if an error occurs. 101 */ 102 public void copyTitle(Content srcContent, ModifiableContent targetContent) throws AmetysRepositoryException 103 { 104 targetContent.setValue(Content.ATTRIBUTE_TITLE, srcContent.getValue(Content.ATTRIBUTE_TITLE)); 105 } 106 107 /** 108 * Set a {@link DefaultContent} user. 109 * @param content the {@link DefaultContent} to set. 110 * @param user the user to set. 111 * @throws AmetysRepositoryException if an error occurs. 112 */ 113 public void setCreator(DefaultContent content, UserIdentity user) throws AmetysRepositoryException 114 { 115 _storeUserMetadata(content, DefaultContent.METADATA_CREATOR, user); 116 } 117 118 /** 119 * Set a {@link DefaultContent} creation date. 120 * @param content the {@link DefaultContent} to set. 121 * @param creationDate the creation date to set. 122 * @throws AmetysRepositoryException if an error occurs. 123 */ 124 public void setCreationDate(DefaultContent content, ZonedDateTime creationDate) throws AmetysRepositoryException 125 { 126 ModifiableRepositoryData repositoryData = new JCRRepositoryData(content.getNode()); 127 Calendar calendar = DateUtils.asCalendar(creationDate); 128 repositoryData.setValue(DefaultContent.METADATA_CREATION, calendar); 129 } 130 131 /** 132 * Set a {@link DefaultContent} contributor. 133 * @param content the {@link DefaultContent} to set. 134 * @param user the contributor to set. 135 * @throws AmetysRepositoryException if an error occurs. 136 */ 137 public void setLastContributor(DefaultContent content, UserIdentity user) throws AmetysRepositoryException 138 { 139 _storeUserMetadata(content, DefaultContent.METADATA_CONTRIBUTOR, user); 140 } 141 142 /** 143 * Set a {@link DefaultContent} last modification date. 144 * @param content the {@link DefaultContent} to set. 145 * @param lastModified the last modification date to set. 146 * @throws AmetysRepositoryException if an error occurs. 147 */ 148 public void setLastModified(DefaultContent content, ZonedDateTime lastModified) throws AmetysRepositoryException 149 { 150 ModifiableRepositoryData repositoryData = new JCRRepositoryData(content.getNode()); 151 Calendar calendar = DateUtils.asCalendar(lastModified); 152 repositoryData.setValue(DefaultContent.METADATA_MODIFIED, calendar); 153 } 154 155 /** 156 * Set a {@link DefaultContent} first validator. 157 * @param content the {@link DefaultContent} to set. 158 * @param user the validator to set. 159 * @throws AmetysRepositoryException if an error occurs. 160 */ 161 public void setFirstValidator(DefaultContent content, UserIdentity user) throws AmetysRepositoryException 162 { 163 _storeUserMetadata(content, DefaultContent.METADATA_FIRST_VALIDATOR, user); 164 } 165 166 /** 167 * Set a {@link DefaultContent} first validation date. 168 * @param content the {@link DefaultContent} to set. 169 * @param validationDate the first validation date. 170 * @throws AmetysRepositoryException if an error occurs. 171 */ 172 public void setFirstValidationDate(DefaultContent content, ZonedDateTime validationDate) throws AmetysRepositoryException 173 { 174 ModifiableRepositoryData repositoryData = new JCRRepositoryData(content.getNode()); 175 Calendar calendar = DateUtils.asCalendar(validationDate); 176 repositoryData.setValue(DefaultContent.METADATA_FIRST_VALIDATION, calendar); 177 } 178 179 /** 180 * Set a {@link DefaultContent} last validator. 181 * @param content the {@link DefaultContent} to set. 182 * @param user the validator to set. 183 * @throws AmetysRepositoryException if an error occurs. 184 */ 185 public void setLastValidator(DefaultContent content, UserIdentity user) throws AmetysRepositoryException 186 { 187 _storeUserMetadata(content, DefaultContent.METADATA_LAST_VALIDATOR, user); 188 } 189 190 /** 191 * Set a {@link DefaultContent} last validation date. 192 * @param content the {@link DefaultContent} to set. 193 * @param validationDate the last validation date. 194 * @throws AmetysRepositoryException if an error occurs. 195 */ 196 public void setLastValidationDate(DefaultContent content, ZonedDateTime validationDate) throws AmetysRepositoryException 197 { 198 ModifiableRepositoryData repositoryData = new JCRRepositoryData(content.getNode()); 199 Calendar calendar = DateUtils.asCalendar(validationDate); 200 repositoryData.setValue(DefaultContent.METADATA_LAST_VALIDATION, calendar); 201 } 202 203 /** 204 * Set a {@link DefaultContent} last major validator. 205 * @param content the {@link DefaultContent} to set. 206 * @param user the validator to set. 207 * @throws AmetysRepositoryException if an error occurs. 208 */ 209 public void setLastMajorValidator(DefaultContent content, UserIdentity user) throws AmetysRepositoryException 210 { 211 _storeUserMetadata(content, DefaultContent.METADATA_LAST_MAJOR_VALIDATOR, user); 212 } 213 214 /** 215 * Set a {@link DefaultContent} last major validation date. 216 * @param content the {@link DefaultContent} to set. 217 * @param validationDate the last major validation date. 218 * @throws AmetysRepositoryException if an error occurs. 219 */ 220 public void setLastMajorValidationDate(DefaultContent content, ZonedDateTime validationDate) throws AmetysRepositoryException 221 { 222 ModifiableRepositoryData repositoryData = new JCRRepositoryData(content.getNode()); 223 Calendar calendar = DateUtils.asCalendar(validationDate); 224 repositoryData.setValue(DefaultContent.METADATA_LAST_MAJORVALIDATION, calendar); 225 } 226 227 /** 228 * Store the outgoing references on the content. 229 * @param content The content concerned by these outgoing references. 230 * @param references A non null map of outgoing references grouped by metadata (key are metadata path) 231 * @throws AmetysRepositoryException if an error occurs. 232 */ 233 public void setOutgoingReferences(DefaultContent content, Map<String, OutgoingReferences> references) throws AmetysRepositoryException 234 { 235 try 236 { 237 Node contentNode = content.getNode(); 238 if (contentNode.hasNode(RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ':' + DefaultContent.METADATA_ROOT_OUTGOING_REFERENCES)) 239 { 240 contentNode.getNode(RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ':' + DefaultContent.METADATA_ROOT_OUTGOING_REFERENCES).remove(); 241 } 242 243 if (references.size() != 0) 244 { 245 Node rootOutgoingRefsNode = contentNode.addNode(RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ':' + DefaultContent.METADATA_ROOT_OUTGOING_REFERENCES); 246 for (String path : references.keySet()) 247 { 248 // Outgoing references node creation (for the given path) 249 Node outgoingRefsNode = rootOutgoingRefsNode.addNode(RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ':' + DefaultContent.METADATA_OUTGOING_REFERENCES); 250 outgoingRefsNode.setProperty(RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ':' + DefaultContent.METADATA_OUTGOING_REFERENCES_PATH_PROPERTY, path); 251 252 // Reference nodes per type 253 OutgoingReferences outgoingReferences = references.get(path); 254 255 for (String type : outgoingReferences.keySet()) 256 { 257 List<String> referenceValues = outgoingReferences.get(type); 258 if (referenceValues != null && !referenceValues.isEmpty()) 259 { 260 Node outgoingReferenceNode = outgoingRefsNode.addNode(type, RepositoryConstants.NAMESPACE_PREFIX + ':' + DefaultContent.METADATA_OUTGOING_REFERENCE_NODETYPE); 261 outgoingReferenceNode.setProperty(RepositoryConstants.NAMESPACE_PREFIX + ':' + DefaultContent.METADATA_OUTGOING_REFERENCE_PROPERTY, referenceValues.toArray(new String[referenceValues.size()])); 262 } 263 } 264 } 265 } 266 } 267 catch (RepositoryException e) 268 { 269 throw new AmetysRepositoryException(e); 270 } 271 } 272 273 /** 274 * Store a metadata of type user in the content 275 * @param content the content described by the metadata 276 * @param metadataName the name of the metadata 277 * @param user the value to set 278 * @throws AmetysRepositoryException when an error occurred 279 */ 280 protected void _storeUserMetadata(DefaultContent content, String metadataName, UserIdentity user) throws AmetysRepositoryException 281 { 282 try 283 { 284 // TODO CMS-9336 All the metatadata here should be stored using types 285 ModifiableRepositoryData repositoryData = new JCRRepositoryData(content.getNode()); 286 ModifiableRepositoryData creatorRepositoryData; 287 if (repositoryData.hasValue(metadataName)) 288 { 289 creatorRepositoryData = repositoryData.getRepositoryData(metadataName); 290 } 291 else 292 { 293 creatorRepositoryData = repositoryData.addRepositoryData(metadataName, RepositoryConstants.USER_NODETYPE); 294 } 295 creatorRepositoryData.setValue("login", user.getLogin()); 296 creatorRepositoryData.setValue("population", user.getPopulationId()); 297 } 298 catch (AmetysRepositoryException e) 299 { 300 throw new AmetysRepositoryException("Error setting the metadata '" + metadataName + "' for content '" + content.getId() + "' with value '" + UserIdentity.userIdentityToString(user) + "'.", e); 301 } 302 } 303}