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.search;
029
030import org.opencms.file.CmsObject;
031import org.opencms.file.CmsProject;
032import org.opencms.file.CmsPropertyDefinition;
033import org.opencms.file.CmsResource;
034import org.opencms.file.CmsResourceFilter;
035import org.opencms.file.types.CmsResourceTypeXmlContainerPage;
036import org.opencms.file.types.I_CmsResourceType;
037import org.opencms.loader.CmsLoaderException;
038import org.opencms.main.CmsException;
039import org.opencms.main.CmsLog;
040import org.opencms.main.OpenCms;
041import org.opencms.search.CmsSearchIndex;
042import org.opencms.search.I_CmsSearchIndex;
043import org.opencms.ui.A_CmsUI;
044import org.opencms.ui.CmsVaadinUtils;
045import org.opencms.ui.CmsVaadinUtils.PropertyId;
046import org.opencms.ui.apps.Messages;
047import org.opencms.ui.components.fileselect.CmsPathSelectField;
048import org.opencms.util.CmsStringUtil;
049import org.opencms.util.CmsUUID;
050
051import java.util.Collections;
052import java.util.Locale;
053
054import org.apache.commons.logging.Log;
055
056import com.vaadin.ui.Button;
057import com.vaadin.ui.Button.ClickEvent;
058import com.vaadin.ui.Button.ClickListener;
059import com.vaadin.v7.data.Property.ValueChangeEvent;
060import com.vaadin.v7.data.Property.ValueChangeListener;
061import com.vaadin.v7.data.util.IndexedContainer;
062import com.vaadin.v7.shared.ui.combobox.FilteringMode;
063import com.vaadin.v7.ui.CheckBox;
064import com.vaadin.v7.ui.ComboBox;
065import com.vaadin.v7.ui.TextField;
066import com.vaadin.v7.ui.VerticalLayout;
067
068/**
069 * The source search form.<p>
070 */
071public class CmsSourceSearchForm extends VerticalLayout {
072
073    /** The available search types. */
074    public static enum SearchType {
075        /** XML content values only. */
076        contentValues(false, true, false),
077        /** Full text search. */
078        fullText(false, false, false),
079        /** Filter using a solr index, before searching for matches. */
080        solr(true, false, false),
081        /** Filter using a solr index, before searching for matches, XML content values only. */
082        solrContentValues(true, true, false),
083
084        /** Property search. */
085        properties(false, false, true),
086        /** */
087        resourcetype(false, false, false),
088        /** */
089        renameContainer(false, false, false);
090
091        /** The content values only flag. */
092        private boolean m_contentValuesOnly;
093
094        /** The is solr search flag. */
095        private boolean m_solrSearch;
096
097        /** The property flag.*/
098        private boolean m_property;
099
100        /**
101         * Constructor.<p>
102         *
103         * @param solrSearch the is solr search flag
104         * @param contentValuesOnly the content values only flag
105         * @param property the property flag
106         */
107        private SearchType(boolean solrSearch, boolean contentValuesOnly, boolean property) {
108
109            m_solrSearch = solrSearch;
110            m_contentValuesOnly = contentValuesOnly;
111            m_property = property;
112        }
113
114        /**
115         * Returns whether this is a content values only search type.<p>
116         *
117         * @return <code>true</code> if this is a content values only search type
118         */
119        public boolean isContentValuesOnly() {
120
121            return m_contentValuesOnly;
122        }
123
124        /**
125         * Returns whether this is a property search type.<p>
126         *
127         * @return true if this is property search
128         *  */
129        public boolean isPropertySearch() {
130
131            return m_property;
132        }
133
134        /**
135         * Returns whether this is a SOLR search type.<p>
136         *
137         * @return <code>true</code> if this is a SOLR search type
138         */
139        public boolean isSolrSearch() {
140
141            return m_solrSearch;
142        }
143    }
144
145    /**Regex expression for finding all. */
146    public static final String REGEX_ALL = ".*";
147
148    /** The log object for this class. */
149    static final Log LOG = CmsLog.getLog(CmsSourceSearchForm.class);
150
151    /** The serial version id. */
152    private static final long serialVersionUID = 1023130318064811880L;
153
154    /** The source search app instance. */
155    private CmsSourceSearchApp m_app;
156
157    /** The search locale select. */
158    private ComboBox m_locale;
159
160    /** The replace check box. */
161    private CheckBox m_replace;
162
163    /** The replace pattern field. */
164    private TextField m_replacePattern;
165
166    /** The resource type select. */
167    private ComboBox m_resourceType;
168
169    /** The search button. */
170    private Button m_search;
171
172    /** Vaadin component.*/
173    private TextField m_oldName;
174
175    /** Vaadin component.*/
176    private TextField m_newName;
177
178    /** Check box to ignore subsites. */
179    private CheckBox m_ignoreSubSites;
180
181    /** The site select. */
182    private ComboBox m_siteSelect;
183
184    /** The search index select. */
185    private ComboBox m_searchIndex;
186
187    /** The search pattern field. */
188    private TextField m_searchPattern;
189
190    /** The search root path select. */
191    private CmsPathSelectField m_searchRoot;
192
193    /** The search root path select. */
194    private CmsPathSelectField m_replaceResource;
195
196    /** The search root path select. */
197    private CmsPathSelectField m_resourceSearch;
198
199    /** The search type select. */
200    private ComboBox m_searchType;
201
202    /** The property select.*/
203    private ComboBox m_property;
204
205    /** The SOLR query field. */
206    private TextField m_solrQuery;
207
208    /** The replace project. */
209    private ComboBox m_workProject;
210
211    /** The XPath field. */
212    private TextField m_xPath;
213
214    /**
215     * Constructor.<p>
216     *
217     * @param app the source search app instance
218     */
219    public CmsSourceSearchForm(CmsSourceSearchApp app) {
220
221        m_app = app;
222        CmsVaadinUtils.readAndLocalizeDesign(this, CmsVaadinUtils.getWpMessagesForCurrentLocale(), null);
223        initFields();
224        m_replace.addValueChangeListener(new ValueChangeListener() {
225
226            private static final long serialVersionUID = 1L;
227
228            public void valueChange(ValueChangeEvent event) {
229
230                updateReplace();
231            }
232        });
233        m_searchType.addValueChangeListener(new ValueChangeListener() {
234
235            private static final long serialVersionUID = 1L;
236
237            public void valueChange(ValueChangeEvent event) {
238
239                changedSearchType();
240            }
241        });
242        m_search.addClickListener(new ClickListener() {
243
244            private static final long serialVersionUID = 1L;
245
246            public void buttonClick(ClickEvent event) {
247
248                search();
249            }
250        });
251        updateReplace();
252        changedSearchType();
253    }
254
255    /**
256     * Initializes the form with the given settings.<p>
257     *
258     * @param settings the settings
259     */
260    public void initFormValues(CmsSearchReplaceSettings settings) {
261
262        m_siteSelect.setValue(settings.getSiteRoot());
263        m_ignoreSubSites.setValue(new Boolean(settings.ignoreSubSites()));
264        m_searchType.setValue(settings.getType());
265        if (!settings.getPaths().isEmpty()) {
266            m_searchRoot.setValue(settings.getPaths().get(0));
267        }
268        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(settings.getTypes())) {
269            try {
270                I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(settings.getTypes());
271                m_resourceType.setValue(type);
272            } catch (CmsLoaderException e) {
273                // nothing to do, skip setting the type
274            }
275        }
276        m_searchPattern.setValue(settings.getSearchpattern());
277        m_ignoreSubSites.setValue(new Boolean(settings.ignoreSubSites()));
278        if (settings.getType().isContentValuesOnly()) {
279            if (settings.getLocale() != null) {
280                m_locale.setValue(settings.getLocale());
281            }
282            m_xPath.setValue(settings.getXpath());
283        }
284        if (settings.getType().isSolrSearch()) {
285            m_solrQuery.setValue(settings.getQuery());
286            m_searchIndex.setValue(settings.getSource());
287        }
288
289        if (settings.getType().isPropertySearch()) {
290            m_property.select(settings.getProperty());
291        }
292        if (settings.getType().equals(SearchType.resourcetype)) {
293            try {
294                CmsObject cms = OpenCms.initCmsObject(A_CmsUI.getCmsObject());
295                cms.getRequestContext().setSiteRoot("");
296                m_resourceSearch.setValue(
297                    cms.readResource(
298                        new CmsUUID(
299                            settings.getSearchpattern().substring(
300                                settings.getSearchpattern().indexOf("<uuid>") + 6,
301                                settings.getSearchpattern().indexOf("</uuid>")))).getRootPath());
302            } catch (CmsException e) {
303                LOG.error("Unable to read resource", e);
304            }
305
306        }
307    }
308
309    /**
310     * Updates the search root.<p>
311     *
312     * @throws CmsException if CmsObject init fails
313     */
314    protected void updateSearchRoot() throws CmsException {
315
316        CmsObject newCms = OpenCms.initCmsObject(A_CmsUI.getCmsObject());
317        newCms.getRequestContext().setSiteRoot((String)m_siteSelect.getValue());
318        m_searchRoot.setCmsObject(newCms);
319        m_searchRoot.setValue("/");
320
321    }
322
323    /**
324     * Handles search type changes.<p>
325     */
326    void changedSearchType() {
327
328        SearchType type = (SearchType)m_searchType.getValue();
329
330        m_property.setVisible(type.isPropertySearch());
331        m_searchPattern.setVisible(
332            (!type.equals(SearchType.resourcetype)) & (!type.equals(SearchType.renameContainer)));
333        m_resourceSearch.setVisible(type.equals(SearchType.resourcetype) | type.equals(SearchType.renameContainer));
334        if ((!type.equals(SearchType.resourcetype)) & (!type.equals(SearchType.renameContainer))) {
335            m_ignoreSubSites.setValue(Boolean.FALSE);
336            m_ignoreSubSites.setVisible(false);
337        } else {
338            m_ignoreSubSites.setVisible(true);
339        }
340
341        m_searchIndex.setVisible(type.isSolrSearch());
342        m_solrQuery.setVisible(type.isSolrSearch());
343        updateReplace();
344        m_xPath.setVisible(type.isContentValuesOnly());
345        m_locale.setVisible(type.isContentValuesOnly());
346
347        m_resourceType.setVisible(
348            !type.isPropertySearch()
349                & !type.equals(SearchType.resourcetype)
350                & !type.equals(SearchType.renameContainer));
351
352        IndexedContainer types = (IndexedContainer)m_resourceType.getContainerDataSource();
353        types.removeAllContainerFilters();
354        types.addContainerFilter(
355            type.isContentValuesOnly() ? CmsVaadinUtils.FILTER_XML_CONTENTS : CmsVaadinUtils.FILTER_NO_FOLDERS);
356    }
357
358    /**
359     * Calls the search for the given parameters.<p>
360     */
361    void search() {
362
363        CmsSearchReplaceSettings settings = new CmsSearchReplaceSettings();
364        settings.setSiteRoot((String)m_siteSelect.getValue());
365        settings.setType((SearchType)m_searchType.getValue());
366        settings.setPaths(Collections.singletonList(m_searchRoot.getValue()));
367        settings.setIgnoreSubSites(m_ignoreSubSites.getValue().booleanValue());
368        I_CmsResourceType type = (I_CmsResourceType)m_resourceType.getValue();
369        if (type != null) {
370            settings.setTypes(type.getTypeName());
371        }
372        if (SearchType.resourcetype.equals(m_searchType.getValue())
373            | SearchType.renameContainer.equals(m_searchType.getValue())) {
374            settings.setTypes(
375                CmsResourceTypeXmlContainerPage.getStaticTypeName()
376                    + ","
377                    + CmsResourceTypeXmlContainerPage.MODEL_GROUP_TYPE_NAME);
378        }
379
380        if (SearchType.renameContainer.equals(m_searchType.getValue())) {
381            try {
382                CmsObject cms = OpenCms.initCmsObject(A_CmsUI.getCmsObject());
383                cms.getRequestContext().setSiteRoot("");
384                CmsResource element = cms.readResource(m_resourceSearch.getValue());
385                settings.setElementResource(element);
386            } catch (CmsException e) {
387                LOG.error("Can not read resource", e);
388            }
389        }
390
391        if (m_replace.getValue().booleanValue()) {
392            try {
393                CmsProject workProject = A_CmsUI.getCmsObject().readProject((CmsUUID)m_workProject.getValue());
394                settings.setProject(workProject.getName());
395            } catch (CmsException e) {
396                // ignore
397            }
398            if (SearchType.resourcetype.equals(m_searchType.getValue())) {
399                try {
400                    CmsObject cms = OpenCms.initCmsObject(A_CmsUI.getCmsObject());
401                    cms.getRequestContext().setSiteRoot("");
402                    CmsResource resource = cms.readResource(m_replaceResource.getValue());
403                    settings.setReplacepattern(CmsSearchReplaceSettings.replaceElementInPagePattern(resource));
404                } catch (CmsException e) {
405                    LOG.error("Unable to read resource.", e);
406                }
407            } else if (SearchType.renameContainer.equals(m_searchType.getValue())) {
408                settings.setReplacepattern(m_oldName.getValue() + ";" + m_newName.getValue());
409            } else {
410
411                settings.setReplacepattern(m_replacePattern.getValue());
412            }
413
414        }
415
416        if (SearchType.resourcetype.equals(m_searchType.getValue())
417            | SearchType.renameContainer.equals(m_searchType.getValue())) {
418            try {
419                CmsObject cms = OpenCms.initCmsObject(A_CmsUI.getCmsObject());
420                cms.getRequestContext().setSiteRoot("");
421                CmsResource resource = cms.readResource(m_resourceSearch.getValue());
422                settings.setSearchpattern(CmsSearchReplaceSettings.searchElementInPagePattern(resource));
423            } catch (CmsException e) {
424                LOG.error("Unable to read resource.", e);
425            }
426        } else {
427
428            settings.setSearchpattern(m_searchPattern.getValue());
429        }
430        if (settings.getType().isContentValuesOnly()) {
431            if (m_locale.getValue() != null) {
432                settings.setLocale(m_locale.getValue().toString());
433            }
434            settings.setXpath(m_xPath.getValue());
435        }
436        if (settings.getType().isSolrSearch()) {
437            settings.setQuery(m_solrQuery.getValue());
438            settings.setSource((String)m_searchIndex.getValue());
439        }
440
441        if (settings.getType().isPropertySearch()) {
442            settings.setProperty((CmsPropertyDefinition)m_property.getValue());
443            settings.setForceReplace(m_replace.getValue().booleanValue());
444        }
445
446        m_app.search(settings, true);
447    }
448
449    /**
450     * Toggles the replace option.<p>
451     */
452    void updateReplace() {
453
454        boolean replace = m_replace.getValue().booleanValue();
455
456        m_replaceResource.setVisible(replace ? SearchType.resourcetype.equals(m_searchType.getValue()) : replace);
457        m_replacePattern.setVisible(
458            replace
459            ? !SearchType.resourcetype.equals(m_searchType.getValue())
460                & !SearchType.renameContainer.equals(m_searchType.getValue())
461            : replace);
462
463        m_newName.setVisible(replace ? SearchType.renameContainer.equals(m_searchType.getValue()) : replace);
464        m_oldName.setVisible(replace ? SearchType.renameContainer.equals(m_searchType.getValue()) : replace);
465
466        m_workProject.setVisible(replace);
467
468        m_search.setCaption(
469            replace
470            ? CmsVaadinUtils.getMessageText(Messages.GUI_SOURCESEARCH_REPLACE_0)
471            : CmsVaadinUtils.getMessageText(Messages.GUI_SOURCESEARCH_SEARCH_0));
472
473    }
474
475    /**
476     * Initializes the form fields.<p>
477     */
478    private void initFields() {
479
480        CmsObject cms = A_CmsUI.getCmsObject();
481        boolean online = cms.getRequestContext().getCurrentProject().isOnlineProject();
482
483        if (m_searchPattern.getValue().isEmpty()) {
484            m_searchPattern.setValue(REGEX_ALL);
485        }
486        m_resourceSearch.setUseRootPaths(true);
487        m_replaceResource.setUseRootPaths(true);
488        m_resourceSearch.requireFile();
489        m_replaceResource.requireFile();
490        CmsObject rootCms;
491        try {
492            rootCms = OpenCms.initCmsObject(cms);
493
494            rootCms.getRequestContext().setSiteRoot("");
495            m_resourceSearch.setCmsObject(rootCms);
496            m_resourceSearch.setDefaultPath(cms.getRequestContext().getSiteRoot());
497            m_replaceResource.setCmsObject(rootCms);
498            m_replaceResource.setDefaultPath(cms.getRequestContext().getSiteRoot());
499
500        } catch (CmsException e1) {
501            //
502        }
503        m_siteSelect.setContainerDataSource(
504            CmsVaadinUtils.getAvailableSitesContainer(cms, CmsVaadinUtils.PROPERTY_LABEL));
505        m_siteSelect.setItemCaptionPropertyId(CmsVaadinUtils.PROPERTY_LABEL);
506        m_siteSelect.setTextInputAllowed(true);
507        m_siteSelect.setNullSelectionAllowed(false);
508        m_siteSelect.setFilteringMode(FilteringMode.CONTAINS);
509        m_siteSelect.setValue(cms.getRequestContext().getSiteRoot());
510        try {
511            for (CmsPropertyDefinition prop : A_CmsUI.getCmsObject().readAllPropertyDefinitions()) {
512                m_property.addItem(prop);
513                m_property.setItemCaption(prop, prop.getName());
514            }
515        } catch (CmsException e) {
516            //
517        }
518        m_siteSelect.addValueChangeListener(new ValueChangeListener() {
519
520            private static final long serialVersionUID = -1079794209679015125L;
521
522            public void valueChange(ValueChangeEvent event) {
523
524                try {
525                    updateSearchRoot();
526                } catch (CmsException e) {
527                    LOG.error("Unable to initialize CmsObject", e);
528                }
529            }
530
531        });
532        m_property.setNullSelectionAllowed(false);
533        m_property.select(m_property.getItemIds().iterator().next());
534        m_property.setFilteringMode(FilteringMode.CONTAINS);
535        m_searchType.setFilteringMode(FilteringMode.OFF);
536        m_searchType.setNullSelectionAllowed(false);
537        m_searchType.addItem(SearchType.fullText);
538        m_searchType.setItemCaption(
539            SearchType.fullText,
540            CmsVaadinUtils.getMessageText(Messages.GUI_SOURCESEARCH_SERACH_TYPE_FULLTEXT_0));
541        m_searchType.addItem(SearchType.contentValues);
542        m_searchType.setItemCaption(
543            SearchType.contentValues,
544            CmsVaadinUtils.getMessageText(Messages.GUI_SOURCESEARCH_SERACH_TYPE_XMLCONTENT_0));
545        m_searchType.addItem(SearchType.properties);
546        m_searchType.setItemCaption(
547            SearchType.properties,
548            CmsVaadinUtils.getMessageText(Messages.GUI_SOURCESEARCH_PROPERTY_SEARCH_0));
549        m_searchType.addItem(SearchType.resourcetype);
550        m_searchType.setItemCaption(
551            SearchType.resourcetype,
552            CmsVaadinUtils.getMessageText(Messages.GUI_SOURCESEARCH_RESOURCE_SEARCH_0));
553        m_searchType.addItem(SearchType.renameContainer);
554        m_searchType.setItemCaption(
555            SearchType.renameContainer,
556            CmsVaadinUtils.getMessageText(Messages.GUI_SOURCESEARCH_RENAME_CONTAINER_SEARCH_0));
557        if (OpenCms.getSearchManager().getSolrServerConfiguration().isEnabled()) {
558
559            m_searchIndex.setFilteringMode(FilteringMode.OFF);
560            m_searchIndex.setNullSelectionAllowed(false);
561            String selectIndex = null;
562            for (CmsSearchIndex index : OpenCms.getSearchManager().getAllSolrIndexes()) {
563                boolean offlineMode = I_CmsSearchIndex.REBUILD_MODE_OFFLINE.equals(index.getRebuildMode());
564                // in case the current project is offline, show offline indexes, otherwise show online indexes
565                if ((!online && offlineMode) || (online && !offlineMode)) {
566                    m_searchIndex.addItem(index.getName());
567                    if (selectIndex == null) {
568                        selectIndex = index.getName();
569                    }
570                }
571            }
572            if (selectIndex != null) {
573                m_searchIndex.setValue(selectIndex);
574
575                // only add the solr search types if there is an index available
576                m_searchType.addItem(SearchType.solr);
577                m_searchType.setItemCaption(
578                    SearchType.solr,
579                    CmsVaadinUtils.getMessageText(Messages.GUI_SOURCESEARCH_SERACH_TYPE_SOLR_0));
580                m_searchType.addItem(SearchType.solrContentValues);
581                m_searchType.setItemCaption(
582                    SearchType.solrContentValues,
583                    CmsVaadinUtils.getMessageText(Messages.GUI_SOURCESEARCH_SERACH_TYPE_SOLR_CONTENT_VALUES_0));
584
585            }
586        }
587        m_searchType.setValue(SearchType.fullText);
588
589        m_searchRoot.setValue("/");
590        m_searchRoot.disableSiteSwitch();
591        m_searchRoot.setResourceFilter(CmsResourceFilter.DEFAULT_FOLDERS);
592        m_searchRoot.requireFolder();
593        m_locale.setFilteringMode(FilteringMode.OFF);
594        for (Locale locale : OpenCms.getLocaleManager().getAvailableLocales()) {
595            m_locale.addItem(locale);
596        }
597
598        m_resourceType.setNullSelectionAllowed(true);
599        IndexedContainer resTypes = CmsVaadinUtils.getResourceTypesContainer();
600        resTypes.addContainerFilter(CmsVaadinUtils.FILTER_NO_FOLDERS);
601
602        m_resourceType.setContainerDataSource(resTypes);
603        m_resourceType.setItemCaptionPropertyId(PropertyId.caption);
604        m_resourceType.setItemIconPropertyId(PropertyId.icon);
605        m_resourceType.setFilteringMode(FilteringMode.CONTAINS);
606
607        m_workProject.setNullSelectionAllowed(false);
608        IndexedContainer projects = CmsVaadinUtils.getProjectsContainer(A_CmsUI.getCmsObject(), "caption");
609        projects.removeItem(CmsProject.ONLINE_PROJECT_ID);
610        m_workProject.setContainerDataSource(projects);
611        m_workProject.setItemCaptionPropertyId("caption");
612
613        if (online) {
614            m_replace.setEnabled(false);
615        } else {
616            m_workProject.setValue(cms.getRequestContext().getCurrentProject().getUuid());
617        }
618    }
619}