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