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.time.ZonedDateTime;
019import java.util.HashMap;
020import java.util.Map;
021
022import javax.jcr.Repository;
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.environment.background.BackgroundEnvironment;
034import org.apache.cocoon.util.log.SLF4JLoggerAdapter;
035import org.quartz.JobDataMap;
036import org.quartz.JobExecutionContext;
037
038import org.ametys.cms.schedule.AbstractSendingMailSchedulable;
039import org.ametys.core.user.UserIdentity;
040import org.ametys.plugins.core.schedule.Scheduler;
041import org.ametys.runtime.servlet.RuntimeServlet;
042import org.ametys.runtime.servlet.RuntimeServlet.ForcedMainteanceInformations;
043import org.ametys.runtime.servlet.RuntimeServlet.MaintenanceStatus;
044import org.ametys.runtime.servlet.RuntimeServlet.RunMode;
045
046/**
047 * Abstract schedulable for rebuilding the live workspace.
048 */
049public abstract class AbstractRebuildLiveWorkspaceSchedulable extends AbstractSendingMailSchedulable
050{
051    /** The key for the maintenance mode to rebuild the live workspace */
052    protected static final String JOBDATAMAP_MAINTENANCE_KEY = "maintenance";
053    
054    private static final String __JOBDATAMAP_MAINTENANCE_KEY = Scheduler.PARAM_VALUES_PREFIX + JOBDATAMAP_MAINTENANCE_KEY;
055    
056    /** The cocoon environment context. */
057    protected org.apache.cocoon.environment.Context _environmentContext;
058    /** Component for rebuilding the live workspace */
059    protected RebuildLiveComponent _rebuildLiveComponent;
060    /** JCR repository */
061    protected Repository _repository;
062    
063    @Override
064    public void contextualize(Context context) throws ContextException
065    {
066        super.contextualize(context);
067        _environmentContext = (org.apache.cocoon.environment.Context) context.get(Constants.CONTEXT_ENVIRONMENT_CONTEXT);
068    }
069    
070    @Override
071    public void service(ServiceManager manager) throws ServiceException
072    {
073        super.service(manager);
074        _rebuildLiveComponent = (RebuildLiveComponent) manager.lookup(RebuildLiveComponent.ROLE);
075        _repository = (Repository) manager.lookup(Repository.class.getName());
076    }
077    
078    @Override
079    protected void _doExecute(JobExecutionContext context) throws Exception
080    {
081        getLogger().info("Time to rebuild live workspace");
082        
083
084        // Create environment
085        Map<String, Object> env = _createAndEnterGenerationEnvironment();
086        
087        JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
088        Boolean maintenance = (Boolean) jobDataMap.get(__JOBDATAMAP_MAINTENANCE_KEY);
089        UserIdentity userIdentity = UserIdentity.stringToUserIdentity(jobDataMap.getString(Scheduler.KEY_RUNNABLE_USERIDENTITY));
090        
091        RunMode oldMode = null;
092        try
093        {
094            
095            if (Boolean.TRUE.equals(maintenance))
096            {
097                oldMode = RuntimeServlet.getRunMode();
098                
099                if (oldMode != RunMode.MAINTENANCE)
100                {
101                    RuntimeServlet.setMaintenanceStatus(MaintenanceStatus.FORCED, new ForcedMainteanceInformations("", userIdentity, ZonedDateTime.now()));
102                    RuntimeServlet.setRunMode(RunMode.MAINTENANCE);
103                }
104            }
105            
106            _rebuildLiveWorkspace(context);
107        }
108        finally
109        {
110            _leaveGenerationEnvironment(env);
111            
112            if (Boolean.TRUE.equals(maintenance) && oldMode != RunMode.MAINTENANCE)
113            {
114                RuntimeServlet.setRunMode(oldMode);
115                RuntimeServlet.setMaintenanceStatus(MaintenanceStatus.NONE, null);
116            }
117        }
118    }
119    
120    /**
121     * Implements this method for building the live.
122     * @param context the context
123     * @throws Exception if an error occurred
124     */
125    protected abstract void _rebuildLiveWorkspace(JobExecutionContext context) throws Exception;
126    
127    private Map<String, Object> _createAndEnterGenerationEnvironment()
128    {
129        BackgroundEnvironment environment;
130        Processor processor;
131
132        try
133        {
134            environment = new BackgroundEnvironment(new SLF4JLoggerAdapter(getLogger()), _environmentContext);
135            processor = (Processor) _smanager.lookup(Processor.ROLE);
136        }
137        catch (Exception e)
138        {
139            throw new CascadingRuntimeException("Error during environment's setup.", e);
140        }
141
142        Object processingKey = CocoonComponentManager.startProcessing(environment);
143        int environmentDepth = CocoonComponentManager.markEnvironment();
144
145        CocoonComponentManager.enterEnvironment(environment, new WrapperComponentManager(_smanager), processor);
146
147        Map<String, Object> result = new HashMap<>();
148
149        result.put("environment", environment);
150        result.put("processor", processor);
151        result.put("processingKey", processingKey);
152        result.put("environmentDepth", Integer.valueOf(environmentDepth));
153
154        return result;
155    }
156
157    private void _leaveGenerationEnvironment(Map environmentInformation)
158    {
159        BackgroundEnvironment environment = (BackgroundEnvironment) environmentInformation.get("environment");
160        Processor processor = (Processor) environmentInformation.get("processor");
161        Object processingKey = environmentInformation.get("processingKey");
162        int environmentDepth = ((Integer) environmentInformation.get("environmentDepth")).intValue();
163
164        CocoonComponentManager.leaveEnvironment();
165        CocoonComponentManager.endProcessing(environment, processingKey);
166
167        try
168        {
169            CocoonComponentManager.checkEnvironment(environmentDepth, new SLF4JLoggerAdapter(getLogger()));
170        }
171        catch (Exception e)
172        {
173            throw new CascadingRuntimeException("Error checking the environment", e);
174        }
175
176        _smanager.release(processor);
177    }
178}