001/*
002 *  Copyright 2019 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.contentio.archive;
017
018import java.io.IOException;
019import java.nio.file.Path;
020import java.util.Collection;
021import java.util.Collections;
022import java.util.Optional;
023import java.util.stream.Stream;
024import java.util.zip.ZipOutputStream;
025
026import javax.jcr.Node;
027import javax.jcr.NodeIterator;
028import javax.jcr.RepositoryException;
029
030import org.apache.avalon.framework.service.ServiceException;
031import org.apache.avalon.framework.service.ServiceManager;
032import org.apache.avalon.framework.service.Serviceable;
033
034import org.ametys.plugins.repository.AmetysObjectResolver;
035import org.ametys.plugins.repository.collection.AmetysObjectCollection;
036import org.ametys.runtime.i18n.I18nizableText;
037import org.ametys.runtime.plugin.component.AbstractLogEnabled;
038
039/**
040 * Archives contents in /ametys:root/ametys:contents
041 */
042public class ContentArchiver extends AbstractLogEnabled implements Archiver, Serviceable
043{
044    /** Archiver id. */
045    public static final String ID = "contents";
046    
047    private AmetysObjectResolver _resolver;
048    private ContentsArchiverHelper _contentsArchiverHelper;
049    
050    private ManifestReaderWriter _manifestReaderWriter = new ContentArchiverManifestReaderWriter();
051    
052    @Override
053    public void service(ServiceManager manager) throws ServiceException
054    {
055        _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE);
056        _contentsArchiverHelper = (ContentsArchiverHelper) manager.lookup(ContentsArchiverHelper.ROLE);
057    }
058    
059    @Override
060    public ManifestReaderWriter getManifestReaderWriter()
061    {
062        return _manifestReaderWriter;
063    }
064    
065    private class ContentArchiverManifestReaderWriter implements ManifestReaderWriter
066    {
067        private static final String __DATA = "contents";
068        
069        @Override
070        public Object getData()
071        {
072            return __DATA;
073        }
074        
075        @SuppressWarnings("synthetic-access")
076        @Override
077        public Stream<PartialImport> toPartialImports(Object data)
078        {
079            return Optional.ofNullable(data)
080                    .filter(String.class::isInstance)
081                    .map(String.class::cast)
082                    .filter(__DATA::equals)
083                    .map(Stream::of)
084                    .orElseGet(() ->
085                    {
086                        getLogger().warn("Unexpected manifest data '{}', we would expect '{}', the ZIP archive probably comes from a different version of Ametys.", data, __DATA);
087                        return Stream.empty();
088                    })
089                    .map(contentsStr -> PartialImport.of(contentsStr, new I18nizableText("plugin.contentio", "PLUGINS_CONTENTIO_ARCHIVE_IMPORT_CONTENT_ARCHIVER_OPTION_ALL")));
090        }
091    }
092    
093    @Override
094    public void export(ZipOutputStream zos) throws IOException
095    {
096        AmetysObjectCollection rootContents = _rootContents();
097        _contentsArchiverHelper.exportContents("contents/", rootContents, zos);
098    }
099    
100    private AmetysObjectCollection _rootContents()
101    {
102        return _resolver.resolveByPath("/ametys:contents");
103    }
104    
105    private void _deleteBeforePartialImport(AmetysObjectCollection rootContents) throws IOException
106    {
107        try
108        {
109            Node rootContentsNode = rootContents.getNode();
110            NodeIterator rootChildren = rootContentsNode.getNodes();
111            while (rootChildren.hasNext())
112            {
113                rootChildren.nextNode().remove();
114            }
115            rootContentsNode.getSession().save();
116        }
117        catch (RepositoryException e)
118        {
119            throw new IOException(e);
120        }
121    }
122    
123    @Override
124    public Collection<String> managedPartialImports(Collection<String> partialImports)
125    {
126        return partialImports.contains(ID)
127                ? Collections.singletonList(ID)
128                : Collections.EMPTY_LIST;
129    }
130    
131    @Override
132    public ImportReport partialImport(Path zipPath, Collection<String> partialImports, Merger merger, boolean deleteBefore) throws IOException
133    {
134        AmetysObjectCollection rootContents = _rootContents();
135        if (deleteBefore)
136        {
137            _deleteBeforePartialImport(rootContents);
138        }
139        return _contentsArchiverHelper.importContents("contents/", rootContents, zipPath, merger, Collections.EMPTY_SET);
140    }
141}