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, 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.ui.dialogs;
029
030import org.opencms.file.CmsFile;
031import org.opencms.file.CmsObject;
032import org.opencms.file.CmsResource;
033import org.opencms.file.CmsResourceFilter;
034import org.opencms.lock.CmsLockActionRecord;
035import org.opencms.lock.CmsLockActionRecord.LockChange;
036import org.opencms.lock.CmsLockException;
037import org.opencms.lock.CmsLockUtil;
038import org.opencms.main.CmsException;
039import org.opencms.main.CmsLog;
040import org.opencms.main.OpenCms;
041import org.opencms.ui.A_CmsUI;
042import org.opencms.ui.CmsVaadinUtils;
043import org.opencms.ui.I_CmsDialogContext;
044import org.opencms.ui.components.CmsBasicDialog;
045import org.opencms.ui.components.CmsDateField;
046import org.opencms.ui.components.CmsOkCancelActionHandler;
047import org.opencms.util.CmsUUID;
048import org.opencms.xml.content.CmsXmlContent;
049
050import java.time.LocalDateTime;
051import java.util.ArrayList;
052import java.util.Date;
053import java.util.Iterator;
054import java.util.List;
055
056import org.apache.commons.logging.Log;
057
058import com.google.common.collect.Lists;
059import com.vaadin.ui.Button;
060import com.vaadin.ui.Button.ClickEvent;
061import com.vaadin.ui.Button.ClickListener;
062import com.vaadin.ui.CheckBox;
063
064/**
065 * Dialog used to change resource modification times.<p>
066 */
067public class CmsTouchDialog extends CmsBasicDialog {
068
069    /** Logger for this class. */
070    private static final Log LOG = CmsLog.getLog(CmsTouchDialog.class);
071
072    /** Serial version id. */
073    private static final long serialVersionUID = 1L;
074
075    /** The dialog context. */
076    protected I_CmsDialogContext m_context;
077
078    /** The Cancel button. */
079    private Button m_cancelButton;
080
081    /** The date selection field. */
082    private CmsDateField m_dateField;
083
084    /** Check box to enable/disable modification of children. */
085    private CheckBox m_modifySubresourcesField;
086
087    /** The OK  button. */
088    private Button m_okButton;
089
090    /** Checkbox to enable/disable rewriting of contents. */
091    private CheckBox m_rewriteContentField;
092
093    /**
094     * Creates a new instance.<p>
095     *
096     * @param context the dialog context
097     */
098    public CmsTouchDialog(I_CmsDialogContext context) {
099
100        m_context = context;
101        boolean hasFolders = false;
102
103        for (CmsResource resource : context.getResources()) {
104            if (resource.isFolder()) {
105                hasFolders = true;
106                break;
107            }
108        }
109
110        CmsVaadinUtils.readAndLocalizeDesign(
111            this,
112            OpenCms.getWorkplaceManager().getMessages(A_CmsUI.get().getLocale()),
113            null);
114        m_modifySubresourcesField.setVisible(hasFolders);
115
116        m_cancelButton.addClickListener(new ClickListener() {
117
118            private static final long serialVersionUID = 1L;
119
120            public void buttonClick(ClickEvent event) {
121
122                cancel();
123            }
124
125        });
126
127        m_okButton.addClickListener(new ClickListener() {
128
129            private static final long serialVersionUID = 1L;
130
131            public void buttonClick(ClickEvent event) {
132
133                submit();
134            }
135        });
136        m_dateField.setValue(LocalDateTime.now());
137        displayResourceInfo(m_context.getResources());
138        setActionHandler(new CmsOkCancelActionHandler() {
139
140            private static final long serialVersionUID = 1L;
141
142            @Override
143            protected void cancel() {
144
145                CmsTouchDialog.this.cancel();
146            }
147
148            @Override
149            protected void ok() {
150
151                submit();
152            }
153        });
154    }
155
156    /**
157     * Touches the selected files.<p>
158     *
159     * @throws CmsException if something goes wrong
160     */
161    protected void touchFiles() throws CmsException {
162
163        Date touchDate = m_dateField.getDate();
164        boolean validDate = touchDate != null;
165        long touchTime = touchDate != null ? touchDate.getTime() : 0;
166        boolean recursive = m_modifySubresourcesField.getValue().booleanValue();
167        boolean rewriteContent = m_rewriteContentField.getValue().booleanValue();
168        List<CmsUUID> changedIds = Lists.newArrayList();
169        for (CmsResource resource : m_context.getResources()) {
170            CmsLockActionRecord actionRecord = null;
171            try {
172                actionRecord = CmsLockUtil.ensureLock(m_context.getCms(), resource);
173                touchSingleResource(
174                    m_context.getCms().getSitePath(resource),
175                    touchTime,
176                    recursive,
177                    validDate,
178                    rewriteContent);
179                changedIds.add(resource.getStructureId());
180            } finally {
181                if ((actionRecord != null) && (actionRecord.getChange() == LockChange.locked)) {
182                    try {
183                        m_context.getCms().unlockResource(resource);
184                    } catch (CmsLockException e) {
185                        LOG.warn(e.getLocalizedMessage(), e);
186                    }
187                }
188
189            }
190
191        }
192        m_context.finish(changedIds);
193
194    }
195
196    /**
197     * Cancels the dialog.<p>
198     */
199    void cancel() {
200
201        m_context.finish(new ArrayList<CmsUUID>());
202    }
203
204    /**
205     * Submits the dialog.<p>
206     */
207    void submit() {
208
209        try {
210            touchFiles();
211        } catch (Exception e) {
212            m_context.error(e);
213        }
214    }
215
216    /**
217     * Rewrites the content of the given file.<p>
218     *
219     * @param resource the resource to rewrite the content for
220     *
221     * @throws CmsException if something goes wrong
222     */
223    private void hardTouch(CmsResource resource) throws CmsException {
224
225        CmsFile file = m_context.getCms().readFile(resource);
226        CmsObject cms = OpenCms.initCmsObject(m_context.getCms());
227        cms.getRequestContext().setAttribute(CmsXmlContent.AUTO_CORRECTION_ATTRIBUTE, Boolean.TRUE);
228        file.setContents(file.getContents());
229        cms.writeFile(file);
230    }
231
232    /**
233     * Performs a touch operation for a single resource.<p>
234     *
235     * @param resourceName the resource name of the resource to touch
236     * @param timeStamp the new time stamp
237     * @param recursive the flag if the touch operation is recursive
238     * @param correctDate the flag if the new time stamp is a correct date
239     * @param touchContent if the content has to be rewritten
240     *
241     * @throws CmsException if touching the resource fails
242     */
243    private void touchSingleResource(
244        String resourceName,
245        long timeStamp,
246        boolean recursive,
247        boolean correctDate,
248        boolean touchContent)
249    throws CmsException {
250
251        CmsObject cms = m_context.getCms();
252        CmsResource sourceRes = cms.readResource(resourceName, CmsResourceFilter.ALL);
253        if (!correctDate) {
254            // no date value entered, use current resource modification date
255            timeStamp = sourceRes.getDateLastModified();
256        }
257
258        if (touchContent) {
259            if (sourceRes.isFile()) {
260                hardTouch(sourceRes);
261            } else if (recursive) {
262                Iterator<CmsResource> it = cms.readResources(resourceName, CmsResourceFilter.ALL, true).iterator();
263                while (it.hasNext()) {
264                    CmsResource subRes = it.next();
265                    if (subRes.isFile()) {
266                        hardTouch(subRes);
267                    }
268                }
269            }
270        }
271
272        cms.setDateLastModified(resourceName, timeStamp, recursive);
273
274    }
275}