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.synchronize;
029
030import org.opencms.file.CmsObject;
031import org.opencms.main.CmsException;
032import org.opencms.main.CmsIllegalArgumentException;
033import org.opencms.util.CmsStringUtil;
034
035import java.io.File;
036import java.io.Serializable;
037import java.util.ArrayList;
038import java.util.Collections;
039import java.util.Iterator;
040import java.util.List;
041
042/**
043 * Contains the settings for the synchronization.<p>
044 *
045 * @since 6.0.0
046 */
047public class CmsSynchronizeSettings implements Serializable {
048
049    /** use well defined serialVersionUID to avoid issues with serialization. */
050    private static final long serialVersionUID = 3713893787290111758L;
051
052    /** The destination path of the synchronization in the "real" file system. */
053    private String m_destinationPathInRfs;
054
055    /** Indicates if the synchronization is enabled or not. */
056    private boolean m_enabled;
057
058    /** The source path list of the synchronization in the OpenCms VFS. */
059    private List<String> m_sourceListInVfs;
060
061    /**
062     * Empty constructor, called from the configuration.<p>
063     */
064    public CmsSynchronizeSettings() {
065
066        m_sourceListInVfs = new ArrayList<String>();
067    }
068
069    /**
070     * Performs a check if the values that have been set are valid.<p>
071     *
072     * @param cms the current users OpenCms context
073     *
074     * @throws CmsException in case the values are not valid
075     */
076    public void checkValues(CmsObject cms) throws CmsException {
077
078        if (isEnabled() && (m_destinationPathInRfs == null)) {
079            // if enabled, it's required to have RFS destination folder available
080            throw new CmsSynchronizeException(Messages.get().container(Messages.ERR_NO_RFS_DESTINATION_0));
081        }
082        if (isEnabled() && ((m_sourceListInVfs == null) || (m_sourceListInVfs.size() == 0))) {
083            // if enabled, it's required to have at last one source folder
084            throw new CmsSynchronizeException(Messages.get().container(Messages.ERR_NO_VFS_SOURCE_0));
085        }
086        Iterator<String> i = m_sourceListInVfs.iterator();
087        // store the current site root
088        String currentSite = cms.getRequestContext().getSiteRoot();
089        // switch to root site
090        cms.getRequestContext().setSiteRoot("");
091        try {
092            while (i.hasNext()) {
093                // try to read all given resources, this will cause an error if the resource does not exist
094                cms.readResource(i.next());
095            }
096        } finally {
097            // reset to current site root
098            cms.getRequestContext().setSiteRoot(currentSite);
099        }
100    }
101
102    /**
103     * Returns the destination path of the synchronization in the "real" file system.<p>
104     *
105     * @return the destination path of the synchronization in the "real" file system
106     */
107    public String getDestinationPathInRfs() {
108
109        return m_destinationPathInRfs;
110    }
111
112    /**
113     * Returns the source path list of the synchronization in the OpenCms VFS.<p>
114     *
115     * The objects in the list are of type <code>{@link String}</code>.
116     *
117     * @return the source path list of the synchronization in the OpenCms VFS
118     */
119    public List<String> getSourceListInVfs() {
120
121        return m_sourceListInVfs;
122    }
123
124    /**
125     * Returns the enabled flag which indicates if this synchronize settings are enabled or not.<p>
126     *
127     * @return the enabled flag
128     */
129    public boolean isEnabled() {
130
131        return m_enabled;
132    }
133
134    /**
135     * Returns <code>true</code> if the synchonization is enabled.<p>
136     *
137     * The synchonization is enabled if both source and destination
138     * path is set, and also the enabled flag is true.<p>
139     *
140     * @return <code>true</code> if the synchonization is enabled
141     */
142    public boolean isSyncEnabled() {
143
144        return isEnabled() && (m_sourceListInVfs != null) && (m_destinationPathInRfs != null);
145    }
146
147    /**
148     * Sets the destination path of the synchronization in the "real" file system.<p>
149     *
150     * @param destinationPathInRfs the destination path of the synchronization in the "real" file system to set
151     */
152    public void setDestinationPathInRfs(String destinationPathInRfs) {
153
154        String destination;
155        if (CmsStringUtil.isEmptyOrWhitespaceOnly(destinationPathInRfs)) {
156            destination = null;
157        } else {
158            destination = destinationPathInRfs.trim();
159        }
160        if (destination != null) {
161            File destinationFolder = new File(destination);
162            if (!destinationFolder.exists() || !destinationFolder.isDirectory()) {
163                // destination folder does not exist
164                throw new CmsIllegalArgumentException(
165                    Messages.get().container(Messages.ERR_RFS_DESTINATION_NOT_THERE_1, destination));
166            }
167            if (!destinationFolder.canWrite()) {
168                // destination folder can't be written to
169                throw new CmsIllegalArgumentException(
170                    Messages.get().container(Messages.ERR_RFS_DESTINATION_NO_WRITE_1, destination));
171            }
172            destination = destinationFolder.getAbsolutePath();
173            if (destination.endsWith(File.separator)) {
174                // ensure that the destination folder DOES NOT end with a file separator
175                destination = destination.substring(0, destination.length() - 1);
176            }
177        }
178        m_destinationPathInRfs = destination;
179    }
180
181    /**
182     * Sets the enabled flag which indicates if this synchronize settings are enabled or not.<p>
183     *
184     * @param enabled the enabled flag to set
185     */
186    public void setEnabled(boolean enabled) {
187
188        m_enabled = enabled;
189    }
190
191    /**
192     * Sets the source path list of the synchronization in the OpenCms VFS.<p>
193     *
194     * The objects in the list must be of type <code>{@link String}</code>.
195     *
196     * @param sourceListInVfs the source path list of the synchronization in the OpenCms VFS to set
197     */
198    public void setSourceListInVfs(List<String> sourceListInVfs) {
199
200        if (sourceListInVfs == null) {
201            m_sourceListInVfs = new ArrayList<String>();
202        } else {
203            m_sourceListInVfs = optimizeSourceList(sourceListInVfs);
204        }
205    }
206
207    /**
208     * @see java.lang.Object#toString()
209     */
210    @Override
211    public String toString() {
212
213        StringBuffer result = new StringBuffer();
214        result.append("[");
215        result.append(this.getClass().getName());
216        result.append(", enabled: ");
217        result.append(m_enabled);
218        result.append(", RFS destination path: ");
219        result.append(m_destinationPathInRfs);
220        result.append(", VFS source path list: ");
221        if (m_sourceListInVfs == null) {
222            result.append(m_sourceListInVfs);
223        } else {
224            Iterator<String> i = m_sourceListInVfs.iterator();
225            while (i.hasNext()) {
226                String path = i.next();
227                result.append(path);
228                if (i.hasNext()) {
229                    result.append(", ");
230                }
231            }
232        }
233        result.append("]");
234        return result.toString();
235    }
236
237    /**
238     * Optimizes the list of VFS source files by removing all resources that
239     * have a parent resource already included in the list.<p>
240     *
241     * @param sourceListInVfs the list of VFS resources to optimize
242     * @return the optimized result list
243     */
244    protected List<String> optimizeSourceList(List<String> sourceListInVfs) {
245
246        // input should be sorted but may be immutable
247        List<String> input = new ArrayList<String>(sourceListInVfs);
248        Collections.sort(input);
249
250        List<String> result = new ArrayList<String>();
251        Iterator<String> i = input.iterator();
252        while (i.hasNext()) {
253            // check all sources in the list
254            String sourceInVfs = i.next();
255            if (CmsStringUtil.isEmpty(sourceInVfs)) {
256                // skip empty strings
257                continue;
258            }
259            boolean found = false;
260            for (int j = (result.size() - 1); j >= 0; j--) {
261                // check if this source is indirectly contained because a parent folder is contained
262                String check = result.get(j);
263                if (sourceInVfs.startsWith(check)) {
264                    found = true;
265                    break;
266                }
267            }
268            if (!found) {
269                // the source is not already contained in the result
270                result.add(sourceInVfs);
271            }
272        }
273
274        return result;
275    }
276}