001/* 002 * Copyright 2021 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.odf.schedulable; 017 018import java.io.IOException; 019import java.util.HashMap; 020import java.util.Map; 021import java.util.Objects; 022 023import org.apache.avalon.framework.service.ServiceException; 024import org.apache.avalon.framework.service.ServiceManager; 025import org.apache.commons.lang3.StringUtils; 026import org.apache.commons.lang3.exception.ExceptionUtils; 027import org.quartz.JobDataMap; 028import org.quartz.JobExecutionContext; 029import org.quartz.JobExecutionException; 030 031import org.ametys.cms.schedule.AbstractSendingMailSchedulable; 032import org.ametys.core.schedule.progression.ContainerProgressionTracker; 033import org.ametys.core.schedule.progression.SimpleProgressionTracker; 034import org.ametys.core.ui.mail.StandardMailBodyHelper; 035import org.ametys.odf.catalog.Catalog; 036import org.ametys.odf.catalog.CatalogsManager; 037import org.ametys.plugins.core.schedule.Scheduler; 038import org.ametys.runtime.i18n.I18nizableText; 039import org.ametys.runtime.i18n.I18nizableTextParameter; 040 041/** 042 * Schedulable to copy a catalog. 043 */ 044public class CopyCatalogSchedulable extends AbstractSendingMailSchedulable 045{ 046 047 /** Schedulable ID */ 048 public static final String SCHEDULABLE_ID = CopyCatalogSchedulable.class.getName(); 049 050 /** The key for the source catalog */ 051 public static final String JOBDATAMAP_SRC_CATALOG_KEY = "srcCatalog"; 052 053 /** The key for the destinationcatalog */ 054 public static final String JOBDATAMAP_DEST_CATALOG_KEY = "destCatalog"; 055 056 private static final String __RESTART_SOLR_COMMIT = "restart-solr-commit"; 057 private static final String __UPDATE_WORKFLOW_STEP = "update-workflow-step"; 058 private static final String __UPDATES_AFTER_COPY_STEP = "updates-after-copy-step"; 059 private static final String __COPY_STEP = "copy-step"; 060 private static final String __BEFORE_COPY_CHECKS_STEP = "before-copy-checks-step"; 061 062 /** The catalogs manager */ 063 protected CatalogsManager _catalogsManager; 064 065 @Override 066 public void service(ServiceManager manager) throws ServiceException 067 { 068 super.service(manager); 069 _catalogsManager = (CatalogsManager) manager.lookup(CatalogsManager.ROLE); 070 } 071 072 @Override 073 protected void _doExecute(JobExecutionContext context, ContainerProgressionTracker progressionTracker) throws Exception 074 { 075 SimpleProgressionTracker beforeCopyChecks = progressionTracker.addSimpleStep(__BEFORE_COPY_CHECKS_STEP, new I18nizableText("plugin.odf", "PLUGINS_ODF_SCHEDULABLE_COPY_CATALOG_BEFORE_COPY_CHECKS_STEP_LABEL")); 076 progressionTracker.addSimpleStep(__COPY_STEP, new I18nizableText("plugin.odf", "PLUGINS_ODF_SCHEDULABLE_COPY_CATALOG_COPY_STEP_LABEL"), 10); 077 progressionTracker.addSimpleStep(__UPDATES_AFTER_COPY_STEP, new I18nizableText("plugin.odf", "PLUGINS_ODF_SCHEDULABLE_COPY_CATALOG_UPDATE_AFTER_COPY_STEP_LABEL"), 5); 078 progressionTracker.addSimpleStep(__UPDATE_WORKFLOW_STEP, new I18nizableText("plugin.odf", "PLUGINS_ODF_SCHEDULABLE_COPY_CATALOG_UPDATE_WORKFLOW_STEP_LABEL"), 10); 079 progressionTracker.addSimpleStep(__RESTART_SOLR_COMMIT, new I18nizableText("plugin.odf", "PLUGINS_ODF_SCHEDULABLE_COPY_CATALOG_RESTART_SOLR_COMMIT_STEP_LABEL"), 10); 080 081 beforeCopyChecks.setSize(1); 082 083 JobDataMap jobDataMap = context.getJobDetail().getJobDataMap(); 084 085 // Check source catalog 086 String srcCatalogName = jobDataMap.getString(Scheduler.PARAM_VALUES_PREFIX + JOBDATAMAP_SRC_CATALOG_KEY); 087 if (StringUtils.isEmpty(srcCatalogName)) 088 { 089 throw new JobExecutionException("The source catalog name cannot be empty."); 090 } 091 092 // Check destination catalog 093 String destCatalogName = jobDataMap.getString(Scheduler.PARAM_VALUES_PREFIX + JOBDATAMAP_DEST_CATALOG_KEY); 094 if (StringUtils.isEmpty(destCatalogName)) 095 { 096 throw new JobExecutionException("The destination catalog name cannot be empty."); 097 } 098 099 // Check that source and destination catalog are different 100 if (Objects.equals(srcCatalogName, destCatalogName)) 101 { 102 throw new JobExecutionException("The source and destination catalogs cannot be the same."); 103 } 104 105 // Check the existence of the source catalog 106 Catalog srcCatalog = _catalogsManager.getCatalog(srcCatalogName); 107 if (srcCatalog == null) 108 { 109 throw new JobExecutionException("The source catalog should exist."); 110 } 111 112 // Check the existence of the destination catalog 113 Catalog destCatalog = _catalogsManager.getCatalog(destCatalogName); 114 if (destCatalog == null) 115 { 116 destCatalog = _catalogsManager.createCatalog(destCatalogName, destCatalogName); 117 } 118 119 beforeCopyChecks.increment(); 120 121 _catalogsManager.copyCatalog(destCatalog, srcCatalog, progressionTracker); 122 } 123 124 @Override 125 protected I18nizableText _getSuccessMailSubject(JobExecutionContext context) throws Exception 126 { 127 return new I18nizableText("plugin.odf", "PLUGINS_ODF_SCHEDULABLE_COPY_CATALOG_SUCCESS_MAIL_SUBJECT"); 128 } 129 130 @Override 131 protected boolean _isMailBodyInHTML(JobExecutionContext context) throws Exception 132 { 133 return true; 134 } 135 136 @Override 137 protected String _getSuccessMailBody(JobExecutionContext context) throws Exception 138 { 139 try 140 { 141 return StandardMailBodyHelper.newHTMLBody() 142 .withTitle(_getSuccessMailSubject(context)) 143 .withMessage(new I18nizableText("plugin.odf", "PLUGINS_ODF_SCHEDULABLE_COPY_CATALOG_SUCCESS_MAIL_BODY", _getCommonI18nParams(context))) 144 .build(); 145 } 146 catch (IOException e) 147 { 148 getLogger().warn("Failed to build HTML email body for catalog copy result. Fallback to no wrapped email", e); 149 return _i18nUtils.translate(new I18nizableText("plugin.odf", "PLUGINS_ODF_SCHEDULABLE_COPY_CATALOG_SUCCESS_MAIL_BODY", _getCommonI18nParams(context))); 150 } 151 } 152 153 @Override 154 protected I18nizableText _getErrorMailSubject(JobExecutionContext context) throws Exception 155 { 156 return new I18nizableText("plugin.odf", "PLUGINS_ODF_SCHEDULABLE_COPY_CATALOG_ERROR_MAIL_SUBJECT"); 157 } 158 159 @Override 160 protected String _getErrorMailBody(JobExecutionContext context, Throwable throwable) throws Exception 161 { 162 try 163 { 164 String error = ExceptionUtils.getStackTrace(throwable); 165 166 return StandardMailBodyHelper.newHTMLBody() 167 .withTitle(_getErrorMailSubject(context)) 168 .withMessage(new I18nizableText("plugin.odf", "PLUGINS_ODF_SCHEDULABLE_COPY_CATALOG_ERROR_MAIL_BODY", _getCommonI18nParams(context))) 169 .withDetails(null, error, true) 170 .build(); 171 } 172 catch (IOException e) 173 { 174 getLogger().warn("Failed to build HTML email body for catalog copy result. Fallback to no wrapped email", e); 175 return _i18nUtils.translate(new I18nizableText("plugin.odf", "PLUGINS_ODF_SCHEDULABLE_COPY_CATALOG_ERROR_MAIL_BODY", _getCommonI18nParams(context))); 176 } 177 } 178 179 private Map<String, I18nizableTextParameter> _getCommonI18nParams(JobExecutionContext context) 180 { 181 JobDataMap jobDataMap = context.getJobDetail().getJobDataMap(); 182 183 Map<String, I18nizableTextParameter> i18nParams = new HashMap<>(); 184 i18nParams.put("srcCatalog", new I18nizableText(jobDataMap.getString(Scheduler.PARAM_VALUES_PREFIX + JOBDATAMAP_SRC_CATALOG_KEY))); 185 i18nParams.put("destCatalog", new I18nizableText(jobDataMap.getString(Scheduler.PARAM_VALUES_PREFIX + JOBDATAMAP_DEST_CATALOG_KEY))); 186 return i18nParams; 187 } 188}