001/*
002 *  Copyright 2016 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.web.live;
017
018import java.util.HashMap;
019import java.util.Map;
020
021import javax.jcr.Repository;
022import javax.mail.MessagingException;
023
024import org.apache.avalon.framework.CascadingRuntimeException;
025import org.apache.avalon.framework.component.WrapperComponentManager;
026import org.apache.avalon.framework.context.Context;
027import org.apache.avalon.framework.context.ContextException;
028import org.apache.avalon.framework.service.ServiceException;
029import org.apache.avalon.framework.service.ServiceManager;
030import org.apache.cocoon.Constants;
031import org.apache.cocoon.Processor;
032import org.apache.cocoon.components.CocoonComponentManager;
033import org.apache.cocoon.util.log.SLF4JLoggerAdapter;
034import org.apache.commons.lang.exception.ExceptionUtils;
035import org.quartz.JobExecutionContext;
036
037import org.ametys.core.util.I18nUtils;
038import org.ametys.core.util.mail.SendMailHelper;
039import org.ametys.plugins.core.impl.schedule.AbstractStaticSchedulable;
040import org.ametys.runtime.config.Config;
041import org.ametys.runtime.i18n.I18nizableText;
042import org.ametys.web.generation.GenerationEnvironment;
043
044/**
045 * Abstract schedulable for rebuilding the live workspace.
046 */
047public abstract class AbstractRebuildLiveWorkspaceSchedulable extends AbstractStaticSchedulable
048{
049    /** The i18n text for the subject of the error mail */
050    protected static I18nizableText __ERROR_MAIL_SUBJECT;
051    /** The i18n text for the body of the error mail */
052    protected static I18nizableText __ERROR_MAIL_BODY;
053    /** The cocoon environment context. */
054    protected org.apache.cocoon.environment.Context _environmentContext;
055    /** The utils for i18n */
056    protected I18nUtils _i18nUtils;
057    /** Component for rebuilding the live workspace */
058    protected RebuildLiveComponent _rebuildLiveComponent;
059    /** JCR repository */
060    protected Repository _repository;
061    
062    @Override
063    public void contextualize(Context context) throws ContextException
064    {
065        super.contextualize(context);
066        _environmentContext = (org.apache.cocoon.environment.Context) context.get(Constants.CONTEXT_ENVIRONMENT_CONTEXT);
067    }
068    
069    @Override
070    public void service(ServiceManager manager) throws ServiceException
071    {
072        super.service(manager);
073        _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE);
074        _rebuildLiveComponent = (RebuildLiveComponent) manager.lookup(RebuildLiveComponent.ROLE);
075        _repository = (Repository) manager.lookup(Repository.class.getName());
076    }
077    
078    @Override
079    public void execute(JobExecutionContext context) throws Exception
080    {
081        getLogger().info("Time to rebuild live workspace");
082        
083        // Create environment
084        Map<String, Object> env = _createAndEnterGenerationEnvironment();
085        
086        try
087        {
088            _doExecute(context);
089        }
090        catch (Exception e)
091        {
092            getLogger().error("Unable to rebuild live workspace", e);
093            _initializeErrorMail(context);
094            _sendErrorMail(ExceptionUtils.getStackTrace(e));
095            throw e;
096        }
097        finally
098        {
099            _leaveGenerationEnvironment(env);
100        }
101    }
102    
103    /**
104     * Executes the runnable. Implements this method for building the live.
105     * @param context the context
106     * @throws Exception if an error occured
107     */
108    protected abstract void _doExecute(JobExecutionContext context) throws Exception;
109    
110    /**
111     * Initializes {@link AbstractRebuildLiveWorkspaceSchedulable#__ERROR_MAIL_BODY} and {@link AbstractRebuildLiveWorkspaceSchedulable#__ERROR_MAIL_SUBJECT}
112     * @param context the context
113     */
114    protected abstract void _initializeErrorMail(JobExecutionContext context);
115    
116    private void _sendErrorMail (String message)
117    {
118        String recipient = Config.getInstance().getValue("smtp.mail.sysadminto");
119        String sender = Config.getInstance().getValue("smtp.mail.from");
120        try
121        {
122            String subject = _i18nUtils.translate(__ERROR_MAIL_SUBJECT);
123            
124            String body = _i18nUtils.translate(__ERROR_MAIL_BODY);
125            body += "\n\n" + message;
126            
127            SendMailHelper.sendMail(subject, null, body, recipient, sender);
128        }
129        catch (MessagingException e)
130        {
131            if (getLogger().isWarnEnabled())
132            {
133                getLogger().warn("Could not send an alert e-mail to " + recipient, e);
134            }
135        }
136    }
137    
138    private Map<String, Object> _createAndEnterGenerationEnvironment()
139    {
140        GenerationEnvironment environment;
141        Processor processor;
142
143        try
144        {
145            environment = new GenerationEnvironment(new SLF4JLoggerAdapter(getLogger()), _environmentContext, "");
146            processor = (Processor) _smanager.lookup(Processor.ROLE);
147        }
148        catch (Exception e)
149        {
150            throw new CascadingRuntimeException("Error during environment's setup.", e);
151        }
152
153        Object processingKey = CocoonComponentManager.startProcessing(environment);
154        int environmentDepth = CocoonComponentManager.markEnvironment();
155
156        CocoonComponentManager.enterEnvironment(environment, new WrapperComponentManager(_smanager), processor);
157
158        Map<String, Object> result = new HashMap<>();
159
160        result.put("environment", environment);
161        result.put("processor", processor);
162        result.put("processingKey", processingKey);
163        result.put("environmentDepth", new Integer(environmentDepth));
164
165        return result;
166    }
167
168    private void _leaveGenerationEnvironment(Map environmentInformation)
169    {
170        GenerationEnvironment environment = (GenerationEnvironment) environmentInformation.get("environment");
171        Processor processor = (Processor) environmentInformation.get("processor");
172        Object processingKey = environmentInformation.get("processingKey");
173        int environmentDepth = ((Integer) environmentInformation.get("environmentDepth")).intValue();
174
175        CocoonComponentManager.leaveEnvironment();
176        CocoonComponentManager.endProcessing(environment, processingKey);
177
178        try
179        {
180            CocoonComponentManager.checkEnvironment(environmentDepth, new SLF4JLoggerAdapter(getLogger()));
181        }
182        catch (Exception e)
183        {
184            throw new CascadingRuntimeException("Error checking the environment", e);
185        }
186
187        _smanager.release(processor);
188    }
189}