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