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.apps.linkvalidation;
029
030import org.opencms.file.CmsObject;
031import org.opencms.file.CmsResource;
032import org.opencms.main.CmsException;
033import org.opencms.main.CmsLog;
034import org.opencms.main.OpenCms;
035import org.opencms.ui.A_CmsUI;
036import org.opencms.ui.CmsVaadinUtils;
037import org.opencms.ui.FontOpenCms;
038import org.opencms.ui.apps.A_CmsWorkplaceApp;
039import org.opencms.ui.apps.CmsFileExplorer;
040import org.opencms.ui.apps.Messages;
041import org.opencms.ui.components.CmsBasicDialog;
042import org.opencms.ui.components.CmsBasicDialog.DialogWidth;
043import org.opencms.ui.components.CmsFileTable;
044import org.opencms.ui.components.CmsResourceTableProperty;
045import org.opencms.ui.components.CmsToolBar;
046import org.opencms.ui.dialogs.CmsDeleteDialog;
047import org.opencms.util.CmsStringUtil;
048import org.opencms.util.CmsUUID;
049
050import java.util.ArrayList;
051import java.util.Collections;
052import java.util.LinkedHashMap;
053import java.util.List;
054import java.util.Map;
055
056import org.apache.commons.logging.Log;
057
058import com.google.common.collect.Multimap;
059import com.vaadin.server.Sizeable.Unit;
060import com.vaadin.shared.MouseEventDetails.MouseButton;
061import com.vaadin.ui.Button;
062import com.vaadin.ui.Button.ClickEvent;
063import com.vaadin.ui.Button.ClickListener;
064import com.vaadin.ui.Component;
065import com.vaadin.ui.HorizontalSplitPanel;
066import com.vaadin.ui.Window;
067import com.vaadin.v7.event.ItemClickEvent;
068import com.vaadin.v7.event.ItemClickEvent.ItemClickListener;
069import com.vaadin.v7.ui.VerticalLayout;
070
071/**
072 * App to check relations of resources in folder to other folder.<p>
073 */
074public class CmsLinkInFolderValidationApp extends A_CmsWorkplaceApp implements I_CmsUpdatableComponent {
075
076    /**
077     * Validator.<p>
078     */
079    public class InFolderValidator extends A_CmsLinkValidator {
080
081        /**Resource which would be broken, if considered resoures would be deleted. */
082        Multimap<CmsResource, CmsResource> brokenResources;
083
084        /**
085         * @see org.opencms.ui.apps.linkvalidation.A_CmsLinkValidator#failedResources(java.util.List)
086         */
087        @Override
088        public List<CmsResource> failedResources(List<String> resources) {
089
090            try {
091                CmsObject cms = OpenCms.initCmsObject(A_CmsUI.getCmsObject());
092                cms.getRequestContext().setSiteRoot("");
093                List<CmsResource> res = new ArrayList<CmsResource>();
094                for (String resource : resources) {
095                    if (cms.existsResource(resource)) {
096                        res.add(cms.readResource(resource));
097                    }
098                }
099
100                brokenResources = CmsDeleteDialog.getBrokenLinks(
101                    cms,
102                    res,
103                    false,
104                    CmsVaadinUtils.isButtonPressed(m_revertButton));
105                return new ArrayList<CmsResource>(brokenResources.keySet());
106            } catch (CmsException e) {
107                return new ArrayList<CmsResource>();
108            }
109        }
110
111        /**
112         * @see org.opencms.ui.apps.linkvalidation.A_CmsLinkValidator#failMessage(org.opencms.file.CmsResource)
113         */
114        @Override
115        public String failMessage(CmsResource resource) {
116
117            if (brokenResources.size() == 0) {
118                return "";
119            }
120            return brokenResources.get(resource).iterator().next().getRootPath();
121        }
122
123        /**
124         * @see org.opencms.ui.apps.linkvalidation.A_CmsLinkValidator#getClickListener()
125         */
126        @Override
127        public ItemClickListener getClickListener() {
128
129            return new ItemClickListener() {
130
131                private static final long serialVersionUID = -7729459896374968941L;
132
133                public void itemClick(ItemClickEvent event) {
134
135                    if (event.getButton().equals(MouseButton.RIGHT)) {
136                        return;
137                    }
138                    if (!property.equals(event.getPropertyId())) {
139                        return;
140                    }
141                    try {
142                        CmsObject cms = OpenCms.initCmsObject(A_CmsUI.getCmsObject());
143                        cms.getRequestContext().setSiteRoot("");
144                        CmsResource resource = cms.readResource(new CmsUUID((String)event.getItemId()));
145                        Window window = CmsBasicDialog.prepareWindow(DialogWidth.wide);
146                        window.setCaption(CmsVaadinUtils.getMessageText(getCaptionKey()));
147                        window.setContent(
148                            new CmsResourceListDialog(new ArrayList<CmsResource>(brokenResources.get(resource))));
149                        A_CmsUI.get().addWindow(window);
150                    } catch (CmsException e) {
151                        LOG.error("Unable to show detail resources", e);
152                    }
153                }
154
155            };
156        }
157
158        /**
159         * @see org.opencms.ui.apps.linkvalidation.A_CmsLinkValidator#getPropertyName()
160         */
161        @Override
162        public String getPropertyName() {
163
164            return "Relations";
165        }
166
167        /**
168         * @see org.opencms.ui.apps.linkvalidation.A_CmsLinkValidator#getTableProperties()
169         */
170        @Override
171        public Map<CmsResourceTableProperty, Integer> getTableProperties() {
172
173            property = new CmsResourceTableProperty(getPropertyName(), String.class, "", getCaptionKey(), true, 0, 200);
174            Map<CmsResourceTableProperty, Integer> res = new LinkedHashMap<CmsResourceTableProperty, Integer>(
175                CmsFileTable.DEFAULT_TABLE_PROPERTIES);
176            res.put(property, Integer.valueOf(0));
177            return res;
178        }
179
180        /**
181         * Returns the caption key.<p>
182         *
183         * @return key for caption
184         */
185        String getCaptionKey() {
186
187            return org.opencms.ui.apps.Messages.GUI_LINKVALIDATION_CHECK_FOLDER_RELATIONS_COLUMN_HEADER_0;
188        }
189
190    }
191
192    /**
193     * Bean for the state of the app.<p>
194     */
195    static class CmsStateBean {
196
197        /**State seperator. */
198        protected static String STATE_SEPERATOR = A_CmsWorkplaceApp.PARAM_SEPARATOR;
199
200        /**Seperator for resources in state. */
201        private static String RESOURCE_SEPERATOR = ";";
202
203        /**List of resources. */
204        private List<String> m_resources;
205
206        /**Reverse the output? */
207        private boolean m_reverse;
208
209        /**CmsObject */
210        private CmsObject m_cms = null;
211
212        /**
213         * public constructor.<p>
214         *
215         * @param resources List of resources (Root-paths)
216         * @param reverse boolean
217         *
218         */
219        public CmsStateBean(List<String> resources, boolean reverse) {
220
221            setCmsObject();
222
223            m_resources = resources;
224            m_reverse = reverse;
225        }
226
227        /**
228         * public constructor.<p>
229         *
230         * @param resources Resources as state string
231         * @param reverse boolean
232         */
233        public CmsStateBean(String resources, boolean reverse) {
234
235            setCmsObject();
236            m_resources = getResourcesFromState(resources);
237            m_reverse = reverse;
238        }
239
240        /**
241         * Parses a given state string to state bean.<p>
242         *
243         * @param state to be read
244         * @return CmsStateBean
245         */
246        public static CmsStateBean parseState(String state) {
247
248            if (CmsStringUtil.isEmptyOrWhitespaceOnly(state)) {
249                return new CmsStateBean(Collections.emptyList(), false);
250            }
251            String[] parameter = state.split(STATE_SEPERATOR);
252            boolean reverse = false;
253            if (parameter.length > 1) {
254                reverse = Boolean.parseBoolean(parameter[1]);
255            }
256            return new CmsStateBean(parameter[0], reverse);
257        }
258
259        /**
260         * Get the resource list.<p>
261         *
262         * @return List of resource root paths
263         */
264        public List<String> getResources() {
265
266            return m_resources;
267        }
268
269        /**
270         * Gets the state string of the current bean.<p>
271         *
272         * @return state string
273         */
274        public String getState() {
275
276            return getResourceString() + STATE_SEPERATOR + Boolean.valueOf(m_reverse).toString();
277
278        }
279
280        /**
281         * Is reverse mode selected?
282         *
283         * @return boolean
284         */
285        public boolean isReverse() {
286
287            return m_reverse;
288        }
289
290        /**
291         * Gets resources from state string.<p>
292         *
293         * @param resources state string
294         * @return List of resource paths
295         */
296        private List<String> getResourcesFromState(String resources) {
297
298            if (CmsStringUtil.isEmptyOrWhitespaceOnly(resources)) {
299                return Collections.EMPTY_LIST;
300            }
301            List<String> res = new ArrayList<String>();
302
303            for (String uuidString : resources.split(RESOURCE_SEPERATOR)) {
304                try {
305                    res.add(m_cms.readResource(new CmsUUID(uuidString)).getRootPath());
306                } catch (CmsException e) {
307                    LOG.error("Can not read resource from state", e);
308                }
309            }
310            return res;
311        }
312
313        /**
314         * Get the state string of the resources.<p>
315         *
316         * @return resources as string to use in state
317         */
318        private String getResourceString() {
319
320            String res = "";
321            try {
322
323                for (String resource : m_resources) {
324                    res += m_cms.readResource(resource).getStructureId().getStringValue() + RESOURCE_SEPERATOR;
325                }
326
327            } catch (CmsException e) {
328                LOG.error("Can't read resource", e);
329            }
330            return res.length() > 1 ? res.substring(0, res.length() - 1) : res;
331        }
332
333        /**
334         * Prepares the CmsObject.<p>
335         */
336        private void setCmsObject() {
337
338            if (m_cms == null) {
339                try {
340                    m_cms = OpenCms.initCmsObject(A_CmsUI.getCmsObject());
341                    m_cms.getRequestContext().setSiteRoot("");
342                } catch (CmsException e) {
343                    m_cms = A_CmsUI.getCmsObject();
344                }
345            }
346        }
347    }
348
349    /** The log object for this class. */
350    static final Log LOG = CmsLog.getLog(CmsLinkInFolderValidationApp.class);
351
352    /**Bean for the state status. */
353    private CmsStateBean m_stateBean;
354
355    /**Vaadin component. */
356    Button m_revertButton;
357
358    /**Table */
359    private CmsLinkValidationInternalTable m_table;
360
361    /**Resource Selector. */
362    private CmsInternalResources m_resourceSelector;
363
364    /**
365     * @see org.opencms.ui.apps.linkvalidation.I_CmsUpdatableComponent#update(java.util.List)
366     */
367    public void update(List<String> resources) {
368
369        openSubView(new CmsStateBean(resources, CmsVaadinUtils.isButtonPressed(m_revertButton)).getState(), true);
370
371    }
372
373    /**
374     * @see org.opencms.ui.apps.A_CmsWorkplaceApp#getBreadCrumbForState(java.lang.String)
375     */
376    @Override
377    protected LinkedHashMap<String, String> getBreadCrumbForState(String state) {
378
379        return null;
380    }
381
382    /**
383     * @see org.opencms.ui.apps.A_CmsWorkplaceApp#getComponentForState(java.lang.String)
384     */
385    @Override
386    protected Component getComponentForState(String state) {
387
388        m_stateBean = CmsStateBean.parseState(state);
389        if (m_revertButton == null) {
390            addToolbars();
391        }
392
393        m_rootLayout.setMainHeightFull(true);
394        HorizontalSplitPanel panel = new HorizontalSplitPanel();
395        VerticalLayout result = new VerticalLayout();
396        result.setSizeFull();
397        VerticalLayout intro = CmsVaadinUtils.getInfoLayout(Messages.GUI_LINKVALIDATION_CHECK_FOLDER_RELATIONS_INTRO_0);
398        VerticalLayout nullResult = CmsVaadinUtils.getInfoLayout(
399            Messages.GUI_LINKVALIDATION_CHECK_FOLDER_RELATIONS_NO_RESULT_0);
400
401        nullResult.setVisible(false);
402        m_table = new CmsLinkValidationInternalTable(intro, nullResult, new InFolderValidator());
403        m_table.setVisible(false);
404        m_table.setSizeFull();
405        m_table.setWidth("100%");
406
407        result.addComponent(m_table);
408        result.addComponent(intro);
409        result.addComponent(nullResult);
410
411        m_table.setVisible(false);
412        m_table.setSizeFull();
413        m_table.setWidth("100%");
414        m_resourceSelector = new CmsInternalResources(this);
415        panel.setFirstComponent(m_resourceSelector);
416        panel.setSecondComponent(result);
417
418        panel.setSplitPosition(CmsFileExplorer.LAYOUT_SPLIT_POSITION, Unit.PIXELS);
419
420        if (!m_stateBean.getResources().isEmpty()) {
421            m_table.update(m_stateBean.getResources());
422            m_resourceSelector.clearResources();
423            for (String resource : m_stateBean.getResources()) {
424                m_resourceSelector.addResource(resource);
425            }
426        }
427
428        return panel;
429    }
430
431    /**
432     * @see org.opencms.ui.apps.A_CmsWorkplaceApp#getSubNavEntries(java.lang.String)
433     */
434    @Override
435    protected List<NavEntry> getSubNavEntries(String state) {
436
437        return null;
438    }
439
440    /**
441     * Toggle table.<p>
442     */
443    protected void toggleTable() {
444
445        CmsVaadinUtils.toggleButton(m_revertButton);
446        openSubView(
447            new CmsStateBean(m_stateBean.getResources(), CmsVaadinUtils.isButtonPressed(m_revertButton)).getState(),
448            true);
449    }
450
451    /**
452     * Add toolbar icons.<p>
453     */
454    private void addToolbars() {
455
456        m_revertButton = CmsToolBar.createButton(
457            FontOpenCms.REDO,
458            CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_GROUPS_TOGGLE_0));
459        m_revertButton.addClickListener(new ClickListener() {
460
461            private static final long serialVersionUID = 8265075332953321274L;
462
463            public void buttonClick(ClickEvent event) {
464
465                toggleTable();
466
467            }
468
469        });
470        if (m_stateBean.isReverse()) {
471            CmsVaadinUtils.toggleButton(m_revertButton);
472        }
473        m_uiContext.addToolbarButton(m_revertButton);
474    }
475}