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}