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