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