001/*
002 *  Copyright 2011 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.contenttype;
017
018import org.apache.avalon.framework.service.ServiceException;
019import org.apache.avalon.framework.service.ServiceManager;
020import org.apache.avalon.framework.service.Serviceable;
021import org.apache.cocoon.xml.AttributesImpl;
022import org.slf4j.Logger;
023import org.slf4j.LoggerFactory;
024import org.xml.sax.Attributes;
025import org.xml.sax.SAXException;
026
027import org.ametys.plugins.repository.AmetysObject;
028import org.ametys.plugins.repository.AmetysObjectResolver;
029import org.ametys.plugins.repository.TraversableAmetysObject;
030import org.ametys.plugins.repository.UnknownAmetysObjectException;
031
032/**
033 * This handler look for links, images or video url which make reference to a AmetysObject (content, resources, ...) in a RichText.
034 * It must be used after a copy of a Content to changes theses references if necessary.
035 */
036public class DefaultDocbookUpdateHandler extends DockbookUpdateHandler implements Serviceable
037{
038    private static Logger _logger = LoggerFactory.getLogger(DefaultDocbookUpdateHandler.class.getName());
039    
040    /** The ametys object resolver */
041    protected AmetysObjectResolver _resolver;
042        
043    @Override
044    public void service(ServiceManager smanager) throws ServiceException
045    {
046        _resolver = (AmetysObjectResolver) smanager.lookup(AmetysObjectResolver.ROLE);
047    }
048   
049    @Override
050    public void startElement(String uri, String loc, String raw, Attributes attrs) throws SAXException
051    {
052        if ("link".equals(loc))
053        {
054            Attributes newAttrs = _getAttributesForLink(attrs);
055            super.startElement(uri, loc, raw, newAttrs);
056            return;
057        }
058        else if ("imagedata".equals(loc) || "videodata".equals(loc))
059        {
060            Attributes newAttrs = _getAttributesForMediaObject(attrs);
061            super.startElement(uri, loc, raw, newAttrs);
062            return;
063        }
064        
065        super.startElement(uri, loc, raw, attrs);
066    }
067    
068    /**
069     * Get attributes for link elements
070     * @param attrs the attributes
071     * @return the new attributes
072     */
073    protected Attributes _getAttributesForLink(Attributes attrs)
074    {
075        String href = attrs.getValue("xlink:href");
076        
077        String updateHref = _getUpdatedAmetysObjectId (href);
078        
079        AttributesImpl newAttrs = new AttributesImpl();
080        _copyAttributes(attrs, newAttrs);
081        newAttrs.addAttribute("", "href", "xlink:href", "CDATA", updateHref);
082     
083        return newAttrs;
084    }
085    
086    /**
087     * Get attributes for media objects such as image, flash
088     * @param attrs the attributes
089     * @return the new attributes
090     */
091    protected Attributes _getAttributesForMediaObject (Attributes attrs)
092    {
093        String href = attrs.getValue("fileref");
094        String type = attrs.getValue("type");
095        
096        String updateHref;
097        if ("local".equals(type))
098        {
099            updateHref = _getUpdatedHrefForLocalData (href);
100        }
101        else
102        {
103            updateHref = _getUpdatedAmetysObjectId (href);
104        }
105        
106        AttributesImpl newAttrs = new AttributesImpl();
107        _copyAttributes(attrs, newAttrs);
108        newAttrs.addAttribute("", "fileref", "fileref", "CDATA", updateHref);
109     
110        return newAttrs;
111    }
112    
113    /**
114     * Copy attributes
115     * @param attrs the attributes to copy
116     * @param newAttrs the new attributes
117     */
118    protected void _copyAttributes(Attributes attrs, AttributesImpl newAttrs)
119    {
120        for (int i = 0; i < attrs.getLength(); i++)
121        {
122            String name = attrs.getQName(i);
123            
124            if (!"xlink:href".equals(name) && !"fileref".equals(name))
125            {
126                newAttrs.addAttribute(attrs.getURI(i), attrs.getLocalName(i), name, attrs.getType(i), attrs.getValue(i));
127            }
128        }
129    }
130    
131    /**
132     * Returns the updated href for local data
133     * @param href the href to update
134     * @return the updated href
135     */
136    protected String _getUpdatedHrefForLocalData (String href)
137    {
138        int index = href.indexOf("@");
139        
140        String id = href.substring(0, index);
141        
142        String updateId = _getUpdatedAmetysObjectId (id);
143        
144        return updateId + href.substring(index);
145    }
146    
147    /**
148     * Return the updated ametys object id
149     * @param id the id to update
150     * @return the updated id
151     */
152    protected String _getUpdatedAmetysObjectId (String id)
153    {
154        try
155        {
156            if (id.equals(_initialContent.getId()))
157            {
158                return _createdContent.getId();
159            }
160            else if (_resolver.hasAmetysObjectForId(id))
161            {
162                AmetysObject ametysObject = _resolver.resolveById(id);
163                String path = ametysObject.getPath();
164                
165                String initialContentPath = _initialContent.getPath();
166                
167                if (path.startsWith(initialContentPath))
168                {
169                    // Is in path
170                    String relPath = path.equals(initialContentPath) ? "" : path.substring(initialContentPath.length() + 1);
171                    try
172                    {
173                        // Find symmetric object on copied sub-tree
174                        if (_createdContent instanceof TraversableAmetysObject)
175                        {
176                            AmetysObject child = "".equals(relPath) ? _createdContent : ((TraversableAmetysObject) _createdContent).getChild(relPath);
177                            return child.getId();
178                        }
179                    }
180                    catch (UnknownAmetysObjectException e)
181                    {
182                        _logger.warn("Object of path " + relPath + " was not found on copied sub-tree " + _createdContent.getPath(), e);
183                    }
184                }
185                else if (path.equals(_initialContentPath))
186                {
187                    // Return id of the new content
188                    return _createdContent.getId();
189                }
190            }
191            
192            // Return same id
193            return id;
194        }
195        catch (UnknownAmetysObjectException e)
196        {
197            // Return same id
198            return id;
199        }
200    }
201}