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}