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.relations;
029
030import org.opencms.file.CmsDataAccessException;
031import org.opencms.file.CmsResource;
032import org.opencms.main.CmsException;
033import org.opencms.util.CmsStringUtil;
034import org.opencms.util.CmsUUID;
035
036import java.io.Serializable;
037
038/**
039 * Represents a category, that is just a folder.<p>
040 *
041 * The category can be centralized under <code>/system/categories/</code>,
042 * or decentralized in every folder.<p>
043 *
044 * For instance, you can have a category folder under <code>/sites/default/</code>
045 * so, any file under <code>/sites/default/</code> could be assigned to any
046 * category defined under <code>/system/categories/</code> or
047 * <code>/sites/default/categories</code>.<p>
048 *
049 * But a file under <code>/sites/othersite/</code> will only be assignable to
050 * categories defined in <code>/system/categories/</code>.<p>
051 *
052 * @since 6.9.2
053 */
054public class CmsCategory implements Comparable<CmsCategory>, Serializable {
055
056    /** The serialization id. */
057    private static final long serialVersionUID = -6395887983124249138L;
058
059    /** The category's base path. */
060    private String m_basePath;
061
062    /** The description of the category. */
063    private String m_description;
064
065    /** The path of the category. */
066    private String m_path;
067
068    /** The category's root path. */
069    private String m_rootPath;
070
071    /** The structure id of the resource that this category represents. */
072    private CmsUUID m_structureId;
073
074    /** The title of the category. */
075    private String m_title;
076
077    /**
078     * Creates a new category based on another one, keeping everything except title and description, which are passed in separately.<p>
079     *
080     * @param other the other category to copy fields from
081     * @param title the new title
082     * @param description the new description
083     */
084    public CmsCategory(CmsCategory other, String title, String description) {
085        m_basePath = other.m_basePath;
086
087        m_path = other.m_path;
088        m_rootPath = other.m_rootPath;
089        m_structureId = other.m_structureId;
090        m_description = description != null ? description : other.m_description;
091        m_title = title != null ? title : other.m_title;
092    }
093
094    /**
095     * Default constructor.<p>
096     *
097     * @param structureId the structure id of the resource that this category represents
098     * @param rootPath the root path of the category folder
099     * @param title the title of the category
100     * @param description the description of the category
101     * @param baseFolder the base categories folder
102     *
103     * @throws CmsException if the root path does not match the given base folder
104     */
105    public CmsCategory(CmsUUID structureId, String rootPath, String title, String description, String baseFolder)
106    throws CmsException {
107
108        m_structureId = structureId;
109        m_rootPath = rootPath;
110        m_title = title;
111        m_description = description;
112        m_path = getCategoryPath(m_rootPath, baseFolder);
113        m_basePath = m_rootPath.substring(0, m_rootPath.length() - m_path.length());
114    }
115
116    /**
117     * Empty default constructor which is only used for serialization.<p>
118     */
119    protected CmsCategory() {
120
121        // do nothing
122    }
123
124    /**
125     * Returns the category path for the given root path.<p>
126     *
127     * @param rootPath the root path
128     * @param baseFolder the categories base folder name
129     *
130     * @return the category path
131     *
132     * @throws CmsException if the root path does not match the given base folder
133     */
134    public static String getCategoryPath(String rootPath, String baseFolder) throws CmsException {
135
136        String base;
137        if (rootPath.startsWith(CmsCategoryService.CENTRALIZED_REPOSITORY)) {
138            base = CmsCategoryService.CENTRALIZED_REPOSITORY;
139        } else {
140            base = baseFolder;
141            if (!base.endsWith("/")) {
142                base += "/";
143            }
144            if (!base.startsWith("/")) {
145                base = "/" + base;
146            }
147            int pos = rootPath.indexOf(base);
148            if (pos < 0) {
149                throw new CmsDataAccessException(
150                    Messages.get().container(Messages.ERR_CATEGORY_INVALID_LOCATION_1, rootPath));
151            }
152            base = rootPath.substring(0, pos + base.length());
153        }
154        return rootPath.substring(base.length());
155    }
156
157    /**
158     * @see java.lang.Comparable#compareTo(java.lang.Object)
159     */
160    public int compareTo(CmsCategory cat) {
161
162        boolean thisGlobal = getBasePath().equals(CmsCategoryService.CENTRALIZED_REPOSITORY);
163        boolean thatGlobal = cat.getBasePath().equals(CmsCategoryService.CENTRALIZED_REPOSITORY);
164        if ((thisGlobal && thatGlobal) || (!thisGlobal && !thatGlobal)) {
165            return getPath().compareTo(cat.getPath());
166        }
167        return thisGlobal ? -1 : 1;
168    }
169
170    /**
171     * @see java.lang.Object#equals(java.lang.Object)
172     */
173    @Override
174    public boolean equals(Object obj) {
175
176        if (!(obj instanceof CmsCategory)) {
177            return false;
178        }
179        CmsCategory compareCategory = (CmsCategory)obj;
180        if (!compareCategory.getPath().equals(getPath())) {
181            return false;
182        }
183        return true;
184    }
185
186    /**
187     * Returns the category's base path.<p>
188     *
189     * @return the category's base path
190     */
191    public String getBasePath() {
192
193        return m_basePath;
194    }
195
196    /**
197     * Returns the description.<p>
198     *
199     * @return the description
200     */
201    public String getDescription() {
202
203        return m_description;
204    }
205
206    /**
207     * Returns the id.<p>
208     *
209     * @return the id
210     */
211    public CmsUUID getId() {
212
213        return m_structureId;
214    }
215
216    /**
217     * Returns the mere category name without it's complete path and without the trailing folder - slash.<p>
218     *
219     * @return the mere category name without it's complete path and without the trailing folder - slash
220     */
221    public String getName() {
222
223        if (CmsStringUtil.isEmptyOrWhitespaceOnly(m_path)) {
224            return "";
225        }
226        String result = CmsResource.getName(m_path);
227        // remove trailing slash as categories are not displayed like folders
228        if (CmsResource.isFolder(result)) {
229            result = result.substring(0, result.length() - 1);
230        }
231        return result;
232    }
233
234    /**
235     * Returns the path.<p>
236     *
237     * @return the path
238     */
239    public String getPath() {
240
241        return m_path;
242    }
243
244    /**
245     * Returns the category's root path.<p>
246     *
247     * @return the category's root path
248     */
249    public String getRootPath() {
250
251        return m_rootPath;
252    }
253
254    /**
255     * Returns the title.<p>
256     *
257     * @return the title
258     */
259    public String getTitle() {
260
261        return m_title;
262    }
263
264    /**
265     * @see java.lang.Object#hashCode()
266     */
267    @Override
268    public int hashCode() {
269
270        return getPath().hashCode();
271    }
272
273    /**
274     * @see java.lang.Object#toString()
275     */
276    @Override
277    public String toString() {
278
279        return "[" + CmsCategory.class.getSimpleName() + "/" + System.identityHashCode(this) + ": " + m_rootPath + " ]";
280    }
281}