File Source: category.java
1 /*
2 * Copyright (c) 2003-2006, Simon Brown
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * - Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 *
16 * - Neither the name of Pebble nor the names of its contributors may
17 * be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32 package net.sourceforge.pebble.domain;
33
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36
37 import java.io.Serializable;
38 import java.util.*;
39
40 import net.sourceforge.pebble.comparator.ReverseBlogEntryIdComparator;
41
42 /**
43 * Represents a blog category.
44 *
45 * @author Simon Brown
46 */
47 public class Category implements Permalinkable, Comparable, Serializable {
48
49 /** the log used by this class */
/*
P/P * Method: net.sourceforge.pebble.domain.Category__static_init
*
* Postconditions:
* init'ed(log)
*/
50 private static final Log log = LogFactory.getLog(Category.class);
51
52 /** the root category identifier */
53 private static final String ROOT_CATEGORY_IDENTIFIER = "/";
54
55 /** the owning blog */
56 private transient Blog blog;
57
58 /** the id of the category */
59 private String id = "";
60
61 /** the name of the category */
62 private String name = "";
63
64 /** the parent category, if applicable */
65 private Category parent = null;
66
67 /** the set of tags for this category */
68 private String tags = "";
69
70 /** the list of tags for this category */
71 private List tagsAsList = new ArrayList();
72
73 /** the sub-categories */
74 private List subCategories = new ArrayList();
75
76 /** the blog entries associated with this category */
77 private List<String> blogEntries = new ArrayList<String>();
78
79 /**
80 * Default, no args constructor.
81 */
/*
P/P * Method: void net.sourceforge.pebble.domain.Category()
*
* Postconditions:
* this.blogEntries == &new ArrayList(Category#3)
* this.id == &""
* this.name == &""
* this.tags == &""
* this.parent == null
* this.subCategories == &new ArrayList(Category#2)
* this.tagsAsList == &new ArrayList(Category#1)
* new ArrayList(Category#1) num objects == 1
* new ArrayList(Category#2) num objects == 1
* new ArrayList(Category#3) num objects == 1
*/
82 public Category() {
83 }
84
85 /**
86 * Creates a new category with the specified properties.
87 *
88 * @param id the id
89 * @param name the name
90 */
/*
P/P * Method: void net.sourceforge.pebble.domain.Category(String, String)
*
* Postconditions:
* this.blogEntries == &new ArrayList(Category#3)
* this.id != null
* this.name == name
* init'ed(this.name)
* init'ed(this.parent)
* this.subCategories == &new ArrayList(Category#2)
* this.tags == &""
* this.tagsAsList == &new ArrayList(Category#1)
* new ArrayList(Category#1) num objects == 1
* new ArrayList(Category#2) num objects == 1
* ...
*/
91 public Category(String id, String name) {
92 setId(id);
93
94 this.name = name;
95 }
96
97 /**
98 * Gets the id of this category.
99 *
100 * @return the id as a String
101 */
102 public String getId() {
/*
P/P * Method: String getId()
*
* Preconditions:
* init'ed(this.id)
*
* Postconditions:
* return_value == this.id
* init'ed(return_value)
*/
103 return id;
104 }
105
106 /**
107 * Sets the id of this category.
108 *
109 * @param id the id as a String
110 */
111 public void setId(String id) {
/*
P/P * Method: void setId(String)
*
* Postconditions:
* this.id != null
*
* Test Vectors:
* id: Addr_Set{null}, Inverse{null}
* java.lang.String:startsWith(...)@113: {1}, {0}
*/
112 this.id = id;
113 if (this.id == null || !this.id.startsWith("/")) {
114 this.id = "/" + this.id;
115 }
116 }
117
118 /**
119 * Gets the name of this category.
120 *
121 * @return the name as a String
122 */
123 public String getName() {
/*
P/P * Method: String getName()
*
* Preconditions:
* init'ed(this.name)
*
* Postconditions:
* return_value == this.name
* init'ed(return_value)
*/
124 return name;
125 }
126
127 /**
128 * Sets the name of this category.
129 *
130 * @param name the new category name
131 */
132 public void setName(String name) {
/*
P/P * Method: void setName(String)
*
* Postconditions:
* this.name == name
* init'ed(this.name)
*/
133 this.name = name;
134 }
135
136 /**
137 * Determines whether this category is a root category.
138 *
139 * @return true if the ID is "/", false otherwise
140 */
141 public boolean isRootCategory() {
/*
P/P * Method: bool isRootCategory()
*
* Preconditions:
* this.id != null
*
* Postconditions:
* init'ed(return_value)
*/
142 return id.equals(ROOT_CATEGORY_IDENTIFIER);
143 }
144
145 /**
146 * Gets the parent of thie category.
147 *
148 * @return a Category instance, or null if this category has no parent
149 */
150 public Category getParent() {
/*
P/P * Method: Category getParent()
*
* Preconditions:
* init'ed(this.parent)
*
* Postconditions:
* return_value == this.parent
* init'ed(return_value)
*/
151 return this.parent;
152 }
153
154 /**
155 * Determines whether this category has the specified parent.
156 *
157 * @param category a Category to test for
158 * @return true if this category has the specified category as one of its
159 * parents, false otherwise
160 */
161 public boolean hasParent(Category category) {
/*
P/P * Method: bool hasParent(Category)
*
* Preconditions:
* init'ed(this.parent)
* (soft) category.id != null
* (soft) init'ed(this...id)
* (soft) init'ed(this...parent)
*
* Postconditions:
* init'ed(return_value)
*/
162 Category parent = getParent();
163 while (parent != null) {
164 if (parent.equals(category)) {
165 return true;
166 } else {
167 parent = parent.getParent();
168 }
169 }
170
171 return false;
172 }
173
174 /**
175 * Sets the parent of this category.
176 *
177 * @param parent a Category instance
178 */
179 public void setParent(Category parent) {
/*
P/P * Method: void setParent(Category)
*
* Postconditions:
* this.parent == parent
* init'ed(this.parent)
*/
180 this.parent = parent;
181 }
182
183 /**
184 * Gets the number of parents that this category has.
185 *
186 * @return the number of parents this category has, or 0 if it is
187 * the root category
188 */
189 public int getNumberOfParents() {
/*
P/P * Method: int getNumberOfParents()
*
* Preconditions:
* init'ed(this.parent)
* (soft) init'ed(this...parent)
*
* Postconditions:
* return_value >= 0
*/
190 int parents = 0;
191 Category parent = getParent();
192 while (parent != null) {
193 parents++;
194 parent = parent.getParent();
195 }
196
197 return parents;
198 }
199
200 /**
201 * Adds a sub-category.
202 *
203 * @param category a Category instance
204 */
205 public synchronized void addSubCategory(Category category) {
/*
P/P * Method: void addSubCategory(Category)
*
* Preconditions:
* init'ed(this.subCategories)
* (soft) category != null
*
* Postconditions:
* category.parent == One-of{old category.parent, this}
*
* Test Vectors:
* this.subCategories: Addr_Set{null}, Inverse{null}
* java.util.List:contains(...)@206: {1}, {0}
*/
206 if (subCategories != null && !subCategories.contains(category)) {
207 subCategories.add(category);
208 category.setParent(this);
209 }
210 }
211
212 /**
213 * Removes a sub-category.
214 *
215 * @param category a Category instance
216 */
217 public synchronized void removeSubCategory(Category category) {
/*
P/P * Method: void removeSubCategory(Category)
*
* Preconditions:
* init'ed(this.subCategories)
* (soft) category != null
*
* Postconditions:
* category.parent == One-of{old category.parent, null}
*
* Test Vectors:
* this.subCategories: Addr_Set{null}, Inverse{null}
* java.util.List:contains(...)@218: {0}, {1}
*/
218 if (subCategories != null && subCategories.contains(category)) {
219 subCategories.remove(category);
220 category.setParent(null);
221 }
222 }
223
224 /**
225 * Gets the list of sub-categories.
226 *
227 * @return a List of Category instances
228 */
229 public List getSubCategories() {
/*
P/P * Method: List getSubCategories()
*
* Preconditions:
* init'ed(this.subCategories)
*
* Postconditions:
* init'ed(return_value)
*/
230 return Collections.unmodifiableList(subCategories);
231 }
232
233 /**
234 * Gets the tags associated with this category.
235 *
236 * @return a list of tags
237 */
238 public String getTags() {
/*
P/P * Method: String getTags()
*
* Preconditions:
* init'ed(this.tags)
*
* Postconditions:
* return_value == this.tags
* init'ed(return_value)
*/
239 return this.tags;
240 }
241
242 /**
243 * Gets the tags associated with this category, as a List.
244 *
245 * @return a List of tags
246 */
247 public List getTagsAsList() {
/*
P/P * Method: List getTagsAsList()
*
* Preconditions:
* init'ed(this.tagsAsList)
*
* Postconditions:
* return_value == this.tagsAsList
* init'ed(return_value)
*/
248 return this.tagsAsList;
249 }
250
251 /**
252 * Gets the tags associated with this category and its parents.
253 *
254 * @return a list of tags
255 */
256 public List getAllTags() {
/*
P/P * Method: List getAllTags()
*
* Preconditions:
* init'ed(this.parent)
* init'ed(this.tagsAsList)
* (soft) init'ed(this...parent)
* (soft) init'ed(this...tagsAsList)
*
* Postconditions:
* return_value == &new ArrayList(getAllTags#1)
* new ArrayList(getAllTags#1) num objects == 1
*/
257 List l = new ArrayList();
258
259 l.addAll(getTagsAsList());
260 Category parent = getParent();
261 while (parent != null) {
262 l.addAll(parent.getTagsAsList());
263 parent = parent.getParent();
264 }
265
266 return l;
267 }
268
269 /**
270 * Sets the set of tags associated with this category.
271 *
272 * @param newTags a set of tags
273 */
274 public void setTags(String newTags) {
/*
P/P * Method: void setTags(String)
*
* Preconditions:
* init'ed(this.blog)
*
* Postconditions:
* init'ed(this.tags)
* this.tagsAsList == &new ArrayList(parse#1)
* new ArrayList(parse#1) num objects == 1
*
* Test Vectors:
* newTags: Addr_Set{null}, Inverse{null}
* java.lang.String:indexOf(...)@275: {-231..-1}, {0..232-1}
*/
275 if (newTags != null && newTags.indexOf(",") > -1) {
276 // if the tags have been comma separated, convert them to
277 // whitespace separated by
278 // - remove whitespace
279 // - convert commas to whitespace
280 newTags = newTags.replaceAll(" ", "").replaceAll(",", " ");
281 }
282 this.tags = newTags;
283 this.tagsAsList = Tag.parse(blog, tags);
284 }
285
286 /**
287 * Sets the owning blog.
288 *
289 * @param blog a Blog instance
290 */
291 public void setBlog(Blog blog) {
/*
P/P * Method: void setBlog(Blog)
*
* Postconditions:
* this.blog == blog
* init'ed(this.blog)
*/
292 this.blog = blog;
293 }
294
295 /**
296 * Gets the permalink for this object.
297 *
298 * @return a URL as a String
299 */
300 public String getPermalink() {
/*
P/P * Method: String getPermalink()
*
* Preconditions:
* this.blog != null
* this.id != null
*
* Postconditions:
* return_value != null
*
* Test Vectors:
* java.lang.String:equals(...)@142: {0}, {1}
*
* Preconditions:
* (soft) net/sourceforge/pebble/domain/BlogManager.instance != null
* (soft) init'ed(net/sourceforge/pebble/domain/BlogManager.instance.multiBlog)
* (soft) init'ed(this.blog.id)
*/
301 if (isRootCategory()) {
302 return blog.getUrl() + "categories/";
303 } else {
304 return blog.getUrl() + "categories" + id + "/";
305 }
306 }
307
308 /**
309 * Gets the hashcode of this object.
310 *
311 * @return the hashcode as an int
312 */
313 public int hashCode() {
/*
P/P * Method: int hashCode()
*
* Preconditions:
* this.id != null
*
* Postconditions:
* init'ed(return_value)
*/
314 return id.hashCode();
315 }
316
317 /**
318 * Determines whether the specified object is equal to this one.
319 *
320 * @param o the object to compare against
321 * @return true if Object o represents the same category, false otherwise
322 */
323 public boolean equals(Object o) {
/*
P/P * Method: bool equals(Object)
*
* Preconditions:
* (soft) o.id != null
* (soft) init'ed(this.id)
*
* Postconditions:
* init'ed(return_value)
*/
324 if (!(o instanceof Category)) {
325 return false;
326 }
327
328 Category cat = (Category)o;
329 return (cat.getId().equals(id));
330 }
331
332 /**
333 * Compares this object with the specified object for order. Returns a
334 * negative integer, zero, or a positive integer as this object is less
335 * than, equal to, or greater than the specified object.<p>
336 *
337 * @param o the Object to be compared.
338 * @return a negative integer, zero, or a positive integer as this object
339 * is less than, equal to, or greater than the specified object.
340 *
341 * @throws ClassCastException if the specified object's type prevents it
342 * from being compared to this Object.
343 */
344 public int compareTo(Object o) {
/*
P/P * Method: int compareTo(Object)
*
* Preconditions:
* o != null
* init'ed(o.id)
* this.id != null
*
* Postconditions:
* init'ed(return_value)
*/
345 Category category = (Category)o;
346 return getId().compareTo(category.getId());
347 }
348
349 /**
350 * Returns a String representation of this object.
351 *
352 * @return a String
353 */
354 public String toString() {
/*
P/P * Method: String toString()
*
* Preconditions:
* init'ed(this.name)
*
* Postconditions:
* return_value == this.name
* init'ed(return_value)
*/
355 return this.name;
356 }
357
358 /**
359 * Gets the blog entries associated with this category.
360 *
361 * @return a Collection of BlogEntry instances
362 */
363 public List<String> getBlogEntries() {
/*
P/P * Method: List getBlogEntries()
*
* Preconditions:
* init'ed(this.blogEntries)
*
* Postconditions:
* return_value == &new ArrayList(getBlogEntries#1)
* new ArrayList(getBlogEntries#1) num objects == 1
*/
364 return new ArrayList<String>(blogEntries);
365 }
366
367 /**
368 * Adds a blog entry to this category.
369 *
370 * @param blogEntry a blog entry id
371 */
372 public synchronized void addBlogEntry(String blogEntry) {
/*
P/P * Method: void addBlogEntry(String)
*
* Preconditions:
* (soft) this...blogEntries != null
* (soft) init'ed(this...parent)
* (soft) this.blogEntries != null
* (soft) init'ed(this.parent)
*
* Test Vectors:
* blogEntry: Addr_Set{null}, Inverse{null}
* this.parent: Addr_Set{null}, Inverse{null}
* java.util.List:contains(...)@373: {1}, {0}
*/
373 if (blogEntry != null && !blogEntries.contains(blogEntry)) {
374 blogEntries.add(blogEntry);
375 Collections.sort(blogEntries, new ReverseBlogEntryIdComparator());
376
377 if (getParent() != null) {
378 getParent().addBlogEntry(blogEntry);
379 }
380 }
381 }
382
383 /**
384 * Removes a blog entry from this category.
385 *
386 * @param blogEntry a blog entry id
387 */
388 public synchronized void removeBlogEntry(String blogEntry) {
/*
P/P * Method: void removeBlogEntry(String)
*
* Preconditions:
* (soft) this...blogEntries != null
* (soft) init'ed(this...parent)
* (soft) this.blogEntries != null
* (soft) init'ed(this.parent)
*
* Test Vectors:
* blogEntry: Addr_Set{null}, Inverse{null}
* this.parent: Addr_Set{null}, Inverse{null}
*/
389 if (blogEntry != null) {
390 blogEntries.remove(blogEntry);
391
392 if (getParent() != null) {
393 getParent().removeBlogEntry(blogEntry);
394 }
395 }
396 }
397
398 /**
399 * Removes all blog entries from this category.
400 */
401 public synchronized void removeAllBlogEntries() {
/*
P/P * Method: void removeAllBlogEntries()
*
* Postconditions:
* this.blogEntries == &new ArrayList(removeAllBlogEntries#1)
* new ArrayList(removeAllBlogEntries#1) num objects == 1
*/
402 blogEntries = new ArrayList<String>();
403 }
404
405 /**
406 * Gets the number of blog entries associated with this category.
407 *
408 * @return an int
409 */
410 public int getNumberOfBlogEntries() {
/*
P/P * Method: int getNumberOfBlogEntries()
*
* Preconditions:
* this.blogEntries != null
*
* Postconditions:
* init'ed(return_value)
*/
411 return this.blogEntries.size();
412 }
413
414 }
SofCheck Inspector Build Version : 2.22510
| category.java |
2010-Jun-25 19:40:32 |
| category.class |
2010-Jul-19 20:23:40 |