001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (C) Alkacon Software (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.ade.sitemap.client.alias;
029
030import org.opencms.ade.sitemap.client.CmsSitemapView;
031import org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapServiceAsync;
032import org.opencms.gwt.client.CmsCoreProvider;
033import org.opencms.gwt.client.rpc.CmsRpcAction;
034import org.opencms.gwt.client.ui.CmsAlertDialog;
035import org.opencms.gwt.client.util.CmsClientStringUtil;
036import org.opencms.gwt.client.util.CmsDomUtil;
037import org.opencms.gwt.shared.alias.CmsAliasEditValidationReply;
038import org.opencms.gwt.shared.alias.CmsAliasEditValidationRequest;
039import org.opencms.gwt.shared.alias.CmsAliasInitialFetchResult;
040import org.opencms.gwt.shared.alias.CmsAliasMode;
041import org.opencms.gwt.shared.alias.CmsAliasSaveValidationRequest;
042import org.opencms.gwt.shared.alias.CmsAliasTableRow;
043import org.opencms.gwt.shared.alias.CmsRewriteAliasTableRow;
044import org.opencms.gwt.shared.alias.CmsRewriteAliasValidationReply;
045import org.opencms.gwt.shared.alias.CmsRewriteAliasValidationRequest;
046import org.opencms.util.CmsUUID;
047
048import java.util.ArrayList;
049import java.util.HashSet;
050import java.util.List;
051import java.util.Set;
052
053/**
054 * This is the controller class for the alias editor which is responsible for reacting to edit operations on the client
055 * by triggering the corresponding validation or save actions on the server.<p>
056 */
057public class CmsAliasTableController {
058
059    /** The set of ids of deleted rows. */
060    protected Set<CmsUUID> m_deletedIds = new HashSet<CmsUUID>();
061
062    /** The view. */
063    protected CmsAliasView m_view;
064
065    /** The URL from which the list of aliases can be downloaded. */
066    String m_downloadUrl;
067
068    /** The initial data loaded from the server. */
069    List<CmsAliasTableRow> m_initialData;
070
071    /** The site root. */
072    String m_siteRoot;
073
074    /**
075     * Gets the service to use for validating/saving aliases.<p>
076     *
077     * @return the service used for validating/saving aliases
078     */
079    protected static I_CmsSitemapServiceAsync getService() {
080
081        return CmsSitemapView.getInstance().getController().getService();
082    }
083
084    /**
085     * Method which should be called when the selection of the rewrite table has been changed.<p>
086     *
087     * @param selectedSet the set of selected rewrite table entries
088     */
089    public void changeRewriteSelection(Set<CmsRewriteAliasTableRow> selectedSet) {
090
091        boolean selectionEmpty = selectedSet.isEmpty();
092        m_view.setRewriteDeleteButtonEnabled(!selectionEmpty);
093
094    }
095
096    /**
097     * This method is called when the selection of the alias table changes.<p>
098     *
099     * @param selectedSet the set of selected rows
100     */
101    public void changeSelection(Set<CmsAliasTableRow> selectedSet) {
102
103        boolean selectionEmpty = selectedSet.isEmpty();
104        m_view.setDeleteButtonEnabled(!selectionEmpty);
105    }
106
107    /**
108     * This method is called when the user wants to delete rewrites aliases.<p>
109     *
110     * @param rowsToDelete the rows the user wants to delete
111     */
112    public void deleteRewrites(List<CmsRewriteAliasTableRow> rowsToDelete) {
113
114        List<CmsRewriteAliasTableRow> liveData = m_view.getRewriteData();
115        liveData.removeAll(rowsToDelete);
116        m_view.getRewriteTable().getSelectionModel().clear();
117        updateValidationStatus();
118    }
119
120    /**
121     * This method is called when the user deletes a set of rows.<p>
122     *
123     * @param rowsToDelete the list of rows which should be deleted
124     */
125    public void deleteRows(List<CmsAliasTableRow> rowsToDelete) {
126
127        List<CmsAliasTableRow> liveData = m_view.getLiveData();
128        for (CmsAliasTableRow row : liveData) {
129            CmsUUID structureId = row.getStructureId();
130            if (structureId != null) {
131                m_deletedIds.add(row.getStructureId());
132            }
133        }
134        // prevent selection model from going out of synch
135        m_view.getTable().getSelectionModel().clear();
136        liveData.removeAll(rowsToDelete);
137        updateValidationStatus();
138    }
139
140    /**
141     * Triggers the download of the current aliases.<p>
142     */
143    public void download() {
144
145        CmsDomUtil.openWindow(m_downloadUrl + "?site=" + m_siteRoot, "_blank", "");
146    }
147
148    /**
149     * This method is called after the mode of an alias has been edited.<p>
150     *
151     * @param row the edited row
152     * @param mode the new alias mode
153     */
154    public void editAliasMode(CmsAliasTableRow row, CmsAliasMode mode) {
155
156        row.setMode(mode);
157        row.setEdited(true);
158    }
159
160    /**
161     * This method is called after the alias path of an alias has been edited.<p>
162     *
163     * @param row the edited row
164     * @param path the new alias path
165     */
166    public void editAliasPath(CmsAliasTableRow row, String path) {
167
168        row.editAliasPath(path);
169        row.setEdited(true);
170        validate();
171
172    }
173
174    /**
175     * This method is called when the user wants to add a new alias entry.<p>
176     *
177     * @param aliasPath the alias path
178     * @param resourcePath the resource site path
179     * @param mode the alias mode
180     */
181    public void editNewAlias(String aliasPath, String resourcePath, CmsAliasMode mode) {
182
183        CmsAliasTableRow row = new CmsAliasTableRow();
184        row.setEdited(true);
185        row.setAliasPath(aliasPath);
186        row.setResourcePath(resourcePath);
187        row.setMode(mode);
188        validateNew(row);
189    }
190
191    /**
192     * This method is called when the user adds a new rewrite alias.<p>
193     *
194     * @param rewriteRegex the rewrite pattern
195     * @param rewriteReplacement the rewrite replacement string
196     *
197     * @param mode the rewrite mode
198     */
199    public void editNewRewrite(String rewriteRegex, String rewriteReplacement, CmsAliasMode mode) {
200
201        CmsRewriteAliasTableRow row = new CmsRewriteAliasTableRow(
202            new CmsUUID(CmsClientStringUtil.randomUUID()),
203            rewriteRegex,
204            rewriteReplacement,
205            mode);
206        m_view.clearRewriteNew();
207        m_view.getRewriteData().add(0, row);
208        validateRewrite();
209    }
210
211    /**
212     * This method is called when the user has edited the resource path of an alias.<p>
213     *
214     * @param row the alias the table row
215     * @param path the new path
216     */
217    public void editResourcePath(CmsAliasTableRow row, String path) {
218
219        row.setEdited(true);
220        row.editResourcePath(path);
221        validate();
222    }
223
224    /**
225     * This method is called when the user has edited a rewrite alias.<p>
226     *
227     * @param object the edited rewrite alias
228     */
229    public void editRewriteAlias(CmsRewriteAliasTableRow object) {
230
231        validateRewrite();
232    }
233
234    /**
235     * Loads the initial data from the server.<p>
236     *
237     * @param afterLoad the action that should be executed after loading
238     */
239    public void load(final Runnable afterLoad) {
240
241        CmsRpcAction<CmsAliasInitialFetchResult> action = new CmsRpcAction<CmsAliasInitialFetchResult>() {
242
243            /**
244             * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute()
245             */
246            @Override
247            public void execute() {
248
249                getService().getAliasTable(this);
250                start(0, true);
251            }
252
253            /**
254             * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object)
255             */
256            @Override
257            public void onResponse(CmsAliasInitialFetchResult aliasTable) {
258
259                stop(false);
260
261                String lockOwner = aliasTable.getAliasTableLockOwner();
262                if (lockOwner != null) {
263
264                    String errorMessage = CmsAliasMessages.messageAliasTableLocked(lockOwner);
265                    String title = CmsAliasMessages.messageAliasTableLockedTitle();
266                    CmsAlertDialog alert = new CmsAlertDialog(title, errorMessage);
267                    alert.center();
268                } else {
269
270                    m_downloadUrl = aliasTable.getDownloadUrl();
271                    m_initialData = aliasTable.getRows();
272                    m_siteRoot = CmsCoreProvider.get().getSiteRoot();
273                    List<CmsAliasTableRow> copiedData = copyData(m_initialData);
274                    List<CmsRewriteAliasTableRow> rewriteData = aliasTable.getRewriteAliases();
275                    m_view.setData(copiedData, rewriteData);
276                    if (afterLoad != null) {
277                        afterLoad.run();
278                    }
279                }
280            }
281        };
282        action.execute();
283    }
284
285    /**
286     * This method is called when the user wants to save the aliases.<p>
287     */
288    public void save() {
289
290        CmsRpcAction<CmsAliasEditValidationReply> action = new CmsRpcAction<CmsAliasEditValidationReply>() {
291
292            @Override
293            public void execute() {
294
295                start(200, false);
296
297                CmsAliasSaveValidationRequest saveRequest = new CmsAliasSaveValidationRequest();
298                saveRequest.setSiteRoot(m_siteRoot);
299                List<CmsAliasTableRow> rows = m_view.getLiveData();
300                saveRequest.setEditedData(rows);
301                saveRequest.setRewriteData(m_view.getRewriteData());
302                saveRequest.getDeletedIds().addAll(m_deletedIds);
303                saveRequest.setOriginalData(m_initialData);
304                getService().saveAliases(saveRequest, this);
305            }
306
307            @Override
308            public void onResponse(CmsAliasEditValidationReply result) {
309
310                stop(false);
311                if (result == null) {
312                    m_view.close();
313                } else if (result.hasErrors()) {
314                    m_view.update(result.getChangedRows());
315                }
316            }
317        };
318        action.execute();
319    }
320
321    /**
322     * Sets the alias editor view.<p>
323     *
324     * @param view the view object
325     */
326    public void setView(CmsAliasView view) {
327
328        m_view = view;
329    }
330
331    /**
332     * Enables or disables the save button of the view depending on whether there are validation errors.<p>
333     */
334    protected void updateValidationStatus() {
335
336        boolean hasErrors = false;
337        for (CmsAliasTableRow row : m_view.getLiveData()) {
338            hasErrors |= row.hasErrors();
339        }
340        for (CmsRewriteAliasTableRow row : m_view.getRewriteData()) {
341            hasErrors |= (row.getError() != null);
342        }
343
344        m_view.setSaveButtonEnabled(!hasErrors);
345        if (hasErrors) {
346            m_view.sortByErrors();
347        }
348    }
349
350    /**
351     * Triggers server-side validatiom of the alias table.<p>
352     */
353    protected void validate() {
354
355        CmsRpcAction<CmsAliasEditValidationReply> action = new CmsRpcAction<CmsAliasEditValidationReply>() {
356
357            @Override
358            public void execute() {
359
360                CmsAliasEditValidationRequest validationRequest = new CmsAliasEditValidationRequest();
361
362                List<CmsAliasTableRow> rows = m_view.getLiveData();
363                validationRequest.setEditedData(rows);
364                validationRequest.setOriginalData(m_initialData);
365                getService().validateAliases(validationRequest, this);
366            }
367
368            @Override
369            public void onResponse(CmsAliasEditValidationReply result) {
370
371                stop(false);
372                List<CmsAliasTableRow> changedRows = result.getChangedRows();
373                m_view.update(changedRows);
374                updateValidationStatus();
375            }
376
377        };
378        action.execute();
379    }
380
381    /**
382     * Triggers server-side validation of the alias table and of a new entry which should be added to it.<p>
383     *
384     * @param newEntry the new entry
385     */
386    protected void validateNew(final CmsAliasTableRow newEntry) {
387
388        CmsRpcAction<CmsAliasEditValidationReply> action = new CmsRpcAction<CmsAliasEditValidationReply>() {
389
390            @Override
391            public void execute() {
392
393                start(200, true);
394                CmsAliasEditValidationRequest validationRequest = new CmsAliasEditValidationRequest();
395                List<CmsAliasTableRow> rows = m_view.getLiveData();
396                validationRequest.setEditedData(rows);
397                validationRequest.setNewEntry(newEntry);
398                validationRequest.setOriginalData(m_initialData);
399                getService().validateAliases(validationRequest, this);
400            }
401
402            @Override
403            public void onResponse(CmsAliasEditValidationReply result) {
404
405                stop(false);
406                List<CmsAliasTableRow> tableRows = result.getChangedRows();
407                CmsAliasTableRow validatedNewEntry = result.getValidatedNewEntry();
408                if (validatedNewEntry.hasErrors()) {
409                    m_view.setNewAliasPathError(validatedNewEntry.getAliasError());
410                    m_view.setNewAliasResourceError(validatedNewEntry.getPathError());
411                } else {
412                    m_view.clearNew();
413                    tableRows.add(validatedNewEntry);
414                }
415                m_view.update(tableRows);
416                updateValidationStatus();
417            }
418        };
419        action.execute();
420    }
421
422    /**
423     * Triggers server-side validation for the rewrite aliases.<p>
424     */
425    protected void validateRewrite() {
426
427        CmsRpcAction<CmsRewriteAliasValidationReply> action = new CmsRpcAction<CmsRewriteAliasValidationReply>() {
428
429            @Override
430            public void execute() {
431
432                start(200, true);
433                List<CmsRewriteAliasTableRow> rowsToValidate = new ArrayList<CmsRewriteAliasTableRow>();
434                rowsToValidate.addAll(m_view.getRewriteData());
435
436                CmsRewriteAliasValidationRequest request = new CmsRewriteAliasValidationRequest(rowsToValidate);
437                getService().validateRewriteAliases(request, this);
438            }
439
440            @Override
441            public void onResponse(CmsRewriteAliasValidationReply result) {
442
443                stop(false);
444                m_view.update(result);
445                updateValidationStatus();
446            }
447
448        };
449        action.execute();
450    }
451
452    /**
453     * Copies a list of rows.<p>
454     *
455     * @param data the original data
456     *
457     * @return the copied data
458     */
459    List<CmsAliasTableRow> copyData(List<CmsAliasTableRow> data) {
460
461        List<CmsAliasTableRow> result = new ArrayList<CmsAliasTableRow>();
462        for (CmsAliasTableRow row : data) {
463            CmsAliasTableRow copiedRow = row.copy();
464            result.add(copiedRow);
465        }
466        return result;
467    }
468
469}