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.web.repository.page.jcr;
017
018import java.util.List;
019
020import javax.jcr.Node;
021import javax.jcr.RepositoryException;
022
023import org.slf4j.Logger;
024import org.slf4j.LoggerFactory;
025
026import org.ametys.cms.repository.Content;
027import org.ametys.cms.repository.DefaultContent;
028import org.ametys.plugins.repository.AmetysObject;
029import org.ametys.plugins.repository.AmetysRepositoryException;
030import org.ametys.plugins.repository.CopiableAmetysObject;
031import org.ametys.plugins.repository.ModifiableTraversableAmetysObject;
032import org.ametys.plugins.repository.RepositoryConstants;
033import org.ametys.plugins.repository.RepositoryIntegrityViolationException;
034import org.ametys.plugins.repository.data.holder.ModifiableModelAwareDataHolder;
035import org.ametys.plugins.repository.data.holder.ModifiableModelLessDataHolder;
036import org.ametys.plugins.repository.data.holder.impl.DefaultModifiableModelAwareDataHolder;
037import org.ametys.plugins.repository.data.holder.impl.DefaultModifiableModelLessDataHolder;
038import org.ametys.plugins.repository.data.repositorydata.ModifiableRepositoryData;
039import org.ametys.plugins.repository.data.repositorydata.impl.JCRRepositoryData;
040import org.ametys.plugins.repository.jcr.JCRAmetysObject;
041import org.ametys.plugins.repository.jcr.SimpleAmetysObject;
042import org.ametys.plugins.repository.metadata.ModifiableCompositeMetadata;
043import org.ametys.web.repository.content.WebContent;
044import org.ametys.web.repository.page.ModifiableZone;
045import org.ametys.web.repository.page.ModifiableZoneItem;
046import org.ametys.web.repository.page.Zone;
047
048/**
049 *  implementation of a {@link ModifiableZoneItem}.
050 */
051public class DefaultZoneItem extends SimpleAmetysObject<DefaultZoneItemFactory> implements ModifiableZoneItem, CopiableAmetysObject
052{
053    /** Constant for title metadata. */
054    public static final String METADATA_TYPE = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":type";
055    /** Constant for service metadata. */
056    public static final String METADATA_SERVICE = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":service";
057    /** Constant for content metadata. */
058    public static final String METADATA_CONTENT = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":content";
059    /** Constant service parameters node type. */
060    public static final String SERVICE_PARAM_NODETYPE = RepositoryConstants.NAMESPACE_PREFIX + ":compositeMetadata";
061    
062    /**
063     * Constant for "metadata set name" metadata.
064     * @deprecated Use {@link #METADATA_VIEW_NAME} instead
065     */
066    @Deprecated
067    public static final String METADATA_METADATASET_NAME = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":metadataSetName";
068    
069    /**
070     * Constant for view name metadata.
071     * TODO NEWATTRIBUTEAPI_SERVICE: Change the name of this metadata to viewName (there may be a lot of impacts..)
072     */
073    public static final String METADATA_VIEW_NAME = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":metadataSetName";
074    
075    private static final Logger __LOGGER = LoggerFactory.getLogger(DefaultZoneItem.class);
076
077    /**
078     * Creates a {@link DefaultZoneItem}.
079     * 
080     * @param node the node backing this {@link AmetysObject}.
081     * @param parentPath the parent path in the Ametys hierarchy.
082     * @param factory the {@link DefaultZoneItemFactory} which creates the AmetysObject.
083     */
084    public DefaultZoneItem(Node node, String parentPath, DefaultZoneItemFactory factory)
085    {
086        super(node, parentPath, factory);
087    }
088    
089    public ZoneType getType() throws AmetysRepositoryException
090    {
091        try
092        {
093            return ZoneType.valueOf(getNode().getProperty(METADATA_TYPE).getString());
094        }
095        catch (RepositoryException e)
096        {
097            throw new AmetysRepositoryException("Unable to get type property", e);
098        }
099    }
100
101    public void setType(ZoneType type) throws AmetysRepositoryException
102    {
103        try
104        {
105            getNode().setProperty(METADATA_TYPE, type.name());
106        }
107        catch (RepositoryException e)
108        {
109            throw new AmetysRepositoryException("Unable to set type property", e);
110        }
111    }
112
113    public <C extends Content> C getContent() throws AmetysRepositoryException
114    {
115        try
116        {
117            return _getFactory().<C>resolveAmetysObject(getNode().getProperty(METADATA_CONTENT).getNode());
118        }
119        catch (RepositoryException e)
120        {
121            throw new AmetysRepositoryException("Unable to get content property", e);
122        }
123    }
124
125    public <C extends Content> void setContent(C content) throws AmetysRepositoryException
126    {
127        try
128        {
129            // FIXME stop using getNode that is JCR but use AmetysObject API... if it seems cool to you
130            getNode().setProperty(METADATA_CONTENT, ((JCRAmetysObject) content).getNode());
131        }
132        catch (RepositoryException e)
133        {
134            throw new AmetysRepositoryException("Unable to set content property", e);
135        }    
136    }
137    
138    @Override
139    public String getMetadataSetName() throws AmetysRepositoryException
140    {
141        return getViewName();
142    }
143    
144    public String getViewName() throws AmetysRepositoryException
145    {
146        try
147        {
148            if (getNode().hasProperty(METADATA_VIEW_NAME))
149            {
150                return getNode().getProperty(METADATA_VIEW_NAME).getString();
151            }
152            return null;
153        }
154        catch (RepositoryException e)
155        {
156            throw new AmetysRepositoryException("Unable to get view name property.", e);
157        }
158    }
159    
160    @Override
161    public void setMetadataSetName(String metadataSetName) throws AmetysRepositoryException
162    {
163        setViewName(metadataSetName);
164    }
165    
166    @Override
167    public void setViewName(String viewName) throws AmetysRepositoryException
168    {
169        try
170        {
171            getNode().setProperty(METADATA_VIEW_NAME, viewName);
172        }
173        catch (RepositoryException e)
174        {
175            throw new AmetysRepositoryException("Unable to set view name property.", e);
176        }
177    }
178    
179    @Override
180    public String getServiceId() throws AmetysRepositoryException
181    {
182        try
183        {
184            return getNode().getProperty(METADATA_SERVICE).getString();
185        }
186        catch (RepositoryException e)
187        {
188            throw new AmetysRepositoryException("Unable to get service property", e);
189        }
190    }
191    
192    @Override
193    public void setServiceId(String serviceId) throws AmetysRepositoryException
194    {
195        try
196        {
197            getNode().setProperty(METADATA_SERVICE, serviceId);
198        }
199        catch (RepositoryException e)
200        {
201            throw new AmetysRepositoryException("Unable to set service property", e);
202        }
203    }
204    
205    public ModifiableModelAwareDataHolder getServiceParameters() throws AmetysRepositoryException
206    {
207        JCRRepositoryData zoneItemRepositoryData = new JCRRepositoryData(getNode());
208        
209        JCRRepositoryData repositoryData = null;
210        if (zoneItemRepositoryData.hasValue(SERVICE_PARAMETERS_DATA_NAME))
211        {
212            repositoryData = (JCRRepositoryData) zoneItemRepositoryData.getRepositoryData(SERVICE_PARAMETERS_DATA_NAME);
213        }
214        else
215        {
216            repositoryData = (JCRRepositoryData) zoneItemRepositoryData.addRepositoryData(SERVICE_PARAMETERS_DATA_NAME, SERVICE_PARAM_NODETYPE);
217        }
218
219        return new DefaultModifiableModelAwareDataHolder(repositoryData, _getFactory().getService(getServiceId()));
220    }
221    
222    public ModifiableModelLessDataHolder getDataHolder()
223    {
224        ModifiableRepositoryData repositoryData = new JCRRepositoryData(getNode());
225        return new DefaultModifiableModelLessDataHolder(_getFactory().getPageDataTypeExtensionPoint(), repositoryData);
226    }
227    
228    @Override
229    public ModifiableCompositeMetadata getMetadataHolder()
230    {
231        __LOGGER.warn("The getMetadataHolder method of DefaultPage is deprecated. Use the getDataHolder instead. StackTrace: ", new Exception());
232        return super.getMetadataHolder();
233    }
234    
235    @Override
236    public ModifiableZoneItem copyTo(ModifiableTraversableAmetysObject parent, String name, List<String> restrictTo) throws AmetysRepositoryException
237    {
238        return copyTo (parent, name);
239    }
240    
241    @Override
242    public ModifiableZoneItem copyTo(ModifiableTraversableAmetysObject parent, String name) throws AmetysRepositoryException
243    {
244        if (parent instanceof DefaultZone)
245        {
246            ModifiableZone parentZone = (ModifiableZone) parent;
247            ModifiableZoneItem cZoneItem = parentZone.addZoneItem();
248            
249            ZoneType type = getType();
250            cZoneItem.setType(type);
251            
252            if (ZoneType.SERVICE.equals(type))
253            {
254                cZoneItem.setServiceId(getServiceId());
255                getServiceParameters().copyTo(cZoneItem.getServiceParameters());
256            }
257            else
258            {
259                Content content = getContent();
260                if (content instanceof WebContent)
261                {
262                    WebContent webContent = (WebContent) content;
263                    if (getZone().getPage().getSiteName().equals(webContent.getSiteName()))
264                    {
265                        if (webContent instanceof DefaultContent)
266                        {
267                            Content cContent = ((DefaultContent) webContent).copyTo(webContent.getSite().getRootContents(), null);
268                            cZoneItem.setContent(cContent);
269                            
270                            // Update references to AmetysObject in RichText
271                            _getFactory().getCopySiteComponent().updateLinksInRichText(getZone().getPage(), cZoneItem.getZone().getPage(), content, cContent);
272                        }
273                    }
274                    else
275                    {
276                        // Copy reference  
277                        cZoneItem.setContent(getContent());
278                    }
279                }
280                else
281                {
282                    // Copy reference
283                    cZoneItem.setContent(getContent());
284                }
285                
286                String metadataSetName = getMetadataSetName();
287                if (metadataSetName != null)
288                {
289                    cZoneItem.setMetadataSetName(metadataSetName);
290                }
291            }
292            
293            return cZoneItem;
294        }
295        else
296        {
297            throw new AmetysRepositoryException("Can not copy a zone item " + getId() + " of type DefaultZoneItem to something that is not a DefaultZone " + parent.getId());
298        }
299    }
300    
301    @Override
302    public boolean canMoveTo(AmetysObject newParent) throws AmetysRepositoryException
303    {
304        return newParent instanceof DefaultZone;
305    }
306    
307    @Override
308    public void moveTo(AmetysObject newParent, boolean renameIfExist) throws AmetysRepositoryException, RepositoryIntegrityViolationException
309    {
310        if (!canMoveTo(newParent))
311        {
312            throw new AmetysRepositoryException("Can not move a zone item " + getId() + " of type DefaultZoneItem to something that is not a DefaultZone " + newParent.getId());
313        }
314        
315        Node node = getNode();
316
317        try
318        {
319            DefaultZone newParentZone = (DefaultZone) newParent;
320                
321            // Move node
322            node.getSession().move(node.getPath(), newParentZone.getNode().getPath() + "/" + DefaultZone.ZONEITEMS_NODE_NAME + "/" + node.getName());
323        }
324        catch (RepositoryException e)
325        {
326            throw new AmetysRepositoryException("Can not move DefaultZoneItem " + getId() + " to DefaultZone " + newParent.getId(), e);
327        }
328    }
329    
330    @Override
331    public void orderBefore(AmetysObject siblingObject) throws AmetysRepositoryException
332    {
333        if (siblingObject != null && !(siblingObject instanceof JCRAmetysObject))
334        {
335            throw new AmetysRepositoryException(String.format("Unable to order zone item '%s' before sibling '%s' (sibling is not a JCRAmetysObject)", this.getId(), siblingObject.getId()));
336        }
337        
338        Node node = getNode();
339        Node siblingNode = siblingObject != null ? ((JCRAmetysObject) siblingObject).getNode() : null;
340        
341        try
342        {
343            node.getParent().orderBefore(node.getName() + "[" + node.getIndex() + "]", siblingNode != null ? siblingNode.getName() + "[" + siblingNode.getIndex() + "]" : null);
344        }
345        catch (RepositoryException e)
346        {
347            throw new AmetysRepositoryException(String.format("Unable to order zone item '%s' before sibling '%s'", this.getId(), siblingObject != null ? siblingObject.getId() : ""), e);
348        }
349    }
350    
351    @Override
352    public Zone getZone()
353    {
354        return getParent().getParent();
355    }
356}