001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software GmbH & Co. KG, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.scheduler.jobs;
029
030import org.opencms.file.CmsObject;
031import org.opencms.file.CmsProject;
032import org.opencms.file.CmsResource;
033import org.opencms.file.CmsResourceFilter;
034import org.opencms.file.CmsUser;
035import org.opencms.lock.CmsLock;
036import org.opencms.main.CmsException;
037import org.opencms.main.CmsLog;
038import org.opencms.main.OpenCms;
039import org.opencms.notification.CmsPublishNotification;
040import org.opencms.report.CmsWorkplaceReport;
041import org.opencms.scheduler.CmsScheduledJobInfo;
042import org.opencms.scheduler.I_CmsScheduledJob;
043import org.opencms.util.CmsUUID;
044
045import java.text.DateFormat;
046import java.util.Date;
047import java.util.Iterator;
048import java.util.Map;
049
050import org.apache.commons.logging.Log;
051
052/**
053 * Scheduled job for time based publishing.<p>
054 *
055 * This class is called via the front end to publish scheduled a file at a given time.<p>
056 *
057 * Per default, it publishes all new, edited and deleted resources in the project which are locked in
058 * the current project. For all resources in the project which are not locked by the current user is the
059 * lock changed. You are able to perform a link validation before
060 * publishing the project by adding the parameter <code>linkcheck=true</code>. It is possible to send
061 * an email to a user in OpenCms in case somthing went wrong during this process. To do so specifiy
062 * a parameter<code>mail-to-user=username_in_opencms</code>.
063 * After running this job, the job is deleted. Therefore the job name is to set in the parameter <code>jobname</code><p>
064 *
065 * @since 7.5.1
066 */
067public class CmsPublishScheduledJob implements I_CmsScheduledJob {
068
069    /** Job name parameter. */
070    public static final String PARAM_JOBNAME = "jobname";
071
072    /** Linkcheck parameter. */
073    public static final String PARAM_LINKCHECK = "linkcheck";
074
075    /** Mail to user parameter. */
076    public static final String PARAM_USER = "mail-to-user";
077
078    /** The log object for this class. */
079    private static final Log LOG = CmsLog.getLog(CmsPublishScheduledJob.class);
080
081    /** Optional parameter containing comma-separated list of structure ids of resources to explicitly unlock at the end of the job (only necessary for resources that don't get published). */
082    public static final String PARAM_UNLOCK_LIST = "unlock-list";
083
084    /**
085     * @see org.opencms.scheduler.I_CmsScheduledJob#launch(org.opencms.file.CmsObject, java.util.Map)
086     */
087    public synchronized String launch(CmsObject cms, Map<String, String> parameters) throws Exception {
088
089        Date jobStart = new Date();
090        String finishMessage;
091        String linkcheck = parameters.get(PARAM_LINKCHECK);
092        String jobName = parameters.get(PARAM_JOBNAME);
093        CmsProject project = cms.getRequestContext().getCurrentProject();
094        CmsWorkplaceReport report = new CmsWorkplaceReport(
095            cms.getRequestContext().getLocale(),
096            cms.getRequestContext().getSiteRoot(),
097            CmsPublishScheduledJob.class);
098
099        try {
100
101            // validate links if linkcheck parameter was given
102            if (Boolean.valueOf(linkcheck).booleanValue()) {
103                OpenCms.getPublishManager().validateRelations(
104                    cms,
105                    OpenCms.getPublishManager().getPublishList(cms),
106                    report);
107            }
108
109            // change lock for the resources if necessary
110            Iterator<String> iter = cms.readProjectResources(project).iterator();
111            while (iter.hasNext()) {
112                String resource = iter.next();
113                // get current lock from file
114                CmsLock lock = cms.getLock(resource);
115                // prove is current lock from current but not in current project
116                if ((lock != null)
117                    && lock.isInProject(cms.getRequestContext().getCurrentProject())
118                    && !lock.isOwnedBy(cms.getRequestContext().getCurrentUser())) {
119                    // file is locked in current project but not by current user
120                    // unlock this file
121                    cms.changeLock(resource);
122                }
123            }
124
125            // publish the project, the publish output will be put in the logfile
126            OpenCms.getPublishManager().publishProject(cms, report);
127            OpenCms.getPublishManager().waitWhileRunning();
128            finishMessage = Messages.get().getBundle().key(Messages.LOG_PUBLISH_FINISHED_1, project.getName());
129
130            // resources that have not been themselves published, but have been locked by the scheduled publish dialog
131            String unlockList = parameters.get(PARAM_UNLOCK_LIST);
132            if (unlockList != null) {
133                for (String idStr : unlockList.split(",")) {
134                    try {
135                        CmsResource resource = cms.readResource(
136                            new CmsUUID(idStr),
137                            CmsResourceFilter.IGNORE_EXPIRATION);
138                        CmsLock lock = cms.getLock(resource);
139                        if (!lock.isUnlocked()) {
140                            cms.unlockResource(resource);
141                        }
142                    } catch (Exception e) {
143                        LOG.debug(e.getLocalizedMessage(), e);
144                    }
145                }
146            }
147        } catch (CmsException e) {
148            // there was an error, so create an output for the logfile
149            finishMessage = Messages.get().getBundle().key(
150                Messages.LOG_PUBLISH_FAILED_2,
151                project.getName(),
152                e.getMessageContainer().key());
153
154            // add error to report
155            report.addError(finishMessage);
156        } finally {
157            //wait for other processes that may add entries to the report
158            long lastTime = report.getLastEntryTime();
159            long beforeLastTime = 0;
160            while (lastTime != beforeLastTime) {
161                wait(30000);
162                beforeLastTime = lastTime;
163                lastTime = report.getLastEntryTime();
164            }
165
166            // delete the job
167            // the job id
168            String jobId = "";
169            // iterate over all jobs to find the current one
170            Iterator<CmsScheduledJobInfo> iter = OpenCms.getScheduleManager().getJobs().iterator();
171            while (iter.hasNext()) {
172                CmsScheduledJobInfo jobInfo = iter.next();
173                // the current job is found with the job name
174                if (jobInfo.getJobName().equals(jobName)) {
175                    // get the current job id
176                    jobId = jobInfo.getId();
177                }
178            }
179            // delete the current job
180            OpenCms.getScheduleManager().unscheduleJob(cms, jobId);
181
182            // send publish notification
183            if (report.hasWarning() || report.hasError()) {
184                try {
185                    String userName = parameters.get(PARAM_USER);
186                    CmsUser user = cms.readUser(userName);
187
188                    CmsPublishNotification notification = new CmsPublishNotification(cms, user, report);
189
190                    DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
191                    notification.addMacro("jobStart", df.format(jobStart));
192
193                    notification.send();
194                } catch (Exception e) {
195                    LOG.error(Messages.get().getBundle().key(Messages.LOG_PUBLISH_SEND_NOTIFICATION_FAILED_0), e);
196                }
197            }
198        }
199
200        return finishMessage;
201    }
202}