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 */ 016package org.ametys.plugins.repository.jcr; 017 018import java.util.Collection; 019import java.util.Collections; 020 021import javax.jcr.ItemNotFoundException; 022import javax.jcr.Node; 023import javax.jcr.Repository; 024import javax.jcr.RepositoryException; 025import javax.jcr.Session; 026 027import org.apache.avalon.framework.configuration.Configurable; 028import org.apache.avalon.framework.configuration.Configuration; 029import org.apache.avalon.framework.configuration.ConfigurationException; 030import org.apache.avalon.framework.logger.AbstractLogEnabled; 031import org.apache.avalon.framework.service.ServiceException; 032import org.apache.avalon.framework.service.ServiceManager; 033import org.apache.avalon.framework.service.Serviceable; 034 035import org.ametys.plugins.repository.AmetysObject; 036import org.ametys.plugins.repository.AmetysObjectFactoryExtensionPoint; 037import org.ametys.plugins.repository.AmetysObjectResolver; 038import org.ametys.plugins.repository.AmetysRepositoryException; 039import org.ametys.plugins.repository.UnknownAmetysObjectException; 040import org.ametys.plugins.repository.data.type.ModelItemTypeExtensionPoint; 041import org.ametys.plugins.repository.provider.AbstractRepository; 042 043/** 044 * Default implementation of a {@link JCRAmetysObjectFactory}, 045 * handling {@link SimpleAmetysObject}.<br> 046 * This implementation takes its scheme and nodetype through a configuration:<br> 047 * <code> 048 * <extension point="org.ametys.plugins.repository.AmetysObjectFactoryExtensionPoint"<br> 049 * id="XXXX" 050 * class="org.ametys.plugins.repository.DefaultAmetysObjectFactory"><br> 051 * <scheme>your_scheme</scheme><br> 052 * <nodetype>your:nodetype</nodetype><br> 053 * [<nodetype>your:nodetype2</nodetype>]<br> 054 * [...]<br> 055 * </extension><br> 056 * This implementation manages only one nodetype. 057 * </code> 058 */ 059public class SimpleAmetysObjectFactory extends AbstractLogEnabled implements JCRAmetysObjectFactory<SimpleAmetysObject>, Configurable, Serviceable 060{ 061 /** The application {@link AmetysObjectResolver} */ 062 protected AmetysObjectResolver _resolver; 063 064 /** The {@link AmetysObjectFactoryExtensionPoint} */ 065 protected AmetysObjectFactoryExtensionPoint _ametysFactoryExtensionPoint; 066 067 /** The configured scheme */ 068 protected String _scheme; 069 070 /** The configured nodetype */ 071 protected String _nodetype; 072 073 /** JCR Repository */ 074 protected Repository _repository; 075 076 /** The Avalon {@link ServiceManager} */ 077 protected ServiceManager _manager; 078 079 /** The extension point with available modelItem types for handled ametys object */ 080 protected ModelItemTypeExtensionPoint _modelItemTypeExtensionPoint; 081 082 public void service(ServiceManager manager) throws ServiceException 083 { 084 _manager = manager; 085 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 086 _repository = (Repository) manager.lookup(AbstractRepository.ROLE); 087 _ametysFactoryExtensionPoint = (AmetysObjectFactoryExtensionPoint) manager.lookup(AmetysObjectFactoryExtensionPoint.ROLE); 088 } 089 090 public void configure(Configuration configuration) throws ConfigurationException 091 { 092 _scheme = configuration.getChild("scheme").getValue(); 093 094 Configuration[] nodetypesConf = configuration.getChildren("nodetype"); 095 096 if (nodetypesConf.length != 1) 097 { 098 throw new ConfigurationException("A SimpleAmetysObjectFactory must have one and only one associated nodetype. " 099 + "The '" + configuration.getAttribute("id") + "' component has " + nodetypesConf.length); 100 } 101 102 _nodetype = nodetypesConf[0].getValue(); 103 } 104 105 AmetysObjectResolver _getResolver() 106 { 107 return _resolver; 108 } 109 110 public String getScheme() 111 { 112 return _scheme; 113 } 114 115 public Collection<String> getNodetypes() 116 { 117 return Collections.singletonList(_nodetype); 118 } 119 120 @SuppressWarnings("unchecked") 121 public SimpleAmetysObject getAmetysObject(Node node, String parentPath) throws AmetysRepositoryException, RepositoryException 122 { 123 return new SimpleAmetysObject(node, parentPath, this); 124 } 125 126 public SimpleAmetysObject getAmetysObjectById(String id) throws AmetysRepositoryException 127 { 128 try 129 { 130 return getAmetysObjectById(id, null); 131 } 132 catch (RepositoryException e) 133 { 134 throw new AmetysRepositoryException("Unable to get AmetysObject for id: " + id, e); 135 } 136 } 137 138 @Override 139 public SimpleAmetysObject getAmetysObjectById(String id, Session session) throws AmetysRepositoryException, RepositoryException 140 { 141 Node node = getNode(id, session); 142 143 if (!node.getPath().startsWith('/' + AmetysObjectResolver.ROOT_REPO)) 144 { 145 throw new AmetysRepositoryException("Cannot resolve a Node outside Ametys tree"); 146 } 147 148 return getAmetysObject(node, null); 149 } 150 151 public boolean hasAmetysObjectForId(String id) throws AmetysRepositoryException 152 { 153 try 154 { 155 getNode(id, null); 156 return true; 157 } 158 catch (UnknownAmetysObjectException e) 159 { 160 return false; 161 } 162 } 163 164 /** 165 * Returns the JCR Node associated with the given object id.<br> 166 * This implementation assumes that the id is like <code><scheme>://<uuid></code> 167 * @param id the unique id of the object 168 * @param session the JCR Session to use to retrieve the Node. 169 * @return the JCR Node associated with the given id 170 */ 171 protected Node getNode(String id, Session session) 172 { 173 // l'id est de la forme <scheme>://uuid 174 String uuid = id.substring(getScheme().length() + 3); 175 176 Session jcrSession = null; 177 try 178 { 179 jcrSession = session != null ? session : _repository.login(); 180 Node node = jcrSession.getNodeByIdentifier(uuid); 181 return node; 182 } 183 catch (ItemNotFoundException e) 184 { 185 if (session == null && jcrSession != null) 186 { 187 // logout only if the session was created here 188 jcrSession.logout(); 189 } 190 191 throw new UnknownAmetysObjectException("There's no node for id " + id, e); 192 } 193 catch (RepositoryException e) 194 { 195 if (session == null && jcrSession != null) 196 { 197 // logout only if the session was created here 198 jcrSession.logout(); 199 } 200 201 throw new AmetysRepositoryException("Unable to get AmetysObject for id: " + id, e); 202 } 203 } 204 205 /** 206 * Returns the parent of the given {@link SimpleAmetysObject} . 207 * @param object a {@link SimpleAmetysObject}. 208 * @return the parent of the given {@link SimpleAmetysObject}. 209 * @throws AmetysRepositoryException if an error occurs. 210 */ 211 public AmetysObject getParent(SimpleAmetysObject object) throws AmetysRepositoryException 212 { 213 if (getLogger().isDebugEnabled()) 214 { 215 getLogger().debug("Entering DefaultTraversableAmetysObjectFactory.getParent with object of name: " + object.getName()); 216 } 217 218 Node node = getWorkspaceNode (object); 219 220 try 221 { 222 Node parentNode = node.getParent(); 223 String parentNodetype = NodeTypeHelper.getNodeTypeName(parentNode); 224 225 if (getLogger().isDebugEnabled()) 226 { 227 getLogger().debug("Parent nodetype is " + parentNodetype); 228 } 229 230 if (parentNodetype.equals(_nodetype)) 231 { 232 if (getLogger().isDebugEnabled()) 233 { 234 getLogger().debug("The parent node has the same nodetype than this ObjectFactory: " + _nodetype); 235 } 236 237 // si le nodetype est celui de la factory, on peut éviter de passer par le resolver 238 return getAmetysObject(parentNode, null); 239 } 240 241 return _resolver.resolve(parentNode, false); 242 } 243 catch (RepositoryException e) 244 { 245 throw new AmetysRepositoryException("Unable to retrieve parent object of object " + object.getName(), e); 246 } 247 } 248 249 /** 250 * Returns the JCR node backing this {@link SimpleAmetysObject} in the JCR workspace. May be overridden to deal with e.g. versionning 251 * @param object a {@link SimpleAmetysObject}. 252 * @return the JCR node backing this {@link SimpleAmetysObject}. 253 */ 254 protected Node getWorkspaceNode(SimpleAmetysObject object) 255 { 256 return object.getNode(); 257 } 258 259 /** 260 * Retrieves the extension point with available modelItem types for handled ametys object 261 * @return the model item type extension point 262 */ 263 public ModelItemTypeExtensionPoint getModelItemTypeExtensionPoint() 264 { 265 if (_modelItemTypeExtensionPoint == null) 266 { 267 try 268 { 269 _modelItemTypeExtensionPoint = (ModelItemTypeExtensionPoint) _manager.lookup(getModelItemTypeExtensionPointId()); 270 } 271 catch (ServiceException e) 272 { 273 throw new AmetysRepositoryException("Caught an exception while retrieving ModelItemTypeExtensionPoint", e); 274 } 275 } 276 277 return _modelItemTypeExtensionPoint; 278 } 279 280 /** 281 * Retrieves the identifier of extension point with available modelItem types for handled ametys object 282 * @return the identifier of the model item type extension point 283 */ 284 protected String getModelItemTypeExtensionPointId() 285 { 286 return ModelItemTypeExtensionPoint.ROLE_BASIC; 287 } 288}