001/* 002 * Copyright 2010 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 */ 016 017package org.ametys.plugins.repository.jcr; 018 019import java.util.Map; 020import java.util.Optional; 021 022import javax.jcr.Node; 023import javax.jcr.RepositoryException; 024import javax.jcr.nodetype.ConstraintViolationException; 025 026import org.apache.jackrabbit.util.Text; 027 028import org.ametys.plugins.repository.AbstractAmetysObject; 029import org.ametys.plugins.repository.AmetysObject; 030import org.ametys.plugins.repository.AmetysRepositoryException; 031import org.ametys.plugins.repository.RepositoryIntegrityViolationException; 032import org.ametys.plugins.repository.data.UnknownDataException; 033import org.ametys.plugins.repository.data.holder.ModifiableDataHolder; 034import org.ametys.plugins.repository.data.holder.group.ModifiableComposite; 035import org.ametys.plugins.repository.data.holder.impl.DefaultModifiableDataHolder; 036import org.ametys.plugins.repository.data.holder.values.SynchronizationResult; 037import org.ametys.plugins.repository.data.repositorydata.ModifiableRepositoryData; 038import org.ametys.plugins.repository.data.repositorydata.impl.JCRRepositoryData; 039import org.ametys.plugins.repository.metadata.CompositeMetadata; 040import org.ametys.plugins.repository.metadata.ModifiableCompositeMetadata; 041import org.ametys.plugins.repository.metadata.jcr.JCRCompositeMetadata; 042import org.ametys.runtime.model.exception.BadDataPathCardinalityException; 043import org.ametys.runtime.model.exception.BadItemTypeException; 044import org.ametys.runtime.model.exception.NotUniqueTypeException; 045import org.ametys.runtime.model.exception.UndefinedItemPathException; 046import org.ametys.runtime.model.exception.UnknownTypeException; 047 048/** 049 * Default implementation of an {@link AmetysObject}, backed by a JCR node.<br> 050 * This implementation heavily relies on its {@link SimpleAmetysObjectFactory} counterpart. 051 * @param <F> the actual type of factory. 052 */ 053public class SimpleAmetysObject<F extends SimpleAmetysObjectFactory> extends AbstractAmetysObject implements JCRAmetysObject 054{ 055 /** The corresponding {@link SimpleAmetysObjectFactory} */ 056 private F _factory; 057 058 private Node _node; 059 060 private String _name; 061 private String _parentPath; 062 063 /** 064 * Creates an {@link SimpleAmetysObject}. 065 * @param node the node backing this {@link AmetysObject} 066 * @param parentPath the parentPath in the Ametys hierarchy 067 * @param factory the {@link SimpleAmetysObjectFactory} which created the AmetysObject 068 */ 069 public SimpleAmetysObject(Node node, String parentPath, F factory) 070 { 071 _node = node; 072 _parentPath = parentPath; 073 _factory = factory; 074 075 try 076 { 077 _name = Text.unescapeIllegalJcrChars(_node.getName()); 078 } 079 catch (RepositoryException e) 080 { 081 throw new AmetysRepositoryException("Unable to get node name", e); 082 } 083 } 084 085 /** 086 * Retrieves the factory. 087 * @return the factory. 088 */ 089 protected F _getFactory() 090 { 091 return _factory; 092 } 093 094 public String getName() throws AmetysRepositoryException 095 { 096 return _name; 097 } 098 099 /** 100 * Returns the root {@link CompositeMetadata} of this {@link AmetysObject}. 101 * @return the root {@link CompositeMetadata} of this {@link AmetysObject} 102 * @deprecated use getRepositoryData instead 103 */ 104 @Deprecated 105 public ModifiableCompositeMetadata getMetadataHolder() 106 { 107 return new JCRCompositeMetadata(getNode(), _getFactory()._getResolver()); 108 } 109 110 public String getParentPath() throws AmetysRepositoryException 111 { 112 if (_parentPath == null) 113 { 114 _parentPath = getParent().getPath(); 115 } 116 117 return _parentPath; 118 } 119 120 /** 121 * Invalidates cached parent path. 122 */ 123 protected void _invalidateParentPath() 124 { 125 _parentPath = null; 126 } 127 128 /** 129 * Recompute the name from the Node.<br> 130 * To be used when the node name changesd internally. 131 */ 132 protected void _invalidateName() 133 { 134 try 135 { 136 _name = Text.unescapeIllegalJcrChars(getNode().getName()); 137 } 138 catch (RepositoryException e) 139 { 140 throw new AmetysRepositoryException(e); 141 } 142 } 143 144 public String getPath() throws AmetysRepositoryException 145 { 146 return getParentPath() + "/" + getName(); 147 } 148 149 public Node getNode() 150 { 151 return _node; 152 } 153 154 public String getId() 155 { 156 try 157 { 158 return _factory.getScheme() + "://" + _node.getIdentifier(); 159 } 160 catch (RepositoryException e) 161 { 162 throw new AmetysRepositoryException("Unable to get node UUID", e); 163 } 164 } 165 166 @Override 167 public void rename(String newName) throws AmetysRepositoryException 168 { 169 try 170 { 171 NodeHelper.rename(getNode(), newName); 172 _name = Text.unescapeIllegalJcrChars(getNode().getName()); 173 } 174 catch (RepositoryException e) 175 { 176 throw new AmetysRepositoryException(e); 177 } 178 } 179 180 public void remove() throws AmetysRepositoryException, RepositoryIntegrityViolationException 181 { 182 try 183 { 184 getNode().remove(); 185 } 186 catch (ConstraintViolationException e) 187 { 188 throw new RepositoryIntegrityViolationException(e); 189 } 190 catch (RepositoryException e) 191 { 192 throw new AmetysRepositoryException(e); 193 } 194 } 195 196 @SuppressWarnings("unchecked") 197 public <A extends AmetysObject> A getParent() throws AmetysRepositoryException 198 { 199 return (A) _factory.getParent(this); 200 } 201 202 @Override 203 public boolean needsSave() throws AmetysRepositoryException 204 { 205 try 206 { 207 return _node.getSession().hasPendingChanges(); 208 } 209 catch (RepositoryException e) 210 { 211 throw new AmetysRepositoryException(e); 212 } 213 } 214 215 public void saveChanges() throws AmetysRepositoryException 216 { 217 try 218 { 219 getNode().getSession().save(); 220 } 221 catch (javax.jcr.RepositoryException e) 222 { 223 throw new AmetysRepositoryException("Unable to save changes", e); 224 } 225 } 226 227 @Override 228 public void revertChanges() throws AmetysRepositoryException 229 { 230 try 231 { 232 getNode().refresh(false); 233 } 234 catch (javax.jcr.RepositoryException e) 235 { 236 throw new AmetysRepositoryException("Unable to revert changes.", e); 237 } 238 } 239 240 @Override 241 protected ModifiableDataHolder getDataHolder() 242 { 243 ModifiableRepositoryData repositoryData = new JCRRepositoryData(getNode()); 244 return new DefaultModifiableDataHolder(_getFactory().getModelItemTypeExtensionPoint(), repositoryData); 245 } 246 247 @Override 248 public ModifiableComposite getComposite(String compositePath) throws IllegalArgumentException, UnknownTypeException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 249 { 250 return getDataHolder().getComposite(compositePath); 251 } 252 253 public ModifiableComposite getComposite(String compositePath, boolean createNew) throws IllegalArgumentException, UnknownTypeException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 254 { 255 return getDataHolder().getComposite(compositePath, createNew); 256 } 257 258 public <T extends SynchronizationResult> T synchronizeValues(Map<String, Object> values) throws UnknownTypeException, NotUniqueTypeException, BadItemTypeException, UndefinedItemPathException 259 { 260 return getDataHolder().synchronizeValues(values); 261 } 262 263 public void setValue(String dataPath, Object value) throws IllegalArgumentException, UnknownDataException, UnknownTypeException, NotUniqueTypeException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 264 { 265 getDataHolder().setValue(dataPath, value); 266 } 267 268 public void setValue(String dataPath, Object value, String dataType) throws IllegalArgumentException, UnknownDataException, UnknownTypeException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 269 { 270 getDataHolder().setValue(dataPath, value, dataType); 271 } 272 273 public void removeValue(String dataPath) throws IllegalArgumentException, UnknownTypeException, BadItemTypeException, UndefinedItemPathException, BadDataPathCardinalityException 274 { 275 getDataHolder().removeValue(dataPath); 276 } 277 278 @Override 279 public ModifiableRepositoryData getRepositoryData() 280 { 281 return getDataHolder().getRepositoryData(); 282 } 283 284 @Override 285 public Optional<? extends ModifiableDataHolder> getParentDataHolder() 286 { 287 return getDataHolder().getParentDataHolder(); 288 } 289 290 @Override 291 public ModifiableDataHolder getRootDataHolder() 292 { 293 return getDataHolder().getRootDataHolder(); 294 } 295}